2 * linux/sound/oss/omap-audio-tsc2101.c
4 * Glue driver for TSC2101 for OMAP processors
6 * Copyright (C) 2004 Texas Instruments, Inc.
8 * This package is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
13 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
14 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 * 2004-08-12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms.
19 * 2004-09-14 Sriram Kannan - Added /proc support for asynchronous starting/stopping the codec
20 * (without affecting the normal driver flow).
21 * 2004-11-04 Nishanth Menon - Support for power management
22 * 2004-11-07 Nishanth Menon - Support for Common TSC access b/w Touchscreen and audio drivers
25 /***************************** INCLUDES ************************************/
27 #include <linux/module.h>
28 #include <linux/init.h>
29 #include <linux/types.h>
31 #include <linux/delay.h>
33 #include <linux/errno.h>
34 #include <linux/sound.h>
35 #include <linux/soundcard.h>
37 #include <asm/semaphore.h>
38 #include <asm/uaccess.h>
39 #include <asm/hardware.h>
40 #include <asm/arch/dma.h>
42 #include <asm/hardware.h>
44 #include <asm/arch/mux.h>
45 #include <asm/arch/io.h>
46 #include <asm/mach-types.h>
48 #include "omap-audio.h"
49 #include "omap-audio-dma-intfc.h"
50 #include <asm/arch/mcbsp.h>
51 #ifdef CONFIG_ARCH_OMAP16XX
52 #include <../drivers/ssi/omap-uwire.h>
53 #include <asm/arch/dsp_common.h>
54 #elif defined(CONFIG_ARCH_OMAP24XX)
56 #error "Unsupported configuration"
59 #include <asm/hardware/tsc2101.h>
60 #include <../drivers/ssi/omap-tsc2101.h>
62 /***************************** MACROS ************************************/
67 #include <linux/proc_fs.h>
68 #define PROC_START_FILE "driver/tsc2101-audio-start"
69 #define PROC_STOP_FILE "driver/tsc2101-audio-stop"
72 #define CODEC_NAME "TSC2101"
74 #ifdef CONFIG_ARCH_OMAP16XX
75 #define PLATFORM_NAME "OMAP16XX"
76 #elif defined(CONFIG_ARCH_OMAP24XX)
77 #define PLATFORM_NAME "OMAP2"
80 /* Define to set the tsc as the master w.r.t McBSP */
84 * AUDIO related MACROS
86 #define DEFAULT_BITPERSAMPLE 16
87 #define AUDIO_RATE_DEFAULT 44100
88 #define PAGE2_AUDIO_CODEC_REGISTERS (2)
91 /* Select the McBSP For Audio */
92 /* 16XX is MCBSP1 and 24XX is MCBSP2*/
93 /* see include/asm-arm/arch-omap/mcbsp.h */
95 #error "UnSupported Configuration"
98 #define REC_MASK (SOUND_MASK_LINE | SOUND_MASK_MIC)
99 #define DEV_MASK (REC_MASK | SOUND_MASK_VOLUME)
106 #define DEFAULT_VOLUME 93
107 #define DEFAULT_INPUT_VOLUME 20 /* An minimal volume */
109 /* Tsc Audio Specific */
110 #define NUMBER_SAMPLE_RATES_SUPPORTED 16
111 #define OUTPUT_VOLUME_MIN 0x7F
112 #define OUTPUT_VOLUME_MAX 0x32
113 #define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
114 #define OUTPUT_VOLUME_MASK OUTPUT_VOLUME_MIN
115 #define DEFAULT_VOLUME_LEVEL OUTPUT_VOLUME_MAX
117 /* use input vol of 75 for 0dB gain */
118 #define INPUT_VOLUME_MIN 0x0
119 #define INPUT_VOLUME_MAX 0x7D
120 #define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
121 #define INPUT_VOLUME_MASK INPUT_VOLUME_MAX
123 /*********** Debug Macros ********/
124 /* To Generate a rather shrill tone -test the entire path */
126 /* To Generate a tone for each keyclick - test the tsc,spi paths*/
127 //#define TEST_KEYCLICK
128 /* To dump the tsc registers for debug */
129 //#define TSC_DUMP_REGISTERS
138 #define DPRINTK(ARGS...) printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
139 #define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__)
140 #define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n)
142 #define DPRINTK( x... )
147 /***************************** Data Structures **********************************/
149 static int audio_ifc_start(void)
151 omap_mcbsp_start(AUDIO_MCBSP);
155 static int audio_ifc_stop(void)
157 omap_mcbsp_stop(AUDIO_MCBSP);
161 static audio_stream_t output_stream = {
163 .dma_dev = AUDIO_DMA_TX,
164 .input_or_output = FMODE_WRITE,
165 .hw_start = audio_ifc_start,
166 .hw_stop = audio_ifc_stop,
169 static audio_stream_t input_stream = {
171 .dma_dev = AUDIO_DMA_RX,
172 .input_or_output = FMODE_READ,
173 .hw_start = audio_ifc_start,
174 .hw_stop = audio_ifc_stop,
177 static int audio_dev_id, mixer_dev_id;
185 } tsc2101_local_info;
187 static tsc2101_local_info tsc2101_local = {
188 volume: DEFAULT_VOLUME,
189 line: DEFAULT_INPUT_VOLUME,
190 mic: DEFAULT_INPUT_VOLUME,
191 recsrc: SOUND_MASK_LINE,
195 struct sample_rate_reg_info {
198 u8 fs_44kHz; /* if 0 48 khz, if 1 44.1 khz fsref */
201 /* To Store the default sample rate */
202 static long audio_samplerate = AUDIO_RATE_DEFAULT;
204 static const struct sample_rate_reg_info
205 reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
232 static struct omap_mcbsp_reg_cfg initial_config = {
233 .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
234 .spcr1 = RINTM(3) | RRST,
235 .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
236 RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(1),
237 .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
238 .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
239 XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1) | XFIG,
240 .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
242 .srgr2 = GSYNC | CLKSP | FSGM | FPER(31),
244 /* platform specific initialization */
245 #ifdef CONFIG_MACH_OMAP_H2
246 .pcr0 = CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP,
247 #elif defined(CONFIG_MACH_OMAP_H3) || defined(CONFIG_MACH_OMAP_H4) || defined(CONFIG_MACH_OMAP_APOLLON)
250 .pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,
252 .pcr0 = CLKRM | SCLKME | FSXP | FSRP | CLKXP | CLKRP,
253 #endif /* tsc Master defs */
255 #endif /* platform specific inits */
258 /***************************** MODULES SPECIFIC FUNCTION PROTOTYPES ********************/
260 static void omap_tsc2101_initialize(void *dummy);
262 static void omap_tsc2101_shutdown(void *dummy);
264 static int omap_tsc2101_ioctl(struct inode *inode, struct file *file,
265 uint cmd, ulong arg);
267 static int omap_tsc2101_probe(void);
269 static void omap_tsc2101_remove(void);
271 static int omap_tsc2101_suspend(void);
273 static int omap_tsc2101_resume(void);
275 static void tsc2101_configure(void);
277 static int mixer_open(struct inode *inode, struct file *file);
279 static int mixer_release(struct inode *inode, struct file *file);
281 static int mixer_ioctl(struct inode *inode, struct file *file, uint cmd,
285 void tsc2101_testkeyclick(void);
292 #ifdef TSC_DUMP_REGISTERS
293 static void tsc2101_dumpRegisters(void);
297 static int codec_start(char *buf, char **start, off_t offset, int count,
298 int *eof, void *data);
300 static int codec_stop(char *buf, char **start, off_t offset, int count,
301 int *eof, void *data);
303 static void tsc2101_start(void);
306 /******************** DATA STRUCTURES USING FUNCTION POINTERS **************************/
308 /* File Op structure for mixer */
309 static struct file_operations omap_mixer_fops = {
311 .release = mixer_release,
312 .ioctl = mixer_ioctl,
316 /* To store characteristic info regarding the codec for the audio driver */
317 static audio_state_t tsc2101_state = {
318 .output_stream = &output_stream,
319 .input_stream = &input_stream,
320 /* .need_tx_for_rx = 1, //Once the Full Duplex works */
322 .hw_init = omap_tsc2101_initialize,
323 .hw_shutdown = omap_tsc2101_shutdown,
324 .client_ioctl = omap_tsc2101_ioctl,
325 .hw_probe = omap_tsc2101_probe,
326 .hw_remove = omap_tsc2101_remove,
327 .hw_suspend = omap_tsc2101_suspend,
328 .hw_resume = omap_tsc2101_resume,
329 .sem = __SEMAPHORE_INIT(tsc2101_state.sem, 1),
332 /* This will be defined in the Audio.h */
333 static struct file_operations *omap_audio_fops;
335 /***************************** MODULES SPECIFIC FUNCTIONs *******************************/
337 /*********************************************************************************
339 * Simplified write for tsc Audio
341 *********************************************************************************/
342 static __inline__ void audio_tsc2101_write(u8 address, u16 data)
344 omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS, address, data);
347 /*********************************************************************************
349 * Simplified read for tsc Audio
351 *********************************************************************************/
352 static __inline__ u16 audio_tsc2101_read(u8 address)
354 return (omap_tsc2101_read(PAGE2_AUDIO_CODEC_REGISTERS, address));
357 /*********************************************************************************
362 ********************************************************************************/
363 static int tsc2101_update(int flag, int val)
371 if (val < 0 || val > 100) {
372 printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
375 /* Convert 0 -> 100 volume to 0x7F(min) -> y(max) volume range */
377 ((val * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MAX;
378 /* invert the value for getting the proper range 0 min and 100 max */
379 volume = OUTPUT_VOLUME_MIN - volume;
380 data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL);
382 ~(DGC_DALVL(OUTPUT_VOLUME_MIN) |
383 DGC_DARVL(OUTPUT_VOLUME_MIN));
384 data |= DGC_DALVL(volume) | DGC_DARVL(volume);
385 audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, data);
386 data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL);
391 if (val < 0 || val > 100) {
392 printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
395 /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
396 /* NOTE: 0 is minimum volume and not mute */
397 volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
398 /* Handset Input not muted, AGC for Handset In off */
399 audio_tsc2101_write(TSC2101_HEADSET_GAIN_CTRL,
400 HGC_ADPGA_HED(volume));
404 if (val < 0 || val > 100) {
405 printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
408 /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
409 /* NOTE: 0 is minimum volume and not mute */
410 volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
411 /* Handset Input not muted, AGC for Handset In off */
412 audio_tsc2101_write(TSC2101_HANDSET_GAIN_CTRL,
413 HNGC_ADPGA_HND(volume));
418 * If more than one recording device selected,
419 * disable the device that is currently in use.
421 if (hweight32(val) > 1)
422 val &= ~tsc2101_local.recsrc;
424 data = audio_tsc2101_read(TSC2101_MIXER_PGA_CTRL);
425 data &= ~MPC_MICSEL(7); /* clear all MICSEL bits */
427 if (val == SOUND_MASK_MIC) {
428 data |= MPC_MICSEL(1);
429 audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, data);
431 else if (val == SOUND_MASK_LINE) {
432 data |= MPC_MICSEL(0);
433 audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, data);
436 printk(KERN_WARNING "omap1610-tsc2101: Wrong RECSRC"
437 " value specified\n");
440 tsc2101_local.recsrc = val;
443 printk(KERN_WARNING "omap1610-tsc2101: Wrong tsc2101_update "
452 /*********************************************************************************
456 ********************************************************************************/
457 static int mixer_open(struct inode *inode, struct file *file)
459 /* Any mixer specific initialization */
461 /* Initalize the tsc2101 */
462 omap_tsc2101_enable();
467 /*********************************************************************************
471 ********************************************************************************/
472 static int mixer_release(struct inode *inode, struct file *file)
474 /* Any mixer specific Un-initialization */
475 omap_tsc2101_disable();
480 /*********************************************************************************
484 ********************************************************************************/
486 mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
491 int nr = _IOC_NR(cmd);
494 * We only accept mixer (type 'M') ioctls.
497 if (_IOC_TYPE(cmd) != 'M')
500 DPRINTK(" 0x%08x\n", cmd);
502 if (cmd == SOUND_MIXER_INFO) {
503 struct mixer_info mi;
505 strncpy(mi.id, "TSC2101", sizeof(mi.id));
506 strncpy(mi.name, "TI TSC2101", sizeof(mi.name));
507 mi.modify_counter = tsc2101_local.mod_cnt;
509 return copy_to_user((void __user *)arg, &mi, sizeof(mi));
512 if (_IOC_DIR(cmd) & _IOC_WRITE) {
513 ret = get_user(val, (int __user *)arg);
517 /* Ignore separate left/right channel for now,
518 * even the codec does support it.
523 case SOUND_MIXER_VOLUME:
524 tsc2101_local.volume = val;
525 tsc2101_local.mod_cnt++;
526 ret = tsc2101_update(SET_VOLUME, gain);
529 case SOUND_MIXER_LINE:
530 tsc2101_local.line = val;
531 tsc2101_local.mod_cnt++;
532 ret = tsc2101_update(SET_LINE, gain);
535 case SOUND_MIXER_MIC:
536 tsc2101_local.mic = val;
537 tsc2101_local.mod_cnt++;
538 ret = tsc2101_update(SET_MIC, gain);
541 case SOUND_MIXER_RECSRC:
542 if ((val & SOUND_MASK_LINE) ||
543 (val & SOUND_MASK_MIC)) {
544 if (tsc2101_local.recsrc != val) {
545 tsc2101_local.mod_cnt++;
546 tsc2101_update(SET_RECSRC, val);
559 if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
563 case SOUND_MIXER_VOLUME:
564 val = tsc2101_local.volume;
565 val = (tsc2101_local.volume << 8) |
566 tsc2101_local.volume;
568 case SOUND_MIXER_LINE:
569 val = (tsc2101_local.line << 8) |
572 case SOUND_MIXER_MIC:
573 val = (tsc2101_local.mic << 8) |
576 case SOUND_MIXER_RECSRC:
577 val = tsc2101_local.recsrc;
579 case SOUND_MIXER_RECMASK:
582 case SOUND_MIXER_DEVMASK:
585 case SOUND_MIXER_CAPS:
588 case SOUND_MIXER_STEREODEVS:
589 val = SOUND_MASK_VOLUME;
593 printk(KERN_WARNING "omap1610-tsc2101: unknown mixer "
594 "read ioctl flag specified\n");
600 ret = put_user(val, (int __user *)arg);
608 /*********************************************************************************
610 * omap_set_samplerate()
612 ********************************************************************************/
613 static int omap_set_samplerate(long sample_rate)
618 /* wait for any frame to complete */
621 /* Search for the right sample rate */
622 while ((reg_info[count].sample_rate != sample_rate) &&
623 (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
626 if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
627 printk(KERN_ERR "Invalid Sample Rate %d requested\n",
633 data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_1);
634 /*Clear prev settings */
635 data &= ~(AC1_DACFS(0x07) | AC1_ADCFS(0x07));
637 AC1_DACFS(reg_info[count].divisor) | AC1_ADCFS(reg_info[count].
639 audio_tsc2101_write(TSC2101_AUDIO_CTRL_1, data);
642 data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_3);
643 /*Clear prev settings */
644 data &= ~(AC3_REFFS | AC3_SLVMS);
645 data |= (reg_info[count].fs_44kHz) ? AC3_REFFS : 0;
648 #endif /* #ifdef TSC_MASTER */
649 audio_tsc2101_write(TSC2101_AUDIO_CTRL_3, data);
651 /* program the PLLs */
652 if (reg_info[count].fs_44kHz) {
653 /* 44.1 khz - 12 MHz Mclk */
654 audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(7)); /* PVAL 1; I_VAL 7 */
655 audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490)); /* D_VAL 5264 */
657 /* 48 khz - 12 Mhz Mclk */
658 audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(8)); /* PVAL 1; I_VAL 8 */
659 audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780)); /* D_VAL 1920 */
662 audio_samplerate = sample_rate;
664 /* Set the sample rate */
667 DEFAULT_MCBSP_CLOCK / (sample_rate *
668 (DEFAULT_BITPERSAMPLE * 2 - 1));
670 initial_config.srgr1 =
671 (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
676 initial_config.srgr2 =
677 (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
679 initial_config.srgr1 =
680 (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
681 initial_config.srgr2 =
682 ((GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
684 #endif /* end of #ifdef TSC_MASTER */
685 omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
690 /*********************************************************************************
692 * omap_tsc2101_initialize() [hw_init() ]
694 ********************************************************************************/
695 static void omap_tsc2101_initialize(void *dummy)
698 DPRINTK("omap_tsc2101_initialize entry\n");
700 /* initialize with default sample rate */
701 audio_samplerate = AUDIO_RATE_DEFAULT;
703 omap_mcbsp_request(AUDIO_MCBSP);
705 /* if configured, then stop mcbsp */
706 omap_mcbsp_stop(AUDIO_MCBSP);
708 omap_tsc2101_enable();
710 omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
711 omap_mcbsp_start(AUDIO_MCBSP);
715 tsc2101_testkeyclick();
722 DPRINTK("omap_tsc2101_initialize exit\n");
725 /*********************************************************************************
727 * omap_tsc2101_shutdown() [hw_shutdown() ]
729 ********************************************************************************/
730 static void omap_tsc2101_shutdown(void *dummy)
733 Turn off codec after it is done.
734 Can't do it immediately, since it may still have
737 Wait 20ms (arbitrary value) and then turn it off.
741 set_current_state(TASK_INTERRUPTIBLE);
744 omap_mcbsp_stop(AUDIO_MCBSP);
745 omap_mcbsp_free(AUDIO_MCBSP);
747 audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL,
748 ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
750 omap_tsc2101_disable();
755 /*********************************************************************************
759 ********************************************************************************/
760 static void tsc2101_configure(void)
764 audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, 0x0000);
766 /*Mute Analog Sidetone */
767 /*Select MIC_INHED input for headset */
768 /*Cell Phone In not connected */
769 audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL,
770 MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
772 /* Set record source */
773 tsc2101_update(SET_RECSRC, tsc2101_local.recsrc);
775 /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
776 /* 1dB AGC hysteresis */
778 audio_tsc2101_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
780 /* Set codec output volume */
781 audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, 0x0000);
783 /* DAC left and right routed to SPK2 */
785 audio_tsc2101_write(TSC2101_AUDIO_CTRL_5,
786 AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
787 AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
790 /* OUT8P/N muted, CPOUT muted */
792 audio_tsc2101_write(TSC2101_AUDIO_CTRL_6,
793 AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
796 /* Headset/Hook switch detect disabled */
797 audio_tsc2101_write(TSC2101_AUDIO_CTRL_7, 0x0000);
799 /* Left line input volume control */
800 tsc2101_update(SET_LINE, tsc2101_local.line);
802 /* mic input volume control */
803 tsc2101_update(SET_MIC, tsc2101_local.mic);
805 /* Left/Right headphone channel volume control */
806 /* Zero-cross detect on */
807 tsc2101_update(SET_VOLUME, tsc2101_local.volume);
809 /* clock configuration */
810 omap_set_samplerate(audio_samplerate);
812 #ifdef TSC_DUMP_REGISTERS
813 tsc2101_dumpRegisters();
820 static void tsc2101_start(void)
824 audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, 0x0000);
826 /*Mute Analog Sidetone */
827 /*Select MIC_INHED input for headset */
828 /*Cell Phone In not connected */
829 audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL,
830 MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
832 /* Set record source */
833 tsc2101_update(SET_RECSRC, tsc2101_local.recsrc);
835 /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
836 /* 1dB AGC hysteresis */
838 audio_tsc2101_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
840 /* Set codec output volume */
841 audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, 0x0000);
843 /* DAC left and right routed to SPK2 */
845 audio_tsc2101_write(TSC2101_AUDIO_CTRL_5,
846 AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
847 AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
850 /* OUT8P/N muted, CPOUT muted */
852 audio_tsc2101_write(TSC2101_AUDIO_CTRL_6,
853 AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
856 /* Headset/Hook switch detect disabled */
857 audio_tsc2101_write(TSC2101_AUDIO_CTRL_7, 0x0000);
859 /* Left line input volume control */
860 tsc2101_update(SET_LINE, tsc2101_local.line);
862 /* mic input volume control */
863 tsc2101_update(SET_MIC, tsc2101_local.mic);
865 /* Left/Right headphone channel volume control */
866 /* Zero-cross detect on */
867 tsc2101_update(SET_VOLUME, tsc2101_local.volume);
874 /******************************************************************************************
876 * All generic ioctl's are handled by audio_ioctl() [File: omap-audio.c]. This
877 * routine handles some platform specific ioctl's
879 ******************************************************************************************/
881 omap_tsc2101_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
886 DPRINTK(" 0x%08x\n", cmd);
889 * These are platform dependent ioctls which are not handled by the
890 * generic omap-audio module.
893 case SNDCTL_DSP_STEREO:
894 ret = get_user(val, (int __user *)arg);
897 /* the AIC23 is stereo only */
898 ret = (val == 0) ? -EINVAL : 1;
900 return put_user(ret, (int __user *)arg);
902 case SNDCTL_DSP_CHANNELS:
903 case SOUND_PCM_READ_CHANNELS:
904 /* the AIC23 is stereo only */
906 return put_user(2, (long __user *)arg);
908 case SNDCTL_DSP_SPEED:
909 ret = get_user(val, (long __user *)arg);
912 ret = omap_set_samplerate(val);
917 case SOUND_PCM_READ_RATE:
919 return put_user(audio_samplerate, (long __user *)arg);
921 case SOUND_PCM_READ_BITS:
922 case SNDCTL_DSP_SETFMT:
923 case SNDCTL_DSP_GETFMTS:
924 /* we can do 16-bit only */
926 return put_user(AFMT_S16_LE, (long __user *)arg);
929 /* Maybe this is meant for the mixer (As per OSS Docs) */
931 return mixer_ioctl(inode, file, cmd, arg);
938 /*********************************************************************************
940 * module_probe for TSC2101
942 ********************************************************************************/
943 static int omap_tsc2101_probe(void)
947 /* Get the fops from audio oss driver */
948 if (!(omap_audio_fops = audio_get_fops())) {
949 printk(KERN_ERR "Unable to Get the FOPs of Audio OSS driver\n");
950 audio_unregister_codec(&tsc2101_state);
954 /* register devices */
955 audio_dev_id = register_sound_dsp(omap_audio_fops, -1);
956 mixer_dev_id = register_sound_mixer(&omap_mixer_fops, -1);
959 create_proc_read_entry(PROC_START_FILE, 0 /* default mode */ ,
960 NULL /* parent dir */ ,
961 codec_start, NULL /* client data */ );
963 create_proc_read_entry(PROC_STOP_FILE, 0 /* default mode */ ,
964 NULL /* parent dir */ ,
965 codec_stop, NULL /* client data */ );
968 /* Announcement Time */
969 printk(KERN_INFO PLATFORM_NAME " " CODEC_NAME
970 " Audio support initialized\n");
976 /*********************************************************************************
978 * Module Remove for TSC2101
980 ********************************************************************************/
981 static void omap_tsc2101_remove(void)
984 /* Un-Register the codec with the audio driver */
985 unregister_sound_dsp(audio_dev_id);
986 unregister_sound_mixer(mixer_dev_id);
989 remove_proc_entry(PROC_START_FILE, NULL);
990 remove_proc_entry(PROC_STOP_FILE, NULL);
996 /*********************************************************************************
998 * Module Suspend for TSC2101
1000 ********************************************************************************/
1001 static int omap_tsc2101_suspend(void)
1008 /*********************************************************************************
1010 * Module Resume for TSC2101
1012 ********************************************************************************/
1013 static int omap_tsc2101_resume(void)
1020 /*********************************************************************************
1022 * module_init for TSC2101
1024 ********************************************************************************/
1025 static int __init audio_tsc2101_init(void)
1031 if (machine_is_omap_osk() || machine_is_omap_innovator())
1034 /* register the codec with the audio driver */
1035 if ((err = audio_register_codec(&tsc2101_state))) {
1037 "Failed to register TSC driver with Audio OSS Driver\n");
1043 /*********************************************************************************
1045 * module_exit for TSC2101
1047 ********************************************************************************/
1048 static void __exit audio_tsc2101_exit(void)
1052 (void)audio_unregister_codec(&tsc2101_state);
1057 /**************************** DEBUG FUNCTIONS ***********************************/
1059 /*********************************************************************************
1061 * This is a test to generate various keyclick sound on tsc.
1062 * verifies if the tsc and the spi interfaces are operational.
1064 ********************************************************************************/
1065 #ifdef TEST_KEYCLICK
1066 void tsc2101_testkeyclick(void)
1069 u16 old_reg_val, reg_val;
1073 old_reg_val = audio_tsc2101_read(TSC2101_AUDIO_CTRL_2);
1075 /* Keyclick active, max amplitude and longest key click len(32 period) */
1076 printk(KERN_INFO " TESTING KEYCLICK\n Listen carefully NOW....\n");
1077 printk(KERN_INFO " OLD REG VAL=0x%x\n", old_reg_val);
1078 /* try all frequencies */
1079 for (; freq < 8; freq++) {
1080 /* Keyclick active, max amplitude and longest key click len(32 period) */
1081 reg_val = old_reg_val | AC2_KCLAC(0x7) | AC2_KCLLN(0xF);
1084 printk(KERN_INFO "\n\nTrying frequency %d reg val= 0x%x\n",
1085 freq, reg_val | AC2_KCLFRQ(freq) | AC2_KCLEN);
1086 audio_tsc2101_write(TSC2101_AUDIO_CTRL_2,
1087 reg_val | AC2_KCLFRQ(freq) | AC2_KCLEN);
1088 printk("DONE. Wait 10 ms ...\n");
1089 /* wait till the kclk bit is auto cleared! time out also to be considered. */
1090 while (audio_tsc2101_read(TSC2101_AUDIO_CTRL_2) & AC2_KCLEN) {
1093 if (uTryVal > 2000) {
1095 "KEYCLICK TIMED OUT! freq val=%d, POSSIBLE ERROR!\n",
1098 "uTryVal == %d: Read back new reg val= 0x%x\n",
1101 (TSC2101_AUDIO_CTRL_2));
1103 audio_tsc2101_write(TSC2101_AUDIO_CTRL_2, 0x00);
1108 /* put the old value back */
1109 audio_tsc2101_write(TSC2101_AUDIO_CTRL_2, old_reg_val);
1110 printk(KERN_INFO " KEYCLICK TEST COMPLETE\n");
1112 } /* End of tsc2101_testkeyclick */
1114 #endif /* TEST_KEYCLICK */
1116 /*********************************************************************************
1118 * This is a test to generate a rather unpleasant sound..
1119 * verifies if the mcbsp is active (requires MCBSP_DIRECT_RW to be active on McBSP)
1121 ********************************************************************************/
1123 /* Generates a shrill tone */
1125 0x0ce4, 0x0ce4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
1126 0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
1127 0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
1128 0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
1129 0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
1130 0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
1131 0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
1132 0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
1133 0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
1134 0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
1135 0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000,
1136 0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
1137 0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
1138 0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
1139 0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
1140 0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
1141 0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
1142 0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
1143 0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
1144 0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
1145 0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
1146 0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000,
1147 0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
1148 0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
1149 0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
1150 0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
1151 0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
1152 0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
1153 0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
1154 0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
1155 0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
1156 0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
1157 0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000
1164 printk(KERN_INFO "TONE GEN TEST :");
1166 for (count = 0; count < 5000; count++) {
1168 for (bytes = 0; bytes < sizeof(tone) / 2; bytes++) {
1169 ret = omap_mcbsp_pollwrite(AUDIO_MCBSP, tone[bytes]);
1173 } else if (ret == -2) {
1174 printk(KERN_INFO "ERROR:bytes=%d\n", bytes);
1179 printk(KERN_INFO "SUCCESS\n");
1182 #endif /* End of TONE_GEN */
1184 /*********************************************************************************
1186 * TSC_DUMP_REGISTERS:
1187 * This will dump the entire register set of Page 2 tsc2101.
1188 * Useful for major goof ups
1190 ********************************************************************************/
1191 #ifdef TSC_DUMP_REGISTERS
1192 static void tsc2101_dumpRegisters(void)
1196 printk("TSC 2101 Register dump for Page 2 \n");
1197 for (i = 0; i < 0x27; i++) {
1198 data = audio_tsc2101_read(i);
1199 printk(KERN_INFO "Register[%x]=0x%04x\n", i, data);
1203 #endif /* End of #ifdef TSC_DUMP_REGISTERS */
1206 static int codec_start(char *buf, char **start, off_t offset, int count,
1207 int *eof, void *data)
1209 omap_tsc2101_enable();
1211 printk("Codec initialization done.\n");
1214 static int codec_stop(char *buf, char **start, off_t offset, int count,
1215 int *eof, void *data)
1218 omap_tsc2101_disable();
1219 audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL,
1220 ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
1221 printk("Codec shutdown.\n");
1226 /*********************************************************************************
1228 * Other misc management, registration etc
1230 ********************************************************************************/
1231 module_init(audio_tsc2101_init);
1232 module_exit(audio_tsc2101_exit);
1234 MODULE_AUTHOR("Texas Instruments");
1236 ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec.");
1237 MODULE_LICENSE("GPL");