2 * sound/arm/omap/omap-alsa-tsc2102.c
4 * Alsa codec driver for TSC2102 chip for OMAP platforms.
6 * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
7 * Code based on the TSC2101 ALSA driver.
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.
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>
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>
27 #include "omap-alsa-tsc2102.h"
29 static struct clk *tsc2102_bclk = 0;
32 * Hardware capabilities
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,
41 static snd_pcm_hw_constraint_list_t tsc2102_hw_constraints_rates = {
42 .count = ARRAY_SIZE(rates),
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,
60 .buffer_bytes_max = 128 * 1024,
61 .period_bytes_min = 32,
62 .period_bytes_max = 8 * 1024,
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));
130 * ALSA operations according to board file
133 static long current_rate = 0;
136 * Sample rate changing
138 static void tsc2102_set_samplerate(long sample_rate)
143 if (sample_rate == current_rate)
147 if (tsc2102_set_rate(sample_rate))
150 /* Set the sample rate */
152 clkgdv = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
154 srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
159 srgr2 = CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1);
161 srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv);
162 srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1);
164 OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR2, srgr2);
165 OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR1, srgr1);
166 current_rate = sample_rate;
169 static void tsc2102_configure(void)
171 tsc2102_dac_power(1);
174 tsc2102_set_i2s_master(1);
176 tsc2102_set_i2s_master(0);
181 * Omap McBSP clock and Power Management configuration
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.
189 * Do clock framework bclk search
191 static void tsc2102_clock_setup(void)
193 tsc2102_bclk = clk_get(0, "bclk");
197 * Do some sanity checks, set clock rate, start it.
199 static int tsc2102_clock_on(void)
203 if (clk_get_usecount(tsc2102_bclk) > 0 &&
204 clk_get_rate(tsc2102_bclk) != CODEC_CLOCK) {
205 /* BCLK is already in use */
207 "BCLK already in use at %d Hz. We change it to %d Hz\n",
208 (uint) clk_get_rate(tsc2102_bclk), CODEC_CLOCK);
210 err = clk_set_rate(tsc2102_bclk, CODEC_CLOCK);
212 printk(KERN_WARNING "Cannot set BCLK clock rate "
213 "for TSC2102 codec, error code = %d\n", err);
216 clk_enable(tsc2102_bclk);
221 * Turn off the audio codec and then stop the clock.
223 static int tsc2102_clock_off(void)
225 DPRINTK("clock use count = %d\n", clk_get_usecount(tsc2102_bclk));
227 clk_disable(tsc2102_bclk);
231 static int tsc2102_get_default_samplerate(void)
233 return DEFAULT_SAMPLE_RATE;
236 static int snd_omap_alsa_tsc2102_suspend(
237 struct platform_device *pdev, pm_message_t state)
239 tsc2102_dac_power(0);
242 return snd_omap_alsa_suspend(pdev, state);
245 static int snd_omap_alsa_tsc2102_resume(struct platform_device *pdev)
247 tsc2102_dac_power(1);
250 tsc2102_set_i2s_master(1);
252 tsc2102_set_i2s_master(0);
255 return snd_omap_alsa_resume(pdev);
258 static int __init snd_omap_alsa_tsc2102_probe(struct platform_device *pdev)
261 struct omap_alsa_codec_config *codec_cfg = pdev->dev.platform_data;
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);
282 static int snd_omap_alsa_tsc2102_remove(struct platform_device *pdev)
284 tsc2102_dac_power(0);
286 return snd_omap_alsa_remove(pdev);
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,
295 .name = "tsc2102-alsa",
296 .owner = THIS_MODULE,
300 static int __init omap_alsa_tsc2102_init(void)
305 err = platform_driver_register(&omap_alsa_driver);
310 static void __exit omap_alsa_tsc2102_exit(void)
313 platform_driver_unregister(&omap_alsa_driver);
316 module_init(omap_alsa_tsc2102_init);
317 module_exit(omap_alsa_tsc2102_exit);