diff options
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r-- | sound/soc/codecs/twl4030.c | 59 | ||||
-rw-r--r-- | sound/soc/codecs/twl4030.h | 1 | ||||
-rw-r--r-- | sound/soc/codecs/wm9705.c | 37 |
3 files changed, 96 insertions, 1 deletions
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 97738e2ece04..bfda7a88e825 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -122,6 +122,9 @@ struct twl4030_priv { unsigned int bypass_state; unsigned int codec_powered; unsigned int codec_muted; + + struct snd_pcm_substream *master_substream; + struct snd_pcm_substream *slave_substream; }; /* @@ -1217,6 +1220,50 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec, return 0; } +static int twl4030_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + struct twl4030_priv *twl4030 = codec->private_data; + + /* If we already have a playback or capture going then constrain + * this substream to match it. + */ + if (twl4030->master_substream) { + struct snd_pcm_runtime *master_runtime; + master_runtime = twl4030->master_substream->runtime; + + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, + master_runtime->rate, + master_runtime->rate); + + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + master_runtime->sample_bits, + master_runtime->sample_bits); + + twl4030->slave_substream = substream; + } else + twl4030->master_substream = substream; + + return 0; +} + +static void twl4030_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + struct twl4030_priv *twl4030 = codec->private_data; + + if (twl4030->master_substream == substream) + twl4030->master_substream = twl4030->slave_substream; + + twl4030->slave_substream = NULL; +} + static int twl4030_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -1224,8 +1271,13 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; + struct twl4030_priv *twl4030 = codec->private_data; u8 mode, old_mode, format, old_format; + if (substream == twl4030->slave_substream) + /* Ignoring hw_params for slave substream */ + return 0; + /* bit rate */ old_mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ; @@ -1259,6 +1311,9 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, case 48000: mode |= TWL4030_APLL_RATE_48000; break; + case 96000: + mode |= TWL4030_APLL_RATE_96000; + break; default: printk(KERN_ERR "TWL4030 hw params: unknown rate %d\n", params_rate(params)); @@ -1384,6 +1439,8 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, #define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) static struct snd_soc_dai_ops twl4030_dai_ops = { + .startup = twl4030_startup, + .shutdown = twl4030_shutdown, .hw_params = twl4030_hw_params, .set_sysclk = twl4030_set_dai_sysclk, .set_fmt = twl4030_set_dai_fmt, @@ -1395,7 +1452,7 @@ struct snd_soc_dai twl4030_dai = { .stream_name = "Playback", .channels_min = 2, .channels_max = 2, - .rates = TWL4030_RATES, + .rates = TWL4030_RATES | SNDRV_PCM_RATE_96000, .formats = TWL4030_FORMATS,}, .capture = { .stream_name = "Capture", diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h index 33dbb144dad1..cb63765db1df 100644 --- a/sound/soc/codecs/twl4030.h +++ b/sound/soc/codecs/twl4030.h @@ -109,6 +109,7 @@ #define TWL4030_APLL_RATE_32000 0x80 #define TWL4030_APLL_RATE_44100 0x90 #define TWL4030_APLL_RATE_48000 0xA0 +#define TWL4030_APLL_RATE_96000 0xE0 #define TWL4030_SEL_16K 0x04 #define TWL4030_CODECPDZ 0x02 #define TWL4030_OPT_MODE 0x01 diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 3265817c5c26..6e23a81dba78 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -317,6 +317,41 @@ static int wm9705_reset(struct snd_soc_codec *codec) return -EIO; } +#ifdef CONFIG_PM +static int wm9705_soc_suspend(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + soc_ac97_ops.write(codec->ac97, AC97_POWERDOWN, 0xffff); + + return 0; +} + +static int wm9705_soc_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + int i, ret; + u16 *cache = codec->reg_cache; + + ret = wm9705_reset(codec); + if (ret < 0) { + printk(KERN_ERR "could not reset AC97 codec\n"); + return ret; + } + + for (i = 2; i < ARRAY_SIZE(wm9705_reg) << 1; i += 2) { + soc_ac97_ops.write(codec->ac97, i, cache[i>>1]); + } + + return 0; +} +#else +#define wm9705_soc_suspend NULL +#define wm9705_soc_resume NULL +#endif + static int wm9705_soc_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); @@ -407,6 +442,8 @@ static int wm9705_soc_remove(struct platform_device *pdev) struct snd_soc_codec_device soc_codec_dev_wm9705 = { .probe = wm9705_soc_probe, .remove = wm9705_soc_remove, + .suspend = wm9705_soc_suspend, + .resume = wm9705_soc_resume, }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm9705); |