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

Pull sound fixes from Takashi Iwai:
 "A collection of device-specific small fixes. At this time, the
  majority of changes are about ASoC while we have usual suspects like
  HD- and USB-audio quirks. Some highlights below.

  ASoC Intel / SoundWire:
   - Fix bus and stream resource leaks at error path in avs and hda-ext
   - More fixes and refactoring in avs for constraining MSBs, async
     handling D0ix
   - Add support for TAC5xx2 SoundWire family and NVL MAX98360A RT5682
     machines
   - Fix uninitialized stream configurations in Realtek SoundWire codecs
   - Adjust latency control to fix no-sound issue on RT721-SDCA

  ASoC AMD:
   - Avoid binding for the acp-da7219-max98357a machine driver
   - Add quirks for Acer Nitro AN17-41 and HP 255R G10
   - Fix memory leaks in ACP6x

  ASoC Codecs & Platforms:
   - Fixes for cs35l56 to avoid deadlock, kexec race, and runtime PM
     imbalances
   - Split stereo streams across mono amps on tas2783-sdw
   - Fix pop noise on es8326 and enable_count underflow on es8389
   - Various fixes for fsl_micfil, sprd, sti, and publish OF module
     aliases
   - Fixes & cleanups for Ux500 (MSP/I2S) and AB8500 codecs

  HD-audio:
   - Fix for channel status notification changes
   - Quirks for HP laptops

  USB-audio:
   - Fix embedded URBs in caiaq, 6fire, hiface, and ua101 drivers
   - More hardening in usx2y and us122l drivers
   - Quirks for Behringer devices

  Misc:
   - Add PCI ID for RME HDSPe AIO PCI Express audio card in hdspm
   - Fix S/PDIF passthrough on CA20K2 in ctxfi"

* tag 'sound-7.3-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (65 commits)
  ALSA: hdspm: Add a new PCI device ID (1d18:3fc6) for RME HDSPe AIO PCI express audio
  ASoC: amd: acp-da7219-max98357a: don't bind on Raven/Picasso boards
  ALSA: hda: Report a change when only the channel status bytes move
  ALSA: us122l: Prevent write upgrades for read mappings
  ALSA: hda/realtek: Add quirk for HP Elite Dragonfly Max G2 speaker
  ASoC: cs35l56: Fix race between kexec and snd_soc_register_component()
  ASoC: amd: yc: add quirk for Acer Nitro AN17-41 internal mic
  ASoC: mt6351: Publish the OF module alias
  ASoC: Intel: SST: Publish the PCI module aliases
  ASoC: bcm: bcm63xx: Publish the OF module aliases
  ALSA: usb-audio: Add quirk flags for Behringer UV1
  ALSA: usb-audio: Add boot quirk for Behringer CM1A
  ALSA: hda/realtek: Add quirk for HP Omen 16-wd0xxx mute LED
  ALSA: usbusx2y: validate URB actual_length in interrupt callback
  ALSA: usbusx2y: fix in04_last array size mismatch with in04_buf
  ALSA: ctxfi: Fix CA20K2 S/PDIF passthrough
  ALSA: usb: 6fire: Avoid embedded URBs
  ALSA: usb: hiface: Avoid embedded URBs
  ALSA: usb: ua101: Avoid embedded URBs
  ALSA: caiaq: Decoupling ep1_in_urb in caiaq dev
  ...
