mirror of
https://github.com/torvalds/linux.git
synced 2026-09-14 16:10:02 +02:00
ASoC: Fixes for v7.3
An unusually large batch of fixes here, partly due to me not sending a pull request last week and partly due to Linus' fixes for the Ericsson systems. I'm fairly sure he's the only user there so it seemed low risk to handle as fixes. We also have a batch of error handling fixes from Cezary and issues with uninitialised stream_config->type from Shuming both of which had user error reports attached. Otherwise everything is a fairly normal combination of quirks and device specific fixes. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmqhUAkACgkQJNaLcl1U h9AeYwf/ZuSXRQJlCkshmJ5qlQDZeYBWs7o0QPW4wA1ZpM0yvq7CP9LExjdsXB+J wP+H6D99ecoG5aUooecjHg/lemLzYHYNUMyT/Dte+VAXg80CoiY70nsGoz5ocpGp R0u9wSILanSfD4GeJti1X5A5aqex9hR0ad2nmrdVefd4+pLlcjFxwDLISiVLbXb4 1bIzNjeXnYsLxp7HIZFrWabpdUm3qt4e7/m3MrD2DMlNu9cq6VMuXmeB3NY/Jo6T wbQpp7EAPox7P/isS4Sl1PiundIzYrOUU55ySYPLltg9BBVt2RDXXPKZ3xCg0UKF FXOde+WwIa12Ppasl8SQWEMfQ63WFA== =ye1f -----END PGP SIGNATURE----- Merge tag 'asoc-fix-v7.3-rc2' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus ASoC: Fixes for v7.3 An unusually large batch of fixes here, partly due to me not sending a pull request last week and partly due to Linus' fixes for the Ericsson systems. I'm fairly sure he's the only user there so it seemed low risk to handle as fixes. We also have a batch of error handling fixes from Cezary and issues with uninitialised stream_config->type from Shuming both of which had user error reports attached. Otherwise everything is a fairly normal combination of quirks and device specific fixes.
This commit is contained in:
commit
6bb147bc47
|
|
@ -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 +
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
}
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 @@ int cs35l56_init(struct cs35l56_private *cs35l56)
|
|||
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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
|
|||
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,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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user