sound fixes for 3.15-rc6
Unfortunately this update became bigger than previous pull requests, which is almost a pattern in rc5-6. But, the only obvious big changes are for the new Intel DSP ASoC drivers, so the impact must be fairly limited. Other than that, usual small fixes in various fields: HD-audio, ASoC core and ASoC fsl and codec drivers. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJTdPwHAAoJEGwxgFQ9KSmk2MoQAI91MJeGAS3nZczw+TnHHBg7 tk/0r85Kdwem2M9tywZVM78q7vECpB7UV8nZXAIHKcc1fpEjzHu3WJnR5zyqrEDO 4o+9gx9gdwUa7Tv+L8n0A7xSAdIPCrqEL5/776YuUUR/MqJsjemP5bbudzd4ffL7 asLEcJWf0HMHePEajyuay21OWtCRABLLGjgVd0QOFce2B8yBmUswHy0XPYV6+39A j+G7/gNK1MMF+gmPMy5XV89C+5V1V9wZ68cJuBKJKODJ6SDnRZGaRt84W/lL15Ag NtzFIT9Sd/qwiOwTtx6qNGmoyxrDfpNQ1Beqd1Mr9kJTowOziRqbZSyNYkKJKkHy FvRuZkRyDPlmsYnBCxQqaKFhMcWu0n6urssU6y2rCWi0HrBsB4i/ttSfFRHwdASt jGj/YU2bCc3B2SeZy+xlKW++KsPS829F4cFGD/kx7PsegGetmAp1S1jJJGXPIno4 jHnVKISWUGGxrPkL+6QxOBFPqtErx0/k/Scb8PwlugkAqQnN2w8Ds5vQ02cs/gOC kPdo5c4mnWLLF7YEwdyd2+u2dlqGoIIAJM0i4qiNRPccAjxrfd6Ao78BoGzvktjg nmzKsHJO/GF3BTf2o73Evr1jtdxmU+9gL8DKsYgFyBOrr511ieetswgIWbZBej+0 UDDaGufcAX9qDoLktzsC =h7mJ -----END PGP SIGNATURE----- Merge tag 'sound-3.15-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound Pull sound fixes from Takashi Iwai: "Unfortunately this update became bigger than previous pull requests, which is almost a pattern in rc5-6. But, the only obvious big changes are for the new Intel DSP ASoC drivers, so the impact must be fairly limited. Other than that, usual small fixes in various fields: HD-audio, ASoC core and ASoC fsl and codec drivers" * tag 'sound-3.15-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (26 commits) ALSA: sb_mixer: missing return statement ASoC: wm8962: Update register CLASS_D_CONTROL_1 to be non-volatile ASoC: Intel: Fix Baytrail SST DSP firmware loading ALSA: hda - mask buggy stream DMA0 for Broadwell display controller ALSA: hda - Add new GPU codec ID to snd-hda ASoC: fsl_esai: Set PCRC and PRRC registers at the end of hw_params() ASoC: fsl_esai: Only bypass sck_div for EXTAL source ASoC: fsl_esai: Fix incorrect condition within ratio range check for FP ASoC: dapm: Fix SUSPEND -> OFF bias sequence ASoC: dapm: Skip CODEC<->CODEC links in connect_dai_link_widgets() ASoC: pcm: Fix incorrect condition check for case SNDRV_PCM_TRIGGER_SUSPEND ALSA: hda - add headset mic detect quirks for three Dell laptops ASoC: Update Cirrus Logic CODEC maintainers. ASoC: Intel: Fix block offset calculations. ASoC: Intel: Fix check for pdata usage before dereference. ASoC: Intel: Fix stream position pointer. ASoC: Intel: Fix allow hw_params to be called more than once. ASoC: Intel: Fix Audio DSP usage when IOMMU is enabled. ASoC: Intel: Fix Haswell/Broadwell DSP page table creation. ASoC: Intel: Fix allocated block list usage when adding blocks. ...
This commit is contained in:
commit
60b5f90d0f
|
@ -2246,12 +2246,6 @@ L: linux-usb@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/usb/host/ohci-ep93xx.c
|
F: drivers/usb/host/ohci-ep93xx.c
|
||||||
|
|
||||||
CIRRUS LOGIC CS4270 SOUND DRIVER
|
|
||||||
M: Timur Tabi <timur@tabi.org>
|
|
||||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
|
||||||
S: Odd Fixes
|
|
||||||
F: sound/soc/codecs/cs4270*
|
|
||||||
|
|
||||||
CIRRUS LOGIC AUDIO CODEC DRIVERS
|
CIRRUS LOGIC AUDIO CODEC DRIVERS
|
||||||
M: Brian Austin <brian.austin@cirrus.com>
|
M: Brian Austin <brian.austin@cirrus.com>
|
||||||
M: Paul Handrigan <Paul.Handrigan@cirrus.com>
|
M: Paul Handrigan <Paul.Handrigan@cirrus.com>
|
||||||
|
|
|
@ -818,12 +818,14 @@ int snd_sbmixer_new(struct snd_sb *chip)
|
||||||
return err;
|
return err;
|
||||||
break;
|
break;
|
||||||
case SB_HW_DT019X:
|
case SB_HW_DT019X:
|
||||||
if ((err = snd_sbmixer_init(chip,
|
err = snd_sbmixer_init(chip,
|
||||||
snd_dt019x_controls,
|
snd_dt019x_controls,
|
||||||
ARRAY_SIZE(snd_dt019x_controls),
|
ARRAY_SIZE(snd_dt019x_controls),
|
||||||
snd_dt019x_init_values,
|
snd_dt019x_init_values,
|
||||||
ARRAY_SIZE(snd_dt019x_init_values),
|
ARRAY_SIZE(snd_dt019x_init_values),
|
||||||
"DT019X")) < 0)
|
"DT019X");
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
strcpy(card->mixername, "???");
|
strcpy(card->mixername, "???");
|
||||||
|
|
|
@ -1367,6 +1367,12 @@ static int azx_first_init(struct azx *chip)
|
||||||
/* initialize streams */
|
/* initialize streams */
|
||||||
azx_init_stream(chip);
|
azx_init_stream(chip);
|
||||||
|
|
||||||
|
/* workaround for Broadwell HDMI: the first stream is broken,
|
||||||
|
* so mask it by keeping it as if opened
|
||||||
|
*/
|
||||||
|
if (pci->vendor == 0x8086 && pci->device == 0x160c)
|
||||||
|
chip->azx_dev[0].opened = 1;
|
||||||
|
|
||||||
/* initialize chip */
|
/* initialize chip */
|
||||||
azx_init_pci(chip);
|
azx_init_pci(chip);
|
||||||
azx_init_chip(chip, (probe_only[dev] & 2) == 0);
|
azx_init_chip(chip, (probe_only[dev] & 2) == 0);
|
||||||
|
|
|
@ -3332,6 +3332,7 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
|
||||||
{ .id = 0x10de0051, .name = "GPU 51 HDMI/DP", .patch = patch_nvhdmi },
|
{ .id = 0x10de0051, .name = "GPU 51 HDMI/DP", .patch = patch_nvhdmi },
|
||||||
{ .id = 0x10de0060, .name = "GPU 60 HDMI/DP", .patch = patch_nvhdmi },
|
{ .id = 0x10de0060, .name = "GPU 60 HDMI/DP", .patch = patch_nvhdmi },
|
||||||
{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
|
{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
|
||||||
|
{ .id = 0x10de0071, .name = "GPU 71 HDMI/DP", .patch = patch_nvhdmi },
|
||||||
{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
|
{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
|
||||||
{ .id = 0x11069f80, .name = "VX900 HDMI/DP", .patch = patch_via_hdmi },
|
{ .id = 0x11069f80, .name = "VX900 HDMI/DP", .patch = patch_via_hdmi },
|
||||||
{ .id = 0x11069f81, .name = "VX900 HDMI/DP", .patch = patch_via_hdmi },
|
{ .id = 0x11069f81, .name = "VX900 HDMI/DP", .patch = patch_via_hdmi },
|
||||||
|
@ -3387,6 +3388,7 @@ MODULE_ALIAS("snd-hda-codec-id:10de0044");
|
||||||
MODULE_ALIAS("snd-hda-codec-id:10de0051");
|
MODULE_ALIAS("snd-hda-codec-id:10de0051");
|
||||||
MODULE_ALIAS("snd-hda-codec-id:10de0060");
|
MODULE_ALIAS("snd-hda-codec-id:10de0060");
|
||||||
MODULE_ALIAS("snd-hda-codec-id:10de0067");
|
MODULE_ALIAS("snd-hda-codec-id:10de0067");
|
||||||
|
MODULE_ALIAS("snd-hda-codec-id:10de0071");
|
||||||
MODULE_ALIAS("snd-hda-codec-id:10de8001");
|
MODULE_ALIAS("snd-hda-codec-id:10de8001");
|
||||||
MODULE_ALIAS("snd-hda-codec-id:11069f80");
|
MODULE_ALIAS("snd-hda-codec-id:11069f80");
|
||||||
MODULE_ALIAS("snd-hda-codec-id:11069f81");
|
MODULE_ALIAS("snd-hda-codec-id:11069f81");
|
||||||
|
|
|
@ -4616,6 +4616,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
||||||
SND_PCI_QUIRK(0x1028, 0x0653, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
|
SND_PCI_QUIRK(0x1028, 0x0653, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
|
||||||
SND_PCI_QUIRK(0x1028, 0x0657, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
|
SND_PCI_QUIRK(0x1028, 0x0657, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
|
||||||
SND_PCI_QUIRK(0x1028, 0x0658, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
|
SND_PCI_QUIRK(0x1028, 0x0658, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x065c, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
|
||||||
SND_PCI_QUIRK(0x1028, 0x065f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
|
SND_PCI_QUIRK(0x1028, 0x065f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
|
||||||
SND_PCI_QUIRK(0x1028, 0x0662, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
|
SND_PCI_QUIRK(0x1028, 0x0662, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
|
||||||
SND_PCI_QUIRK(0x1028, 0x0667, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
|
SND_PCI_QUIRK(0x1028, 0x0667, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
|
||||||
|
@ -4624,6 +4625,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
||||||
SND_PCI_QUIRK(0x1028, 0x0674, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
|
SND_PCI_QUIRK(0x1028, 0x0674, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
|
||||||
SND_PCI_QUIRK(0x1028, 0x067e, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
|
SND_PCI_QUIRK(0x1028, 0x067e, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
|
||||||
SND_PCI_QUIRK(0x1028, 0x067f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
|
SND_PCI_QUIRK(0x1028, 0x067f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0680, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0684, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
|
||||||
SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
|
SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
|
||||||
SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
|
SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
|
||||||
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
|
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
|
||||||
|
|
|
@ -376,7 +376,7 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
|
||||||
reg = AIC31XX_ADCFLAG;
|
reg = AIC31XX_ADCFLAG;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(w->codec->dev, "Unknown widget '%s' calling %s/n",
|
dev_err(w->codec->dev, "Unknown widget '%s' calling %s\n",
|
||||||
w->name, __func__);
|
w->name, __func__);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,6 +154,7 @@ static struct reg_default wm8962_reg[] = {
|
||||||
{ 40, 0x0000 }, /* R40 - SPKOUTL volume */
|
{ 40, 0x0000 }, /* R40 - SPKOUTL volume */
|
||||||
{ 41, 0x0000 }, /* R41 - SPKOUTR volume */
|
{ 41, 0x0000 }, /* R41 - SPKOUTR volume */
|
||||||
|
|
||||||
|
{ 49, 0x0010 }, /* R49 - Class D Control 1 */
|
||||||
{ 51, 0x0003 }, /* R51 - Class D Control 2 */
|
{ 51, 0x0003 }, /* R51 - Class D Control 2 */
|
||||||
|
|
||||||
{ 56, 0x0506 }, /* R56 - Clocking 4 */
|
{ 56, 0x0506 }, /* R56 - Clocking 4 */
|
||||||
|
@ -795,7 +796,6 @@ static bool wm8962_volatile_register(struct device *dev, unsigned int reg)
|
||||||
case WM8962_ALC2:
|
case WM8962_ALC2:
|
||||||
case WM8962_THERMAL_SHUTDOWN_STATUS:
|
case WM8962_THERMAL_SHUTDOWN_STATUS:
|
||||||
case WM8962_ADDITIONAL_CONTROL_4:
|
case WM8962_ADDITIONAL_CONTROL_4:
|
||||||
case WM8962_CLASS_D_CONTROL_1:
|
|
||||||
case WM8962_DC_SERVO_6:
|
case WM8962_DC_SERVO_6:
|
||||||
case WM8962_INTERRUPT_STATUS_1:
|
case WM8962_INTERRUPT_STATUS_1:
|
||||||
case WM8962_INTERRUPT_STATUS_2:
|
case WM8962_INTERRUPT_STATUS_2:
|
||||||
|
@ -2929,13 +2929,22 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
|
||||||
static int wm8962_mute(struct snd_soc_dai *dai, int mute)
|
static int wm8962_mute(struct snd_soc_dai *dai, int mute)
|
||||||
{
|
{
|
||||||
struct snd_soc_codec *codec = dai->codec;
|
struct snd_soc_codec *codec = dai->codec;
|
||||||
int val;
|
int val, ret;
|
||||||
|
|
||||||
if (mute)
|
if (mute)
|
||||||
val = WM8962_DAC_MUTE;
|
val = WM8962_DAC_MUTE | WM8962_DAC_MUTE_ALT;
|
||||||
else
|
else
|
||||||
val = 0;
|
val = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DAC mute bit is mirrored in two registers, update both to keep
|
||||||
|
* the register cache consistent.
|
||||||
|
*/
|
||||||
|
ret = snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_1,
|
||||||
|
WM8962_DAC_MUTE_ALT, val);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
return snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
|
return snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
|
||||||
WM8962_DAC_MUTE, val);
|
WM8962_DAC_MUTE, val);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1954,6 +1954,10 @@
|
||||||
#define WM8962_SPKOUTL_ENA_MASK 0x0040 /* SPKOUTL_ENA */
|
#define WM8962_SPKOUTL_ENA_MASK 0x0040 /* SPKOUTL_ENA */
|
||||||
#define WM8962_SPKOUTL_ENA_SHIFT 6 /* SPKOUTL_ENA */
|
#define WM8962_SPKOUTL_ENA_SHIFT 6 /* SPKOUTL_ENA */
|
||||||
#define WM8962_SPKOUTL_ENA_WIDTH 1 /* SPKOUTL_ENA */
|
#define WM8962_SPKOUTL_ENA_WIDTH 1 /* SPKOUTL_ENA */
|
||||||
|
#define WM8962_DAC_MUTE_ALT 0x0010 /* DAC_MUTE */
|
||||||
|
#define WM8962_DAC_MUTE_ALT_MASK 0x0010 /* DAC_MUTE */
|
||||||
|
#define WM8962_DAC_MUTE_ALT_SHIFT 4 /* DAC_MUTE */
|
||||||
|
#define WM8962_DAC_MUTE_ALT_WIDTH 1 /* DAC_MUTE */
|
||||||
#define WM8962_SPKOUTL_PGA_MUTE 0x0002 /* SPKOUTL_PGA_MUTE */
|
#define WM8962_SPKOUTL_PGA_MUTE 0x0002 /* SPKOUTL_PGA_MUTE */
|
||||||
#define WM8962_SPKOUTL_PGA_MUTE_MASK 0x0002 /* SPKOUTL_PGA_MUTE */
|
#define WM8962_SPKOUTL_PGA_MUTE_MASK 0x0002 /* SPKOUTL_PGA_MUTE */
|
||||||
#define WM8962_SPKOUTL_PGA_MUTE_SHIFT 1 /* SPKOUTL_PGA_MUTE */
|
#define WM8962_SPKOUTL_PGA_MUTE_SHIFT 1 /* SPKOUTL_PGA_MUTE */
|
||||||
|
|
|
@ -258,10 +258,16 @@ static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ratio == 1) {
|
/* Only EXTAL source can be output directly without using PSR and PM */
|
||||||
|
if (ratio == 1 && clksrc == esai_priv->extalclk) {
|
||||||
/* Bypass all the dividers if not being needed */
|
/* Bypass all the dividers if not being needed */
|
||||||
ecr |= tx ? ESAI_ECR_ETO : ESAI_ECR_ERO;
|
ecr |= tx ? ESAI_ECR_ETO : ESAI_ECR_ERO;
|
||||||
goto out;
|
goto out;
|
||||||
|
} else if (ratio < 2) {
|
||||||
|
/* The ratio should be no less than 2 if using other sources */
|
||||||
|
dev_err(dai->dev, "failed to derive required HCK%c rate\n",
|
||||||
|
tx ? 'T' : 'R');
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = fsl_esai_divisor_cal(dai, tx, ratio, false, 0);
|
ret = fsl_esai_divisor_cal(dai, tx, ratio, false, 0);
|
||||||
|
@ -307,7 +313,8 @@ static int fsl_esai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (esai_priv->sck_div[tx] && (ratio > 16 || ratio == 0)) {
|
/* The ratio should be contented by FP alone if bypassing PM and PSR */
|
||||||
|
if (!esai_priv->sck_div[tx] && (ratio > 16 || ratio == 0)) {
|
||||||
dev_err(dai->dev, "the ratio is out of range (1 ~ 16)\n");
|
dev_err(dai->dev, "the ratio is out of range (1 ~ 16)\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -454,12 +461,6 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dai->active) {
|
if (!dai->active) {
|
||||||
/* Reset Port C */
|
|
||||||
regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,
|
|
||||||
ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO));
|
|
||||||
regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC,
|
|
||||||
ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO));
|
|
||||||
|
|
||||||
/* Set synchronous mode */
|
/* Set synchronous mode */
|
||||||
regmap_update_bits(esai_priv->regmap, REG_ESAI_SAICR,
|
regmap_update_bits(esai_priv->regmap, REG_ESAI_SAICR,
|
||||||
ESAI_SAICR_SYNC, esai_priv->synchronous ?
|
ESAI_SAICR_SYNC, esai_priv->synchronous ?
|
||||||
|
@ -519,6 +520,11 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
|
||||||
|
|
||||||
regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);
|
regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);
|
||||||
|
|
||||||
|
/* Remove ESAI personal reset by configuring ESAI_PCRC and ESAI_PRRC */
|
||||||
|
regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,
|
||||||
|
ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO));
|
||||||
|
regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC,
|
||||||
|
ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,7 @@ static const struct file_operations audmux_debugfs_fops = {
|
||||||
.llseek = default_llseek,
|
.llseek = default_llseek,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __init audmux_debugfs_init(void)
|
static void audmux_debugfs_init(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char buf[20];
|
char buf[20];
|
||||||
|
|
|
@ -138,6 +138,7 @@ static int sst_acpi_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
sst_pdata = &sst_acpi->sst_pdata;
|
sst_pdata = &sst_acpi->sst_pdata;
|
||||||
sst_pdata->id = desc->sst_id;
|
sst_pdata->id = desc->sst_id;
|
||||||
|
sst_pdata->dma_dev = dev;
|
||||||
sst_acpi->desc = desc;
|
sst_acpi->desc = desc;
|
||||||
sst_acpi->mach = mach;
|
sst_acpi->mach = mach;
|
||||||
|
|
||||||
|
|
|
@ -324,7 +324,7 @@ static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata)
|
||||||
memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET,
|
memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET,
|
||||||
&pdata->fw_base, sizeof(u32));
|
&pdata->fw_base, sizeof(u32));
|
||||||
|
|
||||||
ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
|
ret = dma_coerce_mask_and_coherent(sst->dma_dev, DMA_BIT_MASK(32));
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
|
@ -542,16 +542,20 @@ struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
struct sst_byt_stream *stream;
|
struct sst_byt_stream *stream;
|
||||||
|
struct sst_dsp *sst = byt->dsp;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
stream = kzalloc(sizeof(*stream), GFP_KERNEL);
|
stream = kzalloc(sizeof(*stream), GFP_KERNEL);
|
||||||
if (stream == NULL)
|
if (stream == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&sst->spinlock, flags);
|
||||||
list_add(&stream->node, &byt->stream_list);
|
list_add(&stream->node, &byt->stream_list);
|
||||||
stream->notify_position = notify_position;
|
stream->notify_position = notify_position;
|
||||||
stream->pdata = data;
|
stream->pdata = data;
|
||||||
stream->byt = byt;
|
stream->byt = byt;
|
||||||
stream->str_id = id;
|
stream->str_id = id;
|
||||||
|
spin_unlock_irqrestore(&sst->spinlock, flags);
|
||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
@ -630,6 +634,8 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
|
||||||
{
|
{
|
||||||
u64 header;
|
u64 header;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
struct sst_dsp *sst = byt->dsp;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (!stream->commited)
|
if (!stream->commited)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -644,8 +650,10 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
|
||||||
|
|
||||||
stream->commited = false;
|
stream->commited = false;
|
||||||
out:
|
out:
|
||||||
|
spin_lock_irqsave(&sst->spinlock, flags);
|
||||||
list_del(&stream->node);
|
list_del(&stream->node);
|
||||||
kfree(stream);
|
kfree(stream);
|
||||||
|
spin_unlock_irqrestore(&sst->spinlock, flags);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,6 +228,7 @@ struct sst_dsp {
|
||||||
spinlock_t spinlock; /* IPC locking */
|
spinlock_t spinlock; /* IPC locking */
|
||||||
struct mutex mutex; /* DSP FW lock */
|
struct mutex mutex; /* DSP FW lock */
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
struct device *dma_dev;
|
||||||
void *thread_context;
|
void *thread_context;
|
||||||
int irq;
|
int irq;
|
||||||
u32 id;
|
u32 id;
|
||||||
|
|
|
@ -337,6 +337,7 @@ struct sst_dsp *sst_dsp_new(struct device *dev,
|
||||||
spin_lock_init(&sst->spinlock);
|
spin_lock_init(&sst->spinlock);
|
||||||
mutex_init(&sst->mutex);
|
mutex_init(&sst->mutex);
|
||||||
sst->dev = dev;
|
sst->dev = dev;
|
||||||
|
sst->dma_dev = pdata->dma_dev;
|
||||||
sst->thread_context = sst_dev->thread_context;
|
sst->thread_context = sst_dev->thread_context;
|
||||||
sst->sst_dev = sst_dev;
|
sst->sst_dev = sst_dev;
|
||||||
sst->id = pdata->id;
|
sst->id = pdata->id;
|
||||||
|
|
|
@ -169,6 +169,7 @@ struct sst_pdata {
|
||||||
u32 dma_base;
|
u32 dma_base;
|
||||||
u32 dma_size;
|
u32 dma_size;
|
||||||
int dma_engine;
|
int dma_engine;
|
||||||
|
struct device *dma_dev;
|
||||||
|
|
||||||
/* DSP */
|
/* DSP */
|
||||||
u32 id;
|
u32 id;
|
||||||
|
|
|
@ -57,14 +57,8 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
|
||||||
sst_fw->private = private;
|
sst_fw->private = private;
|
||||||
sst_fw->size = fw->size;
|
sst_fw->size = fw->size;
|
||||||
|
|
||||||
err = dma_coerce_mask_and_coherent(dsp->dev, DMA_BIT_MASK(32));
|
|
||||||
if (err < 0) {
|
|
||||||
kfree(sst_fw);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* allocate DMA buffer to store FW data */
|
/* allocate DMA buffer to store FW data */
|
||||||
sst_fw->dma_buf = dma_alloc_coherent(dsp->dev, sst_fw->size,
|
sst_fw->dma_buf = dma_alloc_coherent(dsp->dma_dev, sst_fw->size,
|
||||||
&sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL);
|
&sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL);
|
||||||
if (!sst_fw->dma_buf) {
|
if (!sst_fw->dma_buf) {
|
||||||
dev_err(dsp->dev, "error: DMA alloc failed\n");
|
dev_err(dsp->dev, "error: DMA alloc failed\n");
|
||||||
|
@ -106,7 +100,7 @@ void sst_fw_free(struct sst_fw *sst_fw)
|
||||||
list_del(&sst_fw->list);
|
list_del(&sst_fw->list);
|
||||||
mutex_unlock(&dsp->mutex);
|
mutex_unlock(&dsp->mutex);
|
||||||
|
|
||||||
dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf,
|
dma_free_coherent(dsp->dma_dev, sst_fw->size, sst_fw->dma_buf,
|
||||||
sst_fw->dmable_fw_paddr);
|
sst_fw->dmable_fw_paddr);
|
||||||
kfree(sst_fw);
|
kfree(sst_fw);
|
||||||
}
|
}
|
||||||
|
@ -202,6 +196,9 @@ static int block_alloc_contiguous(struct sst_module *module,
|
||||||
size -= block->size;
|
size -= block->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list_for_each_entry(block, &tmp, list)
|
||||||
|
list_add(&block->module_list, &module->block_list);
|
||||||
|
|
||||||
list_splice(&tmp, &dsp->used_block_list);
|
list_splice(&tmp, &dsp->used_block_list);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -247,8 +244,7 @@ static int block_alloc(struct sst_module *module,
|
||||||
/* do we span > 1 blocks */
|
/* do we span > 1 blocks */
|
||||||
if (data->size > block->size) {
|
if (data->size > block->size) {
|
||||||
ret = block_alloc_contiguous(module, data,
|
ret = block_alloc_contiguous(module, data,
|
||||||
block->offset + block->size,
|
block->offset, data->size);
|
||||||
data->size - block->size);
|
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -344,7 +340,7 @@ static int block_alloc_fixed(struct sst_module *module,
|
||||||
|
|
||||||
err = block_alloc_contiguous(module, data,
|
err = block_alloc_contiguous(module, data,
|
||||||
block->offset + block->size,
|
block->offset + block->size,
|
||||||
data->size - block->size + data->offset - block->offset);
|
data->size - block->size);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -371,15 +367,10 @@ static int block_alloc_fixed(struct sst_module *module,
|
||||||
if (data->offset >= block->offset && data->offset < block_end) {
|
if (data->offset >= block->offset && data->offset < block_end) {
|
||||||
|
|
||||||
err = block_alloc_contiguous(module, data,
|
err = block_alloc_contiguous(module, data,
|
||||||
block->offset + block->size,
|
block->offset, data->size);
|
||||||
data->size - block->size);
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* add block */
|
|
||||||
block->data_type = data->data_type;
|
|
||||||
list_move(&block->list, &dsp->used_block_list);
|
|
||||||
list_add(&block->module_list, &module->block_list);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -433,7 +433,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
|
||||||
int ret = -ENODEV, i, j, region_count;
|
int ret = -ENODEV, i, j, region_count;
|
||||||
u32 offset, size;
|
u32 offset, size;
|
||||||
|
|
||||||
dev = sst->dev;
|
dev = sst->dma_dev;
|
||||||
|
|
||||||
switch (sst->id) {
|
switch (sst->id) {
|
||||||
case SST_DEV_ID_LYNX_POINT:
|
case SST_DEV_ID_LYNX_POINT:
|
||||||
|
@ -466,7 +466,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
|
ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(31));
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
|
@ -1159,11 +1159,14 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
struct sst_hsw_stream *stream;
|
struct sst_hsw_stream *stream;
|
||||||
|
struct sst_dsp *sst = hsw->dsp;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
stream = kzalloc(sizeof(*stream), GFP_KERNEL);
|
stream = kzalloc(sizeof(*stream), GFP_KERNEL);
|
||||||
if (stream == NULL)
|
if (stream == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&sst->spinlock, flags);
|
||||||
list_add(&stream->node, &hsw->stream_list);
|
list_add(&stream->node, &hsw->stream_list);
|
||||||
stream->notify_position = notify_position;
|
stream->notify_position = notify_position;
|
||||||
stream->pdata = data;
|
stream->pdata = data;
|
||||||
|
@ -1172,6 +1175,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
|
||||||
|
|
||||||
/* work to process notification messages */
|
/* work to process notification messages */
|
||||||
INIT_WORK(&stream->notify_work, hsw_notification_work);
|
INIT_WORK(&stream->notify_work, hsw_notification_work);
|
||||||
|
spin_unlock_irqrestore(&sst->spinlock, flags);
|
||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
@ -1180,6 +1184,8 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
|
||||||
{
|
{
|
||||||
u32 header;
|
u32 header;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
struct sst_dsp *sst = hsw->dsp;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
/* dont free DSP streams that are not commited */
|
/* dont free DSP streams that are not commited */
|
||||||
if (!stream->commited)
|
if (!stream->commited)
|
||||||
|
@ -1201,8 +1207,11 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
|
||||||
trace_hsw_stream_free_req(stream, &stream->free_req);
|
trace_hsw_stream_free_req(stream, &stream->free_req);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
cancel_work_sync(&stream->notify_work);
|
||||||
|
spin_lock_irqsave(&sst->spinlock, flags);
|
||||||
list_del(&stream->node);
|
list_del(&stream->node);
|
||||||
kfree(stream);
|
kfree(stream);
|
||||||
|
spin_unlock_irqrestore(&sst->spinlock, flags);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1538,10 +1547,28 @@ int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stream pointer positions */
|
/* Stream pointer positions */
|
||||||
int sst_hsw_get_dsp_position(struct sst_hsw *hsw,
|
u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw,
|
||||||
struct sst_hsw_stream *stream)
|
struct sst_hsw_stream *stream)
|
||||||
{
|
{
|
||||||
return stream->rpos.position;
|
u32 rpos;
|
||||||
|
|
||||||
|
sst_dsp_read(hsw->dsp, &rpos,
|
||||||
|
stream->reply.read_position_register_address, sizeof(rpos));
|
||||||
|
|
||||||
|
return rpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stream presentation (monotonic) positions */
|
||||||
|
u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw,
|
||||||
|
struct sst_hsw_stream *stream)
|
||||||
|
{
|
||||||
|
u64 ppos;
|
||||||
|
|
||||||
|
sst_dsp_read(hsw->dsp, &ppos,
|
||||||
|
stream->reply.presentation_position_register_address,
|
||||||
|
sizeof(ppos));
|
||||||
|
|
||||||
|
return ppos;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
|
int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
|
||||||
|
|
|
@ -464,7 +464,9 @@ int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw,
|
||||||
struct sst_hsw_stream *stream, u32 *position);
|
struct sst_hsw_stream *stream, u32 *position);
|
||||||
int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
|
int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
|
||||||
struct sst_hsw_stream *stream, u32 stage_id, u32 position);
|
struct sst_hsw_stream *stream, u32 stage_id, u32 position);
|
||||||
int sst_hsw_get_dsp_position(struct sst_hsw *hsw,
|
u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw,
|
||||||
|
struct sst_hsw_stream *stream);
|
||||||
|
u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw,
|
||||||
struct sst_hsw_stream *stream);
|
struct sst_hsw_stream *stream);
|
||||||
|
|
||||||
/* HW port config */
|
/* HW port config */
|
||||||
|
|
|
@ -99,6 +99,7 @@ struct hsw_pcm_data {
|
||||||
struct snd_compr_stream *cstream;
|
struct snd_compr_stream *cstream;
|
||||||
unsigned int wpos;
|
unsigned int wpos;
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
|
bool allocated;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* private data for the driver */
|
/* private data for the driver */
|
||||||
|
@ -107,12 +108,14 @@ struct hsw_priv_data {
|
||||||
struct sst_hsw *hsw;
|
struct sst_hsw *hsw;
|
||||||
|
|
||||||
/* page tables */
|
/* page tables */
|
||||||
unsigned char *pcm_pg[HSW_PCM_COUNT][2];
|
struct snd_dma_buffer dmab[HSW_PCM_COUNT][2];
|
||||||
|
|
||||||
/* DAI data */
|
/* DAI data */
|
||||||
struct hsw_pcm_data pcm[HSW_PCM_COUNT];
|
struct hsw_pcm_data pcm[HSW_PCM_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data);
|
||||||
|
|
||||||
static inline u32 hsw_mixer_to_ipc(unsigned int value)
|
static inline u32 hsw_mixer_to_ipc(unsigned int value)
|
||||||
{
|
{
|
||||||
if (value >= ARRAY_SIZE(volume_map))
|
if (value >= ARRAY_SIZE(volume_map))
|
||||||
|
@ -273,28 +276,26 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Create DMA buffer page table for DSP */
|
/* Create DMA buffer page table for DSP */
|
||||||
static int create_adsp_page_table(struct hsw_priv_data *pdata,
|
static int create_adsp_page_table(struct snd_pcm_substream *substream,
|
||||||
struct snd_soc_pcm_runtime *rtd,
|
struct hsw_priv_data *pdata, struct snd_soc_pcm_runtime *rtd,
|
||||||
unsigned char *dma_area, size_t size, int pcm, int stream)
|
unsigned char *dma_area, size_t size, int pcm)
|
||||||
{
|
{
|
||||||
int i, pages;
|
struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream);
|
||||||
|
int i, pages, stream = substream->stream;
|
||||||
|
|
||||||
if (size % PAGE_SIZE)
|
pages = snd_sgbuf_aligned_pages(size);
|
||||||
pages = (size / PAGE_SIZE) + 1;
|
|
||||||
else
|
|
||||||
pages = size / PAGE_SIZE;
|
|
||||||
|
|
||||||
dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n",
|
dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n",
|
||||||
dma_area, size, pages);
|
dma_area, size, pages);
|
||||||
|
|
||||||
for (i = 0; i < pages; i++) {
|
for (i = 0; i < pages; i++) {
|
||||||
u32 idx = (((i << 2) + i)) >> 1;
|
u32 idx = (((i << 2) + i)) >> 1;
|
||||||
u32 pfn = (virt_to_phys(dma_area + i * PAGE_SIZE)) >> PAGE_SHIFT;
|
u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT;
|
||||||
u32 *pg_table;
|
u32 *pg_table;
|
||||||
|
|
||||||
dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn);
|
dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn);
|
||||||
|
|
||||||
pg_table = (u32*)(pdata->pcm_pg[pcm][stream] + idx);
|
pg_table = (u32 *)(pdata->dmab[pcm][stream].area + idx);
|
||||||
|
|
||||||
if (i & 1)
|
if (i & 1)
|
||||||
*pg_table |= (pfn << 4);
|
*pg_table |= (pfn << 4);
|
||||||
|
@ -317,12 +318,36 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||||
struct sst_hsw *hsw = pdata->hsw;
|
struct sst_hsw *hsw = pdata->hsw;
|
||||||
struct sst_module *module_data;
|
struct sst_module *module_data;
|
||||||
struct sst_dsp *dsp;
|
struct sst_dsp *dsp;
|
||||||
|
struct snd_dma_buffer *dmab;
|
||||||
enum sst_hsw_stream_type stream_type;
|
enum sst_hsw_stream_type stream_type;
|
||||||
enum sst_hsw_stream_path_id path_id;
|
enum sst_hsw_stream_path_id path_id;
|
||||||
u32 rate, bits, map, pages, module_id;
|
u32 rate, bits, map, pages, module_id;
|
||||||
u8 channels;
|
u8 channels;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* check if we are being called a subsequent time */
|
||||||
|
if (pcm_data->allocated) {
|
||||||
|
ret = sst_hsw_stream_reset(hsw, pcm_data->stream);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_dbg(rtd->dev, "error: reset stream failed %d\n",
|
||||||
|
ret);
|
||||||
|
|
||||||
|
ret = sst_hsw_stream_free(hsw, pcm_data->stream);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_dbg(rtd->dev, "error: free stream failed %d\n",
|
||||||
|
ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
pcm_data->allocated = false;
|
||||||
|
|
||||||
|
pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id,
|
||||||
|
hsw_notify_pointer, pcm_data);
|
||||||
|
if (pcm_data->stream == NULL) {
|
||||||
|
dev_err(rtd->dev, "error: failed to create stream\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* stream direction */
|
/* stream direction */
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||||
path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
|
path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
|
||||||
|
@ -416,8 +441,10 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = create_adsp_page_table(pdata, rtd, runtime->dma_area,
|
dmab = snd_pcm_get_dma_buf(substream);
|
||||||
runtime->dma_bytes, rtd->cpu_dai->id, substream->stream);
|
|
||||||
|
ret = create_adsp_page_table(substream, pdata, rtd, runtime->dma_area,
|
||||||
|
runtime->dma_bytes, rtd->cpu_dai->id);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -430,9 +457,9 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||||
pages = runtime->dma_bytes / PAGE_SIZE;
|
pages = runtime->dma_bytes / PAGE_SIZE;
|
||||||
|
|
||||||
ret = sst_hsw_stream_buffer(hsw, pcm_data->stream,
|
ret = sst_hsw_stream_buffer(hsw, pcm_data->stream,
|
||||||
virt_to_phys(pdata->pcm_pg[rtd->cpu_dai->id][substream->stream]),
|
pdata->dmab[rtd->cpu_dai->id][substream->stream].addr,
|
||||||
pages, runtime->dma_bytes, 0,
|
pages, runtime->dma_bytes, 0,
|
||||||
(u32)(virt_to_phys(runtime->dma_area) >> PAGE_SHIFT));
|
snd_sgbuf_get_addr(dmab, 0) >> PAGE_SHIFT);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret);
|
dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -474,6 +501,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||||
dev_err(rtd->dev, "error: failed to commit stream %d\n", ret);
|
dev_err(rtd->dev, "error: failed to commit stream %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
pcm_data->allocated = true;
|
||||||
|
|
||||||
ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1);
|
ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -541,12 +569,14 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
|
||||||
struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
|
struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
|
||||||
struct sst_hsw *hsw = pdata->hsw;
|
struct sst_hsw *hsw = pdata->hsw;
|
||||||
snd_pcm_uframes_t offset;
|
snd_pcm_uframes_t offset;
|
||||||
|
uint64_t ppos;
|
||||||
|
u32 position = sst_hsw_get_dsp_position(hsw, pcm_data->stream);
|
||||||
|
|
||||||
offset = bytes_to_frames(runtime,
|
offset = bytes_to_frames(runtime, position);
|
||||||
sst_hsw_get_dsp_position(hsw, pcm_data->stream));
|
ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream);
|
||||||
|
|
||||||
dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n",
|
dev_dbg(rtd->dev, "PCM: DMA pointer %du bytes, pos %llu\n",
|
||||||
frames_to_bytes(runtime, (u32)offset));
|
position, ppos);
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,6 +636,7 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream)
|
||||||
dev_dbg(rtd->dev, "error: free stream failed %d\n", ret);
|
dev_dbg(rtd->dev, "error: free stream failed %d\n", ret);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
pcm_data->allocated = 0;
|
||||||
pcm_data->stream = NULL;
|
pcm_data->stream = NULL;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -621,7 +652,7 @@ static struct snd_pcm_ops hsw_pcm_ops = {
|
||||||
.hw_free = hsw_pcm_hw_free,
|
.hw_free = hsw_pcm_hw_free,
|
||||||
.trigger = hsw_pcm_trigger,
|
.trigger = hsw_pcm_trigger,
|
||||||
.pointer = hsw_pcm_pointer,
|
.pointer = hsw_pcm_pointer,
|
||||||
.mmap = snd_pcm_lib_default_mmap,
|
.page = snd_pcm_sgbuf_ops_page,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void hsw_pcm_free(struct snd_pcm *pcm)
|
static void hsw_pcm_free(struct snd_pcm *pcm)
|
||||||
|
@ -632,17 +663,16 @@ static void hsw_pcm_free(struct snd_pcm *pcm)
|
||||||
static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||||
{
|
{
|
||||||
struct snd_pcm *pcm = rtd->pcm;
|
struct snd_pcm *pcm = rtd->pcm;
|
||||||
|
struct snd_soc_platform *platform = rtd->platform;
|
||||||
|
struct sst_pdata *pdata = dev_get_platdata(platform->dev);
|
||||||
|
struct device *dev = pdata->dma_dev;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32));
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
|
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
|
||||||
pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
|
pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
|
||||||
ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
|
ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
|
||||||
SNDRV_DMA_TYPE_DEV,
|
SNDRV_DMA_TYPE_DEV_SG,
|
||||||
rtd->card->dev,
|
dev,
|
||||||
hsw_pcm_hardware.buffer_bytes_max,
|
hsw_pcm_hardware.buffer_bytes_max,
|
||||||
hsw_pcm_hardware.buffer_bytes_max);
|
hsw_pcm_hardware.buffer_bytes_max);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -742,11 +772,14 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
|
||||||
{
|
{
|
||||||
struct sst_pdata *pdata = dev_get_platdata(platform->dev);
|
struct sst_pdata *pdata = dev_get_platdata(platform->dev);
|
||||||
struct hsw_priv_data *priv_data;
|
struct hsw_priv_data *priv_data;
|
||||||
int i;
|
struct device *dma_dev;
|
||||||
|
int i, ret = 0;
|
||||||
|
|
||||||
if (!pdata)
|
if (!pdata)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
dma_dev = pdata->dma_dev;
|
||||||
|
|
||||||
priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL);
|
priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL);
|
||||||
priv_data->hsw = pdata->dsp;
|
priv_data->hsw = pdata->dsp;
|
||||||
snd_soc_platform_set_drvdata(platform, priv_data);
|
snd_soc_platform_set_drvdata(platform, priv_data);
|
||||||
|
@ -758,15 +791,17 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
|
||||||
|
|
||||||
/* playback */
|
/* playback */
|
||||||
if (hsw_dais[i].playback.channels_min) {
|
if (hsw_dais[i].playback.channels_min) {
|
||||||
priv_data->pcm_pg[i][0] = kzalloc(PAGE_SIZE, GFP_DMA);
|
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
|
||||||
if (priv_data->pcm_pg[i][0] == NULL)
|
PAGE_SIZE, &priv_data->dmab[i][0]);
|
||||||
|
if (ret < 0)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* capture */
|
/* capture */
|
||||||
if (hsw_dais[i].capture.channels_min) {
|
if (hsw_dais[i].capture.channels_min) {
|
||||||
priv_data->pcm_pg[i][1] = kzalloc(PAGE_SIZE, GFP_DMA);
|
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
|
||||||
if (priv_data->pcm_pg[i][1] == NULL)
|
PAGE_SIZE, &priv_data->dmab[i][1]);
|
||||||
|
if (ret < 0)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -776,11 +811,11 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
|
||||||
err:
|
err:
|
||||||
for (;i >= 0; i--) {
|
for (;i >= 0; i--) {
|
||||||
if (hsw_dais[i].playback.channels_min)
|
if (hsw_dais[i].playback.channels_min)
|
||||||
kfree(priv_data->pcm_pg[i][0]);
|
snd_dma_free_pages(&priv_data->dmab[i][0]);
|
||||||
if (hsw_dais[i].capture.channels_min)
|
if (hsw_dais[i].capture.channels_min)
|
||||||
kfree(priv_data->pcm_pg[i][1]);
|
snd_dma_free_pages(&priv_data->dmab[i][1]);
|
||||||
}
|
}
|
||||||
return -ENOMEM;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hsw_pcm_remove(struct snd_soc_platform *platform)
|
static int hsw_pcm_remove(struct snd_soc_platform *platform)
|
||||||
|
@ -791,9 +826,9 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform)
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
|
for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
|
||||||
if (hsw_dais[i].playback.channels_min)
|
if (hsw_dais[i].playback.channels_min)
|
||||||
kfree(priv_data->pcm_pg[i][0]);
|
snd_dma_free_pages(&priv_data->dmab[i][0]);
|
||||||
if (hsw_dais[i].capture.channels_min)
|
if (hsw_dais[i].capture.channels_min)
|
||||||
kfree(priv_data->pcm_pg[i][1]);
|
snd_dma_free_pages(&priv_data->dmab[i][1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -197,13 +197,12 @@ static void rsnd_dma_complete(void *data)
|
||||||
* rsnd_dai_pointer_update() will be called twice,
|
* rsnd_dai_pointer_update() will be called twice,
|
||||||
* ant it will breaks io->byte_pos
|
* ant it will breaks io->byte_pos
|
||||||
*/
|
*/
|
||||||
|
|
||||||
rsnd_dai_pointer_update(io, io->byte_per_period);
|
|
||||||
|
|
||||||
if (dma->submit_loop)
|
if (dma->submit_loop)
|
||||||
rsnd_dma_continue(dma);
|
rsnd_dma_continue(dma);
|
||||||
|
|
||||||
rsnd_unlock(priv, flags);
|
rsnd_unlock(priv, flags);
|
||||||
|
|
||||||
|
rsnd_dai_pointer_update(io, io->byte_per_period);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __rsnd_dma_start(struct rsnd_dma *dma)
|
static void __rsnd_dma_start(struct rsnd_dma *dma)
|
||||||
|
|
|
@ -1612,8 +1612,11 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
|
||||||
"ASoC: Failed to turn on bias: %d\n", ret);
|
"ASoC: Failed to turn on bias: %d\n", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prepare for a STADDBY->ON or ON->STANDBY transition */
|
/* Prepare for a transition to ON or away from ON */
|
||||||
if (d->bias_level != d->target_bias_level) {
|
if ((d->target_bias_level == SND_SOC_BIAS_ON &&
|
||||||
|
d->bias_level != SND_SOC_BIAS_ON) ||
|
||||||
|
(d->target_bias_level != SND_SOC_BIAS_ON &&
|
||||||
|
d->bias_level == SND_SOC_BIAS_ON)) {
|
||||||
ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
|
ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
dev_err(d->dev,
|
dev_err(d->dev,
|
||||||
|
@ -3475,8 +3478,11 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
|
||||||
cpu_dai = rtd->cpu_dai;
|
cpu_dai = rtd->cpu_dai;
|
||||||
codec_dai = rtd->codec_dai;
|
codec_dai = rtd->codec_dai;
|
||||||
|
|
||||||
/* dynamic FE links have no fixed DAI mapping */
|
/*
|
||||||
if (rtd->dai_link->dynamic)
|
* dynamic FE links have no fixed DAI mapping.
|
||||||
|
* CODEC<->CODEC links have no direct connection.
|
||||||
|
*/
|
||||||
|
if (rtd->dai_link->dynamic || rtd->dai_link->params)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* there is no point in connecting BE DAI links with dummies */
|
/* there is no point in connecting BE DAI links with dummies */
|
||||||
|
|
|
@ -1675,7 +1675,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
|
||||||
be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
|
be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
|
||||||
break;
|
break;
|
||||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||||
if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)
|
if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
|
if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
|
||||||
|
|
Loading…
Reference in New Issue