]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - sound/arm/omap/omap-alsa-tsc2102.c
Merge current mainline tree into linux-omap tree
[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/io.h>
21 #include <linux/spi/tsc2102.h>
22
23 #include <mach/dma.h>
24 #include <mach/clock.h>
25 #include <mach/omap-alsa.h>
26
27 #include "omap-alsa-tsc2102.h"
28
29 static struct clk *tsc2102_bclk;
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 struct snd_pcm_hw_constraint_list tsc2102_hw_constraints_rates = {
42         .count = ARRAY_SIZE(rates),
43         .list = rates,
44         .mask = 0,
45 };
46
47 static struct snd_pcm_hardware 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 {
71         printk(KERN_INFO "TSC2102_AUDIO1_CTRL = 0x%04x\n",
72                         tsc2102_read_sync(TSC2102_AUDIO1_CTRL));
73         printk(KERN_INFO "TSC2102_DAC_GAIN_CTRL = 0x%04x\n",
74                         tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL));
75         printk(KERN_INFO "TSC2102_AUDIO2_CTRL = 0x%04x\n",
76                         tsc2102_read_sync(TSC2102_AUDIO2_CTRL));
77         printk(KERN_INFO "TSC2102_DAC_POWER_CTRL = 0x%04x\n",
78                         tsc2102_read_sync(TSC2102_DAC_POWER_CTRL));
79         printk(KERN_INFO "TSC2102_AUDIO3_CTRL = 0x%04x\n",
80                         tsc2102_read_sync(TSC2102_AUDIO_CTRL_3));
81         printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N0 = 0x%04x\n",
82                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N0));
83         printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N1 = 0x%04x\n",
84                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N1));
85         printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N2 = 0x%04x\n",
86                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N2));
87         printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N3 = 0x%04x\n",
88                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N3));
89         printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N4 = 0x%04x\n",
90                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N4));
91         printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N5 = 0x%04x\n",
92                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N5));
93         printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_D1 = 0x%04x\n",
94                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D1));
95         printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_D2 = 0x%04x\n",
96                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D2));
97         printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_D4 = 0x%04x\n",
98                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D4));
99         printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_D5 = 0x%04x\n",
100                         tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D5));
101         printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N0 = 0x%04x\n",
102                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N0));
103         printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N1 = 0x%04x\n",
104                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N1));
105         printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N2 = 0x%04x\n",
106                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N2));
107         printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N3 = 0x%04x\n",
108                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N3));
109         printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N4 = 0x%04x\n",
110                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N4));
111         printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N5 = 0x%04x\n",
112                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N5));
113         printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_D1 = 0x%04x\n",
114                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D1));
115         printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_D2 = 0x%04x\n",
116                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D2));
117         printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_D4 = 0x%04x\n",
118                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D4));
119         printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_D5 = 0x%04x\n",
120                         tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D5));
121         printk(KERN_INFO "TSC2102_PLL1_CTRL = 0x%04x\n",
122                         tsc2102_read_sync(TSC2102_PLL1_CTRL));
123         printk(KERN_INFO "TSC2102_PLL2_CTRL = 0x%04x\n",
124                         tsc2102_read_sync(TSC2102_PLL2_CTRL));
125         printk(KERN_INFO "TSC2102_AUDIO4_CTRL = 0x%04x\n",
126                         tsc2102_read_sync(TSC2102_AUDIO4_CTRL));
127 }
128 #endif
129
130 /*
131  * ALSA operations according to board file
132  */
133
134 static long current_rate;
135
136 /*
137  * Sample rate changing
138  */
139 static void tsc2102_set_samplerate(long sample_rate)
140 {
141         int clkgdv = 0;
142         u16 srgr1, srgr2;
143
144         if (sample_rate == current_rate)
145                 return;
146         current_rate = 0;
147
148         if (tsc2102_set_rate(sample_rate))
149                 return;
150
151         /* Set the sample rate */
152 #ifndef TSC_MASTER
153         clkgdv = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
154         if (clkgdv)
155                 srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
156         else
157                 return;
158
159         /* Stereo Mode */
160         srgr2 = CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1);
161 #else
162         srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv);
163         srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1);
164 #endif
165         OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR2, srgr2);
166         OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR1, srgr1);
167         current_rate = sample_rate;
168 }
169
170 static void tsc2102_configure(void)
171 {
172         tsc2102_dac_power(1);
173
174 #ifdef TSC_MASTER
175         tsc2102_set_i2s_master(1);
176 #else
177         tsc2102_set_i2s_master(0);
178 #endif
179 }
180
181 /*
182  * Omap McBSP clock and Power Management configuration
183  *
184  * Here we have some functions that allow clock to be enabled and
185  * disabled only when needed.  Besides doing clock configuration
186  * they allow turn audio on and off when necessary.
187  */
188
189 /*
190  * Do clock framework bclk search
191  */
192 static void tsc2102_clock_setup(void)
193 {
194         tsc2102_bclk = clk_get(0, "bclk");
195 }
196
197 /*
198  * Do some sanity checks, set clock rate, start it.
199  */
200 static int tsc2102_clock_on(void)
201 {
202         int err;
203
204         if (clk_get_usecount(tsc2102_bclk) > 0 &&
205                         clk_get_rate(tsc2102_bclk) != CODEC_CLOCK) {
206                 /* BCLK is already in use */
207                 printk(KERN_WARNING
208                         "BCLK already in use at %d Hz. We change it to %d Hz\n",
209                         (uint) clk_get_rate(tsc2102_bclk), CODEC_CLOCK);
210
211                 err = clk_set_rate(tsc2102_bclk, CODEC_CLOCK);
212                 if (err)
213                         printk(KERN_WARNING "Cannot set BCLK clock rate "
214                                 "for TSC2102 codec, error code = %d\n", err);
215         }
216
217         clk_enable(tsc2102_bclk);
218         return 0;
219 }
220
221 /*
222  * Turn off the audio codec and then stop the clock.
223  */
224 static int tsc2102_clock_off(void)
225 {
226         DPRINTK("clock use count = %d\n", clk_get_usecount(tsc2102_bclk));
227
228         clk_disable(tsc2102_bclk);
229         return 0;
230 }
231
232 static int tsc2102_get_default_samplerate(void)
233 {
234         return DEFAULT_SAMPLE_RATE;
235 }
236
237 static int snd_omap_alsa_tsc2102_suspend(
238                 struct platform_device *pdev, pm_message_t state)
239 {
240         tsc2102_dac_power(0);
241         current_rate = 0;
242
243         return snd_omap_alsa_suspend(pdev, state);
244 }
245
246 static int snd_omap_alsa_tsc2102_resume(struct platform_device *pdev)
247 {
248         tsc2102_dac_power(1);
249
250 #ifdef TSC_MASTER
251         tsc2102_set_i2s_master(1);
252 #else
253         tsc2102_set_i2s_master(0);
254 #endif
255
256         return snd_omap_alsa_resume(pdev);
257 }
258
259 static int __init snd_omap_alsa_tsc2102_probe(struct platform_device *pdev)
260 {
261         int ret;
262         struct omap_alsa_codec_config *codec_cfg = pdev->dev.platform_data;
263
264         if (codec_cfg) {
265                 codec_cfg->hw_constraints_rates =
266                         &tsc2102_hw_constraints_rates;
267                 codec_cfg->snd_omap_alsa_playback =
268                         &tsc2102_snd_omap_alsa_playback;
269                 codec_cfg->codec_configure_dev = tsc2102_configure;
270                 codec_cfg->codec_set_samplerate = tsc2102_set_samplerate;
271                 codec_cfg->codec_clock_setup = tsc2102_clock_setup;
272                 codec_cfg->codec_clock_on = tsc2102_clock_on;
273                 codec_cfg->codec_clock_off = tsc2102_clock_off;
274                 codec_cfg->get_default_samplerate =
275                         tsc2102_get_default_samplerate;
276                 ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
277         } else
278                 ret = -ENODEV;
279
280         return ret;
281 }
282
283 static int snd_omap_alsa_tsc2102_remove(struct platform_device *pdev)
284 {
285         tsc2102_dac_power(0);
286
287         return snd_omap_alsa_remove(pdev);
288 }
289
290 static struct platform_driver omap_alsa_driver = {
291         .probe          = snd_omap_alsa_tsc2102_probe,
292         .remove         = snd_omap_alsa_tsc2102_remove,
293         .suspend        = snd_omap_alsa_tsc2102_suspend,
294         .resume         = snd_omap_alsa_tsc2102_resume,
295         .driver         = {
296                 .name   = "tsc2102-alsa",
297                 .owner  = THIS_MODULE,
298         },
299 };
300
301 static int __init omap_alsa_tsc2102_init(void)
302 {
303         int err;
304
305         ADEBUG();
306         err = platform_driver_register(&omap_alsa_driver);
307
308         return err;
309 }
310
311 static void __exit omap_alsa_tsc2102_exit(void)
312 {
313         ADEBUG();
314         platform_driver_unregister(&omap_alsa_driver);
315 }
316
317 module_init(omap_alsa_tsc2102_init);
318 module_exit(omap_alsa_tsc2102_exit);