mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
ASoC: Fixes for v7.2
We've got a good collection of device specific fix here, plus a couple
of stand out things:
- Richard fixed some special cases with the new device_link creation
by more gracefully handling any errors during creation.
- Charles did some light refactoring of the SoundWire interfaces to
fix some persistent randconfig issues that people kept running into.
-----BEGIN PGP SIGNATURE-----
iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmo9XtYACgkQJNaLcl1U
h9CvHAf/asLvScBxUkGKP76NoX7+czVbpfxH+yfJ6qavcOzvi+hqHlIGh/9vpFSW
GENKI/z/g/9x1WRfwODuBdvBvfkvMGfdUKZoly1zpEICML9cDwvTHwh35TkrwVTf
/cSawS/CByv2ppdeoNe4bBTTSqf4PC0tWo3tRHR2f/LTuSAyac+eJp2PGpRoofBn
te//kJBNSOGLBxJuikOcsf6xfHzB5Rnl5QMXEk1wts5Y51NEpx0PixNbQqJ7Zvee
4jGbytul9RlS26QNM6O5qLGiQy3SpECadwvtMUiYW3jn8/YtSbl760sCeGQXjaRE
7AXiqTVbFRktJ0ffg25eeD4twOE2dQ==
=NKjz
-----END PGP SIGNATURE-----
Merge tag 'asoc-fix-v7.2-merge-window' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Fixes for v7.2
We've got a good collection of device specific fix here, plus a couple
of stand out things:
- Richard fixed some special cases with the new device_link creation
by more gracefully handling any errors during creation.
- Charles did some light refactoring of the SoundWire interfaces to
fix some persistent randconfig issues that people kept running into.
This commit is contained in:
commit
677b16108a
|
|
@ -1372,34 +1372,6 @@ int sdw_slave_get_current_bank(struct sdw_slave *slave)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(sdw_slave_get_current_bank);
|
||||
|
||||
/**
|
||||
* sdw_slave_wait_for_init - Wait for device initialisation
|
||||
* @slave: Pointer to the SoundWire peripheral.
|
||||
* @timeout_ms: Timeout in milliseconds.
|
||||
*
|
||||
* Wait for a peripheral device to enumerate and be initialised by the
|
||||
* SoundWire core.
|
||||
*
|
||||
* Return: Zero on success, and a negative error code on failure.
|
||||
*/
|
||||
int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms)
|
||||
{
|
||||
unsigned long time;
|
||||
|
||||
time = wait_for_completion_timeout(&slave->initialization_complete,
|
||||
msecs_to_jiffies(timeout_ms));
|
||||
if (!time) {
|
||||
dev_err(&slave->dev, "Initialization not complete\n");
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
slave->unattach_request = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdw_slave_wait_for_init);
|
||||
|
||||
static int sdw_slave_set_frequency(struct sdw_slave *slave)
|
||||
{
|
||||
int scale_index;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/idr.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/lockdep_types.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/mutex.h>
|
||||
|
|
@ -1093,8 +1094,6 @@ int sdw_slave_get_current_bank(struct sdw_slave *sdev);
|
|||
|
||||
int sdw_slave_get_scale_index(struct sdw_slave *slave, u8 *base);
|
||||
|
||||
int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms);
|
||||
|
||||
/* messaging and data APIs */
|
||||
int sdw_read(struct sdw_slave *slave, u32 addr);
|
||||
int sdw_write(struct sdw_slave *slave, u32 addr, u8 value);
|
||||
|
|
@ -1138,12 +1137,6 @@ static inline int sdw_slave_get_current_bank(struct sdw_slave *sdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms)
|
||||
{
|
||||
WARN_ONCE(1, "SoundWire API is disabled");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* messaging and data APIs */
|
||||
static inline int sdw_read(struct sdw_slave *slave, u32 addr)
|
||||
{
|
||||
|
|
@ -1207,4 +1200,33 @@ static inline int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u
|
|||
|
||||
#endif /* CONFIG_SOUNDWIRE */
|
||||
|
||||
/**
|
||||
* sdw_slave_wait_for_init - Wait for device initialisation
|
||||
* @slave: Pointer to the SoundWire peripheral.
|
||||
* @timeout_ms: Timeout in milliseconds.
|
||||
*
|
||||
* Wait for a peripheral device to enumerate and be initialised by the
|
||||
* SoundWire core.
|
||||
*
|
||||
* Return: Zero on success, and a negative error code on failure.
|
||||
*/
|
||||
static inline int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms)
|
||||
{
|
||||
unsigned long time;
|
||||
|
||||
if (!slave)
|
||||
return 0;
|
||||
|
||||
time = wait_for_completion_timeout(&slave->initialization_complete,
|
||||
msecs_to_jiffies(timeout_ms));
|
||||
if (!time) {
|
||||
dev_err(&slave->dev, "Initialization not complete\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
slave->unattach_request = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __SOUNDWIRE_H */
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#include <sound/soc.h>
|
||||
|
||||
struct device_link;
|
||||
|
||||
/*
|
||||
* Component probe and remove ordering levels for components with runtime
|
||||
* dependencies.
|
||||
|
|
@ -216,6 +218,8 @@ struct snd_soc_component {
|
|||
struct list_head card_aux_list; /* for auxiliary bound components */
|
||||
struct list_head card_list;
|
||||
|
||||
struct device_link *card_device_link;
|
||||
|
||||
const struct snd_soc_component_driver *driver;
|
||||
|
||||
struct list_head dai_list;
|
||||
|
|
|
|||
|
|
@ -59,9 +59,9 @@
|
|||
#define TASDEVICE_CHECKSUM_REG TASDEVICE_REG(0x0, 0x0, 0x7e)
|
||||
|
||||
/* XM_340 */
|
||||
#define TASDEVICE_XM_A1_REG TASDEVICE_REG(0x64, 0x63, 0x3c)
|
||||
#define TASDEVICE_XM_A1_REG TASDEVICE_REG(0x64, 0x02, 0x4c)
|
||||
/* XM_341 */
|
||||
#define TASDEVICE_XM_A2_REG TASDEVICE_REG(0x64, 0x63, 0x38)
|
||||
#define TASDEVICE_XM_A2_REG TASDEVICE_REG(0x64, 0x02, 0x64)
|
||||
|
||||
/* Volume control */
|
||||
#define TAS2563_DVC_LVL TASDEVICE_REG(0x00, 0x02, 0x0c)
|
||||
|
|
|
|||
|
|
@ -1093,6 +1093,29 @@ static int cs530x_component_probe(struct snd_soc_component *component)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool cs530x_mclk_freq_is_valid(struct cs530x_priv *cs530x,
|
||||
unsigned int freq)
|
||||
{
|
||||
/*
|
||||
* All these chips support 48 kHz- and 44.1 kHz-related sample rates,
|
||||
* but they differ in what MCLK frequency is required for achieving
|
||||
* the sample rate.
|
||||
*/
|
||||
switch (cs530x->devtype) {
|
||||
case CS4282:
|
||||
case CS4302:
|
||||
case CS4304:
|
||||
case CS4308:
|
||||
return freq == 49152000 || freq == 45158400;
|
||||
case CS5302:
|
||||
case CS5304:
|
||||
case CS5308:
|
||||
return freq == 24576000 || freq == 22579200;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id,
|
||||
int source, unsigned int freq, int dir)
|
||||
{
|
||||
|
|
@ -1101,11 +1124,7 @@ static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id,
|
|||
|
||||
switch (source) {
|
||||
case CS530X_SYSCLK_SRC_MCLK:
|
||||
switch (freq) {
|
||||
case CS530X_SYSCLK_REF_45_1MHZ:
|
||||
case CS530X_SYSCLK_REF_49_1MHZ:
|
||||
break;
|
||||
default:
|
||||
if (!cs530x_mclk_freq_is_valid(cs530x, freq)) {
|
||||
dev_err(component->dev, "Invalid MCLK source rate %d\n", freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,12 +200,6 @@
|
|||
/* IN_VOL_CTL5 and OUT_VOL_CTL5 */
|
||||
#define CS530X_INOUT_VU BIT(0)
|
||||
|
||||
/* MCLK Reference Source Frequency */
|
||||
/* 41KHz related */
|
||||
#define CS530X_SYSCLK_REF_45_1MHZ 45158400
|
||||
/* 48KHz related */
|
||||
#define CS530X_SYSCLK_REF_49_1MHZ 49152000
|
||||
|
||||
/* System Clock Source */
|
||||
#define CS530X_SYSCLK_SRC_MCLK 0
|
||||
#define CS530X_SYSCLK_SRC_PLL 1
|
||||
|
|
|
|||
|
|
@ -1111,8 +1111,10 @@ static int es9356_sdca_dev_resume(struct device *dev)
|
|||
es9356->disable_irq = false;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, es9356_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(es9356->regmap, false);
|
||||
regcache_sync(es9356->regmap);
|
||||
|
|
|
|||
|
|
@ -272,8 +272,10 @@ static int max98373_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, MAX98373_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(max98373->regmap, false);
|
||||
regcache_sync(max98373->regmap);
|
||||
|
|
|
|||
|
|
@ -633,7 +633,7 @@ static int pcm512x_dai_startup_slave(struct snd_pcm_substream *substream,
|
|||
struct regmap *regmap = pcm512x->regmap;
|
||||
|
||||
if (IS_ERR(pcm512x->sclk)) {
|
||||
dev_info(dev, "No SCLK, using BCLK: %ld\n",
|
||||
dev_info_once(dev, "No SCLK, using BCLK: %ld\n",
|
||||
PTR_ERR(pcm512x->sclk));
|
||||
|
||||
/* Disable reporting of missing SCLK as an error */
|
||||
|
|
|
|||
|
|
@ -779,8 +779,10 @@ static int rt1017_sdca_dev_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT1017_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt1017->regmap, false);
|
||||
regcache_sync(rt1017->regmap);
|
||||
|
|
|
|||
|
|
@ -774,8 +774,10 @@ static int rt1308_dev_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT1308_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt1308->regmap, false);
|
||||
regcache_sync_region(rt1308->regmap, 0xc000, 0xcfff);
|
||||
|
|
|
|||
|
|
@ -751,8 +751,10 @@ static int rt1316_dev_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT1316_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt1316->regmap, false);
|
||||
regcache_sync(rt1316->regmap);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
struct rt5575_spi_burst_write {
|
||||
u8 cmd;
|
||||
u32 addr;
|
||||
__le32 addr;
|
||||
u8 data[RT5575_SPI_BUF_LEN];
|
||||
u8 dummy;
|
||||
} __packed;
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ static const struct reg_sequence rt5650_init_list[] = {
|
|||
{RT5645_PWR_ANLG1, 0x02},
|
||||
{RT5645_IL_CMD3, 0x6728},
|
||||
{RT5645_PR_BASE + 0x3a, 0x0000},
|
||||
{RT5645_CLSD_OUT_CTRL1, 0x4059},
|
||||
{RT5645_GEN_CTRL3, 0x0200},
|
||||
};
|
||||
|
||||
static const struct reg_default rt5645_reg[] = {
|
||||
|
|
@ -1855,13 +1857,9 @@ static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
|
|||
RT5645_PWR_CLS_D_L,
|
||||
RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
|
||||
RT5645_PWR_CLS_D_L);
|
||||
snd_soc_component_update_bits(component, RT5645_GEN_CTRL3,
|
||||
RT5645_DET_CLK_MASK, RT5645_DET_CLK_MODE1);
|
||||
break;
|
||||
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
snd_soc_component_update_bits(component, RT5645_GEN_CTRL3,
|
||||
RT5645_DET_CLK_MASK, RT5645_DET_CLK_DIS);
|
||||
snd_soc_component_write(component, RT5645_EQ_CTRL2, 0);
|
||||
snd_soc_component_update_bits(component, RT5645_PWR_DIG1,
|
||||
RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@
|
|||
#define RT5645_A_JD_CTRL1 0x94
|
||||
#define RT5645_VAD_CTRL4 0x9d
|
||||
#define RT5645_CLSD_OUT_CTRL 0xa0
|
||||
#define RT5645_CLSD_OUT_CTRL1 0xa1
|
||||
/* Function - Digital */
|
||||
#define RT5645_ADC_EQ_CTRL1 0xae
|
||||
#define RT5645_ADC_EQ_CTRL2 0xaf
|
||||
|
|
|
|||
|
|
@ -769,8 +769,10 @@ static int rt5682_dev_resume(struct device *dev)
|
|||
}
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT5682_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt5682->sdw_regmap, false);
|
||||
regcache_cache_only(rt5682->regmap, false);
|
||||
|
|
|
|||
|
|
@ -528,8 +528,10 @@ static int rt700_dev_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT700_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt700->regmap, false);
|
||||
regcache_sync_region(rt700->regmap, 0x3000, 0x8fff);
|
||||
|
|
|
|||
|
|
@ -454,8 +454,10 @@ static int rt711_sdca_dev_resume(struct device *dev)
|
|||
}
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT711_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt711->regmap, false);
|
||||
regcache_sync(rt711->regmap);
|
||||
|
|
|
|||
|
|
@ -911,8 +911,10 @@ static int rt712_sdca_dmic_dev_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT712_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt712->regmap, false);
|
||||
regcache_sync(rt712->regmap);
|
||||
|
|
|
|||
|
|
@ -467,8 +467,10 @@ static int rt712_sdca_dev_resume(struct device *dev)
|
|||
}
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT712_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt712->regmap, false);
|
||||
regcache_sync(rt712->regmap);
|
||||
|
|
|
|||
|
|
@ -230,8 +230,10 @@ static int rt715_dev_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT715_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt715->regmap, false);
|
||||
regcache_sync_region(rt715->regmap,
|
||||
|
|
|
|||
|
|
@ -507,8 +507,10 @@ static int rt715_dev_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT715_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt715->regmap, false);
|
||||
regcache_sync_region(rt715->regmap, 0x3000, 0x8fff);
|
||||
|
|
|
|||
|
|
@ -505,8 +505,10 @@ static int rt721_sdca_dev_resume(struct device *dev)
|
|||
}
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT721_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt721->regmap, false);
|
||||
regcache_sync(rt721->regmap);
|
||||
|
|
|
|||
|
|
@ -552,8 +552,10 @@ static int rt722_sdca_dev_resume(struct device *dev)
|
|||
}
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT722_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt722->regmap, false);
|
||||
regcache_sync(rt722->regmap);
|
||||
|
|
|
|||
|
|
@ -1445,8 +1445,10 @@ static s32 tac5xx2_sdca_dev_resume(struct device *dev)
|
|||
}
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, TAC5XX2_PROBE_TIMEOUT_MS);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(tac_dev->regmap, false);
|
||||
regcache_mark_dirty(tac_dev->regmap);
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ struct tas2783_prv {
|
|||
wait_queue_head_t fw_wait;
|
||||
bool fw_dl_task_done;
|
||||
bool fw_dl_success;
|
||||
/* use fallback fw name */
|
||||
bool fw_use_fallback;
|
||||
};
|
||||
|
||||
static const struct reg_default tas2783_reg_default[] = {
|
||||
|
|
@ -740,11 +742,19 @@ static void tas2783_fw_ready(const struct firmware *fmw, void *context)
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* firmware binary not found*/
|
||||
if (!fmw || !fmw->data) {
|
||||
/* firmware binary not found*/
|
||||
dev_err(tas_dev->dev,
|
||||
"Failed to read fw binary %s\n",
|
||||
tas_dev->rca_binaryname);
|
||||
if (!tas_dev->fw_use_fallback) {
|
||||
tas_dev->fw_use_fallback = true;
|
||||
dev_info(tas_dev->dev,
|
||||
"Failed to read preferred fw binary: %s, attempting fallback binary load\n",
|
||||
tas_dev->rca_binaryname);
|
||||
} else {
|
||||
dev_err(tas_dev->dev,
|
||||
"Failed to read fallback fw binary %s\n",
|
||||
tas_dev->rca_binaryname);
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1083,8 +1093,10 @@ static s32 tas2783_sdca_dev_resume(struct device *dev)
|
|||
int ret;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, TAS2783_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(tas_dev->regmap, false);
|
||||
regcache_sync(tas_dev->regmap);
|
||||
|
|
@ -1103,13 +1115,16 @@ static void tas_generate_fw_name(struct sdw_slave *slave, char *name, size_t siz
|
|||
bool pci_found = false;
|
||||
#if IS_ENABLED(CONFIG_PCI)
|
||||
struct device *dev = &slave->dev;
|
||||
struct tas2783_prv *tas_dev = dev_get_drvdata(&slave->dev);
|
||||
struct pci_dev *pci = NULL;
|
||||
const char *fw_uid_prefix = tas_dev->fw_use_fallback ? "" : "0x";
|
||||
|
||||
for (; dev; dev = dev->parent) {
|
||||
if (dev->bus == &pci_bus_type) {
|
||||
pci = to_pci_dev(dev);
|
||||
scnprintf(name, size, "%04X-%1X-%1X.bin",
|
||||
pci->subsystem_device, bus->link_id, unique_id);
|
||||
scnprintf(name, size, "%04X-%1X-%s%1X.bin",
|
||||
pci->subsystem_device, bus->link_id,
|
||||
fw_uid_prefix, unique_id);
|
||||
pci_found = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1121,28 +1136,15 @@ static void tas_generate_fw_name(struct sdw_slave *slave, char *name, size_t siz
|
|||
bus->link_id, unique_id);
|
||||
}
|
||||
|
||||
static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
|
||||
static s32 tas_fw_load(struct tas2783_prv *tas_dev, struct sdw_slave *slave)
|
||||
{
|
||||
struct tas2783_prv *tas_dev = dev_get_drvdata(dev);
|
||||
s32 ret;
|
||||
u8 unique_id = tas_dev->sdw_peripheral->id.unique_id;
|
||||
|
||||
if (tas_dev->hw_init)
|
||||
return 0;
|
||||
|
||||
tas_dev->fw_dl_task_done = false;
|
||||
tas_dev->fw_dl_success = false;
|
||||
|
||||
ret = regmap_write(tas_dev->regmap, TAS2783_SW_RESET, 0x1);
|
||||
if (ret) {
|
||||
dev_err(dev, "sw reset failed, err=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
usleep_range(2000, 2200);
|
||||
|
||||
tas_generate_fw_name(slave, tas_dev->rca_binaryname,
|
||||
sizeof(tas_dev->rca_binaryname));
|
||||
|
||||
tas_dev->fw_dl_task_done = false;
|
||||
ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
|
||||
tas_dev->rca_binaryname, tas_dev->dev,
|
||||
GFP_KERNEL, tas_dev, tas2783_fw_ready);
|
||||
|
|
@ -1157,8 +1159,35 @@ static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
|
|||
msecs_to_jiffies(TIMEOUT_FW_DL_MS));
|
||||
if (!ret) {
|
||||
dev_err(tas_dev->dev, "fw request, wait_event timeout\n");
|
||||
ret = -EAGAIN;
|
||||
} else {
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
|
||||
{
|
||||
struct tas2783_prv *tas_dev = dev_get_drvdata(dev);
|
||||
s32 ret;
|
||||
|
||||
if (tas_dev->hw_init)
|
||||
return 0;
|
||||
|
||||
tas_dev->fw_dl_success = false;
|
||||
|
||||
ret = regmap_write(tas_dev->regmap, TAS2783_SW_RESET, 0x1);
|
||||
if (ret) {
|
||||
dev_err(dev, "sw reset failed, err=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
usleep_range(2000, 2200);
|
||||
|
||||
tas_dev->fw_use_fallback = false;
|
||||
ret = tas_fw_load(tas_dev, slave);
|
||||
if (!ret && tas_dev->fw_use_fallback)
|
||||
ret = tas_fw_load(tas_dev, slave);
|
||||
|
||||
if (!ret) {
|
||||
if (tas_dev->sa_func_data)
|
||||
ret = sdca_regmap_write_init(dev, tas_dev->regmap,
|
||||
tas_dev->sa_func_data);
|
||||
|
|
|
|||
|
|
@ -1049,11 +1049,13 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
static const u8 dual_rate_q[] = {4, 8, 9, 12, 16};
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
|
||||
int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
|
||||
u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
|
||||
u16 d, pll_d = 1;
|
||||
bool dual_rate;
|
||||
int clk;
|
||||
int width = aic3x->slot_width;
|
||||
|
||||
|
|
@ -1079,14 +1081,25 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
|
|||
|
||||
/* Fsref can be 44100 or 48000 */
|
||||
fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000;
|
||||
dual_rate = params_rate(params) >= 64000;
|
||||
|
||||
/* Try to find a value for Q which allows us to bypass the PLL and
|
||||
* generate CODEC_CLK directly. */
|
||||
for (pll_q = 2; pll_q < 18; pll_q++)
|
||||
if (aic3x->sysclk / (128 * pll_q) == fsref) {
|
||||
bypass_pll = 1;
|
||||
break;
|
||||
if (dual_rate) {
|
||||
for (int i = 0; i < ARRAY_SIZE(dual_rate_q); i++) {
|
||||
pll_q = dual_rate_q[i];
|
||||
if (aic3x->sysclk / (128 * pll_q) == fsref) {
|
||||
bypass_pll = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (pll_q = 2; pll_q < 18; pll_q++)
|
||||
if (aic3x->sysclk / (128 * pll_q) == fsref) {
|
||||
bypass_pll = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bypass_pll) {
|
||||
pll_q &= 0xf;
|
||||
|
|
@ -1106,13 +1119,13 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
|
|||
* right DAC to right channel input */
|
||||
data = (LDAC2LCH | RDAC2RCH);
|
||||
data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000;
|
||||
if (params_rate(params) >= 64000)
|
||||
if (dual_rate)
|
||||
data |= DUAL_RATE_MODE;
|
||||
snd_soc_component_write(component, AIC3X_CODEC_DATAPATH_REG, data);
|
||||
|
||||
/* codec sample rate select */
|
||||
data = (fsref * 20) / params_rate(params);
|
||||
if (params_rate(params) < 64000)
|
||||
if (!dual_rate)
|
||||
data /= 2;
|
||||
data /= 5;
|
||||
data -= 2;
|
||||
|
|
|
|||
|
|
@ -288,6 +288,26 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
|
|||
config_be.dst_addr_width = buswidth;
|
||||
config_be.dst_maxburst = dma_params_be->maxburst;
|
||||
|
||||
/*
|
||||
* For eDMA, the back-end may report a maxburst size that is not evenly
|
||||
* divisible by the channel count. This causes the DMA transfer length
|
||||
* to misalign with the FIFO boundary, resulting in wrong data and
|
||||
* audible noise. Align maxburst to the nearest valid boundary:
|
||||
* - If maxburst >= channel count, override to the channel count so
|
||||
* each transfer equals exactly one audio frame.
|
||||
* - If maxburst < channel count, override to 1 to avoid partial-frame
|
||||
* transfers.
|
||||
*/
|
||||
if (asrc->use_edma && (dma_params_be->maxburst % params_channels(params))) {
|
||||
if (dma_params_be->maxburst >= params_channels(params)) {
|
||||
config_be.src_maxburst = params_channels(params);
|
||||
config_be.dst_maxburst = params_channels(params);
|
||||
} else {
|
||||
config_be.src_maxburst = 1;
|
||||
config_be.dst_maxburst = 1;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&audio_config, 0, sizeof(audio_config));
|
||||
config_be.peripheral_config = &audio_config;
|
||||
config_be.peripheral_size = sizeof(audio_config);
|
||||
|
|
|
|||
|
|
@ -778,18 +778,6 @@ static void graph_link_init(struct simple_util_priv *priv,
|
|||
graph_parse_daifmt(ports_cpu, &daifmt);
|
||||
graph_parse_daifmt(ports_codec, &daifmt);
|
||||
graph_parse_daifmt(lnk, &daifmt);
|
||||
if (daifmt) {
|
||||
struct device *dev = simple_priv_to_dev(priv);
|
||||
|
||||
/*
|
||||
* Recommend to use Auto Select by using .auto_selectable_formats.
|
||||
* linux/sound/soc/renesas/rcar/core.c can be good sample for it.
|
||||
*
|
||||
* One note is that Audio Graph Card2 still keeps compatible to set
|
||||
* DAI format via DT.
|
||||
*/
|
||||
dev_warn_once(dev, "use .auto_selectable_formats on each corresponding CPU/Codec driver");
|
||||
}
|
||||
|
||||
graph_util_parse_link_direction(lnk, &playback_only, &capture_only);
|
||||
graph_util_parse_link_direction(ports_cpu, &playback_only, &capture_only);
|
||||
|
|
|
|||
|
|
@ -587,6 +587,10 @@ static int graph_callback(const struct gpr_resp_pkt *data, void *priv, int op)
|
|||
token = hdr->token & APM_WRITE_TOKEN_MASK;
|
||||
|
||||
done = data->payload;
|
||||
if (!graph->rx_data.buf) {
|
||||
mutex_unlock(&graph->lock);
|
||||
break;
|
||||
}
|
||||
phys = graph->rx_data.buf[token].phys;
|
||||
mutex_unlock(&graph->lock);
|
||||
/* token numbering starts at 0 */
|
||||
|
|
@ -609,6 +613,10 @@ static int graph_callback(const struct gpr_resp_pkt *data, void *priv, int op)
|
|||
client_event = APM_CLIENT_EVENT_DATA_READ_DONE;
|
||||
mutex_lock(&graph->lock);
|
||||
rd_done = data->payload;
|
||||
if (!graph->tx_data.buf) {
|
||||
mutex_unlock(&graph->lock);
|
||||
break;
|
||||
}
|
||||
phys = graph->tx_data.buf[hdr->token].phys;
|
||||
mutex_unlock(&graph->lock);
|
||||
/* token numbering starts at 0 */
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
|
|
@ -18,6 +19,7 @@
|
|||
#include <sound/pcm_params.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "rockchip_sai.h"
|
||||
|
||||
#define DRV_NAME "rockchip-sai"
|
||||
|
|
@ -215,12 +217,14 @@ static void rockchip_sai_xfer_clk_stop_and_wait(struct rk_sai_dev *sai, unsigned
|
|||
static int rockchip_sai_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct rk_sai_dev *sai = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
rockchip_sai_fsync_lost_detect(sai, 0);
|
||||
rockchip_sai_fsync_err_detect(sai, 0);
|
||||
|
||||
scoped_guard(spinlock_irqsave, &sai->xfer_lock)
|
||||
rockchip_sai_xfer_clk_stop_and_wait(sai, NULL);
|
||||
spin_lock_irqsave(&sai->xfer_lock, flags);
|
||||
rockchip_sai_xfer_clk_stop_and_wait(sai, NULL);
|
||||
spin_unlock_irqrestore(&sai->xfer_lock, flags);
|
||||
|
||||
regcache_cache_only(sai->regmap, true);
|
||||
/*
|
||||
|
|
@ -480,6 +484,7 @@ static int rockchip_sai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
|||
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
|
||||
unsigned int mask = 0, val = 0;
|
||||
unsigned int clk_gates;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
pm_runtime_get_sync(dai->dev);
|
||||
|
|
@ -495,56 +500,56 @@ static int rockchip_sai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
|||
sai->is_master_mode = false;
|
||||
break;
|
||||
default:
|
||||
pm_runtime_put(dai->dev);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto err_pm_put;
|
||||
}
|
||||
|
||||
scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
|
||||
rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
|
||||
if (sai->initialized) {
|
||||
if (sai->has_capture && sai->has_playback)
|
||||
rockchip_sai_xfer_stop(sai, -1);
|
||||
else if (sai->has_capture)
|
||||
rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_CAPTURE);
|
||||
else
|
||||
rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_PLAYBACK);
|
||||
} else {
|
||||
rockchip_sai_clear(sai, 0);
|
||||
sai->initialized = true;
|
||||
}
|
||||
|
||||
regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
|
||||
|
||||
mask = SAI_CKR_CKP_MASK | SAI_CKR_FSP_MASK;
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_NORMAL;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_INVERTED;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_NORMAL;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_INVERTED;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
|
||||
rockchip_sai_fmt_create(sai, fmt);
|
||||
}
|
||||
|
||||
if (clk_gates)
|
||||
regmap_update_bits(sai->regmap, SAI_XFER,
|
||||
SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
|
||||
clk_gates);
|
||||
spin_lock_irqsave(&sai->xfer_lock, flags);
|
||||
rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
|
||||
if (sai->initialized) {
|
||||
if (sai->has_capture && sai->has_playback)
|
||||
rockchip_sai_xfer_stop(sai, -1);
|
||||
else if (sai->has_capture)
|
||||
rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_CAPTURE);
|
||||
else
|
||||
rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_PLAYBACK);
|
||||
} else {
|
||||
rockchip_sai_clear(sai, 0);
|
||||
sai->initialized = true;
|
||||
}
|
||||
|
||||
regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
|
||||
|
||||
mask = SAI_CKR_CKP_MASK | SAI_CKR_FSP_MASK;
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_NORMAL;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_INVERTED;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_NORMAL;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_INVERTED;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto err_xfer_unlock;
|
||||
}
|
||||
|
||||
regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
|
||||
|
||||
rockchip_sai_fmt_create(sai, fmt);
|
||||
|
||||
err_xfer_unlock:
|
||||
if (clk_gates)
|
||||
regmap_update_bits(sai->regmap, SAI_XFER,
|
||||
SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
|
||||
clk_gates);
|
||||
spin_unlock_irqrestore(&sai->xfer_lock, flags);
|
||||
err_pm_put:
|
||||
pm_runtime_put(dai->dev);
|
||||
|
||||
return ret;
|
||||
|
|
@ -560,6 +565,7 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
|
|||
unsigned int ch_per_lane, slot_width;
|
||||
unsigned int val, fscr, reg;
|
||||
unsigned int lanes, req_lanes;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
if (!rockchip_sai_stream_valid(substream, dai))
|
||||
|
|
@ -586,8 +592,8 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
|
|||
dev_err(sai->dev, "not enough lanes (%d) for requested number of %s channels (%d)\n",
|
||||
lanes, reg == SAI_TXCR ? "playback" : "capture",
|
||||
params_channels(params));
|
||||
pm_runtime_put(sai->dev);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto err_pm_put;
|
||||
} else {
|
||||
lanes = req_lanes;
|
||||
}
|
||||
|
|
@ -613,88 +619,84 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
|
|||
val = SAI_XCR_VDW(32);
|
||||
break;
|
||||
default:
|
||||
pm_runtime_put(sai->dev);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto err_pm_put;
|
||||
}
|
||||
|
||||
val |= SAI_XCR_CSR(lanes);
|
||||
|
||||
scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
|
||||
spin_lock_irqsave(&sai->xfer_lock, flags);
|
||||
|
||||
regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val);
|
||||
regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val);
|
||||
|
||||
if (!sai->is_tdm)
|
||||
regmap_update_bits(sai->regmap, reg, SAI_XCR_SBW_MASK,
|
||||
SAI_XCR_SBW(params_physical_width(params)));
|
||||
if (!sai->is_tdm)
|
||||
regmap_update_bits(sai->regmap, reg, SAI_XCR_SBW_MASK,
|
||||
SAI_XCR_SBW(params_physical_width(params)));
|
||||
|
||||
regmap_read(sai->regmap, reg, &val);
|
||||
regmap_read(sai->regmap, reg, &val);
|
||||
|
||||
slot_width = SAI_XCR_SBW_V(val);
|
||||
ch_per_lane = params_channels(params) / lanes;
|
||||
slot_width = SAI_XCR_SBW_V(val);
|
||||
ch_per_lane = params_channels(params) / lanes;
|
||||
|
||||
regmap_update_bits(sai->regmap, reg, SAI_XCR_SNB_MASK,
|
||||
SAI_XCR_SNB(ch_per_lane));
|
||||
regmap_update_bits(sai->regmap, reg, SAI_XCR_SNB_MASK,
|
||||
SAI_XCR_SNB(ch_per_lane));
|
||||
|
||||
fscr = SAI_FSCR_FW(sai->fw_ratio * slot_width * ch_per_lane);
|
||||
fscr = SAI_FSCR_FW(sai->fw_ratio * slot_width * ch_per_lane);
|
||||
|
||||
switch (sai->fpw) {
|
||||
case FPW_ONE_BCLK_WIDTH:
|
||||
fscr |= SAI_FSCR_FPW(1);
|
||||
break;
|
||||
case FPW_ONE_SLOT_WIDTH:
|
||||
fscr |= SAI_FSCR_FPW(slot_width);
|
||||
break;
|
||||
case FPW_HALF_FRAME_WIDTH:
|
||||
fscr |= SAI_FSCR_FPW(sai->fw_ratio * slot_width * ch_per_lane / 2);
|
||||
break;
|
||||
default:
|
||||
dev_err(sai->dev, "Invalid Frame Pulse Width %d\n", sai->fpw);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
regmap_update_bits(sai->regmap, SAI_FSCR,
|
||||
SAI_FSCR_FW_MASK | SAI_FSCR_FPW_MASK, fscr);
|
||||
|
||||
if (sai->is_master_mode) {
|
||||
bclk_rate = sai->fw_ratio * slot_width *
|
||||
ch_per_lane * params_rate(params);
|
||||
ret = clk_set_rate(sai->mclk, sai->mclk_rate);
|
||||
if (ret)
|
||||
dev_err(sai->dev, "Failed to set mclk to %u: %pe\n",
|
||||
sai->mclk_rate, ERR_PTR(ret));
|
||||
else {
|
||||
mclk_rate = clk_get_rate(sai->mclk);
|
||||
if (mclk_rate < bclk_rate) {
|
||||
dev_err(sai->dev, "Mismatch mclk: %u, at least %u\n",
|
||||
mclk_rate, bclk_rate);
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
|
||||
div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
|
||||
mclk_req_rate = bclk_rate * div_bclk;
|
||||
|
||||
if (mclk_rate <
|
||||
mclk_req_rate - CLK_SHIFT_RATE_HZ_MAX ||
|
||||
mclk_rate >
|
||||
mclk_req_rate + CLK_SHIFT_RATE_HZ_MAX) {
|
||||
dev_err(sai->dev,
|
||||
"Mismatch mclk: %u, expected %u (+/- %dHz)\n",
|
||||
mclk_rate, mclk_req_rate,
|
||||
CLK_SHIFT_RATE_HZ_MAX);
|
||||
ret = -EINVAL;
|
||||
} else
|
||||
regmap_update_bits(sai->regmap,
|
||||
SAI_CKR,
|
||||
SAI_CKR_MDIV_MASK,
|
||||
SAI_CKR_MDIV(div_bclk));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (sai->fpw) {
|
||||
case FPW_ONE_BCLK_WIDTH:
|
||||
fscr |= SAI_FSCR_FPW(1);
|
||||
break;
|
||||
case FPW_ONE_SLOT_WIDTH:
|
||||
fscr |= SAI_FSCR_FPW(slot_width);
|
||||
break;
|
||||
case FPW_HALF_FRAME_WIDTH:
|
||||
fscr |= SAI_FSCR_FPW(sai->fw_ratio * slot_width * ch_per_lane / 2);
|
||||
break;
|
||||
default:
|
||||
dev_err(sai->dev, "Invalid Frame Pulse Width %d\n", sai->fpw);
|
||||
ret = -EINVAL;
|
||||
goto err_xfer_unlock;
|
||||
}
|
||||
|
||||
regmap_update_bits(sai->regmap, SAI_FSCR,
|
||||
SAI_FSCR_FW_MASK | SAI_FSCR_FPW_MASK, fscr);
|
||||
|
||||
if (sai->is_master_mode) {
|
||||
bclk_rate = sai->fw_ratio * slot_width * ch_per_lane * params_rate(params);
|
||||
ret = clk_set_rate(sai->mclk, sai->mclk_rate);
|
||||
if (ret) {
|
||||
dev_err(sai->dev, "Failed to set mclk to %u: %pe\n",
|
||||
sai->mclk_rate, ERR_PTR(ret));
|
||||
goto err_xfer_unlock;
|
||||
}
|
||||
|
||||
mclk_rate = clk_get_rate(sai->mclk);
|
||||
if (mclk_rate < bclk_rate) {
|
||||
dev_err(sai->dev, "Mismatch mclk: %u, at least %u\n",
|
||||
mclk_rate, bclk_rate);
|
||||
ret = -EINVAL;
|
||||
goto err_xfer_unlock;
|
||||
}
|
||||
|
||||
div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
|
||||
mclk_req_rate = bclk_rate * div_bclk;
|
||||
|
||||
if (mclk_rate < mclk_req_rate - CLK_SHIFT_RATE_HZ_MAX ||
|
||||
mclk_rate > mclk_req_rate + CLK_SHIFT_RATE_HZ_MAX) {
|
||||
dev_err(sai->dev, "Mismatch mclk: %u, expected %u (+/- %dHz)\n",
|
||||
mclk_rate, mclk_req_rate, CLK_SHIFT_RATE_HZ_MAX);
|
||||
ret = -EINVAL;
|
||||
goto err_xfer_unlock;
|
||||
}
|
||||
|
||||
regmap_update_bits(sai->regmap, SAI_CKR, SAI_CKR_MDIV_MASK,
|
||||
SAI_CKR_MDIV(div_bclk));
|
||||
}
|
||||
|
||||
err_xfer_unlock:
|
||||
spin_unlock_irqrestore(&sai->xfer_lock, flags);
|
||||
err_pm_put:
|
||||
pm_runtime_put(sai->dev);
|
||||
|
||||
return ret;
|
||||
|
|
@ -704,6 +706,7 @@ static int rockchip_sai_prepare(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
|
||||
unsigned long flags;
|
||||
|
||||
if (!rockchip_sai_stream_valid(substream, dai))
|
||||
return 0;
|
||||
|
|
@ -724,12 +727,13 @@ static int rockchip_sai_prepare(struct snd_pcm_substream *substream,
|
|||
* udelay falls short.
|
||||
*/
|
||||
udelay(20);
|
||||
scoped_guard(spinlock_irqsave, &sai->xfer_lock)
|
||||
regmap_update_bits(sai->regmap, SAI_XFER,
|
||||
SAI_XFER_CLK_MASK |
|
||||
SAI_XFER_FSS_MASK,
|
||||
SAI_XFER_CLK_EN |
|
||||
SAI_XFER_FSS_EN);
|
||||
spin_lock_irqsave(&sai->xfer_lock, flags);
|
||||
regmap_update_bits(sai->regmap, SAI_XFER,
|
||||
SAI_XFER_CLK_MASK |
|
||||
SAI_XFER_FSS_MASK,
|
||||
SAI_XFER_CLK_EN |
|
||||
SAI_XFER_FSS_EN);
|
||||
spin_unlock_irqrestore(&sai->xfer_lock, flags);
|
||||
}
|
||||
|
||||
rockchip_sai_fsync_lost_detect(sai, 1);
|
||||
|
|
@ -912,6 +916,7 @@ static int rockchip_sai_set_tdm_slot(struct snd_soc_dai *dai,
|
|||
int slots, int slot_width)
|
||||
{
|
||||
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
|
||||
unsigned long flags;
|
||||
unsigned int clk_gates;
|
||||
int sw = slot_width;
|
||||
|
||||
|
|
@ -927,16 +932,16 @@ static int rockchip_sai_set_tdm_slot(struct snd_soc_dai *dai,
|
|||
return -EINVAL;
|
||||
|
||||
pm_runtime_get_sync(dai->dev);
|
||||
scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
|
||||
rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
|
||||
regmap_update_bits(sai->regmap, SAI_TXCR, SAI_XCR_SBW_MASK,
|
||||
SAI_XCR_SBW(sw));
|
||||
regmap_update_bits(sai->regmap, SAI_RXCR, SAI_XCR_SBW_MASK,
|
||||
SAI_XCR_SBW(sw));
|
||||
regmap_update_bits(sai->regmap, SAI_XFER,
|
||||
SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
|
||||
clk_gates);
|
||||
}
|
||||
spin_lock_irqsave(&sai->xfer_lock, flags);
|
||||
rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
|
||||
regmap_update_bits(sai->regmap, SAI_TXCR, SAI_XCR_SBW_MASK,
|
||||
SAI_XCR_SBW(sw));
|
||||
regmap_update_bits(sai->regmap, SAI_RXCR, SAI_XCR_SBW_MASK,
|
||||
SAI_XCR_SBW(sw));
|
||||
regmap_update_bits(sai->regmap, SAI_XFER,
|
||||
SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
|
||||
clk_gates);
|
||||
spin_unlock_irqrestore(&sai->xfer_lock, flags);
|
||||
pm_runtime_put(dai->dev);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -160,6 +160,9 @@ static int ge_put_enum_double(struct snd_kcontrol *kcontrol,
|
|||
unsigned int reg = e->reg;
|
||||
int ret;
|
||||
|
||||
if (item[0] >= e->items)
|
||||
return -EINVAL;
|
||||
|
||||
reg &= ~SDW_SDCA_CTL_CSEL(0x3F);
|
||||
reg |= SDW_SDCA_CTL_CSEL(SDCA_CTL_GE_DETECTED_MODE);
|
||||
|
||||
|
|
|
|||
|
|
@ -1980,19 +1980,15 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card)
|
|||
}
|
||||
}
|
||||
|
||||
static void snd_soc_remove_device_links(struct snd_soc_card *card,
|
||||
struct snd_soc_component *stop_at)
|
||||
static void snd_soc_remove_device_links(struct snd_soc_card *card)
|
||||
{
|
||||
struct snd_soc_component *component;
|
||||
|
||||
for_each_card_components(card, component) {
|
||||
if (card->dev == component->dev)
|
||||
continue;
|
||||
|
||||
device_link_remove(card->dev, component->dev);
|
||||
|
||||
if (component == stop_at)
|
||||
return;
|
||||
if (component->card_device_link) {
|
||||
device_link_del(component->card_device_link);
|
||||
component->card_device_link = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2001,7 +1997,7 @@ static void snd_soc_unbind_card(struct snd_soc_card *card)
|
|||
if (snd_soc_card_is_instantiated(card)) {
|
||||
card->instantiated = false;
|
||||
|
||||
snd_soc_remove_device_links(card, NULL);
|
||||
snd_soc_remove_device_links(card);
|
||||
|
||||
soc_cleanup_card_resources(card);
|
||||
}
|
||||
|
|
@ -2012,7 +2008,6 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
|
|||
struct snd_soc_pcm_runtime *rtd;
|
||||
struct snd_soc_component *component;
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
|
||||
struct snd_soc_component *last_devlinked_component = NULL;
|
||||
int ret;
|
||||
|
||||
snd_soc_card_mutex_lock_root(card);
|
||||
|
|
@ -2141,19 +2136,21 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
|
|||
* Add device_link from card to component so that system_suspend
|
||||
* will be done in the correct order. The card must suspend first
|
||||
* to stop audio activity before the components suspend.
|
||||
*
|
||||
* If a driver pair already have a link in the opposite direction
|
||||
* they must manage their own suspend order.
|
||||
*/
|
||||
for_each_card_components(card, component) {
|
||||
if (card->dev == component->dev)
|
||||
continue;
|
||||
|
||||
if (!device_link_add(card->dev, component->dev, DL_FLAG_STATELESS)) {
|
||||
dev_warn(card->dev, "Failed to create device link to %s\n",
|
||||
component->card_device_link = device_link_add(card->dev,
|
||||
component->dev,
|
||||
DL_FLAG_STATELESS);
|
||||
if (!component->card_device_link) {
|
||||
dev_warn(card->dev, "Could not create device link to %s\n",
|
||||
dev_name(component->dev));
|
||||
ret = -EINVAL;
|
||||
goto probe_end;
|
||||
}
|
||||
|
||||
last_devlinked_component = component;
|
||||
}
|
||||
|
||||
ret = snd_soc_card_late_probe(card);
|
||||
|
|
@ -2185,9 +2182,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
|
|||
|
||||
probe_end:
|
||||
if (ret < 0) {
|
||||
if (last_devlinked_component)
|
||||
snd_soc_remove_device_links(card, last_devlinked_component);
|
||||
|
||||
snd_soc_remove_device_links(card);
|
||||
soc_cleanup_card_resources(card);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user