📄 omap2-audio-twl4030.c
字号:
if (mcbsp_interface_acquired > 0) { if (mode == SNDRV_PCM_STREAM_CAPTURE) { ret = omap2_mcbsp_set_recv_params(AUDIO_MCBSP, &(plat_mcbsp_config.rx_params)); if (ret < 0) { printk(KERN_ERR "RECV params failed"); goto transfer_exit; } } else { ret = omap2_mcbsp_set_trans_params(AUDIO_MCBSP, &(plat_mcbsp_config. tx_params)); if (ret < 0) { printk(KERN_ERR "TX params failed"); goto transfer_exit; } } } transfer_exit: FN_OUT(ret); return ret;}/** * @brief omap_twl4030_initialize * * @param dummy * * @return 0 if successful */static int omap_twl4030_initialize(){ int ret = 0; FN_IN; mcbsp_interface_acquired++; if (mcbsp_interface_acquired != 1) { ret = 0; goto initialize_exit_path1; } if (unlikely (ret = omap2_mcbsp_request_interface(AUDIO_MCBSP, OMAP2_MCBSP_SLAVE, OMAP2_MCBSP_FCLKSRC_PRCM))) { printk(KERN_ERR " Request for MCBSP Failed[%d]\n", ret); goto initialize_exit_path1; }// omap_twl_state.fmode = state->fmode; ret = twl4030_ext_mut_conf(); if (ret) { printk(KERN_ERR "a twl4030_ext_mut_conf failed [%d]\n", ret); goto initialize_exit_path2; } ret = twl4030_ext_mut_on(); if (ret) { printk(KERN_ERR "a twl4030_ext_mut_on failed [%d]\n", ret); goto initialize_exit_path2; } /* Toggle the codec power mode */ if (unlikely(ret = twl4030_codec_tog_on())) { printk(KERN_ERR "a1 twl4030_codec_tog failed [%d]\n", ret); goto initialize_exit_path2; } /* Sample rate configuration - set APLLs to setup regs */ ret = twl4030_set_samplerate(audio_samplerate); if (ret) { printk(KERN_ERR "Sample rate setting failed [%d]\n", ret); goto initialize_exit_path2; } if (unlikely(ret = twl4030_configure())) { printk(KERN_ERR " twl4030_configure_device failed [%d]\n", ret); goto initialize_exit_path2; } /* switch off the codec so that when mcbsp starts.. we are waiting */ if (unlikely(twl4030_codec_off())) { printk(KERN_ERR "a2 twl4030_codec_off failed [%d]\n", ret); goto initialize_exit_path2; } ret = twl4030_conf_data_interface(); if (ret) { printk(KERN_ERR "Codec Data init failed [%d]\n", ret); goto initialize_exit_path2; } /* register ISR */ ret = omap2_mcbsp_register_isr(AUDIO_MCBSP, twl_mcbsp_irq, NULL, OMAP2_MCBSP_IRQEN_XOVFL | OMAP2_MCBSP_IRQEN_XUNDFL | OMAP2_MCBSP_IRQEN_ROVFL | OMAP2_MCBSP_IRQEN_RUNDFL); if (ret) { printk(KERN_ERR "register of ISR failed [%d]\n", ret); goto initialize_exit_path3; } if (unlikely(ret = twl4030_codec_on())) { printk(KERN_ERR "a2 twl4030_codec_on failed [%d]\n", ret); goto initialize_exit_path3; } if (unlikely(ret = twl4030_ext_mut_off())) { printk(KERN_ERR "twl4030_ext_mut_off failed [%d]\n", ret); goto initialize_exit_path3; } /* Codec is operational */ FN_OUT(0); return 0; initialize_exit_path3: twl4030_unconfigure(); (void)omap2_mcbsp_interface_reset(AUDIO_MCBSP); initialize_exit_path2: /* Dont care abt result */ (void)omap2_mcbsp_release_interface(AUDIO_MCBSP); initialize_exit_path1: FN_OUT(ret); return ret;}/** * @brief omap_twl4030_shutdown * * @param dummy */static void omap_twl4030_shutdown(){ FN_IN; mcbsp_interface_acquired--; if (!mcbsp_interface_acquired) { omap2_mcbsp_unregister_isr(AUDIO_MCBSP); (void)omap2_mcbsp_interface_reset(AUDIO_MCBSP); omap2_mcbsp_release_interface(AUDIO_MCBSP); twl4030_unconfigure(); } FN_OUT(0);}/** * @brief omap_twl4030_sidle * * @return 0 if successful */static int omap_twl4030_sidle(u32 idle_state){ int ret = 0; FN_IN; /* Translate DPM level to McBSP supported level and pass it along */ return ret;}/** * @brief omap_twl4030_probe - check if the device is in real present or not * If present then register the mixer device. else return failure * * @return 0 if chip is present and intialized properly */static int omap_twl4030_probe(){ int ret = 0; FN_IN; /* check if T2 device is actually present - Read IDCODE reg */ printk(KERN_INFO PLATFORM_NAME " " CODEC_NAME " Audio Support: "); if (twl4030_i2c_read_u8(TWL4030_MODULE_INTBR, (u8 *) & ret, 0x00)) { ret = -ENODEV; printk(KERN_INFO "Chip Not detected\n"); goto twl4030_probe_out; } if (mixer_dev_id >= 0) { /* Announcement Time */ printk("Chip Rev[0x%02x] Initialized\n", ret); ret = 0; } else { printk(KERN_INFO "Mixer Not Initialized\n"); ret = mixer_dev_id; } twl4030_probe_out: FN_OUT(ret); return ret;}/** * @brief mixer_open * * @param inode * @param file * * @return 0 if successful */static int mixer_open(void){ int ret = 0; int gain_l,gain_r; /* Any mixer specific initialization */ /* Shut down the twl4030 only if the device is already dead */ if (0 == twl4030_configured) { if (unlikely(ret = twl4030_ext_mut_conf())) { printk(KERN_ERR "twl4030_ext_mut_conf failed [%d]\n", ret); return ret; } if (unlikely(ret = twl4030_ext_mut_on())) { printk(KERN_ERR "twl4030_ext_mut_on failed [%d]\n", ret); return ret; } /* Setup such that it is full duplex -allows dsp side * operations to be smooth */ if (unlikely(ret = twl4030_codec_tog_on())) { printk(KERN_ERR " twl4030_codec_tog failed [%d]\n", ret); /* Dont care abt result */ return ret; } if (unlikely(ret = twl4030_set_samplerate(48000))) { printk(KERN_ERR " sample rate set failed [%d]\n", ret); return ret; } } /* configure me */ if (unlikely(ret = twl4030_configure())) { printk(KERN_ERR " twl4030_configure_device failed [%d]\n", ret); /* Dont care abt result */ return ret; } /* Start codec if codec is just configured */ if (1 == twl4030_configured) { /* setup the default sample rate etc.. */ /* Toggle the codec enable to set the new values */ if (unlikely(ret = twl4030_codec_tog_on())) { printk(KERN_ERR " twl4030_codec_tog failed [%d]\n", ret); goto mixer_fail; } if (unlikely(ret = twl4030_ext_mut_off())) { printk(KERN_ERR "twl4030_ext_mut_off failed [%d]\n", ret); goto mixer_fail; } /* set the sample rate */ ret = twl4030_set_samplerate(48000); DPRINTK("twl4030_set_samplerate, returned 0x%x \n", ret); /* set the format */ ret = twl4030_bit_set(AUDIO_SAMPLE_DATA_WIDTH_16, MIXER_DEVICE); DPRINTK("twl4030_bit_set -sample width, returned 0x%x \n", ret); /* set the channel */ ret = twl4030_stereomode_set(STEREO_MODE,MIXER_DEVICE); DPRINTK("twl4030_stereomode_set , returned 0x%x \n", ret); /* set Volume */ gain_l = READ_LEFT_VOLUME(95 << 8 | 95); gain_r = READ_RIGHT_VOLUME(95 << 8 | 95); ret = twl4030_setvolume(OUTPUT_VOLUME, gain_l, gain_r); DPRINTK("twl4030_setvolume , returned 0x%x \n", ret); } return 0; mixer_fail: /* Dont care abt result */ twl4030_unconfigure(); return ret;}/** * @brief mixer_release * * @param inode * @param file * * @return 0 */static int mixer_release(void){ /* if only I am around, quit the device */ twl4030_unconfigure(); /* Any mixer specific Un-initialization */ return 0;}/* * Alsa mixer Callback 'info' for Stereo Playback Volume Controls */static int __pcm_playback_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; uinfo->value.integer.max = AUDIO_MAX_OUTPUT_VOLUME; return 0;}/* * Alsa mixer Callback 'info' for Mono Playback Volume Controls */static int __pcm_mono_playback_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = AUDIO_MAX_OUTPUT_VOLUME; return 0;}/* * Sidetone 'info' */static int __sidetone_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = SIDETONE_MAX_GAIN; return 0;}/* * Alsa mixer interface function for getting the volume read from the DGC in a * 0 -100 alsa mixer format. */static int __pcm_playback_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ ucontrol->value.integer.value[0] = READ_LEFT_VOLUME(twl4030_local.play_volume); /* L */ ucontrol->value.integer.value[1] = READ_RIGHT_VOLUME(twl4030_local.play_volume);/* R */ return 0;}/* * Alsa mixer interface function for setting the master playback volume */static int __pcm_playback_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ int changed = 0; if ((READ_LEFT_VOLUME(twl4030_local.play_volume) != ucontrol->value.integer.value[0]) | (READ_RIGHT_VOLUME(twl4030_local.play_volume) != ucontrol->value.integer.value[1])) { changed = twl4030_setvolume(OUTPUT_VOLUME, ucontrol->value.integer.value[0], ucontrol->value.integer.value[1]); if (!changed) changed = 1; } return changed;}/* * Headset Get Volume */static int __headset_playback_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ ucontrol->value.integer.value[0] = READ_LEFT_VOLUME(twl4030_local.hset); /* L */ ucontrol->value.integer.value[1] = READ_RIGHT_VOLUME(twl4030_local.hset);/* R */ return 0;}/* * Headset Set Volume */static int __headset_playback_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ int changed = 0; if ((READ_LEFT_VOLUME(twl4030_local.hset) != ucontrol->value.integer.value[0]) | (READ_RIGHT_VOLUME(twl4030_local.hset) != ucontrol->value.integer.value[1])) { changed = twl4030_setvolume(OUTPUT_STEREO_HEADSET, ucontrol->value.integer.value[0], ucontrol->value.integer.value[1]); if (!changed) changed = 1; } return changed;}/** * Switch info */static int __pcm_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; return 0;}/* * Handsfree Switch Control */static int __handsfree_playback_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ if (current_output & OUTPUT_HANDS_FREE_CLASSD) ucontrol->value.integer.value[0] = ((handsfree_en) ? 1 : 0); else ucontrol->value.integer.value[0] = 0; return 0;}static int __handsfree_playback_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ int changed = 0; if (ucontrol->value.integer.value[0] != (handsfree_en)) { if (ucontrol->value.integer.value[0]) { handsfree_en = 1; } else { handsfree_en = 0; } changed = 1; } return changed;}/** * T2 configure */static int __codec_configure_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; return 0;}static int __codec_configure_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ ucontrol->value.integer.value[0] = ((codec_configured) ? 1 : 0); return 0;}static int __codec_configure_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ int changed = 0; if (ucontrol->value.integer.value[0] != (codec_configured)) { if (ucontrol->value.integer.value[0]) { DPRINTK("Request to configure the T2 codec !!!! \n"); mixer_open(); codec_configured = 1; } else { DPRINTK("Request to un-configure the T2 codec !!!! \n"); mixer_release(); codec_configured = 0; } changed = 1; } return changed;}/* Controls to set the T2 sample Rate */static int __codec_samplerate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 8000; uinfo->value.integer.max = 48000; return 0;}static int __codec_samplerate_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ ucontrol->value.integer.value[0] = audio_samplerate; return 0;}static int __codec_samplerate_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ int changed = 0; if (ucontrol->value.integer.value[0] != (audio_samplerate)) { twl4030_set_samplerate(ucontrol->value.integer.value[0]); changed = 1; } return changed;}/* * Handset Earphone Control */static int __earphone_playback_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ ucontrol->value.integer.value[0] = READ_LEFT_VOLUME(twl4030_local.ear); /* L Mono */ return 0;}static int __earphone_playback_volume_put(struct
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -