diff options
38 files changed, 331 insertions, 192 deletions
diff --git a/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt index ce55c0a..4da41bf 100644 --- a/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt +++ b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt @@ -30,6 +30,8 @@ The compatible list for this generic sound card currently: "fsl,imx-audio-sgtl5000" (compatible with Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt) + "fsl,imx-audio-wm8960" + Required properties: - compatible : Contains one of entries in the compatible list. diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index e2b712c..c21c38c 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -343,7 +343,7 @@ void snd_hdac_bus_enter_link_reset(struct hdac_bus *bus); void snd_hdac_bus_exit_link_reset(struct hdac_bus *bus); void snd_hdac_bus_update_rirb(struct hdac_bus *bus); -void snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status, +int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status, void (*ack)(struct hdac_bus *, struct hdac_stream *)); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index fadd3eb..9106d8e 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -74,6 +74,18 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream); static DEFINE_RWLOCK(snd_pcm_link_rwlock); static DECLARE_RWSEM(snd_pcm_link_rwsem); +/* Writer in rwsem may block readers even during its waiting in queue, + * and this may lead to a deadlock when the code path takes read sem + * twice (e.g. one in snd_pcm_action_nonatomic() and another in + * snd_pcm_stream_lock()). As a (suboptimal) workaround, let writer to + * spin until it gets the lock. + */ +static inline void down_write_nonblock(struct rw_semaphore *lock) +{ + while (!down_write_trylock(lock)) + cond_resched(); +} + /** * snd_pcm_stream_lock - Lock the PCM stream * @substream: PCM substream @@ -1813,7 +1825,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) res = -ENOMEM; goto _nolock; } - down_write(&snd_pcm_link_rwsem); + down_write_nonblock(&snd_pcm_link_rwsem); write_lock_irq(&snd_pcm_link_rwlock); if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || substream->runtime->status->state != substream1->runtime->status->state || @@ -1860,7 +1872,7 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream) struct snd_pcm_substream *s; int res = 0; - down_write(&snd_pcm_link_rwsem); + down_write_nonblock(&snd_pcm_link_rwsem); write_lock_irq(&snd_pcm_link_rwlock); if (!snd_pcm_stream_linked(substream)) { res = -EALREADY; diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index 8010766..c850345 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -383,15 +383,20 @@ int snd_seq_pool_init(struct snd_seq_pool *pool) if (snd_BUG_ON(!pool)) return -EINVAL; - if (pool->ptr) /* should be atomic? */ - return 0; - pool->ptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size); - if (!pool->ptr) + cellptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size); + if (!cellptr) return -ENOMEM; /* add new cells to the free cell list */ spin_lock_irqsave(&pool->lock, flags); + if (pool->ptr) { + spin_unlock_irqrestore(&pool->lock, flags); + vfree(cellptr); + return 0; + } + + pool->ptr = cellptr; pool->free = NULL; for (cell = 0; cell < pool->size; cell++) { diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 921fb2b..fe686ee 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -535,19 +535,22 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client, bool is_src, bool ack) { struct snd_seq_port_subs_info *grp; + struct list_head *list; + bool empty; grp = is_src ? &port->c_src : &port->c_dest; + list = is_src ? &subs->src_list : &subs->dest_list; down_write(&grp->list_mutex); write_lock_irq(&grp->list_lock); - if (is_src) - list_del(&subs->src_list); - else - list_del(&subs->dest_list); + empty = list_empty(list); + if (!empty) + list_del_init(list); grp->exclusive = 0; write_unlock_irq(&grp->list_lock); up_write(&grp->list_mutex); - unsubscribe_port(client, port, grp, &subs->info, ack); + if (!empty) + unsubscribe_port(client, port, grp, &subs->info, ack); } /* connect two ports */ diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index b5a17cb..8c48623 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -426,18 +426,22 @@ EXPORT_SYMBOL_GPL(snd_hdac_bus_stop_chip); * @bus: HD-audio core bus * @status: INTSTS register value * @ask: callback to be called for woken streams + * + * Returns the bits of handled streams, or zero if no stream is handled. */ -void snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status, +int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status, void (*ack)(struct hdac_bus *, struct hdac_stream *)) { struct hdac_stream *azx_dev; u8 sd_status; + int handled = 0; list_for_each_entry(azx_dev, &bus->stream_list, list) { if (status & azx_dev->sd_int_sta_mask) { sd_status = snd_hdac_stream_readb(azx_dev, SD_STS); snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); + handled |= 1 << azx_dev->index; if (!azx_dev->substream || !azx_dev->running || !(sd_status & SD_INT_COMPLETE)) continue; @@ -445,6 +449,7 @@ void snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status, ack(bus, azx_dev); } } + return handled; } EXPORT_SYMBOL_GPL(snd_hdac_bus_handle_stream_irq); diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 37cf9ce..27de801 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -930,6 +930,8 @@ irqreturn_t azx_interrupt(int irq, void *dev_id) struct azx *chip = dev_id; struct hdac_bus *bus = azx_bus(chip); u32 status; + bool active, handled = false; + int repeat = 0; /* count for avoiding endless loop */ #ifdef CONFIG_PM if (azx_has_pm_runtime(chip)) @@ -939,33 +941,36 @@ irqreturn_t azx_interrupt(int irq, void *dev_id) spin_lock(&bus->reg_lock); - if (chip->disabled) { - spin_unlock(&bus->reg_lock); - return IRQ_NONE; - } - - status = azx_readl(chip, INTSTS); - if (status == 0 || status == 0xffffffff) { - spin_unlock(&bus->reg_lock); - return IRQ_NONE; - } + if (chip->disabled) + goto unlock; - snd_hdac_bus_handle_stream_irq(bus, status, stream_update); + do { + status = azx_readl(chip, INTSTS); + if (status == 0 || status == 0xffffffff) + break; - /* clear rirb int */ - status = azx_readb(chip, RIRBSTS); - if (status & RIRB_INT_MASK) { - if (status & RIRB_INT_RESPONSE) { - if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) - udelay(80); - snd_hdac_bus_update_rirb(bus); + handled = true; + active = false; + if (snd_hdac_bus_handle_stream_irq(bus, status, stream_update)) + active = true; + + /* clear rirb int */ + status = azx_readb(chip, RIRBSTS); + if (status & RIRB_INT_MASK) { + active = true; + if (status & RIRB_INT_RESPONSE) { + if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) + udelay(80); + snd_hdac_bus_update_rirb(bus); + } + azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); } - azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); - } + } while (active && ++repeat < 10); + unlock: spin_unlock(&bus->reg_lock); - return IRQ_HANDLED; + return IRQ_RETVAL(handled); } EXPORT_SYMBOL_GPL(azx_interrupt); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 4179710..2624cfe 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -363,7 +363,10 @@ enum { ((pci)->device == 0x0d0c) || \ ((pci)->device == 0x160c)) -#define IS_BROXTON(pci) ((pci)->device == 0x5a98) +#define IS_SKL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa170) +#define IS_SKL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d70) +#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) +#define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci)) static char *driver_short_names[] = { [AZX_DRIVER_ICH] = "HDA Intel", @@ -540,13 +543,13 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) snd_hdac_set_codec_wakeup(bus, true); - if (IS_BROXTON(pci)) { + if (IS_SKL_PLUS(pci)) { pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val); val = val & ~INTEL_HDA_CGCTL_MISCBDCGE; pci_write_config_dword(pci, INTEL_HDA_CGCTL, val); } azx_init_chip(chip, full_reset); - if (IS_BROXTON(pci)) { + if (IS_SKL_PLUS(pci)) { pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val); val = val | INTEL_HDA_CGCTL_MISCBDCGE; pci_write_config_dword(pci, INTEL_HDA_CGCTL, val); @@ -555,7 +558,7 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) snd_hdac_set_codec_wakeup(bus, false); /* reduce dma latency to avoid noise */ - if (IS_BROXTON(pci)) + if (IS_BXT(pci)) bxt_reduce_dma_latency(chip); } @@ -977,11 +980,6 @@ static int azx_resume(struct device *dev) /* put codec down to D3 at hibernation for Intel SKL+; * otherwise BIOS may still access the codec and screw up the driver */ -#define IS_SKL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa170) -#define IS_SKL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d70) -#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) -#define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci)) - static int azx_freeze_noirq(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); @@ -2168,10 +2166,10 @@ static void azx_remove(struct pci_dev *pci) struct hda_intel *hda; if (card) { - /* flush the pending probing work */ + /* cancel the pending probing work */ chip = card->private_data; hda = container_of(chip, struct hda_intel, chip); - flush_work(&hda->probe_work); + cancel_work_sync(&hda->probe_work); snd_card_free(card); } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index efd4980..1f357cd 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3801,6 +3801,10 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, static void alc_headset_mode_default(struct hda_codec *codec) { + static struct coef_fw coef0225[] = { + UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10), + {} + }; static struct coef_fw coef0255[] = { WRITE_COEF(0x45, 0xc089), WRITE_COEF(0x45, 0xc489), @@ -3842,6 +3846,9 @@ static void alc_headset_mode_default(struct hda_codec *codec) }; switch (codec->core.vendor_id) { + case 0x10ec0225: + alc_process_coef_fw(codec, coef0225); + break; case 0x10ec0255: case 0x10ec0256: alc_process_coef_fw(codec, coef0255); @@ -4749,6 +4756,9 @@ enum { ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE, ALC293_FIXUP_LENOVO_SPK_NOISE, ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, + ALC255_FIXUP_DELL_SPK_NOISE, + ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC280_FIXUP_HP_HEADSET_MIC, }; static const struct hda_fixup alc269_fixups[] = { @@ -5368,6 +5378,29 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc233_fixup_lenovo_line2_mic_hotkey, }, + [ALC255_FIXUP_DELL_SPK_NOISE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_disable_aamix, + .chained = true, + .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE + }, + [ALC225_FIXUP_DELL1_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* Disable pass-through path for FRONT 14h */ + { 0x20, AC_VERB_SET_COEF_INDEX, 0x36 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x57d7 }, + {} + }, + .chained = true, + .chain_id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE + }, + [ALC280_FIXUP_HP_HEADSET_MIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_disable_aamix, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MIC, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -5410,6 +5443,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK), SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK), SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), + SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE), SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), @@ -5470,6 +5504,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), @@ -5638,10 +5673,10 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {0x21, 0x03211020} static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { - SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, ALC225_STANDARD_PINS, {0x14, 0x901701a0}), - SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, ALC225_STANDARD_PINS, {0x14, 0x901701b0}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index 3191e0a..d1fb035 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -635,6 +635,7 @@ static int acp_dma_open(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) { dev_err(prtd->platform->dev, "set integer constraint failed\n"); + kfree(adata); return ret; } diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 33143fe..9178531 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1929,6 +1929,25 @@ static struct { { 1000000, 13500000, 0, 1 }, }; +static const unsigned int pseudo_fref_max[ARIZONA_FLL_MAX_FRATIO] = { + 13500000, + 6144000, + 6144000, + 3072000, + 3072000, + 2822400, + 2822400, + 1536000, + 1536000, + 1536000, + 1536000, + 1536000, + 1536000, + 1536000, + 1536000, + 768000, +}; + static struct { unsigned int min; unsigned int max; @@ -2042,16 +2061,32 @@ static int arizona_calc_fratio(struct arizona_fll *fll, /* Adjust FRATIO/refdiv to avoid integer mode if possible */ refdiv = cfg->refdiv; + arizona_fll_dbg(fll, "pseudo: initial ratio=%u fref=%u refdiv=%u\n", + init_ratio, Fref, refdiv); + while (div <= ARIZONA_FLL_MAX_REFDIV) { for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO; ratio++) { if ((ARIZONA_FLL_VCO_CORNER / 2) / - (fll->vco_mult * ratio) < Fref) + (fll->vco_mult * ratio) < Fref) { + arizona_fll_dbg(fll, "pseudo: hit VCO corner\n"); break; + } + + if (Fref > pseudo_fref_max[ratio - 1]) { + arizona_fll_dbg(fll, + "pseudo: exceeded max fref(%u) for ratio=%u\n", + pseudo_fref_max[ratio - 1], + ratio); + break; + } if (target % (ratio * Fref)) { cfg->refdiv = refdiv; cfg->fratio = ratio - 1; + arizona_fll_dbg(fll, + "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n", + Fref, refdiv, div, ratio); return ratio; } } @@ -2060,6 +2095,9 @@ static int arizona_calc_fratio(struct arizona_fll *fll, if (target % (ratio * Fref)) { cfg->refdiv = refdiv; cfg->fratio = ratio - 1; + arizona_fll_dbg(fll, + "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n", + Fref, refdiv, div, ratio); return ratio; } } @@ -2068,6 +2106,9 @@ static int arizona_calc_fratio(struct arizona_fll *fll, Fref /= 2; refdiv++; init_ratio = arizona_find_fratio(Fref, NULL); + arizona_fll_dbg(fll, + "pseudo: change fref=%u refdiv=%d(%d) ratio=%u\n", + Fref, refdiv, div, init_ratio); } arizona_fll_warn(fll, "Falling back to integer mode operation\n"); diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index bc08f0c..1bd3164 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -266,6 +266,8 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) } else { *mic = false; regmap_write(rt286->regmap, RT286_SET_MIC1, 0x20); + regmap_update_bits(rt286->regmap, + RT286_CBJ_CTRL1, 0x0400, 0x0000); } } else { regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf); @@ -470,24 +472,6 @@ static int rt286_set_dmic1_event(struct snd_soc_dapm_widget *w, return 0; } -static int rt286_vref_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - snd_soc_update_bits(codec, - RT286_CBJ_CTRL1, 0x0400, 0x0000); - mdelay(50); - break; - default: - return 0; - } - - return 0; -} - static int rt286_ldo2_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -536,7 +520,7 @@ static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY_S("HV", 1, RT286_POWER_CTRL1, 12, 1, NULL, 0), SND_SOC_DAPM_SUPPLY("VREF", RT286_POWER_CTRL1, - 0, 1, rt286_vref_event, SND_SOC_DAPM_PRE_PMU), + 0, 1, NULL, 0), SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT286_POWER_CTRL2, 2, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("LDO2", 2, RT286_POWER_CTRL1, @@ -911,8 +895,6 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_ON: mdelay(10); snd_soc_update_bits(codec, - RT286_CBJ_CTRL1, 0x0400, 0x0400); - snd_soc_update_bits(codec, RT286_DC_GAIN, 0x200, 0x0); break; @@ -920,8 +902,6 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_STANDBY: snd_soc_write(codec, RT286_SET_AUDIO_POWER, AC_PWRST_D3); - snd_soc_update_bits(codec, - RT286_CBJ_CTRL1, 0x0400, 0x0000); break; default: diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index c61d38b..93e8c90 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -776,7 +776,7 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = { /* IN1/IN2 Control */ SOC_SINGLE_TLV("IN1 Boost", RT5645_IN1_CTRL1, - RT5645_BST_SFT1, 8, 0, bst_tlv), + RT5645_BST_SFT1, 12, 0, bst_tlv), SOC_SINGLE_TLV("IN2 Boost", RT5645_IN2_CTRL, RT5645_BST_SFT2, 8, 0, bst_tlv), diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c index 820d8fa..fb8ea05 100644 --- a/sound/soc/codecs/rt5659.c +++ b/sound/soc/codecs/rt5659.c @@ -3985,7 +3985,6 @@ static int rt5659_i2c_probe(struct i2c_client *i2c, if (rt5659 == NULL) return -ENOMEM; - rt5659->i2c = i2c; i2c_set_clientdata(i2c, rt5659); if (pdata) @@ -4157,24 +4156,17 @@ static int rt5659_i2c_probe(struct i2c_client *i2c, INIT_DELAYED_WORK(&rt5659->jack_detect_work, rt5659_jack_detect_work); - if (rt5659->i2c->irq) { - ret = request_threaded_irq(rt5659->i2c->irq, NULL, rt5659_irq, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING + if (i2c->irq) { + ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, + rt5659_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "rt5659", rt5659); if (ret) dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); } - ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5659, + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5659, rt5659_dai, ARRAY_SIZE(rt5659_dai)); - - if (ret) { - if (rt5659->i2c->irq) - free_irq(rt5659->i2c->irq, rt5659); - } - - return 0; } static int rt5659_i2c_remove(struct i2c_client *i2c) @@ -4191,24 +4183,29 @@ void rt5659_i2c_shutdown(struct i2c_client *client) regmap_write(rt5659->regmap, RT5659_RESET, 0); } +#ifdef CONFIG_OF static const struct of_device_id rt5659_of_match[] = { { .compatible = "realtek,rt5658", }, { .compatible = "realtek,rt5659", }, - {}, + { }, }; +MODULE_DEVICE_TABLE(of, rt5659_of_match); +#endif +#ifdef CONFIG_ACPI static struct acpi_device_id rt5659_acpi_match[] = { - { "10EC5658", 0}, - { "10EC5659", 0}, - { }, + { "10EC5658", 0, }, + { "10EC5659", 0, }, + { }, }; MODULE_DEVICE_TABLE(acpi, rt5659_acpi_match); +#endif struct i2c_driver rt5659_i2c_driver = { .driver = { .name = "rt5659", .owner = THIS_MODULE, - .of_match_table = rt5659_of_match, + .of_match_table = of_match_ptr(rt5659_of_match), .acpi_match_table = ACPI_PTR(rt5659_acpi_match), }, .probe = rt5659_i2c_probe, diff --git a/sound/soc/codecs/rt5659.h b/sound/soc/codecs/rt5659.h index 8f07ee9..d31c9e5 100644 --- a/sound/soc/codecs/rt5659.h +++ b/sound/soc/codecs/rt5659.h @@ -1792,7 +1792,6 @@ struct rt5659_priv { struct snd_soc_codec *codec; struct rt5659_platform_data pdata; struct regmap *regmap; - struct i2c_client *i2c; struct gpio_desc *gpiod_ldo1_en; struct gpio_desc *gpiod_reset; struct snd_soc_jack *hs_jack; diff --git a/sound/soc/codecs/sigmadsp-i2c.c b/sound/soc/codecs/sigmadsp-i2c.c index 21ca3a5..d374c18 100644 --- a/sound/soc/codecs/sigmadsp-i2c.c +++ b/sound/soc/codecs/sigmadsp-i2c.c @@ -31,7 +31,10 @@ static int sigmadsp_write_i2c(void *control_data, kfree(buf); - return ret; + if (ret < 0) + return ret; + + return 0; } static int sigmadsp_read_i2c(void *control_data, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 6088d30..97c0f1e 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2382,6 +2382,7 @@ error: static int wm5110_remove(struct platform_device *pdev) { + snd_soc_unregister_platform(&pdev->dev); snd_soc_unregister_codec(&pdev->dev); pm_runtime_disable(&pdev->dev); diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index ff23772..d7f444f 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -240,13 +240,13 @@ SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL, SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL, 7, 1, 1), -SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume", +SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT3 Volume", WM8960_INBMIX1, 4, 7, 0, lineinboost_tlv), -SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT2 Volume", +SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT2 Volume", WM8960_INBMIX1, 1, 7, 0, lineinboost_tlv), -SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT3 Volume", +SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume", WM8960_INBMIX2, 4, 7, 0, lineinboost_tlv), -SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT2 Volume", +SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT2 Volume", WM8960_INBMIX2, 1, 7, 0, lineinboost_tlv), SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT1 Volume", WM8960_RINPATH, 4, 3, 0, micboost_tlv), @@ -643,29 +643,31 @@ static int wm8960_configure_clocking(struct snd_soc_codec *codec) return -EINVAL; } - /* check if the sysclk frequency is available. */ - for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) { - if (sysclk_divs[i] == -1) - continue; - sysclk = freq_out / sysclk_divs[i]; - for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) { - if (sysclk == dac_divs[j] * lrclk) { + if (wm8960->clk_id != WM8960_SYSCLK_PLL) { + /* check if the sysclk frequency is available. */ + for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) { + if (sysclk_divs[i] == -1) + continue; + sysclk = freq_out / sysclk_divs[i]; + for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) { + if (sysclk != dac_divs[j] * lrclk) + continue; for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) if (sysclk == bclk * bclk_divs[k] / 10) break; if (k != ARRAY_SIZE(bclk_divs)) break; } + if (j != ARRAY_SIZE(dac_divs)) + break; } - if (j != ARRAY_SIZE(dac_divs)) - break; - } - if (i != ARRAY_SIZE(sysclk_divs)) { - goto configure_clock; - } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) { - dev_err(codec->dev, "failed to configure clock\n"); - return -EINVAL; + if (i != ARRAY_SIZE(sysclk_divs)) { + goto configure_clock; + } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) { + dev_err(codec->dev, "failed to configure clock\n"); + return -EINVAL; + } } /* get a available pll out frequency and set pll */ for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) { diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index ce664c2..bff258d 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -645,6 +645,8 @@ static int dw_i2s_probe(struct platform_device *pdev) dev->dev = &pdev->dev; + dev->i2s_reg_comp1 = I2S_COMP_PARAM_1; + dev->i2s_reg_comp2 = I2S_COMP_PARAM_2; if (pdata) { dev->capability = pdata->cap; clk_id = NULL; @@ -652,9 +654,6 @@ static int dw_i2s_probe(struct platform_device *pdev) if (dev->quirks & DW_I2S_QUIRK_COMP_REG_OFFSET) { dev->i2s_reg_comp1 = pdata->i2s_reg_comp1; dev->i2s_reg_comp2 = pdata->i2s_reg_comp2; - } else { - dev->i2s_reg_comp1 = I2S_COMP_PARAM_1; - dev->i2s_reg_comp2 = I2S_COMP_PARAM_2; } ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata); } else { diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 40dfd8a..ed8de10 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -112,20 +112,6 @@ struct fsl_ssi_rxtx_reg_val { struct fsl_ssi_reg_val tx; }; -static const struct reg_default fsl_ssi_reg_defaults[] = { - {CCSR_SSI_SCR, 0x00000000}, - {CCSR_SSI_SIER, 0x00003003}, - {CCSR_SSI_STCR, 0x00000200}, - {CCSR_SSI_SRCR, 0x00000200}, - {CCSR_SSI_STCCR, 0x00040000}, - {CCSR_SSI_SRCCR, 0x00040000}, - {CCSR_SSI_SACNT, 0x00000000}, - {CCSR_SSI_STMSK, 0x00000000}, - {CCSR_SSI_SRMSK, 0x00000000}, - {CCSR_SSI_SACCEN, 0x00000000}, - {CCSR_SSI_SACCDIS, 0x00000000}, -}; - static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -190,8 +176,7 @@ static const struct regmap_config fsl_ssi_regconfig = { .val_bits = 32, .reg_stride = 4, .val_format_endian = REGMAP_ENDIAN_NATIVE, - .reg_defaults = fsl_ssi_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(fsl_ssi_reg_defaults), + .num_reg_defaults_raw = CCSR_SSI_SACCDIS / sizeof(uint32_t) + 1, .readable_reg = fsl_ssi_readable_reg, .volatile_reg = fsl_ssi_volatile_reg, .precious_reg = fsl_ssi_precious_reg, @@ -201,6 +186,7 @@ static const struct regmap_config fsl_ssi_regconfig = { struct fsl_ssi_soc_data { bool imx; + bool imx21regs; /* imx21-class SSI - no SACC{ST,EN,DIS} regs */ bool offline_config; u32 sisr_write_mask; }; @@ -303,6 +289,7 @@ static struct fsl_ssi_soc_data fsl_ssi_mpc8610 = { static struct fsl_ssi_soc_data fsl_ssi_imx21 = { .imx = true, + .imx21regs = true, .offline_config = true, .sisr_write_mask = 0, }; @@ -586,8 +573,12 @@ static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private) */ regmap_write(regs, CCSR_SSI_SACNT, CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV); - regmap_write(regs, CCSR_SSI_SACCDIS, 0xff); - regmap_write(regs, CCSR_SSI_SACCEN, 0x300); + + /* no SACC{ST,EN,DIS} regs on imx21-class SSI */ + if (!ssi_private->soc->imx21regs) { + regmap_write(regs, CCSR_SSI_SACCDIS, 0xff); + regmap_write(regs, CCSR_SSI_SACCEN, 0x300); + } /* * Enable SSI, Transmit and Receive. AC97 has to communicate with the @@ -1397,6 +1388,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) struct resource *res; void __iomem *iomem; char name[64]; + struct regmap_config regconfig = fsl_ssi_regconfig; of_id = of_match_device(fsl_ssi_ids, &pdev->dev); if (!of_id || !of_id->data) @@ -1444,15 +1436,25 @@ static int fsl_ssi_probe(struct platform_device *pdev) return PTR_ERR(iomem); ssi_private->ssi_phys = res->start; + if (ssi_private->soc->imx21regs) { + /* + * According to datasheet imx21-class SSI + * don't have SACC{ST,EN,DIS} regs. + */ + regconfig.max_register = CCSR_SSI_SRMSK; + regconfig.num_reg_defaults_raw = + CCSR_SSI_SRMSK / sizeof(uint32_t) + 1; + } + ret = of_property_match_string(np, "clock-names", "ipg"); if (ret < 0) { ssi_private->has_ipg_clk_name = false; ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem, - &fsl_ssi_regconfig); + ®config); } else { ssi_private->has_ipg_clk_name = true; ssi_private->regs = devm_regmap_init_mmio_clk(&pdev->dev, - "ipg", iomem, &fsl_ssi_regconfig); + "ipg", iomem, ®config); } if (IS_ERR(ssi_private->regs)) { dev_err(&pdev->dev, "Failed to init register map\n"); diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c index a407e83..fb896b2 100644 --- a/sound/soc/fsl/imx-spdif.c +++ b/sound/soc/fsl/imx-spdif.c @@ -72,8 +72,6 @@ static int imx_spdif_audio_probe(struct platform_device *pdev) goto end; } - platform_set_drvdata(pdev, data); - end: of_node_put(spdif_np); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 1ded881..2389ab4 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -99,7 +99,7 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, if (ret && ret != -ENOTSUPP) goto err; } - + return 0; err: return ret; } diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 803f95e..7d7c872 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -30,11 +30,15 @@ config SND_SST_IPC_ACPI config SND_SOC_INTEL_SST tristate select SND_SOC_INTEL_SST_ACPI if ACPI + select SND_SOC_INTEL_SST_MATCH if ACPI depends on (X86 || COMPILE_TEST) config SND_SOC_INTEL_SST_ACPI tristate +config SND_SOC_INTEL_SST_MATCH + tristate + config SND_SOC_INTEL_HASWELL tristate @@ -57,7 +61,7 @@ config SND_SOC_INTEL_HASWELL_MACH config SND_SOC_INTEL_BYT_RT5640_MACH tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" depends on X86_INTEL_LPSS && I2C - depends on DW_DMAC_CORE=y && (SND_SOC_INTEL_BYTCR_RT5640_MACH = n) + depends on DW_DMAC_CORE=y && (SND_SST_IPC_ACPI = n) select SND_SOC_INTEL_SST select SND_SOC_INTEL_BAYTRAIL select SND_SOC_RT5640 @@ -69,7 +73,7 @@ config SND_SOC_INTEL_BYT_RT5640_MACH config SND_SOC_INTEL_BYT_MAX98090_MACH tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" depends on X86_INTEL_LPSS && I2C - depends on DW_DMAC_CORE=y + depends on DW_DMAC_CORE=y && (SND_SST_IPC_ACPI = n) select SND_SOC_INTEL_SST select SND_SOC_INTEL_BAYTRAIL select SND_SOC_MAX98090 @@ -97,6 +101,7 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH select SND_SOC_RT5640 select SND_SST_MFLD_PLATFORM select SND_SST_IPC_ACPI + select SND_SOC_INTEL_SST_MATCH if ACPI help This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR platforms with RT5640 audio codec. @@ -109,6 +114,7 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH select SND_SOC_RT5651 select SND_SST_MFLD_PLATFORM select SND_SST_IPC_ACPI + select SND_SOC_INTEL_SST_MATCH if ACPI help This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR platforms with RT5651 audio codec. @@ -121,6 +127,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH select SND_SOC_RT5670 select SND_SST_MFLD_PLATFORM select SND_SST_IPC_ACPI + select SND_SOC_INTEL_SST_MATCH if ACPI help This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell platforms with RT5672 audio codec. @@ -133,6 +140,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH select SND_SOC_RT5645 select SND_SST_MFLD_PLATFORM select SND_SST_IPC_ACPI + select SND_SOC_INTEL_SST_MATCH if ACPI help This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell platforms with RT5645/5650 audio codec. @@ -145,6 +153,7 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH select SND_SOC_TS3A227E select SND_SST_MFLD_PLATFORM select SND_SST_IPC_ACPI + select SND_SOC_INTEL_SST_MATCH if ACPI help This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell platforms with MAX98090 audio codec it also can support TI jack chip as aux device. diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 55c33dc..52ed434 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -528,6 +528,7 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { .ops = &sst_compr_dai_ops, .playback = { .stream_name = "Compress Playback", + .channels_min = 1, }, }, /* BE CPU Dais */ diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 7396ddb..2cbcbe4 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -212,7 +212,10 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, { struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - channels->min = channels->max = 4; + if (params_channels(params) == 2) + channels->min = channels->max = 2; + else + channels->min = channels->max = 4; return 0; } diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 668fdee..fbbb25c 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -1,13 +1,10 @@ snd-soc-sst-dsp-objs := sst-dsp.o -ifneq ($(CONFIG_SND_SST_IPC_ACPI),) -snd-soc-sst-acpi-objs := sst-match-acpi.o -else -snd-soc-sst-acpi-objs := sst-acpi.o sst-match-acpi.o -endif - +snd-soc-sst-acpi-objs := sst-acpi.o +snd-soc-sst-match-objs := sst-match-acpi.o snd-soc-sst-ipc-objs := sst-ipc.o snd-soc-sst-dsp-$(CONFIG_DW_DMAC_CORE) += sst-firmware.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o +obj-$(CONFIG_SND_SOC_INTEL_SST_MATCH) += snd-soc-sst-match.o diff --git a/sound/soc/intel/common/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c index 7a85c57..2c5eda1 100644 --- a/sound/soc/intel/common/sst-acpi.c +++ b/sound/soc/intel/common/sst-acpi.c @@ -215,6 +215,7 @@ static struct sst_acpi_desc sst_acpi_broadwell_desc = { .dma_size = SST_LPT_DSP_DMA_SIZE, }; +#if !IS_ENABLED(CONFIG_SND_SST_IPC_ACPI) static struct sst_acpi_mach baytrail_machines[] = { { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL }, { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL }, @@ -231,11 +232,14 @@ static struct sst_acpi_desc sst_acpi_baytrail_desc = { .sst_id = SST_DEV_ID_BYT, .resindex_dma_base = -1, }; +#endif static const struct acpi_device_id sst_acpi_match[] = { { "INT33C8", (unsigned long)&sst_acpi_haswell_desc }, { "INT3438", (unsigned long)&sst_acpi_broadwell_desc }, +#if !IS_ENABLED(CONFIG_SND_SST_IPC_ACPI) { "80860F28", (unsigned long)&sst_acpi_baytrail_desc }, +#endif { } }; MODULE_DEVICE_TABLE(acpi, sst_acpi_match); diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c index dd077e1..3b4539d 100644 --- a/sound/soc/intel/common/sst-match-acpi.c +++ b/sound/soc/intel/common/sst-match-acpi.c @@ -41,3 +41,6 @@ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines) return NULL; } EXPORT_SYMBOL_GPL(sst_acpi_find_machine); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index de6dac4..4629372 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -688,14 +688,14 @@ int skl_unbind_modules(struct skl_sst *ctx, /* get src queue index */ src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max); if (src_index < 0) - return -EINVAL; + return 0; msg.src_queue = src_index; /* get dst queue index */ dst_index = skl_get_queue_index(dst_mcfg->m_in_pin, src_id, in_max); if (dst_index < 0) - return -EINVAL; + return 0; msg.dst_queue = dst_index; @@ -747,7 +747,7 @@ int skl_bind_modules(struct skl_sst *ctx, skl_dump_bind_info(ctx, src_mcfg, dst_mcfg); - if (src_mcfg->m_state < SKL_MODULE_INIT_DONE && + if (src_mcfg->m_state < SKL_MODULE_INIT_DONE || dst_mcfg->m_state < SKL_MODULE_INIT_DONE) return 0; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index f355325..b6e6b61 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -863,6 +863,7 @@ static int skl_get_delay_from_lpib(struct hdac_ext_bus *ebus, else delay += hstream->bufsize; } + delay = (hstream->bufsize == delay) ? 0 : delay; if (delay >= hstream->period_bytes) { dev_info(bus->dev, diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 4624556..a294fee 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -54,12 +54,9 @@ static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w) /* * Each pipelines needs memory to be allocated. Check if we have free memory - * from available pool. Then only add this to pool - * This is freed when pipe is deleted - * Note: DSP does actual memory management we only keep track for complete - * pool + * from available pool. */ -static bool skl_tplg_alloc_pipe_mem(struct skl *skl, +static bool skl_is_pipe_mem_avail(struct skl *skl, struct skl_module_cfg *mconfig) { struct skl_sst *ctx = skl->skl_sst; @@ -74,10 +71,20 @@ static bool skl_tplg_alloc_pipe_mem(struct skl *skl, "exceeds ppl memory available %d mem %d\n", skl->resource.max_mem, skl->resource.mem); return false; + } else { + return true; } +} +/* + * Add the mem to the mem pool. This is freed when pipe is deleted. + * Note: DSP does actual memory management we only keep track for complete + * pool + */ +static void skl_tplg_alloc_pipe_mem(struct skl *skl, + struct skl_module_cfg *mconfig) +{ skl->resource.mem += mconfig->pipe->memory_pages; - return true; } /* @@ -85,10 +92,10 @@ static bool skl_tplg_alloc_pipe_mem(struct skl *skl, * quantified in MCPS (Million Clocks Per Second) required for module/pipe * * Each pipelines needs mcps to be allocated. Check if we have mcps for this - * pipe. This adds the mcps to driver counter - * This is removed on pipeline delete + * pipe. */ -static bool skl_tplg_alloc_pipe_mcps(struct skl *skl, + +static bool skl_is_pipe_mcps_avail(struct skl *skl, struct skl_module_cfg *mconfig) { struct skl_sst *ctx = skl->skl_sst; @@ -98,13 +105,18 @@ static bool skl_tplg_alloc_pipe_mcps(struct skl *skl, "%s: module_id %d instance %d\n", __func__, mconfig->id.module_id, mconfig->id.instance_id); dev_err(ctx->dev, - "exceeds ppl memory available %d > mem %d\n", + "exceeds ppl mcps available %d > mem %d\n", skl->resource.max_mcps, skl->resource.mcps); return false; + } else { + return true; } +} +static void skl_tplg_alloc_pipe_mcps(struct skl *skl, + struct skl_module_cfg *mconfig) +{ skl->resource.mcps += mconfig->mcps; - return true; } /* @@ -411,7 +423,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) mconfig = w->priv; /* check resource available */ - if (!skl_tplg_alloc_pipe_mcps(skl, mconfig)) + if (!skl_is_pipe_mcps_avail(skl, mconfig)) return -ENOMEM; if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) { @@ -435,6 +447,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) ret = skl_tplg_set_module_params(w, ctx); if (ret < 0) return ret; + skl_tplg_alloc_pipe_mcps(skl, mconfig); } return 0; @@ -477,10 +490,10 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, struct skl_sst *ctx = skl->skl_sst; /* check resource available */ - if (!skl_tplg_alloc_pipe_mcps(skl, mconfig)) + if (!skl_is_pipe_mcps_avail(skl, mconfig)) return -EBUSY; - if (!skl_tplg_alloc_pipe_mem(skl, mconfig)) + if (!skl_is_pipe_mem_avail(skl, mconfig)) return -ENOMEM; /* @@ -526,11 +539,15 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, src_module = dst_module; } + skl_tplg_alloc_pipe_mem(skl, mconfig); + skl_tplg_alloc_pipe_mcps(skl, mconfig); + return 0; } static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, struct skl *skl, + struct snd_soc_dapm_widget *src_w, struct skl_module_cfg *src_mconfig) { struct snd_soc_dapm_path *p; @@ -547,6 +564,10 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name); next_sink = p->sink; + + if (!is_skl_dsp_widget_type(p->sink)) + return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig); + /* * here we will check widgets in sink pipelines, so that * can be any widgets type and we are only interested if @@ -576,7 +597,7 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, } if (!sink) - return skl_tplg_bind_sinks(next_sink, skl, src_mconfig); + return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig); return 0; } @@ -605,7 +626,7 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, * if sink is not started, start sink pipe first, then start * this pipe */ - ret = skl_tplg_bind_sinks(w, skl, src_mconfig); + ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig); if (ret) return ret; @@ -773,10 +794,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, continue; } - ret = skl_unbind_modules(ctx, src_module, dst_module); - if (ret < 0) - return ret; - + skl_unbind_modules(ctx, src_module, dst_module); src_module = dst_module; } @@ -814,9 +832,6 @@ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, * This is a connecter and if path is found that means * unbind between source and sink has not happened yet */ - ret = skl_stop_pipe(ctx, sink_mconfig->pipe); - if (ret < 0) - return ret; ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig); } @@ -842,6 +857,12 @@ static int skl_tplg_vmixer_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_PRE_PMU: return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); + case SND_SOC_DAPM_POST_PMU: + return skl_tplg_mixer_dapm_post_pmu_event(w, skl); + + case SND_SOC_DAPM_PRE_PMD: + return skl_tplg_mixer_dapm_pre_pmd_event(w, skl); + case SND_SOC_DAPM_POST_PMD: return skl_tplg_mixer_dapm_post_pmd_event(w, skl); } @@ -916,6 +937,13 @@ static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, skl_get_module_params(skl->skl_sst, (u32 *)bc->params, bc->max, bc->param_id, mconfig); + /* decrement size for TLV header */ + size -= 2 * sizeof(u32); + + /* check size as we don't want to send kernel data */ + if (size > bc->max) + size = bc->max; + if (bc->params) { if (copy_to_user(data, &bc->param_id, sizeof(u32))) return -EFAULT; @@ -1510,6 +1538,7 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus) &skl_tplg_ops, fw, 0); if (ret < 0) { dev_err(bus->dev, "tplg component load failed%d\n", ret); + release_firmware(fw); return -EINVAL; } diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 443a15d..092705e 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -614,8 +614,6 @@ static int skl_probe(struct pci_dev *pci, goto out_unregister; /*configure PM */ - pm_runtime_set_autosuspend_delay(bus->dev, SKL_SUSPEND_DELAY); - pm_runtime_use_autosuspend(bus->dev); pm_runtime_put_noidle(bus->dev); pm_runtime_allow(bus->dev); diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 15c04e2..9769676 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -9,7 +9,7 @@ config SND_SOC_MEDIATEK config SND_SOC_MT8173_MAX98090 tristate "ASoC Audio driver for MT8173 with MAX98090 codec" - depends on SND_SOC_MEDIATEK + depends on SND_SOC_MEDIATEK && I2C select SND_SOC_MAX98090 help This adds ASoC driver for Mediatek MT8173 boards @@ -19,7 +19,7 @@ config SND_SOC_MT8173_MAX98090 config SND_SOC_MT8173_RT5650_RT5676 tristate "ASoC Audio driver for MT8173 with RT5650 RT5676 codecs" - depends on SND_SOC_MEDIATEK + depends on SND_SOC_MEDIATEK && I2C select SND_SOC_RT5645 select SND_SOC_RT5677 help diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index c866ade..a6c7b8d 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -381,9 +381,19 @@ static int mxs_saif_startup(struct snd_pcm_substream *substream, __raw_writel(BM_SAIF_CTRL_CLKGATE, saif->base + SAIF_CTRL + MXS_CLR_ADDR); + clk_prepare(saif->clk); + return 0; } +static void mxs_saif_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai); + + clk_unprepare(saif->clk); +} + /* * Should only be called when port is inactive. * although can be called multiple times by upper layers. @@ -424,8 +434,6 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream, return ret; } - /* prepare clk in hw_param, enable in trigger */ - clk_prepare(saif->clk); if (saif != master_saif) { /* * Set an initial clock rate for the saif internal logic to work @@ -611,6 +619,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd, static const struct snd_soc_dai_ops mxs_saif_dai_ops = { .startup = mxs_saif_startup, + .shutdown = mxs_saif_shutdown, .trigger = mxs_saif_trigger, .prepare = mxs_saif_prepare, .hw_params = mxs_saif_hw_params, diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 79688aa..4aeb8e1 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -440,18 +440,18 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) } static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream, - struct snd_soc_pcm_runtime *soc_runtime) + struct snd_soc_pcm_runtime *rt) { struct snd_dma_buffer *buf = &substream->dma_buffer; size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = soc_runtime->dev; + buf->dev.dev = rt->platform->dev; buf->private_data = NULL; - buf->area = dma_alloc_coherent(soc_runtime->dev, size, &buf->addr, + buf->area = dma_alloc_coherent(rt->platform->dev, size, &buf->addr, GFP_KERNEL); if (!buf->area) { - dev_err(soc_runtime->dev, "%s: Could not allocate DMA buffer\n", + dev_err(rt->platform->dev, "%s: Could not allocate DMA buffer\n", __func__); return -ENOMEM; } @@ -461,12 +461,12 @@ static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream, } static void lpass_platform_free_buffer(struct snd_pcm_substream *substream, - struct snd_soc_pcm_runtime *soc_runtime) + struct snd_soc_pcm_runtime *rt) { struct snd_dma_buffer *buf = &substream->dma_buffer; if (buf->area) { - dma_free_coherent(soc_runtime->dev, buf->bytes, buf->area, + dma_free_coherent(rt->dev, buf->bytes, buf->area, buf->addr); } buf->area = NULL; @@ -499,9 +499,6 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) snd_soc_pcm_set_drvdata(soc_runtime, data); - soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32); - soc_runtime->dev->dma_mask = &soc_runtime->dev->coherent_dma_mask; - ret = lpass_platform_alloc_buffer(substream, soc_runtime); if (ret) return ret; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 5a2812f..0d37079 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -310,7 +310,7 @@ struct dapm_kcontrol_data { }; static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, - struct snd_kcontrol *kcontrol) + struct snd_kcontrol *kcontrol, const char *ctrl_name) { struct dapm_kcontrol_data *data; struct soc_mixer_control *mc; @@ -333,7 +333,7 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, if (mc->autodisable) { struct snd_soc_dapm_widget template; - name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name, + name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name, "Autodisable"); if (!name) { ret = -ENOMEM; @@ -371,7 +371,7 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, if (e->autodisable) { struct snd_soc_dapm_widget template; - name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name, + name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name, "Autodisable"); if (!name) { ret = -ENOMEM; @@ -871,7 +871,7 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w, kcontrol->private_free = dapm_kcontrol_free; - ret = dapm_kcontrol_data_alloc(w, kcontrol); + ret = dapm_kcontrol_data_alloc(w, kcontrol, name); if (ret) { snd_ctl_free_one(kcontrol); goto exit_free; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index e898b42..1af4f23 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1810,7 +1810,8 @@ int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) && - (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND)) continue; dev_dbg(be->dev, "ASoC: hw_free BE %s\n", diff --git a/sound/usb/midi.c b/sound/usb/midi.c index b79875e..47de8af 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -2458,7 +2458,6 @@ int __snd_usbmidi_create(struct snd_card *card, else err = snd_usbmidi_create_endpoints(umidi, endpoints); if (err < 0) { - snd_usbmidi_free(umidi); return err; } |