Path: blob/master/sound/pci/cs5535audio/cs5535audio_pm.c
26439 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Power management for audio on multifunction CS5535 companion device3* Copyright (C) Jaya Kumar4*/56#include <linux/init.h>7#include <linux/pci.h>8#include <linux/delay.h>9#include <sound/core.h>10#include <sound/control.h>11#include <sound/initval.h>12#include <sound/asoundef.h>13#include <sound/pcm.h>14#include <sound/ac97_codec.h>15#include "cs5535audio.h"1617static void snd_cs5535audio_stop_hardware(struct cs5535audio *cs5535au)18{19/*20we depend on snd_ac97_suspend to tell the21AC97 codec to shutdown. the amd spec suggests22that the LNK_SHUTDOWN be done at the same time23that the codec power-down is issued. instead,24we do it just after rather than at the same25time. excluding codec specific build_ops->suspend26ac97 powerdown hits:270x8000 EAPD280x4000 Headphone amplifier290x0300 ADC & DAC300x0400 Analog Mixer powerdown (Vref on)31I am not sure if this is the best that we can do.32The remainder to be investigated are:33- analog mixer (vref off) 0x080034- AC-link powerdown 0x100035- codec internal clock 0x200036*/3738/* set LNK_SHUTDOWN to shutdown AC link */39cs_writel(cs5535au, ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_SHUTDOWN);4041}4243static int __maybe_unused snd_cs5535audio_suspend(struct device *dev)44{45struct snd_card *card = dev_get_drvdata(dev);46struct cs5535audio *cs5535au = card->private_data;47int i;4849snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);50snd_ac97_suspend(cs5535au->ac97);51for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) {52struct cs5535audio_dma *dma = &cs5535au->dmas[i];53if (dma && dma->substream)54dma->saved_prd = dma->ops->read_prd(cs5535au);55}56/* save important regs, then disable aclink in hw */57snd_cs5535audio_stop_hardware(cs5535au);58return 0;59}6061static int __maybe_unused snd_cs5535audio_resume(struct device *dev)62{63struct snd_card *card = dev_get_drvdata(dev);64struct cs5535audio *cs5535au = card->private_data;65u32 tmp;66int timeout;67int i;6869/* set LNK_WRM_RST to reset AC link */70cs_writel(cs5535au, ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_WRM_RST);7172timeout = 50;73do {74tmp = cs_readl(cs5535au, ACC_CODEC_STATUS);75if (tmp & PRM_RDY_STS)76break;77udelay(1);78} while (--timeout);7980if (!timeout)81dev_err(cs5535au->card->dev, "Failure getting AC Link ready\n");8283/* set up rate regs, dma. actual initiation is done in trig */84for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) {85struct cs5535audio_dma *dma = &cs5535au->dmas[i];86if (dma && dma->substream) {87dma->substream->ops->prepare(dma->substream);88dma->ops->setup_prd(cs5535au, dma->saved_prd);89}90}9192/* we depend on ac97 to perform the codec power up */93snd_ac97_resume(cs5535au->ac97);94snd_power_change_state(card, SNDRV_CTL_POWER_D0);9596return 0;97}9899SIMPLE_DEV_PM_OPS(snd_cs5535audio_pm, snd_cs5535audio_suspend, snd_cs5535audio_resume);100101102