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

pxa2xx-ac97.c (6788B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * linux/sound/pxa2xx-ac97.c -- AC97 support for the Intel PXA2xx chip.
      4 *
      5 * Author:	Nicolas Pitre
      6 * Created:	Dec 02, 2004
      7 * Copyright:	MontaVista Software Inc.
      8 */
      9
     10#include <linux/init.h>
     11#include <linux/io.h>
     12#include <linux/module.h>
     13#include <linux/platform_device.h>
     14#include <linux/dmaengine.h>
     15#include <linux/dma-mapping.h>
     16
     17#include <sound/core.h>
     18#include <sound/pcm.h>
     19#include <sound/ac97_codec.h>
     20#include <sound/initval.h>
     21#include <sound/pxa2xx-lib.h>
     22#include <sound/dmaengine_pcm.h>
     23
     24#include <linux/platform_data/asoc-pxa.h>
     25
     26static void pxa2xx_ac97_legacy_reset(struct snd_ac97 *ac97)
     27{
     28	if (!pxa2xx_ac97_try_cold_reset())
     29		pxa2xx_ac97_try_warm_reset();
     30
     31	pxa2xx_ac97_finish_reset();
     32}
     33
     34static unsigned short pxa2xx_ac97_legacy_read(struct snd_ac97 *ac97,
     35					      unsigned short reg)
     36{
     37	int ret;
     38
     39	ret = pxa2xx_ac97_read(ac97->num, reg);
     40	if (ret < 0)
     41		return 0;
     42	else
     43		return (unsigned short)(ret & 0xffff);
     44}
     45
     46static void pxa2xx_ac97_legacy_write(struct snd_ac97 *ac97,
     47				     unsigned short reg, unsigned short val)
     48{
     49	pxa2xx_ac97_write(ac97->num, reg, val);
     50}
     51
     52static const struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
     53	.read	= pxa2xx_ac97_legacy_read,
     54	.write	= pxa2xx_ac97_legacy_write,
     55	.reset	= pxa2xx_ac97_legacy_reset,
     56};
     57
     58static struct snd_pcm *pxa2xx_ac97_pcm;
     59static struct snd_ac97 *pxa2xx_ac97_ac97;
     60
     61static int pxa2xx_ac97_pcm_open(struct snd_pcm_substream *substream)
     62{
     63	struct snd_pcm_runtime *runtime = substream->runtime;
     64	pxa2xx_audio_ops_t *platform_ops;
     65	int ret, i;
     66
     67	ret = pxa2xx_pcm_open(substream);
     68	if (ret)
     69		return ret;
     70
     71	runtime->hw.channels_min = 2;
     72	runtime->hw.channels_max = 2;
     73
     74	i = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
     75		AC97_RATES_FRONT_DAC : AC97_RATES_ADC;
     76	runtime->hw.rates = pxa2xx_ac97_ac97->rates[i];
     77	snd_pcm_limit_hw_rates(runtime);
     78
     79	platform_ops = substream->pcm->card->dev->platform_data;
     80	if (platform_ops && platform_ops->startup) {
     81		ret = platform_ops->startup(substream, platform_ops->priv);
     82		if (ret < 0)
     83			pxa2xx_pcm_close(substream);
     84	}
     85
     86	return ret;
     87}
     88
     89static int pxa2xx_ac97_pcm_close(struct snd_pcm_substream *substream)
     90{
     91	pxa2xx_audio_ops_t *platform_ops;
     92
     93	platform_ops = substream->pcm->card->dev->platform_data;
     94	if (platform_ops && platform_ops->shutdown)
     95		platform_ops->shutdown(substream, platform_ops->priv);
     96
     97	return 0;
     98}
     99
    100static int pxa2xx_ac97_pcm_prepare(struct snd_pcm_substream *substream)
    101{
    102	struct snd_pcm_runtime *runtime = substream->runtime;
    103	int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
    104		  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
    105	int ret;
    106
    107	ret = pxa2xx_pcm_prepare(substream);
    108	if (ret < 0)
    109		return ret;
    110
    111	return snd_ac97_set_rate(pxa2xx_ac97_ac97, reg, runtime->rate);
    112}
    113
    114#ifdef CONFIG_PM_SLEEP
    115
    116static int pxa2xx_ac97_do_suspend(struct snd_card *card)
    117{
    118	pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
    119
    120	snd_power_change_state(card, SNDRV_CTL_POWER_D3cold);
    121	snd_ac97_suspend(pxa2xx_ac97_ac97);
    122	if (platform_ops && platform_ops->suspend)
    123		platform_ops->suspend(platform_ops->priv);
    124
    125	return pxa2xx_ac97_hw_suspend();
    126}
    127
    128static int pxa2xx_ac97_do_resume(struct snd_card *card)
    129{
    130	pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
    131	int rc;
    132
    133	rc = pxa2xx_ac97_hw_resume();
    134	if (rc)
    135		return rc;
    136
    137	if (platform_ops && platform_ops->resume)
    138		platform_ops->resume(platform_ops->priv);
    139	snd_ac97_resume(pxa2xx_ac97_ac97);
    140	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
    141
    142	return 0;
    143}
    144
    145static int pxa2xx_ac97_suspend(struct device *dev)
    146{
    147	struct snd_card *card = dev_get_drvdata(dev);
    148	int ret = 0;
    149
    150	if (card)
    151		ret = pxa2xx_ac97_do_suspend(card);
    152
    153	return ret;
    154}
    155
    156static int pxa2xx_ac97_resume(struct device *dev)
    157{
    158	struct snd_card *card = dev_get_drvdata(dev);
    159	int ret = 0;
    160
    161	if (card)
    162		ret = pxa2xx_ac97_do_resume(card);
    163
    164	return ret;
    165}
    166
    167static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_resume);
    168#endif
    169
    170static const struct snd_pcm_ops pxa2xx_ac97_pcm_ops = {
    171	.open		= pxa2xx_ac97_pcm_open,
    172	.close		= pxa2xx_ac97_pcm_close,
    173	.hw_params	= pxa2xx_pcm_hw_params,
    174	.prepare	= pxa2xx_ac97_pcm_prepare,
    175	.trigger	= pxa2xx_pcm_trigger,
    176	.pointer	= pxa2xx_pcm_pointer,
    177};
    178
    179
    180static int pxa2xx_ac97_pcm_new(struct snd_card *card)
    181{
    182	struct snd_pcm *pcm;
    183	int ret;
    184
    185	ret = snd_pcm_new(card, "PXA2xx-PCM", 0, 1, 1, &pcm);
    186	if (ret)
    187		goto out;
    188
    189	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
    190	if (ret)
    191		goto out;
    192
    193	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pxa2xx_ac97_pcm_ops);
    194	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pxa2xx_ac97_pcm_ops);
    195	ret = pxa2xx_pcm_preallocate_dma_buffer(pcm);
    196	if (ret)
    197		goto out;
    198
    199	pxa2xx_ac97_pcm = pcm;
    200	ret = 0;
    201
    202 out:
    203	return ret;
    204}
    205
    206static int pxa2xx_ac97_probe(struct platform_device *dev)
    207{
    208	struct snd_card *card;
    209	struct snd_ac97_bus *ac97_bus;
    210	struct snd_ac97_template ac97_template;
    211	int ret;
    212	pxa2xx_audio_ops_t *pdata = dev->dev.platform_data;
    213
    214	if (dev->id >= 0) {
    215		dev_err(&dev->dev, "PXA2xx has only one AC97 port.\n");
    216		ret = -ENXIO;
    217		goto err_dev;
    218	}
    219
    220	ret = snd_card_new(&dev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
    221			   THIS_MODULE, 0, &card);
    222	if (ret < 0)
    223		goto err;
    224
    225	strscpy(card->driver, dev->dev.driver->name, sizeof(card->driver));
    226
    227	ret = pxa2xx_ac97_pcm_new(card);
    228	if (ret)
    229		goto err;
    230
    231	ret = pxa2xx_ac97_hw_probe(dev);
    232	if (ret)
    233		goto err;
    234
    235	ret = snd_ac97_bus(card, 0, &pxa2xx_ac97_ops, NULL, &ac97_bus);
    236	if (ret)
    237		goto err_remove;
    238	memset(&ac97_template, 0, sizeof(ac97_template));
    239	ret = snd_ac97_mixer(ac97_bus, &ac97_template, &pxa2xx_ac97_ac97);
    240	if (ret)
    241		goto err_remove;
    242
    243	snprintf(card->shortname, sizeof(card->shortname),
    244		 "%s", snd_ac97_get_short_name(pxa2xx_ac97_ac97));
    245	snprintf(card->longname, sizeof(card->longname),
    246		 "%s (%s)", dev->dev.driver->name, card->mixername);
    247
    248	if (pdata && pdata->codec_pdata[0])
    249		snd_ac97_dev_add_pdata(ac97_bus->codec[0], pdata->codec_pdata[0]);
    250	ret = snd_card_register(card);
    251	if (ret == 0) {
    252		platform_set_drvdata(dev, card);
    253		return 0;
    254	}
    255
    256err_remove:
    257	pxa2xx_ac97_hw_remove(dev);
    258err:
    259	if (card)
    260		snd_card_free(card);
    261err_dev:
    262	return ret;
    263}
    264
    265static int pxa2xx_ac97_remove(struct platform_device *dev)
    266{
    267	struct snd_card *card = platform_get_drvdata(dev);
    268
    269	if (card) {
    270		snd_card_free(card);
    271		pxa2xx_ac97_hw_remove(dev);
    272	}
    273
    274	return 0;
    275}
    276
    277static struct platform_driver pxa2xx_ac97_driver = {
    278	.probe		= pxa2xx_ac97_probe,
    279	.remove		= pxa2xx_ac97_remove,
    280	.driver		= {
    281		.name	= "pxa2xx-ac97",
    282#ifdef CONFIG_PM_SLEEP
    283		.pm	= &pxa2xx_ac97_pm_ops,
    284#endif
    285	},
    286};
    287
    288module_platform_driver(pxa2xx_ac97_driver);
    289
    290MODULE_AUTHOR("Nicolas Pitre");
    291MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip");
    292MODULE_LICENSE("GPL");
    293MODULE_ALIAS("platform:pxa2xx-ac97");