]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - sound/arm/omap/omap-alsa-tsc2102.c
Merge with /home/tmlind/src/kernel/linux-2.6
[linux-2.6-omap-h63xx.git] / sound / arm / omap / omap-alsa-tsc2102.c
1 /*
2  * sound/arm/omap/omap-alsa-tsc2102.c
3  * 
4  * Alsa codec driver for TSC2102 chip for OMAP platforms.
5  *
6  * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
7  * Code based on the TSC2101 ALSA driver.
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by the
11  * Free Software Foundation; either version 2 of the License, or (at your
12  * option) any later version.
13  */
14
15 #include <linux/delay.h>
16 #include <linux/soundcard.h>
17 #include <linux/platform_device.h>
18 #include <linux/clk.h>
19 #include <linux/module.h>
20 #include <linux/spi/tsc2102.h>
21
22 #include <asm/arch/mcbsp.h>
23 #include <asm/arch/dma.h>
24 #include <asm/arch/clock.h>
25 #include <asm/arch/omap-alsa.h>
26
27 #include "omap-alsa-tsc2102.h"
28
29 static struct clk *tsc2102_bclk = 0;
30
31 /*
32  * Hardware capabilities
33  */
34
35 /* DAC sampling rates (BCLK = 12 MHz) */
36 static unsigned int rates[] = {
37         7350, 8000, 8820, 9600, 11025, 12000, 14700,
38         16000, 22050, 24000, 29400, 32000, 44100, 48000,
39 };
40
41 static snd_pcm_hw_constraint_list_t tsc2102_hw_constraints_rates = {
42         .count = ARRAY_SIZE(rates),
43         .list = rates,
44         .mask = 0,
45 };
46
47 static snd_pcm_hardware_t tsc2102_snd_omap_alsa_playback = {
48         .info                   = SNDRV_PCM_INFO_INTERLEAVED |
49                 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP |
50                 SNDRV_PCM_INFO_MMAP_VALID,
51         .formats                = SNDRV_PCM_FMTBIT_S16_LE,
52         .rates                  = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
53                 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
54                 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
55                 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_KNOT,
56         .rate_min               = 7350,
57         .rate_max               = 48000,
58         .channels_min           = 2,
59         .channels_max           = 2,
60         .buffer_bytes_max       = 128 * 1024,
61         .period_bytes_min       = 32,
62         .period_bytes_max       = 8 * 1024,
63         .periods_min            = 16,
64         .periods_max            = 255,
65         .fifo_size              = 0,
66 };
67
68 #ifdef DUMP_TSC2102_AUDIO_REGISTERS
69 static void dump_tsc2102_audio_regs(void) {
70         printk("TSC2102_AUDIO1_CTRL = 0x%04x\n",
71                         tsc2102_read_sync(TSC2102_AUDIO1_CTRL));
72         printk("TSC2102_DAC_GAIN_CTRL = 0x%04x\n",
73                         tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL));
74         printk("TSC2102_AUDIO2_CTRL = 0x%04x\n",
75                         tsc2102_read_sync(TSC2102_AUDIO2_CTRL));
76         printk("TSC2102_DAC_POWER_CTRL = 0x%04x\n",
77                         tsc2102_read_sync(TSC2102_DAC_POWER_CTRL));
78         printk("TSC2102_AUDIO3_CTRL = 0x%04x\n",
79                         tsc2102_read_sync(TSC2102_AUDIO_CTRL_3));
80         printk("TSC2102_LCH_BASS_BOOST_N0 = 0x%04x\n",
81                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N0));
82         printk("TSC2102_LCH_BASS_BOOST_N1 = 0x%04x\n",
83                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N1));
84         printk("TSC2102_LCH_BASS_BOOST_N2 = 0x%04x\n",
85                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N2));
86         printk("TSC2102_LCH_BASS_BOOST_N3 = 0x%04x\n",
87                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N3));
88         printk("TSC2102_LCH_BASS_BOOST_N4 = 0x%04x\n",
89                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N4));
90         printk("TSC2102_LCH_BASS_BOOST_N5 = 0x%04x\n",
91                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N5));
92         printk("TSC2102_LCH_BASS_BOOST_D1 = 0x%04x\n",
93                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D1));
94         printk("TSC2102_LCH_BASS_BOOST_D2 = 0x%04x\n",
95                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D2));
96         printk("TSC2102_LCH_BASS_BOOST_D4 = 0x%04x\n",
97                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D4));
98         printk("TSC2102_LCH_BASS_BOOST_D5 = 0x%04x\n",
99                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D5));
100         printk("TSC2102_RCH_BASS_BOOST_N0 = 0x%04x\n",
101                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N0));
102         printk("TSC2102_RCH_BASS_BOOST_N1 = 0x%04x\n",
103                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N1));
104         printk("TSC2102_RCH_BASS_BOOST_N2 = 0x%04x\n",
105                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N2));
106         printk("TSC2102_RCH_BASS_BOOST_N3 = 0x%04x\n",
107                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N3));
108         printk("TSC2102_RCH_BASS_BOOST_N4 = 0x%04x\n",
109                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N4));
110         printk("TSC2102_RCH_BASS_BOOST_N5 = 0x%04x\n",
111                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N5));
112         printk("TSC2102_RCH_BASS_BOOST_D1 = 0x%04x\n",
113                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D1));
114         printk("TSC2102_RCH_BASS_BOOST_D2 = 0x%04x\n",
115                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D2));
116         printk("TSC2102_RCH_BASS_BOOST_D4 = 0x%04x\n",
117                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D4));
118         printk("TSC2102_RCH_BASS_BOOST_D5 = 0x%04x\n",
119                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D5));
120         printk("TSC2102_PLL1_CTRL = 0x%04x\n",
121                         tsc2102_read_sync(TSC2102_PLL1_CTRL));
122         printk("TSC2102_PLL2_CTRL = 0x%04x\n",
123                         tsc2102_read_sync(TSC2102_PLL2_CTRL));
124         printk("TSC2102_AUDIO4_CTRL = 0x%04x\n",
125                         tsc2102_read_sync(TSC2102_AUDIO4_CTRL));
126 }
127 #endif
128
129 /*
130  * ALSA operations according to board file
131  */
132
133 static long current_rate = 0;
134
135 /*
136  * Sample rate changing
137  */
138 static void tsc2102_set_samplerate(long sample_rate)
139 {
140         int clkgdv = 0;
141         u16 srgr1, srgr2;
142
143         if (sample_rate == current_rate)
144                 return;
145         current_rate = 0;
146
147         if (tsc2102_set_rate(sample_rate))
148                 return;
149
150         /* Set the sample rate */
151 #ifndef TSC_MASTER
152         clkgdv = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
153         if (clkgdv)
154                 srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
155         else
156                 return;
157
158         /* Stereo Mode */
159         srgr2 = CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1);
160 #else
161         srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv);
162         srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1);
163 #endif
164         OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR2, srgr2);
165         OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR1, srgr1);
166         current_rate = sample_rate;
167 }
168
169 static void tsc2102_configure(void)
170 {
171         tsc2102_dac_power(1);
172
173 #ifdef TSC_MASTER
174         tsc2102_set_i2s_master(1);
175 #else
176         tsc2102_set_i2s_master(0);
177 #endif
178 }
179
180 /*
181  * Omap McBSP clock and Power Management configuration
182  *  
183  * Here we have some functions that allow clock to be enabled and
184  * disabled only when needed.  Besides doing clock configuration
185  * they allow turn audio on and off when necessary.
186  */
187
188 /*
189  * Do clock framework bclk search
190  */
191 static void tsc2102_clock_setup(void)
192 {
193         tsc2102_bclk = clk_get(0, "bclk");
194 }
195
196 /*
197  * Do some sanity checks, set clock rate, start it.
198  */
199 static int tsc2102_clock_on(void)
200 {
201         int err;
202
203         if (clk_get_usecount(tsc2102_bclk) > 0 &&
204                         clk_get_rate(tsc2102_bclk) != CODEC_CLOCK) {
205                 /* BCLK is already in use */
206                 printk(KERN_WARNING
207                         "BCLK already in use at %d Hz. We change it to %d Hz\n",
208                         (uint) clk_get_rate(tsc2102_bclk), CODEC_CLOCK);
209
210                 err = clk_set_rate(tsc2102_bclk, CODEC_CLOCK);
211                 if (err)
212                         printk(KERN_WARNING "Cannot set BCLK clock rate "
213                                 "for TSC2102 codec, error code = %d\n", err);
214         }
215
216         clk_enable(tsc2102_bclk);
217         return 0;
218 }
219
220 /*
221  * Turn off the audio codec and then stop the clock.
222  */
223 static int tsc2102_clock_off(void)
224 {
225         DPRINTK("clock use count = %d\n", clk_get_usecount(tsc2102_bclk));
226
227         clk_disable(tsc2102_bclk);
228         return 0;
229 }
230
231 static int tsc2102_get_default_samplerate(void)
232 {
233         return DEFAULT_SAMPLE_RATE;
234 }
235
236 static int snd_omap_alsa_tsc2102_suspend(
237                 struct platform_device *pdev, pm_message_t state)
238 {
239         tsc2102_dac_power(0);
240         current_rate = 0;
241
242         return snd_omap_alsa_suspend(pdev, state);
243 }
244
245 static int snd_omap_alsa_tsc2102_resume(struct platform_device *pdev)
246 {
247         tsc2102_dac_power(1);
248
249 #ifdef TSC_MASTER
250         tsc2102_set_i2s_master(1);
251 #else
252         tsc2102_set_i2s_master(0);
253 #endif
254
255         return snd_omap_alsa_resume(pdev);
256 }
257
258 static int __init snd_omap_alsa_tsc2102_probe(struct platform_device *pdev)
259 {
260         int ret;
261         struct omap_alsa_codec_config *codec_cfg = pdev->dev.platform_data;
262
263         if (codec_cfg) {
264                 codec_cfg->hw_constraints_rates =
265                         &tsc2102_hw_constraints_rates;
266                 codec_cfg->snd_omap_alsa_playback =
267                         &tsc2102_snd_omap_alsa_playback;
268                 codec_cfg->codec_configure_dev = tsc2102_configure;
269                 codec_cfg->codec_set_samplerate = tsc2102_set_samplerate;
270                 codec_cfg->codec_clock_setup = tsc2102_clock_setup;
271                 codec_cfg->codec_clock_on = tsc2102_clock_on;
272                 codec_cfg->codec_clock_off = tsc2102_clock_off;
273                 codec_cfg->get_default_samplerate =
274                         tsc2102_get_default_samplerate;
275                 ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
276         } else
277                 ret = -ENODEV;
278
279         return ret;
280 }
281
282 static int snd_omap_alsa_tsc2102_remove(struct platform_device *pdev)
283 {
284         tsc2102_dac_power(0);
285
286         return snd_omap_alsa_remove(pdev);
287 }
288
289 static struct platform_driver omap_alsa_driver = {
290         .probe          = snd_omap_alsa_tsc2102_probe,
291         .remove         = snd_omap_alsa_tsc2102_remove,
292         .suspend        = snd_omap_alsa_tsc2102_suspend,
293         .resume         = snd_omap_alsa_tsc2102_resume,
294         .driver         = {
295                 .name   = "tsc2102-alsa",
296                 .owner  = THIS_MODULE,
297         },
298 };
299
300 static int __init omap_alsa_tsc2102_init(void)
301 {
302         int err;
303
304         ADEBUG();
305         err = platform_driver_register(&omap_alsa_driver);
306
307         return err;
308 }
309
310 static void __exit omap_alsa_tsc2102_exit(void)
311 {
312         ADEBUG();
313         platform_driver_unregister(&omap_alsa_driver);
314 }
315
316 module_init(omap_alsa_tsc2102_init);
317 module_exit(omap_alsa_tsc2102_exit);