sound fixes for 5.5-rc7

This became bigger than I have hoped for rc7.  But, the only large LOC
 is for stm32 fixes that are simple rewriting of register access
 helpers, while the rest are all nice and small fixes:
 
 - A few ASoC fixes for the remaining probe error handling bugs
 
 - ALSA sequencer core fix for racy proc file accesses
 
 - Revert the option rename of snd-hda-intel to make compatible again
 
 - Various device-specific fixes
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAl4gjbEOHHRpd2FpQHN1
 c2UuZGUACgkQLtJE4w1nLE8Pow/+KXlxZDprRwaW5jX23k7OOOdZOjyrM+XNNH1J
 ubCV5jHfZqT6FK2Ewo6ytxDOE7liiAZCs1r5D7of8sRHPVeMfgyRNdL4MbirR03n
 eGzREtynfPXymcnaKZuuantFNl4rq3ovwCUOTiqNgTdONZzakm3bISMf5RLF0SBU
 wuImY3PHepcjah3BXBTJHj8V9KpmDasd15DcrK0j/W+oS4eNnxSCoH4gzAwjAuDO
 v2bEsF/yXGDhriyl/squJjVBnNOkzn/fyRAQl7RGe8pNa4PWIvbAaqd5qaIch4EH
 perJfnvhB5SoB/s7mJ3jwnjA/vx0VKkCOw7Wufr/3+i1gKsuDbkvh8eaoN0/rnNk
 gn56hLux7nnbOW5uzVG12PekIf3T7uJMM7mMZGAMOeQpWK6xCpDHHlC/1rZd+idy
 SUgkqHEhQl9Qu5d7c7KkTy408FOzhaL4HZX5wqSghPUj2mFrWZGxpQvLlD1FYCE2
 NuFKzPNYaeLbUyhJJ2HBmjEov0R3ASZzVYx/fRarc+JET7jI/hyWfBJ+oe1qy1Ff
 X7gDrLpbXd61lgtCALlv9K1v5Ap7FSkAEXiHI4jtj/9m0yN/XTp5pqjd4itW7ZR9
 2EuQrsysh1JimFBauNdLVRCPooPkAqiEeWscMjqgBth2l7BhinYoXIMcA+fchUgC
 up9VJeQ=
 =M4pi
 -----END PGP SIGNATURE-----

Merge tag 'sound-5.5-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound fixes from Takashi Iwai:
 "This became bigger than I have hoped for rc7. But, the only large LOC
  is for stm32 fixes that are simple rewriting of register access
  helpers, while the rest are all nice and small fixes:

   - A few ASoC fixes for the remaining probe error handling bugs

   - ALSA sequencer core fix for racy proc file accesses

   - Revert the option rename of snd-hda-intel to make compatible again

   - Various device-specific fixes"

* tag 'sound-5.5-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: seq: Fix racy access for queue timer in proc read
  ALSA: usb-audio: fix sync-ep altsetting sanity check
  ASoC: msm8916-wcd-digital: Reset RX interpolation path after use
  ASoC: msm8916-wcd-analog: Fix MIC BIAS Internal1
  ASoC: cros_ec_codec: Make the device acpi compatible
  ASoC: sti: fix possible sleep-in-atomic
  ASoC: msm8916-wcd-analog: Fix selected events for MIC BIAS External1
  ASoC: hdac_hda: Fix error in driver removal after failed probe
  ASoC: SOF: Intel: fix HDA codec driver probe with multiple controllers
  ASoC: SOF: Intel: lower print level to dbg if we will reinit DSP
  ALSA: dice: fix fallback from protocol extension into limited functionality
  ALSA: firewire-tascam: fix corruption due to spin lock without restoration in SoftIRQ context
  ALSA: hda: Rename back to dmic_detect option
  ASoC: stm32: dfsdm: fix 16 bits record
  ASoC: stm32: sai: fix possible circular locking
  ASoC: Fix NULL dereference at freeing
  ASoC: Intel: bytcht_es8316: Fix Irbis NB41 netbook quirk
  ASoC: rt5640: Fix NULL dereference on module unload
This commit is contained in:
Linus Torvalds 2020-01-17 08:38:35 -08:00
commit 07d5ac6a12
17 changed files with 234 additions and 94 deletions

View File

@ -471,15 +471,19 @@ void snd_seq_info_timer_read(struct snd_info_entry *entry,
q = queueptr(idx); q = queueptr(idx);
if (q == NULL) if (q == NULL)
continue; continue;
if ((tmr = q->timer) == NULL || mutex_lock(&q->timer_mutex);
(ti = tmr->timeri) == NULL) { tmr = q->timer;
queuefree(q); if (!tmr)
continue; goto unlock;
} ti = tmr->timeri;
if (!ti)
goto unlock;
snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name); snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name);
resolution = snd_timer_resolution(ti) * tmr->ticks; resolution = snd_timer_resolution(ti) * tmr->ticks;
snd_iprintf(buffer, " Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000); snd_iprintf(buffer, " Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000);
snd_iprintf(buffer, " Skew : %u / %u\n", tmr->skew, tmr->skew_base); snd_iprintf(buffer, " Skew : %u / %u\n", tmr->skew, tmr->skew_base);
unlock:
mutex_unlock(&q->timer_mutex);
queuefree(q); queuefree(q);
} }
} }

View File

@ -159,8 +159,11 @@ int snd_dice_detect_extension_formats(struct snd_dice *dice)
int j; int j;
for (j = i + 1; j < 9; ++j) { for (j = i + 1; j < 9; ++j) {
if (pointers[i * 2] == pointers[j * 2]) if (pointers[i * 2] == pointers[j * 2]) {
// Fallback to limited functionality.
err = -ENXIO;
goto end; goto end;
}
} }
} }

View File

@ -157,14 +157,15 @@ static void read_status_messages(struct amdtp_stream *s,
if ((before ^ after) & mask) { if ((before ^ after) & mask) {
struct snd_firewire_tascam_change *entry = struct snd_firewire_tascam_change *entry =
&tscm->queue[tscm->push_pos]; &tscm->queue[tscm->push_pos];
unsigned long flag;
spin_lock_irq(&tscm->lock); spin_lock_irqsave(&tscm->lock, flag);
entry->index = index; entry->index = index;
entry->before = before; entry->before = before;
entry->after = after; entry->after = after;
if (++tscm->push_pos >= SND_TSCM_QUEUE_COUNT) if (++tscm->push_pos >= SND_TSCM_QUEUE_COUNT)
tscm->push_pos = 0; tscm->push_pos = 0;
spin_unlock_irq(&tscm->lock); spin_unlock_irqrestore(&tscm->lock, flag);
wake_up(&tscm->hwdep_wait); wake_up(&tscm->hwdep_wait);
} }

View File

@ -125,7 +125,7 @@ static char *patch[SNDRV_CARDS];
static bool beep_mode[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = static bool beep_mode[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] =
CONFIG_SND_HDA_INPUT_BEEP_MODE}; CONFIG_SND_HDA_INPUT_BEEP_MODE};
#endif #endif
static bool dsp_driver = 1; static bool dmic_detect = 1;
module_param_array(index, int, NULL, 0444); module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
@ -160,9 +160,10 @@ module_param_array(beep_mode, bool, NULL, 0444);
MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode " MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode "
"(0=off, 1=on) (default=1)."); "(0=off, 1=on) (default=1).");
#endif #endif
module_param(dsp_driver, bool, 0444); module_param(dmic_detect, bool, 0444);
MODULE_PARM_DESC(dsp_driver, "Allow DSP driver selection (bypass this driver) " MODULE_PARM_DESC(dmic_detect, "Allow DSP driver selection (bypass this driver) "
"(0=off, 1=on) (default=1)"); "(0=off, 1=on) (default=1); "
"deprecated, use snd-intel-dspcfg.dsp_driver option instead");
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int param_set_xint(const char *val, const struct kernel_param *kp); static int param_set_xint(const char *val, const struct kernel_param *kp);
@ -2099,11 +2100,13 @@ static int azx_probe(struct pci_dev *pci,
/* /*
* stop probe if another Intel's DSP driver should be activated * stop probe if another Intel's DSP driver should be activated
*/ */
if (dsp_driver) { if (dmic_detect) {
err = snd_intel_dsp_driver_probe(pci); err = snd_intel_dsp_driver_probe(pci);
if (err != SND_INTEL_DSP_DRIVER_ANY && if (err != SND_INTEL_DSP_DRIVER_ANY &&
err != SND_INTEL_DSP_DRIVER_LEGACY) err != SND_INTEL_DSP_DRIVER_LEGACY)
return -ENODEV; return -ENODEV;
} else {
dev_warn(&pci->dev, "dmic_detect option is deprecated, pass snd-intel-dspcfg.dsp_driver=1 option instead\n");
} }
err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,

View File

@ -10,6 +10,7 @@
#include <crypto/hash.h> #include <crypto/hash.h>
#include <crypto/sha.h> #include <crypto/sha.h>
#include <linux/acpi.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/io.h> #include <linux/io.h>
@ -1047,10 +1048,17 @@ static const struct of_device_id cros_ec_codec_of_match[] = {
MODULE_DEVICE_TABLE(of, cros_ec_codec_of_match); MODULE_DEVICE_TABLE(of, cros_ec_codec_of_match);
#endif #endif
static const struct acpi_device_id cros_ec_codec_acpi_id[] = {
{ "GOOG0013", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, cros_ec_codec_acpi_id);
static struct platform_driver cros_ec_codec_platform_driver = { static struct platform_driver cros_ec_codec_platform_driver = {
.driver = { .driver = {
.name = "cros-ec-codec", .name = "cros-ec-codec",
.of_match_table = of_match_ptr(cros_ec_codec_of_match), .of_match_table = of_match_ptr(cros_ec_codec_of_match),
.acpi_match_table = ACPI_PTR(cros_ec_codec_acpi_id),
}, },
.probe = cros_ec_codec_platform_probe, .probe = cros_ec_codec_platform_probe,
}; };

View File

@ -588,7 +588,9 @@ static int hdac_hda_dev_remove(struct hdac_device *hdev)
struct hdac_hda_priv *hda_pvt; struct hdac_hda_priv *hda_pvt;
hda_pvt = dev_get_drvdata(&hdev->dev); hda_pvt = dev_get_drvdata(&hdev->dev);
cancel_delayed_work_sync(&hda_pvt->codec.jackpoll_work); if (hda_pvt && hda_pvt->codec.registered)
cancel_delayed_work_sync(&hda_pvt->codec.jackpoll_work);
return 0; return 0;
} }

View File

@ -396,9 +396,6 @@ static int pm8916_wcd_analog_enable_micbias_int(struct snd_soc_component
switch (event) { switch (event) {
case SND_SOC_DAPM_PRE_PMU: case SND_SOC_DAPM_PRE_PMU:
snd_soc_component_update_bits(component, CDC_A_MICB_1_INT_RBIAS,
MICB_1_INT_TX2_INT_RBIAS_EN_MASK,
MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE);
snd_soc_component_update_bits(component, reg, MICB_1_EN_PULL_DOWN_EN_MASK, 0); snd_soc_component_update_bits(component, reg, MICB_1_EN_PULL_DOWN_EN_MASK, 0);
snd_soc_component_update_bits(component, CDC_A_MICB_1_EN, snd_soc_component_update_bits(component, CDC_A_MICB_1_EN,
MICB_1_EN_OPA_STG2_TAIL_CURR_MASK, MICB_1_EN_OPA_STG2_TAIL_CURR_MASK,
@ -448,6 +445,14 @@ static int pm8916_wcd_analog_enable_micbias_int1(struct
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component); struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
snd_soc_component_update_bits(component, CDC_A_MICB_1_INT_RBIAS,
MICB_1_INT_TX1_INT_RBIAS_EN_MASK,
MICB_1_INT_TX1_INT_RBIAS_EN_ENABLE);
break;
}
return pm8916_wcd_analog_enable_micbias_int(component, event, w->reg, return pm8916_wcd_analog_enable_micbias_int(component, event, w->reg,
wcd->micbias1_cap_mode); wcd->micbias1_cap_mode);
} }
@ -558,6 +563,11 @@ static int pm8916_wcd_analog_enable_micbias_int2(struct
struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component); struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component);
switch (event) { switch (event) {
case SND_SOC_DAPM_PRE_PMU:
snd_soc_component_update_bits(component, CDC_A_MICB_1_INT_RBIAS,
MICB_1_INT_TX2_INT_RBIAS_EN_MASK,
MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE);
break;
case SND_SOC_DAPM_POST_PMU: case SND_SOC_DAPM_POST_PMU:
pm8916_mbhc_configure_bias(wcd, true); pm8916_mbhc_configure_bias(wcd, true);
break; break;
@ -938,10 +948,10 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("MIC BIAS External1", CDC_A_MICB_1_EN, 7, 0, SND_SOC_DAPM_SUPPLY("MIC BIAS External1", CDC_A_MICB_1_EN, 7, 0,
pm8916_wcd_analog_enable_micbias_ext1, pm8916_wcd_analog_enable_micbias_ext1,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("MIC BIAS External2", CDC_A_MICB_2_EN, 7, 0, SND_SOC_DAPM_SUPPLY("MIC BIAS External2", CDC_A_MICB_2_EN, 7, 0,
pm8916_wcd_analog_enable_micbias_ext2, pm8916_wcd_analog_enable_micbias_ext2,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_ADC_E("ADC1", NULL, CDC_A_TX_1_EN, 7, 0, SND_SOC_DAPM_ADC_E("ADC1", NULL, CDC_A_TX_1_EN, 7, 0,
pm8916_wcd_analog_enable_adc, pm8916_wcd_analog_enable_adc,

View File

@ -586,6 +586,12 @@ static int msm8916_wcd_digital_enable_interpolator(
snd_soc_component_write(component, rx_gain_reg[w->shift], snd_soc_component_write(component, rx_gain_reg[w->shift],
snd_soc_component_read32(component, rx_gain_reg[w->shift])); snd_soc_component_read32(component, rx_gain_reg[w->shift]));
break; break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_component_update_bits(component, LPASS_CDC_CLK_RX_RESET_CTL,
1 << w->shift, 1 << w->shift);
snd_soc_component_update_bits(component, LPASS_CDC_CLK_RX_RESET_CTL,
1 << w->shift, 0x0);
break;
} }
return 0; return 0;
} }

View File

@ -2432,6 +2432,13 @@ static void rt5640_disable_jack_detect(struct snd_soc_component *component)
{ {
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
/*
* soc_remove_component() force-disables jack and thus rt5640->jack
* could be NULL at the time of driver's module unloading.
*/
if (!rt5640->jack)
return;
disable_irq(rt5640->irq); disable_irq(rt5640->irq);
rt5640_cancel_work(rt5640); rt5640_cancel_work(rt5640);

View File

@ -442,7 +442,8 @@ static const struct dmi_system_id byt_cht_es8316_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "IRBIS"), DMI_MATCH(DMI_SYS_VENDOR, "IRBIS"),
DMI_MATCH(DMI_PRODUCT_NAME, "NB41"), DMI_MATCH(DMI_PRODUCT_NAME, "NB41"),
}, },
.driver_data = (void *)(BYT_CHT_ES8316_INTMIC_IN2_MAP .driver_data = (void *)(BYT_CHT_ES8316_SSP0
| BYT_CHT_ES8316_INTMIC_IN2_MAP
| BYT_CHT_ES8316_JD_INVERTED), | BYT_CHT_ES8316_JD_INVERTED),
}, },
{ /* Teclast X98 Plus II */ { /* Teclast X98 Plus II */

View File

@ -539,6 +539,9 @@ void snd_soc_pcm_component_free(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_component *component; struct snd_soc_component *component;
if (!rtd->pcm)
return;
for_each_rtd_components(rtd, rtdcom, component) for_each_rtd_components(rtd, rtdcom, component)
if (component->driver->pcm_destruct) if (component->driver->pcm_destruct)
component->driver->pcm_destruct(component, rtd->pcm); component->driver->pcm_destruct(component, rtd->pcm);

View File

@ -24,19 +24,18 @@
#define IDISP_VID_INTEL 0x80860000 #define IDISP_VID_INTEL 0x80860000
/* load the legacy HDA codec driver */ /* load the legacy HDA codec driver */
#ifdef MODULE static int hda_codec_load_module(struct hda_codec *codec)
static void hda_codec_load_module(struct hda_codec *codec)
{ {
#ifdef MODULE
char alias[MODULE_NAME_LEN]; char alias[MODULE_NAME_LEN];
const char *module = alias; const char *module = alias;
snd_hdac_codec_modalias(&codec->core, alias, sizeof(alias)); snd_hdac_codec_modalias(&codec->core, alias, sizeof(alias));
dev_dbg(&codec->core.dev, "loading codec module: %s\n", module); dev_dbg(&codec->core.dev, "loading codec module: %s\n", module);
request_module(module); request_module(module);
}
#else
static void hda_codec_load_module(struct hda_codec *codec) {}
#endif #endif
return device_attach(hda_codec_dev(codec));
}
/* enable controller wake up event for all codecs with jack connectors */ /* enable controller wake up event for all codecs with jack connectors */
void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev) void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev)
@ -129,10 +128,16 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
if ((mach_params && mach_params->common_hdmi_codec_drv) || if ((mach_params && mach_params->common_hdmi_codec_drv) ||
(resp & 0xFFFF0000) != IDISP_VID_INTEL) { (resp & 0xFFFF0000) != IDISP_VID_INTEL) {
hdev->type = HDA_DEV_LEGACY; hdev->type = HDA_DEV_LEGACY;
hda_codec_load_module(&hda_priv->codec); ret = hda_codec_load_module(&hda_priv->codec);
/*
* handle ret==0 (no driver bound) as an error, but pass
* other return codes without modification
*/
if (ret == 0)
ret = -ENOENT;
} }
return 0; return ret;
#else #else
hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL); hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL);
if (!hdev) if (!hdev)

View File

@ -329,13 +329,13 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
if (!ret) if (!ret)
break; break;
dev_err(sdev->dev, "error: Error code=0x%x: FW status=0x%x\n", dev_dbg(sdev->dev, "iteration %d of Core En/ROM load failed: %d\n",
i, ret);
dev_dbg(sdev->dev, "Error code=0x%x: FW status=0x%x\n",
snd_sof_dsp_read(sdev, HDA_DSP_BAR, snd_sof_dsp_read(sdev, HDA_DSP_BAR,
HDA_DSP_SRAM_REG_ROM_ERROR), HDA_DSP_SRAM_REG_ROM_ERROR),
snd_sof_dsp_read(sdev, HDA_DSP_BAR, snd_sof_dsp_read(sdev, HDA_DSP_BAR,
HDA_DSP_SRAM_REG_ROM_STATUS)); HDA_DSP_SRAM_REG_ROM_STATUS));
dev_err(sdev->dev, "error: iteration %d of Core En/ROM load failed: %d\n",
i, ret);
} }
if (i == HDA_FW_BOOT_ATTEMPTS) { if (i == HDA_FW_BOOT_ATTEMPTS) {

View File

@ -226,7 +226,6 @@ static void uni_player_set_channel_status(struct uniperif *player,
* sampling frequency. If no sample rate is already specified, then * sampling frequency. If no sample rate is already specified, then
* set one. * set one.
*/ */
mutex_lock(&player->ctrl_lock);
if (runtime) { if (runtime) {
switch (runtime->rate) { switch (runtime->rate) {
case 22050: case 22050:
@ -303,7 +302,6 @@ static void uni_player_set_channel_status(struct uniperif *player,
player->stream_settings.iec958.status[3 + (n * 4)] << 24; player->stream_settings.iec958.status[3 + (n * 4)] << 24;
SET_UNIPERIF_CHANNEL_STA_REGN(player, n, status); SET_UNIPERIF_CHANNEL_STA_REGN(player, n, status);
} }
mutex_unlock(&player->ctrl_lock);
/* Update the channel status */ /* Update the channel status */
if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
@ -365,8 +363,10 @@ static int uni_player_prepare_iec958(struct uniperif *player,
SET_UNIPERIF_CTRL_ZERO_STUFF_HW(player); SET_UNIPERIF_CTRL_ZERO_STUFF_HW(player);
mutex_lock(&player->ctrl_lock);
/* Update the channel status */ /* Update the channel status */
uni_player_set_channel_status(player, runtime); uni_player_set_channel_status(player, runtime);
mutex_unlock(&player->ctrl_lock);
/* Clear the user validity user bits */ /* Clear the user validity user bits */
SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 0); SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 0);
@ -598,7 +598,6 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol,
iec958->status[1] = ucontrol->value.iec958.status[1]; iec958->status[1] = ucontrol->value.iec958.status[1];
iec958->status[2] = ucontrol->value.iec958.status[2]; iec958->status[2] = ucontrol->value.iec958.status[2];
iec958->status[3] = ucontrol->value.iec958.status[3]; iec958->status[3] = ucontrol->value.iec958.status[3];
mutex_unlock(&player->ctrl_lock);
spin_lock_irqsave(&player->irq_lock, flags); spin_lock_irqsave(&player->irq_lock, flags);
if (player->substream && player->substream->runtime) if (player->substream && player->substream->runtime)
@ -608,6 +607,8 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol,
uni_player_set_channel_status(player, NULL); uni_player_set_channel_status(player, NULL);
spin_unlock_irqrestore(&player->irq_lock, flags); spin_unlock_irqrestore(&player->irq_lock, flags);
mutex_unlock(&player->ctrl_lock);
return 0; return 0;
} }

View File

@ -153,13 +153,13 @@ static const struct snd_soc_component_driver stm32_adfsdm_dai_component = {
.name = "stm32_dfsdm_audio", .name = "stm32_dfsdm_audio",
}; };
static void memcpy_32to16(void *dest, const void *src, size_t n) static void stm32_memcpy_32to16(void *dest, const void *src, size_t n)
{ {
unsigned int i = 0; unsigned int i = 0;
u16 *d = (u16 *)dest, *s = (u16 *)src; u16 *d = (u16 *)dest, *s = (u16 *)src;
s++; s++;
for (i = n; i > 0; i--) { for (i = n >> 1; i > 0; i--) {
*d++ = *s++; *d++ = *s++;
s++; s++;
} }
@ -186,8 +186,8 @@ static int stm32_afsdm_pcm_cb(const void *data, size_t size, void *private)
if ((priv->pos + src_size) > buff_size) { if ((priv->pos + src_size) > buff_size) {
if (format == SNDRV_PCM_FORMAT_S16_LE) if (format == SNDRV_PCM_FORMAT_S16_LE)
memcpy_32to16(&pcm_buff[priv->pos], src_buff, stm32_memcpy_32to16(&pcm_buff[priv->pos], src_buff,
buff_size - priv->pos); buff_size - priv->pos);
else else
memcpy(&pcm_buff[priv->pos], src_buff, memcpy(&pcm_buff[priv->pos], src_buff,
buff_size - priv->pos); buff_size - priv->pos);
@ -196,8 +196,8 @@ static int stm32_afsdm_pcm_cb(const void *data, size_t size, void *private)
} }
if (format == SNDRV_PCM_FORMAT_S16_LE) if (format == SNDRV_PCM_FORMAT_S16_LE)
memcpy_32to16(&pcm_buff[priv->pos], stm32_memcpy_32to16(&pcm_buff[priv->pos],
&src_buff[src_size - cur_size], cur_size); &src_buff[src_size - cur_size], cur_size);
else else
memcpy(&pcm_buff[priv->pos], &src_buff[src_size - cur_size], memcpy(&pcm_buff[priv->pos], &src_buff[src_size - cur_size],
cur_size); cur_size);

View File

@ -184,6 +184,56 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
} }
} }
static int stm32_sai_sub_reg_up(struct stm32_sai_sub_data *sai,
unsigned int reg, unsigned int mask,
unsigned int val)
{
int ret;
ret = clk_enable(sai->pdata->pclk);
if (ret < 0)
return ret;
ret = regmap_update_bits(sai->regmap, reg, mask, val);
clk_disable(sai->pdata->pclk);
return ret;
}
static int stm32_sai_sub_reg_wr(struct stm32_sai_sub_data *sai,
unsigned int reg, unsigned int mask,
unsigned int val)
{
int ret;
ret = clk_enable(sai->pdata->pclk);
if (ret < 0)
return ret;
ret = regmap_write_bits(sai->regmap, reg, mask, val);
clk_disable(sai->pdata->pclk);
return ret;
}
static int stm32_sai_sub_reg_rd(struct stm32_sai_sub_data *sai,
unsigned int reg, unsigned int *val)
{
int ret;
ret = clk_enable(sai->pdata->pclk);
if (ret < 0)
return ret;
ret = regmap_read(sai->regmap, reg, val);
clk_disable(sai->pdata->pclk);
return ret;
}
static const struct regmap_config stm32_sai_sub_regmap_config_f4 = { static const struct regmap_config stm32_sai_sub_regmap_config_f4 = {
.reg_bits = 32, .reg_bits = 32,
.reg_stride = 4, .reg_stride = 4,
@ -295,7 +345,7 @@ static int stm32_sai_set_clk_div(struct stm32_sai_sub_data *sai,
mask = SAI_XCR1_MCKDIV_MASK(SAI_XCR1_MCKDIV_WIDTH(version)); mask = SAI_XCR1_MCKDIV_MASK(SAI_XCR1_MCKDIV_WIDTH(version));
cr1 = SAI_XCR1_MCKDIV_SET(div); cr1 = SAI_XCR1_MCKDIV_SET(div);
ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, mask, cr1); ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, mask, cr1);
if (ret < 0) if (ret < 0)
dev_err(&sai->pdev->dev, "Failed to update CR1 register\n"); dev_err(&sai->pdev->dev, "Failed to update CR1 register\n");
@ -372,8 +422,8 @@ static int stm32_sai_mclk_enable(struct clk_hw *hw)
dev_dbg(&sai->pdev->dev, "Enable master clock\n"); dev_dbg(&sai->pdev->dev, "Enable master clock\n");
return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, return stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
SAI_XCR1_MCKEN, SAI_XCR1_MCKEN); SAI_XCR1_MCKEN, SAI_XCR1_MCKEN);
} }
static void stm32_sai_mclk_disable(struct clk_hw *hw) static void stm32_sai_mclk_disable(struct clk_hw *hw)
@ -383,7 +433,7 @@ static void stm32_sai_mclk_disable(struct clk_hw *hw)
dev_dbg(&sai->pdev->dev, "Disable master clock\n"); dev_dbg(&sai->pdev->dev, "Disable master clock\n");
regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_MCKEN, 0); stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, SAI_XCR1_MCKEN, 0);
} }
static const struct clk_ops mclk_ops = { static const struct clk_ops mclk_ops = {
@ -446,15 +496,15 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
unsigned int sr, imr, flags; unsigned int sr, imr, flags;
snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING; snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
regmap_read(sai->regmap, STM_SAI_IMR_REGX, &imr); stm32_sai_sub_reg_rd(sai, STM_SAI_IMR_REGX, &imr);
regmap_read(sai->regmap, STM_SAI_SR_REGX, &sr); stm32_sai_sub_reg_rd(sai, STM_SAI_SR_REGX, &sr);
flags = sr & imr; flags = sr & imr;
if (!flags) if (!flags)
return IRQ_NONE; return IRQ_NONE;
regmap_write_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK, stm32_sai_sub_reg_wr(sai, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
SAI_XCLRFR_MASK); SAI_XCLRFR_MASK);
if (!sai->substream) { if (!sai->substream) {
dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr); dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
@ -503,8 +553,8 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai,
int ret; int ret;
if (dir == SND_SOC_CLOCK_OUT && sai->sai_mclk) { if (dir == SND_SOC_CLOCK_OUT && sai->sai_mclk) {
ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
SAI_XCR1_NODIV, SAI_XCR1_NODIV,
freq ? 0 : SAI_XCR1_NODIV); freq ? 0 : SAI_XCR1_NODIV);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -583,7 +633,7 @@ static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
slotr_mask |= SAI_XSLOTR_SLOTEN_MASK; slotr_mask |= SAI_XSLOTR_SLOTEN_MASK;
regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX, slotr_mask, slotr); stm32_sai_sub_reg_up(sai, STM_SAI_SLOTR_REGX, slotr_mask, slotr);
sai->slot_width = slot_width; sai->slot_width = slot_width;
sai->slots = slots; sai->slots = slots;
@ -665,7 +715,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
cr1_mask |= SAI_XCR1_CKSTR; cr1_mask |= SAI_XCR1_CKSTR;
frcr_mask |= SAI_XFRCR_FSPOL; frcr_mask |= SAI_XFRCR_FSPOL;
regmap_update_bits(sai->regmap, STM_SAI_FRCR_REGX, frcr_mask, frcr); stm32_sai_sub_reg_up(sai, STM_SAI_FRCR_REGX, frcr_mask, frcr);
/* DAI clock master masks */ /* DAI clock master masks */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@ -693,7 +743,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
cr1_mask |= SAI_XCR1_SLAVE; cr1_mask |= SAI_XCR1_SLAVE;
conf_update: conf_update:
ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1); ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, cr1_mask, cr1);
if (ret < 0) { if (ret < 0) {
dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
return ret; return ret;
@ -730,12 +780,12 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream,
} }
/* Enable ITs */ /* Enable ITs */
regmap_write_bits(sai->regmap, STM_SAI_CLRFR_REGX, stm32_sai_sub_reg_wr(sai, STM_SAI_CLRFR_REGX,
SAI_XCLRFR_MASK, SAI_XCLRFR_MASK); SAI_XCLRFR_MASK, SAI_XCLRFR_MASK);
imr = SAI_XIMR_OVRUDRIE; imr = SAI_XIMR_OVRUDRIE;
if (STM_SAI_IS_CAPTURE(sai)) { if (STM_SAI_IS_CAPTURE(sai)) {
regmap_read(sai->regmap, STM_SAI_CR2_REGX, &cr2); stm32_sai_sub_reg_rd(sai, STM_SAI_CR2_REGX, &cr2);
if (cr2 & SAI_XCR2_MUTECNT_MASK) if (cr2 & SAI_XCR2_MUTECNT_MASK)
imr |= SAI_XIMR_MUTEDETIE; imr |= SAI_XIMR_MUTEDETIE;
} }
@ -745,8 +795,8 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream,
else else
imr |= SAI_XIMR_AFSDETIE | SAI_XIMR_LFSDETIE; imr |= SAI_XIMR_AFSDETIE | SAI_XIMR_LFSDETIE;
regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, stm32_sai_sub_reg_up(sai, STM_SAI_IMR_REGX,
SAI_XIMR_MASK, imr); SAI_XIMR_MASK, imr);
return 0; return 0;
} }
@ -763,10 +813,10 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
* SAI fifo threshold is set to half fifo, to keep enough space * SAI fifo threshold is set to half fifo, to keep enough space
* for DMA incoming bursts. * for DMA incoming bursts.
*/ */
regmap_write_bits(sai->regmap, STM_SAI_CR2_REGX, stm32_sai_sub_reg_wr(sai, STM_SAI_CR2_REGX,
SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK, SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK,
SAI_XCR2_FFLUSH | SAI_XCR2_FFLUSH |
SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF)); SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF));
/* DS bits in CR1 not set for SPDIF (size forced to 24 bits).*/ /* DS bits in CR1 not set for SPDIF (size forced to 24 bits).*/
if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
@ -795,7 +845,7 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
if ((sai->slots == 2) && (params_channels(params) == 1)) if ((sai->slots == 2) && (params_channels(params) == 1))
cr1 |= SAI_XCR1_MONO; cr1 |= SAI_XCR1_MONO;
ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1); ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, cr1_mask, cr1);
if (ret < 0) { if (ret < 0) {
dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
return ret; return ret;
@ -809,7 +859,7 @@ static int stm32_sai_set_slots(struct snd_soc_dai *cpu_dai)
struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
int slotr, slot_sz; int slotr, slot_sz;
regmap_read(sai->regmap, STM_SAI_SLOTR_REGX, &slotr); stm32_sai_sub_reg_rd(sai, STM_SAI_SLOTR_REGX, &slotr);
/* /*
* If SLOTSZ is set to auto in SLOTR, align slot width on data size * If SLOTSZ is set to auto in SLOTR, align slot width on data size
@ -831,16 +881,16 @@ static int stm32_sai_set_slots(struct snd_soc_dai *cpu_dai)
sai->slots = 2; sai->slots = 2;
/* The number of slots in the audio frame is equal to NBSLOT[3:0] + 1*/ /* The number of slots in the audio frame is equal to NBSLOT[3:0] + 1*/
regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX, stm32_sai_sub_reg_up(sai, STM_SAI_SLOTR_REGX,
SAI_XSLOTR_NBSLOT_MASK, SAI_XSLOTR_NBSLOT_MASK,
SAI_XSLOTR_NBSLOT_SET((sai->slots - 1))); SAI_XSLOTR_NBSLOT_SET((sai->slots - 1)));
/* Set default slots mask if not already set from DT */ /* Set default slots mask if not already set from DT */
if (!(slotr & SAI_XSLOTR_SLOTEN_MASK)) { if (!(slotr & SAI_XSLOTR_SLOTEN_MASK)) {
sai->slot_mask = (1 << sai->slots) - 1; sai->slot_mask = (1 << sai->slots) - 1;
regmap_update_bits(sai->regmap, stm32_sai_sub_reg_up(sai,
STM_SAI_SLOTR_REGX, SAI_XSLOTR_SLOTEN_MASK, STM_SAI_SLOTR_REGX, SAI_XSLOTR_SLOTEN_MASK,
SAI_XSLOTR_SLOTEN_SET(sai->slot_mask)); SAI_XSLOTR_SLOTEN_SET(sai->slot_mask));
} }
dev_dbg(cpu_dai->dev, "Slots %d, slot width %d\n", dev_dbg(cpu_dai->dev, "Slots %d, slot width %d\n",
@ -870,14 +920,14 @@ static void stm32_sai_set_frame(struct snd_soc_dai *cpu_dai)
dev_dbg(cpu_dai->dev, "Frame length %d, frame active %d\n", dev_dbg(cpu_dai->dev, "Frame length %d, frame active %d\n",
sai->fs_length, fs_active); sai->fs_length, fs_active);
regmap_update_bits(sai->regmap, STM_SAI_FRCR_REGX, frcr_mask, frcr); stm32_sai_sub_reg_up(sai, STM_SAI_FRCR_REGX, frcr_mask, frcr);
if ((sai->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_LSB) { if ((sai->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_LSB) {
offset = sai->slot_width - sai->data_size; offset = sai->slot_width - sai->data_size;
regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX, stm32_sai_sub_reg_up(sai, STM_SAI_SLOTR_REGX,
SAI_XSLOTR_FBOFF_MASK, SAI_XSLOTR_FBOFF_MASK,
SAI_XSLOTR_FBOFF_SET(offset)); SAI_XSLOTR_FBOFF_SET(offset));
} }
} }
@ -994,9 +1044,9 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai,
return -EINVAL; return -EINVAL;
} }
regmap_update_bits(sai->regmap, stm32_sai_sub_reg_up(sai,
STM_SAI_CR1_REGX, STM_SAI_CR1_REGX,
SAI_XCR1_OSR, cr1); SAI_XCR1_OSR, cr1);
div = stm32_sai_get_clk_div(sai, sai_clk_rate, div = stm32_sai_get_clk_div(sai, sai_clk_rate,
sai->mclk_rate); sai->mclk_rate);
@ -1058,12 +1108,12 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
dev_dbg(cpu_dai->dev, "Enable DMA and SAI\n"); dev_dbg(cpu_dai->dev, "Enable DMA and SAI\n");
regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
SAI_XCR1_DMAEN, SAI_XCR1_DMAEN); SAI_XCR1_DMAEN, SAI_XCR1_DMAEN);
/* Enable SAI */ /* Enable SAI */
ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
SAI_XCR1_SAIEN, SAI_XCR1_SAIEN); SAI_XCR1_SAIEN, SAI_XCR1_SAIEN);
if (ret < 0) if (ret < 0)
dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
break; break;
@ -1072,16 +1122,16 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n"); dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n");
regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, stm32_sai_sub_reg_up(sai, STM_SAI_IMR_REGX,
SAI_XIMR_MASK, 0); SAI_XIMR_MASK, 0);
regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
SAI_XCR1_SAIEN, SAI_XCR1_SAIEN,
(unsigned int)~SAI_XCR1_SAIEN); (unsigned int)~SAI_XCR1_SAIEN);
ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
SAI_XCR1_DMAEN, SAI_XCR1_DMAEN,
(unsigned int)~SAI_XCR1_DMAEN); (unsigned int)~SAI_XCR1_DMAEN);
if (ret < 0) if (ret < 0)
dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
@ -1101,7 +1151,7 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream,
struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
unsigned long flags; unsigned long flags;
regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0); stm32_sai_sub_reg_up(sai, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0);
clk_disable_unprepare(sai->sai_ck); clk_disable_unprepare(sai->sai_ck);
@ -1169,7 +1219,7 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
cr1_mask |= SAI_XCR1_SYNCEN_MASK; cr1_mask |= SAI_XCR1_SYNCEN_MASK;
cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync); cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync);
return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1); return stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, cr1_mask, cr1);
} }
static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = { static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = {
@ -1322,8 +1372,13 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
if (STM_SAI_HAS_PDM(sai) && STM_SAI_IS_SUB_A(sai)) if (STM_SAI_HAS_PDM(sai) && STM_SAI_IS_SUB_A(sai))
sai->regmap_config = &stm32_sai_sub_regmap_config_h7; sai->regmap_config = &stm32_sai_sub_regmap_config_h7;
sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "sai_ck", /*
base, sai->regmap_config); * Do not manage peripheral clock through regmap framework as this
* can lead to circular locking issue with sai master clock provider.
* Manage peripheral clock directly in driver instead.
*/
sai->regmap = devm_regmap_init_mmio(&pdev->dev, base,
sai->regmap_config);
if (IS_ERR(sai->regmap)) { if (IS_ERR(sai->regmap)) {
dev_err(&pdev->dev, "Failed to initialize MMIO\n"); dev_err(&pdev->dev, "Failed to initialize MMIO\n");
return PTR_ERR(sai->regmap); return PTR_ERR(sai->regmap);
@ -1420,6 +1475,10 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
return PTR_ERR(sai->sai_ck); return PTR_ERR(sai->sai_ck);
} }
ret = clk_prepare(sai->pdata->pclk);
if (ret < 0)
return ret;
if (STM_SAI_IS_F4(sai->pdata)) if (STM_SAI_IS_F4(sai->pdata))
return 0; return 0;
@ -1501,22 +1560,48 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int stm32_sai_sub_remove(struct platform_device *pdev)
{
struct stm32_sai_sub_data *sai = dev_get_drvdata(&pdev->dev);
clk_unprepare(sai->pdata->pclk);
return 0;
}
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int stm32_sai_sub_suspend(struct device *dev) static int stm32_sai_sub_suspend(struct device *dev)
{ {
struct stm32_sai_sub_data *sai = dev_get_drvdata(dev); struct stm32_sai_sub_data *sai = dev_get_drvdata(dev);
int ret;
ret = clk_enable(sai->pdata->pclk);
if (ret < 0)
return ret;
regcache_cache_only(sai->regmap, true); regcache_cache_only(sai->regmap, true);
regcache_mark_dirty(sai->regmap); regcache_mark_dirty(sai->regmap);
clk_disable(sai->pdata->pclk);
return 0; return 0;
} }
static int stm32_sai_sub_resume(struct device *dev) static int stm32_sai_sub_resume(struct device *dev)
{ {
struct stm32_sai_sub_data *sai = dev_get_drvdata(dev); struct stm32_sai_sub_data *sai = dev_get_drvdata(dev);
int ret;
ret = clk_enable(sai->pdata->pclk);
if (ret < 0)
return ret;
regcache_cache_only(sai->regmap, false); regcache_cache_only(sai->regmap, false);
return regcache_sync(sai->regmap); ret = regcache_sync(sai->regmap);
clk_disable(sai->pdata->pclk);
return ret;
} }
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
@ -1531,6 +1616,7 @@ static struct platform_driver stm32_sai_sub_driver = {
.pm = &stm32_sai_sub_pm_ops, .pm = &stm32_sai_sub_pm_ops,
}, },
.probe = stm32_sai_sub_probe, .probe = stm32_sai_sub_probe,
.remove = stm32_sai_sub_remove,
}; };
module_platform_driver(stm32_sai_sub_driver); module_platform_driver(stm32_sai_sub_driver);

View File

@ -370,7 +370,7 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs,
add_sync_ep_from_ifnum: add_sync_ep_from_ifnum:
iface = usb_ifnum_to_if(dev, ifnum); iface = usb_ifnum_to_if(dev, ifnum);
if (!iface || iface->num_altsetting == 0) if (!iface || iface->num_altsetting < 2)
return -EINVAL; return -EINVAL;
alts = &iface->altsetting[1]; alts = &iface->altsetting[1];