Merge remote-tracking branch 'asoc/for-5.13' into asoc-linus

This commit is contained in:
Mark Brown 2021-06-25 14:08:01 +01:00
commit c073a58a7e
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
29 changed files with 297 additions and 99 deletions

View File

@ -75,6 +75,10 @@ properties:
$ref: "/schemas/types.yaml#/definitions/uint32"
enum: [ 0, 1, 2, 3 ]
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
required:
- compatible
- reg

View File

@ -7354,7 +7354,6 @@ F: drivers/net/ethernet/freescale/fs_enet/
F: include/linux/fs_enet_pd.h
FREESCALE SOC SOUND DRIVERS
M: Timur Tabi <timur@kernel.org>
M: Nicolin Chen <nicoleotsuka@gmail.com>
M: Xiubo Li <Xiubo.Lee@gmail.com>
R: Fabio Estevam <festevam@gmail.com>

View File

@ -492,7 +492,7 @@ int sdw_read_no_pm(struct sdw_slave *slave, u32 addr)
}
EXPORT_SYMBOL(sdw_read_no_pm);
static int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
{
int tmp;
@ -503,6 +503,21 @@ static int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
tmp = (tmp & ~mask) | val;
return sdw_write_no_pm(slave, addr, tmp);
}
EXPORT_SYMBOL(sdw_update_no_pm);
/* Read-Modify-Write Slave register */
int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
{
int tmp;
tmp = sdw_read(slave, addr);
if (tmp < 0)
return tmp;
tmp = (tmp & ~mask) | val;
return sdw_write(slave, addr, tmp);
}
EXPORT_SYMBOL(sdw_update);
/**
* sdw_nread() - Read "n" contiguous SDW Slave registers

View File

@ -201,19 +201,6 @@ static inline void sdw_fill_port_params(struct sdw_port_params *params,
params->data_mode = data_mode;
}
/* Read-Modify-Write Slave register */
static inline int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
{
int tmp;
tmp = sdw_read(slave, addr);
if (tmp < 0)
return tmp;
tmp = (tmp & ~mask) | val;
return sdw_write(slave, addr, tmp);
}
/* broadcast read/write for tests */
int sdw_bread_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr);
int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 value);

View File

@ -1041,6 +1041,9 @@ int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value);
int sdw_read_no_pm(struct sdw_slave *slave, u32 addr);
int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);
int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);
int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val);
int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val);
int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id);
void sdw_extract_slave_id(struct sdw_bus *bus, u64 addr, struct sdw_slave_id *id);

View File

