]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - sound/oss/omap-audio-tsc2101.c
h63xx: tsc2101 alsa sound support
[linux-2.6-omap-h63xx.git] / sound / oss / omap-audio-tsc2101.c
1 /*
2  * linux/sound/oss/omap-audio-tsc2101.c
3  *
4  * Glue driver for TSC2101 for OMAP processors
5  *
6  * Copyright (C) 2004 Texas Instruments, Inc.
7  *
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.
11  *
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.
15  *
16  * History:
17  *  -------
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
23  */
24
25 /***************************** INCLUDES ************************************/
26
27 #include <linux/module.h>
28 #include <linux/init.h>
29 #include <linux/types.h>
30 #include <linux/fs.h>
31 #include <linux/delay.h>
32 #include <linux/pm.h>
33 #include <linux/errno.h>
34 #include <linux/sound.h>
35 #include <linux/soundcard.h>
36 #include <linux/mutex.h>
37
38 #include <asm/uaccess.h>
39 #include <asm/hardware.h>
40 #include <asm/arch/dma.h>
41 #include <asm/io.h>
42 #include <asm/hardware.h>
43
44 #include <asm/arch/mux.h>
45 #include <asm/arch/io.h>
46 #include <asm/mach-types.h>
47
48 #include "omap-audio.h"
49 #include "omap-audio-dma-intfc.h"
50 #include <asm/arch/mcbsp.h>
51 #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_MACH_OMAP_H6300)
52 #include <../drivers/ssi/omap-uwire.h>
53 #include <asm/arch/dsp_common.h>
54 #elif defined(CONFIG_ARCH_OMAP24XX)
55 #else
56 #error "Unsupported configuration"
57 #endif
58
59 #include <asm/hardware/tsc2101.h>
60 #include <../drivers/ssi/omap-tsc2101.h>
61
62 /***************************** MACROS ************************************/
63
64 #define PROC_SUPPORT
65
66 #ifdef PROC_SUPPORT
67 #include <linux/proc_fs.h>
68 #define PROC_START_FILE "driver/tsc2101-audio-start"
69 #define PROC_STOP_FILE  "driver/tsc2101-audio-stop"
70 #endif
71
72 #define CODEC_NAME               "TSC2101"
73
74 #ifdef CONFIG_ARCH_OMAP16XX
75 #define PLATFORM_NAME "OMAP16XX"
76 #elif CONFIG_MACH_OMAP_H6300
77 #define PLATFORM_NAME "OMAP15XX"
78 #elif defined(CONFIG_ARCH_OMAP24XX)
79 #define PLATFORM_NAME "OMAP2"
80 #endif
81
82 #if CONFIG_ARCH_OMAP16XX
83 #define OMAP_DSP_BASE        0xE0000000
84 #endif
85
86 /* Define to set the tsc as the master w.r.t McBSP */
87 #define TSC_MASTER
88
89 /*
90  * AUDIO related MACROS
91  */
92 #define DEFAULT_BITPERSAMPLE          16
93 #define AUDIO_RATE_DEFAULT                44100
94 #define PAGE2_AUDIO_CODEC_REGISTERS   (2)
95 #define LEAVE_CS                                  0x80
96
97 /* Select the McBSP For Audio */
98 /* 16XX is MCBSP1 and 24XX is MCBSP2*/
99 /* see include/asm-arm/arch-omap/mcbsp.h */
100 #ifndef AUDIO_MCBSP
101 #error "UnSupported Configuration"
102 #endif
103
104 #define REC_MASK                                  (SOUND_MASK_LINE | SOUND_MASK_MIC)
105 #define DEV_MASK                                  (REC_MASK | SOUND_MASK_VOLUME)
106
107 #define SET_VOLUME                                1
108 #define SET_LINE                                  2
109 #define SET_MIC       3
110 #define SET_RECSRC            4
111
112 #define DEFAULT_VOLUME                93
113 #define DEFAULT_INPUT_VOLUME      20    /* An minimal volume */
114
115 /* Tsc Audio Specific */
116 #define NUMBER_SAMPLE_RATES_SUPPORTED 16
117 #define OUTPUT_VOLUME_MIN 0x7F
118 #define OUTPUT_VOLUME_MAX 0x32
119 #define OUTPUT_VOLUME_RANGE           (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
120 #define OUTPUT_VOLUME_MASK            OUTPUT_VOLUME_MIN
121 #define DEFAULT_VOLUME_LEVEL          OUTPUT_VOLUME_MAX
122
123 /* use input vol of 75 for 0dB gain */
124 #define INPUT_VOLUME_MIN                      0x0
125 #define INPUT_VOLUME_MAX         0x7D
126 #define INPUT_VOLUME_RANGE                    (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
127 #define INPUT_VOLUME_MASK                     INPUT_VOLUME_MAX
128
129 /*********** Debug Macros ********/
130 /* To Generate a rather shrill tone -test the entire path */
131 //#define TONE_GEN
132 ///* To Generate a tone for each keyclick - test the tsc,spi paths*/
133 //#define TEST_KEYCLICK
134 /* To dump the tsc registers for debug */
135 //#define TSC_DUMP_REGISTERS
136
137 #ifdef DPRINTK
138 #undef DPRINTK
139 #endif
140 #undef DEBUG
141
142 //#define DEBUG
143 #ifdef DEBUG
144 #define DPRINTK(ARGS...)  printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
145 #define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__)
146 #define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n)
147 #else
148 #define DPRINTK( x... )
149 #define FN_IN
150 #define FN_OUT(n)
151 #endif
152
153 /***************************** Data Structures **********************************/
154
155 static int audio_ifc_start(void)
156 {
157         omap_mcbsp_start(AUDIO_MCBSP);
158         return 0;
159 }
160
161 static int audio_ifc_stop(void)
162 {
163         omap_mcbsp_stop(AUDIO_MCBSP);
164         return 0;
165 }
166
167 static audio_stream_t output_stream = {
168         .id                     = "TSC2101 out",
169         .dma_dev                = AUDIO_DMA_TX,
170         .input_or_output        = FMODE_WRITE,
171         .hw_start               = audio_ifc_start,
172         .hw_stop                = audio_ifc_stop,
173 };
174
175 static audio_stream_t input_stream = {
176         .id                     = "TSC2101 in",
177         .dma_dev                = AUDIO_DMA_RX,
178         .input_or_output        = FMODE_READ,
179         .hw_start               = audio_ifc_start,
180         .hw_stop                = audio_ifc_stop,
181 };
182
183 static int audio_dev_id, mixer_dev_id;
184
185 typedef struct {
186         u8      volume;
187         u8      line;
188         u8      mic;
189         int     recsrc;
190         int     mod_cnt;
191 } tsc2101_local_info;
192
193 static tsc2101_local_info tsc2101_local = {
194         volume:         DEFAULT_VOLUME,
195         line:           DEFAULT_INPUT_VOLUME,
196         mic:            DEFAULT_INPUT_VOLUME,
197         recsrc:         SOUND_MASK_LINE,
198         mod_cnt:        0
199 };
200
201 struct sample_rate_reg_info {
202         u16 sample_rate;
203         u8  divisor;
204         u8  fs_44kHz;           /* if 0 48 khz, if 1 44.1 khz fsref */
205 };
206
207 /* To Store the default sample rate */
208 static long audio_samplerate = AUDIO_RATE_DEFAULT;
209
210 static const struct sample_rate_reg_info
211  reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
212         /* Div 1 */
213         {48000, 0, 0},
214         {44100, 0, 1},
215         /* Div 1.5 */
216         {32000, 1, 0},
217         {29400, 1, 1},
218         /* Div 2 */
219         {24000, 2, 0},
220         {22050, 2, 1},
221         /* Div 3 */
222         {16000, 3, 0},
223         {14700, 3, 1},
224         /* Div 4 */
225         {12000, 4, 0},
226         {11025, 4, 1},
227         /* Div 5 */
228         {9600, 5, 0},
229         {8820, 5, 1},
230         /* Div 5.5 */
231         {8727, 6, 0},
232         {8018, 6, 1},
233         /* Div 6 */
234         {8000, 7, 0},
235         {7350, 7, 1},
236 };
237
238 static struct omap_mcbsp_reg_cfg initial_config = {
239 #ifdef CONFIG_MACH_OMAP_H6300
240         .spcr2 = 0x0005,
241         .spcr1 = 0x0005,
242         .rcr2  = 0x8041,
243         .rcr1  = 0x8041,
244         .xcr2  = 0x00a1,
245         .xcr1  = 0x00a1,
246         .srgr2 = 0xb000,
247         .srgr1 = 0xb000,
248         .pcr0  = 0x0081,
249 #else
250         .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
251         .spcr1 = RINTM(3) | RRST,
252         .rcr2  = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
253                  RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(1),
254         .rcr1  = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
255         .xcr2  = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
256                  XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1) | XFIG,
257         .xcr1  = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
258         .srgr1 = FWID(15),
259         .srgr2 = GSYNC | CLKSP | FSGM | FPER(31),
260
261         /* platform specific initialization */
262 #ifdef CONFIG_MACH_OMAP_H2
263         .pcr0  = CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP,
264 #elif defined(CONFIG_MACH_OMAP_H3) || defined(CONFIG_MACH_OMAP_H4) || defined(CONFIG_MACH_OMAP_APOLLON)
265
266 #ifndef TSC_MASTER
267         .pcr0  = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,
268 #else
269         .pcr0  = CLKRM | SCLKME | FSXP | FSRP | CLKXP | CLKRP,
270 #endif                          /* tsc Master defs */
271
272 #endif                          /* platform specific inits */
273 #endif /* CONFIG_MACH_OMAP_H6300 */
274 };
275
276 /***************************** MODULES SPECIFIC FUNCTION PROTOTYPES ********************/
277
278 static void omap_tsc2101_initialize(void *dummy);
279
280 static void omap_tsc2101_shutdown(void *dummy);
281
282 static int  omap_tsc2101_ioctl(struct inode *inode, struct file *file,
283                                uint cmd, ulong arg);
284
285 static int  omap_tsc2101_probe(void);
286
287 static void omap_tsc2101_remove(void);
288
289 static int  omap_tsc2101_suspend(void);
290
291 static int  omap_tsc2101_resume(void);
292
293 static void tsc2101_configure(void);
294
295 static int  mixer_open(struct inode *inode, struct file *file);
296
297 static int  mixer_release(struct inode *inode, struct file *file);
298
299 static int  mixer_ioctl(struct inode *inode, struct file *file, uint cmd,
300                         ulong arg);
301
302 #ifdef TEST_KEYCLICK
303 void tsc2101_testkeyclick(void);
304 #endif
305
306 #ifdef TONE_GEN
307 void toneGen(void);
308 #endif
309
310 #ifdef TSC_DUMP_REGISTERS
311 static void tsc2101_dumpRegisters(void);
312 #endif
313
314 #ifdef PROC_SUPPORT
315 static int codec_start(char *buf, char **start, off_t offset, int count,
316                        int *eof, void *data);
317
318 static int codec_stop(char *buf, char **start, off_t offset, int count,
319                       int *eof, void *data);
320
321 static void tsc2101_start(void);
322 #endif
323
324 /******************** DATA STRUCTURES USING FUNCTION POINTERS **************************/
325
326 /* File Op structure for mixer */
327 static struct file_operations omap_mixer_fops = {
328         .open           = mixer_open,
329         .release        = mixer_release,
330         .ioctl          = mixer_ioctl,
331         .owner          = THIS_MODULE
332 };
333
334 /* To store characteristic info regarding the codec for the audio driver */
335 static audio_state_t tsc2101_state = {
336         .output_stream  = &output_stream,
337         .input_stream   = &input_stream,
338 /*      .need_tx_for_rx = 1, //Once the Full Duplex works  */
339         .need_tx_for_rx = 0,
340         .hw_init        = omap_tsc2101_initialize,
341         .hw_shutdown    = omap_tsc2101_shutdown,
342         .client_ioctl   = omap_tsc2101_ioctl,
343         .hw_probe       = omap_tsc2101_probe,
344         .hw_remove      = omap_tsc2101_remove,
345         .hw_suspend     = omap_tsc2101_suspend,
346         .hw_resume      = omap_tsc2101_resume,
347         .mutex          = __MUTEX_INITIALIZER(tsc2101_state.mutex),
348 };
349
350 /* This will be defined in the Audio.h */
351 static struct file_operations *omap_audio_fops;
352
353 /***************************** MODULES SPECIFIC FUNCTIONs *******************************/
354
355 /*********************************************************************************
356  *
357  * Simplified write for tsc Audio
358  *
359  *********************************************************************************/
360 static __inline__ void audio_tsc2101_write(u8 address, u16 data)
361 {
362         omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS, address, data);
363 }
364
365 /*********************************************************************************
366  *
367  * Simplified read for tsc  Audio
368  *
369  *********************************************************************************/
370 static __inline__ u16 audio_tsc2101_read(u8 address)
371 {
372         return (omap_tsc2101_read(PAGE2_AUDIO_CODEC_REGISTERS, address));
373 }
374
375 /*********************************************************************************
376  *
377  * tsc2101_update()
378  * Volume Adj etc
379  *
380  ********************************************************************************/
381 static int tsc2101_update(int flag, int val)
382 {
383         u16 volume;
384         u16 data;
385
386         FN_IN;
387         switch (flag) {
388         case SET_VOLUME:
389                 if (val < 0 || val > 100) {
390                         printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
391                         return -EPERM;
392                 }
393                 /* Convert 0 -> 100 volume to 0x7F(min) -> y(max) volume range */
394                 volume =
395                     ((val * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MAX;
396                 /* invert the value for getting the proper range 0 min and 100 max */
397                 volume = OUTPUT_VOLUME_MIN - volume;
398                 data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL);
399                 data &=
400                     ~(DGC_DALVL(OUTPUT_VOLUME_MIN) |
401                       DGC_DARVL(OUTPUT_VOLUME_MIN));
402                 data |= DGC_DALVL(volume) | DGC_DARVL(volume);
403                 audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, data);
404                 data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL);
405
406                 break;
407
408         case SET_LINE:
409                 if (val < 0 || val > 100) {
410                         printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
411                         return -EPERM;
412                 }
413                 /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
414                 /* NOTE: 0 is minimum volume and not mute */
415                 volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
416                 /* Handset Input not muted, AGC for Handset In off */
417                 audio_tsc2101_write(TSC2101_HEADSET_GAIN_CTRL,
418         HGC_ADPGA_HED(volume));
419                 break;
420
421         case SET_MIC:
422                 if (val < 0 || val > 100) {
423                         printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
424                         return -EPERM;
425                 }
426                 /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
427                 /* NOTE: 0 is minimum volume and not mute */
428                 volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
429                 /* Handset Input not muted, AGC for Handset In off */
430                 audio_tsc2101_write(TSC2101_HANDSET_GAIN_CTRL,
431         HNGC_ADPGA_HND(volume));
432                 break;
433
434         case SET_RECSRC:
435                 /*
436                  * If more than one recording device selected,
437                  * disable the device that is currently in use.
438                  */
439                 if (hweight32(val) > 1)
440                         val &= ~tsc2101_local.recsrc;
441
442                 data = audio_tsc2101_read(TSC2101_MIXER_PGA_CTRL);
443                 data &= ~MPC_MICSEL(7); /* clear all MICSEL bits */
444
445                 if (val == SOUND_MASK_MIC) {
446                         data |=  MPC_MICSEL(1);
447                         audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, data);
448                 }
449                 else if (val == SOUND_MASK_LINE) {
450                         data |=  MPC_MICSEL(0);
451                         audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, data);
452                 }
453                 else {
454                         printk(KERN_WARNING "omap1610-tsc2101: Wrong RECSRC"
455          " value specified\n");
456                         return -EINVAL;
457                 }
458                 tsc2101_local.recsrc = val;
459                 break;
460         default:
461                 printk(KERN_WARNING "omap1610-tsc2101: Wrong tsc2101_update "
462         "flag specified\n");
463                 break;
464         }
465
466         FN_OUT(0);
467         return 0;
468 }
469
470 /*********************************************************************************
471  *
472  * mixer_open()
473  *
474  ********************************************************************************/
475 static int mixer_open(struct inode *inode, struct file *file)
476 {
477         /* Any mixer specific initialization */
478
479         /* Initalize the tsc2101 */
480         omap_tsc2101_enable();
481
482         return 0;
483 }
484
485 /*********************************************************************************
486  *
487  * mixer_release()
488  *
489  ********************************************************************************/
490 static int mixer_release(struct inode *inode, struct file *file)
491 {
492         /* Any mixer specific Un-initialization */
493         omap_tsc2101_disable();
494
495         return 0;
496 }
497
498 /*********************************************************************************
499  *
500  * mixer_ioctl()
501  *
502  ********************************************************************************/
503 static int
504 mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
505 {
506         int val;
507         int gain;
508         int ret = 0;
509         int nr = _IOC_NR(cmd);
510
511         /*
512          * We only accept mixer (type 'M') ioctls.
513          */
514         FN_IN;
515         if (_IOC_TYPE(cmd) != 'M')
516                 return -EINVAL;
517
518         DPRINTK(" 0x%08x\n", cmd);
519
520         if (cmd == SOUND_MIXER_INFO) {
521                 struct mixer_info mi;
522
523                 strncpy(mi.id, "TSC2101", sizeof(mi.id));
524                 strncpy(mi.name, "TI TSC2101", sizeof(mi.name));
525                 mi.modify_counter = tsc2101_local.mod_cnt;
526                 FN_OUT(1);
527                 return copy_to_user((void __user *)arg, &mi, sizeof(mi));
528         }
529
530         if (_IOC_DIR(cmd) & _IOC_WRITE) {
531                 ret = get_user(val, (int __user *)arg);
532                 if (ret)
533                         goto out;
534
535                 /* Ignore separate left/right channel for now,
536                  * even the codec does support it.
537                  */
538                 gain = val & 255;
539
540                 switch (nr) {
541                 case SOUND_MIXER_VOLUME:
542                         tsc2101_local.volume = val;
543                         tsc2101_local.mod_cnt++;
544                         ret = tsc2101_update(SET_VOLUME, gain);
545                         break;
546
547                 case SOUND_MIXER_LINE:
548                         tsc2101_local.line = val;
549                         tsc2101_local.mod_cnt++;
550                         ret = tsc2101_update(SET_LINE, gain);
551                         break;
552
553                 case SOUND_MIXER_MIC:
554                         tsc2101_local.mic = val;
555                         tsc2101_local.mod_cnt++;
556                         ret = tsc2101_update(SET_MIC, gain);
557                         break;
558
559                 case SOUND_MIXER_RECSRC:
560                         if ((val & SOUND_MASK_LINE) ||
561                             (val & SOUND_MASK_MIC)) {
562                                 if (tsc2101_local.recsrc != val) {
563                                         tsc2101_local.mod_cnt++;
564                                         tsc2101_update(SET_RECSRC, val);
565                                 }
566                         }
567                         else {
568                                 ret = -EINVAL;
569                         }
570                         break;
571
572                 default:
573                         ret = -EINVAL;
574                 }
575         }
576
577         if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
578                 ret = 0;
579
580                 switch (nr) {
581                 case SOUND_MIXER_VOLUME:
582                         val = tsc2101_local.volume;
583                         val = (tsc2101_local.volume << 8) |
584           tsc2101_local.volume;
585                         break;
586                 case SOUND_MIXER_LINE:
587                         val = (tsc2101_local.line << 8) |
588           tsc2101_local.line;
589                         break;
590                 case SOUND_MIXER_MIC:
591                         val = (tsc2101_local.mic << 8) |
592           tsc2101_local.mic;
593                         break;
594                 case SOUND_MIXER_RECSRC:
595                         val = tsc2101_local.recsrc;
596                         break;
597                 case SOUND_MIXER_RECMASK:
598                         val = REC_MASK;
599                         break;
600                 case SOUND_MIXER_DEVMASK:
601                         val = DEV_MASK;
602                         break;
603                 case SOUND_MIXER_CAPS:
604                         val = 0;
605                         break;
606                 case SOUND_MIXER_STEREODEVS:
607                         val = SOUND_MASK_VOLUME;
608                         break;
609                 default:
610                         val = 0;
611                         printk(KERN_WARNING "omap1610-tsc2101: unknown mixer "
612          "read ioctl flag specified\n");
613                         ret = -EINVAL;
614                         break;
615                 }
616
617                 if (ret == 0)
618                         ret = put_user(val, (int __user *)arg);
619         }
620       out:
621         FN_OUT(0);
622         return ret;
623
624 }
625
626 /*********************************************************************************
627  *
628  * omap_set_samplerate()
629  *
630  ********************************************************************************/
631 static int omap_set_samplerate(long sample_rate)
632 {
633         u8 count = 0;
634         u16 data = 0;
635         int clkgdv = 0;
636         /* wait for any frame to complete */
637         udelay(125);
638
639         /* Search for the right sample rate */
640         while ((reg_info[count].sample_rate != sample_rate) &&
641                (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
642                 count++;
643         }
644         if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
645                 printk(KERN_ERR "Invalid Sample Rate %d requested\n",
646                        (int)sample_rate);
647                 return -EPERM;
648         }
649
650         /* Set AC1 */
651         data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_1);
652         /*Clear prev settings */
653         data &= ~(AC1_DACFS(0x07) | AC1_ADCFS(0x07));
654         data |=
655             AC1_DACFS(reg_info[count].divisor) | AC1_ADCFS(reg_info[count].
656                                                            divisor);
657         audio_tsc2101_write(TSC2101_AUDIO_CTRL_1, data);
658
659         /* Set the AC3 */
660         data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_3);
661         /*Clear prev settings */
662         data &= ~(AC3_REFFS | AC3_SLVMS);
663         data |= (reg_info[count].fs_44kHz) ? AC3_REFFS : 0;
664 #ifdef TSC_MASTER
665         data |= AC3_SLVMS;
666 #endif                          /* #ifdef TSC_MASTER */
667         audio_tsc2101_write(TSC2101_AUDIO_CTRL_3, data);
668
669         /* program the PLLs */
670         if (reg_info[count].fs_44kHz) {
671                 /* 44.1 khz - 12 MHz Mclk */
672                 audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(7));    /* PVAL 1; I_VAL 7 */
673                 audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490));    /* D_VAL 5264 */
674         } else {
675                 /* 48 khz - 12 Mhz Mclk */
676                 audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(8));    /* PVAL 1; I_VAL 8 */
677                 audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780));     /* D_VAL 1920 */
678         }
679
680         audio_samplerate = sample_rate;
681
682         /* Set the sample rate */
683 #ifndef TSC_MASTER
684         clkgdv =
685             DEFAULT_MCBSP_CLOCK / (sample_rate *
686                                    (DEFAULT_BITPERSAMPLE * 2 - 1));
687         if (clkgdv)
688                 initial_config.srgr1 =
689                     (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
690         else
691                 return (1);
692
693         /* Stereo Mode */
694         initial_config.srgr2 =
695             (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
696 #else
697         initial_config.srgr1 =
698             (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
699         initial_config.srgr2 =
700             ((GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
701
702 #endif                          /* end of #ifdef TSC_MASTER */
703         omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
704
705         return 0;
706 }
707
708 /*********************************************************************************
709  *
710  * omap_tsc2101_initialize() [hw_init() ]
711  *
712  ********************************************************************************/
713 static void omap_tsc2101_initialize(void *dummy)
714 {
715
716         DPRINTK("omap_tsc2101_initialize entry\n");
717
718         /* initialize with default sample rate */
719         audio_samplerate = AUDIO_RATE_DEFAULT;
720
721         omap_mcbsp_request(AUDIO_MCBSP);
722
723         /* if configured, then stop mcbsp */
724         omap_mcbsp_stop(AUDIO_MCBSP);
725
726         omap_tsc2101_enable();
727
728         omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
729         omap_mcbsp_start(AUDIO_MCBSP);
730         tsc2101_configure();
731
732 #ifdef TEST_KEYCLICK
733         tsc2101_testkeyclick();
734 #endif
735
736 #ifdef TONE_GEN
737         toneGen();
738 #endif
739
740         DPRINTK("omap_tsc2101_initialize exit\n");
741 }
742
743 /*********************************************************************************
744  *
745  * omap_tsc2101_shutdown() [hw_shutdown() ]
746  *
747  ********************************************************************************/
748 static void omap_tsc2101_shutdown(void *dummy)
749 {
750         /*
751            Turn off codec after it is done.
752            Can't do it immediately, since it may still have
753            buffered data.
754
755            Wait 20ms (arbitrary value) and then turn it off.
756          */
757
758         FN_IN;
759         set_current_state(TASK_INTERRUPTIBLE);
760         schedule_timeout(2);
761
762         omap_mcbsp_stop(AUDIO_MCBSP);
763         omap_mcbsp_free(AUDIO_MCBSP);
764
765         audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL,
766                             ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
767
768         omap_tsc2101_disable();
769
770         FN_OUT(0);
771 }
772
773 /*********************************************************************************
774  *
775  * tsc2101_configure
776  *
777  ********************************************************************************/
778 static void tsc2101_configure(void)
779 {
780         FN_IN;
781
782         audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, 0x0000);
783
784         /*Mute Analog Sidetone */
785         /*Select MIC_INHED input for headset */
786         /*Cell Phone In not connected */
787         audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL,
788                             MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
789
790         /* Set record source */
791         tsc2101_update(SET_RECSRC, tsc2101_local.recsrc);
792
793         /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
794         /* 1dB AGC hysteresis */
795         /* MICes bias 2V */
796         audio_tsc2101_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
797
798         /* Set codec output volume */
799         audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, 0x0000);
800
801         /* DAC left and right routed to SPK2 */
802         /* SPK1/2 unmuted */
803         audio_tsc2101_write(TSC2101_AUDIO_CTRL_5,
804                             AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
805                             AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
806                             AC5_HDSCPTC);
807
808         /* OUT8P/N muted, CPOUT muted */
809
810         audio_tsc2101_write(TSC2101_AUDIO_CTRL_6,
811                             AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
812                             AC6_VGNDSCPTC);
813
814         /* Headset/Hook switch detect disabled */
815         audio_tsc2101_write(TSC2101_AUDIO_CTRL_7, 0x0000);
816
817         /* Left line input volume control */
818         tsc2101_update(SET_LINE, tsc2101_local.line);
819
820         /* mic input volume control */
821         tsc2101_update(SET_MIC, tsc2101_local.mic);
822
823         /* Left/Right headphone channel volume control */
824         /* Zero-cross detect on */
825         tsc2101_update(SET_VOLUME, tsc2101_local.volume);
826
827         /* clock configuration */
828         omap_set_samplerate(audio_samplerate);
829
830 #ifdef TSC_DUMP_REGISTERS
831         tsc2101_dumpRegisters();
832 #endif
833
834         FN_OUT(0);
835 }
836
837 #ifdef PROC_SUPPORT
838 static void tsc2101_start(void)
839 {
840         FN_IN;
841
842         audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, 0x0000);
843
844         /*Mute Analog Sidetone */
845         /*Select MIC_INHED input for headset */
846         /*Cell Phone In not connected */
847         audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL,
848                             MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
849
850         /* Set record source */
851         tsc2101_update(SET_RECSRC, tsc2101_local.recsrc);
852
853         /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
854         /* 1dB AGC hysteresis */
855         /* MICes bias 2V */
856         audio_tsc2101_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
857
858         /* Set codec output volume */
859         audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, 0x0000);
860
861         /* DAC left and right routed to SPK2 */
862         /* SPK1/2 unmuted */
863         audio_tsc2101_write(TSC2101_AUDIO_CTRL_5,
864                             AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
865                             AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
866                             AC5_HDSCPTC);
867
868         /* OUT8P/N muted, CPOUT muted */
869
870         audio_tsc2101_write(TSC2101_AUDIO_CTRL_6,
871                             AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
872                             AC6_VGNDSCPTC);
873
874         /* Headset/Hook switch detect disabled */
875         audio_tsc2101_write(TSC2101_AUDIO_CTRL_7, 0x0000);
876
877         /* Left line input volume control */
878         tsc2101_update(SET_LINE, tsc2101_local.line);
879
880         /* mic input volume control */
881         tsc2101_update(SET_MIC, tsc2101_local.mic);
882
883         /* Left/Right headphone channel volume control */
884         /* Zero-cross detect on */
885         tsc2101_update(SET_VOLUME, tsc2101_local.volume);
886
887         FN_OUT(0);
888
889 }
890 #endif
891
892 /******************************************************************************************
893  *
894  * All generic ioctl's are handled by audio_ioctl() [File: omap-audio.c]. This
895  * routine handles some platform specific ioctl's
896  *
897  ******************************************************************************************/
898 static int
899 omap_tsc2101_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
900 {
901         long val;
902         int ret = 0;
903
904         DPRINTK(" 0x%08x\n", cmd);
905
906         /*
907          * These are platform dependent ioctls which are not handled by the
908          * generic omap-audio module.
909          */
910         switch (cmd) {
911         case SNDCTL_DSP_STEREO:
912                 ret = get_user(val, (int __user *)arg);
913                 if (ret)
914                         return ret;
915                 /* the AIC23 is stereo only */
916                 ret = (val == 0) ? -EINVAL : 1;
917                 FN_OUT(1);
918                 return put_user(ret, (int __user *)arg);
919
920         case SNDCTL_DSP_CHANNELS:
921         case SOUND_PCM_READ_CHANNELS:
922                 /* the AIC23 is stereo only */
923                 FN_OUT(2);
924                 return put_user(2, (long __user *)arg);
925
926         case SNDCTL_DSP_SPEED:
927                 ret = get_user(val, (long __user *)arg);
928                 if (ret)
929                         break;
930                 ret = omap_set_samplerate(val);
931                 if (ret)
932                         break;
933                 /* fall through */
934
935         case SOUND_PCM_READ_RATE:
936                 FN_OUT(3);
937                 return put_user(audio_samplerate, (long __user *)arg);
938
939         case SOUND_PCM_READ_BITS:
940         case SNDCTL_DSP_SETFMT:
941         case SNDCTL_DSP_GETFMTS:
942                 /* we can do 16-bit only */
943                 FN_OUT(4);
944                 return put_user(AFMT_S16_LE, (long __user *)arg);
945
946         default:
947                 /* Maybe this is meant for the mixer (As per OSS Docs) */
948                 FN_OUT(5);
949                 return mixer_ioctl(inode, file, cmd, arg);
950         }
951
952         FN_OUT(0);
953         return ret;
954 }
955
956 /*********************************************************************************
957  *
958  * module_probe for TSC2101
959  *
960  ********************************************************************************/
961 static int omap_tsc2101_probe(void)
962 {
963         FN_IN;
964
965         /* Get the fops from audio oss driver */
966         if (!(omap_audio_fops = audio_get_fops())) {
967                 printk(KERN_ERR "Unable to Get the FOPs of Audio OSS driver\n");
968                 audio_unregister_codec(&tsc2101_state);
969                 return -EPERM;
970         }
971
972         /* register devices */
973         audio_dev_id = register_sound_dsp(omap_audio_fops, -1);
974         mixer_dev_id = register_sound_mixer(&omap_mixer_fops, -1);
975
976 #ifdef PROC_SUPPORT
977         create_proc_read_entry(PROC_START_FILE, 0 /* default mode */ ,
978                                NULL /* parent dir */ ,
979                                codec_start, NULL /* client data */ );
980
981         create_proc_read_entry(PROC_STOP_FILE, 0 /* default mode */ ,
982                                NULL /* parent dir */ ,
983                                codec_stop, NULL /* client data */ );
984 #endif
985
986         /* Announcement Time */
987         printk(KERN_INFO PLATFORM_NAME " " CODEC_NAME
988                " Audio support initialized\n");
989
990         FN_OUT(0);
991         return 0;
992 }
993
994 /*********************************************************************************
995  *
996  * Module Remove for TSC2101
997  *
998  ********************************************************************************/
999 static void omap_tsc2101_remove(void)
1000 {
1001         FN_IN;
1002         /* Un-Register the codec with the audio driver */
1003         unregister_sound_dsp(audio_dev_id);
1004         unregister_sound_mixer(mixer_dev_id);
1005
1006 #ifdef PROC_SUPPORT
1007         remove_proc_entry(PROC_START_FILE, NULL);
1008         remove_proc_entry(PROC_STOP_FILE, NULL);
1009 #endif
1010         FN_OUT(0);
1011
1012 }
1013
1014 /*********************************************************************************
1015  *
1016  * Module Suspend for TSC2101
1017  *
1018  ********************************************************************************/
1019 static int omap_tsc2101_suspend(void)
1020 {
1021
1022         FN_OUT(0);
1023         return 0;
1024 }
1025
1026 /*********************************************************************************
1027  *
1028  * Module Resume for TSC2101
1029  *
1030  ********************************************************************************/
1031 static int omap_tsc2101_resume(void)
1032 {
1033
1034         FN_OUT(0);
1035         return 0;
1036 }
1037
1038 /*********************************************************************************
1039  *
1040  * module_init for TSC2101
1041  *
1042  ********************************************************************************/
1043 static int __init audio_tsc2101_init(void)
1044 {
1045
1046         int err = 0;
1047         FN_IN;
1048
1049         if (machine_is_omap_osk() || machine_is_omap_innovator())
1050                 return -ENODEV;
1051
1052         /* register the codec with the audio driver */
1053         if ((err = audio_register_codec(&tsc2101_state))) {
1054                 printk(KERN_ERR
1055                        "Failed to register TSC driver with Audio OSS Driver\n");
1056         }
1057         FN_OUT(err);
1058         return err;
1059 }
1060
1061 /*********************************************************************************
1062  *
1063  * module_exit for TSC2101
1064  *
1065  ********************************************************************************/
1066 static void __exit audio_tsc2101_exit(void)
1067 {
1068
1069         FN_IN;
1070         (void)audio_unregister_codec(&tsc2101_state);
1071         FN_OUT(0);
1072         return;
1073 }
1074
1075 /**************************** DEBUG FUNCTIONS ***********************************/
1076
1077 /*********************************************************************************
1078  * TEST_KEYCLICK:
1079  * This is a test to generate various keyclick sound on tsc.
1080  * verifies if the tsc and the spi interfaces are operational.
1081  *
1082  ********************************************************************************/
1083 #ifdef TEST_KEYCLICK
1084 void tsc2101_testkeyclick(void)
1085 {
1086         u8 freq = 0;
1087         u16 old_reg_val, reg_val;
1088         u32 uDummyVal = 0;
1089         u32 uTryVal = 0;
1090
1091         old_reg_val = audio_tsc2101_read(TSC2101_AUDIO_CTRL_2);
1092
1093         /* Keyclick active, max amplitude and longest key click len(32 period) */
1094         printk(KERN_INFO " TESTING KEYCLICK\n Listen carefully NOW....\n");
1095         printk(KERN_INFO " OLD REG VAL=0x%x\n", old_reg_val);
1096         /* try all frequencies */
1097         for (; freq < 8; freq++) {
1098                 /* Keyclick active, max amplitude and longest key click len(32 period) */
1099                 reg_val = old_reg_val | AC2_KCLAC(0x7) | AC2_KCLLN(0xF);
1100                 uDummyVal = 0;
1101                 uTryVal = 0;
1102                 printk(KERN_INFO "\n\nTrying frequency %d reg val= 0x%x\n",
1103                        freq, reg_val | AC2_KCLFRQ(freq) | AC2_KCLEN);
1104                 audio_tsc2101_write(TSC2101_AUDIO_CTRL_2,
1105                                     reg_val | AC2_KCLFRQ(freq) | AC2_KCLEN);
1106                 printk("DONE. Wait 10 ms ...\n");
1107                 /* wait till the kclk bit is auto cleared! time out also to be considered. */
1108                 while (audio_tsc2101_read(TSC2101_AUDIO_CTRL_2) & AC2_KCLEN) {
1109                         udelay(3);
1110                         uTryVal++;
1111                         if (uTryVal > 2000) {
1112                                 printk(KERN_ERR
1113                                        "KEYCLICK TIMED OUT! freq val=%d, POSSIBLE ERROR!\n",
1114                                        freq);
1115                                 printk(KERN_INFO
1116                                        "uTryVal == %d: Read back new reg val= 0x%x\n",
1117                                        uTryVal,
1118                                        audio_tsc2101_read
1119                                        (TSC2101_AUDIO_CTRL_2));
1120                                 /* clear */
1121                                 audio_tsc2101_write(TSC2101_AUDIO_CTRL_2, 0x00);
1122                                 break;
1123                         }
1124                 }
1125         }
1126         /* put the old value back */
1127         audio_tsc2101_write(TSC2101_AUDIO_CTRL_2, old_reg_val);
1128         printk(KERN_INFO " KEYCLICK TEST COMPLETE\n");
1129
1130 }                               /* End of tsc2101_testkeyclick */
1131
1132 #endif                          /* TEST_KEYCLICK */
1133
1134 /*********************************************************************************
1135  * TONEGEN:
1136  * This is a test to generate a rather unpleasant sound..
1137  * verifies if the mcbsp is active (requires MCBSP_DIRECT_RW to be active on McBSP)
1138  *
1139  ********************************************************************************/
1140 #ifdef TONE_GEN
1141 /* Generates a shrill tone */
1142 u16 tone[] = {
1143         0x0ce4, 0x0ce4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
1144         0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
1145         0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
1146         0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
1147         0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
1148         0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
1149         0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
1150         0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
1151         0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
1152         0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
1153         0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000,
1154         0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
1155         0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
1156         0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
1157         0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
1158         0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
1159         0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
1160         0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
1161         0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
1162         0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
1163         0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
1164         0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000,
1165         0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
1166         0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
1167         0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
1168         0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
1169         0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
1170         0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
1171         0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
1172         0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
1173         0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
1174         0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
1175         0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000
1176 };
1177
1178 void toneGen(void)
1179 {
1180         int count = 0;
1181         int ret = 0;
1182         printk(KERN_INFO "TONE GEN TEST :");
1183
1184         for (count = 0; count < 5000; count++) {
1185                 int bytes;
1186                 for (bytes = 0; bytes < sizeof(tone) / 2; bytes++) {
1187                         ret = omap_mcbsp_pollwrite(AUDIO_MCBSP, tone[bytes]);
1188                         if (ret == -1) {
1189                                 /* retry */
1190                                 bytes--;
1191                         } else if (ret == -2) {
1192                                 printk(KERN_INFO "ERROR:bytes=%d\n", bytes);
1193                                 return;
1194                         }
1195                 }
1196         }
1197         printk(KERN_INFO "SUCCESS\n");
1198 }
1199
1200 #endif                          /* End of TONE_GEN */
1201
1202 /*********************************************************************************
1203  *
1204  * TSC_DUMP_REGISTERS:
1205  * This will dump the entire register set of Page 2 tsc2101. 
1206  * Useful for major goof ups
1207  *
1208  ********************************************************************************/
1209 #ifdef TSC_DUMP_REGISTERS
1210 static void tsc2101_dumpRegisters(void)
1211 {
1212         int i = 0;
1213         u16 data = 0;
1214         printk("TSC 2101 Register dump for Page 2 \n");
1215         for (i = 0; i < 0x27; i++) {
1216                 data = audio_tsc2101_read(i);
1217                 printk(KERN_INFO "Register[%x]=0x%04x\n", i, data);
1218
1219         }
1220 }
1221 #endif                          /* End of #ifdef TSC_DUMP_REGISTERS */
1222
1223 #ifdef PROC_SUPPORT
1224 static int codec_start(char *buf, char **start, off_t offset, int count,
1225                        int *eof, void *data)
1226 {
1227         omap_tsc2101_enable();
1228         tsc2101_start();
1229         printk("Codec initialization done.\n");
1230         return 0;
1231 }
1232 static int codec_stop(char *buf, char **start, off_t offset, int count,
1233                       int *eof, void *data)
1234 {
1235
1236         omap_tsc2101_disable();
1237         audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL,
1238                             ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
1239         printk("Codec shutdown.\n");
1240         return 0;
1241 }
1242 #endif
1243
1244 /*********************************************************************************
1245  *
1246  * Other misc management, registration etc
1247  *
1248  ********************************************************************************/
1249 module_init(audio_tsc2101_init);
1250 module_exit(audio_tsc2101_exit);
1251
1252 MODULE_AUTHOR("Texas Instruments");
1253 MODULE_DESCRIPTION
1254     ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec.");
1255 MODULE_LICENSE("GPL");