]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - sound/soc/codecs/pcm3008.c
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[karo-tx-linux.git] / sound / soc / codecs / pcm3008.c
1 /*
2  * ALSA Soc PCM3008 codec support
3  *
4  * Author:      Hugo Villeneuve
5  * Copyright (C) 2008 Lyrtech inc
6  *
7  * Based on AC97 Soc codec, original copyright follow:
8  * Copyright 2005 Wolfson Microelectronics PLC.
9  *
10  *  This program is free software; you can redistribute  it and/or modify it
11  *  under  the terms of  the GNU General  Public License as published by the
12  *  Free Software Foundation;  either version 2 of the  License, or (at your
13  *  option) any later version.
14  *
15  * Generic PCM3008 support.
16  */
17
18 #include <linux/init.h>
19 #include <linux/kernel.h>
20 #include <linux/device.h>
21 #include <linux/gpio.h>
22 #include <linux/slab.h>
23 #include <sound/core.h>
24 #include <sound/pcm.h>
25 #include <sound/initval.h>
26 #include <sound/soc.h>
27
28 #include "pcm3008.h"
29
30 #define PCM3008_VERSION "0.2"
31
32 #define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |    \
33                        SNDRV_PCM_RATE_48000)
34
35 struct snd_soc_dai pcm3008_dai = {
36         .name = "PCM3008 HiFi",
37         .playback = {
38                 .stream_name = "PCM3008 Playback",
39                 .channels_min = 1,
40                 .channels_max = 2,
41                 .rates = PCM3008_RATES,
42                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
43         },
44         .capture = {
45                 .stream_name = "PCM3008 Capture",
46                 .channels_min = 1,
47                 .channels_max = 2,
48                 .rates = PCM3008_RATES,
49                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
50         },
51 };
52 EXPORT_SYMBOL_GPL(pcm3008_dai);
53
54 static void pcm3008_gpio_free(struct pcm3008_setup_data *setup)
55 {
56         gpio_free(setup->dem0_pin);
57         gpio_free(setup->dem1_pin);
58         gpio_free(setup->pdad_pin);
59         gpio_free(setup->pdda_pin);
60 }
61
62 static int pcm3008_soc_probe(struct platform_device *pdev)
63 {
64         struct snd_soc_device *socdev = platform_get_drvdata(pdev);
65         struct snd_soc_codec *codec;
66         struct pcm3008_setup_data *setup = socdev->codec_data;
67         int ret = 0;
68
69         printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION);
70
71         socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
72         if (!socdev->card->codec)
73                 return -ENOMEM;
74
75         codec = socdev->card->codec;
76         mutex_init(&codec->mutex);
77
78         codec->name = "PCM3008";
79         codec->owner = THIS_MODULE;
80         codec->dai = &pcm3008_dai;
81         codec->num_dai = 1;
82         codec->write = NULL;
83         codec->read = NULL;
84         INIT_LIST_HEAD(&codec->dapm_widgets);
85         INIT_LIST_HEAD(&codec->dapm_paths);
86
87         /* Register PCMs. */
88         ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
89         if (ret < 0) {
90                 printk(KERN_ERR "pcm3008: failed to create pcms\n");
91                 goto pcm_err;
92         }
93
94         /* DEM1  DEM0  DE-EMPHASIS_MODE
95          * Low   Low   De-emphasis 44.1 kHz ON
96          * Low   High  De-emphasis OFF
97          * High  Low   De-emphasis 48 kHz ON
98          * High  High  De-emphasis 32 kHz ON
99          */
100
101         /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */
102         ret = gpio_request(setup->dem0_pin, "codec_dem0");
103         if (ret == 0)
104                 ret = gpio_direction_output(setup->dem0_pin, 1);
105         if (ret != 0)
106                 goto gpio_err;
107
108         /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */
109         ret = gpio_request(setup->dem1_pin, "codec_dem1");
110         if (ret == 0)
111                 ret = gpio_direction_output(setup->dem1_pin, 0);
112         if (ret != 0)
113                 goto gpio_err;
114
115         /* Configure PDAD GPIO. */
116         ret = gpio_request(setup->pdad_pin, "codec_pdad");
117         if (ret == 0)
118                 ret = gpio_direction_output(setup->pdad_pin, 1);
119         if (ret != 0)
120                 goto gpio_err;
121
122         /* Configure PDDA GPIO. */
123         ret = gpio_request(setup->pdda_pin, "codec_pdda");
124         if (ret == 0)
125                 ret = gpio_direction_output(setup->pdda_pin, 1);
126         if (ret != 0)
127                 goto gpio_err;
128
129         return ret;
130
131 gpio_err:
132         pcm3008_gpio_free(setup);
133 pcm_err:
134         kfree(socdev->card->codec);
135
136         return ret;
137 }
138
139 static int pcm3008_soc_remove(struct platform_device *pdev)
140 {
141         struct snd_soc_device *socdev = platform_get_drvdata(pdev);
142         struct snd_soc_codec *codec = socdev->card->codec;
143         struct pcm3008_setup_data *setup = socdev->codec_data;
144
145         if (!codec)
146                 return 0;
147
148         pcm3008_gpio_free(setup);
149         snd_soc_free_pcms(socdev);
150         kfree(socdev->card->codec);
151
152         return 0;
153 }
154
155 #ifdef CONFIG_PM
156 static int pcm3008_soc_suspend(struct platform_device *pdev, pm_message_t msg)
157 {
158         struct snd_soc_device *socdev = platform_get_drvdata(pdev);
159         struct pcm3008_setup_data *setup = socdev->codec_data;
160
161         gpio_set_value(setup->pdad_pin, 0);
162         gpio_set_value(setup->pdda_pin, 0);
163
164         return 0;
165 }
166
167 static int pcm3008_soc_resume(struct platform_device *pdev)
168 {
169         struct snd_soc_device *socdev = platform_get_drvdata(pdev);
170         struct pcm3008_setup_data *setup = socdev->codec_data;
171
172         gpio_set_value(setup->pdad_pin, 1);
173         gpio_set_value(setup->pdda_pin, 1);
174
175         return 0;
176 }
177 #else
178 #define pcm3008_soc_suspend NULL
179 #define pcm3008_soc_resume NULL
180 #endif
181
182 struct snd_soc_codec_device soc_codec_dev_pcm3008 = {
183         .probe =        pcm3008_soc_probe,
184         .remove =       pcm3008_soc_remove,
185         .suspend =      pcm3008_soc_suspend,
186         .resume =       pcm3008_soc_resume,
187 };
188 EXPORT_SYMBOL_GPL(soc_codec_dev_pcm3008);
189
190 static int __init pcm3008_init(void)
191 {
192         return snd_soc_register_dai(&pcm3008_dai);
193 }
194 module_init(pcm3008_init);
195
196 static void __exit pcm3008_exit(void)
197 {
198         snd_soc_unregister_dai(&pcm3008_dai);
199 }
200 module_exit(pcm3008_exit);
201
202 MODULE_DESCRIPTION("Soc PCM3008 driver");
203 MODULE_AUTHOR("Hugo Villeneuve");
204 MODULE_LICENSE("GPL");