cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cs5535audio_pm.c (2832B)


      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
     18static 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
     44static 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
     62static 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
    100SIMPLE_DEV_PM_OPS(snd_cs5535audio_pm, snd_cs5535audio_suspend, snd_cs5535audio_resume);