@ -200,6 +200,7 @@ struct atmel_i2s_dev {
unsigned int fmt;
const struct atmel_i2s_gck_param *gck_param;
const struct atmel_i2s_caps *caps;
int clk_use_no;
};
static irqreturn_t atmel_i2s_interrupt(int irq, void *dev_id)
@ -321,9 +322,16 @@ static int atmel_i2s_hw_params(struct snd_pcm_substream *substream,
{
struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
unsigned int mr = 0;
unsigned int mr = 0, mr_mask;
int ret;
mr_mask = ATMEL_I2SC_MR_FORMAT_MASK | ATMEL_I2SC_MR_MODE_MASK |
ATMEL_I2SC_MR_DATALENGTH_MASK;
if (is_playback)
mr_mask |= ATMEL_I2SC_MR_TXMONO;
else
mr_mask |= ATMEL_I2SC_MR_RXMONO;
switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
mr |= ATMEL_I2SC_MR_FORMAT_I2S;
@ -402,7 +410,7 @@ static int atmel_i2s_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
return regmap_write(dev->regmap, ATMEL_I2SC_MR, mr);
return regmap_update_bits(dev->regmap, ATMEL_I2SC_MR, mr_mask, mr);
}
static int atmel_i2s_switch_mck_generator(struct atmel_i2s_dev *dev,
@ -495,18 +503,28 @@ static int atmel_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
is_master = (mr & ATMEL_I2SC_MR_MODE_MASK) == ATMEL_I2SC_MR_MODE_MASTER;
/* If master starts, enable the audio clock. */
if (is_master && mck_enabled)
err = atmel_i2s_switch_mck_generator(dev, true);
if (err)
return err;
if (is_master && mck_enabled) {
if (!dev->clk_use_no) {
err = atmel_i2s_switch_mck_generator(dev, true);
if (err)
return err;
}
dev->clk_use_no++;
}
err = regmap_write(dev->regmap, ATMEL_I2SC_CR, cr);
if (err)
return err;
/* If master stops, disable the audio clock. */
if (is_master && !mck_enabled)
err = atmel_i2s_switch_mck_generator(dev, false);
if (is_master && !mck_enabled) {
if (dev->clk_use_no == 1) {
err = atmel_i2s_switch_mck_generator(dev, false);
if (err)
return err;
}
dev->clk_use_no--;
}
return err;
}
@ -542,6 +560,7 @@ static struct snd_soc_dai_driver atmel_i2s_dai = {
},
.ops = &atmel_i2s_dai_ops,
.symmetric_rate = 1,
.symmetric_sample_bits = 1,
};
static const struct snd_soc_component_driver atmel_i2s_component = {

View File

@ -79,7 +79,7 @@
#define CS42L42_HP_PDN_SHIFT 3
#define CS42L42_HP_PDN_MASK (1 << CS42L42_HP_PDN_SHIFT)
#define CS42L42_ADC_PDN_SHIFT 2
#define CS42L42_ADC_PDN_MASK (1 << CS42L42_HP_PDN_SHIFT)
#define CS42L42_ADC_PDN_MASK (1 << CS42L42_ADC_PDN_SHIFT)
#define CS42L42_PDN_ALL_SHIFT 0
#define CS42L42_PDN_ALL_MASK (1 << CS42L42_PDN_ALL_SHIFT)

View File

@ -271,7 +271,7 @@ static __maybe_unused int max98373_resume(struct device *dev)
struct max98373_priv *max98373 = dev_get_drvdata(dev);
unsigned long time;
if (!max98373->hw_init)
if (!max98373->first_hw_init)
return 0;
if (!slave->unattach_request)
@ -362,7 +362,7 @@ static int max98373_io_init(struct sdw_slave *slave)
struct device *dev = &slave->dev;
struct max98373_priv *max98373 = dev_get_drvdata(dev);
if (max98373->pm_init_once) {
if (max98373->first_hw_init) {
regcache_cache_only(max98373->regmap, false);
regcache_cache_bypass(max98373->regmap, true);
}
@ -370,7 +370,7 @@ static int max98373_io_init(struct sdw_slave *slave)
/*
* PM runtime is only enabled when a Slave reports as Attached
*/
if (!max98373->pm_init_once) {
if (!max98373->first_hw_init) {
/* set autosuspend parameters */
pm_runtime_set_autosuspend_delay(dev, 3000);
pm_runtime_use_autosuspend(dev);
@ -462,12 +462,12 @@ static int max98373_io_init(struct sdw_slave *slave)
regmap_write(max98373->regmap, MAX98373_R20B5_BDE_EN, 1);
regmap_write(max98373->regmap, MAX98373_R20E2_LIMITER_EN, 1);
if (max98373->pm_init_once) {
if (max98373->first_hw_init) {
regcache_cache_bypass(max98373->regmap, false);
regcache_mark_dirty(max98373->regmap);
}
max98373->pm_init_once = true;
max98373->first_hw_init = true;
max98373->hw_init = true;
pm_runtime_mark_last_busy(dev);
@ -787,6 +787,8 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
max98373->cache = devm_kcalloc(dev, max98373->cache_num,
sizeof(*max98373->cache),
GFP_KERNEL);
if (!max98373->cache)
return -ENOMEM;
for (i = 0; i < max98373->cache_num; i++)
max98373->cache[i].reg = max98373_sdw_cache_reg[i];
@ -795,7 +797,7 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
max98373_slot_config(dev, max98373);
max98373->hw_init = false;
max98373->pm_init_once = false;
max98373->first_hw_init = false;
/* codec registration */
ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98373_sdw,

View File

@ -226,7 +226,7 @@ struct max98373_priv {
/* variables to support soundwire */
struct sdw_slave *slave;
bool hw_init;
bool pm_init_once;
bool first_hw_init;
int slot;
unsigned int rx_mask;
};

View File

@ -709,7 +709,7 @@ static int __maybe_unused rt1308_dev_resume(struct device *dev)
struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev);
unsigned long time;
if (!rt1308->hw_init)
if (!rt1308->first_hw_init)
return 0;
if (!slave->unattach_request)

View File

@ -701,7 +701,7 @@ static int __maybe_unused rt1316_dev_resume(struct device *dev)
struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(dev);
unsigned long time;
if (!rt1316->hw_init)
if (!rt1316->first_hw_init)
return 0;
if (!slave->unattach_request)

View File

@ -3388,44 +3388,30 @@ static int rt5645_probe(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
int ret = 0;
rt5645->component = component;
switch (rt5645->codec_type) {
case CODEC_TYPE_RT5645:
ret = snd_soc_dapm_new_controls(dapm,
snd_soc_dapm_new_controls(dapm,
rt5645_specific_dapm_widgets,
ARRAY_SIZE(rt5645_specific_dapm_widgets));
if (ret < 0)
goto exit;
ret = snd_soc_dapm_add_routes(dapm,
snd_soc_dapm_add_routes(dapm,
rt5645_specific_dapm_routes,
ARRAY_SIZE(rt5645_specific_dapm_routes));
if (ret < 0)
goto exit;
if (rt5645->v_id < 3) {
ret = snd_soc_dapm_add_routes(dapm,
snd_soc_dapm_add_routes(dapm,
rt5645_old_dapm_routes,
ARRAY_SIZE(rt5645_old_dapm_routes));
if (ret < 0)
goto exit;
}
break;
case CODEC_TYPE_RT5650:
ret = snd_soc_dapm_new_controls(dapm,
snd_soc_dapm_new_controls(dapm,
rt5650_specific_dapm_widgets,
ARRAY_SIZE(rt5650_specific_dapm_widgets));
if (ret < 0)
goto exit;
ret = snd_soc_dapm_add_routes(dapm,
snd_soc_dapm_add_routes(dapm,
rt5650_specific_dapm_routes,
ARRAY_SIZE(rt5650_specific_dapm_routes));
if (ret < 0)
goto exit;
break;
}
@ -3433,17 +3419,9 @@ static int rt5645_probe(struct snd_soc_component *component)
/* for JD function */
if (rt5645->pdata.jd_mode) {
ret = snd_soc_dapm_force_enable_pin(dapm, "JD Power");
if (ret < 0)
goto exit;
ret = snd_soc_dapm_force_enable_pin(dapm, "LDO2");
if (ret < 0)
goto exit;
ret = snd_soc_dapm_sync(dapm);
if (ret < 0)
goto exit;
snd_soc_dapm_force_enable_pin(dapm, "JD Power");
snd_soc_dapm_force_enable_pin(dapm, "LDO2");
snd_soc_dapm_sync(dapm);
}
if (rt5645->pdata.long_name)
@ -3454,14 +3432,9 @@ static int rt5645_probe(struct snd_soc_component *component)
GFP_KERNEL);
if (!rt5645->eq_param)
ret = -ENOMEM;
exit:
/*
* If there was an error above, everything will be cleaned up by the
* caller if we return an error here. This will be done with a later
* call to rt5645_remove().
*/
return ret;
return -ENOMEM;
return 0;
}
static void rt5645_remove(struct snd_soc_component *component)

View File

@ -344,6 +344,8 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap,
rt5682->sdw_regmap = regmap;
rt5682->is_sdw = true;
mutex_init(&rt5682->disable_irq_lock);
rt5682->regmap = devm_regmap_init(dev, NULL, dev,
&rt5682_sdw_indirect_regmap);
if (IS_ERR(rt5682->regmap)) {
@ -378,6 +380,8 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
int ret = 0, loop = 10;
unsigned int val;
rt5682->disable_irq = false;
if (rt5682->hw_init)
return 0;
@ -400,6 +404,11 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
pm_runtime_get_noresume(&slave->dev);
if (rt5682->first_hw_init) {
regcache_cache_only(rt5682->regmap, false);
regcache_cache_bypass(rt5682->regmap, true);
}
while (loop > 0) {
regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
if (val == DEVICE_ID)
@ -408,14 +417,11 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
usleep_range(30000, 30005);
loop--;
}
if (val != DEVICE_ID) {
dev_err(dev, "Device with ID register %x is not rt5682\n", val);
return -ENODEV;
}
if (rt5682->first_hw_init) {
regcache_cache_only(rt5682->regmap, false);
regcache_cache_bypass(rt5682->regmap, true);
ret = -ENODEV;
goto err_nodev;
}
rt5682_calibrate(rt5682);
@ -486,10 +492,11 @@ reinit:
rt5682->hw_init = true;
rt5682->first_hw_init = true;
err_nodev:
pm_runtime_mark_last_busy(&slave->dev);
pm_runtime_put_autosuspend(&slave->dev);
dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
dev_dbg(&slave->dev, "%s hw_init complete: %d\n", __func__, ret);
return ret;
}
@ -676,10 +683,12 @@ static int rt5682_interrupt_callback(struct sdw_slave *slave,
dev_dbg(&slave->dev,
"%s control_port_stat=%x", __func__, status->control_port);
if (status->control_port & 0x4) {
mutex_lock(&rt5682->disable_irq_lock);
if (status->control_port & 0x4 && !rt5682->disable_irq) {
mod_delayed_work(system_power_efficient_wq,
&rt5682->jack_detect_work, msecs_to_jiffies(rt5682->irq_work_delay_time));
}
mutex_unlock(&rt5682->disable_irq_lock);
return 0;
}
@ -737,13 +746,41 @@ static int __maybe_unused rt5682_dev_suspend(struct device *dev)
return 0;
}
static int __maybe_unused rt5682_dev_system_suspend(struct device *dev)
{
struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
struct sdw_slave *slave = dev_to_sdw_dev(dev);
int ret;
if (!rt5682->hw_init)
return 0;
/*
* prevent new interrupts from being handled after the
* deferred work completes and before the parent disables
* interrupts on the link
*/
mutex_lock(&rt5682->disable_irq_lock);
rt5682->disable_irq = true;
ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1,
SDW_SCP_INT1_IMPL_DEF, 0);
mutex_unlock(&rt5682->disable_irq_lock);
if (ret < 0) {
/* log but don't prevent suspend from happening */
dev_dbg(&slave->dev, "%s: could not disable imp-def interrupts\n:", __func__);
}
return rt5682_dev_suspend(dev);
}
static int __maybe_unused rt5682_dev_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
unsigned long time;
if (!rt5682->hw_init)
if (!rt5682->first_hw_init)
return 0;
if (!slave->unattach_request)
@ -765,7 +802,7 @@ regmap_sync:
}
static const struct dev_pm_ops rt5682_pm = {
SET_SYSTEM_SLEEP_PM_OPS(rt5682_dev_suspend, rt5682_dev_resume)
SET_SYSTEM_SLEEP_PM_OPS(rt5682_dev_system_suspend, rt5682_dev_resume)
SET_RUNTIME_PM_OPS(rt5682_dev_suspend, rt5682_dev_resume, NULL)
};

View File

@ -1415,6 +1415,8 @@ struct rt5682_priv {
struct regulator_bulk_data supplies[RT5682_NUM_SUPPLIES];
struct delayed_work jack_detect_work;
struct delayed_work jd_check_work;
struct mutex disable_irq_lock; /* imp-def irq lock protection */
bool disable_irq;
struct mutex calibrate_mutex;
struct sdw_slave *slave;
enum sdw_slave_status status;

View File

@ -418,10 +418,12 @@ static int rt700_interrupt_callback(struct sdw_slave *slave,
dev_dbg(&slave->dev,
"%s control_port_stat=%x", __func__, status->control_port);
if (status->control_port & 0x4) {
mutex_lock(&rt700->disable_irq_lock);
if (status->control_port & 0x4 && !rt700->disable_irq) {
mod_delayed_work(system_power_efficient_wq,
&rt700->jack_detect_work, msecs_to_jiffies(250));
}
mutex_unlock(&rt700->disable_irq_lock);
return 0;
}
@ -490,6 +492,34 @@ static int __maybe_unused rt700_dev_suspend(struct device *dev)
return 0;
}
static int __maybe_unused rt700_dev_system_suspend(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt700_priv *rt700 = dev_get_drvdata(dev);
int ret;
if (!rt700->hw_init)
return 0;
/*
* prevent new interrupts from being handled after the
* deferred work completes and before the parent disables
* interrupts on the link
*/
mutex_lock(&rt700->disable_irq_lock);
rt700->disable_irq = true;
ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1,
SDW_SCP_INT1_IMPL_DEF, 0);
mutex_unlock(&rt700->disable_irq_lock);
if (ret < 0) {
/* log but don't prevent suspend from happening */
dev_dbg(&slave->dev, "%s: could not disable imp-def interrupts\n:", __func__);
}
return rt700_dev_suspend(dev);
}
#define RT700_PROBE_TIMEOUT 5000
static int __maybe_unused rt700_dev_resume(struct device *dev)
@ -498,7 +528,7 @@ static int __maybe_unused rt700_dev_resume(struct device *dev)
struct rt700_priv *rt700 = dev_get_drvdata(dev);
unsigned long time;
if (!rt700->hw_init)
if (!rt700->first_hw_init)
return 0;
if (!slave->unattach_request)
@ -521,7 +551,7 @@ regmap_sync:
}
static const struct dev_pm_ops rt700_pm = {
SET_SYSTEM_SLEEP_PM_OPS(rt700_dev_suspend, rt700_dev_resume)
SET_SYSTEM_SLEEP_PM_OPS(rt700_dev_system_suspend, rt700_dev_resume)
SET_RUNTIME_PM_OPS(rt700_dev_suspend, rt700_dev_resume, NULL)
};

View File

@ -1112,6 +1112,8 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap,
rt700->sdw_regmap = sdw_regmap;
rt700->regmap = regmap;
mutex_init(&rt700->disable_irq_lock);
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@ -1133,6 +1135,8 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave)
{
struct rt700_priv *rt700 = dev_get_drvdata(dev);
rt700->disable_irq = false;
if (rt700->hw_init)
return 0;

View File

@ -23,6 +23,8 @@ struct rt700_priv {
struct delayed_work jack_detect_work;
struct delayed_work jack_btn_check_work;
int jack_type;
struct mutex disable_irq_lock; /* imp-def irq lock protection */
bool disable_irq;
};
struct sdw_stream_data {

View File

@ -75,6 +75,16 @@ static bool rt711_sdca_mbq_readable_register(struct device *dev, unsigned int re
case 0x5b00000 ... 0x5b000ff:
case 0x5f00000 ... 0x5f000ff:
case 0x6100000 ... 0x61000ff:
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_L):
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_R):
case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_L):
case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_R):
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_L):
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_R):
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_L):
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_R):
case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_L):
case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_R):
return true;
default:
return false;
@ -246,6 +256,15 @@ static int rt711_sdca_interrupt_callback(struct sdw_slave *slave,
scp_sdca_stat2 = rt711->scp_sdca_stat2;
}
/*
* The critical section below intentionally protects a rather large piece of code.
* We don't want to allow the system suspend to disable an interrupt while we are
* processing it, which could be problematic given the quirky SoundWire interrupt
* scheme. We do want however to prevent new workqueues from being scheduled if
* the disable_irq flag was set during system suspend.
*/
mutex_lock(&rt711->disable_irq_lock);
ret = sdw_read_no_pm(rt711->slave, SDW_SCP_SDCA_INT1);
if (ret < 0)
goto io_error;
@ -304,13 +323,16 @@ static int rt711_sdca_interrupt_callback(struct sdw_slave *slave,
"%s scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__,
rt711->scp_sdca_stat1, rt711->scp_sdca_stat2);
if (status->sdca_cascade)
if (status->sdca_cascade && !rt711->disable_irq)
mod_delayed_work(system_power_efficient_wq,
&rt711->jack_detect_work, msecs_to_jiffies(30));
mutex_unlock(&rt711->disable_irq_lock);
return 0;
io_error:
mutex_unlock(&rt711->disable_irq_lock);
pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
return ret;
}
@ -372,6 +394,36 @@ static int __maybe_unused rt711_sdca_dev_suspend(struct device *dev)
return 0;
}
static int __maybe_unused rt711_sdca_dev_system_suspend(struct device *dev)
{
struct rt711_sdca_priv *rt711_sdca = dev_get_drvdata(dev);
struct sdw_slave *slave = dev_to_sdw_dev(dev);
int ret1, ret2;
if (!rt711_sdca->hw_init)
return 0;
/*
* prevent new interrupts from being handled after the
* deferred work completes and before the parent disables
* interrupts on the link
*/
mutex_lock(&rt711_sdca->disable_irq_lock);
rt711_sdca->disable_irq = true;
ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
SDW_SCP_SDCA_INTMASK_SDCA_0, 0);
ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
SDW_SCP_SDCA_INTMASK_SDCA_8, 0);
mutex_unlock(&rt711_sdca->disable_irq_lock);
if (ret1 < 0 || ret2 < 0) {
/* log but don't prevent suspend from happening */
dev_dbg(&slave->dev, "%s: could not disable SDCA interrupts\n:", __func__);
}
return rt711_sdca_dev_suspend(dev);
}
#define RT711_PROBE_TIMEOUT 5000
static int __maybe_unused rt711_sdca_dev_resume(struct device *dev)
@ -380,7 +432,7 @@ static int __maybe_unused rt711_sdca_dev_resume(struct device *dev)
struct rt711_sdca_priv *rt711 = dev_get_drvdata(dev);
unsigned long time;
if (!rt711->hw_init)
if (!rt711->first_hw_init)
return 0;
if (!slave->unattach_request)
@ -403,7 +455,7 @@ regmap_sync:
}
static const struct dev_pm_ops rt711_sdca_pm = {
SET_SYSTEM_SLEEP_PM_OPS(rt711_sdca_dev_suspend, rt711_sdca_dev_resume)
SET_SYSTEM_SLEEP_PM_OPS(rt711_sdca_dev_system_suspend, rt711_sdca_dev_resume)
SET_RUNTIME_PM_OPS(rt711_sdca_dev_suspend, rt711_sdca_dev_resume, NULL)
};

