/* * linux/sound/oss/davinci-audio-ak4353.c * * Glue driver for AK4353 for Davinci processors * * Copyright (C) 2006 Texas Instruments, Inc. * * This package is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * History: * ------- * 2005-10-18 Rishi Bhattacharya - Support for AK4353 codec and Davinci DM644x Processor */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include "davinci-ak4353.h" #include "davinci-audio.h" #include "davinci-audio-dma-intfc.h" #ifdef CONFIG_PROC_FS #include #define PROC_START_FILE "driver/ak4353-audio-start" #define PROC_STOP_FILE "driver/ak4353-audio-stop" #endif //#define DEBUG #ifdef DEBUG #define DPRINTK(ARGS...) do { \ printk("<%s>: ",__FUNCTION__);printk(ARGS); \ } while (0) #else #define DPRINTK( x... ) #endif #define CODEC_NAME "AK4353" #define PLATFORM_NAME "DAVINCI" /* Define to set the AK4353 as the master w.r.t McBSP */ #define AK4353_MASTER #undef AK4353_MASTER /* * AUDIO related MACROS */ #define AC3 0 #define PTEST 0 #define DEFAULT_BITPERSAMPLE 16 #if AC3 || PTEST #define AUDIO_RATE_DEFAULT 48000 #define MCBSP_CLKRP 18432000 #define CKS_DEFAULT 2 /* 384fs */ #define DFS_DEFAULT 0 /* normal speed */ #else #define AUDIO_RATE_DEFAULT 44100 #define MCBSP_CLKRP 22579200 #define CKS_DEFAULT 4 /* 512fs */ #define DFS_DEFAULT 0 /* normal speed */ #endif /* Select the McBSP For Audio */ #define AUDIO_MCBSP DAVINCI_MCBSP1 #define AVM_HPON 0 /* */ #define AVM_INPUT 0 #if AVM_INPUT #define REC_MASK (SOUND_MASK_LINE | SOUND_MASK_MIC) #else #define REC_MASK 0 #endif #define DEV_MASK (REC_MASK | SOUND_MASK_VOLUME) #define MONO 1 #define STEREO 2 #define SET_VOLUME 1 #define SET_LINE 2 #define SET_MIC 3 #define SET_RECSRC 4 #define SET_IGAIN 5 #define SET_OGAIN 6 #define SET_BASS 7 #define SET_TREBLE 8 #define SET_MICBIAS 9 #define DEFAULT_OUTPUT_VOLUME 100 #define OUTPUT_VOLUME_MIN 0 #define OUTPUT_VOLUME_MAX 255 #define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN) #define NUMBER_SAMPLE_RATES_SUPPORTED 11 static audio_stream_t output_stream = { .id = "AK4353 out", .dma_dev = DAVINCI_DMA_MCBSP1_TX, .input_or_output = FMODE_WRITE }; static int audio_dev_id, mixer_dev_id; static struct ak4353_local_info { u8 volume; u16 volume_reg; int nochan; u8 bass; u8 treble; int mod_cnt; } ak4353_local; struct sample_rate_reg_info { u32 sample_rate; u32 Fsref; float divider; u8 data; }; /* To Store the default sample rate */ static long audio_samplerate = AUDIO_RATE_DEFAULT; extern struct clk *davinci_mcbsp_get_clock(void); /* DAC USB-mode sampling rates*/ static const struct sample_rate_reg_info reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = { /* {sample_rate, Fsref, divider, data}*/ {96000, 96000, 1, 0x00}, {88200, 88200, 1, 0x00}, {48000, 48000, 1, 0x00}, {44100, 44100, 1, 0x00}, {32000, 48000, 1.5, 0x11}, {24000, 96000, 4, 0x66}, {22050, 44100, 2, 0x22}, {16000, 48000, 3, 0x44}, {12000, 48000, 4, 0x66}, {11025, 44100, 4, 0x66}, {8000, 48000, 6, 0xAA}, }; static struct davinci_mcbsp_reg_cfg initial_config = { .spcr2 = FREE | XINTM(3), .spcr1 = RINTM(3), .rcr2 = RWDLEN2(DAVINCI_MCBSP_WORD_16), .rcr1 = RFRLEN1(1) | RWDLEN1(DAVINCI_MCBSP_WORD_16), .xcr2 = XWDLEN2(DAVINCI_MCBSP_WORD_16) | XFIG, .xcr1 = XFRLEN1(1) | XWDLEN1(DAVINCI_MCBSP_WORD_16), .srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1), .srgr2 = FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1), #ifndef AK4353_MASTER /* configure McBSP to be the I2S master */ .pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP, #else /* configure McBSP to be the I2S slave */ .pcr0 = CLKXP | CLKRP, #endif /* AK4353_MASTER */ }; static void davinci_ak4353_initialize(void *dummy); static void davinci_ak4353_shutdown(void *dummy); static int davinci_ak4353_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg); static int davinci_ak4353_probe(void); #ifdef MODULE static void davinci_ak4353_remove(void); #endif static int davinci_ak4353_suspend(void); static int davinci_ak4353_resume(void); static inline void ak4353_configure(void); static int mixer_open(struct inode *inode, struct file *file); static int mixer_release(struct inode *inode, struct file *file); static int mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg); #ifdef CONFIG_PROC_FS static int codec_start(char *buf, char **start, off_t offset, int count, int *eof, void *data); static int codec_stop(char *buf, char **start, off_t offset, int count, int *eof, void *data); #endif /* File Op structure for mixer */ static struct file_operations davinci_mixer_fops = { .open = mixer_open, .release = mixer_release, .ioctl = mixer_ioctl, .owner = THIS_MODULE }; /* To store characteristic info regarding the codec for the audio driver */ static audio_state_t ak4353_state = { .owner = THIS_MODULE, .output_stream = &output_stream, .input_stream = NULL, /* .need_tx_for_rx = 1, //Once the Full Duplex works */ .need_tx_for_rx = 0, .hw_init = davinci_ak4353_initialize, .hw_shutdown = davinci_ak4353_shutdown, .client_ioctl = davinci_ak4353_ioctl, .hw_probe = davinci_ak4353_probe, .hw_remove = __exit_p(davinci_ak4353_remove), .hw_suspend = davinci_ak4353_suspend, .hw_resume = davinci_ak4353_resume, .sem = __SEMAPHORE_INIT(ak4353_state.sem, 1), }; /* This will be defined in the audio.h */ static struct file_operations *davinci_audio_fops; extern int ak4353_write_value(u8 reg, u16 value); /* TLV320AK4353 write */ static __inline__ void audio_ak4353_write(u8 address, u16 data) { DPRINTK("ak4353 write reg=0x%02x val 0x%04x\n", address, data); if (ak4353_write_value(address, data) < 0) printk(KERN_INFO "ak4353 write failed for reg = %d\n", address); } static int ak4353_update(int flag, int val) { u16 volume; u16 gain; /* Ignore separate left/right channel for now, even the codec does support it. */ val &= 0xff; switch (flag) { case SET_VOLUME: if (val < 0 || val > 100) { DPRINTK("Trying a bad volume value(%d)!\n", val); return -EPERM; } // Convert 0 -> 100 volume to 0x77 (LHV_MIN) -> 0x00 (LHV_MAX) volume = ((val * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MIN; ak4353_local.volume_reg = volume; if (ak4353_local.nochan == STEREO) { audio_ak4353_write(0x03, ak4353_local.volume_reg); audio_ak4353_write(0x04, ak4353_local.volume_reg); } else if (ak4353_local.nochan == MONO) { audio_ak4353_write(0x03, ak4353_local.volume_reg); audio_ak4353_write(0x04, ak4353_local.volume_reg); } break; case SET_BASS: break; case SET_TREBLE: break; } return 0; } static int mixer_open(struct inode *inode, struct file *file) { /* Any mixer specific initialization */ return 0; } static int mixer_release(struct inode *inode, struct file *file) { /* Any mixer specific Un-initialization */ return 0; } static int mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) { int val; int ret = 0; int nr = _IOC_NR(cmd); /* * We only accept mixer (type 'M') ioctls. */ if (_IOC_TYPE(cmd) != 'M') return -EINVAL; DPRINTK(" 0x%08x\n", cmd); if (cmd == SOUND_MIXER_INFO) { struct mixer_info mi; strncpy(mi.id, "AK4353", sizeof(mi.id)); strncpy(mi.name, "AKM AK4353", sizeof(mi.name)); mi.modify_counter = ak4353_local.mod_cnt; return copy_to_user((void *)arg, &mi, sizeof(mi)); } if (_IOC_DIR(cmd) & _IOC_WRITE) { ret = get_user(val, (int *)arg); if (ret) goto out; switch (nr) { case SOUND_MIXER_VOLUME: ak4353_local.mod_cnt++; ret = ak4353_update(SET_VOLUME, val); if (!ret) ak4353_local.volume = val; break; case SOUND_MIXER_BASS: ak4353_local.mod_cnt++; ret = ak4353_update(SET_BASS, val); if (!ret) ak4353_local.bass = val; break; case SOUND_MIXER_TREBLE: ak4353_local.mod_cnt++; ret = ak4353_update(SET_TREBLE, val); if (!ret) ak4353_local.treble = val; break; default: ret = -EINVAL; } } if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) { ret = 0; switch (nr) { case SOUND_MIXER_VOLUME: val = ak4353_local.volume; break; case SOUND_MIXER_BASS: val = ak4353_local.bass; break; case SOUND_MIXER_TREBLE: val = ak4353_local.treble; break; case SOUND_MIXER_CAPS: val = 0; break; default: val = 0; ret = -EINVAL; break; } if (ret == 0) ret = put_user(val, (int *)arg); } out: return ret; } static int davinci_set_samplerate(long sample_rate) { u8 count = 0; /* wait for any frame to complete */ udelay(125); /* Search for the right sample rate */ while ((reg_info[count].sample_rate != sample_rate) && (count < NUMBER_SAMPLE_RATES_SUPPORTED)) { count++; } if (count == NUMBER_SAMPLE_RATES_SUPPORTED) { DPRINTK("Invalid Sample Rate %d requested\n", (int)sample_rate); return -EPERM; } /* CODEC DATAPATH SETUP */ audio_samplerate = sample_rate; #ifndef AK4353_MASTER { int clkgdv = 0; unsigned long clkval = 0; struct clk *mbspclk; /* Set Sample Rate at McBSP Formula : Codec System Clock = Input clock to McBSP; clkgdv = ((Codec System Clock / (SampleRate * BitsPerSample * 2)) - 1); FWID = BitsPerSample - 1; FPER = (BitsPerSample * 2) - 1; */ mbspclk = davinci_mcbsp_get_clock(); if (mbspclk == NULL) { DPRINTK(" Failed to get internal clock to MCBSP"); return -EPERM; } clkval = clk_get_rate(mbspclk); DPRINTK("mcbsp_clk = %ld\n", clkval); clkval = MCBSP_CLKRP; if (clkval) { clkgdv = (clkval / (sample_rate * DEFAULT_BITPERSAMPLE * 2)) - 1; } else { DPRINTK(" Failed to get the MCBSP clock\n"); return -EPERM; } DPRINTK("clkgdv = %d\n", clkgdv); if (clkgdv > 255 || clkgdv < 0) { /* For requested sampling rate, the input clock to MCBSP cant be devided down to get the in range clock devider value for 16 bits sample */ DPRINTK("Invalid Sample Rate %d requested\n", (int)sample_rate); return -EPERM; } initial_config.srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv)); initial_config.srgr2 = (FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)); initial_config.pcr0 = FSXM | FSRM | CLKXM | SCLKME | CLKXP | FSXP; davinci_mcbsp_stop(AUDIO_MCBSP); davinci_mcbsp_config(AUDIO_MCBSP, &initial_config); } #endif /* AK4353_MASTER */ return 0; } static void davinci_ak4353_shutdown(void *dummy) { /* Turn off codec after it is done. Can't do it immediately, since it may still have buffered data. Wait 20ms (arbitrary value) and then turn it off. */ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(2); davinci_mcbsp_stop(AUDIO_MCBSP); davinci_mcbsp_free(AUDIO_MCBSP); /* Self clearing ak4353 software reset */ //audio_ak4353_write(1, 0x80); } static void davinci_set_mono_stereo(int mode) { if (mode == MONO) { } else if (mode == STEREO) { } else { DPRINTK(" REQUEST FOR INVALID MODE\n"); } } /* AK4353 Register */ #define REG_CTRL1 0x00 #define RSTN 0x01 #define DIF(mode) (((mode)&0x7)<<1) /*default 5=101 I2S*/ #define DIF_LSB16 0 #define DIF_LSB18 1 #define DIF_LSB20 2 #define DIF_LSB24 3 #define DIF_MSB24 4 #define DIF_I2S 5 #define REG_CTRL2 0x01 #define CKS(clksel) (((clksel)&0x7)<<1) /*default 0 */ #define DFS(mode) (((mode)&0x3)<<4) /*default 0 */ #define REG_CTRL3 0x02 #define SMUTE 0x01 #define ATC 0x20 #define DEM(resp) (((resp)&0x3)<<2) #define PL(mode) (((mode)&0xf)<<4) #define REG_ATTL 0x03 #define REG_ATTR 0x04 #define REG_TX 0x05 #define TXE 0x01 #define INVALID 0x02 #define REG_CHSTAT1 0x06 #define REG_CHSTAT2 0x07 static inline void ak4353_configure() { DPRINTK(" CONFIGURING AK4353\n"); /* reset */ audio_ak4353_write(REG_CTRL1,DIF(DIF_LSB16)); audio_ak4353_write(REG_CTRL2,CKS(CKS_DEFAULT)|DFS(DFS_DEFAULT)); /* configure */ audio_ak4353_write(REG_CTRL3,DEM(1)|PL(9)); #if AC3 audio_ak4353_write(REG_TX,TXE|INVALID); audio_ak4353_write(REG_CHSTAT1,0x11); #else audio_ak4353_write(REG_TX,TXE); audio_ak4353_write(REG_CHSTAT1,0x00); #endif audio_ak4353_write(REG_CHSTAT2,0x8C); /* out of reset */ audio_ak4353_write(REG_CTRL1,DIF(DIF_LSB16)|RSTN); audio_ak4353_write(REG_CTRL2,CKS(CKS_DEFAULT)|DFS(DFS_DEFAULT)|RSTN); davinci_set_mono_stereo(ak4353_local.nochan); ak4353_update(SET_VOLUME, ak4353_local.volume); } static void davinci_ak4353_initialize(void *dummy) { DPRINTK("entry\n"); /* initialize with default sample rate */ audio_samplerate = AUDIO_RATE_DEFAULT; if (davinci_mcbsp_request(AUDIO_MCBSP) < 0) { DPRINTK("MCBSP request failed\n"); return; } /* if configured, then stop mcbsp */ davinci_mcbsp_stop(AUDIO_MCBSP); /* configure ak4353 with default params */ ak4353_configure(); /* set initial (default) sample rate */ davinci_set_samplerate(audio_samplerate); #ifdef AK4353_MASTER davinci_mcbsp_config(AUDIO_MCBSP, &initial_config); #endif DPRINTK("exit\n"); } static int davinci_ak4353_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) { long val; int ret = 0; DPRINTK(" 0x%08x\n", cmd); /* * These are platform dependent ioctls which are not handled by the * generic davinci-audio module. */ switch (cmd) { case SNDCTL_DSP_STEREO: ret = get_user(val, (int *)arg); if (ret) return ret; /* the Davinci supports AK4353 as stereo, mono on stereo jack */ ret = (val == 0) ? -EINVAL : 1; return put_user(ret, (int *)arg); case SNDCTL_DSP_CHANNELS: ret = get_user(val, (long *)arg); if (ret) { DPRINTK("get_user failed\n"); break; } if (val == STEREO) { DPRINTK("Driver support for AK4353 as stereo\n"); ak4353_local.nochan = STEREO; davinci_set_mono_stereo(ak4353_local.nochan); } else if (val == MONO) { DPRINTK("Driver support for AK4353 as mono\n"); ak4353_local.nochan = MONO; davinci_set_mono_stereo(ak4353_local.nochan); } else { DPRINTK ("Driver support for AK4353 as stereo/mono mode\n"); return -EPERM; } case SOUND_PCM_READ_CHANNELS: /* the Davinci supports AK4353 as stereo, mono on stereo jack */ if (ak4353_local.nochan == MONO) return put_user(MONO, (long *)arg); else return put_user(STEREO, (long *)arg); case SNDCTL_DSP_SPEED: ret = get_user(val, (long *)arg); if (ret) { DPRINTK("get_user failed\n"); break; } ret = davinci_set_samplerate(val); if (ret) { DPRINTK("davinci_set_samplerate failed\n"); break; } /* fall through */ case SOUND_PCM_READ_RATE: return put_user(audio_samplerate, (long *)arg); case SNDCTL_DSP_SETFMT: /* set Format */ ret = get_user(val, (long *)arg); if (ret) { DPRINTK("get_user failed\n"); break; } #if 0 audio_ak4353_write( ((val>>8)&0xff), val & 0xff ); #else if (val != AFMT_S16_LE) { DPRINTK ("Driver supports only AFMT_S16_LE audio format\n"); return -EPERM; } #endif case SOUND_PCM_READ_BITS: case SNDCTL_DSP_GETFMTS: /* we can do 16-bit only */ return put_user(AFMT_S16_LE, (long *)arg); default: /* Maybe this is meant for the mixer (As per OSS Docs) */ return mixer_ioctl(inode, file, cmd, arg); } return ret; } static int davinci_ak4353_probe(void) { /* Get the fops from audio oss driver */ if (!(davinci_audio_fops = audio_get_fops())) { DPRINTK ("Unable to get the file operations for AK4353 OSS driver\n"); audio_unregister_codec(&ak4353_state); return -EPERM; } ak4353_local.volume = DEFAULT_OUTPUT_VOLUME; ak4353_local.nochan = STEREO; ak4353_local.mod_cnt = 0; /* register devices */ audio_dev_id = register_sound_dsp(davinci_audio_fops, -1); mixer_dev_id = register_sound_mixer(&davinci_mixer_fops, -1); #ifdef CONFIG_PROC_FS create_proc_read_entry(PROC_START_FILE, 0 /* default mode */ , NULL /* parent dir */ , codec_start, NULL /* client data */ ); create_proc_read_entry(PROC_STOP_FILE, 0 /* default mode */ , NULL /* parent dir */ , codec_stop, NULL /* client data */ ); #endif /* Announcement Time */ DPRINTK(PLATFORM_NAME " " CODEC_NAME " audio support initialized\n"); return 0; } #ifdef MODULE static void __exit davinci_ak4353_remove(void) { /* Un-Register the codec with the audio driver */ unregister_sound_dsp(audio_dev_id); unregister_sound_mixer(mixer_dev_id); #ifdef CONFIG_PROC_FS remove_proc_entry(PROC_START_FILE, NULL); remove_proc_entry(PROC_STOP_FILE, NULL); #endif } #endif /* MODULE */ static int davinci_ak4353_suspend(void) { /* Empty for the moment */ return 0; } static int davinci_ak4353_resume(void) { /* Empty for the moment */ return 0; } static int __init audio_ak4353_init(void) { int err = 0; /* register the codec with the audio driver */ if ((err = audio_register_codec(&ak4353_state))) { DPRINTK ("Failed to register AK4353 driver with Audio OSS Driver\n"); } else { DPRINTK("codec driver register success\n"); } return err; } static void __exit audio_ak4353_exit(void) { (void)audio_unregister_codec(&ak4353_state); return; } #ifdef CONFIG_PROC_FS static int codec_start(char *buf, char **start, off_t offset, int count, int *eof, void *data) { void *foo = NULL; davinci_ak4353_initialize(foo); DPRINTK("AK4353 codec initialization done.\n"); return 0; } static int codec_stop(char *buf, char **start, off_t offset, int count, int *eof, void *data) { void *foo = NULL; davinci_ak4353_shutdown(foo); DPRINTK("AK4353 codec shutdown.\n"); return 0; } #endif /* CONFIG_PROC_FS */ module_init(audio_ak4353_init); module_exit(audio_ak4353_exit); MODULE_AUTHOR("AVM"); MODULE_DESCRIPTION("Glue audio driver for the AKM AK4353 codec."); MODULE_LICENSE("GPL");