mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-09 23:39:18 +00:00
Merge remote-tracking branch 'asoc/for-5.13' into asoc-linus
This commit is contained in:
commit
c073a58a7e
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 = {
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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 },
|
||||
|
@ -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,
|
||||
|
@ -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) */
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user