View File

@ -1411,6 +1411,8 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap,
rt711->regmap = regmap;
rt711->mbq_regmap = mbq_regmap;
mutex_init(&rt711->disable_irq_lock);
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@ -1494,12 +1496,16 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave)
int ret = 0;
unsigned int val;
rt711->disable_irq = false;
if (rt711->hw_init)
return 0;
if (rt711->first_hw_init) {
regcache_cache_only(rt711->regmap, false);
regcache_cache_bypass(rt711->regmap, true);
regcache_cache_only(rt711->mbq_regmap, false);
regcache_cache_bypass(rt711->mbq_regmap, true);
} else {
/*
* PM runtime is only enabled when a Slave reports as Attached
@ -1565,6 +1571,8 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave)
if (rt711->first_hw_init) {
regcache_cache_bypass(rt711->regmap, false);
regcache_mark_dirty(rt711->regmap);
regcache_cache_bypass(rt711->mbq_regmap, false);
regcache_mark_dirty(rt711->mbq_regmap);
} else
rt711->first_hw_init = true;

View File

@ -27,6 +27,8 @@ struct rt711_sdca_priv {
struct delayed_work jack_detect_work;
struct delayed_work jack_btn_check_work;
struct mutex calibrate_mutex; /* for headset calibration */
struct mutex disable_irq_lock; /* SDCA irq lock protection */
bool disable_irq;
int jack_type, jd_src;
unsigned int scp_sdca_stat1, scp_sdca_stat2;
int hw_ver;

View File

@ -423,10 +423,12 @@ static int rt711_interrupt_callback(struct sdw_slave *slave,
dev_dbg(&slave->dev,
"%s control_port_stat=%x", __func__, status->control_port);
if (status->control_port & 0x4) {
mutex_lock(&rt711->disable_irq_lock);
if (status->control_port & 0x4 && !rt711->disable_irq) {
mod_delayed_work(system_power_efficient_wq,
&rt711->jack_detect_work, msecs_to_jiffies(250));
}
mutex_unlock(&rt711->disable_irq_lock);
return 0;
}
@ -493,6 +495,34 @@ static int __maybe_unused rt711_dev_suspend(struct device *dev)
return 0;
}
static int __maybe_unused rt711_dev_system_suspend(struct device *dev)
{
struct rt711_priv *rt711 = dev_get_drvdata(dev);
struct sdw_slave *slave = dev_to_sdw_dev(dev);
int ret;
if (!rt711->hw_init)
return 0;
/*
* prevent new interrupts from being handled after the
* deferred work completes and before the parent disables
* interrupts on the link
*/
mutex_lock(&rt711->disable_irq_lock);
rt711->disable_irq = true;
ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1,
SDW_SCP_INT1_IMPL_DEF, 0);
mutex_unlock(&rt711->disable_irq_lock);
if (ret < 0) {
/* log but don't prevent suspend from happening */
dev_dbg(&slave->dev, "%s: could not disable imp-def interrupts\n:", __func__);
}
return rt711_dev_suspend(dev);
}
#define RT711_PROBE_TIMEOUT 5000
static int __maybe_unused rt711_dev_resume(struct device *dev)
@ -501,7 +531,7 @@ static int __maybe_unused rt711_dev_resume(struct device *dev)
struct rt711_priv *rt711 = dev_get_drvdata(dev);
unsigned long time;
if (!rt711->hw_init)
if (!rt711->first_hw_init)
return 0;
if (!slave->unattach_request)
@ -524,7 +554,7 @@ regmap_sync:
}
static const struct dev_pm_ops rt711_pm = {
SET_SYSTEM_SLEEP_PM_OPS(rt711_dev_suspend, rt711_dev_resume)
SET_SYSTEM_SLEEP_PM_OPS(rt711_dev_system_suspend, rt711_dev_resume)
SET_RUNTIME_PM_OPS(rt711_dev_suspend, rt711_dev_resume, NULL)
};

