diff options
Diffstat (limited to 'sound/soc/fsl/fsl_sai.c')
-rw-r--r-- | sound/soc/fsl/fsl_sai.c | 59 |
1 files changed, 56 insertions, 3 deletions
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index a18fd92c4..08b460ba0 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -27,13 +27,13 @@ #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\ FSL_SAI_CSR_FEIE) -static u32 fsl_sai_rates[] = { +static const unsigned int fsl_sai_rates[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000 }; -static struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = { +static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = { .count = ARRAY_SIZE(fsl_sai_rates), .list = fsl_sai_rates, }; @@ -454,7 +454,8 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx. * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx. */ - regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0); + regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, + sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0); regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0); @@ -504,6 +505,24 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); regmap_update_bits(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); + + /* + * For sai master mode, after several open/close sai, + * there will be no frame clock, and can't recover + * anymore. Add software reset to fix this issue. + * This is a hardware bug, and will be fix in the + * next sai version. + */ + if (!sai->is_slave_mode) { + /* Software Reset for both Tx and Rx */ + regmap_write(sai->regmap, + FSL_SAI_TCSR, FSL_SAI_CSR_SR); + regmap_write(sai->regmap, + FSL_SAI_RCSR, FSL_SAI_CSR_SR); + /* Clear SR bit to finish the reset */ + regmap_write(sai->regmap, FSL_SAI_TCSR, 0); + regmap_write(sai->regmap, FSL_SAI_RCSR, 0); + } } break; default: @@ -637,6 +656,8 @@ static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg) static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { + case FSL_SAI_TCSR: + case FSL_SAI_RCSR: case FSL_SAI_TFR: case FSL_SAI_RFR: case FSL_SAI_TDR: @@ -681,6 +702,7 @@ static const struct regmap_config fsl_sai_regmap_config = { .readable_reg = fsl_sai_readable_reg, .volatile_reg = fsl_sai_volatile_reg, .writeable_reg = fsl_sai_writeable_reg, + .cache_type = REGCACHE_FLAT, }; static int fsl_sai_probe(struct platform_device *pdev) @@ -801,11 +823,42 @@ static const struct of_device_id fsl_sai_ids[] = { { .compatible = "fsl,imx6sx-sai", }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, fsl_sai_ids); + +#ifdef CONFIG_PM_SLEEP +static int fsl_sai_suspend(struct device *dev) +{ + struct fsl_sai *sai = dev_get_drvdata(dev); + + regcache_cache_only(sai->regmap, true); + regcache_mark_dirty(sai->regmap); + + return 0; +} + +static int fsl_sai_resume(struct device *dev) +{ + struct fsl_sai *sai = dev_get_drvdata(dev); + + regcache_cache_only(sai->regmap, false); + regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR); + regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR); + msleep(1); + regmap_write(sai->regmap, FSL_SAI_TCSR, 0); + regmap_write(sai->regmap, FSL_SAI_RCSR, 0); + return regcache_sync(sai->regmap); +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops fsl_sai_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(fsl_sai_suspend, fsl_sai_resume) +}; static struct platform_driver fsl_sai_driver = { .probe = fsl_sai_probe, .driver = { .name = "fsl-sai", + .pm = &fsl_sai_pm_ops, .of_match_table = fsl_sai_ids, }, }; |