]> git.karo-electronics.de Git - mv-sheeva.git/blob - sound/soc/codecs/ac97.c
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[mv-sheeva.git] / sound / soc / codecs / ac97.c
1 /*
2  * ac97.c  --  ALSA Soc AC97 codec support
3  *
4  * Copyright 2005 Wolfson Microelectronics PLC.
5  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
6  *
7  *  This program is free software; you can redistribute  it and/or modify it
8  *  under  the terms of  the GNU General  Public License as published by the
9  *  Free Software Foundation;  either version 2 of the  License, or (at your
10  *  option) any later version.
11  *
12  * Generic AC97 support.
13  */
14
15 #include <linux/init.h>
16 #include <linux/slab.h>
17 #include <linux/kernel.h>
18 #include <linux/device.h>
19 #include <sound/core.h>
20 #include <sound/pcm.h>
21 #include <sound/ac97_codec.h>
22 #include <sound/initval.h>
23 #include <sound/soc.h>
24 #include "ac97.h"
25
26 #define AC97_VERSION "0.6"
27
28 static int ac97_prepare(struct snd_pcm_substream *substream,
29                         struct snd_soc_dai *dai)
30 {
31         struct snd_pcm_runtime *runtime = substream->runtime;
32         struct snd_soc_pcm_runtime *rtd = substream->private_data;
33         struct snd_soc_device *socdev = rtd->socdev;
34         struct snd_soc_codec *codec = socdev->card->codec;
35
36         int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
37                   AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
38         return snd_ac97_set_rate(codec->ac97, reg, runtime->rate);
39 }
40
41 #define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
42                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
43                 SNDRV_PCM_RATE_48000)
44
45 static struct snd_soc_dai_ops ac97_dai_ops = {
46         .prepare        = ac97_prepare,
47 };
48
49 struct snd_soc_dai ac97_dai = {
50         .name = "AC97 HiFi",
51         .ac97_control = 1,
52         .playback = {
53                 .stream_name = "AC97 Playback",
54                 .channels_min = 1,
55                 .channels_max = 2,
56                 .rates = STD_AC97_RATES,
57                 .formats = SND_SOC_STD_AC97_FMTS,},
58         .capture = {
59                 .stream_name = "AC97 Capture",
60                 .channels_min = 1,
61                 .channels_max = 2,
62                 .rates = STD_AC97_RATES,
63                 .formats = SND_SOC_STD_AC97_FMTS,},
64         .ops = &ac97_dai_ops,
65 };
66 EXPORT_SYMBOL_GPL(ac97_dai);
67
68 static unsigned int ac97_read(struct snd_soc_codec *codec,
69         unsigned int reg)
70 {
71         return soc_ac97_ops.read(codec->ac97, reg);
72 }
73
74 static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
75         unsigned int val)
76 {
77         soc_ac97_ops.write(codec->ac97, reg, val);
78         return 0;
79 }
80
81 static int ac97_soc_probe(struct platform_device *pdev)
82 {
83         struct snd_soc_device *socdev = platform_get_drvdata(pdev);
84         struct snd_soc_codec *codec;
85         struct snd_ac97_bus *ac97_bus;
86         struct snd_ac97_template ac97_template;
87         int ret = 0;
88
89         printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION);
90
91         socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
92         if (!socdev->card->codec)
93                 return -ENOMEM;
94         codec = socdev->card->codec;
95         mutex_init(&codec->mutex);
96
97         codec->name = "AC97";
98         codec->owner = THIS_MODULE;
99         codec->dai = &ac97_dai;
100         codec->num_dai = 1;
101         codec->write = ac97_write;
102         codec->read = ac97_read;
103         INIT_LIST_HEAD(&codec->dapm_widgets);
104         INIT_LIST_HEAD(&codec->dapm_paths);
105
106         ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
107         if (ret < 0) {
108                 printk(KERN_ERR "ASoC: failed to init gen ac97 glue\n");
109                 goto err;
110         }
111
112         /* register pcms */
113         ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
114         if (ret < 0)
115                 goto err;
116
117         /* add codec as bus device for standard ac97 */
118         ret = snd_ac97_bus(codec->card, 0, &soc_ac97_ops, NULL, &ac97_bus);
119         if (ret < 0)
120                 goto bus_err;
121
122         memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
123         ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97);
124         if (ret < 0)
125                 goto bus_err;
126
127         return 0;
128
129 bus_err:
130         snd_soc_free_pcms(socdev);
131
132 err:
133         kfree(socdev->card->codec);
134         socdev->card->codec = NULL;
135         return ret;
136 }
137
138 static int ac97_soc_remove(struct platform_device *pdev)
139 {
140         struct snd_soc_device *socdev = platform_get_drvdata(pdev);
141         struct snd_soc_codec *codec = socdev->card->codec;
142
143         if (!codec)
144                 return 0;
145
146         snd_soc_free_pcms(socdev);
147         kfree(socdev->card->codec);
148
149         return 0;
150 }
151
152 #ifdef CONFIG_PM
153 static int ac97_soc_suspend(struct platform_device *pdev, pm_message_t msg)
154 {
155         struct snd_soc_device *socdev = platform_get_drvdata(pdev);
156
157         snd_ac97_suspend(socdev->card->codec->ac97);
158
159         return 0;
160 }
161
162 static int ac97_soc_resume(struct platform_device *pdev)
163 {
164         struct snd_soc_device *socdev = platform_get_drvdata(pdev);
165
166         snd_ac97_resume(socdev->card->codec->ac97);
167
168         return 0;
169 }
170 #else
171 #define ac97_soc_suspend NULL
172 #define ac97_soc_resume NULL
173 #endif
174
175 struct snd_soc_codec_device soc_codec_dev_ac97 = {
176         .probe =        ac97_soc_probe,
177         .remove =       ac97_soc_remove,
178         .suspend =      ac97_soc_suspend,
179         .resume =       ac97_soc_resume,
180 };
181 EXPORT_SYMBOL_GPL(soc_codec_dev_ac97);
182
183 MODULE_DESCRIPTION("Soc Generic AC97 driver");
184 MODULE_AUTHOR("Liam Girdwood");
185 MODULE_LICENSE("GPL");