View File

@ -1166,6 +1166,8 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap,
rt711->sdw_regmap = sdw_regmap;
rt711->regmap = regmap;
mutex_init(&rt711->disable_irq_lock);
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@ -1190,6 +1192,8 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave)
{
struct rt711_priv *rt711 = dev_get_drvdata(dev);
rt711->disable_irq = false;
if (rt711->hw_init)
return 0;

View File

@ -25,6 +25,8 @@ struct rt711_priv {
struct work_struct calibration_work;
struct mutex calibrate_mutex; /* for headset calibration */
int jack_type, jd_src;
struct mutex disable_irq_lock; /* imp-def irq lock protection */
bool disable_irq;
};
struct sdw_stream_data {

View File

@ -70,6 +70,7 @@ static bool rt715_sdca_mbq_readable_register(struct device *dev, unsigned int re
case 0x2000036:
case 0x2000037:
case 0x2000039:
case 0x2000044:
case 0x6100000:
return true;
default:
@ -224,7 +225,7 @@ static int __maybe_unused rt715_dev_resume(struct device *dev)
struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev);
unsigned long time;
if (!rt715->hw_init)
if (!rt715->first_hw_init)
return 0;
if (!slave->unattach_request)

View File

@ -113,6 +113,7 @@ static const struct reg_default rt715_mbq_reg_defaults_sdca[] = {
{ 0x2000036, 0x0000 },
{ 0x2000037, 0x0000 },
{ 0x2000039, 0xaa81 },
{ 0x2000044, 0x0202 },
{ 0x6100000, 0x0100 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
RT715_SDCA_FU_VOL_CTRL, CH_01), 0x00 },

View File

@ -997,7 +997,7 @@ int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap,
* HW init will be performed when device reports present
*/
rt715->hw_init = false;
rt715->first_init = false;
rt715->first_hw_init = false;
ret = devm_snd_soc_register_component(dev,
&soc_codec_dev_rt715_sdca,
@ -1018,7 +1018,7 @@ int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave)
/*
* PM runtime is only enabled when a Slave reports as Attached
*/
if (!rt715->first_init) {
if (!rt715->first_hw_init) {
/* set autosuspend parameters */
pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
pm_runtime_use_autosuspend(&slave->dev);
@ -1031,7 +1031,7 @@ int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave)
pm_runtime_enable(&slave->dev);
rt715->first_init = true;
rt715->first_hw_init = true;
}
pm_runtime_get_noresume(&slave->dev);
@ -1054,6 +1054,9 @@ int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave)
rt715_sdca_index_update_bits(rt715, RT715_VENDOR_REG,
RT715_REV_1, 0x40, 0x40);
}
/* DFLL Calibration trigger */
rt715_sdca_index_update_bits(rt715, RT715_VENDOR_REG,
RT715_DFLL_VAD, 0x1, 0x1);
/* trigger mode = VAD enable */
regmap_write(rt715->regmap,
SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,

View File

@ -27,7 +27,7 @@ struct rt715_sdca_priv {
enum sdw_slave_status status;
struct sdw_bus_params params;
bool hw_init;
bool first_init;
bool first_hw_init;
int l_is_unmute;
int r_is_unmute;
int hw_sdw_ver;
@ -81,6 +81,7 @@ struct rt715_sdca_kcontrol_private {
#define RT715_AD_FUNC_EN 0x36
#define RT715_REV_1 0x37
#define RT715_SDW_INPUT_SEL 0x39
#define RT715_DFLL_VAD 0x44
#define RT715_EXT_DMIC_CLK_CTRL2 0x54
/* Index (NID:61h) */

View File

@ -541,7 +541,7 @@ static int __maybe_unused rt715_dev_resume(struct device *dev)
struct rt715_priv *rt715 = dev_get_drvdata(dev);
unsigned long time;
if (!rt715->hw_init)
if (!rt715->first_hw_init)
return 0;
if (!slave->unattach_request)

View File

@ -1375,14 +1375,27 @@ static int fsl_spdif_probe(struct platform_device *pdev)
&spdif_priv->cpu_dai_drv, 1);
if (ret) {
dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
return ret;
goto err_pm_disable;
}
ret = imx_pcm_dma_init(pdev, IMX_SPDIF_DMABUF_SIZE);
if (ret && ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret);
if (ret) {
dev_err_probe(&pdev->dev, ret, "imx_pcm_dma_init failed\n");
goto err_pm_disable;
}
return ret;
err_pm_disable:
pm_runtime_disable(&pdev->dev);
return ret;
}
static int fsl_spdif_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
return 0;
}
#ifdef CONFIG_PM
@ -1391,6 +1404,9 @@ static int fsl_spdif_runtime_suspend(struct device *dev)
struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev);
int i;
/* Disable all the interrupts */
regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SIE, 0xffffff, 0);
regmap_read(spdif_priv->regmap, REG_SPDIF_SRPC,
&spdif_priv->regcache_srpc);
regcache_cache_only(spdif_priv->regmap, true);
@ -1487,6 +1503,7 @@ static struct platform_driver fsl_spdif_driver = {
.pm = &fsl_spdif_pm,
},
.probe = fsl_spdif_probe,
.remove = fsl_spdif_remove,
};
module_platform_driver(fsl_spdif_driver);