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>
36 #include <linux/mutex.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,
331 /* This will be defined in the Audio.h */
332 static struct file_operations *omap_audio_fops;
334 /***************************** MODULES SPECIFIC FUNCTIONs *******************************/
336 /*********************************************************************************
338 * Simplified write for tsc Audio
340 *********************************************************************************/
341 static __inline__ void audio_tsc2101_write(u8 address, u16 data)
343 omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS, address, data);
346 /*********************************************************************************
348 * Simplified read for tsc Audio
350 *********************************************************************************/
351 static __inline__ u16 audio_tsc2101_read(u8 address)
353 return (omap_tsc2101_read(PAGE2_AUDIO_CODEC_REGISTERS, address));
356 /*********************************************************************************
361 ********************************************************************************/
362 static int tsc2101_update(int flag, int val)
370 if (val < 0 || val > 100) {
371 printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
374 /* Convert 0 -> 100 volume to 0x7F(min) -> y(max) volume range */
376 ((val * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MAX;
377 /* invert the value for getting the proper range 0 min and 100 max */
378 volume = OUTPUT_VOLUME_MIN - volume;
379 data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL);
381 ~(DGC_DALVL(OUTPUT_VOLUME_MIN) |
382 DGC_DARVL(OUTPUT_VOLUME_MIN));
383 data |= DGC_DALVL(volume) | DGC_DARVL(volume);
384 audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, data);
385 data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL);
390 if (val < 0 || val > 100) {
391 printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
394 /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
395 /* NOTE: 0 is minimum volume and not mute */
396 volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
397 /* Handset Input not muted, AGC for Handset In off */
398 audio_tsc2101_write(TSC2101_HEADSET_GAIN_CTRL,
399 HGC_ADPGA_HED(volume));
403 if (val < 0 || val > 100) {
404 printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
407 /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
408 /* NOTE: 0 is minimum volume and not mute */
409 volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
410 /* Handset Input not muted, AGC for Handset In off */
411 audio_tsc2101_write(TSC2101_HANDSET_GAIN_CTRL,
412 HNGC_ADPGA_HND(volume));
417 * If more than one recording device selected,
418 * disable the device that is currently in use.
420 if (hweight32(val) > 1)
421 val &= ~tsc2101_local.recsrc;
423 data = audio_tsc2101_read(TSC2101_MIXER_PGA_CTRL);
424 data &= ~MPC_MICSEL(7); /* clear all MICSEL bits */
426 if (val == SOUND_MASK_MIC) {
427 data |= MPC_MICSEL(1);
428 audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, data);
430 else if (val == SOUND_MASK_LINE) {
431 data |= MPC_MICSEL(0);
432 audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, data);
435 printk(KERN_WARNING "omap1610-tsc2101: Wrong RECSRC"
436 " value specified\n");
439 tsc2101_local.recsrc = val;
442 printk(KERN_WARNING "omap1610-tsc2101: Wrong tsc2101_update "
451 /*********************************************************************************
455 ********************************************************************************/
456 static int mixer_open(struct inode *inode, struct file *file)
458 /* Any mixer specific initialization */
460 /* Initalize the tsc2101 */
461 omap_tsc2101_enable();
466 /*********************************************************************************
470 ********************************************************************************/
471 static int mixer_release(struct inode *inode, struct file *file)
473 /* Any mixer specific Un-initialization */
474 omap_tsc2101_disable();
479 /*********************************************************************************
483 ********************************************************************************/
485 mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
490 int nr = _IOC_NR(cmd);
493 * We only accept mixer (type 'M') ioctls.
496 if (_IOC_TYPE(cmd) != 'M')
499 DPRINTK(" 0x%08x\n", cmd);
501 if (cmd == SOUND_MIXER_INFO) {
502 struct mixer_info mi;
504 strncpy(mi.id, "TSC2101", sizeof(mi.id));
505 strncpy(mi.name, "TI TSC2101", sizeof(mi.name));
506 mi.modify_counter = tsc2101_local.mod_cnt;
508 return copy_to_user((void __user *)arg, &mi, sizeof(mi));
511 if (_IOC_DIR(cmd) & _IOC_WRITE) {
512 ret = get_user(val, (int __user *)arg);
516 /* Ignore separate left/right channel for now,
517 * even the codec does support it.
522 case SOUND_MIXER_VOLUME:
523 tsc2101_local.volume = val;
524 tsc2101_local.mod_cnt++;
525 ret = tsc2101_update(SET_VOLUME, gain);
528 case SOUND_MIXER_LINE:
529 tsc2101_local.line = val;
530 tsc2101_local.mod_cnt++;
531 ret = tsc2101_update(SET_LINE, gain);
534 case SOUND_MIXER_MIC:
535 tsc2101_local.mic = val;
536 tsc2101_local.mod_cnt++;
537 ret = tsc2101_update(SET_MIC, gain);
540 case SOUND_MIXER_RECSRC:
541 if ((val & SOUND_MASK_LINE) ||
542 (val & SOUND_MASK_MIC)) {
543 if (tsc2101_local.recsrc != val) {
544 tsc2101_local.mod_cnt++;
545 tsc2101_update(SET_RECSRC, val);
558 if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
562 case SOUND_MIXER_VOLUME:
563 val = tsc2101_local.volume;
564 val = (tsc2101_local.volume << 8) |
565 tsc2101_local.volume;
567 case SOUND_MIXER_LINE:
568 val = (tsc2101_local.line << 8) |
571 case SOUND_MIXER_MIC:
572 val = (tsc2101_local.mic << 8) |
575 case SOUND_MIXER_RECSRC:
576 val = tsc2101_local.recsrc;
578 case SOUND_MIXER_RECMASK:
581 case SOUND_MIXER_DEVMASK:
584 case SOUND_MIXER_CAPS:
587 case SOUND_MIXER_STEREODEVS:
588 val = SOUND_MASK_VOLUME;
592 printk(KERN_WARNING "omap1610-tsc2101: unknown mixer "
593 "read ioctl flag specified\n");
599 ret = put_user(val, (int __user *)arg);
607 /*********************************************************************************
609 * omap_set_samplerate()
611 ********************************************************************************/
612 static int omap_set_samplerate(long sample_rate)
617 /* wait for any frame to complete */
620 /* Search for the right sample rate */
621 while ((reg_info[count].sample_rate != sample_rate) &&
622 (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
625 if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
626 printk(KERN_ERR "Invalid Sample Rate %d requested\n",
632 data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_1);
633 /*Clear prev settings */
634 data &= ~(AC1_DACFS(0x07) | AC1_ADCFS(0x07));
636 AC1_DACFS(reg_info[count].divisor) | AC1_ADCFS(reg_info[count].
638 audio_tsc2101_write(TSC2101_AUDIO_CTRL_1, data);
641 data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_3);
642 /*Clear prev settings */
643 data &= ~(AC3_REFFS | AC3_SLVMS);
644 data |= (reg_info[count].fs_44kHz) ? AC3_REFFS : 0;
647 #endif /* #ifdef TSC_MASTER */
648 audio_tsc2101_write(TSC2101_AUDIO_CTRL_3, data);
650 /* program the PLLs */
651 if (reg_info[count].fs_44kHz) {
652 /* 44.1 khz - 12 MHz Mclk */
653 audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(7)); /* PVAL 1; I_VAL 7 */
654 audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490)); /* D_VAL 5264 */
656 /* 48 khz - 12 Mhz Mclk */
657 audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(8)); /* PVAL 1; I_VAL 8 */
658 audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780)); /* D_VAL 1920 */
661 audio_samplerate = sample_rate;
663 /* Set the sample rate */
666 DEFAULT_MCBSP_CLOCK / (sample_rate *
667 (DEFAULT_BITPERSAMPLE * 2 - 1));
669 initial_config.srgr1 =
670 (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
675 initial_config.srgr2 =
676 (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
678 initial_config.srgr1 =
679 (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
680 initial_config.srgr2 =
681 ((GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
683 #endif /* end of #ifdef TSC_MASTER */
684 omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
689 /*********************************************************************************
691 * omap_tsc2101_initialize() [hw_init() ]
693 ********************************************************************************/
694 static void omap_tsc2101_initialize(void *dummy)
697 DPRINTK("omap_tsc2101_initialize entry\n");
699 /* initialize with default sample rate */
700 audio_samplerate = AUDIO_RATE_DEFAULT;
702 omap_mcbsp_request(AUDIO_MCBSP);
704 /* if configured, then stop mcbsp */
705 omap_mcbsp_stop(AUDIO_MCBSP);
707 omap_tsc2101_enable();
709 omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
710 omap_mcbsp_start(AUDIO_MCBSP);
714 tsc2101_testkeyclick();
721 DPRINTK("omap_tsc2101_initialize exit\n");
724 /*********************************************************************************
726 * omap_tsc2101_shutdown() [hw_shutdown() ]
728 ********************************************************************************/
729 static void omap_tsc2101_shutdown(void *dummy)
732 Turn off codec after it is done.
733 Can't do it immediately, since it may still have
736 Wait 20ms (arbitrary value) and then turn it off.
740 set_current_state(TASK_INTERRUPTIBLE);
743 omap_mcbsp_stop(AUDIO_MCBSP);
744 omap_mcbsp_free(AUDIO_MCBSP);
746 audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL,
747 ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
749 omap_tsc2101_disable();
754 /*********************************************************************************
758 ********************************************************************************/
759 static void tsc2101_configure(void)
763 audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, 0x0000);
765 /*Mute Analog Sidetone */
766 /*Select MIC_INHED input for headset */
767 /*Cell Phone In not connected */
768 audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL,
769 MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
771 /* Set record source */
772 tsc2101_update(SET_RECSRC, tsc2101_local.recsrc);
774 /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
775 /* 1dB AGC hysteresis */
777 audio_tsc2101_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
779 /* Set codec output volume */
780 audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, 0x0000);
782 /* DAC left and right routed to SPK2 */
784 audio_tsc2101_write(TSC2101_AUDIO_CTRL_5,
785 AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
786 AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
789 /* OUT8P/N muted, CPOUT muted */
791 audio_tsc2101_write(TSC2101_AUDIO_CTRL_6,
792 AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
795 /* Headset/Hook switch detect disabled */
796 audio_tsc2101_write(TSC2101_AUDIO_CTRL_7, 0x0000);
798 /* Left line input volume control */
799 tsc2101_update(SET_LINE, tsc2101_local.line);
801 /* mic input volume control */
802 tsc2101_update(SET_MIC, tsc2101_local.mic);
804 /* Left/Right headphone channel volume control */
805 /* Zero-cross detect on */
806 tsc2101_update(SET_VOLUME, tsc2101_local.volume);
808 /* clock configuration */
809 omap_set_samplerate(audio_samplerate);
811 #ifdef TSC_DUMP_REGISTERS
812 tsc2101_dumpRegisters();
819 static void tsc2101_start(void)
823 audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, 0x0000);
825 /*Mute Analog Sidetone */
826 /*Select MIC_INHED input for headset */
827 /*Cell Phone In not connected */
828 audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL,
829 MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
831 /* Set record source */
832 tsc2101_update(SET_RECSRC, tsc2101_local.recsrc);
834 /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
835 /* 1dB AGC hysteresis */
837 audio_tsc2101_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
839 /* Set codec output volume */
840 audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, 0x0000);
842 /* DAC left and right routed to SPK2 */
844 audio_tsc2101_write(TSC2101_AUDIO_CTRL_5,
845 AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
846 AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
849 /* OUT8P/N muted, CPOUT muted */
851 audio_tsc2101_write(TSC2101_AUDIO_CTRL_6,
852 AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
855 /* Headset/Hook switch detect disabled */
856 audio_tsc2101_write(TSC2101_AUDIO_CTRL_7, 0x0000);
858 /* Left line input volume control */
859 tsc2101_update(SET_LINE, tsc2101_local.line);
861 /* mic input volume control */
862 tsc2101_update(SET_MIC, tsc2101_local.mic);
864 /* Left/Right headphone channel volume control */
865 /* Zero-cross detect on */
866 tsc2101_update(SET_VOLUME, tsc2101_local.volume);
873 /******************************************************************************************
875 * All generic ioctl's are handled by audio_ioctl() [File: omap-audio.c]. This
876 * routine handles some platform specific ioctl's
878 ******************************************************************************************/
880 omap_tsc2101_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
885 DPRINTK(" 0x%08x\n", cmd);
888 * These are platform dependent ioctls which are not handled by the
889 * generic omap-audio module.
892 case SNDCTL_DSP_STEREO:
893 ret = get_user(val, (int __user *)arg);
896 /* the AIC23 is stereo only */
897 ret = (val == 0) ? -EINVAL : 1;
899 return put_user(ret, (int __user *)arg);
901 case SNDCTL_DSP_CHANNELS:
902 case SOUND_PCM_READ_CHANNELS:
903 /* the AIC23 is stereo only */
905 return put_user(2, (long __user *)arg);
907 case SNDCTL_DSP_SPEED:
908 ret = get_user(val, (long __user *)arg);
911 ret = omap_set_samplerate(val);
916 case SOUND_PCM_READ_RATE:
918 return put_user(audio_samplerate, (long __user *)arg);
920 case SOUND_PCM_READ_BITS:
921 case SNDCTL_DSP_SETFMT:
922 case SNDCTL_DSP_GETFMTS:
923 /* we can do 16-bit only */
925 return put_user(AFMT_S16_LE, (long __user *)arg);
928 /* Maybe this is meant for the mixer (As per OSS Docs) */
930 return mixer_ioctl(inode, file, cmd, arg);
937 /*********************************************************************************
939 * module_probe for TSC2101
941 ********************************************************************************/
942 static int omap_tsc2101_probe(void)
946 /* Get the fops from audio oss driver */
947 if (!(omap_audio_fops = audio_get_fops())) {
948 printk(KERN_ERR "Unable to Get the FOPs of Audio OSS driver\n");
949 audio_unregister_codec(&tsc2101_state);
953 /* register devices */
954 audio_dev_id = register_sound_dsp(omap_audio_fops, -1);
955 mixer_dev_id = register_sound_mixer(&omap_mixer_fops, -1);
958 create_proc_read_entry(PROC_START_FILE, 0 /* default mode */ ,
959 NULL /* parent dir */ ,
960 codec_start, NULL /* client data */ );
962 create_proc_read_entry(PROC_STOP_FILE, 0 /* default mode */ ,
963 NULL /* parent dir */ ,
964 codec_stop, NULL /* client data */ );
967 /* Announcement Time */
968 printk(KERN_INFO PLATFORM_NAME " " CODEC_NAME
969 " Audio support initialized\n");
975 /*********************************************************************************
977 * Module Remove for TSC2101
979 ********************************************************************************/
980 static void omap_tsc2101_remove(void)
983 /* Un-Register the codec with the audio driver */
984 unregister_sound_dsp(audio_dev_id);
985 unregister_sound_mixer(mixer_dev_id);
988 remove_proc_entry(PROC_START_FILE, NULL);
989 remove_proc_entry(PROC_STOP_FILE, NULL);
995 /*********************************************************************************
997 * Module Suspend for TSC2101
999 ********************************************************************************/
1000 static int omap_tsc2101_suspend(void)
1007 /*********************************************************************************
1009 * Module Resume for TSC2101
1011 ********************************************************************************/
1012 static int omap_tsc2101_resume(void)
1019 /*********************************************************************************
1021 * module_init for TSC2101
1023 ********************************************************************************/
1024 static int __init audio_tsc2101_init(void)
1030 if (machine_is_omap_osk() || machine_is_omap_innovator())
1033 mutex_init(&tsc2101_state.mutex);
1035 /* register the codec with the audio driver */
1036 if ((err = audio_register_codec(&tsc2101_state))) {
1038 "Failed to register TSC driver with Audio OSS Driver\n");
1044 /*********************************************************************************
1046 * module_exit for TSC2101
1048 ********************************************************************************/
1049 static void __exit audio_tsc2101_exit(void)
1053 (void)audio_unregister_codec(&tsc2101_state);
1058 /**************************** DEBUG FUNCTIONS ***********************************/
1060 /*********************************************************************************
1062 * This is a test to generate various keyclick sound on tsc.
1063 * verifies if the tsc and the spi interfaces are operational.
1065 ********************************************************************************/
1066 #ifdef TEST_KEYCLICK
1067 void tsc2101_testkeyclick(void)
1070 u16 old_reg_val, reg_val;
1074 old_reg_val = audio_tsc2101_read(TSC2101_AUDIO_CTRL_2);
1076 /* Keyclick active, max amplitude and longest key click len(32 period) */
1077 printk(KERN_INFO " TESTING KEYCLICK\n Listen carefully NOW....\n");
1078 printk(KERN_INFO " OLD REG VAL=0x%x\n", old_reg_val);
1079 /* try all frequencies */
1080 for (; freq < 8; freq++) {
1081 /* Keyclick active, max amplitude and longest key click len(32 period) */
1082 reg_val = old_reg_val | AC2_KCLAC(0x7) | AC2_KCLLN(0xF);
1085 printk(KERN_INFO "\n\nTrying frequency %d reg val= 0x%x\n",
1086 freq, reg_val | AC2_KCLFRQ(freq) | AC2_KCLEN);
1087 audio_tsc2101_write(TSC2101_AUDIO_CTRL_2,
1088 reg_val | AC2_KCLFRQ(freq) | AC2_KCLEN);
1089 printk("DONE. Wait 10 ms ...\n");
1090 /* wait till the kclk bit is auto cleared! time out also to be considered. */
1091 while (audio_tsc2101_read(TSC2101_AUDIO_CTRL_2) & AC2_KCLEN) {
1094 if (uTryVal > 2000) {
1096 "KEYCLICK TIMED OUT! freq val=%d, POSSIBLE ERROR!\n",
1099 "uTryVal == %d: Read back new reg val= 0x%x\n",
1102 (TSC2101_AUDIO_CTRL_2));
1104 audio_tsc2101_write(TSC2101_AUDIO_CTRL_2, 0x00);
1109 /* put the old value back */
1110 audio_tsc2101_write(TSC2101_AUDIO_CTRL_2, old_reg_val);
1111 printk(KERN_INFO " KEYCLICK TEST COMPLETE\n");
1113 } /* End of tsc2101_testkeyclick */
1115 #endif /* TEST_KEYCLICK */
1117 /*********************************************************************************
1119 * This is a test to generate a rather unpleasant sound..
1120 * verifies if the mcbsp is active (requires MCBSP_DIRECT_RW to be active on McBSP)
1122 ********************************************************************************/
1124 /* Generates a shrill tone */
1126 0x0ce4, 0x0ce4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
1127 0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
1128 0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
1129 0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
1130 0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
1131 0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
1132 0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
1133 0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
1134 0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
1135 0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
1136 0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000,
1137 0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
1138 0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
1139 0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
1140 0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
1141 0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
1142 0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
1143 0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
1144 0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
1145 0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
1146 0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
1147 0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000,
1148 0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
1149 0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
1150 0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
1151 0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
1152 0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
1153 0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
1154 0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
1155 0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
1156 0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
1157 0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
1158 0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000
1165 printk(KERN_INFO "TONE GEN TEST :");
1167 for (count = 0; count < 5000; count++) {
1169 for (bytes = 0; bytes < sizeof(tone) / 2; bytes++) {
1170 ret = omap_mcbsp_pollwrite(AUDIO_MCBSP, tone[bytes]);
1174 } else if (ret == -2) {
1175 printk(KERN_INFO "ERROR:bytes=%d\n", bytes);
1180 printk(KERN_INFO "SUCCESS\n");
1183 #endif /* End of TONE_GEN */
1185 /*********************************************************************************
1187 * TSC_DUMP_REGISTERS:
1188 * This will dump the entire register set of Page 2 tsc2101.
1189 * Useful for major goof ups
1191 ********************************************************************************/
1192 #ifdef TSC_DUMP_REGISTERS
1193 static void tsc2101_dumpRegisters(void)
1197 printk("TSC 2101 Register dump for Page 2 \n");
1198 for (i = 0; i < 0x27; i++) {
1199 data = audio_tsc2101_read(i);
1200 printk(KERN_INFO "Register[%x]=0x%04x\n", i, data);
1204 #endif /* End of #ifdef TSC_DUMP_REGISTERS */
1207 static int codec_start(char *buf, char **start, off_t offset, int count,
1208 int *eof, void *data)
1210 omap_tsc2101_enable();
1212 printk("Codec initialization done.\n");
1215 static int codec_stop(char *buf, char **start, off_t offset, int count,
1216 int *eof, void *data)
1219 omap_tsc2101_disable();
1220 audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL,
1221 ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
1222 printk("Codec shutdown.\n");
1227 /*********************************************************************************
1229 * Other misc management, registration etc
1231 ********************************************************************************/
1232 module_init(audio_tsc2101_init);
1233 module_exit(audio_tsc2101_exit);
1235 MODULE_AUTHOR("Texas Instruments");
1237 ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec.");
1238 MODULE_LICENSE("GPL");