1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Power management for audio on multifunction CS5535 companion device 4 * Copyright (C) Jaya Kumar 5 */ 6 7 #include <linux/init.h> 8 #include <linux/pci.h> 9 #include <linux/delay.h> 10 #include <sound/core.h> 11 #include <sound/control.h> 12 #include <sound/initval.h> 13 #include <sound/asoundef.h> 14 #include <sound/pcm.h> 15 #include <sound/ac97_codec.h> 16 #include "cs5535audio.h" 17 18 static void snd_cs5535audio_stop_hardware(struct cs5535audio *cs5535au) 19 { 20 /* 21 we depend on snd_ac97_suspend to tell the 22 AC97 codec to shutdown. the amd spec suggests 23 that the LNK_SHUTDOWN be done at the same time 24 that the codec power-down is issued. instead, 25 we do it just after rather than at the same 26 time. excluding codec specific build_ops->suspend 27 ac97 powerdown hits: 28 0x8000 EAPD 29 0x4000 Headphone amplifier 30 0x0300 ADC & DAC 31 0x0400 Analog Mixer powerdown (Vref on) 32 I am not sure if this is the best that we can do. 33 The remainder to be investigated are: 34 - analog mixer (vref off) 0x0800 35 - AC-link powerdown 0x1000 36 - codec internal clock 0x2000 37 */ 38 39 /* set LNK_SHUTDOWN to shutdown AC link */ 40 cs_writel(cs5535au, ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_SHUTDOWN); 41 42 } 43 44 static int __maybe_unused snd_cs5535audio_suspend(struct device *dev) 45 { 46 struct snd_card *card = dev_get_drvdata(dev); 47 struct cs5535audio *cs5535au = card->private_data; 48 int i; 49 50 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 51 snd_ac97_suspend(cs5535au->ac97); 52 for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) { 53 struct cs5535audio_dma *dma = &cs5535au->dmas[i]; 54 if (dma && dma->substream) 55 dma->saved_prd = dma->ops->read_prd(cs5535au); 56 } 57 /* save important regs, then disable aclink in hw */ 58 snd_cs5535audio_stop_hardware(cs5535au); 59 return 0; 60 } 61 62 static int __maybe_unused snd_cs5535audio_resume(struct device *dev) 63 { 64 struct snd_card *card = dev_get_drvdata(dev); 65 struct cs5535audio *cs5535au = card->private_data; 66 u32 tmp; 67 int timeout; 68 int i; 69 70 /* set LNK_WRM_RST to reset AC link */ 71 cs_writel(cs5535au, ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_WRM_RST); 72 73 timeout = 50; 74 do { 75 tmp = cs_readl(cs5535au, ACC_CODEC_STATUS); 76 if (tmp & PRM_RDY_STS) 77 break; 78 udelay(1); 79 } while (--timeout); 80 81 if (!timeout) 82 dev_err(cs5535au->card->dev, "Failure getting AC Link ready\n"); 83 84 /* set up rate regs, dma. actual initiation is done in trig */ 85 for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) { 86 struct cs5535audio_dma *dma = &cs5535au->dmas[i]; 87 if (dma && dma->substream) { 88 dma->substream->ops->prepare(dma->substream); 89 dma->ops->setup_prd(cs5535au, dma->saved_prd); 90 } 91 } 92 93 /* we depend on ac97 to perform the codec power up */ 94 snd_ac97_resume(cs5535au->ac97); 95 snd_power_change_state(card, SNDRV_CTL_POWER_D0); 96 97 return 0; 98 } 99 100 SIMPLE_DEV_PM_OPS(snd_cs5535audio_pm, snd_cs5535audio_suspend, snd_cs5535audio_resume); 101
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.