This commit is contained in:
Linus Torvalds
2026-09-11 10:00:07 -07:00
59 changed files with 1246 additions and 984 deletions
+2
View File
@@ -7451,6 +7451,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x887c, "HP Laptop 14s-fq1xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x888a, "HP ENVY x360 Convertible 15-eu0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS),
SND_PCI_QUIRK(0x103c, 0x888d, "HP ZBook Power 15.6 inch G8 Mobile Workstation PC", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8890, "HP Elite Dragonfly Max G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
SND_PCI_QUIRK(0x103c, 0x8895, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8896, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8898, "HP EliteBook 845 G8 Notebook PC", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
@@ -7566,6 +7567,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8b92, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8b97, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8ba9, "HP Omen 16-wd0xxx", ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8bb3, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8bb4, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8bb6, "HP Laptop 15-fd0039nt", ALC236_FIXUP_HP_15_FD0XXX),
+3 -1
View File
@@ -2277,6 +2277,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
int idx = kcontrol->private_value;
struct hda_spdif_out *spdif;
hda_nid_t nid;
unsigned int old_status;
unsigned short val;
int change;
@@ -2285,6 +2286,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
guard(mutex)(&codec->spdif_mutex);
spdif = snd_array_elem(&codec->spdif_out, idx);
nid = spdif->nid;
old_status = spdif->status;
spdif->status = ucontrol->value.iec958.status[0] |
((unsigned int)ucontrol->value.iec958.status[1] << 8) |
((unsigned int)ucontrol->value.iec958.status[2] << 16) |
@@ -2295,7 +2297,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
spdif->ctls = val;
if (change && nid != (u16)-1)
set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff);
return change;
return change || spdif->status != old_status;
}
#define snd_hda_spdif_out_switch_info snd_ctl_boolean_mono_info
+3 -1
View File
@@ -90,8 +90,10 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus)
for (idx = 0; idx < link_count; idx++) {
hlink = kzalloc_obj(*hlink);
if (!hlink)
if (!hlink) {
snd_hdac_ext_link_free_all(bus);
return -ENOMEM;
}
hlink->index = idx;
hlink->bus = bus;
hlink->ml_addr = bus->mlcap + AZX_ML_BASE +
+3 -2
View File
@@ -102,8 +102,10 @@ int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
for (i = 0; i < num_stream; i++) {
struct hdac_ext_stream *hext_stream = kzalloc_obj(*hext_stream);
if (!hext_stream)
if (!hext_stream) {
snd_hdac_ext_stream_free_all(bus);
return -ENOMEM;
}
tag = ++stream_tag;
snd_hdac_ext_stream_init(bus, hext_stream, idx, dir, tag);
idx++;
@@ -111,7 +113,6 @@ int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
}
return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init_all);
+1
View File
@@ -994,6 +994,7 @@ static int daio_mgr_dao_init(struct hw *hw, void *blk, unsigned int idx, unsigne
/* S/PDIF output */
switch ((conf & 0xf)) {
case 1:
case 9:
set_field(&ctl->txctl[idx], ATXCTL_NUC, 0);
break;
case 2:
+2 -8
View File
@@ -1071,14 +1071,8 @@ struct hdspm {
static const struct pci_device_id snd_hdspm_ids[] = {
{
.vendor = PCI_VENDOR_ID_XILINX,
.device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.class = 0,
.class_mask = 0,
.driver_data = 0},
{ PCI_DEVICE(PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI) },
{ PCI_DEVICE(0x1d18, 0x3fc6) }, /* RME HDSPe AIO PCI express audio */
{0,}
};
+23
View File
@@ -17,6 +17,7 @@
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/acpi.h>
#include <linux/pci.h>
#include "acp.h"
#include "../codecs/da7219.h"
@@ -742,6 +743,18 @@ static const struct regulator_desc acp_da7219_desc = {
.n_voltages = 1,
};
/*
* The ACP3.x+ (Raven/Picasso and later) audio coprocessor is a dedicated PCI
* function. Carrizo/Stoney - the only platforms handled by this driver - reach
* the ACP through the GPU driver and have no such device.
*/
#define ACP3X_PCI_DEV_ID 0x15e2
static const struct pci_device_id acp3x_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP3X_PCI_DEV_ID) },
{ 0, },
};
static int cz_probe(struct platform_device *pdev)
{
int ret;
@@ -750,6 +763,16 @@ static int cz_probe(struct platform_device *pdev)
struct regulator_dev *rdev;
struct device *dev = &pdev->dev;
/*
* AMDI5682 is also matched by acp3x-alc5682-max98357 (Raven/Picasso).
* If the ACP3.x PCI function is present this is such a board; return
* -ENODEV so that driver binds instead.
*/
if (pci_dev_present(acp3x_pci_ids)) {
dev_info(dev, "ACP3.x PCI device present, deferring to acp3x-alc5682-max98357\n");
return -ENODEV;
}
card = (struct snd_soc_card *)acp_soc_is_rltk_max(dev);
if (!card)
return -ENODEV;
+1 -1
View File
@@ -104,7 +104,7 @@ static void disable_pdm_interrupts(void __iomem *acp_base)
u32 ext_int_ctrl;
ext_int_ctrl = rn_readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
ext_int_ctrl |= ~PDM_DMA_INTR_MASK;
ext_int_ctrl &= ~PDM_DMA_INTR_MASK;
rn_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL);
}
+14
View File
@@ -388,6 +388,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Nitro ANV15-41"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "RB"),
DMI_MATCH(DMI_PRODUCT_NAME, "Nitro AN17-41"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
@@ -892,6 +899,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "TM2423"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP 255R 15.6 inch G10 Notebook PC"),
}
},
{}
};
+2
View File
@@ -275,9 +275,11 @@ static int acp6x_pdm_dma_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct pdm_dev_data *adata = dev_get_drvdata(component->dev);
struct snd_pcm_runtime *runtime = substream->runtime;
acp6x_disable_pdm_interrupts(adata->acp6x_base);
adata->capture_stream = NULL;
kfree(runtime->private_data);
return 0;
}
+1
View File
@@ -285,6 +285,7 @@ static const struct of_device_id snd_soc_bcm_audio_match[] = {
{.compatible = "brcm,bcm63xx-i2s"},
{ }
};
MODULE_DEVICE_TABLE(of, snd_soc_bcm_audio_match);
#endif
static struct platform_driver bcm63xx_i2s_driver = {
File diff suppressed because it is too large Load Diff
+2 -5
View File
@@ -386,11 +386,8 @@ static int __maybe_unused cs35l56_sdw_system_suspend(struct device *dev)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
if (!cs35l56->base.init_done)
return 0;
/* runtime_resume unmasks the interrupt */
cs35l56_mask_soundwire_interrupts(cs35l56);
if (cs35l56->sdw_attached)
cs35l56_mask_soundwire_interrupts(cs35l56);
return cs35l56_system_suspend(dev);
}
+103 -13
View File
@@ -18,9 +18,11 @@
#include <linux/interrupt.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -37,6 +39,13 @@
#include "wm_adsp.h"
#include "cs35l56.h"
/*
* snd_soc_register_component() can call component_probe() on all instances
* in a card, so deferred registration must be protected across all instances.
*/
static DEFINE_MUTEX(cs35l56_component_register_lock);
static bool cs35l56_shutting_down;
void cs35l56_mask_soundwire_interrupts(struct cs35l56_private *cs35l56)
{
/*
@@ -1365,12 +1374,6 @@ static int _cs35l56_component_probe(struct snd_soc_component *component)
BUILD_BUG_ON(ARRAY_SIZE(cs35l56_tx_input_texts) != ARRAY_SIZE(cs35l56_tx_input_values));
if (!wait_for_completion_timeout(&cs35l56->init_completion,
msecs_to_jiffies(5000))) {
dev_err(cs35l56->base.dev, "%s: init_completion timed out\n", __func__);
return -ENODEV;
}
cs35l56->dsp.part = kasprintf(GFP_KERNEL, "cs35l%02x", cs35l56->base.type);
if (!cs35l56->dsp.part)
return -ENOMEM;
@@ -1939,6 +1942,45 @@ static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l5
return ret;
}
static int cs35l56_component_register(struct cs35l56_private *cs35l56)
{
int ret;
ret = snd_soc_register_component(cs35l56->base.dev,
&soc_component_dev_cs35l56,
cs35l56_dai, ARRAY_SIZE(cs35l56_dai));
if (ret < 0) {
dev_err(cs35l56->base.dev, "Register codec failed: %d\n", ret);
return ret;
}
cs35l56->component_registered = true;
return 0;
}
static void cs35l56_component_register_work(struct work_struct *work)
{
struct cs35l56_private *cs35l56 = container_of(work,
struct cs35l56_private,
component_register_work);
int ret;
guard(mutex)(&cs35l56_component_register_lock);
if (cs35l56_shutting_down)
return;
PM_RUNTIME_ACQUIRE_AUTOSUSPEND(cs35l56->base.dev, pm_err);
ret = PM_RUNTIME_ACQUIRE_ERR(&pm_err);
if (ret) {
dev_err(cs35l56->base.dev, "register_work failed to get pm_runtime: %d\n", ret);
return;
}
cs35l56_component_register(cs35l56);
}
int cs35l56_common_probe(struct cs35l56_private *cs35l56, int irq)
{
int ret;
@@ -1947,6 +1989,7 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56, int irq)
mutex_init(&cs35l56->base.irq_lock);
cs35l56->base.cal_index = -1;
cs35l56->speaker_id = -ENOENT;
INIT_WORK(&cs35l56->component_register_work, cs35l56_component_register_work);
dev_set_drvdata(cs35l56->base.dev, cs35l56);
@@ -2020,12 +2063,17 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56, int irq)
if (ret)
goto err_remove_wm_adsp;
ret = snd_soc_register_component(cs35l56->base.dev,
&soc_component_dev_cs35l56,
cs35l56_dai, ARRAY_SIZE(cs35l56_dai));
if (ret < 0) {
dev_err_probe(cs35l56->base.dev, ret, "Register codec failed\n");
goto err_free_irq;
/*
* Defer calling snd_soc_register_component() on SoundWire to prevent
* a deadlock where it calls our component_probe(), which requires the
* SoundWire enumeration to complete, but because we are still in probe()
* the SoundWire core will not call the update_status() callback. At time
* of writing snd_soc_register_component() never returns EPROBE_DEFER.
*/
if (!cs35l56->sdw_peripheral) {
ret = cs35l56_component_register(cs35l56);
if (ret < 0)
goto err_free_irq;
}
return 0;
@@ -2055,6 +2103,7 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_common_probe, "SND_SOC_CS35L56_CORE");
int cs35l56_init(struct cs35l56_private *cs35l56)
{
bool first_time_init = !cs35l56->base.init_done;
int ret;
/*
@@ -2131,13 +2180,23 @@ post_soft_reset:
cs35l56->base.init_done = true;
complete_all(&cs35l56->init_completion);
if (cs35l56->sdw_peripheral && first_time_init) {
/*
* Hardware now accessible, queue work to call
* snd_soc_register_component().
*/
queue_work(system_freezable_wq, &cs35l56->component_register_work);
}
return 0;
}
EXPORT_SYMBOL_NS_GPL(cs35l56_init, "SND_SOC_CS35L56_CORE");
void cs35l56_remove(struct cs35l56_private *cs35l56)
{
snd_soc_unregister_component(cs35l56->base.dev);
cancel_work_sync(&cs35l56->component_register_work);
if (cs35l56->component_registered)
snd_soc_unregister_component(cs35l56->base.dev);
cs35l56->base.init_done = false;
@@ -2172,6 +2231,37 @@ EXPORT_NS_GPL_DEV_PM_OPS(cs35l56_pm_ops_i2c_spi, SND_SOC_CS35L56_CORE) = {
};
#endif
static int cs35l56_reboot_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
guard(mutex)(&cs35l56_component_register_lock);
cs35l56_shutting_down = true;
return NOTIFY_DONE;
}
static struct notifier_block cs35l56_reboot_notifier = {
.notifier_call = cs35l56_reboot_notify,
};
static int __init cs35l56_modinit(void)
{
/*
* Use reboot notifier to prevent race between shutdown and
* snd_soc_register_component(). Driver shutdown() callback would
* run too late, after device_shutdown() is already walking the
* device list that component registration can modify.
*/
return register_reboot_notifier(&cs35l56_reboot_notifier);
}
module_init(cs35l56_modinit);
static void __exit cs35l56_modexit(void)
{
unregister_reboot_notifier(&cs35l56_reboot_notifier);
}
module_exit(cs35l56_modexit);
MODULE_DESCRIPTION("ASoC CS35L56 driver");
MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");
+2
View File
@@ -32,6 +32,7 @@ struct sdw_slave;
struct cs35l56_private {
struct wm_adsp dsp; /* must be first member */
struct cs35l56_base base;
struct work_struct component_register_work;
struct work_struct dsp_work;
struct workqueue_struct *dsp_wq;
struct snd_soc_component *component;
@@ -41,6 +42,7 @@ struct cs35l56_private {
const char *fallback_fw_suffix;
bool soft_resetting;
bool sdw_attached;
bool component_registered;
struct completion init_completion;
int speaker_id;
+17 -2
View File
@@ -26,6 +26,7 @@ struct es8326_priv {
struct snd_soc_component *component;
struct delayed_work jack_detect_work;
struct delayed_work button_press_work;
struct delayed_work capture_pop_work;
struct snd_soc_jack *jack;
int irq;
/* The lock protects the situation that an irq is generated
@@ -628,6 +629,7 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction)
regmap_update_bits(es8326->regmap, ES8326_HP_DRIVER_REF,
0x30, 0x00);
} else {
cancel_delayed_work_sync(&es8326->capture_pop_work);
regmap_update_bits(es8326->regmap, ES8326_ADC_MUTE,
0x0F, 0x0F);
if (es8326->version > ES8326_VERSION_B) {
@@ -666,8 +668,9 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction)
regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x70, 0x70);
regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x00);
}
regmap_update_bits(es8326->regmap, ES8326_ADC_MUTE,
0x0F, 0x00);
queue_delayed_work(system_dfl_wq, &es8326->capture_pop_work,
msecs_to_jiffies(40));
}
}
return 0;
@@ -773,6 +776,15 @@ static void es8326_disable_micbias(struct snd_soc_component *component)
snd_soc_dapm_mutex_unlock(dapm);
}
static void es8326_capture_pop_handler(struct work_struct *work)
{
struct es8326_priv *es8326 =
container_of(work, struct es8326_priv, capture_pop_work.work);
regmap_update_bits(es8326->regmap, ES8326_ADC_MUTE,
0x0F, 0x00);
}
/*
* For button detection, set the following in soundcard
* snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
@@ -1140,6 +1152,7 @@ static int es8326_suspend(struct snd_soc_component *component)
struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
cancel_delayed_work_sync(&es8326->jack_detect_work);
cancel_delayed_work_sync(&es8326->capture_pop_work);
es8326_disable_micbias(component);
es8326->calibrated = false;
regmap_write(es8326->regmap, ES8326_CLK_MUX, 0x2d);
@@ -1291,6 +1304,8 @@ static int es8326_i2c_probe(struct i2c_client *i2c)
es8326_jack_detect_handler);
INIT_DELAYED_WORK(&es8326->button_press_work,
es8326_jack_button_handler);
INIT_DELAYED_WORK(&es8326->capture_pop_work,
es8326_capture_pop_handler);
/* ES8316 is level-based while ES8326 is edge-based */
ret = devm_request_threaded_irq(&i2c->dev, es8326->irq, NULL, es8326_irq,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+20 -14
View File
@@ -812,6 +812,23 @@ static int es8389_pcm_hw_free(struct snd_pcm_substream *substream,
return 0;
}
static void es8389_standby(struct snd_soc_component *component)
{
struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, 0x04);
regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, 0x04);
regmap_write(es8389->regmap, ES8389_CSM_JUMP, 0xD4);
usleep_range(70000, 72000);
regmap_write(es8389->regmap, ES8389_ANA_CTL1, 0x59);
regmap_write(es8389->regmap, ES8389_ADC_EN, 0x00);
regmap_write(es8389->regmap, ES8389_CLK_OFF1, 0x00);
regmap_write(es8389->regmap, ES8389_RESET, 0x3E);
regmap_update_bits(es8389->regmap, ES8389_DAC_INV, 0x80, 0x80);
usleep_range(8000, 8500);
regmap_update_bits(es8389->regmap, ES8389_DAC_INV, 0x80, 0x00);
}
static int es8389_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
@@ -834,18 +851,7 @@ static int es8389_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, 0x04);
regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, 0x04);
regmap_write(es8389->regmap, ES8389_CSM_JUMP, 0xD4);
usleep_range(70000, 72000);
regmap_write(es8389->regmap, ES8389_ANA_CTL1, 0x59);
regmap_write(es8389->regmap, ES8389_ADC_EN, 0x00);
regmap_write(es8389->regmap, ES8389_CLK_OFF1, 0x00);
regmap_write(es8389->regmap, ES8389_RESET, 0x3E);
regmap_update_bits(es8389->regmap, ES8389_DAC_INV, 0x80, 0x80);
usleep_range(8000, 8500);
regmap_update_bits(es8389->regmap, ES8389_DAC_INV, 0x80, 0x00);
es8389_standby(component);
clk_disable_unprepare(es8389->mclk);
break;
case SND_SOC_BIAS_OFF:
@@ -1015,7 +1021,7 @@ static int es8389_suspend(struct snd_soc_component *component)
{
struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
es8389_set_bias_level(component, SND_SOC_BIAS_STANDBY);
es8389_standby(component);
regcache_cache_only(es8389->regmap, true);
regcache_mark_dirty(es8389->regmap);
@@ -1084,7 +1090,7 @@ static int es8389_probe(struct snd_soc_component *component)
es8389->hpf_freq = ES8389_HPF_DEFAULT;
es8389_init(component);
es8389_set_bias_level(component, SND_SOC_BIAS_STANDBY);
es8389_standby(component);
return 0;
}
+1
View File
@@ -1478,6 +1478,7 @@ static const struct of_device_id mt6351_of_match[] = {
{.compatible = "mediatek,mt6351-sound",},
{}
};
MODULE_DEVICE_TABLE(of, mt6351_of_match);
static struct platform_driver mt6351_codec_driver = {
.driver = {
+7 -17
View File
@@ -16,6 +16,7 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc-dapm.h>
#include <sound/sdw.h>
#include <sound/initval.h>
#include "rt1318-sdw.h"
@@ -564,11 +565,10 @@ static int rt1318_sdw_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct rt1318_sdw_priv *rt1318 =
snd_soc_component_get_drvdata(component);
struct sdw_stream_config stream_config;
struct sdw_stream_config stream_config = {0};
struct sdw_port_config port_config;
enum sdw_data_direction direction;
struct sdw_stream_runtime *sdw_stream;
int retval, port, num_channels, ch_mask;
int retval, port;
unsigned int sampling_rate;
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
@@ -582,23 +582,13 @@ static int rt1318_sdw_hw_params(struct snd_pcm_substream *substream,
/* SoundWire specific configuration */
/* port 1 for playback */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
direction = SDW_DATA_DIR_RX;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
port = 1;
} else {
direction = SDW_DATA_DIR_TX;
else
port = 2;
}
num_channels = params_channels(params);
ch_mask = (1 << num_channels) - 1;
stream_config.frame_rate = params_rate(params);
stream_config.ch_count = num_channels;
stream_config.bps = snd_pcm_format_width(params_format(params));
stream_config.direction = direction;
port_config.ch_mask = ch_mask;
/* SoundWire specific configuration */
snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
port_config.num = port;
retval = sdw_stream_add_slave(rt1318->sdw_slave, &stream_config,
+1 -1
View File
@@ -3246,7 +3246,7 @@ static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct rt1320_sdw_priv *rt1320 =
snd_soc_component_get_drvdata(component);
struct sdw_stream_config stream_config;
struct sdw_stream_config stream_config = {0};
struct sdw_port_config port_config;
struct sdw_port_config dmic_port_config[2];
struct sdw_stream_runtime *sdw_stream;
+5 -12
View File
@@ -23,6 +23,7 @@
#include <linux/soundwire/sdw_registers.h>
#include <linux/slab.h>
#include <sound/soc-dapm.h>
#include <sound/sdw.h>
#include <sound/tlv.h>
#include "rt712-sdca.h"
@@ -1449,11 +1450,10 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
struct sdw_stream_config stream_config;
struct sdw_stream_config stream_config = {0};
struct sdw_port_config port_config;
enum sdw_data_direction direction;
struct sdw_stream_runtime *sdw_stream;
int retval, port, num_channels;
int retval, port;
unsigned int sampling_rate;
dev_dbg(dai->dev, "%s %s id %d", __func__, dai->name, dai->id);
@@ -1471,7 +1471,6 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
/* SoundWire specific configuration */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
direction = SDW_DATA_DIR_RX;
if (dai->id == RT712_AIF1)
port = 1;
else if (dai->id == RT712_AIF2)
@@ -1479,7 +1478,6 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
else
return -EINVAL;
} else {
direction = SDW_DATA_DIR_TX;
if (dai->id == RT712_AIF1)
port = 4;
else if (dai->id == RT712_AIF3)
@@ -1488,13 +1486,8 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
stream_config.frame_rate = params_rate(params);
stream_config.ch_count = params_channels(params);
stream_config.bps = snd_pcm_format_width(params_format(params));
stream_config.direction = direction;
num_channels = params_channels(params);
port_config.ch_mask = GENMASK(num_channels - 1, 0);
/* SoundWire specific configuration */
snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
port_config.num = port;
retval = sdw_stream_add_slave(rt712->slave, &stream_config,
+6 -11
View File
@@ -21,6 +21,7 @@
#include <linux/soundwire/sdw_registers.h>
#include <linux/slab.h>
#include <sound/soc-dapm.h>
#include <sound/sdw.h>
#include <sound/tlv.h>
#include "rt721-sdca.h"
@@ -206,6 +207,7 @@ static void rt721_sdca_amp_preset(struct rt721_sdca_priv *rt721)
regmap_write(rt721->regmap,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
RT721_SDCA_CTL_FU_MUTE, CH_02), 0x00);
regmap_write(rt721->regmap, 0x2f5d, 0x1);
}
static void rt721_sdca_jack_preset(struct rt721_sdca_priv *rt721)
@@ -1268,11 +1270,10 @@ static int rt721_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
struct sdw_stream_config stream_config;
struct sdw_stream_config stream_config = {0};
struct sdw_port_config port_config;
enum sdw_data_direction direction;
struct sdw_stream_runtime *sdw_stream;
int retval, port, num_channels;
int retval, port;
unsigned int sampling_rate;
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
@@ -1291,7 +1292,6 @@ static int rt721_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
* RT721_AIF3 with port = 6 for digital-mic capture
*/
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
direction = SDW_DATA_DIR_RX;
if (dai->id == RT721_AIF1)
port = 1;
else if (dai->id == RT721_AIF2)
@@ -1299,7 +1299,6 @@ static int rt721_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
else
return -EINVAL;
} else {
direction = SDW_DATA_DIR_TX;
if (dai->id == RT721_AIF1)
port = 2;
else if (dai->id == RT721_AIF3)
@@ -1307,13 +1306,9 @@ static int rt721_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
else
return -EINVAL;
}
stream_config.frame_rate = params_rate(params);
stream_config.ch_count = params_channels(params);
stream_config.bps = snd_pcm_format_width(params_format(params));
stream_config.direction = direction;
num_channels = params_channels(params);
port_config.ch_mask = GENMASK(num_channels - 1, 0);
/* SoundWire specific configuration */
snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
port_config.num = port;
retval = sdw_stream_add_slave(rt721->slave, &stream_config,
+5 -11
View File
@@ -24,6 +24,7 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc-dapm.h>
#include <sound/sdw.h>
#include <sound/tlv.h>
#include "rt722-sdca.h"
@@ -1442,11 +1443,10 @@ static int rt722_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
struct sdw_stream_config stream_config;
struct sdw_stream_config stream_config = {0};
struct sdw_port_config port_config;
enum sdw_data_direction direction;
struct sdw_stream_runtime *sdw_stream;
int retval, port, num_channels;
int retval, port;
unsigned int sampling_rate;
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
@@ -1465,7 +1465,6 @@ static int rt722_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
* RT722_AIF3 with port = 6 for digital-mic capture
*/
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
direction = SDW_DATA_DIR_RX;
if (dai->id == RT722_AIF1)
port = 1;
else if (dai->id == RT722_AIF2)
@@ -1473,7 +1472,6 @@ static int rt722_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
else
return -EINVAL;
} else {
direction = SDW_DATA_DIR_TX;
if (dai->id == RT722_AIF1)
port = 2;
else if (dai->id == RT722_AIF3)
@@ -1481,13 +1479,9 @@ static int rt722_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
else
return -EINVAL;
}
stream_config.frame_rate = params_rate(params);
stream_config.ch_count = params_channels(params);
stream_config.bps = snd_pcm_format_width(params_format(params));
stream_config.direction = direction;
num_channels = params_channels(params);
port_config.ch_mask = GENMASK(num_channels - 1, 0);
/* SoundWire specific configuration */
snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
port_config.num = port;
retval = sdw_stream_add_slave(rt722->slave, &stream_config,
+1 -4
View File
@@ -936,9 +936,8 @@ static int rt766_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
struct sdw_stream_config stream_config;
struct sdw_stream_config stream_config = {0};
struct sdw_port_config port_config;
enum sdw_data_direction direction;
struct sdw_stream_runtime *sdw_stream;
unsigned int sampling_rate;
int retval, port;
@@ -957,7 +956,6 @@ static int rt766_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
/* SoundWire specific configuration */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
direction = SDW_DATA_DIR_RX;
if (dai->id == RT766_AIF1)
port = 3;
else if (dai->id == RT766_AIF2)
@@ -965,7 +963,6 @@ static int rt766_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
else
return -EINVAL;
} else {
direction = SDW_DATA_DIR_TX;
if (dai->id == RT766_AIF1)
port = 12;
else if (dai->id == RT766_AIF3)
+25
View File
@@ -1001,6 +1001,31 @@ static s32 tas_sdw_hw_params(struct snd_pcm_substream *substream,
/* SoundWire specific configuration */
snd_sdw_params_to_config(substream, params,
&stream_config, &port_config);
/*
* The two mono amps each render one channel of the stereo stream:
* snd_sdw_params_to_config() hands every codec the full mask for
* playback, which leaves the pair in mirror mode and one channel
* unreproduced. Claim a single channel instead, keyed off the
* machine-assigned component prefix rather than the SoundWire
* address, which is board-specific: soc_sdw_ti_amp.c names the amps
* tas2783-1..4.
*
* Which side an amp then renders does not follow from the bit that
* is set - sdw_compute_slave_ports() advances the payload offset by
* the popcount of ch_mask and never looks at which bit it is - but
* from the amp's position in the codec order of the DAI link, which
* on these boards matches the prefix numbering.
*/
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
params_channels(params) == 2 && component->name_prefix) {
const char *idx_str = strrchr(component->name_prefix, '-');
unsigned long idx;
if (idx_str && !kstrtoul(idx_str + 1, 10, &idx) && idx)
port_config.ch_mask = (idx & 1) ? BIT(0) : BIT(1);
}
/* port 1 for playback */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
port_config.num = 1;
+13 -8
View File
@@ -953,12 +953,17 @@ static int fsl_micfil_reparent_rootclk(struct fsl_micfil *micfil, unsigned int s
/* Get root clock */
clk = micfil->mclk;
/* Disable clock first, for it was enabled by pm_runtime */
/* Reparent root clock to the PLL matching this sample rate */
fsl_asoc_reparent_pll_clocks(dev, clk, micfil->pll8k_clk,
micfil->pll11k_clk, ratio);
ret = clk_prepare_enable(clk);
if (ret)
return ret;
/* Enable only once; hw_params can be called multiple times */
if (!micfil->mclk_flag) {
ret = clk_prepare_enable(clk);
if (ret)
return ret;
micfil->mclk_flag = true;
}
return 0;
}
@@ -991,8 +996,6 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
if (ret)
return ret;
micfil->mclk_flag = true;
/* floor(K * CLKDIV) */
switch (micfil->quality) {
case QUALITY_HIGH:
@@ -1068,8 +1071,10 @@ static int fsl_micfil_hw_free(struct snd_pcm_substream *substream,
{
struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai);
clk_disable_unprepare(micfil->mclk);
micfil->mclk_flag = false;
if (micfil->mclk_flag) {
clk_disable_unprepare(micfil->mclk);
micfil->mclk_flag = false;
}
return 0;
}
+1
View File
@@ -167,6 +167,7 @@ static const struct pci_device_id intel_sst_ids[] = {
{ PCI_DEVICE_DATA(INTEL, SST_TNG, 0) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, intel_sst_ids);
static struct pci_driver sst_driver = {
.name = SST_DRV_NAME,
+17
View File
@@ -15,6 +15,22 @@
#include "../../../codecs/hda.h"
#include "../utils.h"
static int avs_link_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
const struct snd_soc_pcm_stream *stream_info;
struct snd_soc_dai *codec_dai;
codec_dai = snd_soc_rtd_to_codec(rtd, 0);
stream_info = snd_soc_dai_get_pcm_stream(codec_dai, substream->stream);
return snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, stream_info->sig_bits);
}
static const struct snd_soc_ops avs_link_ops = {
.startup = avs_link_startup,
};
static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int pcm_count,
struct snd_soc_dai_link **links)
{
@@ -43,6 +59,7 @@ static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int
dl[i].platforms = platform;
dl[i].num_platforms = 1;
dl[i].ignore_pmdown_time = 1;
dl[i].ops = &avs_link_ops;
dl[i].codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
dl[i].cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+41 -18
View File
@@ -92,16 +92,28 @@ static int avs_hdac_bus_init_streams(struct hdac_bus *bus)
{
unsigned int cp_streams, pb_streams;
unsigned int gcap;
int ret;
gcap = snd_hdac_chip_readw(bus, GCAP);
cp_streams = (gcap >> 8) & 0x0F;
pb_streams = (gcap >> 12) & 0x0F;
bus->num_streams = cp_streams + pb_streams;
snd_hdac_ext_stream_init_all(bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
snd_hdac_ext_stream_init_all(bus, cp_streams, pb_streams, SNDRV_PCM_STREAM_PLAYBACK);
ret = snd_hdac_ext_stream_init_all(bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
if (ret)
return ret;
ret = snd_hdac_ext_stream_init_all(bus, cp_streams, pb_streams, SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto err;
return snd_hdac_bus_alloc_stream_pages(bus);
ret = snd_hdac_bus_alloc_stream_pages(bus);
if (ret)
goto err;
return 0;
err:
snd_hdac_ext_stream_free_all(bus);
return ret;
}
static bool avs_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset)
@@ -383,6 +395,18 @@ static int avs_bus_init(struct avs_dev *adev, struct pci_dev *pci, const struct
struct device *dev = &pci->dev;
int ret;
ipc = devm_kzalloc(dev, sizeof(*ipc), GFP_KERNEL);
if (!ipc)
return -ENOMEM;
adev->modcfg_buf = devm_kzalloc(dev, AVS_MAILBOX_SIZE, GFP_KERNEL);
if (!adev->modcfg_buf)
return -ENOMEM;
ret = avs_ipc_init(ipc, dev);
if (ret < 0)
return ret;
ret = snd_hdac_ext_bus_init(&bus->core, dev, NULL, &soc_hda_ext_bus_ops);
if (ret < 0)
return ret;
@@ -394,17 +418,6 @@ static int avs_bus_init(struct avs_dev *adev, struct pci_dev *pci, const struct
bus->mixer_assigned = -1;
mutex_init(&bus->prepare_mutex);
ipc = devm_kzalloc(dev, sizeof(*ipc), GFP_KERNEL);
if (!ipc)
return -ENOMEM;
ret = avs_ipc_init(ipc, dev);
if (ret < 0)
return ret;
adev->modcfg_buf = devm_kzalloc(dev, AVS_MAILBOX_SIZE, GFP_KERNEL);
if (!adev->modcfg_buf)
return -ENOMEM;
adev->dev = dev;
adev->spec = (const struct avs_spec *)id->driver_data;
adev->ipc = ipc;
@@ -456,13 +469,14 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
ret = pcim_request_all_regions(pci, "AVS HDAudio");
if (ret < 0)
return ret;
goto err_request_regions;
bus->addr = pci_resource_start(pci, 0);
bus->remap_addr = pci_ioremap_bar(pci, 0);
if (!bus->remap_addr) {
dev_err(bus->dev, "ioremap error\n");
return -ENXIO;
ret = -ENXIO;
goto err_request_regions;
}
adev->dsp_ba = pci_ioremap_bar(pci, 4);
@@ -473,8 +487,13 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
}
snd_hdac_bus_parse_capabilities(bus);
if (bus->mlcap)
snd_hdac_ext_bus_get_ml_capabilities(bus);
if (bus->mlcap) {
ret = snd_hdac_ext_bus_get_ml_capabilities(bus);
if (ret < 0) {
dev_err(dev, "failed to get ml capabilities: %d\n", ret);
goto err_ml_cap;
}
}
if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)))
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
@@ -516,9 +535,13 @@ err_acquire_irq:
snd_hdac_bus_free_stream_pages(bus);
snd_hdac_ext_stream_free_all(bus);
err_init_streams:
snd_hdac_ext_link_free_all(bus);
err_ml_cap:
iounmap(adev->dsp_ba);
err_remap_bar4:
iounmap(bus->remap_addr);
err_request_regions:
snd_hdac_ext_bus_exit(bus);
return ret;
}
+9 -3
View File
@@ -9,6 +9,7 @@
#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/kfifo.h>
#include <linux/module.h>
#include <linux/wait.h>
#include <linux/sched/signal.h>
#include <linux/string_helpers.h>
@@ -236,15 +237,20 @@ static int strace_open(struct inode *inode, struct file *file)
if (!try_module_get(adev->dev->driver->owner))
return -ENODEV;
if (kfifo_initialized(&adev->trace_fifo))
return -EBUSY;
if (kfifo_initialized(&adev->trace_fifo)) {
ret = -EBUSY;
goto err;
}
ret = kfifo_alloc(&adev->trace_fifo, PAGE_SIZE, GFP_KERNEL);
if (ret < 0)
return ret;
goto err;
file->private_data = adev;
return 0;
err:
module_put(adev->dev->driver->owner);
return ret;
}
static int strace_release(struct inode *inode, struct file *file)
+3 -3
View File
@@ -172,7 +172,7 @@ static void avs_dsp_exception_caught(struct avs_dev *adev, union avs_notify_msg
/* Avoid deadlock as the exception may be the response to SET_D0IX. */
if (current_work() != &ipc->d0ix_work.work)
cancel_delayed_work_sync(&ipc->d0ix_work);
cancel_delayed_work(&ipc->d0ix_work);
ipc->in_d0ix = false;
/* Re-enabled on recovery completion. */
pm_runtime_disable(adev->dev);
@@ -395,11 +395,11 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
struct avs_ipc *ipc = adev->ipc;
int ret;
guard(mutex)(&ipc->msg_mutex);
if (!ipc->ready)
return -EPERM;
guard(mutex)(&ipc->msg_mutex);
spin_lock(&ipc->rx_lock);
avs_ipc_msg_init(ipc, reply);
avs_dsp_send_tx(adev, request, true);
+3 -8
View File
@@ -836,15 +836,10 @@ static int avs_path_module_type_create(struct avs_dev *adev, struct avs_path_mod
static int avs_path_module_send_init_configs(struct avs_dev *adev, struct avs_path_module *mod)
{
struct avs_soc_component *acomp;
struct avs_tplg_module *template = mod->template;
acomp = to_avs_soc_component(mod->template->owner->owner->owner->owner->comp);
u32 num_ids = mod->template->num_config_ids;
u32 *ids = mod->template->config_ids;
for (int i = 0; i < num_ids; i++) {
struct avs_tplg_init_config *config = &acomp->tplg->init_configs[ids[i]];
for (int i = 0; i < template->num_init_configs; i++) {
struct avs_tplg_init_config *config = template->init_configs[i];
size_t len = config->length;
void *data = config->data;
u32 param = config->param;
+20 -14
View File
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <sound/hda_register.h>
@@ -987,13 +988,25 @@ static int avs_component_load_libraries(struct avs_soc_component *acomp)
return ret;
}
static int avs_request_topology(struct snd_soc_component *component, const char *name,
const struct firmware **fw)
{
char *fullname __free(kfree) = NULL;
fullname = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix, name);
if (!fullname)
return -ENOMEM;
return request_firmware(fw, fullname, component->dev);
}
static int avs_component_probe(struct snd_soc_component *component)
{
struct snd_soc_card *card = component->card;
struct snd_soc_acpi_mach *mach;
struct avs_soc_component *acomp;
const struct firmware *fw;
struct avs_dev *adev;
char *filename;
int ret;
dev_dbg(card->dev, "probing %s card %s\n", component->name, card->name);
@@ -1009,13 +1022,7 @@ static int avs_component_probe(struct snd_soc_component *component)
goto finalize;
/* Load specified topology and create debugfs for it. */
filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix,
mach->tplg_filename);
if (!filename)
return -ENOMEM;
ret = avs_load_topology(component, filename);
kfree(filename);
ret = avs_request_topology(component, mach->tplg_filename, &fw);
if (ret == -ENOENT && !strncmp(mach->tplg_filename, "hda-", 4)) {
unsigned int vendor_id;
@@ -1030,18 +1037,17 @@ static int avs_component_probe(struct snd_soc_component *component)
"hda-generic-tplg.bin");
if (!mach->tplg_filename)
return -ENOMEM;
filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix,
mach->tplg_filename);
if (!filename)
return -ENOMEM;
dev_info(card->dev, "trying to load fallback topology %s\n", mach->tplg_filename);
ret = avs_load_topology(component, filename);
kfree(filename);
ret = avs_request_topology(component, mach->tplg_filename, &fw);
}
if (ret < 0)
return ret;
ret = snd_soc_tplg_component_load(component, &avs_tplg_ops, fw);
if (ret)
return ret;
ret = avs_component_load_libraries(acomp);
if (ret < 0) {
dev_err(card->dev, "libraries loading failed: %d\n", ret);
+28 -21
View File
@@ -350,6 +350,7 @@ AVS_DEFINE_PTR_PARSER(modcfg_base, struct avs_tplg_modcfg_base, modcfgs_base);
AVS_DEFINE_PTR_PARSER(modcfg_ext, struct avs_tplg_modcfg_ext, modcfgs_ext);
AVS_DEFINE_PTR_PARSER(pplcfg, struct avs_tplg_pplcfg, pplcfgs);
AVS_DEFINE_PTR_PARSER(binding, struct avs_tplg_binding, bindings);
AVS_DEFINE_PTR_PARSER(init_config, struct avs_tplg_init_config, init_configs);
AVS_DEFINE_PTR_PARSER(nhlt_config, struct avs_tplg_nhlt_config, nhlt_configs);
static int
@@ -1198,7 +1199,7 @@ static const struct avs_tplg_token_parser module_parsers[] = {
{
.token = AVS_TKN_MOD_INIT_CONFIG_NUM_IDS_U32,
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
.offset = offsetof(struct avs_tplg_module, num_config_ids),
.offset = offsetof(struct avs_tplg_module, num_init_configs),
.parse = avs_parse_byte_token,
},
{
@@ -1214,10 +1215,32 @@ static const struct avs_tplg_token_parser init_config_parsers[] = {
.token = AVS_TKN_MOD_INIT_CONFIG_ID_U32,
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
.offset = 0,
.parse = avs_parse_word_token,
.parse = avs_parse_init_config_ptr,
},
};
static int avs_tplg_module_init_configs(struct snd_soc_component *comp,
struct avs_tplg_module *module,
struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
{
struct avs_tplg_init_config **cfgs;
int ret;
if (!module->num_init_configs)
return -EINVAL;
cfgs = devm_kcalloc(comp->card->dev, module->num_init_configs, sizeof(*cfgs), GFP_KERNEL);
if (!cfgs)
return -ENOMEM;
ret = parse_dictionary_entries(comp, tuples, block_size, cfgs, module->num_init_configs,
sizeof(*cfgs), AVS_TKN_MOD_INIT_CONFIG_ID_U32,
init_config_parsers, ARRAY_SIZE(init_config_parsers));
if (!ret)
module->init_configs = cfgs;
return ret;
}
static struct avs_tplg_module *
avs_tplg_module_create(struct snd_soc_component *comp, struct avs_tplg_pipeline *owner,
struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
@@ -1244,27 +1267,11 @@ avs_tplg_module_create(struct snd_soc_component *comp, struct avs_tplg_pipeline
block_size -= esize;
/* Parse trailing config ids if any. */
if (block_size) {
u32 num_config_ids = module->num_config_ids;
u32 *config_ids;
if (!num_config_ids)
return ERR_PTR(-EINVAL);
config_ids = devm_kcalloc(comp->card->dev, num_config_ids, sizeof(*config_ids),
GFP_KERNEL);
if (!config_ids)
return ERR_PTR(-ENOMEM);
tuples = avs_tplg_vendor_array_at(tuples, esize);
ret = parse_dictionary_entries(comp, tuples, block_size,
config_ids, num_config_ids, sizeof(*config_ids),
AVS_TKN_MOD_INIT_CONFIG_ID_U32,
init_config_parsers,
ARRAY_SIZE(init_config_parsers));
ret = avs_tplg_module_init_configs(comp, module, tuples, block_size);
if (ret)
return ERR_PTR(ret);
module->config_ids = config_ids;
}
module->owner = owner;
@@ -2194,7 +2201,7 @@ avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_
return 0;
}
static const struct snd_soc_tplg_ops avs_tplg_ops = {
const struct snd_soc_tplg_ops avs_tplg_ops = {
.io_ops = avs_control_ops,
.io_ops_count = ARRAY_SIZE(avs_control_ops),
.control_load = avs_control_load,
+3 -2
View File
@@ -221,8 +221,8 @@ struct avs_tplg_module {
u8 domain;
struct avs_tplg_modcfg_ext *cfg_ext;
u32 ctl_id;
u32 num_config_ids;
u32 *config_ids;
u32 num_init_configs;
struct avs_tplg_init_config **init_configs;
struct avs_tplg_nhlt_config *nhlt_config;
struct avs_tplg_pipeline *owner;
@@ -230,6 +230,7 @@ struct avs_tplg_module {
struct list_head node;
};
extern const struct snd_soc_tplg_ops avs_tplg_ops;
struct avs_tplg *avs_tplg_new(struct snd_soc_component *comp);
int avs_load_topology(struct snd_soc_component *comp, const char *filename);
+3 -1
View File
@@ -533,12 +533,14 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
select SND_SOC_CS35L56_SPI
select SND_SOC_CS35L56_SDW
select SND_SOC_ES9356
imply SND_SOC_TAC5XX2_SDW
select SND_SOC_DMIC
select SND_SOC_INTEL_HDA_DSP_COMMON
imply SND_SOC_SDW_MOCKUP
help
Add support for Intel SoundWire-based platforms connected to
MAX98373, RT700, RT711, RT1308 and RT715
MAX98373, RT700, RT711, RT1308, RT715, TAC5XX2_SDW family (including
TAC5572, TAC5682).
If unsure select "N".
endif
+8
View File
@@ -908,6 +908,14 @@ static const struct platform_device_id board_ids[] = {
SOF_SSP_PORT_BT_OFFLOAD(2) |
SOF_BT_OFFLOAD_PRESENT),
},
{
.name = "nvl_rt5682_def",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
SOF_SSP_PORT_CODEC(0) |
SOF_SSP_PORT_AMP(1) |
SOF_SSP_PORT_BT_OFFLOAD(2) |
SOF_BT_OFFLOAD_PRESENT),
},
{
.name = "ptl_rt5682_c1_h02",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
@@ -51,10 +51,10 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_nvl_machines[] = {
},
{
.comp_ids = &nvl_rt5682_rt5682s_hp,
.drv_name = "sof_rt5682",
.sof_tplg_filename = "sof-nvl-rt5682", /* the tplg suffix is added at run time */
.tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
SND_SOC_ACPI_TPLG_INTEL_SSP_MSB,
.drv_name = "nvl_rt5682_def",
.sof_tplg_filename = "sof-nvl", /* the tplg suffix is added at run time */
.tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
},
/* place amp/hdmi-in only boards in the end of table */
{
+14 -1
View File
@@ -17,7 +17,7 @@
/* Default values if userspace does not set */
#define SPRD_COMPR_MIN_FRAGMENT_SIZE SZ_8K
#define SPRD_COMPR_MAX_FRAGMENT_SIZE SZ_128K
#define SPRD_COMPR_MAX_FRAGMENT_SIZE SZ_32K
#define SPRD_COMPR_MIN_NUM_FRAGMENTS 4
#define SPRD_COMPR_MAX_NUM_FRAGMENTS 64
@@ -271,6 +271,19 @@ static int sprd_platform_compr_set_params(struct snd_soc_component *component,
struct sprd_compr_params compr_params = { };
int ret;
/*
* The stage 0 IRAM buffer and the stage 1 DDR buffer are allocated
* with fixed sizes at open time, so the requested fragment size and
* fragments must fit into them, otherwise sprd_platform_compr_copy()
* would overflow the buffers. Note the compress core only checks the
* fragment size and fragments against an u32 overflow, not against
* the buffer sizes advertised by get_caps.
*/
if (params->buffer.fragment_size > SPRD_COMPR_IRAM_BUF_SIZE ||
(u64)params->buffer.fragment_size * params->buffer.fragments >
SPRD_COMPR_AREA_BUF_SIZE)
return -EINVAL;
/*
* Configure the DMA engine 2-stage transfer mode. Channel 1 set as the
* destination channel, and channel 0 set as the source channel, that
+2 -2
View File
@@ -416,6 +416,8 @@ int uni_reader_init(struct platform_device *pdev,
else
reader->hw = &uni_reader_pcm_hw;
spin_lock_init(&reader->irq_lock);
ret = devm_request_irq(&pdev->dev, reader->irq,
uni_reader_irq_handler, IRQF_SHARED,
dev_name(&pdev->dev), reader);
@@ -424,8 +426,6 @@ int uni_reader_init(struct platform_device *pdev,
return -EBUSY;
}
spin_lock_init(&reader->irq_lock);
return 0;
}
EXPORT_SYMBOL_GPL(uni_reader_init);
+79 -110
View File
@@ -14,7 +14,7 @@
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <linux/mfd/db8500-prcmu.h>
#include <linux/reset.h>
#include <sound/soc.h>
#include <sound/soc-dai.h>
@@ -34,8 +34,10 @@ static int setup_pcm_multichan(struct snd_soc_dai *dai,
if (drvdata->slots > 1) {
msp_config->multichannel_configured = 1;
multi->tx_multichannel_enable = true;
multi->rx_multichannel_enable = true;
multi->tx_multichannel_enable =
msp_config->direction & MSP_DIR_TX;
multi->rx_multichannel_enable =
msp_config->direction & MSP_DIR_RX;
multi->rx_comparison_enable_mode = MSP_COMPARISON_DISABLED;
multi->tx_channel_0_enable = drvdata->tx_mask;
@@ -57,72 +59,21 @@ static int setup_pcm_multichan(struct snd_soc_dai *dai,
return 0;
}
static int setup_frameper(struct snd_soc_dai *dai, unsigned int rate,
struct msp_protdesc *prot_desc)
static void setup_frameper(struct snd_soc_dai *dai,
struct msp_protdesc *prot_desc)
{
struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
switch (drvdata->slots) {
case 1:
switch (rate) {
case 8000:
prot_desc->frame_period =
FRAME_PER_SINGLE_SLOT_8_KHZ;
break;
case 16000:
prot_desc->frame_period =
FRAME_PER_SINGLE_SLOT_16_KHZ;
break;
case 44100:
prot_desc->frame_period =
FRAME_PER_SINGLE_SLOT_44_1_KHZ;
break;
case 48000:
prot_desc->frame_period =
FRAME_PER_SINGLE_SLOT_48_KHZ;
break;
default:
dev_err(dai->dev,
"%s: Error: Unsupported sample-rate (freq = %d)!\n",
__func__, rate);
return -EINVAL;
}
break;
case 2:
prot_desc->frame_period = FRAME_PER_2_SLOTS;
break;
case 8:
prot_desc->frame_period = FRAME_PER_8_SLOTS;
break;
case 16:
prot_desc->frame_period = FRAME_PER_16_SLOTS;
break;
default:
dev_err(dai->dev,
"%s: Error: Unsupported slot-count (slots = %d)!\n",
__func__, drvdata->slots);
return -EINVAL;
}
prot_desc->clocks_per_frame =
prot_desc->frame_period+1;
prot_desc->clocks_per_frame = drvdata->slots * drvdata->slot_width;
prot_desc->frame_period = prot_desc->clocks_per_frame - 1;
dev_dbg(dai->dev, "%s: Clocks per frame: %u\n",
__func__,
prot_desc->clocks_per_frame);
return 0;
}
static int setup_pcm_framing(struct snd_soc_dai *dai, unsigned int rate,
struct msp_protdesc *prot_desc)
static int setup_pcm_framing(struct snd_soc_dai *dai,
struct msp_protdesc *prot_desc)
{
struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
@@ -163,7 +114,9 @@ static int setup_pcm_framing(struct snd_soc_dai *dai, unsigned int rate,
prot_desc->tx_elem_len_2 = MSP_ELEM_LEN_16;
prot_desc->rx_elem_len_2 = MSP_ELEM_LEN_16;
return setup_frameper(dai, rate, prot_desc);
setup_frameper(dai, prot_desc);
return 0;
}
static int setup_clocking(struct snd_soc_dai *dai,
@@ -177,7 +130,16 @@ static int setup_clocking(struct snd_soc_dai *dai,
case SND_SOC_DAIFMT_NB_IF:
msp_config->tx_fsync_pol ^= 1 << TFSPOL_SHIFT;
msp_config->rx_fsync_pol ^= 1 << RFSPOL_SHIFT;
break;
case SND_SOC_DAIFMT_IB_NF:
msp_config->bclk_inverted = true;
break;
case SND_SOC_DAIFMT_IB_IF:
msp_config->bclk_inverted = true;
msp_config->tx_fsync_pol ^= 1 << TFSPOL_SHIFT;
msp_config->rx_fsync_pol ^= 1 << RFSPOL_SHIFT;
break;
default:
@@ -192,6 +154,7 @@ static int setup_clocking(struct snd_soc_dai *dai,
case SND_SOC_DAIFMT_BC_FC:
dev_dbg(dai->dev, "%s: Codec is master.\n", __func__);
msp_config->clock_provider = false;
msp_config->iodelay = 0x20;
msp_config->rx_fsync_sel = 0;
msp_config->tx_fsync_sel = 1 << TFSSEL_SHIFT;
@@ -204,6 +167,7 @@ static int setup_clocking(struct snd_soc_dai *dai,
case SND_SOC_DAIFMT_BP_FP:
dev_dbg(dai->dev, "%s: Codec is slave.\n", __func__);
msp_config->clock_provider = true;
msp_config->tx_clk_sel = TX_CLK_SEL_SRG;
msp_config->tx_fsync_sel = TX_SYNC_SRG_PROG;
msp_config->rx_clk_sel = RX_CLK_SEL_SRG;
@@ -362,7 +326,7 @@ static int setup_msp_config(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
ret = setup_pcm_framing(dai, runtime->rate, prot_desc);
ret = setup_pcm_framing(dai, prot_desc);
if (ret < 0)
return ret;
@@ -424,21 +388,21 @@ static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream,
int ret;
struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
unsigned int configured = is_playback ? PLAYBACK_CONFIGURED :
CAPTURE_CONFIGURED;
unsigned int dir = is_playback ? MSP_DIR_TX : MSP_DIR_RX;
dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
snd_pcm_stream_str(substream));
if (drvdata->vape_opp_constraint == 1) {
prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
"ux500_msp_i2s", 50);
drvdata->vape_opp_constraint = 0;
}
if (ux500_msp_i2s_close(drvdata->msp,
is_playback ? MSP_DIR_TX : MSP_DIR_RX)) {
dev_err(dai->dev,
"%s: Error: MSP %d (%s): Unable to close i2s.\n",
__func__, dai->id, snd_pcm_stream_str(substream));
if (drvdata->configured & configured) {
if (ux500_msp_i2s_close(drvdata->msp, dir)) {
dev_err(dai->dev,
"%s: Error: MSP %d (%s): Unable to close i2s.\n",
__func__, dai->id,
snd_pcm_stream_str(substream));
}
drvdata->configured &= ~configured;
}
/* Disable and unprepare clocks */
@@ -456,15 +420,23 @@ static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream,
static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
int ret = 0;
struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
struct snd_pcm_runtime *runtime = substream->runtime;
struct ux500_msp_config msp_config;
bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
unsigned int configured = is_playback ? PLAYBACK_CONFIGURED :
CAPTURE_CONFIGURED;
int ret;
dev_dbg(dai->dev, "%s: MSP %d (%s): Enter (rate = %d).\n", __func__,
dai->id, snd_pcm_stream_str(substream), runtime->rate);
setup_msp_config(substream, dai, &msp_config);
if (drvdata->configured & configured)
return 0;
ret = setup_msp_config(substream, dai, &msp_config);
if (ret)
return ret;
ret = ux500_msp_i2s_open(drvdata->msp, &msp_config);
if (ret < 0) {
@@ -473,22 +445,9 @@ static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream,
return ret;
}
/* Set OPP-level */
if ((drvdata->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) &&
(drvdata->msp->f_bitclk > 19200000)) {
/* If the bit-clock is higher than 19.2MHz, Vape should be
* run in 100% OPP. Only when bit-clock is used (MSP master)
*/
prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
"ux500-msp-i2s", 100);
drvdata->vape_opp_constraint = 1;
} else {
prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
"ux500-msp-i2s", 50);
drvdata->vape_opp_constraint = 0;
}
drvdata->configured |= configured;
return ret;
return 0;
}
static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream,
@@ -496,7 +455,6 @@ static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
unsigned int mask, slots_active;
struct snd_pcm_runtime *runtime = substream->runtime;
struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n",
@@ -504,9 +462,8 @@ static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream,
switch (drvdata->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_CHANNELS,
1, 2);
if (params_channels(params) < 1 || params_channels(params) > 2)
return -EINVAL;
break;
case SND_SOC_DAIFMT_DSP_B:
@@ -518,9 +475,8 @@ static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream,
slots_active = hweight32(mask);
dev_dbg(dai->dev, "TDM-slots active: %d", slots_active);
snd_pcm_hw_constraint_single(runtime,
SNDRV_PCM_HW_PARAM_CHANNELS,
slots_active);
if (!slots_active || params_channels(params) != slots_active)
return -EINVAL;
break;
default:
@@ -553,20 +509,21 @@ static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *dai,
default:
dev_err(dai->dev,
"%s: Error: Unsupported protocol/master (fmt = 0x%x)!\n",
__func__, drvdata->fmt);
__func__, fmt);
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
case SND_SOC_DAIFMT_NB_IF:
case SND_SOC_DAIFMT_IB_NF:
case SND_SOC_DAIFMT_IB_IF:
break;
default:
dev_err(dai->dev,
"%s: Error: Unsupported inversion (fmt = 0x%x)!\n",
__func__, drvdata->fmt);
__func__, fmt);
return -EINVAL;
}
@@ -600,17 +557,23 @@ static int ux500_msp_dai_set_tdm_slot(struct snd_soc_dai *dai,
__func__, slots);
return -EINVAL;
}
drvdata->slots = slots;
if (!(slot_width == 16)) {
if (slot_width != 16) {
dev_err(dai->dev, "%s: Error: Unsupported slot-width (%d)!\n",
__func__, slot_width);
return -EINVAL;
}
drvdata->slot_width = slot_width;
drvdata->tx_mask = tx_mask & cap;
drvdata->rx_mask = rx_mask & cap;
if ((tx_mask | rx_mask) & ~cap) {
dev_err(dai->dev, "%s: Slot mask exceeds %d slots\n",
__func__, slots);
return -EINVAL;
}
drvdata->slots = slots;
drvdata->slot_width = slot_width;
drvdata->tx_mask = tx_mask;
drvdata->rx_mask = rx_mask;
return 0;
}
@@ -716,6 +679,7 @@ static const struct snd_soc_component_driver ux500_msp_component = {
static int ux500_msp_drv_probe(struct platform_device *pdev)
{
struct ux500_msp_i2s_drvdata *drvdata;
struct reset_control *reset;
int ret = 0;
drvdata = devm_kzalloc(&pdev->dev,
@@ -729,7 +693,6 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
drvdata->tx_mask = 0x01;
drvdata->rx_mask = 0x01;
drvdata->slot_width = 16;
drvdata->master_clk = MSP_INPUT_FREQ_APB;
drvdata->reg_vape = devm_regulator_get(&pdev->dev, "v-ape");
if (IS_ERR(drvdata->reg_vape)) {
@@ -739,8 +702,6 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
__func__, ret);
return ret;
}
prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)pdev->name, 50);
drvdata->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
if (IS_ERR(drvdata->pclk)) {
ret = PTR_ERR(drvdata->pclk);
@@ -758,9 +719,19 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
__func__, ret);
return ret;
}
drvdata->master_clk = clk_get_rate(drvdata->clk);
if (!drvdata->master_clk) {
dev_err(&pdev->dev, "MSP clock has no rate\n");
return -EINVAL;
}
reset = devm_reset_control_get_exclusive_deasserted(&pdev->dev, NULL);
if (IS_ERR(reset))
return dev_err_probe(&pdev->dev, PTR_ERR(reset),
"Failed to deassert MSP reset\n");
ret = ux500_msp_i2s_init_msp(pdev, &drvdata->msp);
if (!drvdata->msp) {
if (ret) {
dev_err(&pdev->dev,
"%s: ERROR: Failed to init MSP-struct (%d)!",
__func__, ret);
@@ -799,8 +770,6 @@ static void ux500_msp_drv_remove(struct platform_device *pdev)
snd_soc_unregister_component(&pdev->dev);
prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s");
ux500_msp_i2s_cleanup_msp(pdev, drvdata->msp);
}
+1 -13
View File
@@ -22,17 +22,6 @@
#define UX500_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
#define FRAME_PER_SINGLE_SLOT_8_KHZ 31
#define FRAME_PER_SINGLE_SLOT_16_KHZ 124
#define FRAME_PER_SINGLE_SLOT_44_1_KHZ 63
#define FRAME_PER_SINGLE_SLOT_48_KHZ 49
#define FRAME_PER_2_SLOTS 31
#define FRAME_PER_8_SLOTS 138
#define FRAME_PER_16_SLOTS 277
#define UX500_MSP_INTERNAL_CLOCK_FREQ 40000000
#define UX500_MSP1_INTERNAL_CLOCK_FREQ UX500_MSP_INTERNAL_CLOCK_FREQ
#define UX500_MSP_MIN_CHANNELS 1
#define UX500_MSP_MAX_CHANNELS 8
@@ -47,6 +36,7 @@ struct ux500_msp_i2s_drvdata {
struct ux500_msp *msp;
struct regulator *reg_vape;
unsigned int fmt;
unsigned int configured;
unsigned int tx_mask;
unsigned int rx_mask;
int slots;
@@ -57,8 +47,6 @@ struct ux500_msp_i2s_drvdata {
struct clk *clk;
struct clk *pclk;
/* Regulators */
int vape_opp_constraint;
};
int ux500_msp_dai_set_data_delay(struct snd_soc_dai *dai, int delay);
+179 -81
View File
@@ -201,10 +201,12 @@ static int configure_protocol(struct ux500_msp *msp,
/* The code below should not be separated. */
temp_reg = readl(msp->registers + MSP_GCR) & ~TX_CLK_POL_RISING;
temp_reg |= MSP_TX_CLKPOL_BIT(~protdesc->tx_clk_pol);
temp_reg |= MSP_TX_CLKPOL_BIT(!protdesc->tx_clk_pol ^
config->bclk_inverted);
writel(temp_reg, msp->registers + MSP_GCR);
temp_reg = readl(msp->registers + MSP_GCR) & ~RX_CLK_POL_RISING;
temp_reg |= MSP_RX_CLKPOL_BIT(protdesc->rx_clk_pol);
temp_reg |= MSP_RX_CLKPOL_BIT(protdesc->rx_clk_pol ^
config->bclk_inverted);
writel(temp_reg, msp->registers + MSP_GCR);
return 0;
@@ -212,35 +214,20 @@ static int configure_protocol(struct ux500_msp *msp,
static int setup_bitclk(struct ux500_msp *msp, struct ux500_msp_config *config)
{
struct msp_protdesc *protdesc;
u64 desired_bitclk;
unsigned int bitclk;
u32 reg_val_GCR;
u32 frame_per = 0;
u32 sck_div = 0;
u32 frame_width = 0;
u32 temp_reg = 0;
struct msp_protdesc *protdesc = NULL;
u32 sck_div;
u32 temp_reg;
reg_val_GCR = readl(msp->registers + MSP_GCR);
writel(reg_val_GCR & ~SRG_ENABLE, msp->registers + MSP_GCR);
if (config->default_protdesc)
protdesc =
(struct msp_protdesc *)&prot_descs[config->protocol];
else
protdesc = (struct msp_protdesc *)&config->protdesc;
switch (config->protocol) {
case MSP_PCM_PROTOCOL:
case MSP_PCM_COMPAND_PROTOCOL:
frame_width = protdesc->frame_width;
sck_div = config->f_inputclk / (config->frame_freq *
(protdesc->clocks_per_frame));
frame_per = protdesc->frame_period;
break;
case MSP_I2S_PROTOCOL:
frame_width = protdesc->frame_width;
sck_div = config->f_inputclk / (config->frame_freq *
(protdesc->clocks_per_frame));
frame_per = protdesc->frame_period;
break;
default:
dev_err(msp->dev, "%s: ERROR: Unknown protocol (%d)!\n",
@@ -249,12 +236,35 @@ static int setup_bitclk(struct ux500_msp *msp, struct ux500_msp_config *config)
return -EINVAL;
}
if (config->default_protdesc)
protdesc = (struct msp_protdesc *)&prot_descs[config->protocol];
else
protdesc = &config->protdesc;
if (!config->frame_freq || !protdesc->clocks_per_frame)
return -EINVAL;
desired_bitclk = (u64)config->frame_freq * protdesc->clocks_per_frame;
if (desired_bitclk > config->f_inputclk)
return -EINVAL;
bitclk = desired_bitclk;
if (config->f_inputclk % bitclk) {
dev_err(msp->dev,
"Input clock %u cannot generate bit clock %u\n",
config->f_inputclk, bitclk);
return -EINVAL;
}
sck_div = config->f_inputclk / bitclk;
if (!sck_div || sck_div > SCK_DIV_MASK + 1)
return -EINVAL;
temp_reg = (sck_div - 1) & SCK_DIV_MASK;
temp_reg |= FRAME_WIDTH_BITS(frame_width);
temp_reg |= FRAME_PERIOD_BITS(frame_per);
temp_reg |= FRAME_WIDTH_BITS(protdesc->frame_width);
temp_reg |= FRAME_PERIOD_BITS(protdesc->frame_period);
writel(temp_reg, msp->registers + MSP_SRG);
msp->f_bitclk = (config->f_inputclk)/(sck_div + 1);
msp->f_bitclk = config->f_inputclk / sck_div;
/* Enable bit-clock */
udelay(100);
@@ -344,20 +354,27 @@ static int configure_multichannel(struct ux500_msp *msp,
return 0;
}
static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)
static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config,
bool first)
{
int status = 0;
u32 reg_val_DMACR, reg_val_GCR;
int status;
u32 reg_val_DMACR;
/* Configure msp with protocol dependent settings */
configure_protocol(msp, config);
setup_bitclk(msp, config);
status = configure_protocol(msp, config);
if (status)
return status;
if (first && config->clock_provider) {
status = setup_bitclk(msp, config);
if (status)
return status;
}
if (config->multichannel_configured == 1) {
status = configure_multichannel(msp, config);
if (status)
dev_warn(msp->dev,
"%s: WARN: configure_multichannel failed (%d)!\n",
__func__, status);
return status;
}
reg_val_DMACR = readl(msp->registers + MSP_DMACR);
@@ -369,11 +386,7 @@ static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)
writel(config->iodelay, msp->registers + MSP_IODLY);
/* Enable frame generation logic */
reg_val_GCR = readl(msp->registers + MSP_GCR);
writel(reg_val_GCR | FRAME_GEN_ENABLE, msp->registers + MSP_GCR);
return status;
return 0;
}
static void flush_fifo_rx(struct ux500_msp *msp)
@@ -411,12 +424,37 @@ static void flush_fifo_tx(struct ux500_msp *msp)
writel(reg_val_GCR, msp->registers + MSP_GCR);
}
static bool ux500_msp_config_compatible(struct ux500_msp *msp,
struct ux500_msp_config *config)
{
struct ux500_msp_config *active = &msp->config;
return active->f_inputclk == config->f_inputclk &&
active->tx_clk_sel == config->tx_clk_sel &&
active->rx_clk_sel == config->rx_clk_sel &&
active->srg_clk_sel == config->srg_clk_sel &&
active->rx_fsync_pol == config->rx_fsync_pol &&
active->tx_fsync_pol == config->tx_fsync_pol &&
active->rx_fsync_sel == config->rx_fsync_sel &&
active->tx_fsync_sel == config->tx_fsync_sel &&
active->default_protdesc == config->default_protdesc &&
active->protocol == config->protocol &&
active->frame_freq == config->frame_freq &&
active->data_size == config->data_size &&
active->def_elem_len == config->def_elem_len &&
active->clock_provider == config->clock_provider &&
active->bclk_inverted == config->bclk_inverted &&
!memcmp(&active->protdesc, &config->protdesc,
sizeof(active->protdesc));
}
int ux500_msp_i2s_open(struct ux500_msp *msp,
struct ux500_msp_config *config)
{
u32 old_reg, new_reg, mask;
int res;
unsigned int tx_sel, rx_sel, tx_busy, rx_busy;
bool first;
if (in_interrupt()) {
dev_err(msp->dev,
@@ -444,40 +482,68 @@ int ux500_msp_i2s_open(struct ux500_msp *msp,
return -EBUSY;
}
msp->dir_busy |= (tx_sel ? MSP_DIR_TX : 0) | (rx_sel ? MSP_DIR_RX : 0);
first = !msp->dir_busy;
if (!first && !ux500_msp_config_compatible(msp, config)) {
dev_err(msp->dev, "%s: Incompatible duplex configuration\n",
__func__);
return -EBUSY;
}
/* First do the global config register */
mask = RX_CLK_SEL_MASK | TX_CLK_SEL_MASK | RX_FSYNC_MASK |
TX_FSYNC_MASK | RX_SYNC_SEL_MASK | TX_SYNC_SEL_MASK |
RX_FIFO_ENABLE_MASK | TX_FIFO_ENABLE_MASK | SRG_CLK_SEL_MASK |
LOOPBACK_MASK | TX_EXTRA_DELAY_MASK;
if (first) {
/* First do the global config register */
mask = RX_CLK_SEL_MASK | TX_CLK_SEL_MASK | RX_FSYNC_MASK |
TX_FSYNC_MASK | RX_SYNC_SEL_MASK | TX_SYNC_SEL_MASK |
RX_FIFO_ENABLE_MASK | TX_FIFO_ENABLE_MASK |
SRG_CLK_SEL_MASK | LOOPBACK_MASK | TX_EXTRA_DELAY_MASK;
new_reg = (config->tx_clk_sel | config->rx_clk_sel |
config->rx_fsync_pol | config->tx_fsync_pol |
config->rx_fsync_sel | config->tx_fsync_sel |
config->rx_fifo_config | config->tx_fifo_config |
config->srg_clk_sel | config->loopback_enable |
config->tx_data_enable);
new_reg = config->tx_clk_sel | config->rx_clk_sel |
config->rx_fsync_pol | config->tx_fsync_pol |
config->rx_fsync_sel | config->tx_fsync_sel |
config->rx_fifo_config | config->tx_fifo_config |
config->srg_clk_sel | config->loopback_enable |
config->tx_data_enable;
old_reg = readl(msp->registers + MSP_GCR);
old_reg &= ~mask;
new_reg |= old_reg;
writel(new_reg, msp->registers + MSP_GCR);
old_reg = readl(msp->registers + MSP_GCR);
old_reg &= ~mask;
new_reg |= old_reg;
writel(new_reg, msp->registers + MSP_GCR);
writel(MSP_WMRK_TX_4_ELEMENTS | MSP_WMRK_RX_4_ELEMENTS,
msp->registers + MSP_WMRK);
}
res = enable_msp(msp, config);
res = enable_msp(msp, config, first);
if (res < 0) {
dev_err(msp->dev, "%s: ERROR: enable_msp failed (%d)!\n",
__func__, res);
return -EBUSY;
if (tx_sel)
writel(0, msp->registers + MSP_TCF);
if (rx_sel)
writel(0, msp->registers + MSP_RCF);
if (first) {
writel(0, msp->registers + MSP_GCR);
writel(0, msp->registers + MSP_DMACR);
writel(0, msp->registers + MSP_SRG);
writel(0, msp->registers + MSP_MCR);
}
return res;
}
msp->dir_busy |= config->direction;
if (first) {
msp->config = *config;
msp->clock_provider = config->clock_provider;
}
if (config->loopback_enable & 0x80)
msp->loopback_enable = 1;
/* Flush FIFOs */
flush_fifo_tx(msp);
flush_fifo_rx(msp);
if (tx_sel)
flush_fifo_tx(msp);
if (rx_sel)
flush_fifo_rx(msp);
msp->msp_state = MSP_STATE_CONFIGURED;
if (!msp->dir_running)
msp->msp_state = MSP_STATE_CONFIGURED;
return 0;
}
@@ -494,7 +560,6 @@ static void disable_msp_rx(struct ux500_msp *msp)
~(RX_SERVICE_INT | RX_OVERRUN_ERROR_INT),
msp->registers + MSP_IMSC);
msp->dir_busy &= ~MSP_DIR_RX;
}
static void disable_msp_tx(struct ux500_msp *msp)
@@ -510,7 +575,6 @@ static void disable_msp_tx(struct ux500_msp *msp)
~(TX_SERVICE_INT | TX_UNDERRUN_ERR_INT),
msp->registers + MSP_IMSC);
msp->dir_busy &= ~MSP_DIR_TX;
}
static int disable_msp(struct ux500_msp *msp, unsigned int dir)
@@ -520,7 +584,7 @@ static int disable_msp(struct ux500_msp *msp, unsigned int dir)
reg_val_GCR = readl(msp->registers + MSP_GCR);
disable_tx = dir & MSP_DIR_TX;
disable_rx = dir & MSP_DIR_TX;
disable_rx = dir & MSP_DIR_RX;
if (disable_tx && disable_rx) {
reg_val_GCR = readl(msp->registers + MSP_GCR);
writel(reg_val_GCR | LOOPBACK_MASK,
@@ -553,7 +617,15 @@ static int disable_msp(struct ux500_msp *msp, unsigned int dir)
int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction)
{
u32 reg_val_GCR, enable_bit;
u32 reg_val_DMACR, reg_val_GCR, dma_enable_bit, enable_bit;
unsigned int dir;
if (direction == SNDRV_PCM_STREAM_PLAYBACK)
dir = MSP_DIR_TX;
else if (direction == SNDRV_PCM_STREAM_CAPTURE)
dir = MSP_DIR_RX;
else
return -EINVAL;
if (msp->msp_state == MSP_STATE_IDLE) {
dev_err(msp->dev, "%s: ERROR: MSP is not configured!\n",
@@ -565,21 +637,44 @@ int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction)
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (direction == SNDRV_PCM_STREAM_PLAYBACK)
if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
enable_bit = TX_ENABLE;
else
dma_enable_bit = TX_DMA_ENABLE;
} else {
enable_bit = RX_ENABLE;
dma_enable_bit = RX_DMA_ENABLE;
}
if (!(msp->dir_busy & dir))
return -EINVAL;
reg_val_DMACR = readl(msp->registers + MSP_DMACR);
writel(reg_val_DMACR | dma_enable_bit,
msp->registers + MSP_DMACR);
reg_val_GCR = readl(msp->registers + MSP_GCR);
if (msp->clock_provider)
enable_bit |= FRAME_GEN_ENABLE;
writel(reg_val_GCR | enable_bit, msp->registers + MSP_GCR);
msp->dir_running |= dir;
msp->msp_state = MSP_STATE_RUNNING;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (direction == SNDRV_PCM_STREAM_PLAYBACK)
if (!(msp->dir_busy & dir))
return -EINVAL;
if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
disable_msp_tx(msp);
else
msp->dir_running &= ~MSP_DIR_TX;
} else {
disable_msp_rx(msp);
msp->dir_running &= ~MSP_DIR_RX;
}
if (!msp->dir_running) {
reg_val_GCR = readl(msp->registers + MSP_GCR);
writel(reg_val_GCR & ~FRAME_GEN_ENABLE,
msp->registers + MSP_GCR);
msp->msp_state = MSP_STATE_CONFIGURED;
}
break;
default:
return -EINVAL;
@@ -594,7 +689,18 @@ int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir);
if (!dir || dir & ~(MSP_DIR_TX | MSP_DIR_RX) ||
(msp->dir_busy & dir) != dir)
return -EINVAL;
status = disable_msp(msp, dir);
msp->dir_busy &= ~dir;
msp->dir_running &= ~dir;
if (msp->dir_busy && !msp->dir_running) {
writel(readl(msp->registers + MSP_GCR) & ~FRAME_GEN_ENABLE,
msp->registers + MSP_GCR);
msp->msp_state = MSP_STATE_CONFIGURED;
}
if (msp->dir_busy == 0) {
/* disable sample rate and frame generators */
msp->msp_state = MSP_STATE_IDLE;
@@ -618,6 +724,8 @@ int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
writel(0, msp->registers + MSP_RCE1);
writel(0, msp->registers + MSP_RCE2);
writel(0, msp->registers + MSP_RCE3);
memset(&msp->config, 0, sizeof(msp->config));
msp->clock_provider = false;
}
return status;
@@ -627,7 +735,7 @@ int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
int ux500_msp_i2s_init_msp(struct platform_device *pdev,
struct ux500_msp **msp_p)
{
struct resource *res = NULL;
struct resource *res;
struct ux500_msp *msp;
*msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL);
@@ -637,20 +745,10 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
msp->dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(&pdev->dev, "%s: ERROR: Unable to get resource!\n",
__func__);
return -ENOMEM;
}
msp->registers = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(msp->registers))
return PTR_ERR(msp->registers);
msp->tx_rx_addr = res->start + MSP_DR;
msp->registers = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (msp->registers == NULL) {
dev_err(&pdev->dev, "%s: ERROR: ioremap failed!\n", __func__);
return -ENOMEM;
}
msp->msp_state = MSP_STATE_IDLE;
msp->loopback_enable = 0;
+10 -2
View File
@@ -12,8 +12,6 @@
#include <linux/platform_device.h>
#define MSP_INPUT_FREQ_APB 48000000
/*** Stereo mode. Used for APB data accesses as 16 bits accesses (mono),
* 32 bits accesses (stereo).
***/
@@ -64,6 +62,7 @@ enum msp_direction {
#define MSP_SRG 0x10
#define MSP_FLR 0x14
#define MSP_DMACR 0x18
#define MSP_WMRK 0x1c
#define MSP_IMSC 0x20
#define MSP_RIS 0x24
@@ -230,6 +229,10 @@ enum msp_direction {
#define RDMAE_SHIFT 0
#define TDMAE_SHIFT 1
/* FIFO watermark register */
#define MSP_WMRK_RX_4_ELEMENTS BIT(0)
#define MSP_WMRK_TX_4_ELEMENTS BIT(3)
/* Interrupt Register */
#define RX_SERVICE_INT BIT(0)
#define RX_OVERRUN_ERROR_INT BIT(1)
@@ -460,6 +463,8 @@ struct ux500_msp_config {
enum msp_data_size data_size;
unsigned int def_elem_len;
unsigned int iodelay;
bool clock_provider;
bool bclk_inverted;
};
struct ux500_msp {
@@ -470,8 +475,11 @@ struct ux500_msp {
enum msp_state msp_state;
int def_elem_len;
unsigned int dir_busy;
unsigned int dir_running;
int loopback_enable;
unsigned int f_bitclk;
bool clock_provider;
struct ux500_msp_config config;
};
int ux500_msp_i2s_init_msp(struct platform_device *pdev,
+28 -14
View File
@@ -21,7 +21,6 @@ enum {
static void usb6fire_comm_init_urb(struct comm_runtime *rt, struct urb *urb,
u8 *buffer, void *context, void(*handler)(struct urb *urb))
{
usb_init_urb(urb);
urb->transfer_buffer = buffer;
urb->pipe = usb_sndintpipe(rt->chip->dev, COMM_EP);
urb->complete = handler;
@@ -142,6 +141,19 @@ static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request,
return ret;
}
static void usb6fire_comm_free(struct comm_runtime *rt)
{
if (!rt)
return;
if (rt->chip)
rt->chip->comm = NULL;
usb_free_urb(rt->receiver);
kfree(rt->receiver_buffer);
kfree(rt);
}
int usb6fire_comm_init(struct sfire_chip *chip)
{
struct comm_runtime *rt = kzalloc_obj(struct comm_runtime);
@@ -153,14 +165,18 @@ int usb6fire_comm_init(struct sfire_chip *chip)
rt->receiver_buffer = kzalloc(COMM_RECEIVER_BUFSIZE, GFP_KERNEL);
if (!rt->receiver_buffer) {
kfree(rt);
return -ENOMEM;
ret = -ENOMEM;
goto error;
}
urb = &rt->receiver;
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
ret = -ENOMEM;
goto error;
}
rt->receiver = urb;
rt->serial = 1;
rt->chip = chip;
usb_init_urb(urb);
rt->init_urb = usb6fire_comm_init_urb;
rt->write8 = usb6fire_comm_write8;
rt->write16 = usb6fire_comm_write16;
@@ -175,13 +191,15 @@ int usb6fire_comm_init(struct sfire_chip *chip)
urb->interval = 1;
ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret < 0) {
kfree(rt->receiver_buffer);
kfree(rt);
dev_err(&chip->dev->dev, "cannot create comm data receiver.");
return ret;
goto error;
}
chip->comm = rt;
return 0;
error:
usb6fire_comm_free(rt);
return ret;
}
void usb6fire_comm_abort(struct sfire_chip *chip)
@@ -189,14 +207,10 @@ void usb6fire_comm_abort(struct sfire_chip *chip)
struct comm_runtime *rt = chip->comm;
if (rt)
usb_poison_urb(&rt->receiver);
usb_poison_urb(rt->receiver);
}
void usb6fire_comm_destroy(struct sfire_chip *chip)
{
struct comm_runtime *rt = chip->comm;
kfree(rt->receiver_buffer);
kfree(rt);
chip->comm = NULL;
usb6fire_comm_free(chip->comm);
}
+1 -1
View File
@@ -19,7 +19,7 @@ enum /* settings for comm */
struct comm_runtime {
struct sfire_chip *chip;
struct urb receiver;
struct urb *receiver;
u8 *receiver_buffer;
u8 serial; /* urb serial */
+30 -13
View File
@@ -66,7 +66,7 @@ static void usb6fire_midi_out_trigger(
struct snd_rawmidi_substream *alsa_sub, int up)
{
struct midi_runtime *rt = alsa_sub->rmidi->private_data;
struct urb *urb = &rt->out_urb;
struct urb *urb = rt->out_urb;
__s8 ret;
guard(spinlock_irqsave)(&rt->out_lock);
@@ -137,6 +137,19 @@ static const struct snd_rawmidi_ops in_ops = {
.trigger = usb6fire_midi_in_trigger
};
static void usb6fire_midi_free(struct midi_runtime *rt)
{
if (!rt)
return;
if (rt->chip)
rt->chip->midi = NULL;
usb_free_urb(rt->out_urb);
kfree(rt->out_buffer);
kfree(rt);
}
int usb6fire_midi_init(struct sfire_chip *chip)
{
int ret;
@@ -148,8 +161,14 @@ int usb6fire_midi_init(struct sfire_chip *chip)
rt->out_buffer = kzalloc(MIDI_BUFSIZE, GFP_KERNEL);
if (!rt->out_buffer) {
kfree(rt);
return -ENOMEM;
ret = -ENOMEM;
goto error;
}
rt->out_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!rt->out_urb) {
ret = -ENOMEM;
goto error;
}
rt->chip = chip;
@@ -160,15 +179,13 @@ int usb6fire_midi_init(struct sfire_chip *chip)
spin_lock_init(&rt->in_lock);
spin_lock_init(&rt->out_lock);
comm_rt->init_urb(comm_rt, &rt->out_urb, rt->out_buffer, rt,
comm_rt->init_urb(comm_rt, rt->out_urb, rt->out_buffer, rt,
usb6fire_midi_out_handler);
ret = snd_rawmidi_new(chip->card, "6FireUSB", 0, 1, 1, &rt->instance);
if (ret < 0) {
kfree(rt->out_buffer);
kfree(rt);
dev_err(&chip->dev->dev, "unable to create midi.\n");
return ret;
goto error;
}
rt->instance->private_data = rt;
strscpy(rt->instance->name, "DMX6FireUSB MIDI");
@@ -182,6 +199,10 @@ int usb6fire_midi_init(struct sfire_chip *chip)
chip->midi = rt;
return 0;
error:
usb6fire_midi_free(rt);
return ret;
}
void usb6fire_midi_abort(struct sfire_chip *chip)
@@ -189,14 +210,10 @@ void usb6fire_midi_abort(struct sfire_chip *chip)
struct midi_runtime *rt = chip->midi;
if (rt)
usb_poison_urb(&rt->out_urb);
usb_poison_urb(rt->out_urb);
}
void usb6fire_midi_destroy(struct sfire_chip *chip)
{
struct midi_runtime *rt = chip->midi;
kfree(rt->out_buffer);
kfree(rt);
chip->midi = NULL;
usb6fire_midi_free(chip->midi);
}
+1 -1
View File
@@ -22,7 +22,7 @@ struct midi_runtime {
spinlock_t in_lock;
spinlock_t out_lock;
struct snd_rawmidi_substream *out;
struct urb out_urb;
struct urb *out_urb;
u8 out_serial; /* serial number of out packet */
u8 *out_buffer;
int buffer_offset;
+75 -53
View File
@@ -138,8 +138,8 @@ static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt)
rt->stream_state = STREAM_STOPPING;
for (i = 0; i < PCM_N_URBS; i++) {
usb_kill_urb(&rt->in_urbs[i].instance);
usb_kill_urb(&rt->out_urbs[i].instance);
usb_kill_urb(rt->in_urbs[i].instance);
usb_kill_urb(rt->out_urbs[i].instance);
}
ctrl_rt->usb_streaming = false;
ctrl_rt->update_streaming(ctrl_rt);
@@ -161,13 +161,13 @@ static int usb6fire_pcm_stream_start(struct pcm_runtime *rt)
rt->stream_state = STREAM_STARTING;
for (i = 0; i < PCM_N_URBS; i++) {
for (k = 0; k < PCM_N_PACKETS_PER_URB; k++) {
packet = &rt->in_urbs[i].packets[k];
packet = &rt->in_urbs[i].instance->iso_frame_desc[k];
packet->offset = k * rt->in_packet_size;
packet->length = rt->in_packet_size;
packet->actual_length = 0;
packet->status = 0;
}
ret = usb_submit_urb(&rt->in_urbs[i].instance,
ret = usb_submit_urb(rt->in_urbs[i].instance,
GFP_ATOMIC);
if (ret) {
usb6fire_pcm_stream_stop(rt);
@@ -197,6 +197,7 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb)
unsigned int total_length = 0;
struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance);
struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;
struct usb_iso_packet_descriptor *isoc;
u32 *src = NULL;
u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off
* (alsa_rt->frame_bits >> 3));
@@ -207,8 +208,9 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb)
for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
/* at least 4 header bytes for valid packet.
* after that: 32 bits per sample for analog channels */
if (urb->packets[i].actual_length > 4)
frame_count = (urb->packets[i].actual_length - 4)
isoc = &urb->instance->iso_frame_desc[i];
if (isoc->actual_length > 4)
frame_count = (isoc->actual_length - 4)
/ (rt->in_n_analog << 2);
else
frame_count = 0;
@@ -220,7 +222,7 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb)
else
return;
src++; /* skip leading 4 bytes of every packet */
total_length += urb->packets[i].length;
total_length += isoc->length;
for (frame = 0; frame < frame_count; frame++) {
memcpy(dest, src, bytes_per_frame);
dest += alsa_rt->channels;
@@ -244,6 +246,7 @@ static void usb6fire_pcm_playback(struct pcm_substream *sub,
int frame_count;
struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance);
struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;
struct usb_iso_packet_descriptor *isoc;
u32 *src = (u32 *) (alsa_rt->dma_area + sub->dma_off
* (alsa_rt->frame_bits >> 3));
u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size
@@ -263,8 +266,9 @@ static void usb6fire_pcm_playback(struct pcm_substream *sub,
for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
/* at least 4 header bytes for valid packet.
* after that: 32 bits per sample for analog channels */
if (urb->packets[i].length > 4)
frame_count = (urb->packets[i].length - 4)
isoc = &urb->instance->iso_frame_desc[i];
if (isoc->length > 4)
frame_count = (isoc->length - 4)
/ (rt->out_n_analog << 2);
else
frame_count = 0;
@@ -289,6 +293,7 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb)
struct pcm_urb *out_urb = in_urb->peer;
struct pcm_runtime *rt = in_urb->chip->pcm;
struct pcm_substream *sub;
struct usb_iso_packet_descriptor *isoc_out, *isoc_in;
bool period_elapsed;
int total_length = 0;
int frame_count;
@@ -299,11 +304,13 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb)
if (usb_urb->status || rt->panic || rt->stream_state == STREAM_STOPPING)
return;
for (i = 0; i < PCM_N_PACKETS_PER_URB; i++)
if (in_urb->packets[i].status) {
for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
isoc_in = &in_urb->instance->iso_frame_desc[i];
if (isoc_in->status) {
rt->panic = true;
return;
}
}
if (rt->stream_state == STREAM_DISABLED) {
dev_err(&rt->chip->dev->dev,
@@ -328,12 +335,13 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb)
/* setup out urb structure */
for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
out_urb->packets[i].offset = total_length;
out_urb->packets[i].length = (in_urb->packets[i].actual_length
- 4) / (rt->in_n_analog << 2)
isoc_out = &out_urb->instance->iso_frame_desc[i];
isoc_in = &in_urb->instance->iso_frame_desc[i];
isoc_out->offset = total_length;
isoc_out->length = (isoc_in->actual_length - 4) / (rt->in_n_analog << 2)
* (rt->out_n_analog << 2) + 4;
out_urb->packets[i].status = 0;
total_length += out_urb->packets[i].length;
isoc_out->status = 0;
total_length += isoc_out->length;
}
memset(out_urb->buffer, 0, total_length);
@@ -354,9 +362,10 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb)
/* setup the 4th byte of each sample (0x40 for analog channels) */
dest = out_urb->buffer;
for (i = 0; i < PCM_N_PACKETS_PER_URB; i++)
if (out_urb->packets[i].length >= 4) {
frame_count = (out_urb->packets[i].length - 4)
for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
isoc_out = &out_urb->instance->iso_frame_desc[i];
if (isoc_out->length >= 4) {
frame_count = (isoc_out->length - 4)
/ (rt->out_n_analog << 2);
*(dest++) = 0xaa;
*(dest++) = 0xaa;
@@ -370,8 +379,10 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb)
*(dest++) = 0x40;
}
}
usb_submit_urb(&out_urb->instance, GFP_ATOMIC);
usb_submit_urb(&in_urb->instance, GFP_ATOMIC);
}
usb_submit_urb(out_urb->instance, GFP_ATOMIC);
usb_submit_urb(in_urb->instance, GFP_ATOMIC);
}
static void usb6fire_pcm_out_urb_handler(struct urb *usb_urb)
@@ -534,22 +545,25 @@ static const struct snd_pcm_ops pcm_ops = {
.pointer = usb6fire_pcm_pointer,
};
static void usb6fire_pcm_init_urb(struct pcm_urb *urb,
struct sfire_chip *chip, bool in, int ep,
void (*handler)(struct urb *))
static int usb6fire_pcm_init_urb(struct pcm_urb *urb,
struct sfire_chip *chip, bool in, int ep,
void (*handler)(struct urb *))
{
urb->chip = chip;
usb_init_urb(&urb->instance);
urb->instance.transfer_buffer = urb->buffer;
urb->instance.transfer_buffer_length =
urb->instance = usb_alloc_urb(PCM_N_PACKETS_PER_URB, GFP_KERNEL);
if (!urb->instance)
return -ENOMEM;
urb->instance->transfer_buffer = urb->buffer;
urb->instance->transfer_buffer_length =
PCM_N_PACKETS_PER_URB * PCM_MAX_PACKET_SIZE;
urb->instance.dev = chip->dev;
urb->instance.pipe = in ? usb_rcvisocpipe(chip->dev, ep)
urb->instance->dev = chip->dev;
urb->instance->pipe = in ? usb_rcvisocpipe(chip->dev, ep)
: usb_sndisocpipe(chip->dev, ep);
urb->instance.interval = 1;
urb->instance.complete = handler;
urb->instance.context = urb;
urb->instance.number_of_packets = PCM_N_PACKETS_PER_URB;
urb->instance->interval = 1;
urb->instance->complete = handler;
urb->instance->context = urb;
urb->instance->number_of_packets = PCM_N_PACKETS_PER_URB;
return 0;
}
static int usb6fire_pcm_buffers_init(struct pcm_runtime *rt)
@@ -571,14 +585,23 @@ static int usb6fire_pcm_buffers_init(struct pcm_runtime *rt)
return 0;
}
static void usb6fire_pcm_buffers_destroy(struct pcm_runtime *rt)
static void usb6fire_pcm_free(struct pcm_runtime *rt)
{
int i;
if (!rt)
return;
if (rt->chip)
rt->chip->pcm = NULL;
for (i = 0; i < PCM_N_URBS; i++) {
usb_free_urb(rt->out_urbs[i].instance);
kfree(rt->out_urbs[i].buffer);
usb_free_urb(rt->in_urbs[i].instance);
kfree(rt->in_urbs[i].buffer);
}
kfree(rt);
}
int usb6fire_pcm_init(struct sfire_chip *chip)
@@ -593,11 +616,8 @@ int usb6fire_pcm_init(struct sfire_chip *chip)
return -ENOMEM;
ret = usb6fire_pcm_buffers_init(rt);
if (ret) {
usb6fire_pcm_buffers_destroy(rt);
kfree(rt);
return ret;
}
if (ret)
goto error;
rt->chip = chip;
rt->stream_state = STREAM_DISABLED;
@@ -609,10 +629,14 @@ int usb6fire_pcm_init(struct sfire_chip *chip)
spin_lock_init(&rt->capture.lock);
for (i = 0; i < PCM_N_URBS; i++) {
usb6fire_pcm_init_urb(&rt->in_urbs[i], chip, true, IN_EP,
usb6fire_pcm_in_urb_handler);
usb6fire_pcm_init_urb(&rt->out_urbs[i], chip, false, OUT_EP,
usb6fire_pcm_out_urb_handler);
ret = usb6fire_pcm_init_urb(&rt->in_urbs[i], chip, true, IN_EP,
usb6fire_pcm_in_urb_handler);
if (ret < 0)
goto error;
ret = usb6fire_pcm_init_urb(&rt->out_urbs[i], chip, false, OUT_EP,
usb6fire_pcm_out_urb_handler);
if (ret < 0)
goto error;
rt->in_urbs[i].peer = &rt->out_urbs[i];
rt->out_urbs[i].peer = &rt->in_urbs[i];
@@ -620,10 +644,8 @@ int usb6fire_pcm_init(struct sfire_chip *chip)
ret = snd_pcm_new(chip->card, "DMX6FireUSB", 0, 1, 1, &pcm);
if (ret < 0) {
usb6fire_pcm_buffers_destroy(rt);
kfree(rt);
dev_err(&chip->dev->dev, "cannot create pcm instance.\n");
return ret;
goto error;
}
pcm->private_data = rt;
@@ -636,6 +658,10 @@ int usb6fire_pcm_init(struct sfire_chip *chip)
chip->pcm = rt;
return 0;
error:
usb6fire_pcm_free(rt);
return ret;
}
void usb6fire_pcm_abort(struct sfire_chip *chip)
@@ -653,8 +679,8 @@ void usb6fire_pcm_abort(struct sfire_chip *chip)
snd_pcm_stop_xrun(rt->capture.instance);
for (i = 0; i < PCM_N_URBS; i++) {
usb_poison_urb(&rt->in_urbs[i].instance);
usb_poison_urb(&rt->out_urbs[i].instance);
usb_poison_urb(rt->in_urbs[i].instance);
usb_poison_urb(rt->out_urbs[i].instance);
}
}
@@ -662,9 +688,5 @@ void usb6fire_pcm_abort(struct sfire_chip *chip)
void usb6fire_pcm_destroy(struct sfire_chip *chip)
{
struct pcm_runtime *rt = chip->pcm;
usb6fire_pcm_buffers_destroy(rt);
kfree(rt);
chip->pcm = NULL;
usb6fire_pcm_free(chip->pcm);
}
+1 -4
View File
@@ -24,10 +24,7 @@ enum /* settings for pcm */
struct pcm_urb {
struct sfire_chip *chip;
/* BEGIN DO NOT SEPARATE */
struct urb instance;
struct usb_iso_packet_descriptor packets[PCM_N_PACKETS_PER_URB];
/* END DO NOT SEPARATE */
struct urb *instance;
u8 *buffer;
struct pcm_urb *peer;
+24 -12
View File
@@ -192,8 +192,8 @@ static void usb_ep1_command_reply_dispatch (struct urb* urb)
break;
}
cdev->ep1_in_urb.actual_length = 0;
ret = usb_submit_urb(&cdev->ep1_in_urb, GFP_ATOMIC);
cdev->ep1_in_urb->actual_length = 0;
ret = usb_submit_urb(cdev->ep1_in_urb, GFP_ATOMIC);
if (ret < 0)
dev_err(dev, "unable to submit urb. OOM!?\n");
}
@@ -408,6 +408,10 @@ static void card_free(struct snd_card *card)
#endif
snd_usb_caiaq_audio_free(cdev);
usb_put_dev(cdev->chip.dev);
usb_free_urb(cdev->ep1_in_urb);
cdev->ep1_in_urb = NULL;
usb_free_urb(cdev->midi_out_urb);
cdev->midi_out_urb = NULL;
}
static int create_card(struct usb_device *usb_dev,
@@ -457,22 +461,30 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
return -EIO;
}
usb_init_urb(&cdev->ep1_in_urb);
usb_init_urb(&cdev->midi_out_urb);
cdev->ep1_in_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!cdev->ep1_in_urb)
return -ENOMEM;
usb_fill_bulk_urb(&cdev->ep1_in_urb, usb_dev,
cdev->midi_out_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!cdev->midi_out_urb) {
usb_free_urb(cdev->ep1_in_urb);
cdev->ep1_in_urb = NULL;
return -ENOMEM;
}
usb_fill_bulk_urb(cdev->ep1_in_urb, usb_dev,
usb_rcvbulkpipe(usb_dev, 0x1),
cdev->ep1_in_buf, EP1_BUFSIZE,
usb_ep1_command_reply_dispatch, cdev);
usb_fill_bulk_urb(&cdev->midi_out_urb, usb_dev,
usb_fill_bulk_urb(cdev->midi_out_urb, usb_dev,
usb_sndbulkpipe(usb_dev, 0x1),
cdev->midi_out_buf, EP1_BUFSIZE,
snd_usb_caiaq_midi_output_done, cdev);
/* sanity checks of EPs before actually submitting */
if (usb_urb_ep_type_check(&cdev->ep1_in_urb) ||
usb_urb_ep_type_check(&cdev->midi_out_urb)) {
if (usb_urb_ep_type_check(cdev->ep1_in_urb) ||
usb_urb_ep_type_check(cdev->midi_out_urb)) {
dev_err(dev, "invalid EPs\n");
return -EINVAL;
}
@@ -480,7 +492,7 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
init_waitqueue_head(&cdev->ep1_wait_queue);
init_waitqueue_head(&cdev->prepare_wait_queue);
if (usb_submit_urb(&cdev->ep1_in_urb, GFP_KERNEL) != 0)
if (usb_submit_urb(cdev->ep1_in_urb, GFP_KERNEL) != 0)
return -EIO;
err = snd_usb_caiaq_send_command(cdev, EP1_CMD_GET_DEVICE_INFO, NULL, 0);
@@ -530,7 +542,7 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
return 0;
err_kill_urb:
usb_kill_urb(&cdev->ep1_in_urb);
usb_kill_urb(cdev->ep1_in_urb);
return err;
}
@@ -576,8 +588,8 @@ static void snd_disconnect(struct usb_interface *intf)
#endif
snd_usb_caiaq_audio_disconnect(cdev);
usb_kill_urb(&cdev->ep1_in_urb);
usb_kill_urb(&cdev->midi_out_urb);
usb_kill_urb(cdev->ep1_in_urb);
usb_kill_urb(cdev->midi_out_urb);
snd_card_free_when_closed(card);
}
+2 -2
View File
@@ -60,8 +60,8 @@ struct snd_usb_caiaq_cb_info;
struct snd_usb_caiaqdev {
struct snd_usb_audio chip;
struct urb ep1_in_urb;
struct urb midi_out_urb;
struct urb *ep1_in_urb;
struct urb *midi_out_urb;
struct urb **data_urbs_in;
struct urb **data_urbs_out;
struct snd_usb_caiaq_cb_info *data_cb_info;
+3 -3
View File
@@ -43,7 +43,7 @@ static int snd_usb_caiaq_midi_output_close(struct snd_rawmidi_substream *substre
{
struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;
if (cdev->midi_out_active) {
usb_kill_urb(&cdev->midi_out_urb);
usb_kill_urb(cdev->midi_out_urb);
cdev->midi_out_active = 0;
}
return 0;
@@ -64,9 +64,9 @@ static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *cdev,
return;
cdev->midi_out_buf[2] = len;
cdev->midi_out_urb.transfer_buffer_length = len+3;
cdev->midi_out_urb->transfer_buffer_length = len+3;
ret = usb_submit_urb(&cdev->midi_out_urb, GFP_ATOMIC);
ret = usb_submit_urb(cdev->midi_out_urb, GFP_ATOMIC);
if (ret < 0)
dev_err(dev,
"snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed,"
+23 -21
View File
@@ -24,7 +24,7 @@
struct pcm_urb {
struct hiface_chip *chip;
struct urb instance;
struct urb *instance;
struct usb_anchor submitted;
u8 *buffer;
};
@@ -193,7 +193,7 @@ static void hiface_pcm_stream_stop(struct pcm_runtime *rt)
if (!time)
usb_kill_anchored_urbs(
&rt->out_urbs[i].submitted);
usb_kill_urb(&rt->out_urbs[i].instance);
usb_kill_urb(rt->out_urbs[i].instance);
}
rt->stream_state = STREAM_DISABLED;
@@ -215,9 +215,9 @@ static int hiface_pcm_stream_start(struct pcm_runtime *rt)
rt->stream_state = STREAM_STARTING;
for (i = 0; i < PCM_N_URBS; i++) {
memset(rt->out_urbs[i].buffer, 0, PCM_PACKET_SIZE);
usb_anchor_urb(&rt->out_urbs[i].instance,
usb_anchor_urb(rt->out_urbs[i].instance,
&rt->out_urbs[i].submitted);
ret = usb_submit_urb(&rt->out_urbs[i].instance,
ret = usb_submit_urb(rt->out_urbs[i].instance,
GFP_ATOMIC);
if (ret) {
hiface_pcm_stream_stop(rt);
@@ -334,7 +334,7 @@ static void hiface_pcm_out_urb_handler(struct urb *usb_urb)
if (do_period_elapsed)
snd_pcm_period_elapsed(sub->instance);
ret = usb_submit_urb(&out_urb->instance, GFP_ATOMIC);
ret = usb_submit_urb(out_urb->instance, GFP_ATOMIC);
if (ret < 0)
goto out_fail;
@@ -492,16 +492,18 @@ static int hiface_pcm_init_urb(struct pcm_urb *urb,
void (*handler)(struct urb *))
{
urb->chip = chip;
usb_init_urb(&urb->instance);
urb->instance = usb_alloc_urb(0, GFP_KERNEL);
if (!urb->instance)
return -ENOMEM;
urb->buffer = kzalloc(PCM_PACKET_SIZE, GFP_KERNEL);
if (!urb->buffer)
return -ENOMEM;
usb_fill_bulk_urb(&urb->instance, chip->dev,
usb_fill_bulk_urb(urb->instance, chip->dev,
usb_sndbulkpipe(chip->dev, ep), (void *)urb->buffer,
PCM_PACKET_SIZE, handler, urb);
if (usb_urb_ep_type_check(&urb->instance))
if (usb_urb_ep_type_check(urb->instance))
return -EINVAL;
init_usb_anchor(&urb->submitted);
@@ -520,24 +522,26 @@ void hiface_pcm_abort(struct hiface_chip *chip)
}
}
static void hiface_pcm_destroy(struct hiface_chip *chip)
static void hiface_pcm_destroy(struct pcm_runtime *rt)
{
struct pcm_runtime *rt = chip->pcm;
int i;
for (i = 0; i < PCM_N_URBS; i++)
kfree(rt->out_urbs[i].buffer);
if (!rt)
return;
kfree(chip->pcm);
chip->pcm = NULL;
if (rt->chip)
rt->chip->pcm = NULL;
for (i = 0; i < PCM_N_URBS; i++) {
usb_free_urb(rt->out_urbs[i].instance);
kfree(rt->out_urbs[i].buffer);
}
kfree(rt);
}
static void hiface_pcm_free(struct snd_pcm *pcm)
{
struct pcm_runtime *rt = pcm->private_data;
if (rt)
hiface_pcm_destroy(rt->chip);
hiface_pcm_destroy(pcm->private_data);
}
int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq)
@@ -587,8 +591,6 @@ int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq)
return 0;
error:
for (i = 0; i < PCM_N_URBS; i++)
kfree(rt->out_urbs[i].buffer);
kfree(rt);
hiface_pcm_destroy(rt);
return ret;
}
+54 -48
View File
@@ -109,10 +109,10 @@ struct ua101 {
unsigned int buffer_pos;
unsigned int queue_length;
struct ua101_urb {
struct urb urb;
struct usb_iso_packet_descriptor iso_frame_desc[1];
struct urb *urb;
struct list_head ready_list;
} *urbs[MAX_QUEUE_LENGTH];
struct ua101 *ua;
} urbs[MAX_QUEUE_LENGTH];
struct {
unsigned int size;
void *addr;
@@ -167,15 +167,15 @@ static void abort_usb_playback(struct ua101 *ua)
wake_up(&ua->alsa_playback_wait);
}
static void playback_urb_complete(struct urb *usb_urb)
static void playback_urb_complete(struct urb *urb)
{
struct ua101_urb *urb = (struct ua101_urb *)usb_urb;
struct ua101 *ua = urb->urb.context;
struct ua101_urb *ua_urb = urb->context;
struct ua101 *ua = ua_urb->ua;
if (unlikely(urb->urb.status == -ENOENT || /* unlinked */
urb->urb.status == -ENODEV || /* device removed */
urb->urb.status == -ECONNRESET || /* unlinked */
urb->urb.status == -ESHUTDOWN)) { /* device disabled */
if (unlikely(urb->status == -ENOENT || /* unlinked */
urb->status == -ENODEV || /* device removed */
urb->status == -ECONNRESET || /* unlinked */
urb->status == -ESHUTDOWN)) { /* device disabled */
abort_usb_playback(ua);
abort_alsa_playback(ua);
return;
@@ -184,18 +184,19 @@ static void playback_urb_complete(struct urb *usb_urb)
if (test_bit(USB_PLAYBACK_RUNNING, &ua->states)) {
/* append URB to FIFO */
guard(spinlock_irqsave)(&ua->lock);
list_add_tail(&urb->ready_list, &ua->ready_playback_urbs);
list_add_tail(&ua_urb->ready_list, &ua->ready_playback_urbs);
if (ua->rate_feedback_count > 0)
queue_work(system_highpri_wq, &ua->playback_work);
ua->playback.substream->runtime->delay -=
urb->urb.iso_frame_desc[0].length /
urb->iso_frame_desc[0].length /
ua->playback.frame_bytes;
}
}
static void first_playback_urb_complete(struct urb *urb)
{
struct ua101 *ua = urb->context;
struct ua101_urb *ua_urb = urb->context;
struct ua101 *ua = ua_urb->ua;
urb->complete = playback_urb_complete;
playback_urb_complete(urb);
@@ -248,7 +249,8 @@ static void playback_work(struct work_struct *work)
{
struct ua101 *ua = container_of(work, struct ua101, playback_work);
unsigned int frames;
struct ua101_urb *urb;
struct ua101_urb *ua_urb;
struct urb *urb;
bool do_period_elapsed = false;
int err;
@@ -275,23 +277,24 @@ static void playback_work(struct work_struct *work)
ua->rate_feedback_count--;
/* take URB out of FIFO */
urb = list_first_entry(&ua->ready_playback_urbs,
struct ua101_urb, ready_list);
list_del(&urb->ready_list);
ua_urb = list_first_entry(&ua->ready_playback_urbs,
struct ua101_urb, ready_list);
list_del(&ua_urb->ready_list);
urb = ua_urb->urb;
/* fill packet with data or silence */
urb->urb.iso_frame_desc[0].length =
urb->iso_frame_desc[0].length =
frames * ua->playback.frame_bytes;
if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states))
do_period_elapsed |= copy_playback_data(&ua->playback,
&urb->urb,
urb,
frames);
else
memset(urb->urb.transfer_buffer, 0,
urb->urb.iso_frame_desc[0].length);
memset(urb->transfer_buffer, 0,
urb->iso_frame_desc[0].length);
/* and off you go ... */
err = usb_submit_urb(&urb->urb, GFP_ATOMIC);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (unlikely(err < 0)) {
abort_usb_playback(ua);
abort_alsa_playback(ua);
@@ -342,7 +345,8 @@ static bool copy_capture_data(struct ua101_stream *stream, struct urb *urb,
static void capture_urb_complete(struct urb *urb)
{
struct ua101 *ua = urb->context;
struct ua101_urb *ua_urb = urb->context;
struct ua101 *ua = ua_urb->ua;
struct ua101_stream *stream = &ua->capture;
unsigned int frames, write_ptr;
bool do_period_elapsed;
@@ -413,7 +417,8 @@ stream_stopped:
static void first_capture_urb_complete(struct urb *urb)
{
struct ua101 *ua = urb->context;
struct ua101_urb *ua_urb = urb->context;
struct ua101 *ua = ua_urb->ua;
urb->complete = capture_urb_complete;
capture_urb_complete(urb);
@@ -427,7 +432,7 @@ static int submit_stream_urbs(struct ua101 *ua, struct ua101_stream *stream)
unsigned int i;
for (i = 0; i < stream->queue_length; ++i) {
int err = usb_submit_urb(&stream->urbs[i]->urb, GFP_KERNEL);
int err = usb_submit_urb(stream->urbs[i].urb, GFP_KERNEL);
if (err < 0) {
dev_err(&ua->dev->dev, "USB request error %d: %s\n",
err, usb_error_string(err));
@@ -442,8 +447,8 @@ static void kill_stream_urbs(struct ua101_stream *stream)
unsigned int i;
for (i = 0; i < stream->queue_length; ++i)
if (stream->urbs[i])
usb_kill_urb(&stream->urbs[i]->urb);
if (stream->urbs[i].urb)
usb_kill_urb(stream->urbs[i].urb);
}
static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index)
@@ -508,7 +513,7 @@ static int start_usb_capture(struct ua101 *ua)
return err;
clear_bit(CAPTURE_URB_COMPLETED, &ua->states);
ua->capture.urbs[0]->urb.complete = first_capture_urb_complete;
ua->capture.urbs[0].urb->complete = first_capture_urb_complete;
ua->rate_feedback_start = 0;
ua->rate_feedback_count = 0;
@@ -550,7 +555,7 @@ static int start_usb_playback(struct ua101 *ua)
return err;
clear_bit(PLAYBACK_URB_COMPLETED, &ua->states);
ua->playback.urbs[0]->urb.complete =
ua->playback.urbs[0].urb->complete =
first_playback_urb_complete;
scoped_guard(spinlock_irq, &ua->lock) {
INIT_LIST_HEAD(&ua->ready_playback_urbs);
@@ -580,7 +585,7 @@ static int start_usb_playback(struct ua101 *ua)
add_with_wraparound(ua, &ua->rate_feedback_start, 1);
ua->rate_feedback_count--;
}
urb = &ua->playback.urbs[i]->urb;
urb = ua->playback.urbs[i].urb;
urb->iso_frame_desc[0].length =
frames * ua->playback.frame_bytes;
memset(urb->transfer_buffer, 0,
@@ -1059,7 +1064,7 @@ static int alloc_stream_urbs(struct ua101 *ua, struct ua101_stream *stream,
void (*urb_complete)(struct urb *))
{
unsigned max_packet_size = stream->max_packet_bytes;
struct ua101_urb *urb;
struct urb *urb;
unsigned int b, u = 0;
for (b = 0; b < ARRAY_SIZE(stream->buffers); ++b) {
@@ -1070,23 +1075,24 @@ static int alloc_stream_urbs(struct ua101 *ua, struct ua101_stream *stream,
while (size >= max_packet_size) {
if (u >= stream->queue_length)
goto bufsize_error;
urb = kmalloc_obj(*urb);
urb = usb_alloc_urb(1, GFP_KERNEL);
if (!urb)
return -ENOMEM;
usb_init_urb(&urb->urb);
urb->urb.dev = ua->dev;
urb->urb.pipe = stream->usb_pipe;
urb->urb.transfer_flags = URB_NO_TRANSFER_DMA_MAP;
urb->urb.transfer_buffer = addr;
urb->urb.transfer_dma = dma;
urb->urb.transfer_buffer_length = max_packet_size;
urb->urb.number_of_packets = 1;
urb->urb.interval = 1;
urb->urb.context = ua;
urb->urb.complete = urb_complete;
urb->urb.iso_frame_desc[0].offset = 0;
urb->urb.iso_frame_desc[0].length = max_packet_size;
stream->urbs[u++] = urb;
urb->dev = ua->dev;
urb->pipe = stream->usb_pipe;
urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
urb->transfer_buffer = addr;
urb->transfer_dma = dma;
urb->transfer_buffer_length = max_packet_size;
urb->number_of_packets = 1;
urb->interval = 1;
urb->context = &stream->urbs[u];
urb->complete = urb_complete;
urb->iso_frame_desc[0].offset = 0;
urb->iso_frame_desc[0].length = max_packet_size;
stream->urbs[u].ua = ua;
stream->urbs[u].urb = urb;
u++;
size -= max_packet_size;
addr += max_packet_size;
dma += max_packet_size;
@@ -1104,8 +1110,8 @@ static void free_stream_urbs(struct ua101_stream *stream)
unsigned int i;
for (i = 0; i < stream->queue_length; ++i) {
kfree(stream->urbs[i]);
stream->urbs[i] = NULL;
usb_free_urb(stream->urbs[i].urb);
stream->urbs[i].urb = NULL;
}
}
+25
View File
@@ -849,6 +849,27 @@ static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev)
return 0;
}
/*
* A post configuration device descriptor read is needed to make the CM1A
* operational after reenumeration.
*/
static int snd_usb_cm1a_boot_quirk(struct usb_device *dev)
{
struct usb_device_descriptor *desc __free(kfree) = kmalloc_obj(*desc);
int err;
if (!desc)
return -ENOMEM;
err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, sizeof(*desc));
if (err < 0) {
dev_err(&dev->dev, "failed to read device descriptor: %d\n", err);
return err;
}
return 0;
}
/*
* Some sound cards from Native Instruments are in fact compliant to the USB
* audio standard of version 2 and other approved USB standards, even though
@@ -1681,6 +1702,8 @@ int snd_usb_apply_boot_quirk_once(struct usb_device *dev,
switch (id) {
case USB_ID(0x07fd, 0x0008): /* MOTU M Series, 1st hardware version */
return snd_usb_motu_m_series_boot_quirk(dev);
case USB_ID(0x1397, 0x1234): /* Behringer CM1A */
return snd_usb_cm1a_boot_quirk(dev);
}
return 0;
@@ -2390,6 +2413,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
DEVICE_FLG(0x1397, 0x050c, /* Behringer Flow 8 */
QUIRK_FLAG_IFB_SILENCE_ON_EMPTY),
DEVICE_FLG(0x1397, 0x0510, /* Behringer UV1 */
QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
DEVICE_FLG(0x13e5, 0x0001, /* Serato Phono */
QUIRK_FLAG_IGNORE_CTL_ERROR),
DEVICE_FLG(0x152a, 0x85dd, /* SMSL USB DAC */
+5 -2
View File
@@ -180,8 +180,11 @@ static int usb_stream_hwdep_mmap(struct snd_hwdep *hw,
guard(mutex)(&us122l->mutex);
s = us122l->sk.s;
read = offset < s->read_size;
if (read && area->vm_flags & VM_WRITE)
return -EPERM;
if (read) {
if (area->vm_flags & VM_WRITE)
return -EPERM;
vm_flags_clear(area, VM_MAYWRITE);
}
/* if userspace tries to mmap beyond end of our buffer, fail */
if (size > PAGE_ALIGN(read ? s->read_size : s->write_size)) {
dev_warn(hw->card->dev, "%s: size %lu > %u\n", __func__,
+7 -3
View File
@@ -189,6 +189,9 @@ static void i_usx2y_in04_int(struct urb *urb)
return;
}
if (urb->actual_length < USX2Y_IN04_SIZE)
goto resubmit;
if (us428ctls) {
diff = -1;
if (us428ctls->ctl_snapshot_last == -2) {
@@ -196,7 +199,7 @@ static void i_usx2y_in04_int(struct urb *urb)
memcpy(usx2y->in04_last, usx2y->in04_buf, sizeof(usx2y->in04_last));
us428ctls->ctl_snapshot_last = -1;
} else {
for (i = 0; i < 21; i++) {
for (i = 0; i < USX2Y_IN04_SIZE; i++) {
if (usx2y->in04_last[i] != ((char *)usx2y->in04_buf)[i]) {
if (diff < 0)
diff = i;
@@ -253,6 +256,7 @@ static void i_usx2y_in04_int(struct urb *urb)
if (err)
dev_err(&urb->dev->dev, "in04_int() usb_submit_urb err=%i\n", err);
resubmit:
urb->dev = usx2y->dev;
usb_submit_urb(urb, GFP_ATOMIC);
}
@@ -305,7 +309,7 @@ int usx2y_in04_init(struct usx2ydev *usx2y)
goto error;
}
usx2y->in04_buf = kmalloc(21, GFP_KERNEL);
usx2y->in04_buf = kzalloc(USX2Y_IN04_SIZE, GFP_KERNEL);
if (!usx2y->in04_buf) {
err = -ENOMEM;
goto error;
@@ -313,7 +317,7 @@ int usx2y_in04_init(struct usx2ydev *usx2y)
init_waitqueue_head(&usx2y->in04_wait_queue);
usb_fill_int_urb(usx2y->in04_urb, usx2y->dev, usb_rcvintpipe(usx2y->dev, 0x4),
usx2y->in04_buf, 21,
usx2y->in04_buf, USX2Y_IN04_SIZE,
i_usx2y_in04_int, usx2y,
10);
if (usb_urb_ep_type_check(usx2y->in04_urb)) {
+3 -1
View File
@@ -5,6 +5,8 @@
#include "../midi.h"
#include "usbus428ctldefs.h"
#define USX2Y_IN04_SIZE sizeof(struct us428_ctls)
#define NRURBS 2
/* Default value used for nr of packs per urb.
@@ -55,7 +57,7 @@ struct usx2ydev {
int stride;
struct urb *in04_urb;
void *in04_buf;
char in04_last[24];
char in04_last[USX2Y_IN04_SIZE];
unsigned int in04_int_calls;
struct snd_usx2y_urb_seq *us04;
wait_queue_head_t in04_wait_queue;