2 * sound/arm/omap-aic23.c
4 * Alsa Driver for AIC23 codec 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 * Based on sa11xx-uda1341.c,
11 * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version.
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
21 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * You should have received a copy of the GNU General Public License along
30 * with this program; if not, write to the Free Software Foundation, Inc.,
31 * 675 Mass Ave, Cambridge, MA 02139, USA.
35 * 2005-07-29 INdT Kernel Team - Alsa driver for omap osk. Creation of new
38 * 2005-12-18 Dirk Behme - Added L/R Channel Interchange fix as proposed by Ajaya Babu
41 #include <linux/config.h>
42 #include <sound/driver.h>
43 #include <linux/module.h>
44 #include <linux/platform_device.h>
45 #include <linux/moduleparam.h>
46 #include <linux/init.h>
47 #include <linux/errno.h>
48 #include <linux/ioctl.h>
49 #include <linux/delay.h>
50 #include <linux/slab.h>
51 #include <linux/clk.h>
57 #include <asm/hardware.h>
58 #include <asm/mach-types.h>
59 #include <asm/arch/dma.h>
60 #include <asm/arch/aic23.h>
61 #include <asm/arch/mcbsp.h>
63 #include <sound/core.h>
64 #include <sound/pcm.h>
65 #include <sound/initval.h>
66 #include <sound/memalloc.h>
68 #include "omap-alsa-dma.h"
69 #include "omap-aic23.h"
74 #define ADEBUG() printk("XXX Alsa debug f:%s, l:%d\n", __FUNCTION__, __LINE__)
76 #define ADEBUG() /* nop */
79 /* Define to set the AIC23 as the master w.r.t McBSP */
83 * AUDIO related MACROS
85 #define DEFAULT_BITPERSAMPLE 16
86 #define AUDIO_RATE_DEFAULT 44100
87 #define AUDIO_MCBSP OMAP_MCBSP1
88 #define NUMBER_SAMPLE_RATES_SUPPORTED 10
91 MODULE_AUTHOR("Daniel Petrini, David Cohen, Anderson Briglia - INdT");
92 MODULE_LICENSE("GPL");
93 MODULE_DESCRIPTION("OMAP AIC23 driver for ALSA");
94 MODULE_SUPPORTED_DEVICE("{{AIC23,OMAP AIC23}}");
95 MODULE_ALIAS("omap_mcbsp.1");
97 static char *id = NULL;
98 MODULE_PARM_DESC(id, "OMAP OSK ALSA Driver for AIC23 chip.");
100 static struct snd_card_omap_aic23 *omap_aic23 = NULL;
102 static struct clk *aic23_mclk = 0;
104 struct sample_rate_rate_reg_info {
105 u8 control; /* SR3, SR2, SR1, SR0 and BOSR */
106 u8 divider; /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
110 * DAC USB-mode sampling rates (MCLK = 12 MHz)
111 * The rates and rate_reg_into MUST be in the same order
113 static unsigned int rates[] = {
114 4000, 8000, 16000, 22050,
118 static const struct sample_rate_rate_reg_info
119 rate_reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
120 {0x06, 1}, /* 4000 */
121 {0x06, 0}, /* 8000 */
122 {0x0C, 1}, /* 16000 */
123 {0x11, 1}, /* 22050 */
124 {0x00, 1}, /* 24000 */
125 {0x0C, 0}, /* 32000 */
126 {0x11, 0}, /* 44100 */
127 {0x00, 0}, /* 48000 */
128 {0x1F, 0}, /* 88200 */
129 {0x0E, 0}, /* 96000 */
133 * mcbsp configuration structure
135 static struct omap_mcbsp_reg_cfg initial_config_mcbsp = {
136 .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
137 .spcr1 = RINTM(3) | RRST,
138 .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
139 RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(0),
140 .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
141 .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
142 XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(0) | XFIG,
143 .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
144 .srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1),
145 .srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1),
147 /* configure McBSP to be the I2S master */
148 .pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,
150 /* configure McBSP to be the I2S slave */
151 .pcr0 = CLKXP | CLKRP,
152 #endif /* AIC23_MASTER */
155 static snd_pcm_hw_constraint_list_t hw_constraints_rates = {
156 .count = ARRAY_SIZE(rates),
162 * HW interface start and stop helper functions
164 static int audio_ifc_start(void)
166 omap_mcbsp_start(AUDIO_MCBSP);
170 static int audio_ifc_stop(void)
172 omap_mcbsp_stop(AUDIO_MCBSP);
177 * Codec/mcbsp init and configuration section
178 * codec dependent code.
182 * Sample rate changing
184 static void omap_aic23_set_samplerate(struct snd_card_omap_aic23
185 *omap_aic23, long rate)
190 /* Fix the rate if it has a wrong value */
193 else if (rate >= 88200)
195 else if (rate >= 48000)
197 else if (rate >= 44100)
199 else if (rate >= 32000)
201 else if (rate >= 24000)
203 else if (rate >= 22050)
205 else if (rate >= 16000)
207 else if (rate >= 8000)
212 /* Search for the right sample rate */
213 /* Verify what happens if the rate is not supported
214 * now it goes to 96Khz */
215 while ((rates[count] != rate) &&
216 (count < (NUMBER_SAMPLE_RATES_SUPPORTED - 1))) {
220 data = (rate_reg_info[count].divider << CLKIN_SHIFT) |
221 (rate_reg_info[count].control << BOSR_SHIFT) | USB_CLK_ON;
223 audio_aic23_write(SAMPLE_RATE_CONTROL_ADDR, data);
225 omap_aic23->samplerate = rate;
228 static inline void aic23_configure(void)
231 audio_aic23_write(RESET_CONTROL_ADDR, 0);
233 /* Initialize the AIC23 internal state */
235 /* Analog audio path control, DAC selected, delete INSEL_MIC for line in */
236 audio_aic23_write(ANALOG_AUDIO_CONTROL_ADDR, DEFAULT_ANALOG_AUDIO_CONTROL);
238 /* Digital audio path control, de-emphasis control 44.1kHz */
239 audio_aic23_write(DIGITAL_AUDIO_CONTROL_ADDR, DEEMP_44K);
241 /* Digital audio interface, master/slave mode, I2S, 16 bit */
243 audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR,
244 MS_MASTER | IWL_16 | FOR_DSP);
246 audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, IWL_16 | FOR_DSP);
249 /* Enable digital interface */
250 audio_aic23_write(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
254 static void omap_aic23_audio_init(struct snd_card_omap_aic23 *omap_aic23)
256 /* Setup DMA stuff */
257 omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Alsa AIC23 out";
258 omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id =
259 SNDRV_PCM_STREAM_PLAYBACK;
260 omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev =
262 omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK].hw_start =
264 omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK].hw_stop =
267 omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE].id = "Alsa AIC23 in";
268 omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE].stream_id =
269 SNDRV_PCM_STREAM_CAPTURE;
270 omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev =
272 omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE].hw_start =
274 omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE].hw_stop =
277 /* configuring the McBSP */
278 omap_mcbsp_request(AUDIO_MCBSP);
280 /* if configured, then stop mcbsp */
281 omap_mcbsp_stop(AUDIO_MCBSP);
283 omap_mcbsp_config(AUDIO_MCBSP, &initial_config_mcbsp);
284 omap_mcbsp_start(AUDIO_MCBSP);
290 * Depends on omap-aic23-dma.c functions and (omap) dma.c
293 #define DMA_BUF_SIZE 1024 * 8
295 static int audio_dma_request(struct audio_stream *s,
296 void (*callback) (void *))
300 err = omap_request_sound_dma(s->dma_dev, s->id, s, &s->lch);
302 printk(KERN_ERR "unable to grab audio dma 0x%x\n",
307 static int audio_dma_free(struct audio_stream *s)
311 err = omap_free_sound_dma(s, &s->lch);
313 printk(KERN_ERR "Unable to free audio dma channels!\n");
318 * This function should calculate the current position of the dma in the
319 * buffer. It will help alsa middle layer to continue update the buffer.
320 * Its correctness is crucial for good functioning.
322 static u_int audio_get_dma_pos(struct audio_stream *s)
324 snd_pcm_substream_t *substream = s->stream;
325 snd_pcm_runtime_t *runtime = substream->runtime;
331 /* this must be called w/ interrupts locked as requested in dma.c */
332 spin_lock_irqsave(&s->dma_lock, flags);
334 /* For the current period let's see where we are */
335 count = omap_get_dma_src_addr_counter(s->lch[s->dma_q_head]);
337 spin_unlock_irqrestore(&s->dma_lock, flags);
339 /* Now, the position related to the end of that period */
340 offset = bytes_to_frames(runtime, s->offset) - bytes_to_frames(runtime, count);
342 if (offset >= runtime->buffer_size || offset < 0)
349 * this stops the dma and clears the dma ptrs
351 static void audio_stop_dma(struct audio_stream *s)
356 spin_lock_irqsave(&s->dma_lock, flags);
361 /* this stops the dma channel and clears the buffer ptrs */
362 omap_audio_stop_dma(s);
364 omap_clear_sound_dma(s);
366 spin_unlock_irqrestore(&s->dma_lock, flags);
370 * Main dma routine, requests dma according where you are in main alsa buffer
372 static void audio_process_dma(struct audio_stream *s)
374 snd_pcm_substream_t *substream = s->stream;
375 snd_pcm_runtime_t *runtime;
376 unsigned int dma_size;
380 runtime = substream->runtime;
382 dma_size = frames_to_bytes(runtime, runtime->period_size);
383 offset = dma_size * s->period;
384 snd_assert(dma_size <= DMA_BUF_SIZE,);
386 omap_start_sound_dma(s,
387 (dma_addr_t) runtime->dma_area +
391 "audio_process_dma: cannot queue DMA buffer (%i)\n",
397 s->period %= runtime->periods;
404 * This is called when dma IRQ occurs at the end of each transmited block
406 void audio_dma_callback(void *data)
408 struct audio_stream *s = data;
411 * If we are getting a callback for an active stream then we inform
412 * the PCM middle layer we've finished a period
415 snd_pcm_period_elapsed(s->stream);
417 spin_lock(&s->dma_lock);
418 if (s->periods > 0) {
421 audio_process_dma(s);
422 spin_unlock(&s->dma_lock);
428 * PCM settings and callbacks
431 static int snd_omap_aic23_trigger(snd_pcm_substream_t * substream, int cmd)
433 struct snd_card_omap_aic23 *chip =
434 snd_pcm_substream_chip(substream);
435 int stream_id = substream->pstr->stream;
436 struct audio_stream *s = &chip->s[stream_id];
440 /* note local interrupts are already disabled in the midlevel code */
441 spin_lock(&s->dma_lock);
443 case SNDRV_PCM_TRIGGER_START:
444 /* requested stream startup */
446 audio_process_dma(s);
448 case SNDRV_PCM_TRIGGER_STOP:
449 /* requested stream shutdown */
456 spin_unlock(&s->dma_lock);
461 static int snd_omap_aic23_prepare(snd_pcm_substream_t * substream)
463 struct snd_card_omap_aic23 *chip =
464 snd_pcm_substream_chip(substream);
465 snd_pcm_runtime_t *runtime = substream->runtime;
466 struct audio_stream *s = &chip->s[substream->pstr->stream];
468 /* set requested samplerate */
469 omap_aic23_set_samplerate(chip, runtime->rate);
477 static snd_pcm_uframes_t snd_omap_aic23_pointer(snd_pcm_substream_t *
480 struct snd_card_omap_aic23 *chip =
481 snd_pcm_substream_chip(substream);
483 return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
486 /* Hardware capabilities */
488 static snd_pcm_hardware_t snd_omap_aic23_capture = {
489 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
490 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
491 .formats = (SNDRV_PCM_FMTBIT_S16_LE),
492 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
493 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
494 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
495 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
496 SNDRV_PCM_RATE_KNOT),
501 .buffer_bytes_max = 128 * 1024,
502 .period_bytes_min = 32,
503 .period_bytes_max = 8 * 1024,
509 static snd_pcm_hardware_t snd_omap_aic23_playback = {
510 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
511 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
512 .formats = (SNDRV_PCM_FMTBIT_S16_LE),
513 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
514 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
515 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
516 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
517 SNDRV_PCM_RATE_KNOT),
522 .buffer_bytes_max = 128 * 1024,
523 .period_bytes_min = 32,
524 .period_bytes_max = 8 * 1024,
530 static int snd_card_omap_aic23_open(snd_pcm_substream_t * substream)
532 struct snd_card_omap_aic23 *chip =
533 snd_pcm_substream_chip(substream);
534 snd_pcm_runtime_t *runtime = substream->runtime;
535 int stream_id = substream->pstr->stream;
539 chip->s[stream_id].stream = substream;
541 omap_aic23_clock_on();
543 if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
544 runtime->hw = snd_omap_aic23_playback;
546 runtime->hw = snd_omap_aic23_capture;
548 snd_pcm_hw_constraint_integer(runtime,
549 SNDRV_PCM_HW_PARAM_PERIODS)) <
553 snd_pcm_hw_constraint_list(runtime, 0,
554 SNDRV_PCM_HW_PARAM_RATE,
555 &hw_constraints_rates)) < 0)
561 static int snd_card_omap_aic23_close(snd_pcm_substream_t * substream)
563 struct snd_card_omap_aic23 *chip =
564 snd_pcm_substream_chip(substream);
567 omap_aic23_clock_off();
568 chip->s[substream->pstr->stream].stream = NULL;
573 /* HW params & free */
575 static int snd_omap_aic23_hw_params(snd_pcm_substream_t * substream,
576 snd_pcm_hw_params_t * hw_params)
578 return snd_pcm_lib_malloc_pages(substream,
579 params_buffer_bytes(hw_params));
582 static int snd_omap_aic23_hw_free(snd_pcm_substream_t * substream)
584 return snd_pcm_lib_free_pages(substream);
589 static snd_pcm_ops_t snd_card_omap_aic23_playback_ops = {
590 .open = snd_card_omap_aic23_open,
591 .close = snd_card_omap_aic23_close,
592 .ioctl = snd_pcm_lib_ioctl,
593 .hw_params = snd_omap_aic23_hw_params,
594 .hw_free = snd_omap_aic23_hw_free,
595 .prepare = snd_omap_aic23_prepare,
596 .trigger = snd_omap_aic23_trigger,
597 .pointer = snd_omap_aic23_pointer,
600 static snd_pcm_ops_t snd_card_omap_aic23_capture_ops = {
601 .open = snd_card_omap_aic23_open,
602 .close = snd_card_omap_aic23_close,
603 .ioctl = snd_pcm_lib_ioctl,
604 .hw_params = snd_omap_aic23_hw_params,
605 .hw_free = snd_omap_aic23_hw_free,
606 .prepare = snd_omap_aic23_prepare,
607 .trigger = snd_omap_aic23_trigger,
608 .pointer = snd_omap_aic23_pointer,
612 * Alsa init and exit section
614 * Inits pcm alsa structures, allocate the alsa buffer, suspend, resume
616 static int __init snd_card_omap_aic23_pcm(struct snd_card_omap_aic23
617 *omap_aic23, int device)
624 snd_pcm_new(omap_aic23->card, "AIC23 PCM", device, 1, 1,
628 /* sets up initial buffer with continuous allocation */
629 snd_pcm_lib_preallocate_pages_for_all(pcm,
630 SNDRV_DMA_TYPE_CONTINUOUS,
631 snd_dma_continuous_data
633 128 * 1024, 128 * 1024);
635 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
636 &snd_card_omap_aic23_playback_ops);
637 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
638 &snd_card_omap_aic23_capture_ops);
639 pcm->private_data = omap_aic23;
641 strcpy(pcm->name, "omap aic23 pcm");
643 omap_aic23_audio_init(omap_aic23);
645 /* setup DMA controller */
646 audio_dma_request(&omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK],
648 audio_dma_request(&omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE],
651 omap_aic23->pcm = pcm;
659 static int snd_omap_aic23_suspend(snd_card_t * card, pm_message_t state)
661 struct snd_card_omap_aic23 *chip = card->pm_private_data;
664 if (chip->card->power_state != SNDRV_CTL_POWER_D3hot) {
665 snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
666 snd_pcm_suspend_all(chip->pcm);
667 /* Mutes and turn clock off */
668 omap_aic23_clock_off();
669 snd_omap_suspend_mixer();
676 * Prepare hardware for resume
678 static int snd_omap_aic23_resume(snd_card_t * card)
680 struct snd_card_omap_aic23 *chip = card->pm_private_data;
683 if (chip->card->power_state != SNDRV_CTL_POWER_D0) {
684 snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
685 omap_aic23_clock_on();
686 snd_omap_resume_mixer();
693 * Driver suspend/resume - calls alsa functions. Some hints from aaci.c
695 static int omap_aic23_suspend(struct platform_device *pdev, pm_message_t state)
697 snd_card_t *card = platform_get_drvdata(pdev);
699 if (card->power_state != SNDRV_CTL_POWER_D3hot) {
700 snd_omap_aic23_suspend(card, PMSG_SUSPEND);
705 static int omap_aic23_resume(struct platform_device *pdev)
707 snd_card_t *card = platform_get_drvdata(pdev);
709 if (card->power_state != SNDRV_CTL_POWER_D0) {
710 snd_omap_aic23_resume(card);
716 #define snd_omap_aic23_suspend NULL
717 #define snd_omap_aic23_resume NULL
718 #define omap_aic23_suspend NULL
719 #define omap_aic23_resume NULL
721 #endif /* CONFIG_PM */
725 void snd_omap_aic23_free(snd_card_t * card)
727 struct snd_card_omap_aic23 *chip = card->private_data;
731 * Turn off codec after it is done.
732 * Can't do it immediately, since it may still have
735 set_current_state(TASK_INTERRUPTIBLE);
738 omap_mcbsp_stop(AUDIO_MCBSP);
739 omap_mcbsp_free(AUDIO_MCBSP);
741 audio_aic23_write(RESET_CONTROL_ADDR, 0);
742 audio_aic23_write(POWER_DOWN_CONTROL_ADDR, 0xff);
744 audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
745 audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
749 * Omap MCBSP clock configuration
751 * Here we have some functions that allows clock to be enabled and
752 * disabled only when needed. Besides doing clock configuration
753 * it allows turn on/turn off audio when necessary.
755 #define CODEC_CLOCK 12000000
756 #define AUDIO_RATE_DEFAULT 44100
759 * Do clock framework mclk search
761 static __init void omap_aic23_clock_setup(void)
763 aic23_mclk = clk_get(0, "mclk");
767 * Do some sanity check, set clock rate, starts it and
768 * turn codec audio on
770 int omap_aic23_clock_on(void)
772 if (clk_get_usecount(aic23_mclk) > 0) {
773 /* MCLK is already in use */
775 "MCLK in use at %d Hz. We change it to %d Hz\n",
776 (uint) clk_get_rate(aic23_mclk),
780 if (clk_set_rate(aic23_mclk, CODEC_CLOCK)) {
782 "Cannot set MCLK for AIC23 CODEC\n");
786 clk_enable(aic23_mclk);
789 "MCLK = %d [%d], usecount = %d\n",
790 (uint) clk_get_rate(aic23_mclk), CODEC_CLOCK,
791 clk_get_usecount(aic23_mclk));
793 /* Now turn the audio on */
794 audio_aic23_write(POWER_DOWN_CONTROL_ADDR,
795 ~DEVICE_POWER_OFF & ~OUT_OFF & ~DAC_OFF &
796 ~ADC_OFF & ~MIC_OFF & ~LINE_OFF);
801 * Do some sanity check, turn clock off and then turn
804 int omap_aic23_clock_off(void)
806 if (clk_get_usecount(aic23_mclk) > 0) {
807 if (clk_get_rate(aic23_mclk) != CODEC_CLOCK) {
809 "MCLK for audio should be %d Hz. But is %d Hz\n",
810 (uint) clk_get_rate(aic23_mclk),
814 clk_disable(aic23_mclk);
817 audio_aic23_write(POWER_DOWN_CONTROL_ADDR,
818 DEVICE_POWER_OFF | OUT_OFF | DAC_OFF |
819 ADC_OFF | MIC_OFF | LINE_OFF);
823 /* module init & exit */
826 * Inits alsa soudcard structure
828 static int __init snd_omap_aic23_probe(struct platform_device *pdev)
834 /* gets clock from clock framework */
835 omap_aic23_clock_setup();
837 /* register the soundcard */
838 card = snd_card_new(-1, id, THIS_MODULE, sizeof(omap_aic23));
842 omap_aic23 = kcalloc(1, sizeof(*omap_aic23), GFP_KERNEL);
843 if (omap_aic23 == NULL)
846 card->private_data = (void *) omap_aic23;
847 card->private_free = snd_omap_aic23_free;
849 omap_aic23->card = card;
850 omap_aic23->samplerate = AUDIO_RATE_DEFAULT;
852 spin_lock_init(&omap_aic23->s[0].dma_lock);
853 spin_lock_init(&omap_aic23->s[1].dma_lock);
856 if ((err = snd_omap_mixer(omap_aic23)) < 0)
860 if ((err = snd_card_omap_aic23_pcm(omap_aic23, 0)) < 0)
863 snd_card_set_pm_callback(card, snd_omap_aic23_suspend,
864 snd_omap_aic23_resume, omap_aic23);
866 strcpy(card->driver, "AIC23");
867 strcpy(card->shortname, "OSK AIC23");
868 sprintf(card->longname, "OMAP OSK with AIC23");
870 snd_omap_init_mixer();
872 if ((err = snd_card_register(card)) == 0) {
873 printk(KERN_INFO "OSK audio support initialized\n");
874 platform_set_drvdata(pdev, card);
879 snd_omap_aic23_free(card);
884 static int snd_omap_aic23_remove(struct platform_device *pdev)
886 snd_card_t *card = platform_get_drvdata(pdev);
887 struct snd_card_omap_aic23 *chip = card->private_data;
892 card->private_data = NULL;
895 platform_set_drvdata(pdev, NULL);
901 static struct platform_driver omap_alsa_driver = {
902 .probe = snd_omap_aic23_probe,
903 .remove = snd_omap_aic23_remove,
904 .suspend = omap_aic23_suspend,
905 .resume = omap_aic23_resume,
907 .name = "omap_mcbsp",
911 static int __init omap_aic23_init(void)
916 err = platform_driver_register(&omap_alsa_driver);
921 static void __exit omap_aic23_exit(void)
925 platform_driver_unregister(&omap_alsa_driver);
928 module_init(omap_aic23_init);
929 module_exit(omap_aic23_exit);