ac97.c 4.0 KB
Newer Older
1 2 3 4
/*
 * ac97.c  --  ALSA Soc AC97 codec support
 *
 * Copyright 2005 Wolfson Microelectronics PLC.
5
 * Author: Liam Girdwood <lrg@slimlogic.co.uk>
6 7 8 9 10 11 12 13 14 15
 *
 *  This program is free software; you can redistribute  it and/or modify it
 *  under  the terms of  the GNU General  Public License as published by the
 *  Free Software Foundation;  either version 2 of the  License, or (at your
 *  option) any later version.
 *
 * Generic AC97 support.
 */

#include <linux/init.h>
16
#include <linux/slab.h>
17 18 19 20 21 22 23 24
#include <linux/kernel.h>
#include <linux/device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
#include <sound/initval.h>
#include <sound/soc.h>

25
#define AC97_VERSION "0.6"
26

27 28
static int ac97_prepare(struct snd_pcm_substream *substream,
			struct snd_soc_dai *dai)
29 30 31
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
32
	struct snd_soc_codec *codec = rtd->codec;
33 34 35 36 37 38

	int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
		  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
	return snd_ac97_set_rate(codec->ac97, reg, runtime->rate);
}

39
#define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
40 41
		SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
		SNDRV_PCM_RATE_48000)
42

43 44 45 46
static struct snd_soc_dai_ops ac97_dai_ops = {
	.prepare	= ac97_prepare,
};

47 48
static struct snd_soc_dai_driver ac97_dai = {
	.name = "ac97-hifi",
M
Mark Brown 已提交
49
	.ac97_control = 1,
50 51 52
	.playback = {
		.stream_name = "AC97 Playback",
		.channels_min = 1,
53 54
		.channels_max = 2,
		.rates = STD_AC97_RATES,
55
		.formats = SND_SOC_STD_AC97_FMTS,},
56 57 58
	.capture = {
		.stream_name = "AC97 Capture",
		.channels_min = 1,
59 60
		.channels_max = 2,
		.rates = STD_AC97_RATES,
61
		.formats = SND_SOC_STD_AC97_FMTS,},
62
	.ops = &ac97_dai_ops,
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
};

static unsigned int ac97_read(struct snd_soc_codec *codec,
	unsigned int reg)
{
	return soc_ac97_ops.read(codec->ac97, reg);
}

static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
	unsigned int val)
{
	soc_ac97_ops.write(codec->ac97, reg, val);
	return 0;
}

78
static int ac97_soc_probe(struct snd_soc_codec *codec)
79 80 81
{
	struct snd_ac97_bus *ac97_bus;
	struct snd_ac97_template ac97_template;
82
	int ret;
83 84 85

	printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION);

86 87 88 89 90
	ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
	if (ret < 0) {
		printk(KERN_ERR "ASoC: failed to init gen ac97 glue\n");
		return ret;
	}
91 92

	/* add codec as bus device for standard ac97 */
93
	ret = snd_ac97_bus(codec->card->snd_card, 0, &soc_ac97_ops, NULL, &ac97_bus);
94
	if (ret < 0)
95
		return ret;
96 97 98

	memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
	ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97);
99
	if (ret < 0)
100
		return ret;
101

102 103 104
	return 0;
}

105
static int ac97_soc_remove(struct snd_soc_codec *codec)
106 107 108 109
{
	return 0;
}

M
Manuel Lauss 已提交
110
#ifdef CONFIG_PM
111
static int ac97_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
M
Manuel Lauss 已提交
112
{
113
	snd_ac97_suspend(codec->ac97);
M
Manuel Lauss 已提交
114 115 116 117

	return 0;
}

118
static int ac97_soc_resume(struct snd_soc_codec *codec)
M
Manuel Lauss 已提交
119
{
120
	snd_ac97_resume(codec->ac97);
M
Manuel Lauss 已提交
121 122 123 124 125 126 127 128

	return 0;
}
#else
#define ac97_soc_suspend NULL
#define ac97_soc_resume NULL
#endif

129 130 131
static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
	.write = ac97_write,
	.read = ac97_read,
132 133
	.probe = 	ac97_soc_probe,
	.remove = 	ac97_soc_remove,
M
Manuel Lauss 已提交
134 135
	.suspend =	ac97_soc_suspend,
	.resume =	ac97_soc_resume,
136
};
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170

static __devinit int ac97_probe(struct platform_device *pdev)
{
	return snd_soc_register_codec(&pdev->dev,
			&soc_codec_dev_ac97, &ac97_dai, 1);
}

static int __devexit ac97_remove(struct platform_device *pdev)
{
	snd_soc_unregister_codec(&pdev->dev);
	return 0;
}

static struct platform_driver ac97_codec_driver = {
	.driver = {
			.name = "ac97-codec",
			.owner = THIS_MODULE,
	},

	.probe = ac97_probe,
	.remove = __devexit_p(ac97_remove),
};

static int __init ac97_init(void)
{
	return platform_driver_register(&ac97_codec_driver);
}
module_init(ac97_init);

static void __exit ac97_exit(void)
{
	platform_driver_unregister(&ac97_codec_driver);
}
module_exit(ac97_exit);
171 172 173 174

MODULE_DESCRIPTION("Soc Generic AC97 driver");
MODULE_AUTHOR("Liam Girdwood");
MODULE_LICENSE("GPL");