2 * arch/arm/mach-omap1/omap-alsa-aic23.c
4 * Alsa codec Driver for AIC23 chip on OSK5912 platform board
6 * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
7 * Written by Daniel Petrini, David Cohen, Anderson Briglia
8 * {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
10 * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
12 * Based in former alsa driver for osk and oss driver
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the License, or (at your
17 * option) any later version.
20 #include <sound/driver.h>
21 #include <sound/core.h>
22 #include <sound/pcm.h>
23 #include <sound/initval.h>
24 #include <sound/control.h>
25 #include <linux/clk.h>
26 #include <asm/arch/clock.h>
27 #include <asm/arch/aic23.h>
29 #include <asm/arch/omap-alsa.h>
30 #include "omap-alsa-aic23.h"
32 static struct clk *aic23_mclk = 0;
35 static const struct aic23_samplerate_reg_info
36 rate_reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
37 {4000, 0x06, 1}, /* 4000 */
38 {8000, 0x06, 0}, /* 8000 */
39 {16000, 0x0C, 1}, /* 16000 */
40 {22050, 0x11, 1}, /* 22050 */
41 {24000, 0x00, 1}, /* 24000 */
42 {32000, 0x0C, 0}, /* 32000 */
43 {44100, 0x11, 0}, /* 44100 */
44 {48000, 0x00, 0}, /* 48000 */
45 {88200, 0x1F, 0}, /* 88200 */
46 {96000, 0x0E, 0}, /* 96000 */
50 * Hardware capabilities
54 * DAC USB-mode sampling rates (MCLK = 12 MHz)
55 * The rates and rate_reg_into MUST be in the same order
57 static unsigned int rates[] = {
58 4000, 8000, 16000, 22050,
63 static snd_pcm_hw_constraint_list_t aic23_hw_constraints_rates = {
64 .count = ARRAY_SIZE(rates),
69 static snd_pcm_hardware_t aic23_snd_omap_alsa_playback = {
70 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
71 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
72 .formats = (SNDRV_PCM_FMTBIT_S16_LE),
73 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
74 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
75 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
76 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
82 .buffer_bytes_max = 128 * 1024,
83 .period_bytes_min = 32,
84 .period_bytes_max = 8 * 1024,
90 static snd_pcm_hardware_t aic23_snd_omap_alsa_capture = {
91 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
92 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
93 .formats = (SNDRV_PCM_FMTBIT_S16_LE),
94 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
95 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
96 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
97 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
103 .buffer_bytes_max = 128 * 1024,
104 .period_bytes_min = 32,
105 .period_bytes_max = 8 * 1024,
112 * Codec/mcbsp init and configuration section
113 * codec dependent code.
116 extern int tlv320aic23_write_value(u8 reg, u16 value);
118 /* TLV320AIC23 is a write only device */
119 void audio_aic23_write(u8 address, u16 data)
121 tlv320aic23_write_value(address, data);
123 EXPORT_SYMBOL_GPL(audio_aic23_write);
126 * Sample rate changing
128 void aic23_set_samplerate(long rate)
133 /* Fix the rate if it has a wrong value */
136 else if (rate >= 88200)
138 else if (rate >= 48000)
140 else if (rate >= 44100)
142 else if (rate >= 32000)
144 else if (rate >= 24000)
146 else if (rate >= 22050)
148 else if (rate >= 16000)
150 else if (rate >= 8000)
155 /* Search for the right sample rate */
156 /* Verify what happens if the rate is not supported
157 * now it goes to 96Khz */
158 while ((rate_reg_info[count].sample_rate != rate) &&
159 (count < (NUMBER_SAMPLE_RATES_SUPPORTED - 1))) {
163 data = (rate_reg_info[count].divider << CLKIN_SHIFT) |
164 (rate_reg_info[count].control << BOSR_SHIFT) | USB_CLK_ON;
166 audio_aic23_write(SAMPLE_RATE_CONTROL_ADDR, data);
169 inline void aic23_configure(void)
172 audio_aic23_write(RESET_CONTROL_ADDR, 0);
174 /* Initialize the AIC23 internal state */
176 /* Analog audio path control, DAC selected, delete INSEL_MIC for line in */
177 audio_aic23_write(ANALOG_AUDIO_CONTROL_ADDR, DEFAULT_ANALOG_AUDIO_CONTROL);
179 /* Digital audio path control, de-emphasis control 44.1kHz */
180 audio_aic23_write(DIGITAL_AUDIO_CONTROL_ADDR, DEEMP_44K);
182 /* Digital audio interface, master/slave mode, I2S, 16 bit */
184 audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR,
185 MS_MASTER | IWL_16 | FOR_DSP);
187 audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, IWL_16 | FOR_DSP);
190 /* Enable digital interface */
191 audio_aic23_write(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
195 * Omap MCBSP clock configuration and Power Management
197 * Here we have some functions that allows clock to be enabled and
198 * disabled only when needed. Besides doing clock configuration
199 * it allows turn on/turn off audio when necessary.
202 * Do clock framework mclk search
204 void aic23_clock_setup(void)
206 aic23_mclk = clk_get(0, "mclk");
210 * Do some sanity check, set clock rate, starts it and
211 * turn codec audio on
213 int aic23_clock_on(void)
215 if (clk_get_usecount(aic23_mclk) > 0) {
216 /* MCLK is already in use */
218 "MCLK in use at %d Hz. We change it to %d Hz\n",
219 (uint) clk_get_rate(aic23_mclk),
223 if (clk_set_rate(aic23_mclk, CODEC_CLOCK)) {
225 "Cannot set MCLK for AIC23 CODEC\n");
229 clk_enable(aic23_mclk);
232 "MCLK = %d [%d], usecount = %d\n",
233 (uint) clk_get_rate(aic23_mclk), CODEC_CLOCK,
234 clk_get_usecount(aic23_mclk));
236 /* Now turn the audio on */
237 audio_aic23_write(POWER_DOWN_CONTROL_ADDR,
238 ~DEVICE_POWER_OFF & ~OUT_OFF & ~DAC_OFF &
239 ~ADC_OFF & ~MIC_OFF & ~LINE_OFF);
243 * Do some sanity check, turn clock off and then turn
246 int aic23_clock_off(void)
248 if (clk_get_usecount(aic23_mclk) > 0) {
249 if (clk_get_rate(aic23_mclk) != CODEC_CLOCK) {
251 "MCLK for audio should be %d Hz. But is %d Hz\n",
252 (uint) clk_get_rate(aic23_mclk),
256 clk_disable(aic23_mclk);
259 audio_aic23_write(POWER_DOWN_CONTROL_ADDR,
260 DEVICE_POWER_OFF | OUT_OFF | DAC_OFF |
261 ADC_OFF | MIC_OFF | LINE_OFF);
265 int aic23_get_default_samplerate(void)
267 return DEFAULT_SAMPLE_RATE;
270 static int __init snd_omap_alsa_aic23_probe(struct platform_device *pdev)
273 struct omap_alsa_codec_config *codec_cfg;
275 codec_cfg = pdev->dev.platform_data;
276 if (codec_cfg != NULL) {
277 codec_cfg->hw_constraints_rates = &aic23_hw_constraints_rates;
278 codec_cfg->snd_omap_alsa_playback = &aic23_snd_omap_alsa_playback;
279 codec_cfg->snd_omap_alsa_capture = &aic23_snd_omap_alsa_capture;
280 codec_cfg->codec_configure_dev = aic23_configure;
281 codec_cfg->codec_set_samplerate = aic23_set_samplerate;
282 codec_cfg->codec_clock_setup = aic23_clock_setup;
283 codec_cfg->codec_clock_on = aic23_clock_on;
284 codec_cfg->codec_clock_off = aic23_clock_off;
285 codec_cfg->get_default_samplerate = aic23_get_default_samplerate;
286 ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
293 static struct platform_driver omap_alsa_driver = {
294 .probe = snd_omap_alsa_aic23_probe,
295 .remove = snd_omap_alsa_remove,
296 .suspend = snd_omap_alsa_suspend,
297 .resume = snd_omap_alsa_resume,
299 .name = "omap_alsa_mcbsp",
303 static int __init omap_alsa_aic23_init(void)
308 err = platform_driver_register(&omap_alsa_driver);
313 static void __exit omap_alsa_aic23_exit(void)
317 platform_driver_unregister(&omap_alsa_driver);
320 module_init(omap_alsa_aic23_init);
321 module_exit(omap_alsa_aic23_exit);