Sound support for EZX platform diff -Nru --exclude-from=/sunbeam/home/laforge/scripts/dontdiff linux-2.6.16.5/sound/oss/ezx-a780.c linux-2.6.16.5-exz/sound/oss/ezx-a780.c --- linux-2.6.16.5/sound/oss/ezx-a780.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.5-exz/sound/oss/ezx-a780.c 2006-04-16 18:49:29.000000000 +0200 @@ -0,0 +1,530 @@ +/* + * linux/drivers/sound/ezx-a780.c + * + * + * Description: Motorola a780 phone specific functions implementation for audio drivers + * + * + * Copyright: BJDC motorola. + * + * This program 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. + * + * + * History: + * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Created, Make the e680 louder speaker work. + * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs + * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix + * Jin Lihong(w20076) Mar.25,2004,LIBdd90846 a780 new gain setting interface + * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 close dsp protection,and add 3d control interface for app + * Jin Lihong(w20076) Jun.22,2004,LIBee24284 mixer power save + * Cheng Xuefeng(a2491c) Jun.24,2004,LIBdd95397 Add EMU PIHF carkit sound path + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ezx-common.h" + + +#ifdef CONFIG_ARCH_EZX_A780 + +extern u32 gpio_hw_attenuate_a780_status; + + +void close_input_carkit(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close input carkit. \n"); +#endif + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX); +} + + +#if EMU_PIHF_FEATURE +void close_input_pihf_carkit(void) +{ + printk("EMU:%s,%s\n",__FILE__,__FUNCTION__); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX); +} +#endif /* EMU_PIHF_FEATURE */ + + +void close_input_handset(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close input handset. \n"); +#endif + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON1); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_MUX); +} + + +void close_input_headset(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close input headset. \n"); +#endif + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_MUX); +} + + +void open_input_carkit(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open input carkit. \n"); +#endif + + codec_input_path = CARKIT_INPUT; + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX); +} + + +#if EMU_PIHF_FEATURE +void open_input_pihf_carkit(void) +{ + printk("EMU:%s,%s\n",__FILE__,__FUNCTION__); + codec_input_path = PIHF_CARKIT_INPUT; + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX); +} +#endif /* EMU_PIHF_FEATURE */ + + +void open_input_handset(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open input handset. \n"); +#endif + + codec_input_path = HANDSET_INPUT; + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON1); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_MUX); +} + + +void open_input_headset(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open input headset. \n"); +#endif + + codec_input_path = HEADSET_INPUT; + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_MUX); +} + + +void close_output_pcap_headset(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output pcap headset. \n"); +#endif + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); +} + + +void close_output_pcap_louderspeaker(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output pcap louderspeaker. \n"); +#endif + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A2_EN); +} + + +void close_output_pcap_earpiece(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output pcap earpiece. \n"); +#endif + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1_EN); +} + + +void close_output_pcap_carkit(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output pcap carkit. \n"); +#endif + EIHF_Mute(EIHF_MUTE); //Mute EIHF + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + + Set_EMU_Mux_Switch(DEFAULT_USB_MODE); +} + + +#if EMU_PIHF_FEATURE +void close_output_pcap_pihf_carkit(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output pcap pihf carkit. \n"); + printk("EMU:%s,%s\n",__FILE__,__FUNCTION__); +#endif + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); +} +#endif /* EMU_PIHF_FEATURE */ + + +void close_output_pcap_headjack(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output pcap headjack. \n"); +#endif + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); +} + + +void close_output_pcap_bluetooth(void) +{ +} + + +int open_output_pcap_headset(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output pcap headset. \n"); +#endif + + if((audioonflag & DSP_DEVICE)==DSP_DEVICE) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + codec_output_path = val; + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_pcap_louderspeaker(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output pcap louderspeaker. \n"); +#endif + + if((audioonflag & DSP_DEVICE)==DSP_DEVICE) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL_6DB); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + codec_output_path = val; + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A2_EN); + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_pcap_earpiece(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output pcap earpiece. \n"); +#endif + + if((audioonflag & DSP_DEVICE)==DSP_DEVICE) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL_6DB); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + codec_output_path = val; + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1_EN); + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_pcap_carkit(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output pcap carkit. \n"); +#endif + + Set_EMU_Mux_Switch(MONO_AUDIO_MODE); + + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + + codec_output_path = val; + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + + set_output_gain_hw_reg(); + + EIHF_Mute(EIHF_UNMUTE); + + return ret; +} + + +#if EMU_PIHF_FEATURE +int open_output_pcap_pihf_carkit(long val) +{ + int ret; + + printk("EMU:%s,%s\n",__FILE__,__FUNCTION__); + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + + codec_output_path = val; + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + + set_output_gain_hw_reg(); + + return ret; +} +#endif /* EMU_PIHF_FEATURE */ + + +int open_output_pcap_headjack(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output pcap headjack. \n"); +#endif + + if((audioonflag & DSP_DEVICE)==DSP_DEVICE) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL_6DB); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + codec_output_path = val; + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_pcap_bluetooth(long val) +{ + return 0; +} + + +void set_output_gain_hw_reg(void) +{ + SSP_PCAP_AUDOG_set( PCAP_OUTPUT_GAIN_REG_VAL_FROM_LOGIC ); + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "codec_output_gain=%d\n", codec_output_gain); + printk(EZXOSS_DEBUG "output gain=%d\n",PCAP_OUTPUT_GAIN_REG_VAL_FROM_LOGIC); +#endif +} + + +void set_input_gain_hw_reg(void) +{ + SSP_PCAP_AUDIG_set( PCAP_INPUT_AUDIG_REG_VAL_FROM_LOGIC ); + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "codec_input_gain=%d\n", codec_input_gain); +#endif +} + + +void poweron_mixer( audio_dev_type type ) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "A780 No. 0x%X device wants to power on the mixer hardware.\n", type); + printk(EZXOSS_DEBUG "A780 No. 0x%X device has already powered on the mixer hardware.\n", audioonflag); +#endif + + audioonflag |= type; + if( audioonflag == type ) + { +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "A780 No. 0x%X device is powering on the mixer hardware.\n", type); +#endif + + ssp_pcap_open(SSP_PCAP_AUDIO_OPEN); + + /* (1) set pcap audio power V2_EN_2(OR WITH V2_EN) */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2); + + /* (6) enable output_path and set gain */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP); /* disable codec bypass */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ST_DAC_SW); /* close stereo switch */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CDC_SW); /* open telephone codec path into right PGA */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); /* close PGA_INR into PGA */ + + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN); /* enable right PGA */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN); /* enable left PGA */ + } +} + + +void shutdown_mixer( audio_dev_type type ) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "A780 No. 0x%X device wants to shut down the mixer hardware.\n", type); +#endif + + audioonflag &= ~type; + + if( audioonflag == 0 ) + { +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "A780 No. 0x%X device is shutting down the mixer hardware.\n", type); +#endif + /* close pcap output path */ + SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER, SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); + } + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "A780 No. 0x%X device is still using the mixer hardware.\n", audioonflag); +#endif +} + + +void mixer_not_in_use(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " A780 mixer not in use.\n"); +#endif + + (*mixer_close_output_path[OUTPUT_BASE_TYPE(codec_output_base)][codec_output_path])(); + (*mixer_close_input_path[codec_input_path])(); + + if( micinflag == 0 ) /* close pcap output path */ + SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER, SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); +} + + +u32 gpio_hw_attenuate_a780_status; +void use_hw_noise_attenuate(void) +{ + set_GPIO_mode(GPIO_HW_ATTENUATE_A780 | GPIO_OUT); + clr_GPIO(GPIO_HW_ATTENUATE_A780); + PGSR(GPIO_HW_ATTENUATE_A780) &= ~GPIO_bit(GPIO_HW_ATTENUATE_A780); + gpio_hw_attenuate_a780_status = 0; +#ifdef EZX_OSS_DEBUG + printk( EZXOSS_DEBUG "set a780 hw noise attenuation gpio low. \n"); +#endif +} + + +void bypass_hw_noise_attenuate(void) +{ + set_GPIO_mode(GPIO_HW_ATTENUATE_A780 | GPIO_OUT); + set_GPIO(GPIO_HW_ATTENUATE_A780); + PGSR(GPIO_HW_ATTENUATE_A780) |= GPIO_bit(GPIO_HW_ATTENUATE_A780); + gpio_hw_attenuate_a780_status = 1; +#ifdef EZX_OSS_DEBUG + printk( EZXOSS_DEBUG "set a780 hw noise attenuation gpio high. \n"); +#endif +} + + +void pcap_use_ap_13m_clock(void) +{ + OSCC |= 0x00000008; + set_GPIO_mode(AP_13MHZ_OUTPUT_PIN | GPIO_ALT_FN_3_OUT); + + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_CLK_IN_SEL); +} + + +void pcap_use_bp_13m_clock(void) +{ + OSCC &= ~0x00000008; + set_GPIO_mode(AP_13MHZ_OUTPUT_PIN | GPIO_IN); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_CLK_IN_SEL); +} + + +#ifdef CONFIG_PM +int mixer_hw_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +{ + switch(req){ + case PM_SUSPEND: +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " A780 before AP sleep.\n"); +#endif + if( (audioonflag & PHONE_DEVICE) == 0 ) + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR); + break; + case PM_RESUME: +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " A780 after AP sleep.\n"); +#endif + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR); + set_output_gain_hw_reg(); + + if(gpio_hw_attenuate_a780_status) + bypass_hw_noise_attenuate(); + else + use_hw_noise_attenuate(); + if(audioonflag) + (*mixer_open_output_path[OUTPUT_BASE_TYPE(codec_output_base)][codec_output_path])(codec_output_base|codec_output_path); + + break; + } + return 0; +} +#endif + + +void mute_output_to_avoid_pcap_noise(void) +{ +} + + +void undo_mute_output_to_avoid_pcap_noise(void) +{ +} + + +#endif + + diff -Nru --exclude-from=/sunbeam/home/laforge/scripts/dontdiff linux-2.6.16.5/sound/oss/ezx-a780.h linux-2.6.16.5-exz/sound/oss/ezx-a780.h --- linux-2.6.16.5/sound/oss/ezx-a780.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.5-exz/sound/oss/ezx-a780.h 2006-04-16 18:49:29.000000000 +0200 @@ -0,0 +1,117 @@ +/* + * linux/drivers/sound/ezx-a780.h + * + * + * Description: header file for ezx-a780.c + * + * + * Copyright: BJDC motorola. + * + * This program 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. + * + * + * History: + * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Created, Make the e680 louder speaker work. + * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs + * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix + * Jin Lihong(w20076) Mar.25,2004,LIBdd90846 a780 new gain setting interface + * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 close dsp protection,and add 3d control interface for app + * Jin Lihong(w20076) Jun.22,2004,LIBee24284 mixer power save + * Cheng Xuefeng(a2491c) Jun.24,2004,LIBdd95397 Add EMU PIHF carkit sound path + * + */ + +#ifndef EZX_A780_H +#define EZX_A780_H + +#include + +#ifdef CONFIG_ARCH_EZX_A780 + +//#define EZX_OSS_DEBUG /* debug switch for all ezx oss src files excluding ezx-audio.c */ +#undef EZX_OSS_DEBUG +//#define EZX_OSS_AUDIO_DEBUG /* debug switch for src file ezx-audio.c */ +#undef EZX_OSS_AUDIO_DEBUG + +/* +#ifdef EZX_OSS_DBG +#define OSSPRINTF(fmt,args...) printf(fmt,##args) +#else +#define OSSPRINTF(fmt,args...) { } +#endif +*/ + + +typedef enum{ + PHONE_DEVICE = 0x01, + DSP_DEVICE = 0x02, + DSP16_DEVICE = 0x04, + AUDIO_DEVICE = 0x08 +}audio_dev_type; + +typedef enum{ + HW_ATTENUATION_USED, + HW_ATTENUATION_BYPASSED +}hw_noise_attenuation; + + +void close_input_carkit(void); +void close_input_handset(void); +void close_input_headset(void); +#if EMU_PIHF_FEATURE +void close_input_pihf_carkit(void); +#endif + +void open_input_carkit(void); +void open_input_handset(void); +void open_input_headset(void); +#if EMU_PIHF_FEATURE +void open_input_pihf_carkit(void); +#endif + +void close_output_pcap_headset(void); +void close_output_pcap_louderspeaker(void); +void close_output_pcap_earpiece(void); +void close_output_pcap_carkit(void); +void close_output_pcap_headjack(void); +void close_output_pcap_bluetooth(void); +#if EMU_PIHF_FEATURE +void close_output_pcap_pihf_carkit(void); +#endif + +int open_output_pcap_headset(long val); +int open_output_pcap_louderspeaker(long val); +int open_output_pcap_earpiece(long val); +int open_output_pcap_carkit(long val); +int open_output_pcap_headjack(long val); +int open_output_pcap_bluetooth(long val); +#if EMU_PIHF_FEATURE +int open_output_pcap_pihf_carkit(long val); +#endif + +void set_output_gain_hw_reg(void); +void set_input_gain_hw_reg(void); + +void poweron_mixer( audio_dev_type type ); +void shutdown_mixer( audio_dev_type type ); +void mixer_not_in_use(void); + +void use_hw_noise_attenuate(void); +void bypass_hw_noise_attenuate(void); + +void pcap_use_ap_13m_clock(void); +void pcap_use_bp_13m_clock(void); + +void mute_output_to_avoid_pcap_noise(void); +void undo_mute_output_to_avoid_pcap_noise(void); + +int mixer_hw_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data); + +#endif + + +#endif + + diff -Nru --exclude-from=/sunbeam/home/laforge/scripts/dontdiff linux-2.6.16.5/sound/oss/ezx-asspm.c linux-2.6.16.5-exz/sound/oss/ezx-asspm.c --- linux-2.6.16.5/sound/oss/ezx-asspm.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.5-exz/sound/oss/ezx-asspm.c 2006-04-16 18:49:29.000000000 +0200 @@ -0,0 +1,550 @@ +/* + * linux/drivers/sound/ezx-asspm.c + * + * + * Description: assp interface for the ezx platform + * + * + * Copyright: BJDC motorola. + * + * This program 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. + * + * + * History: + * zhouqiong Jun 20,2002 created + * zhouqiong Sep 19,2002 according code review meeting minutes. + * zhouqiong Oct 30,2002 according new requirement for VA.ASSP interface split to + * /dev/dsp (support stereo playback) and /dev/dsp16 (support + * mono playback and record).this file is for mono playback and record + * zhouqiong Nov 05,2002 according code review meeting minutes. + * zhouqiong Mar 04,2003 (1) don't close headset interrupt; + * (2) when headset in, output gain decrease 6db + * zhouqiong Apr 24,2003 no switch for headset insert and remove + * LiYong Sep 23,2003 Port from EZX + * Jin Lihong(w20076) Jan 02,2004,LIBdd66088 (1) Port from UDC e680 kernel of jem vob. + * (2) Move audio driver DEBUG macro definition to ezx-audio.h + * header file,and redefine DEBUG to EZX_OSS_DEBUG + * (3) reorganize file header + * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Make the e680 louder speaker work. + * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs + * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix + * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 close dsp protection,and add 3d control interface for app + * lin weiqiang Jun.08,2004,LIBee14656 record noise bug fix. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ezx-audio.h" +#include "ezx-common.h" + + +static DECLARE_MUTEX(cotulla_assp_mono_mutex); + +EXPORT_SYMBOL(set_pcap_telephone_codec); +EXPORT_SYMBOL(set_pcap_input_path); +EXPORT_SYMBOL(set_pcap_output_path); + +static int assp_mono_init(void); +static void assp_mono_shutdown(void); + +void set_pcap_telephone_codec(int port) +{ + unsigned long ssp_pcap_register_val; + SSP_PCAP_BIT_STATUS phoneClkBit; + /* set pcap register, telephone codec */ + /* (1) set pcap audio power V2_EN_2(OR WITH V2_EN) */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2); + + /* disable PCAP stereo DAC */ + SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ST_DAC_REGISTER, 0); + /* (2) set codec sample rate(FS_8K_16K=0) */ + /* CDC_CLK(000=13MHZ) bitclk output(SMB=0) audio IO1(DIG_AUD_IN=1) */ + ssp_pcap_register_val = PCAP_CDC_CLK_IN_13M0; + phoneClkBit = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL); + SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_CODEC_REGISTER, ssp_pcap_register_val); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_SMB); /* master */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_8K_16K); /* 8K sample rate */ +/* + if( SSP_PCAP_BIT_ONE == phoneClkBit) + { + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL); + } + else + { + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL); + } +*/ + if(port) + { + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DIG_AUD_IN); /* DAI1 */ + } + else + { + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_DIG_AUD_IN); /* DAI0 */ + } + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDIHPF); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDOHPF); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_INV); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_INV); + + /*(3) reset digital filter(DF_RESET=1) */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_ADITH); + /* (4) enable pcap clk(CDC_CLK_EN=1),enable CODEC(CDC_EN=1) */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); + mdelay(1); /* specified enable time */ +} + + +void set_pcap_output_path(void) +{ + int ret; + + /* enable output_path */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ST_DAC_SW); /* close stereo switch */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); /* close PGA_INR into PGA */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CDC_SW); /* open telephone switch */ + + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN); /* enable right PGA */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN); /* disable left PGA */ + + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); /* right+left output */ + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "codec_output_path = %d\n", codec_output_path); + printk(EZXOSS_DEBUG "codec_output_base = %d\n", codec_output_base); +#endif + ret = (*mixer_open_output_path[OUTPUT_BASE_TYPE(codec_output_base)][codec_output_path])(codec_output_base|codec_output_path); +} + + +void set_pcap_input_path(void) +{ + unsigned long ssp_pcap_register_val; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "codec_input_path=%d\n", codec_input_path); +#endif + + (*mixer_open_input_path[codec_input_path])(); + set_input_gain_hw_reg(); + +#ifdef EZX_OSS_DEBUG + SSP_PCAP_read_data_from_PCAP(0x1a,&ssp_pcap_register_val); + printk(EZXOSS_DEBUG "pcap register 26 = 0x%lx\n", ssp_pcap_register_val); +#endif +} + + +/*initialize hardware, assp controller and pcap register*/ +static int assp_mono_init(void) +{ + unsigned long flags; + unsigned long ssp_pcap_register_val; + unsigned int audiostatus; + unsigned long timeout; + +/* +#ifdef CONFIG_ARCH_EZX_E680 + if( audioonflag & FM_DEVICE ){ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "E680 open dsp16 EBUSY because 0x%X device is using the sound hardware.\n",audioonflag ); +#endif + return -EBUSY; + } +#endif +*/ + + audioonflag |= DSP16_DEVICE; + + down(&cotulla_assp_mono_mutex); + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "setup assp controller register \n"); +#endif + local_irq_save(flags); + CKEN |= CKEN4_ASSP; /* need enable cken4 */ + + set_GPIO_mode(GPIO_SYNC_IN_ASSP_MD); + set_GPIO_mode(GPIO_SDATA_OUT_ASSP_MD); + set_GPIO_mode(GPIO_BITCLK_IN_ASSP_MD); + set_GPIO_mode(GPIO_SDATA_IN_ASSP_MD); + + /* setup assp port */ + ASSCR0 = ASSCR0_FRF_PSP | ASSCR0_DSS_16bit; /* psp mode, 16bit */ + ASSCR1 = ASSCR1_TTE | ASSCR1_EBCEI | ASSCR1_SCLKDIR | ASSCR1_SFRMDIR | ASSCR1_RFTH_14 | ASSCR1_TFTH_4; + ASSPSP = ASSPSP_SFRMWDTH_1 | ASSPSP_STRTDLY_1 | ASSPSP_SFRMP_HIGH | ASSPSP_SCMODE; + ASSCR1 |= ASSCR1_RSRE | ASSCR1_TSRE; /* enable transmit and receive dma request */ + ASSCR0 |= ASSCR0_SSE; /* enable assp controller */ + local_irq_restore(flags); + +#ifdef EZX_OSS_DEBUG + audiostatus = ASSCR0; + printk(EZXOSS_DEBUG "ASSCR0 = 0x%lx\n", audiostatus); + audiostatus = ASSCR1; + printk(EZXOSS_DEBUG "ASSCR1 = 0x%lx\n", audiostatus); + audiostatus = ASSPSP; + printk(EZXOSS_DEBUG "ASSPSP = 0x%lx\n", audiostatus); +#endif + + mute_output_to_avoid_pcap_noise(); + + ssp_pcap_open(SSP_PCAP_AUDIO_OPEN); + if( MONODEVOPENED == DSP16_DEVICE ) + pcap_use_ap_13m_clock(); + +/* not in phone call, PCAP telephone */ + if((audioonflag & PHONE_DEVICE)==0){ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "setup pcap audio register\n"); +#endif + set_pcap_telephone_codec(1); + set_pcap_output_path(); + set_pcap_input_path(); + } + else{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "there is phone call\n"); +#endif + /* set pcap register, stereo DAC */ + //SSP_PCAP_read_data_from_PCAP(SSP_PCAP_ADJ_ST_DAC_REGISTER, &ssp_pcap_register_val); + //ssp_pcap_register_val |= PCAP_ST_SAMPLE_RATE_8K | PCAP_ST_BCLK_SLOT_4 | PCAP_ST_CLK_PLL_CLK_IN_BITCLK | PCAP_DIGITAL_AUDIO_INTERFACE_NETWORK; //NETWORK mode + //SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ST_DAC_REGISTER, ssp_pcap_register_val); + SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_8K); + SSP_PCAP_BCLK_set(PCAP_ST_BCLK_SLOT_4); + SSP_PCAP_STCLK_set(PCAP_ST_CLK_PLL_CLK_IN_FSYNC); + SSP_PCAP_DIG_AUD_FS_set(PCAP_DIGITAL_AUDIO_INTERFACE_NETWORK); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_INV); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_FS_INV); + + /* (3) reset digital filter(DF_RESET_ST_DAC=1) */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_DF_RESET_ST_DAC); + + /* (4)set bitclk output(SMB_ST_DAC=0), audio IO=part1(DIG_AUD_IN_ST_DAC=1) */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_SMB_ST_DAC); /* input, slave mode */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_DIG_AUD_IN_ST_DAC); + + /* (5) enable pcap clk(ST_CLK_EN=1),enable dac(ST_DAC_EN=1) */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_EN); + mdelay(1); /* specified enable time according spec */ + + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ST_DAC_SW); /* close stereo switch */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN); /* enable left PGA */ + } + + undo_mute_output_to_avoid_pcap_noise(); + +#ifdef EZX_OSS_DEBUG + SSP_PCAP_read_data_from_PCAP(0x0d,&ssp_pcap_register_val); + printk(EZXOSS_DEBUG "pcap register 13 = 0x%lx\n", ssp_pcap_register_val); + SSP_PCAP_read_data_from_PCAP(0x0c,&ssp_pcap_register_val); + printk(EZXOSS_DEBUG "pcap register 12 = 0x%lx\n", ssp_pcap_register_val); + SSP_PCAP_read_data_from_PCAP(0x0b,&ssp_pcap_register_val); + printk(EZXOSS_DEBUG "pcap register 11 = 0x%lx\n", ssp_pcap_register_val); + SSP_PCAP_read_data_from_PCAP(0x1a,&ssp_pcap_register_val); + printk(EZXOSS_DEBUG "pcap register 26 = 0x%lx\n", ssp_pcap_register_val); +#endif + timeout = 0; + /* check if ssp is ready for slave operation */ + while(((audiostatus = ASSSR) & ASSSR_CSS) !=0){ + if((timeout++) > 10000000) + goto err; + } + + up(&cotulla_assp_mono_mutex); + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " complete all hardware init \n"); +#endif + return 0; + +err: + up(&cotulla_assp_mono_mutex); + printk(EZXOSS_DEBUG "audio panic2: ssp don't ready for slave operation!!! "); + return -ENODEV; +} + + +static void assp_mono_shutdown(void) +{ + unsigned long ssp_pcap_register_val; + + down(&cotulla_assp_mono_mutex); + + /* clear ASSP port */ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close assp port\n"); +#endif + ASSCR0 = 0; + ASSCR1 = 0; + ASSPSP = 0; + CKEN &= ~CKEN4_ASSP; + + set_GPIO_mode(GPIO_ASSP_SCLK3 | GPIO_IN); /* Assp Frame sync */ + set_GPIO_mode(GPIO_ASSP_TXD3 | GPIO_IN); + set_GPIO_mode(GPIO_ASSP_RXD3 | GPIO_IN); /* ASSP BitCLK */ + set_GPIO_mode(GPIO_ASSP_SFRM3 | GPIO_IN); /* ASsp RX */ + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close pcap register\n"); +#endif + + mute_output_to_avoid_pcap_noise(); /* mute hw noise and save power */ + + if( MONODEVOPENED == DSP16_DEVICE ) + pcap_use_bp_13m_clock(); + + if((audioonflag & PHONE_DEVICE) == 0){ + /* close pcap output path */ + SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER,SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); + /* close pcap input path */ + if(micinflag) + SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER,SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2); + else + SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER, 0); + /* disable PCAP mono codec */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_SMB); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_DIG_AUD_IN); /* DAI0 */ + /* set fsync, tx, bitclk are tri-stated */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CD_TS); + } + else{ + /* disable PCAP stereo DAC */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_SMB_ST_DAC); + } + +#ifdef CONFIG_ARCH_EZX_E680 + e680_boomer_path_mono_lineout(); /* mute hw noise and save power for e680 */ +#endif + + audioonflag &= ~DSP16_DEVICE; + +#ifdef EZX_OSS_DEBUG + SSP_PCAP_read_data_from_PCAP(0x0d,&ssp_pcap_register_val); + printk("pcap register 13 = 0x%lx\n", ssp_pcap_register_val); + SSP_PCAP_read_data_from_PCAP(0x0c,&ssp_pcap_register_val); + printk("pcap register 12 = 0x%lx\n", ssp_pcap_register_val); + SSP_PCAP_read_data_from_PCAP(0x0b,&ssp_pcap_register_val); + printk("pcap register 11 = 0x%lx\n", ssp_pcap_register_val); + SSP_PCAP_read_data_from_PCAP(0x1a,&ssp_pcap_register_val); + printk("pcap register 26 = 0x%lx\n", ssp_pcap_register_val); +#endif + up(&cotulla_assp_mono_mutex); +} + + +/* + * ASSP codec ioctls + */ +static int codec_adc_rate = PHONE_CODEC_DEFAULT_RATE; /* default 8k sample rate */ +static int codec_dac_rate = PHONE_CODEC_DEFAULT_RATE; /* default 8k sample rate */ + +static int assp_mono_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret; + long val; + int audiostatus, timeout; + + switch(cmd) { + case SNDCTL_DSP_STEREO: +#ifdef EZX_OSS_DEBUG + printk(" check if support stereo\n"); +#endif + ret = get_user(val, (int *) arg); + if (ret) + return ret; + + if(val) + ret = -EINVAL; /* not support stereo */ + else + ret = 1; + return put_user(ret, (int *) arg); + + case SNDCTL_DSP_CHANNELS: + case SOUND_PCM_READ_CHANNELS: +#ifdef EZX_OSS_DEBUG + printk(" check if 2 channels \n"); +#endif + return put_user(1, (long *) arg); + + case SNDCTL_DSP_SPEED: +#ifdef EZX_OSS_DEBUG + printk(" set sample frequency \n"); +#endif + ret = get_user(val, (long *) arg); + if (ret) + return ret; + + down(&cotulla_assp_mono_mutex); + ASSCR0 &= ~ASSCR0_SSE; + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); + switch(val) + { + case PHONE_CODEC_16K_RATE: + ret= SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_8K_16K); + codec_adc_rate = val; + codec_dac_rate = val; + break; + case PHONE_CODEC_DEFAULT_RATE: + ret = SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_8K_16K); + codec_adc_rate = val; + codec_dac_rate = val; + break; + default: + ret = -EINVAL; + break; + } + /* reset digital filter(DF_RESET=1) */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); + + ASSCR0 |= ASSCR0_SSE; /* enable assp controller */ + timeout = 0; + /* check if ssp is ready for slave operation */ + while(((audiostatus = ASSSR) & ASSSR_CSS) !=0) + { + if((timeout++) > 10000000) + { + printk("audio panic3: can't be slave mode!!!"); + ret = -ENODEV; + break; + } + } +#ifdef EZX_OSS_DEBUG + printk("AD sample freq = %d\n", codec_adc_rate); + printk("DA sample freq = %d\n", codec_dac_rate); +#endif + up(&cotulla_assp_mono_mutex); + return put_user(codec_adc_rate, (long *) arg); + + case SOUND_PCM_READ_RATE: + if (file->f_mode & FMODE_WRITE) + { +#ifdef EZX_OSS_DEBUG + printk("read DA sample freq\n"); +#endif + val = codec_dac_rate; + } + if (file->f_mode & FMODE_READ) + { +#ifdef EZX_OSS_DEBUG + printk("read AD sample freq\n"); +#endif + val = codec_adc_rate; + } + return put_user(val, (long *) arg); + + case SNDCTL_DSP_SETFMT: + case SNDCTL_DSP_GETFMTS: + /* SUPPORT little endian signed 16 */ +#ifdef EZX_OSS_DEBUG + printk("data format is AFMT_S16_LEd\n"); +#endif + return put_user(AFMT_S16_LE, (long *) arg); + + default: + return mixer_ioctl(inode, file, cmd, arg); + } + return 0; +} + + +/* + * Audio stuff + */ +static audio_stream_t assp_mono_audio_out = { + name: "assp mono audio out", + dcmd: DCMD_TXASSDRM, + drcmr: &DRCMRTXASSDR, /* ASSP dma map register */ + dev_addr: __PREG(ASSDR), +}; + +static audio_stream_t assp_mono_audio_in = { + name: "assp mono audio in", + dcmd: DCMD_RXASSDR, + drcmr: &DRCMRRXASSDR, /* ASSP dma map register */ + dev_addr: __PREG(ASSDR), +}; + +static audio_state_t assp_mono_audio_state = { + output_stream: &assp_mono_audio_out, + input_stream: &assp_mono_audio_in, + client_ioctl: assp_mono_ioctl, + hw_init: assp_mono_init, + hw_shutdown: assp_mono_shutdown, + sem: __MUTEX_INITIALIZER(assp_mono_audio_state.sem), +}; + +static int assp_mono_audio_open(struct inode *inode, struct file *file) +{ +#ifdef EZX_OSS_DEBUG + printk("assp mono audio open \n"); +#endif + + return cotulla_audio_attach(inode, file, &assp_mono_audio_state); +} + +/* + * Missing fields of this structure will be patched with the call + * to cotulla_audio_attach(). + */ + +static struct file_operations assp_mono_audio_fops = { + open: assp_mono_audio_open, + owner: THIS_MODULE +}; + +static int __init cotulla_assp_mono_init(void) +{ + assp_mono_audio_state.dev_dsp = register_sound_dsp16(&assp_mono_audio_fops, -1); + +#ifdef EZX_OSS_DEBUG + printk("/dev/dsp16 init ok\n"); +#endif + return 0; +} + +static void __exit cotulla_assp_mono_exit(void) +{ + unregister_sound_dsp16(assp_mono_audio_state.dev_dsp); +#ifdef EZX_OSS_DEBUG + printk("/dev/dsp16 exit ok\n"); +#endif +} + +module_init(cotulla_assp_mono_init); +module_exit(cotulla_assp_mono_exit); + diff -Nru --exclude-from=/sunbeam/home/laforge/scripts/dontdiff linux-2.6.16.5/sound/oss/ezx-assps.c linux-2.6.16.5-exz/sound/oss/ezx-assps.c --- linux-2.6.16.5/sound/oss/ezx-assps.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.5-exz/sound/oss/ezx-assps.c 2006-04-16 18:49:29.000000000 +0200 @@ -0,0 +1,1168 @@ +/* + * linux/drivers/sound/ezx-assps.c + * + * + * Description: assp interface for the ezx platform + * + * + * Copyright: BJDC motorola. + * + * This program 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. + * + * + * History: + * zhouqiong Jun 20,2002 created + * zhouqiong Sep 19,2002 according code review meeting minutes. + * zhouqiong Oct 30,2002 according new requirement for VA.ASSP interface split to + * /dev/dsp (support stereo playback) and /dev/dsp16 (support + * mono playback and record) this file is for stereo playback. + * zhouqiong Nov 05,2002 according code review meeting minutes. + * zhouqiong Jan 13,2003 (1) add audio panic return value + * (2) modify sample frequency to standard + * zhouqiong Mar 03,2003 (1) open headset interrupt + * (2) change gain when headset is in + * (3) add ioctl to get headset status + * zhouqiong Apr 17,2003 (1) according codec_dac_rate init pcap + * zhouqiong Apr 18,2003 (1) change output gain according output path + * zhouqiong Apr 24,2003 (1) no switch when headset insert and remove + * zhouqiong May 21,2003 (1) modify loudspk gain max 0db, for audio-shaping + * LiYong Sep 23,2003 (1)Port from EZX; (2)Modify the ASSP port inital + * Jin Lihong(w20076) Jan 02,2004,Libdd66088 (1) Port from UDC e680 kernel of jem vob. + * (2) Move audio driver DEBUG macro definition to ezx-audio.h + * header file,and redefine DEBUG to EZX_OSS_DEBUG + * (3) reorganize file header + * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Make the e680 louder speaker work. + * Jia Tong(w19836) Feb 04,2004,LIBdd67717 haptics feature added + * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs + * Jia Tong(w19836) Feb 23,2004,LIBdd79841 haptics GPIO initialization change + * Li Yong(w19946) Feb 26,2004 LIBdd80614 Add DAI test + * Add control to switch PCAP CODEC mode from master to slave mode + * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix + * Jia Tong(w19836) Mar 17,2004,LIBdd87621 GPIO change for haptics filter & boomer mute while setting haptics. + * Jin Lihong(w20076) Mar.25,2004,LIBdd90846 a780 new gain setting interface + * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 close dsp protection,and add 3d control interface for app + * Li Yong(w19946) Apr.23.2004.LIBee02702 Add EMU Carkit + * Li Yong(w19946) May.23.2004.LIBee12065 Add the EMU audio test + * lin weiqiang Jun.08,2004,LIBee14656 record noise bug fix. + * Jin Lihong(w20076) Jun.22,2004,LIBee24284 mixer power save + * Jin Lihong(w20076) Aug.11,2004,LIBff01482 audio pcap LOW_POWER bit initialize + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ezx-audio.h" +#include "ezx-common.h" + + +static DECLARE_MUTEX(cotulla_assp_mutex); + +static int codec_dac_rate = STEREO_CODEC_44K_RATE; /* default 44k sample rate */ +static struct timer_list audio_timer,mic_timer; + +#ifdef CONFIG_PM +static struct pm_dev *mixer_hw_pm_dev; +#endif + + +EXPORT_SYMBOL(headjack_change_interrupt_routine); +EXPORT_SYMBOL(mic_change_interrupt_routine); +EXPORT_SYMBOL(mixer_ioctl); + +static int assp_init(void); +static void assp_shutdown(void); +static void change_input_output(void); +static void open_mic_interrupt(void); + +void Set_EMU_Mux_Switch(int mode); +void EIHF_Mute(int Flag); + +static int EMU_AUD_test_flag = 0; + +static struct timer_list EMU_timer; + +/*initialize hardware, assp controller and pcap register*/ +static int assp_init(void) +{ + unsigned long flags; + unsigned long ssp_pcap_register_val; + unsigned long audiostatus; + unsigned long timeout; + int ret; + + down(&cotulla_assp_mutex); +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "setup assp controller register \n"); +#endif + local_irq_save(flags); + CKEN |= CKEN4_ASSP; /* need enable cken4 */ + + set_GPIO_mode(GPIO_SYNC_IN_ASSP_MD); /* Assp Frame sync */ + set_GPIO_mode(GPIO_SDATA_OUT_ASSP_MD); /* Assp TX */ + set_GPIO_mode(GPIO_BITCLK_IN_ASSP_MD); /* ASSP BitCLK */ + set_GPIO_mode(GPIO_SDATA_IN_ASSP_MD); /* ASsp RX */ + + /* setup assp port */ + ASSCR0 = ASSCR0_FRF_PSP | ASSCR0_EDSS | ASSCR0_DSS_16bit; /* PSP mode, 32bit */ + ASSCR1 = ASSCR1_EBCEI | ASSCR1_SCLKDIR | ASSCR1_SFRMDIR | ASSCR1_TFTH_4; + ASSPSP = ASSPSP_SFRMWDTH_16 | ASSPSP_SCMODE; + ASSCR1 |= ASSCR1_TSRE; /* enable transmit dma request */ + ASSCR0 |= ASSCR0_SSE; /* enable assp controller */ + local_irq_restore(flags); + +#ifdef EZX_OSS_DEBUG + audiostatus = ASSCR0; + printk(EZXOSS_DEBUG "ASSCR0 = 0x%lx\n", audiostatus); + audiostatus = ASSCR1; + printk(EZXOSS_DEBUG "ASSCR1 = 0x%lx\n", audiostatus); + audiostatus = ASSPSP; + printk(EZXOSS_DEBUG "ASSPSP = 0x%lx\n", audiostatus); +#endif + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "setup pcap audio register\n"); +#endif + + mute_output_to_avoid_pcap_noise(); + poweron_mixer(DSP_DEVICE); + + /* (1) set bitclk(BCK=3, two_time_slot) pll clock(ST_CLK=0, 13M) NORMAL mode(DIG_AUD_FS =00) */ + ssp_pcap_register_val = PCAP_ST_BCLK_SLOT_2 | PCAP_ST_CLK_PLL_CLK_IN_13M0 | PCAP_DIGITAL_AUDIO_INTERFACE_NORMAL; //NORMAL mode + SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ST_DAC_REGISTER, ssp_pcap_register_val); + /* here dsp device must use AP 13Mhz clock */ + pcap_use_ap_13m_clock(); + + /* set stereo sample rate */ + switch(codec_dac_rate) + { + case STEREO_CODEC_48K_RATE: + SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_48K); + break; + + case STEREO_CODEC_44K_RATE: + SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_44K); + break; + + case STEREO_CODEC_32K_RATE: + SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_32K); + break; + + case STEREO_CODEC_24K_RATE: + SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_24K); + break; + + case STEREO_CODEC_22K_RATE: + SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_22K); + break; + + case STEREO_CODEC_16K_RATE: + SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_16K); + break; + + case STEREO_CODEC_12K_RATE: + SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_12K); + break; + + case STEREO_CODEC_11K_RATE: + SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_11K); + break; + + case STEREO_CODEC_8K_RATE: + SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_8K); + break; + default: + SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_44K); + break; + } +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "codec_dac_rate=%d\n", codec_dac_rate); +#endif + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_INV); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_FS_INV); + + /* (3) reset digital filter(DF_RESET_ST_DAC=1) */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_DF_RESET_ST_DAC); + + /* (4)set bitclk output(SMB_ST_DAC=0), audio IO=part1(DIG_AUD_IN_ST_DAC=1) */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_SMB_ST_DAC); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_DIG_AUD_IN_ST_DAC); + + /* (5) enable pcap clk(ST_CLK_EN=1),enable dac(ST_DAC_EN=1) */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_EN); + mdelay(1); /* specified enable time according spec */ + +#ifdef CONFIG_ARCH_EZX_A780 +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "codec_output_path=%d\n", codec_output_path); + printk(EZXOSS_DEBUG "codec_output_base=%d\n", codec_output_base); +#endif + ret = (*mixer_open_output_path[OUTPUT_BASE_TYPE(codec_output_base)][codec_output_path])(codec_output_base|codec_output_path); +#endif + + undo_mute_output_to_avoid_pcap_noise(); + +#ifdef EZX_OSS_DEBUG + SSP_PCAP_read_data_from_PCAP(0x0d,&ssp_pcap_register_val); + printk(EZXOSS_DEBUG "pcap register 13 = 0x%lx\n", ssp_pcap_register_val); + SSP_PCAP_read_data_from_PCAP(0x0c,&ssp_pcap_register_val); + printk(EZXOSS_DEBUG "pcap register 12 = 0x%lx\n", ssp_pcap_register_val); + SSP_PCAP_read_data_from_PCAP(0x0b,&ssp_pcap_register_val); + printk(EZXOSS_DEBUG "pcap register 11 = 0x%lx\n", ssp_pcap_register_val); + SSP_PCAP_read_data_from_PCAP(0x1a,&ssp_pcap_register_val); + printk(EZXOSS_DEBUG "pcap register 26 = 0x%lx\n", ssp_pcap_register_val); +#endif + timeout = 0; + /* check if ssp is ready for slave operation */ + while(((audiostatus = ASSSR) & ASSSR_CSS) !=0) { + if((timeout++) > 10000000) + goto err; + } + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " complete all hardware init \n"); +#endif + up(&cotulla_assp_mutex); + + return 0; +err: + up(&cotulla_assp_mutex); + printk(EZXOSS_DEBUG "audio panic: ssp don't ready for slave operation!!! "); + return -ENODEV; +} + + +static void assp_shutdown(void) +{ + down(&cotulla_assp_mutex); + + /* clear ASSP port */ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close assp port\n"); +#endif + ASSCR0 = 0; + ASSCR1 = 0; + ASSPSP = 0; + CKEN &= ~CKEN4_ASSP; + + set_GPIO_mode(GPIO_ASSP_SCLK3 | GPIO_IN); /* Assp Frame sync */ + set_GPIO_mode(GPIO_ASSP_TXD3 | GPIO_IN); + set_GPIO_mode(GPIO_ASSP_RXD3 | GPIO_IN); /* ASSP BitCLK */ + set_GPIO_mode(GPIO_ASSP_SFRM3 | GPIO_IN); /* ASsp RX */ + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close pcap register\n"); +#endif + + shutdown_mixer(DSP_DEVICE); + + /* disable PCAP stereo DAC */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_SMB_ST_DAC); + pcap_use_bp_13m_clock(); + + up(&cotulla_assp_mutex); +} + + +/* + * for stereo headset and mono headset insert, it will take A1I interrupt + * in A1I interrupt handler, open MB_ON2 to check if mic connect + */ +void headjack_change_interrupt_routine(int ch, void *dev_id, struct pt_regs *regs) +{ + int bdelay = 20; + + del_timer(&audio_timer); + init_timer(&audio_timer); + audio_timer.function = change_input_output; + audio_timer.expires = (jiffies + bdelay); + add_timer(&audio_timer); +} + + +static void open_mic_interrupt(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "Open mic interrupt\n"); +#endif + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_MB2I ); + udelay(10); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_MSR_MB2M); +} + + +void Set_EMU_Mux_Switch(int mode) +{ + set_GPIO_mode(GPIO_EMU_MUX1 | GPIO_OUT); + set_GPIO_mode(GPIO_EMU_MUX2 | GPIO_OUT); + + switch(mode) + { + case DEFAULT_USB_MODE: + clr_GPIO(GPIO_EMU_MUX1); + clr_GPIO(GPIO_EMU_MUX2); //default mode + break; + + case MONO_AUDIO_MODE: + set_GPIO(GPIO_EMU_MUX1); + clr_GPIO(GPIO_EMU_MUX2); //Mono audio mode + break; + + case SETERO_AUDIO_MODE: + set_GPIO(GPIO_EMU_MUX1); + set_GPIO(GPIO_EMU_MUX2); //Setero audio mode + break; + + default: + break; + } + + printk("::set EMU Mux GPIO.\n"); +} + +void EIHF_Mute(int Flag) +{ + + set_GPIO_mode(GPIO_SNP_INT_CTL | GPIO_OUT); + if(EMU_AUD_test_flag) //At the audio EMU test mode + { + clr_GPIO(GPIO_SNP_INT_CTL); + return; + } + + if(!Flag) + { + clr_GPIO(GPIO_SNP_INT_CTL); + } + else + { + set_GPIO(GPIO_SNP_INT_CTL); // high is active + } + +} + +void Switch_Audio_To_USB() +{ + set_GPIO_mode(GPIO_SNP_INT_IN | GPIO_IN); + + while(1) //If the EMU ID short to GND + { + if(!(GPLR(GPIO_SNP_INT_IN) & GPIO_bit(GPIO_SNP_INT_IN))) + break; + } + EIHF_Mute(EIHF_MUTE); + Set_EMU_Mux_Switch(DEFAULT_USB_MODE); // Switch the MUX to USB mode + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP); // Disable the PCAP loopback + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PS); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU); //Pull up the D+ + + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_USB4VI); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_MSR_USB4VM); + + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_USB1VI); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_MSR_USB1VM); + + EMU_AUD_test_flag = 0; // Restore the default value +} + +void Switch_USB_To_Audio() +{ + EMU_AUD_test_flag = 0xff; // Enter the EMU audio test mode + set_GPIO_mode(GPIO_SNP_INT_IN | GPIO_IN); + + + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_MSR_USB4VM); + + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_MSR_USB1VM); + + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PS); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU); + + + del_timer(&EMU_timer); //Start one timer + init_timer(&EMU_timer); + EMU_timer.function = Switch_Audio_To_USB; + EMU_timer.expires = (jiffies+500); + add_timer(&EMU_timer); +} + + + +static void change_input_output(void) +{ + unsigned long ssp_pcap_bit_status; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "enter headjack change interrupt routine \n"); +#endif + /* read pcap register to check if headjack is in */ + ssp_pcap_bit_status = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_A1SNS); + if(ssp_pcap_bit_status) /* headset is in */ + { +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "headset insert\n"); +#endif + headset_in_handler(0, NULL, NULL); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2); + micinflag = 1; + del_timer(&mic_timer); + init_timer(&mic_timer); + mic_timer.function = open_mic_interrupt; + mic_timer.expires = (jiffies+100); + add_timer(&mic_timer); + } + else /* headset is out */ + { +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "headset remove\n"); +#endif + headset_out_handler(0, NULL, NULL); + micinflag = 0; + del_timer(&mic_timer); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_MB2I); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_MSR_MB2M); + } +} + + +void mic_change_interrupt_routine(int ch, void *dev_id, struct pt_regs *regs) +{ + int ssp_pcap_bit_status; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "enter mic change interrupt routine \n"); +#endif + + /* read pcap register to check if headjack is in */ + ssp_pcap_bit_status = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_A1SNS); + if( ssp_pcap_bit_status ) /* headjack is in */ + { + answer_button_handler(0, NULL, NULL); + } +} + + +/* + * Audio Mixer stuff + */ +int mixer_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret; + int i,j; + long val; + unsigned long ssp_pcap_register_val; + + switch(cmd) + { +#ifdef MAKE_FTR_HAPTICS + case SOUND_MIXER_WRITE_HAPTICS_ON: + Set_Haptics_GPIO(); + break; + case SOUND_MIXER_WRITE_HAPTICS_OFF: + Clear_Haptics_GPIO(); + break; + case SOUND_MIXER_READ_HAPTICS_FIL: + if( (GPDR(GPIO_FLT_SEL_BUL) & GPIO_bit(GPIO_FLT_SEL_BUL))==0 ) + val = 0; + else + val = 1; + return put_user(val, (long *)arg); +#endif + + case SOUND_MIXER_READ_IGAIN: + val = codec_input_gain; +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " read input gain=%d\n", val); +#endif + return put_user(val, (long *)arg); + + case SOUND_MIXER_WRITE_IGAIN: + ret = get_user(val, (long *) arg); + if (ret) + return ret; + + if( (valEZX_OSS_MAX_LOGICAL_GAIN) ) + ret = -EINVAL; + else{ + codec_input_gain = val; +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " write input gain=%d\n", codec_input_gain); +#endif + set_input_gain_hw_reg(); + } + + return put_user(ret, (int *) arg); + + case SOUND_MIXER_READ_OGAIN: + /* read pcap ogain register */ + val = codec_output_gain; +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " read output gain=%d\n", val); +#endif + return put_user(val, (long *)arg); + + case SOUND_MIXER_WRITE_VOLUME: + case SOUND_MIXER_WRITE_OGAIN: + ret = get_user(val, (long *) arg); + if (ret) + return ret; +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " write output gain=%d\n", val); +#endif + + if((val >= EZX_OSS_MIN_LOGICAL_GAIN)&&(val <=EZX_OSS_MAX_LOGICAL_GAIN)) + { + codec_output_gain = val; + /* write pcap ogain register */ + set_output_gain_hw_reg(); + } + else + { + ret = -EINVAL; +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "value is invalid\n"); +#endif + } + return put_user(ret, (int *) arg); + + case SOUND_MIXER_READ_RECSRC: +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " read input path\n"); +#endif + /* read pcap input status, 0-extmic, 1-A5, 2-A3 */ + val = codec_input_path; + return put_user(val, (long *)arg); + + case SOUND_MIXER_WRITE_RECSRC: + ret = get_user(val, (long *) arg); + if (ret) + return ret; +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " force write input path=%d\n", val); +#endif + /* close old input path */ + (*mixer_close_input_path[codec_input_path])(); + /* open input path */ + if( (val>INPUT_PATH_MAX) || (valOUTPUT_BASE_MAX) || (GET_OUTPUT_PATH(val)>OUTPUT_PATH_MAX) ) + ret = -EINVAL; + else + ret = (*mixer_open_output_path[OUTPUT_BASE_TYPE(GET_OUTPUT_BASE(val))][GET_OUTPUT_PATH(val)])(val); + + if( audioonflag == 0 ) + mixer_not_in_use(); /* for power save */ + +#ifdef EZX_OSS_DEBUG + SSP_PCAP_read_data_from_PCAP(0x0c,&ssp_pcap_register_val); + printk(EZXOSS_DEBUG "pcap register 12 = 0x%lx\n", ssp_pcap_register_val); +#endif + return put_user(ret, (int *) arg); + + case SOUND_MIXER_WRITE_MUTE: /* mute output path */ + /* 0-unmute, 1-mute */ + ret = get_user(val, (long *) arg); + if (ret) + return ret; + if(val == 1) /* if mute */ + { +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " mute PGA\n"); +#endif + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN); + } + else if(val == 0) /* unmute */ + { +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "unmute PGA\n"); +#endif + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN); + } + else + { + ret = -EINVAL; + } + return put_user(ret, (int *) arg); + + case SOUND_MIXER_WRITE_INPUTMUTE: /* mute input path for DAI test */ + /* 0-unmute, 1-mute */ + ret = get_user(val, (long *) arg); + if (ret) + return ret; + if(val == 1) /* if mute */ + { +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " mute input\n"); +#endif + (*mixer_close_input_path[codec_input_path])(); + } + else if(val == 0) /* unmute */ + { +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "unmute input\n"); +#endif + (*mixer_open_input_path[codec_input_path])(); + } + else + { + ret = -EINVAL; + } + return put_user(ret, (int *) arg); + + case SOUND_MIXER_WRITE_LOOPBACK: /* set loopback mode for DAI test */ + /* 0-unloopback, 1-loopback */ + ret = get_user(val, (long *) arg); + if (ret) + return ret; + if(val == 1) + { +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "loopback\n"); +#endif + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP); + + + } + else if(val ==0) + { +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "unloopback\n"); +#endif + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP); + } + else + { + ret = -EINVAL; + } + return put_user(ret, (int *) arg); + + case SOUND_MIXER_WRITE_AUDOHPF: /* set audio output High Pass filter for test command */ + /* 0-disable filter, 1-enable filter */ + ret = get_user(val, (long *) arg); + if (ret) + return ret; + if(val == 1) + { +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "enable audio output High Pass filter\n"); +#endif + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDOHPF); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET); + + } + else if(val ==0) + { +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "disable audio output High Pass filter\n"); +#endif + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDOHPF); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET); + } + else + { + ret = -EINVAL; + } + return put_user(ret, (int *) arg); + + case SOUND_MIXER_WRITE_AUDIHPF: /* set audio input High Pass filter for test command */ + /* 0-disable filter, 1-enable filter */ + ret = get_user(val, (long *) arg); + if (ret) + return ret; + if(val == 1) + { +#ifdef EZX_OSS_DEBUG + printk("enable audio input High Pass filter\n"); +#endif + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDIHPF); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET); + + } + else if(val ==0) + { +#ifdef EZX_OSS_DEBUG + printk("disable audio input High Pass filter\n"); +#endif + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDIHPF); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET); + } + else + { + ret = -EINVAL; + } + return put_user(ret, (int *) arg); + + case SOUND_MIXER_WRITE_CODEC_SLAVE: + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_SMB); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET); + return put_user(ret, (int *) arg); + case SOUND_MIXER_READ_HEADSET_STATUS: /* read if headset is in */ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "read headset status, jiffies=%d\n", jiffies); +#endif + + j=0; + for(i=0;i<3;i++) + { + val = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_A1SNS); + if(val) + j++; + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(50*HZ/1000); + } + if(j>=2) + { + ret = STEREO_HEADSET; + micinflag=1; + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_MSR_MB2M); + } + else + { + ret = NO_HEADSET; + micinflag=0; + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_MSR_MB2M); + } + return put_user(ret, (long *)arg); + + case SOUND_MIXER_WRITE_EIHF_MUX: + ret = get_user(val, (long *) arg); + if(ret) + return ret; +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " \n user space is writing MUX status =%d\n", val); +#endif + switch(val) + { + case DEFAULT_USB_MODE: + Set_EMU_Mux_Switch(DEFAULT_USB_MODE); + break; + case MONO_AUDIO_MODE: + Set_EMU_Mux_Switch(MONO_AUDIO_MODE); + break; + case SETERO_AUDIO_MODE: + Set_EMU_Mux_Switch(SETERO_AUDIO_MODE); + break; + default: + ret = -EINVAL; + } + return put_user(ret, (int *) arg); + + case SOUND_MIXER_WRITE_EIHF_MUTE: + ret = get_user(val, (long *) arg); + if(ret) + return ret; +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " \n user space is writing MUTE status =%d\n", val); +#endif + if(val) + EIHF_Mute(EIHF_UNMUTE); + else + EIHF_Mute(EIHF_MUTE); + + return put_user(ret, (int *) arg); + case SOUND_MIXER_WRITE_EMU_TEST: + ret = get_user(val, (long *) arg); + if(ret) + return ret; + Switch_USB_To_Audio(); + return put_user(ret, (int *) arg); + +#ifdef CONFIG_ARCH_EZX_E680 + case SOUND_MIXER_READ_3D_STATUS: + val = get_boomer_3d_status(); +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " read e680 3d status =%d\n", val); +#endif + return put_user(val, (long *)arg); + + case SOUND_MIXER_WRITE_3D_STATUS: + ret = get_user(val, (long *) arg); + if(ret) + return ret; +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " user space is writing 3d status =%d\n", val); +#endif + + if( (valLOUDERSPEAKER_OFF_HEADSET_OFF_3D) ) + ret = -EINVAL; + else + set_boomer_3d_status((boomer_3d_status)val); + + return put_user(ret, (int *) arg); +#endif + +#ifdef CONFIG_ARCH_EZX_A780 + case SOUND_MIXER_WRITE_HW_ATTENU: + ret = get_user(val, (long *) arg); + if(ret) + return ret; + + if(val == HW_ATTENUATION_USED){ + use_hw_noise_attenuate(); + ret = HW_ATTENUATION_USED; + } + else if(val == HW_ATTENUATION_BYPASSED){ + bypass_hw_noise_attenuate(); + ret = HW_ATTENUATION_BYPASSED; + } + else + ret = -EINVAL; + + return put_user(ret, (int *) arg); +#endif + + default: + return -EINVAL; + } + + return 0; +} + + +static struct file_operations mixer_fops = { + ioctl: mixer_ioctl, + owner: THIS_MODULE +}; + +/* + * ASSP codec ioctls + */ + +static int assp_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret; + long val; + int audiostatus, timeout; + + switch(cmd) { + case SNDCTL_DSP_STEREO: +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " check if support stereo\n"); +#endif + ret = get_user(val, (int *) arg); + if (ret) + return ret; + if(file->f_mode & FMODE_WRITE) + { + if(val) /* write only support stereo mode */ + ret = 1; + else /* not support mono mode */ + ret = -EINVAL; + } + else + { + ret = -EINVAL; + } + return put_user(ret, (int *) arg); + + case SNDCTL_DSP_CHANNELS: + case SOUND_PCM_READ_CHANNELS: +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " check if 2 channels \n"); +#endif + if(file->f_mode & FMODE_WRITE) + { + return put_user(2, (long *) arg); + } + else + { + ret = -EINVAL; + return put_user(ret, (long *) arg); + } + + case SNDCTL_DSP_SPEED: +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " set sample frequency \n"); +#endif + ret = get_user(val, (long *) arg); + if (ret) + return ret; + + if(file->f_mode & FMODE_WRITE) + { + down(&cotulla_assp_mutex); + ASSCR0 &= ~ASSCR0_SSE; + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_EN); + switch(val) + { + case STEREO_CODEC_48K_RATE: + ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_48K); + /* set pcap dac sample rate */ + codec_dac_rate = val; + break; + + case STEREO_CODEC_44K_RATE: + ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_44K); + /* set pcap dac sample rate */ + codec_dac_rate = val; + break; + + case STEREO_CODEC_32K_RATE: + ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_32K); + /* set pcap dac sample rate */ + codec_dac_rate = val; + break; + + case STEREO_CODEC_24K_RATE: + ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_24K); + /* set pcap dac sample rate */ + codec_dac_rate = val; + break; + + case STEREO_CODEC_22K_RATE: + ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_22K); + /* set pcap dac sample rate */ + codec_dac_rate = val; + break; + + case STEREO_CODEC_16K_RATE: + ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_16K); + /* set pcap dac sample rate */ + codec_dac_rate = val; + break; + + case STEREO_CODEC_12K_RATE: + ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_12K); + /* set pcap dac sample rate */ + codec_dac_rate = val; + break; + + case STEREO_CODEC_11K_RATE: + ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_11K); + /* set pcap dac sample rate */ + codec_dac_rate = val; + break; + + case STEREO_CODEC_8K_RATE: + ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_8K); + /* set pcap dac sample rate */ + codec_dac_rate = val; + break; + default: + ret = -EINVAL; + break; + } + /* reset digital filter(DF_RESET_ST_DAC=1) */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_DF_RESET_ST_DAC); + + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_EN); +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "DA sample freq = %d\n", codec_dac_rate); +#endif + ASSCR0 |= ASSCR0_SSE; /* enable assp controller */ + timeout = 0; + /* check if ssp is ready for slave operation */ + while(((audiostatus = ASSSR) & ASSSR_CSS) !=0) + { + if((timeout++) > 10000000) + { + printk(EZXOSS_DEBUG "audio panic: can't be slave mode!!!"); + ret = -ENODEV; + break; + } + } + up(&cotulla_assp_mutex); + } + else + { + ret = -EINVAL; + } + return put_user(codec_dac_rate, (long *) arg); + + case SOUND_PCM_READ_RATE: + if (file->f_mode & FMODE_WRITE) + { +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "read DA sample freq\n"); +#endif + val = codec_dac_rate; + } + else + { + val = -EINVAL; + } + return put_user(val, (long *) arg); + + case SNDCTL_DSP_SETFMT: + case SNDCTL_DSP_GETFMTS: + /* SUPPORT little endian signed 16 */ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "data format is AFMT_S16_LEd\n"); +#endif + return put_user(AFMT_S16_LE, (long *) arg); + + default: + return mixer_ioctl(inode, file, cmd, arg); + } + return 0; +} + + +/* + * Audio stuff + */ +static audio_stream_t assp_audio_out = { + name: "assp audio out", + dcmd: DCMD_TXASSDR, + drcmr: &DRCMRTXASSDR, /* ASSP dma map register */ + dev_addr: __PREG(ASSDR), +}; + + +static audio_stream_t assp_audio_in = { + name: "assp audio in", + dcmd: DCMD_RXASSDR, + drcmr: &DRCMRRXASSDR, /* ASSP dma map register */ + dev_addr: __PREG(ASSDR), +}; + + +static audio_state_t assp_audio_state = { + output_stream: &assp_audio_out, + input_stream: &assp_audio_in, + client_ioctl: assp_ioctl, + hw_init: assp_init, + hw_shutdown: assp_shutdown, + sem: __MUTEX_INITIALIZER(assp_audio_state.sem), +}; + + +static int assp_audio_open(struct inode *inode, struct file *file) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "assp audio open \n"); +#endif + + return cotulla_audio_attach(inode, file, &assp_audio_state); +} + + +/* + * Missing fields of this structure will be patched with the call + * to cotulla_audio_attach(). + */ +static struct file_operations assp_audio_fops = { + open: assp_audio_open, + owner: THIS_MODULE +}; + + +static int mixer_dev_id; + +static int __init cotulla_assp_init(void) +{ + assp_audio_state.dev_dsp = register_sound_dsp(&assp_audio_fops, -1); + mixer_dev_id = register_sound_mixer(&mixer_fops, -1); + + set_GPIO_mode(GPIO_ASSP_SCLK3 | GPIO_IN); /* Assp Frame sync */ + set_GPIO_mode(GPIO_ASSP_TXD3 | GPIO_IN); + set_GPIO_mode(GPIO_ASSP_RXD3 | GPIO_IN); /* ASSP BitCLK */ + set_GPIO_mode(GPIO_ASSP_SFRM3 | GPIO_IN); /* ASsp RX */ + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR); + +#ifdef CONFIG_ARCH_EZX_E680 + Clear_Haptics_GPIO(); + e680_boomer_init(); +#endif + +#ifdef CONFIG_PM + mixer_hw_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, mixer_hw_pm_callback); +#endif + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "cotulla-assp-init ok\n"); +#endif + return 0; +} + + +static void __exit cotulla_assp_exit(void) +{ + unregister_sound_dsp(assp_audio_state.dev_dsp); + unregister_sound_mixer(mixer_dev_id); + +#ifdef CONFIG_ARCH_EZX_E680 + e680_boomer_shutdown(); +#endif + + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR); + +#ifdef CONFIG_PM + pm_unregister(mixer_hw_pm_dev); +#endif + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "cotulla-assp-exit ok\n"); +#endif +} + + +module_init(cotulla_assp_init); +module_exit(cotulla_assp_exit); + + diff -Nru --exclude-from=/sunbeam/home/laforge/scripts/dontdiff linux-2.6.16.5/sound/oss/ezx-audio.c linux-2.6.16.5-exz/sound/oss/ezx-audio.c --- linux-2.6.16.5/sound/oss/ezx-audio.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.5-exz/sound/oss/ezx-audio.c 2006-04-16 18:49:29.000000000 +0200 @@ -0,0 +1,1122 @@ +/* + * linux/drivers/sound/ezx-audio.c + * + * + * Description: audio interface for ezx + * + * + * Copyright: BJDC motorola. + * + * This program 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. + * + * + * History: + * zhouqiong Jun 20,2002 created + * LiYong Sep 23,2003 (1)Port from EZX + * Jin Lihong(w20076) Jan 02,2004,Libdd66088 (1) Port from UDC e680 kernel of jem vob. + * (2) Move audio driver DEBUG macro definition to ezx-audio.h + * header file,and redefine DEBUG to EZX_OSS_AUDIO_DEBUG + * (3) reorganize file header + * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Make the e680 louder speaker work. + * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix + * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 close dsp protection,and add 3d control interface for app + * Jin Lihong(w20076) Jun.15,2004,LIBee21625 boomer's power management + * Jin Lihong(w20076) Aug.11,2004,LIBff01482 DMA channel release bug fix + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ezx-common.h" +#include "ezx-audio.h" + + +#define AUDIO_NBFRAGS_DEFAULT 8 +#define AUDIO_FRAGSIZE_DEFAULT 8192 + +#define MAX_DMA_SIZE 4096 +#define DMA_DESC_SIZE sizeof(pxa_dma_desc) + +#define AUDIO_ACTIVE(state) ((state)->rd_ref || (state)->wr_ref) + + +/* + * This function frees all buffers + */ +static void audio_clear_buf(audio_stream_t *s) +{ + DECLARE_WAITQUEUE(wait, current); + int frag; + + if (!s->buffers) + return; + + /* Ensure DMA isn't running */ +#ifdef EZX_OSS_AUDIO_DEBUG + printk("ensure dma isn't running\n"); +#endif + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&s->stop_wq, &wait); + DCSR(s->dma_ch) = DCSR_STOPIRQEN; + schedule(); + remove_wait_queue(&s->stop_wq, &wait); +#ifdef EZX_OSS_AUDIO_DEBUG + printk("free dma buffers\n"); +#endif + /* free DMA buffers */ + for (frag = 0; frag < s->nbfrags; frag++) { + audio_buf_t *b = &s->buffers[frag]; + if (!b->master) + continue; + consistent_free(b->data, b->master, b->dma_desc->dsadr); + } +#ifdef EZX_OSS_AUDIO_DEBUG + printk("free descriptor buffers\n"); +#endif + /* free descriptor ring */ + if (s->buffers->dma_desc) + consistent_free(s->buffers->dma_desc, + s->nbfrags * s->descs_per_frag * DMA_DESC_SIZE, + s->dma_desc_phys); + + /* free buffer structure array */ + kfree(s->buffers); + s->buffers = NULL; +} + +/* + * This function allocates the DMA descriptor array and buffer data space + * according to the current number of fragments and fragment size. + */ +static int audio_setup_buf(audio_stream_t *s) +{ + pxa_dma_desc *dma_desc; + dma_addr_t dma_desc_phys; + int nb_desc, frag, i, buf_size = 0; + char *dma_buf = NULL; + dma_addr_t dma_buf_phys = 0; + + if (s->buffers) + return -EBUSY; +#ifdef EZX_OSS_AUDIO_DEBUG + printk("audio setup buffer \n"); +#endif + /* Our buffer structure array */ + s->buffers = kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL); + if (!s->buffers) + goto err; + memzero(s->buffers, sizeof(audio_buf_t) * s->nbfrags); + + /* + * Our DMA descriptor array: + * for Each fragment we have one checkpoint descriptor plus one + * descriptor per MAX_DMA_SIZE byte data blocks. + */ +#ifdef EZX_OSS_AUDIO_DEBUG + printk("malloc descriptor memory\n"); +#endif + nb_desc = (1 + (s->fragsize + MAX_DMA_SIZE - 1)/MAX_DMA_SIZE) * s->nbfrags; + dma_desc = consistent_alloc(GFP_KERNEL, + nb_desc * DMA_DESC_SIZE, + &dma_desc_phys); + if (!dma_desc) + goto err; + s->descs_per_frag = nb_desc / s->nbfrags; + s->buffers->dma_desc = dma_desc; + s->dma_desc_phys = dma_desc_phys; + for (i = 0; i < nb_desc - 1; i++) + dma_desc[i].ddadr = dma_desc_phys + (i + 1) * DMA_DESC_SIZE; + dma_desc[i].ddadr = dma_desc_phys; +#ifdef EZX_OSS_AUDIO_DEBUG + printk("malloc dma memory\n"); +#endif + /* Our actual DMA buffers */ + for (frag = 0; frag < s->nbfrags; frag++) { + audio_buf_t *b = &s->buffers[frag]; + + /* + * Let's allocate non-cached memory for DMA buffers. + * We try to allocate all memory at once. + * If this fails (a common reason is memory fragmentation), + * then we'll try allocating smaller buffers. + */ + if (!buf_size) { + buf_size = (s->nbfrags - frag) * s->fragsize; + do { + dma_buf = consistent_alloc(GFP_KERNEL, + buf_size, + &dma_buf_phys); + if (!dma_buf) + buf_size -= s->fragsize; + } while (!dma_buf && buf_size); + if (!dma_buf) + goto err; + b->master = buf_size; + memzero(dma_buf, buf_size); + } + + /* + * Set up our checkpoint descriptor. Since the count + * is always zero, we'll abuse the dsadr and dtadr fields + * just in case this one is picked up by the hardware + * while processing SOUND_DSP_GETPTR. + */ + dma_desc->dsadr = dma_buf_phys; + dma_desc->dtadr = dma_buf_phys; + dma_desc->dcmd = DCMD_ENDIRQEN; + if (s->output && !s->mapped) + dma_desc->ddadr |= DDADR_STOP; + b->dma_desc = dma_desc++; + + /* set up the actual data descriptors */ + for (i = 0; (i * MAX_DMA_SIZE) < s->fragsize; i++) { + dma_desc[i].dsadr = (s->output) ? + (dma_buf_phys + i*MAX_DMA_SIZE) : s->dev_addr; + dma_desc[i].dtadr = (s->output) ? + s->dev_addr : (dma_buf_phys + i*MAX_DMA_SIZE); + dma_desc[i].dcmd = s->dcmd | + ((s->fragsize < MAX_DMA_SIZE) ? + s->fragsize : MAX_DMA_SIZE); + } + dma_desc += i; + + /* handle buffer pointers */ + b->data = dma_buf; + dma_buf += s->fragsize; + dma_buf_phys += s->fragsize; + buf_size -= s->fragsize; + } + + s->usr_frag = s->dma_frag = 0; + s->bytecount = 0; + s->getptrCount = 0; + s->fragcount = 0; + sema_init(&s->sem, (s->output) ? s->nbfrags : 0); + return 0; + +err: + printk("cotulla-audio: unable to allocate audio memory\n "); + audio_clear_buf(s); + return -ENOMEM; +} + +/* + * Our DMA interrupt handler + */ +static void audio_dma_irq(int ch, void *dev_id, struct pt_regs *regs) +{ + audio_stream_t *s = dev_id; + u_int dcsr; + + dcsr = DCSR(ch); +#ifdef EZX_OSS_AUDIO_DEBUG + printk("dcsr=0x%lx\n", dcsr); +#endif + DCSR(ch) = dcsr & ~DCSR_STOPIRQEN; + + if (!s->buffers) { + printk("SSP DMA: wow... received IRQ for channel %d but no buffer exists\n", ch); + return; + } + + if (dcsr & DCSR_BUSERR) + printk("SSP DMA: bus error interrupt on channel %d\n", ch); + + if (dcsr & DCSR_ENDINTR) + { + u_long cur_dma_desc; + u_int cur_dma_frag; + + /* + * Find out which DMA desc is current. Note that DDADR + * points to the next desc, not the current one. + */ + cur_dma_desc = DDADR(ch) - s->dma_desc_phys - DMA_DESC_SIZE; + /* + * Let the compiler nicely optimize constant divisors into + * multiplications for the common cases which is much faster. + * Common cases: x = 1 + (1 << y) for y = [0..3] + */ + switch (s->descs_per_frag) { + case 2: cur_dma_frag = cur_dma_desc / (2*DMA_DESC_SIZE); break; + case 3: cur_dma_frag = cur_dma_desc / (3*DMA_DESC_SIZE); break; + case 5: cur_dma_frag = cur_dma_desc / (5*DMA_DESC_SIZE); break; + case 9: cur_dma_frag = cur_dma_desc / (9*DMA_DESC_SIZE); break; + default: cur_dma_frag = + cur_dma_desc / (s->descs_per_frag * DMA_DESC_SIZE); + } + + /* Account for possible wrap back of cur_dma_desc above */ + if (cur_dma_frag >= s->nbfrags) + cur_dma_frag = s->nbfrags - 1; + +#ifdef EZX_OSS_AUDIO_DEBUG + printk("cur_dma_frag=0x%lx\n", cur_dma_frag); + printk("s->dma_frag=0x%lx\n", s->dma_frag); +#endif + while (s->dma_frag != cur_dma_frag) { + if (!s->mapped) { + /* + * This fragment is done - set the checkpoint + * descriptor to STOP until it is gets + * processed by the read or write function. + */ + s->buffers[s->dma_frag].dma_desc->ddadr |= DDADR_STOP; + up(&s->sem); + } + if (++s->dma_frag >= s->nbfrags) + s->dma_frag = 0; + + /* Accounting */ + s->bytecount += s->fragsize; + s->fragcount++; + } + + /* ... and for polling processes */ + wake_up(&s->frag_wq); + } + + if ((dcsr & DCSR_STOPIRQEN) && (dcsr & DCSR_STOPSTATE)) + wake_up(&s->stop_wq); +#ifdef EZX_OSS_AUDIO_DEBUG + printk("audio dma irq complete\n"); +#endif +} + +/* + * Validate and sets up buffer fragments, etc. + */ +static int audio_set_fragments(audio_stream_t *s, int val) +{ + if (s->mapped || DCSR(s->dma_ch) & DCSR_RUN) + return -EBUSY; + if (s->buffers) + audio_clear_buf(s); +#ifdef EZX_OSS_AUDIO_DEBUG + printk("audio set fragments\n"); +#endif + s->nbfrags = (val >> 16) & 0x7FFF; + val &= 0xffff; + if (val < 5) + val = 5; + if (val > 15) + val = 15; + s->fragsize = 1 << val; + if (s->nbfrags < 2) + s->nbfrags = 2; + if (s->nbfrags * s->fragsize > 256 * 1024) + s->nbfrags = 256 * 1024 / s->fragsize; + if (audio_setup_buf(s)) + return -ENOMEM; + return val|(s->nbfrags << 16); +} + + +/* + * The fops functions + */ + +static int audio_write(struct file *file, const char *buffer, + size_t count, loff_t *ppos) +{ + const char *buffer0 = buffer; + audio_state_t *state = (audio_state_t *)file->private_data; + audio_stream_t *s = state->output_stream; + int chunksize, ret = 0; + unsigned int audiostatus; + + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->mapped) + return -ENXIO; + if (!s->buffers && audio_setup_buf(s)) + return -ENOMEM; + +#ifdef EZX_OSS_AUDIO_DEBUG + printk("enter audio write \n"); + printk("buffer0=0x%lx\n", buffer0); + printk("count=%d\n", count); +#endif + while (count > 0) { + audio_buf_t *b = &s->buffers[s->usr_frag]; + + /* Grab a fragment */ + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + if (down_trylock(&s->sem)) + break; + } else { + ret = -ERESTARTSYS; + if (down_interruptible(&s->sem)) + break; + } + + /* Feed the current buffer */ + chunksize = s->fragsize - b->offset; + if (chunksize > count) + chunksize = count; + if (copy_from_user(b->data + b->offset, buffer, chunksize)) { + up(&s->sem); + return -EFAULT; + } + b->offset += chunksize; + buffer += chunksize; + + count -= chunksize; + if (b->offset < s->fragsize) { + up(&s->sem); + break; + } + + /* + * Activate DMA on current buffer. + * We unlock this fragment's checkpoint descriptor and + * kick DMA if it is idle. Using checkpoint descriptors + * allows for control operations without the need for + * stopping the DMA channel if it is already running. + */ + b->offset = 0; +#ifdef EZX_OSS_AUDIO_DEBUG + printk("enable dma run\n"); +#endif + b->dma_desc->ddadr &= ~DDADR_STOP; + if (DCSR(s->dma_ch) & DCSR_STOPSTATE) { + DDADR(s->dma_ch) = b->dma_desc->ddadr; + DCSR(s->dma_ch) = DCSR_RUN; + } + + /* move the index to the next fragment */ + if (++s->usr_frag >= s->nbfrags) + s->usr_frag = 0; + } + + if ((buffer - buffer0)) + ret = buffer - buffer0; +#ifdef EZX_OSS_AUDIO_DEBUG + printk("write bytes=0x%x \n", ret); +#endif + return ret; +} + + +static int audio_read(struct file *file, char *buffer, + size_t count, loff_t *ppos) +{ + char *buffer0 = buffer; + audio_state_t *state = file->private_data; + audio_stream_t *s = state->input_stream; + int chunksize, ret = 0; + + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->mapped) + return -ENXIO; + if (!s->buffers && audio_setup_buf(s)) + return -ENOMEM; + +#ifdef EZX_OSS_AUDIO_DEBUG + printk("enter audio read \n"); + printk("buffer0=0x%lx\n", buffer0); + printk("count=%d\n", count); +#endif + while (count > 0) { + audio_buf_t *b = &s->buffers[s->usr_frag]; + + /* prime DMA */ + if (DCSR(s->dma_ch) & DCSR_STOPSTATE) { + DDADR(s->dma_ch) = + s->buffers[s->dma_frag].dma_desc->ddadr; + DCSR(s->dma_ch) = DCSR_RUN; + } + + /* Wait for a buffer to become full */ + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + if (down_trylock(&s->sem)) + break; + } else { + ret = -ERESTARTSYS; + if (down_interruptible(&s->sem)) + break; + } + + /* Grab data from current buffer */ + chunksize = s->fragsize - b->offset; + if (chunksize > count) + chunksize = count; + if (copy_to_user(buffer, b->data + b->offset, chunksize)) { + up(&s->sem); + return -EFAULT; + } + b->offset += chunksize; + buffer += chunksize; + count -= chunksize; + if (b->offset < s->fragsize) { + up(&s->sem); + break; + } + + /* + * Make this buffer available for DMA again. + * We unlock this fragment's checkpoint descriptor and + * kick DMA if it is idle. Using checkpoint descriptors + * allows for control operations without the need for + * stopping the DMA channel if it is already running. + */ + b->offset = 0; + b->dma_desc->ddadr &= ~DDADR_STOP; + + /* move the index to the next fragment */ + if (++s->usr_frag >= s->nbfrags) + s->usr_frag = 0; + } + + if ((buffer - buffer0)) + ret = buffer - buffer0; +#ifdef EZX_OSS_AUDIO_DEBUG + printk("read bytes=0x%x \n", ret); +#endif + return ret; +} + + +static int audio_sync(struct file *file) +{ + audio_state_t *state = file->private_data; + audio_stream_t *s = state->output_stream; + audio_buf_t *b; + pxa_dma_desc *final_desc; + u_long dcmd_save = 0; + DECLARE_WAITQUEUE(wait, current); + + if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped) + return 0; +#ifdef EZX_OSS_AUDIO_DEBUG + printk("enter audio sync \n"); +#endif + /* + * Send current buffer if it contains data. Be sure to send + * a full sample count. + */ + final_desc = NULL; + b = &s->buffers[s->usr_frag]; + if (b->offset &= ~3) + { + final_desc = &b->dma_desc[1 + b->offset/MAX_DMA_SIZE]; + b->offset &= (MAX_DMA_SIZE-1); + dcmd_save = final_desc->dcmd; + final_desc->dcmd = b->offset | s->dcmd | DCMD_ENDIRQEN; + final_desc->ddadr |= DDADR_STOP; + b->offset = 0; + b->dma_desc->ddadr &= ~DDADR_STOP; + if (DCSR(s->dma_ch) & DCSR_STOPSTATE) { + DDADR(s->dma_ch) = b->dma_desc->ddadr; + DCSR(s->dma_ch) = DCSR_RUN; + } + } + + /* Wait for DMA to complete. */ + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&s->frag_wq, &wait); + while ((DCSR(s->dma_ch) & DCSR_RUN) && !signal_pending(current)) { + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&s->frag_wq, &wait); + + /* Restore the descriptor chain. */ + if (final_desc) { + final_desc->dcmd = dcmd_save; + final_desc->ddadr &= ~DDADR_STOP; + b->dma_desc->ddadr |= DDADR_STOP; + } + return 0; +} + + +static unsigned int audio_poll(struct file *file, + struct poll_table_struct *wait) +{ + audio_state_t *state = file->private_data; + audio_stream_t *is = state->input_stream; + audio_stream_t *os = state->output_stream; + unsigned int mask = 0; + +#ifdef EZX_OSS_AUDIO_DEBUG + printk("enter audio poll \n"); +#endif + if (file->f_mode & FMODE_READ) { + /* Start audio input if not already active */ + if (!is->buffers && audio_setup_buf(is)) + return -ENOMEM; + if (DCSR(is->dma_ch) & DCSR_STOPSTATE) { + DDADR(is->dma_ch) = + is->buffers[is->dma_frag].dma_desc->ddadr; + DCSR(is->dma_ch) = DCSR_RUN; + } + poll_wait(file, &is->frag_wq, wait); + } + + if (file->f_mode & FMODE_WRITE) { + if (!os->buffers && audio_setup_buf(os)) + return -ENOMEM; + poll_wait(file, &os->frag_wq, wait); + } + + if (file->f_mode & FMODE_READ) + if (( is->mapped && (is->bytecount != is->getptrCount)) || + (!is->mapped && atomic_read(&is->sem.count) > 0)) + mask |= POLLIN | POLLRDNORM; + + if (file->f_mode & FMODE_WRITE) + if (( os->mapped && (os->bytecount != os->getptrCount)) || + (!os->mapped && atomic_read(&os->sem.count) > 0)) + mask |= POLLOUT | POLLWRNORM; + + return mask; +} + + +static int audio_ioctl( struct inode *inode, struct file *file, + uint cmd, ulong arg) +{ + audio_state_t *state = file->private_data; + audio_stream_t *os = state->output_stream; + audio_stream_t *is = state->input_stream; + long val; + + switch (cmd) { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, (int *)arg); + + case SNDCTL_DSP_GETBLKSIZE: +#ifdef EZX_OSS_AUDIO_DEBUG + printk("get block size\n"); +#endif + if (file->f_mode & FMODE_WRITE) + return put_user(os->fragsize, (int *)arg); + else + return put_user(is->fragsize, (int *)arg); + + case SNDCTL_DSP_GETCAPS: +#ifdef EZX_OSS_AUDIO_DEBUG + printk("get audio capability \n"); +#endif + val = DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP; + if (is && os) + val |= DSP_CAP_DUPLEX; + return put_user(val, (int *)arg); + + case SNDCTL_DSP_SETFRAGMENT: +#ifdef EZX_OSS_AUDIO_DEBUG + printk("set fragment no\n"); +#endif + if (get_user(val, (long *) arg)) + return -EFAULT; + + if (file->f_mode & FMODE_READ) + { + int ret = audio_set_fragments(is, val); + if (ret < 0) + return ret; + ret = put_user(ret, (int *)arg); + if (ret) + return ret; + } + if (file->f_mode & FMODE_WRITE) + { + int ret = audio_set_fragments(os, val); + if (ret < 0) + return ret; + ret = put_user(ret, (int *)arg); + if (ret) + return ret; + } + return 0; + + case SNDCTL_DSP_SYNC: + return audio_sync(file); + + case SNDCTL_DSP_SETDUPLEX: + return 0; + + case SNDCTL_DSP_POST: + return 0; + + case SNDCTL_DSP_GETTRIGGER: +#ifdef EZX_OSS_AUDIO_DEBUG + printk("get trigger\n"); +#endif + val = 0; + if (file->f_mode & FMODE_READ && DCSR(is->dma_ch) & DCSR_RUN) + val |= PCM_ENABLE_INPUT; + if (file->f_mode & FMODE_WRITE && DCSR(os->dma_ch) & DCSR_RUN) + val |= PCM_ENABLE_OUTPUT; + return put_user(val, (int *)arg); + + case SNDCTL_DSP_SETTRIGGER: +#ifdef EZX_OSS_AUDIO_DEBUG + printk("set trigger\n"); +#endif + if (get_user(val, (int *)arg)) + return -EFAULT; + if (file->f_mode & FMODE_READ) + { + if (val & PCM_ENABLE_INPUT) + { + if (!is->buffers && audio_setup_buf(is)) + return -ENOMEM; + if (!(DCSR(is->dma_ch) & DCSR_RUN)) + { + audio_buf_t *b = &is->buffers[is->dma_frag]; + DDADR(is->dma_ch) = b->dma_desc->ddadr; + DCSR(is->dma_ch) = DCSR_RUN; +#ifdef EZX_OSS_AUDIO_DEBUG + printk("start read dma channel\n"); +#endif + } + } else{ + DCSR(is->dma_ch) = 0; + } + } + if (file->f_mode & FMODE_WRITE) + { + if (val & PCM_ENABLE_OUTPUT) + { + if (!os->buffers && audio_setup_buf(os)) + return -ENOMEM; + if (!(DCSR(os->dma_ch) & DCSR_RUN)) { + audio_buf_t *b = &os->buffers[os->dma_frag]; + DDADR(os->dma_ch) = b->dma_desc->ddadr; + DCSR(os->dma_ch) = DCSR_RUN; +#ifdef EZX_OSS_AUDIO_DEBUG + printk("start write dma channel\n"); +#endif + } + } else{ + DCSR(os->dma_ch) = 0; + } + } + return 0; + + case SNDCTL_DSP_GETOSPACE: + case SNDCTL_DSP_GETISPACE: + { + audio_buf_info inf = { 0, }; + audio_stream_t *s = (cmd == SNDCTL_DSP_GETOSPACE) ? os : is; +#ifdef EZX_OSS_AUDIO_DEBUG + printk("get input and output space size\n"); +#endif + if ((s == is && !(file->f_mode & FMODE_READ)) || + (s == os && !(file->f_mode & FMODE_WRITE))) + return -EINVAL; + if (!s->buffers && audio_setup_buf(s)) + return -ENOMEM; + + inf.bytes = atomic_read(&s->sem.count) * s->fragsize; + inf.bytes -= s->buffers[s->usr_frag].offset; + inf.fragments = inf.bytes / s->fragsize; + inf.fragsize = s->fragsize; + inf.fragstotal = s->nbfrags; + + return copy_to_user((void *)arg, &inf, sizeof(inf)); + } + + case SNDCTL_DSP_GETOPTR: + case SNDCTL_DSP_GETIPTR: + { + count_info inf = { 0, }; + audio_stream_t *s = (cmd == SNDCTL_DSP_GETOPTR) ? os : is; + dma_addr_t ptr; + int bytecount, offset, flags; +#ifdef EZX_OSS_AUDIO_DEBUG + printk("get input and output pointer\n"); +#endif + if ((s == is && !(file->f_mode & FMODE_READ)) || + (s == os && !(file->f_mode & FMODE_WRITE))) + return -EINVAL; + + if (DCSR(s->dma_ch) & DCSR_RUN) + { + audio_buf_t *b; + save_flags_cli(flags); + ptr = (s->output) ? DSADR(s->dma_ch) : DTADR(s->dma_ch); + b = &s->buffers[s->dma_frag]; + offset = ptr - b->dma_desc->dsadr; + if (offset >= s->fragsize) + offset = s->fragsize - 4; + } else + { + save_flags(flags); + offset = 0; + } + inf.ptr = s->dma_frag * s->fragsize + offset; + bytecount = s->bytecount + offset; + s->getptrCount = s->bytecount; /* so poll can tell if it changes */ + inf.blocks = s->fragcount; + s->fragcount = 0; + restore_flags(flags); + if (bytecount < 0) + bytecount = 0; + inf.bytes = bytecount; + return copy_to_user((void *)arg, &inf, sizeof(inf)); + } + + case SNDCTL_DSP_NONBLOCK: +#ifdef EZX_OSS_AUDIO_DEBUG + printk("set device none block mode\n"); +#endif + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_GETODELAY: + { + int count = 0, offset; + int i; + int flags; + audio_buf_t *b; + dma_addr_t ptr; +#ifdef EZX_OSS_AUDIO_DEBUG + printk("get output delay\n "); +#endif + if(!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if(!os->buffers && audio_setup_buf(os)) + return -ENOMEM; + + save_flags_cli(flags); + for(i = 0; i < os->nbfrags; i++){ + /* if contain data */ + if(atomic_read(&os->sem.count) <= 0){ + count += os->fragsize; + } + } + if (DCSR(os->dma_ch) & DCSR_RUN) + { + ptr = DSADR(os->dma_ch); + b = &os->buffers[os->dma_frag]; + offset = ptr - b->dma_desc->dsadr; + if (offset >= os->fragsize) + offset = os->fragsize - 4; + } else + { + offset = 0; + } + count -= offset; + restore_flags(flags); + return put_user(count,(int *)arg); + } + + case SNDCTL_DSP_RESET: +#ifdef EZX_OSS_AUDIO_DEBUG + printk("reset audio data buffer\n"); +#endif + if (file->f_mode & FMODE_WRITE) + audio_clear_buf(os); + if (file->f_mode & FMODE_READ) + audio_clear_buf(is); + return 0; + + default: + return state->client_ioctl(inode, file, cmd, arg); + } + + return 0; +} + + +static int audio_mmap(struct file *file, struct vm_area_struct *vma) +{ + audio_state_t *state = file->private_data; + audio_stream_t *s; + unsigned long size, vma_addr; + int i, ret; + + if (vma->vm_pgoff != 0) + return -EINVAL; + + if (vma->vm_flags & VM_WRITE) { + if (!state->wr_ref) + return -EINVAL; + s = state->output_stream; + } else if (vma->vm_flags & VM_READ) { + if (!state->rd_ref) + return -EINVAL; + s = state->input_stream; + } else return -EINVAL; + + if (s->mapped) + return -EINVAL; + +#ifdef EZX_OSS_AUDIO_DEBUG + printk("enter audio mmap \n"); +#endif + size = vma->vm_end - vma->vm_start; + if (size != s->fragsize * s->nbfrags) + return -EINVAL; + if (!s->buffers && audio_setup_buf(s)) + return -ENOMEM; + + vma_addr = vma->vm_start; + for (i = 0; i < s->nbfrags; i++) { + audio_buf_t *buf = &s->buffers[i]; + if (!buf->master) + continue; + ret = remap_page_range(vma_addr, buf->dma_desc->dsadr, + buf->master, vma->vm_page_prot); + if (ret) + return ret; + vma_addr += buf->master; + } + for (i = 0; i < s->nbfrags; i++) + s->buffers[i].dma_desc->ddadr &= ~DDADR_STOP; + + s->mapped = 1; + return 0; +} + + +static int audio_release(struct inode *inode, struct file *file) +{ + audio_state_t *state = file->private_data; + audio_stream_t *is = state->input_stream; + audio_stream_t *os = state->output_stream; + + down(&state->sem); + +#ifdef EZX_OSS_AUDIO_DEBUG + printk("enter audio release \n"); +#endif + if (file->f_mode & FMODE_READ) + { + audio_clear_buf(state->input_stream); + *is->drcmr = 0; + pxa_free_dma(is->dma_ch); + state->rd_ref = 0; + } + + if (file->f_mode & FMODE_WRITE) + { + audio_sync(file); + audio_clear_buf(state->output_stream); + *os->drcmr = 0; + pxa_free_dma(os->dma_ch); + state->wr_ref = 0; + } + + if (!AUDIO_ACTIVE(state)) { + if (state->hw_shutdown) + state->hw_shutdown(); +#ifdef CONFIG_PM + pm_unregister(state->pm_dev); +#endif + } + + up(&state->sem); + return 0; +} + +#ifdef CONFIG_PM +static int audio_dma_sleep(audio_stream_t *s) +{ + dmach_t channel; + + channel = s->dma_ch; + DCSR(channel)=DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; +#ifdef EZX_OSS_AUDIO_DEBUG + printk("DINT=0x%lx\n", DINT); + printk("DCSR(%d)=0x%lx\n", channel, DCSR(channel)); + printk("s->dcmd=0x%lx\n", s->dcmd); + printk("*s->drcmr=0x%lx\n", *s->drcmr); + printk("DDADR(%d)=0x%lx\n", channel, DDADR(channel)); +#endif + return 0; +} + +static int audio_dma_wakeup(audio_stream_t *s) +{ + dmach_t channel; + + channel = s->dma_ch; + DCSR(channel)=DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; + *s->drcmr = s->dma_ch | DRCMR_MAPVLD; +#ifdef EZX_OSS_AUDIO_DEBUG + printk("DINT=0x%lx\n", DINT); + printk("DCSR(%d)=0x%lx\n", channel, DCSR(channel)); + printk("s->dcmd=0x%lx\n", s->dcmd); + printk("*s->drcmr=0x%lx\n", *s->drcmr); + printk("DDADR(%d)=0x%lx\n", channel, DDADR(channel)); +#endif + return 0; +} + +static int audio_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +{ + audio_state_t *state = (audio_state_t *)pm_dev->data; + + switch (req) { + case PM_SUSPEND: /* enter D1-D3 */ + if (state->output_stream) + audio_dma_sleep(state->output_stream); + if (state->input_stream) + audio_dma_sleep(state->input_stream); + if (AUDIO_ACTIVE(state) && state->hw_shutdown) + state->hw_shutdown(); + break; + case PM_RESUME: /* enter D0 */ + if (AUDIO_ACTIVE(state) && state->hw_init) + state->hw_init(); + if (state->output_stream) + audio_dma_wakeup(state->output_stream); + if (state->input_stream) + audio_dma_wakeup(state->input_stream); + break; + } + return 0; +} +#endif + + +int cotulla_audio_attach(struct inode *inode, struct file *file, + audio_state_t *state) +{ + audio_stream_t *is = state->input_stream; + audio_stream_t *os = state->output_stream; + int err; + + down(&state->sem); + + /* access control */ + err = -ENODEV; + if ((file->f_mode & FMODE_WRITE) && !os) + goto out; + if ((file->f_mode & FMODE_READ) && !is) + goto out; + + err = -EBUSY; + if ((file->f_mode & FMODE_WRITE) && state->wr_ref) + goto out; + if ((file->f_mode & FMODE_READ) && state->rd_ref) + goto out; + +#ifdef EZX_OSS_AUDIO_DEBUG + printk("request dma channels \n"); +#endif + /* request DMA channels */ + if (file->f_mode & FMODE_WRITE) + { + err = pxa_request_dma(os->name, DMA_PRIO_LOW, audio_dma_irq, os); + if (err < 0) + goto out; + os->dma_ch = err; + } + + if (file->f_mode & FMODE_READ) + { + err = pxa_request_dma(is->name, DMA_PRIO_LOW, audio_dma_irq, is); + if (err < 0){ + if(file->f_mode & FMODE_WRITE){ + *os->drcmr = 0; + pxa_free_dma(os->dma_ch); + } + goto out; + } + is->dma_ch = err; + } + + err = -ENODEV; + /* now complete initialisation */ + if(!AUDIO_ACTIVE(state)){ + if(state->hw_init){ + err = state->hw_init(); + if(err<0){ + if(file->f_mode & FMODE_WRITE){ + *os->drcmr = 0; + pxa_free_dma(os->dma_ch); + } + if(file->f_mode & FMODE_READ){ + *is->drcmr = 0; + pxa_free_dma(is->dma_ch); + } + goto out; + } + } + +#ifdef CONFIG_PM + state->pm_dev = pm_register(PM_SYS_DEV, 0, audio_pm_callback); + if (state->pm_dev) + state->pm_dev->data = state; +#endif + } +#ifdef EZX_OSS_AUDIO_DEBUG + printk("init data structure \n"); +#endif + file->private_data = state; + file->f_op->release = audio_release; + file->f_op->write = audio_write; + file->f_op->read = audio_read; + file->f_op->mmap = audio_mmap; + file->f_op->poll = audio_poll; + file->f_op->ioctl = audio_ioctl; + file->f_op->llseek = no_llseek; + + if ((file->f_mode & FMODE_WRITE)) + { + state->wr_ref = 1; + os->fragsize = AUDIO_FRAGSIZE_DEFAULT; + os->nbfrags = AUDIO_NBFRAGS_DEFAULT; + os->output = 1; + os->mapped = 0; + init_waitqueue_head(&os->frag_wq); + init_waitqueue_head(&os->stop_wq); + *os->drcmr = os->dma_ch | DRCMR_MAPVLD; +#ifdef EZX_OSS_AUDIO_DEBUG + printk("*os->drcmr=0x%lx\n", *os->drcmr); +#endif + } + if (file->f_mode & FMODE_READ) + { + state->rd_ref = 1; + is->fragsize = AUDIO_FRAGSIZE_DEFAULT; + is->nbfrags = AUDIO_NBFRAGS_DEFAULT; + is->output = 0; + is->mapped = 0; + init_waitqueue_head(&is->frag_wq); + init_waitqueue_head(&is->stop_wq); + *is->drcmr = is->dma_ch | DRCMR_MAPVLD; +#ifdef EZX_OSS_AUDIO_DEBUG + printk("*is->drcmr=0x%lx\n", *is->drcmr); +#endif + } + err = 0; + up(&state->sem); +#ifdef EZX_OSS_AUDIO_DEBUG + printk("audio device open success\n"); +#endif + return err; +out: + up(&state->sem); + printk("audio device is busy or there is no audio device\n"); + return err; +} + +EXPORT_SYMBOL(cotulla_audio_attach); + + diff -Nru --exclude-from=/sunbeam/home/laforge/scripts/dontdiff linux-2.6.16.5/sound/oss/ezx-audio.h linux-2.6.16.5-exz/sound/oss/ezx-audio.h --- linux-2.6.16.5/sound/oss/ezx-audio.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.5-exz/sound/oss/ezx-audio.h 2006-04-16 18:49:29.000000000 +0200 @@ -0,0 +1,120 @@ +/* + * linux/drivers/sound/ezx-audio.h + * + * + * Description: audio interface for ezx + * + * + * Copyright: BJDC motorola. + * + * This program 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. + * + * + * History: + * zhou qiong June,2002 Created + * LiYong Sep 23,2003 Port from EZX + * Jin Lihong(w20076) Jan 02,2004,Libdd66088 (1) Port from UDC e680 kernel of jem vob. + * (2) Move all audio driver DEBUG macro definition to ezx-audio.h + * header file,and redefine DEBUG to EZX_OSS_DEBUG/EZX_OSS_AUDIO_DEBUG + * (3) reorganize file header + * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Make the e680 louder speaker work. + * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs + * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix + * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 close dsp protection,and add 3d control interface for app + * + */ + +#ifndef EZX_AUDIO_H +#define EZX_AUDIO_H + + +#define NO_HEADSET 0 +#define MONO_HEADSET 1 +#define STEREO_HEADSET 2 + +#define OUT_ADJUST_GAIN 2 +#define IN_ADJUST_GAIN 12 + +#define ASSP_CLK (1<<20) +#define ASSP_PINS (7<<17) + + +#define PHONE_CODEC_DEFAULT_RATE 8000 +#define PHONE_CODEC_16K_RATE 16000 + + +#define STEREO_CODEC_8K_RATE 8000 +#define STEREO_CODEC_11K_RATE 11025 +#define STEREO_CODEC_12K_RATE 12000 +#define STEREO_CODEC_16K_RATE 16000 +#define STEREO_CODEC_22K_RATE 22050 +#define STEREO_CODEC_24K_RATE 24000 +#define STEREO_CODEC_32K_RATE 32000 +#define STEREO_CODEC_44K_RATE 44100 +#define STEREO_CODEC_48K_RATE 48000 + + +typedef struct { + int offset; /* current buffer position */ + char *data; /* actual buffer */ + pxa_dma_desc *dma_desc; /* pointer to the starting desc */ + int master; /* owner for buffer allocation, contain size whn true */ +}audio_buf_t; + +typedef struct { + char *name; /* stream identifier */ + audio_buf_t *buffers; /* pointer to audio buffer array */ + u_int usr_frag; /* user fragment index */ + u_int dma_frag; /* DMA fragment index */ + u_int fragsize; /* fragment size */ + u_int nbfrags; /* number of fragments */ + u_int dma_ch; /* DMA channel number */ + dma_addr_t dma_desc_phys; /* phys addr of descriptor ring */ + u_int descs_per_frag; /* nbr descriptors per fragment */ + int bytecount; /* nbr of processed bytes */ + int getptrCount; /* value of bytecount last time anyone asked via GETxPTR*/ + int fragcount; /* nbr of fragment transitions */ + struct semaphore sem; /* account for fragment usage */ + wait_queue_head_t frag_wq; /* for poll(), etc. */ + wait_queue_head_t stop_wq; /* for users of DCSR_STOPIRQEN */ + u_long dcmd; /* DMA descriptor dcmd field */ + volatile u32 *drcmr; /* the DMA request channel to use */ + u_long dev_addr; /* device physical address for DMA */ + int mapped:1; /* mmap()'ed buffers */ + int output:1; /* 0 for input, 1 for output */ +}audio_stream_t; + +typedef struct { + audio_stream_t *output_stream; + audio_stream_t *input_stream; + int dev_dsp; /* audio device handle */ + int rd_ref:1; /* open reference for recording */ + int wr_ref:1; /* open reference for playback */ + int (*hw_init)(void); + void (*hw_shutdown)(void); + int (*client_ioctl)(struct inode *, struct file *, uint, ulong); + struct pm_dev *pm_dev; + struct semaphore sem; /* prevent races in attach/release */ +}audio_state_t; + + +extern int cotulla_audio_attach(struct inode *inode, struct file *file, audio_state_t *state); + +/* for headset and mic interrupt routine*/ +extern void headjack_change_interrupt_routine(int ch, void *dev_id, struct pt_regs *regs); +extern void mic_change_interrupt_routine(int ch, void *dev_id, struct pt_regs *regs); +extern int mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); + +extern void set_pcap_telephone_codec(int port); +extern void set_pcap_output_path(void); +extern void set_pcap_input_path(void); + + +extern void bluetoothaudio_open(void); +extern void bluetoothaudio_close(void); + + +#endif + diff -Nru --exclude-from=/sunbeam/home/laforge/scripts/dontdiff linux-2.6.16.5/sound/oss/ezx-common.c linux-2.6.16.5-exz/sound/oss/ezx-common.c --- linux-2.6.16.5/sound/oss/ezx-common.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.5-exz/sound/oss/ezx-common.c 2006-04-16 18:49:29.000000000 +0200 @@ -0,0 +1,216 @@ +/* + * linux/drivers/sound/ezx-common.c + * + * + * Description: common functions implementation for ezx audio drivers + * + * + * Copyright: BJDC motorola. + * + * This program 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. + * + * + * History: + * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Created, Make the e680 louder speaker work. + * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs + * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix + * Jin Lihong(w20076) Mar.25,2004,LIBdd90846 a780 new gain setting interface + * Jin Lihong(w20076) Apr.24,2004,LIBee03164 reduce music noise, add new pathes for haptics + * Cheng Xuefeng(a2491c) June.24,2004,LIBdd95397 Add sound path for EMU PIHF + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ezx-common.h" + + +int codec_output_gain = EZX_OSS_DEFAULT_OUTPUT_LOGICAL_GAIN; /* A2,loudspeaker, gain level */ +output_enum codec_output_path = LOUDERSPEAKER_OUT; +output_base_enum codec_output_base = PCAP_BASE; + +int codec_input_gain = EZX_OSS_DEFAULT_AUDIG_LOGICAL_GAIN; /* A5,mic,gain=+17db */ +input_enum codec_input_path = HANDSET_INPUT; +int audioonflag = 0; +int micinflag = 0; + + +#ifdef CONFIG_ARCH_EZX_E680 + +void (*mixer_close_input_path[INPUT_TOTAL_TYPES])(void) = +{ + close_input_carkit, + close_input_handset, + close_input_headset, + close_input_funlight +}; + +void (*mixer_open_input_path[INPUT_TOTAL_TYPES])(void) = +{ + open_input_carkit, + open_input_handset, + open_input_headset, + open_input_funlight +}; + +void (*mixer_close_output_path[][OUTPUT_TOTAL_TYPES])(void) = +{ + { + close_output_pcap_headset, + close_output_pcap_louderspeaker, + close_output_pcap_earpiece, + close_output_pcap_carkit, + close_output_pcap_headjack, + close_output_pcap_bluetooth, + close_output_pcap_louderspeaker_mixed + }, + { + close_output_ma3_headset, + close_output_ma3_louderspeaker, + close_output_ma3_earpiece, + close_output_ma3_carkit, + close_output_ma3_headjack, + close_output_ma3_bluetooth, + close_output_ma3_louderspeaker_mixed + }, + { + close_output_fm_headset, + close_output_fm_louderspeaker, + close_output_fm_earpiece, + close_output_fm_carkit, + close_output_fm_headjack, + close_output_fm_bluetooth, + close_output_fm_louderspeaker_mixed + }, + { + close_output_mixed_headset, + close_output_mixed_louderspeaker, + close_output_mixed_earpiece, + close_output_mixed_carkit, + close_output_mixed_headjack, + close_output_mixed_bluetooth, + close_output_mixed_louderspeaker_mixed + } +}; + +int (*mixer_open_output_path[][OUTPUT_TOTAL_TYPES])(long val) = +{ + { + open_output_pcap_headset, + open_output_pcap_louderspeaker, + open_output_pcap_earpiece, + open_output_pcap_carkit, + open_output_pcap_headjack, + open_output_pcap_bluetooth, + open_output_pcap_louderspeaker_mixed + }, + { + open_output_ma3_headset, + open_output_ma3_louderspeaker, + open_output_ma3_earpiece, + open_output_ma3_carkit, + open_output_ma3_headjack, + open_output_ma3_bluetooth, + open_output_ma3_louderspeaker_mixed + }, + { + open_output_fm_headset, + open_output_fm_louderspeaker, + open_output_fm_earpiece, + open_output_fm_carkit, + open_output_fm_headjack, + open_output_fm_bluetooth, + open_output_fm_louderspeaker_mixed + }, + { + open_output_mixed_headset, + open_output_mixed_louderspeaker, + open_output_mixed_earpiece, + open_output_mixed_carkit, + open_output_mixed_headjack, + open_output_mixed_bluetooth, + open_output_mixed_louderspeaker_mixed + } +}; +#endif /* CONFIG_ARCH_EZX_E680 */ + + +#ifdef CONFIG_ARCH_EZX_A780 +void (*mixer_close_input_path[INPUT_TOTAL_TYPES])(void) = +{ + close_input_carkit, + close_input_handset, +#if EMU_PIHF_FEATURE + close_input_headset, + close_input_pihf_carkit +#else + close_input_headset +#endif + +}; + +void (*mixer_open_input_path[INPUT_TOTAL_TYPES])(void) = +{ + open_input_carkit, + open_input_handset, +#if EMU_PIHF_FEATURE + open_input_headset, + open_input_pihf_carkit +#else + open_input_headset +#endif +}; + +void (*mixer_close_output_path[][OUTPUT_TOTAL_TYPES])(void) = +{ + { + close_output_pcap_headset, + close_output_pcap_louderspeaker, + close_output_pcap_earpiece, + close_output_pcap_carkit, + close_output_pcap_headjack, +#if EMU_PIHF_FEATURE + close_output_pcap_bluetooth, + close_output_pcap_pihf_carkit +#else + close_output_pcap_bluetooth +#endif + } +}; + +int (*mixer_open_output_path[][OUTPUT_TOTAL_TYPES])(long val) = +{ + { + open_output_pcap_headset, + open_output_pcap_louderspeaker, + open_output_pcap_earpiece, + open_output_pcap_carkit, + open_output_pcap_headjack, +#if EMU_PIHF_FEATURE + open_output_pcap_bluetooth, + open_output_pcap_pihf_carkit +#else + open_output_pcap_bluetooth +#endif + } +}; +#endif + + diff -Nru --exclude-from=/sunbeam/home/laforge/scripts/dontdiff linux-2.6.16.5/sound/oss/ezx-common.h linux-2.6.16.5-exz/sound/oss/ezx-common.h --- linux-2.6.16.5/sound/oss/ezx-common.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.5-exz/sound/oss/ezx-common.h 2006-04-16 18:49:29.000000000 +0200 @@ -0,0 +1,161 @@ +/* + * linux/drivers/sound/ezx-common.h + * + * + * Description: header file for ezx-common.c + * + * + * Copyright: BJDC motorola. + * + * This program 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. + * + * + * History: + * Jin Lihong(w20076) Jan 12,2004,LIBdd68327 Created,Make the e680 louder speaker work. + * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs + * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix + * Jin Lihong(w20076) Mar.25,2004,LIBdd90846 a780 new gain setting interface + * Jin Lihong(w20076) Apr.24,2004,LIBee03164 reduce music noise, add new pathes for haptics + * Li Yong(w19946) Apr.22.2004.LIBee02702 Add EMU carKit + * Cheng Xuefeng(a2491c) Jun.15.2004,LIBdd95397 Support EMU PIHF feature + * + */ + +#ifndef EZX_COMMON_H +#define EZX_COMMON_H + +#include "ezx-e680.h" +#include "ezx-a780.h" +#include "../../drivers/misc/ezx/ssp_pcap.h" + +#define EZXOSS_EMERG "Snd driver w20076 <0 EMERG>: " /* system is unusable */ +#define EZXOSS_ALERT "Snd driver w20076 <1 ALERT>: " /* action must be taken immediately */ +#define EZXOSS_CRIT "Snd driver w20076 <2 CRIT>: " /* critical conditions */ +#define EZXOSS_ERR "Snd driver w20076 <3 ERR>: " /* error conditions */ +#define EZXOSS_WARNING "Snd driver w20076 <4 WARNING>: " /* warning conditions */ +#define EZXOSS_NOTICE "Snd driver w20076 <5 NOTICE>: " /* normal but significant condition */ +#define EZXOSS_INFO "Snd driver w20076 <6 INFO>: " /* informational */ +#define EZXOSS_DEBUG "Snd driver w20076 <7 DEBUG>: " /* debug-level messages */ + +#define MONODEVOPENED ( audioonflag & (PHONE_DEVICE|DSP16_DEVICE|AUDIO_DEVICE) ) +#define PHONEDEVOPENED ( audioonflag & PHONE_DEVICE ) + +#define EZX_OSS_MIN_LOGICAL_GAIN 0 +#define EZX_OSS_MAX_LOGICAL_GAIN 100 +#define EZX_OSS_DEFAULT_OUTPUT_LOGICAL_GAIN 74 /* +9db, same as a760 */ +#define EZX_OSS_DEFAULT_AUDIG_LOGICAL_GAIN 55 /* +17db, same as a760 */ +#define EZX_OSS_DEFAULT_MIC2IG_LOGICAL_GAIN 55 /* +17db, same as a760 */ + +#define PCAP_OUTPUT_GAIN_MIN_REG_VAL 0 +#define PCAP_OUTPUT_GAIN_MAX_REG_VAL 15 +#define PCAP_INPUT_GAIN_MIN_REG_VAL 0 +#define PCAP_INPUT_GAIN_MAX_REG_VAL 31 +/*EMU CarKit Mute control signal */ +#define EIHF_UNMUTE 0x01 +#define EIHF_MUTE 0x00 + +#define DEFAULT_USB_MODE 0x00 +#define MONO_AUDIO_MODE 0x02 +#define SETERO_AUDIO_MODE 0x03 + +#define PCAP_OUTPUT_GAIN_REG_VAL_FROM_LOGIC (codec_output_gain*PCAP_OUTPUT_GAIN_MAX_REG_VAL/EZX_OSS_MAX_LOGICAL_GAIN) +#define PCAP_INPUT_AUDIG_REG_VAL_FROM_LOGIC (codec_input_gain*PCAP_INPUT_GAIN_MAX_REG_VAL/EZX_OSS_MAX_LOGICAL_GAIN) +#define PCAP_INPUT_MIC2IG_REG_VAL_FROM_LOGIC (codec_input_gain*PCAP_INPUT_GAIN_MAX_REG_VAL/EZX_OSS_MAX_LOGICAL_GAIN) + +#ifdef EMU_PIHF_FEATURE +typedef enum{ + HEADSET_OUT, /* ear-phone : stereo headset */ + LOUDERSPEAKER_OUT, /* A2_OUTPUT in a760 */ + EARPIECE_OUT, /* A1_OUTPUT in a760 */ + CARKIT_OUT, /* A4_OUTPUT in a760 */ + HEADJACK_OUT, /* mono headjack, HEADJACK_OUTPUT in a760 */ + BLUETOOTH_OUT, /* bluetooth headset */ + PIHF_CARKIT_OUT /* A4_OUTPUT in a760 */ +}output_enum; +#else /* EMU_PIHF_FEATURE */ +typedef enum{ + HEADSET_OUT, /* ear-phone : stereo headset */ + LOUDERSPEAKER_OUT, /* A2_OUTPUT in a760 */ + EARPIECE_OUT, /* A1_OUTPUT in a760 */ + CARKIT_OUT, /* A4_OUTPUT in a760 */ + HEADJACK_OUT, /* mono headjack, HEADJACK_OUTPUT in a760 */ + BLUETOOTH_OUT, /* bluetooth headset */ + LOUDERSPEAKER_MIXED_OUT /* e680 louderspeaker out, boomer input is stereo+mono, mono is aimed for haptics signals */ +}output_enum; +#endif /* EMU_PIHF_FEAURE */ + +typedef enum{ + PCAP_BASE = 0x0000 , /* used to tell that we are setting the PCAP */ + MA3_BASE = 0x0100 , /* MA3 Midi device */ + FM_BASE = 0x0200 , /* FM radio device */ + MIXED_BASE = 0x0300 /* Both MA3 device and PCAP device are used */ +}output_base_enum; + +#ifdef EMU_PIHF_FEATURE +typedef enum{ + CARKIT_INPUT, /* EXT_MIC */ + HANDSET_INPUT , /* A5 */ + HEADSET_INPUT , /* A3 */ + PIHF_CARKIT_INPUT /* EXT_MIC */ +}input_enum; +#else /* EMU_PIHF_FEATURE */ +typedef enum{ + CARKIT_INPUT, /* EXT_MIC */ + HANDSET_INPUT , /* A5 */ + HEADSET_INPUT , /* A3 */ + FUNLIGHT_INPUT /* E680 funlight */ +}input_enum; +#endif /* EMU_PIHF_FEATURE */ + + +#define INPUT_PATH_MIN CARKIT_INPUT + +#ifdef CONFIG_PXA_EZX_A780 +#ifdef EMU_PIHF_FEATURE +#define INPUT_PATH_MAX PIHF_CARKIT_INPUT +#define INPUT_TOTAL_TYPES 4 /* = HEADSET_INPUT+1 */ +#define OUTPUT_PATH_MAX PIHF_CARKIT_OUT +#define OUTPUT_BASE_MAX PCAP_BASE +#define OUTPUT_TOTAL_TYPES 7 /* = BLUETOOTH_OUT+1 */ +#else /* EMU_PIHF_FEATURE */ +#define INPUT_PATH_MAX HEADSET_INPUT +#define INPUT_TOTAL_TYPES 3 /* = HEADSET_INPUT+1 */ +#define OUTPUT_PATH_MAX BLUETOOTH_OUT +#define OUTPUT_BASE_MAX PCAP_BASE +#define OUTPUT_TOTAL_TYPES 6 /* = BLUETOOTH_OUT+1 */ +#endif /* EMU_PIHF_FEATURE */ +#endif + +#ifdef CONFIG_PXA_EZX_E680 +#define INPUT_PATH_MAX FUNLIGHT_INPUT +#define INPUT_TOTAL_TYPES 4 /* = FUNLIGHT_INPUT + 1 */ +#define OUTPUT_PATH_MAX LOUDERSPEAKER_MIXED_OUT +#define OUTPUT_BASE_MAX MIXED_BASE +#define OUTPUT_TOTAL_TYPES 7 /* = LOUDERSPEAKER_MIXED_OUT+1 */ +#endif + +#define OUTPUT_BASE_MEANINGFUL_START_BIT 8 +#define OUTPUT_BASE_TYPE(x) (x >>OUTPUT_BASE_MEANINGFUL_START_BIT) +#define OUTPUT_BASE_TOTAL_TYPES (OUTPUT_BASE_MAX>>OUTPUT_BASE_MEANINGFUL_START_BIT +1) +#define GET_OUTPUT_BASE(x) (x&0xFF00) +#define GET_OUTPUT_PATH(x) (x&0x00FF) + + +extern int codec_output_gain, codec_input_gain; +extern output_enum codec_output_path; +extern input_enum codec_input_path; +extern output_base_enum codec_output_base; +extern int audioonflag; +extern int micinflag; + +extern void (*mixer_close_output_path[][OUTPUT_TOTAL_TYPES])(void); +extern int (*mixer_open_output_path[][OUTPUT_TOTAL_TYPES])(long val); +extern void (*mixer_close_input_path[INPUT_TOTAL_TYPES])(void); +extern void (*mixer_open_input_path[INPUT_TOTAL_TYPES])(void); + + +#endif + + diff -Nru --exclude-from=/sunbeam/home/laforge/scripts/dontdiff linux-2.6.16.5/sound/oss/ezx-e680.c linux-2.6.16.5-exz/sound/oss/ezx-e680.c --- linux-2.6.16.5/sound/oss/ezx-e680.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.5-exz/sound/oss/ezx-e680.c 2006-04-16 18:49:29.000000000 +0200 @@ -0,0 +1,1733 @@ +/* + * linux/drivers/sound/ezx-e680.c + * + * + * Description: Motorola e680 phone specific functions implementation for audio drivers + * + * + * Copyright: BJDC motorola. + * + * This program 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. + * + * + * History: + * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Created, Make the e680 louder speaker work. + * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs + * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix + * Jin Lihong(w20076) Mar.25,2004,LIBdd90336 play music noise tmp solution + * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 close dsp protection,and add 3d control interface for app + * Jin Lihong(w20076) Apr.20,2004,LIBee01165 reduce noise + * Jin Lihong(w20076) Apr.24,2004,LIBee03164 reduce music noise, add new pathes for haptics + * Li Yong(w19946) Apr.23.2004.LIBee02702 Add EMU Carkit + * Jin Lihong(w20076) Jun.08,2004,libee14656 change boomer input path for mono sound + * Jin Lihong(w20076) Jun.15,2004,LIBee21625 boomer's power management + * Jin Lihong(w20076) Jun.22,2004,LIBee24284 mixer power save + * Wu Hongxing(w20691)Jul.07,2004 LIBee29664 ap 13m clock usage. + * Jin Lihong(w20076) Aug.11,2004,LIBff01482 mixer power on/off sequence optimize + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ezx-common.h" + + +#ifdef CONFIG_ARCH_EZX_E680 + +EXPORT_SYMBOL(poweron_mixer); +EXPORT_SYMBOL(shutdown_mixer); +EXPORT_SYMBOL(kernel_clr_oscc_13m_clock); +EXPORT_SYMBOL(kernel_set_oscc_13m_clock); + +static DECLARE_MUTEX(ezx_mixer_mutex); + + + +#define BOOMER_MONO_VOL_REG_PREFIX 0x00 +#define BOOMER_STEREO_LEFT_VOL_REG_PREFIX 0x40 +#define BOOMER_STEREO_RIGHT_VOL_REG_PREFIX 0x80 +#define BOOMER_MODE_CONTROL_REG_PREFIX 0xC0 + +#define BOOMER_MONO_GAIN_MIN_REG_VAL 0 +#define BOOMER_MONO_GAIN_MAX_REG_VAL 31 +#define BOOMER_MONO_GAIN_DEFAULT_REG_VAL 15 +#define BOOMER_MONO_GAIN_DEFAULT_FIXED_REG_VAL 23 +#define BOOMER_MONO_GAIN_MIXED_INPUT_CASE_REG_VAL 15 /* when in a special use case: mono input for haptics, + stereo input for audio signals */ + +#define BOOMER_STEREO_LEFT_GAIN_MIN_REG_VAL 0 +#define BOOMER_STEREO_LEFT_GAIN_MAX_REG_VAL 31 +#define BOOMER_STEREO_LEFT_GAIN_DEFAULT_REG_VAL 15 +#define BOOMER_STEREO_LEFT_GAIN_DEFAULT_FIXED_REG_VAL 27 +#define BOOMER_STEREO_LEFT_GAIN_MIXED_INPUT_CASE_REG_VAL 27 /* when in a special use case: mono input for haptics, + stereo input for audio signals */ + +#define BOOMER_STEREO_RIGHT_GAIN_MIN_REG_VAL 0 +#define BOOMER_STEREO_RIGHT_GAIN_MAX_REG_VAL 31 +#define BOOMER_STEREO_RIGHT_GAIN_DEFAULT_REG_VAL 15 +#define BOOMER_STEREO_RIGHT_GAIN_DEFAULT_FIXED_REG_VAL 27 +#define BOOMER_STEREO_RIGHT_GAIN_MIXED_INPUT_CASE_REG_VAL 27 /* when in a special use case: mono input for haptics, + stereo input for audio signals */ + +#define BOOMER_OUTPUT_GAIN_MONO_REG_VAL_FROM_LOGIC (codec_output_gain*BOOMER_MONO_GAIN_MAX_REG_VAL/EZX_OSS_MAX_LOGICAL_GAIN) +#define BOOMER_OUTPUT_GAIN_STEREO_LEFT_REG_VAL_FROM_LOGIC (codec_output_gain*BOOMER_STEREO_LEFT_GAIN_MAX_REG_VAL/EZX_OSS_MAX_LOGICAL_GAIN) +#define BOOMER_OUTPUT_GAIN_STEREO_RIGHT_REG_VAL_FROM_LOGIC (codec_output_gain*BOOMER_STEREO_RIGHT_GAIN_MAX_REG_VAL/EZX_OSS_MAX_LOGICAL_GAIN) + +#define BOOMER_LOUDER_SPEAKER_3D_OFF 0X00 /* bit LD5 */ +#define BOOMER_LOUDER_SPEAKER_3D_ON 0X20 +#define BOOMER_HEADPHONE_3D_OFF 0X00 /* bit RD5 */ +#define BOOMER_HEADPHONE_3D_ON 0X20 + +#define BOOMER_SHUTDOWN 0X00 /* bit CD3 ~ CD0 */ +#define BOOMER_IN_MONO_OUT_MONO_EARPIECE 0X01 +#define BOOMER_IN_MONO_OUT_LOUDER_SPEAKER 0X02 +#define BOOMER_IN_MONO_OUT_LOUDER_SPEAKER_AND_HEADPHONE 0X03 +#define BOOMER_IN_MONO_OUT_HEADPHONE 0X04 +#define BOOMER_IN_MONO_OUT_MONO_LINEOUT 0X05 +#define BOOMER_IN_STEREO_OUT_MONO_EARPIECE 0X06 +#define BOOMER_IN_STEREO_OUT_LOUDER_SPEAKER 0X07 +#define BOOMER_IN_STEREO_OUT_LOUDER_SPEAKER_AND_HEADPHONE 0X08 +#define BOOMER_IN_STEREO_OUT_HEADPHONE 0X09 +#define BOOMER_IN_STEREO_OUT_MONO_LINEOUT 0X0a +#define BOOMER_IN_MONO_AND_STEREO_OUT_MONO_EARPIECE 0X0b +#define BOOMER_IN_MONO_AND_STEREO_OUT_LOUDER_SPEAKER 0X0c +#define BOOMER_IN_MONO_AND_STEREO_OUT_LOUDER_SPEAKER_AND_HEADPHONE 0X0d +#define BOOMER_IN_MONO_AND_STEREO_OUT_HEADPHONE 0X0e +#define BOOMER_IN_MONO_AND_STEREO_OUT_MONO_LINEOUT 0X0f + +#define BOOMER_FAST_WAKEUP 0X00 /* bit CD5 */ +#define BOOMER_SLOW_WAKEUP 0X20 + +#define BOOMER_EARPIECE_GAIN_SMALL_OPTION 0X00 /* bit CD4 */ +#define BOOMER_EARPIECE_GAIN_LARGE_OPTION 0X10 + + +typedef struct { + u8 monovol; /* mono volume */ + u8 leftvol; /* stereo left volume */ + u8 rightvol; /* stereo right volume */ + u8 path; /* boomer path setup */ + u8 speaker3d; + u8 headphone3d; + u8 wakeuptime; /* fast or slow wakeup setting */ + u8 earpiecegaintable; /* earpiece gain table select */ +} e680_boomer; + + +static e680_boomer e680boomer; +static u32 gpio_flt_sel_status; +u32 gpio_va_sel_status; + +static void set_boomer_mono_vol_reg( void ); +static void set_boomer_stereo_left_vol_reg(void); +static void set_boomer_stereo_right_vol_reg(void); +static void set_boomer_mode_control_reg(void); + +static void write_boomer(const char *buf, size_t count); +extern int mixer_write(const char *buf, size_t count); + + +void e680_boomer_init(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "e680 boomer init\n"); +#endif + + e680boomer.monovol = BOOMER_MONO_GAIN_DEFAULT_REG_VAL; + e680boomer.leftvol = BOOMER_STEREO_LEFT_GAIN_DEFAULT_REG_VAL; + e680boomer.rightvol = BOOMER_STEREO_RIGHT_GAIN_DEFAULT_REG_VAL; + e680boomer.path = BOOMER_IN_MONO_OUT_MONO_LINEOUT; + e680boomer.speaker3d = BOOMER_LOUDER_SPEAKER_3D_ON; + e680boomer.headphone3d = BOOMER_HEADPHONE_3D_ON; + e680boomer.wakeuptime = BOOMER_FAST_WAKEUP; + e680boomer.earpiecegaintable = BOOMER_EARPIECE_GAIN_LARGE_OPTION; + + set_boomer_mode_control_reg(); + set_boomer_mono_vol_reg(); + set_boomer_stereo_left_vol_reg(); + set_boomer_stereo_right_vol_reg(); +} + + +void e680_boomer_shutdown(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "e680 boomer shutdown.\n"); +#endif + + e680boomer.path = BOOMER_SHUTDOWN; + set_boomer_mode_control_reg(); +} + + +void e680_boomer_path_mono_lineout(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " set E680 boomer path to mono input mono lineout.\n"); +#endif + + e680boomer.path = BOOMER_IN_MONO_OUT_MONO_LINEOUT; + set_boomer_mode_control_reg(); +} + + +void e680_boomer_path_tmp_mono_lineout(void) +{ + u8 mode; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " mute E680 boomer.\n"); +#endif + + mode = BOOMER_MODE_CONTROL_REG_PREFIX | BOOMER_IN_MONO_OUT_MONO_LINEOUT + | e680boomer.wakeuptime | e680boomer.earpiecegaintable; + + write_boomer(&mode, 1); +} + + +void e680_boomer_path_tmp_shutdown(void) +{ + u8 mode; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " E680 boomer path set to tmp shutdown..\n"); +#endif + + mode = BOOMER_MODE_CONTROL_REG_PREFIX | BOOMER_SHUTDOWN + | e680boomer.wakeuptime | e680boomer.earpiecegaintable; + + write_boomer(&mode, 1); +} + + +void e680_boomer_path_restore(void) +{ + u8 mode; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " E680 boomer path restore: path = 0X%X \n", e680boomer.path); +#endif + mode = BOOMER_MODE_CONTROL_REG_PREFIX | e680boomer.path | e680boomer.wakeuptime | e680boomer.earpiecegaintable; + write_boomer(&mode, 1); +} + + +static void set_boomer_mono_vol_reg( void ) +{ + u8 vol; + + vol = BOOMER_MONO_VOL_REG_PREFIX | e680boomer.monovol; + write_boomer(&vol, 1); + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "set e680 boomer mono volume register,vol=0x%2X \n", vol); +#endif +} + + +static void set_boomer_stereo_left_vol_reg(void) +{ + u8 vol; + + vol = BOOMER_STEREO_LEFT_VOL_REG_PREFIX | e680boomer.leftvol | e680boomer.speaker3d; + write_boomer(&vol, 1); + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "set e680 boomer stereo left volume register,vol=0x%2X \n", vol); +#endif +} + + +static void set_boomer_stereo_right_vol_reg(void) +{ + u8 vol; + + vol = BOOMER_STEREO_RIGHT_VOL_REG_PREFIX | e680boomer.rightvol | e680boomer.headphone3d; + write_boomer(&vol, 1); + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "set e680 boomer stereo right volume register,vol=0x%2X \n", vol); +#endif +} + + +static void set_boomer_mode_control_reg(void) +{ + u8 mode; + + mode = BOOMER_MODE_CONTROL_REG_PREFIX | e680boomer.path | e680boomer.wakeuptime | e680boomer.earpiecegaintable; + write_boomer(&mode, 1); + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "set e680 boomer mode control register,mode=0x%2X \n", mode); +#endif +} + + +static void write_boomer(const char *buf, size_t count) +{ + int ret, i = 0; + size_t written = 0; + + while(written2 ) + break; + } + if( written < count ) + printk(EZXOSS_ERR "write boomer failed.\n"); +} + + +void poweron_mixer( audio_dev_type type ) +{ + down(&ezx_mixer_mutex); + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "E680 No. 0x%X device wants to power on the mixer hardware.\n", type); + printk(EZXOSS_DEBUG "E680 No. 0x%X device has already powered on the mixer hardware.\n", audioonflag); +#endif + + audioonflag |= type; + + if( MIXERISSTEREO == type ){ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "E680 No. 0x%X device is powering on the mixer hardware.\n", type); +#endif + + if( (type==MIDI_DEVICE) || (type==FM_DEVICE) ) + mute_output_to_avoid_pcap_noise(); + + ssp_pcap_open(SSP_PCAP_AUDIO_OPEN); + + /* (1) set pcap audio power V2_EN_2(OR WITH V2_EN) */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2); + + /* (6) enable output_path and set gain */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP); /* disable codec bypass */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ST_DAC_SW); /* close stereo switch */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CDC_SW); /* open telephone codec path into right PGA */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); /* close PGA_INR into PGA */ + + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN); /* enable right PGA */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN); /* enable left PGA */ + + if( (type==MIDI_DEVICE) || (type==FM_DEVICE) ) + undo_mute_output_to_avoid_pcap_noise(); + } + + up(&ezx_mixer_mutex); +} + + +void shutdown_mixer( audio_dev_type type ) +{ + down(&ezx_mixer_mutex); + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "E680 No. 0x%X device wants to shut down the mixer hardware.\n", type); +#endif + + if( audioonflag == type ){ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "E680 No. 0x%X device is shutting down the mixer hardware.\n", type); +#endif + + e680_boomer_path_mono_lineout(); /* mute hw noise and save power for e680 */ + + /* close pcap output path */ + SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER, SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); + } + + audioonflag &= ~type; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "E680 No. 0x%X device is still using the mixer hardware.\n", audioonflag); +#endif + + up(&ezx_mixer_mutex); +} + + +void mixer_not_in_use(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " E680 mixer not in use.\n"); +#endif + + (*mixer_close_output_path[OUTPUT_BASE_TYPE(codec_output_base)][codec_output_path])(); + (*mixer_close_input_path[codec_input_path])(); + + if( micinflag == 0 ) /* close pcap output path */ + SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER, SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); + + e680_boomer_path_mono_lineout(); +} + + +void set_output_gain_hw_reg(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "set output gain hw register. \n"); +#endif + + SSP_PCAP_AUDOG_set( PCAP_OUTPUT_GAIN_REG_VAL_FROM_LOGIC ); + + if( e680boomer.path == BOOMER_SHUTDOWN ){ + ; + } + else if( e680boomer.path <= BOOMER_IN_MONO_OUT_MONO_LINEOUT ){ + e680boomer.monovol = BOOMER_MONO_GAIN_DEFAULT_FIXED_REG_VAL; + set_boomer_mono_vol_reg(); + } + else if( e680boomer.path <= BOOMER_IN_STEREO_OUT_MONO_LINEOUT ){ + e680boomer.leftvol = BOOMER_STEREO_LEFT_GAIN_DEFAULT_FIXED_REG_VAL; + e680boomer.rightvol = BOOMER_STEREO_RIGHT_GAIN_DEFAULT_FIXED_REG_VAL; + set_boomer_stereo_left_vol_reg(); + set_boomer_stereo_right_vol_reg(); + } + else{ + if( e680boomer.path == BOOMER_IN_MONO_AND_STEREO_OUT_LOUDER_SPEAKER ){ + e680boomer.monovol = BOOMER_MONO_GAIN_MIXED_INPUT_CASE_REG_VAL; + e680boomer.leftvol = BOOMER_STEREO_LEFT_GAIN_MIXED_INPUT_CASE_REG_VAL; + e680boomer.rightvol = BOOMER_STEREO_RIGHT_GAIN_MIXED_INPUT_CASE_REG_VAL; + } + else{ + e680boomer.monovol = BOOMER_MONO_GAIN_DEFAULT_FIXED_REG_VAL; + e680boomer.leftvol = BOOMER_STEREO_LEFT_GAIN_DEFAULT_FIXED_REG_VAL; + e680boomer.rightvol = BOOMER_STEREO_RIGHT_GAIN_DEFAULT_FIXED_REG_VAL; + } + set_boomer_mono_vol_reg(); + set_boomer_stereo_left_vol_reg(); + set_boomer_stereo_right_vol_reg(); + } + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "codec_output_gain=%d\n", codec_output_gain); +#endif +} + + +void set_input_gain_hw_reg(void) +{ + SSP_PCAP_AUDIG_set( PCAP_INPUT_AUDIG_REG_VAL_FROM_LOGIC ); + +#ifdef EZX_OSS_DEBUG + printk( EZXOSS_DEBUG "codec_input_gain=%d\n", codec_input_gain ); +#endif +} + + +void set_boomer_3d_status(boomer_3d_status status) +{ +#ifdef EZX_OSS_DEBUG + printk( EZXOSS_DEBUG "set boomer 3d status.\n"); +#endif + + switch(status) + { + case LOUDERSPEAKER_ON_HEADSET_OFF_3D: + e680boomer.speaker3d = BOOMER_LOUDER_SPEAKER_3D_ON; + e680boomer.headphone3d = BOOMER_HEADPHONE_3D_OFF; + break; + + case LOUDERSPEAKER_OFF_HEADSET_ON_3D: + e680boomer.speaker3d = BOOMER_LOUDER_SPEAKER_3D_OFF; + e680boomer.headphone3d = BOOMER_HEADPHONE_3D_ON; + break; + + case LOUDERSPEAKER_OFF_HEADSET_OFF_3D: + e680boomer.speaker3d = BOOMER_LOUDER_SPEAKER_3D_OFF; + e680boomer.headphone3d = BOOMER_HEADPHONE_3D_OFF; + break; + + case LOUDERSPEAKER_ON_HEADSET_ON_3D: + default: + e680boomer.speaker3d = BOOMER_LOUDER_SPEAKER_3D_ON; + e680boomer.headphone3d = BOOMER_HEADPHONE_3D_ON; + } + + set_boomer_stereo_left_vol_reg(); + set_boomer_stereo_right_vol_reg(); +} + + +boomer_3d_status get_boomer_3d_status(void) +{ +#ifdef EZX_OSS_DEBUG + printk( EZXOSS_DEBUG "get boomer 3d status.\n"); +#endif + + if(e680boomer.speaker3d == BOOMER_LOUDER_SPEAKER_3D_ON){ + if(e680boomer.headphone3d == BOOMER_HEADPHONE_3D_ON) + return LOUDERSPEAKER_ON_HEADSET_ON_3D; + else + return LOUDERSPEAKER_ON_HEADSET_OFF_3D; + } + else{ + if(e680boomer.headphone3d == BOOMER_HEADPHONE_3D_ON) + return LOUDERSPEAKER_OFF_HEADSET_ON_3D; + else + return LOUDERSPEAKER_OFF_HEADSET_OFF_3D; + } +} + + +void set_gpio_va_sel_out_high(void) +{ + set_GPIO_mode(GPIO_VA_SEL_BUL | GPIO_OUT); + set_GPIO(GPIO_VA_SEL_BUL); + PGSR(GPIO_VA_SEL_BUL) |= GPIO_bit(GPIO_VA_SEL_BUL); + gpio_va_sel_status = 1; +#ifdef EZX_OSS_DEBUG + printk( EZXOSS_DEBUG "set VA_SEL high. \n"); +#endif +} + + +void set_gpio_va_sel_out_low(void) +{ + set_GPIO_mode(GPIO_VA_SEL_BUL | GPIO_OUT); + clr_GPIO(GPIO_VA_SEL_BUL); + PGSR(GPIO_VA_SEL_BUL) &= ~GPIO_bit(GPIO_VA_SEL_BUL); + gpio_va_sel_status = 0; +#ifdef EZX_OSS_DEBUG + printk( EZXOSS_DEBUG "set VA_SEL low. \n"); +#endif +} + + +void close_input_carkit(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close input carkit. \n"); +#endif + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX); +} + + +void close_input_handset(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close input handset. \n"); +#endif + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON1); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_MUX); +} + + +void close_input_headset(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close input headset. \n"); +#endif + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_MUX); +} + + +void close_input_funlight(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close input funlight. \n"); +#endif + + /* disable PCAP codec */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_SMB); + /* set fsync, tx, bitclk are tri-stated */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CD_TS); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX); +} + + +void open_input_carkit(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open input carkit. \n"); +#endif + codec_input_path = CARKIT_INPUT; + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX); +} + + +void open_input_handset(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open input handset. \n"); +#endif + + codec_input_path = HANDSET_INPUT; + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON1); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_MUX); +} + + +void open_input_headset(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open input headset. \n"); +#endif + + codec_input_path = HEADSET_INPUT; + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_MUX); +} + + +void open_input_funlight(void) +{ + unsigned long ssp_pcap_register_val; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open input funlight. \n"); +#endif + + codec_input_path = FUNLIGHT_INPUT; + + set_gpio_va_sel_out_high(); + + /* (2) set codec sample rate(FS_8K_16K=0) */ + /* CDC_CLK(000=13MHZ) bitclk output(SMB=0) audio IO1(DIG_AUD_IN=1) */ + ssp_pcap_register_val = PCAP_CDC_CLK_IN_13M0; + SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_CODEC_REGISTER, ssp_pcap_register_val); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_SMB); /* codec master */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_8K_16K); /* 8K sample rate */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_DIG_AUD_IN); /* DAI0 */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDIHPF); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDOHPF); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_INV); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_INV); + + /*(3) reset digital filter(DF_RESET=1) */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_ADITH); + /* (4) enable pcap clk(CDC_CLK_EN=1),enable CODEC(CDC_EN=1) */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); + mdelay(1); /* specified enable time */ + + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX); +} + + +void close_output_pcap_headset(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output pcap headset. \n"); +#endif + + e680_boomer_path_mono_lineout(); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); +} + + +void close_output_pcap_louderspeaker(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output pcap louderspeaker. \n"); +#endif + + e680_boomer_path_mono_lineout(); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); +} + + +void close_output_pcap_earpiece(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output pcap earpiece. \n"); +#endif + + e680_boomer_path_mono_lineout(); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1_EN); +} + + +void close_output_pcap_carkit(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output pcap carkit. \n"); +#endif + e680_boomer_path_mono_lineout(); + EIHF_Mute(EIHF_MUTE); //Mute EIHF + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + + Set_EMU_Mux_Switch(DEFAULT_USB_MODE); +} + + +void close_output_pcap_headjack(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output pcap headjack. \n"); +#endif + + e680_boomer_path_mono_lineout(); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); +} + + +void close_output_pcap_bluetooth(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output pcap bluetooth. \n"); +#endif + +} + + +void close_output_pcap_louderspeaker_mixed(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output pcap louderspeaker mixed. \n"); +#endif + + e680_boomer_path_mono_lineout(); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); +} + + +void close_output_ma3_headset(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output ma3 headset. \n"); +#endif + + e680_boomer_path_mono_lineout(); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); +} + + +void close_output_ma3_louderspeaker(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output ma3 louderspeaker. \n"); +#endif + + e680_boomer_path_mono_lineout(); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); +} + + +void close_output_ma3_earpiece(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output ma3 earpiece. \n"); +#endif + +} + + +void close_output_ma3_carkit(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output ma3 carkit. \n"); +#endif + +} + + +void close_output_ma3_headjack(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output ma3 headjack. \n"); +#endif + + e680_boomer_path_mono_lineout(); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); +} + + +void close_output_ma3_bluetooth(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output ma3 bluetooth. \n"); +#endif + +} + + +void close_output_ma3_louderspeaker_mixed(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output ma3 louderspeaker mixed. \n"); +#endif + + e680_boomer_path_mono_lineout(); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); +} + + +void close_output_fm_headset(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output fm headset. \n"); +#endif + + e680_boomer_path_mono_lineout(); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); +} + + +void close_output_fm_louderspeaker(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output fm louderspeaker. \n"); +#endif + + e680_boomer_path_mono_lineout(); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); +} + + +void close_output_fm_earpiece(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output fm earpiece. \n"); +#endif + +} + + +void close_output_fm_carkit(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output fm carkit. \n"); +#endif + +} + + +void close_output_fm_headjack(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output fm headjack. \n"); +#endif + + e680_boomer_path_mono_lineout(); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); +} + + +void close_output_fm_bluetooth(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output fm bluetooth. \n"); +#endif + +} + + +void close_output_fm_louderspeaker_mixed(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output fm louderspeaker mixed. \n"); +#endif + + e680_boomer_path_mono_lineout(); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); +} + + +void close_output_mixed_headset(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output mixed headset. \n"); +#endif + + e680_boomer_path_mono_lineout(); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); +} + + +void close_output_mixed_louderspeaker(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output mixed louderspeaker. \n"); +#endif + + e680_boomer_path_mono_lineout(); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); +} + + +void close_output_mixed_earpiece(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output mixed earpiece. \n"); +#endif + +} + + +void close_output_mixed_carkit(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output mixed carkit. \n"); +#endif + +} + + +void close_output_mixed_headjack(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output mixed headjack. \n"); +#endif + + e680_boomer_path_mono_lineout(); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); +} + + +void close_output_mixed_bluetooth(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output mixed bluetooth. \n"); +#endif + +} + + +void close_output_mixed_louderspeaker_mixed(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "close output mixed louderspeaker mixed. \n"); +#endif + + e680_boomer_path_mono_lineout(); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); +} + + +int open_output_pcap_headset(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output pcap headset. \n"); +#endif + + /* set pcap output path register AR_EN=1, AL_EN=1 */ + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path = BOOMER_IN_STEREO_OUT_HEADPHONE; + + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + set_boomer_mode_control_reg(); + + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_pcap_louderspeaker(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output pcap louderspeaker. \n"); +#endif + + /* set pcap output path register AR_EN=1, AL_EN=1 */ + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path = BOOMER_IN_STEREO_OUT_LOUDER_SPEAKER; + + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + set_boomer_mode_control_reg(); + + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_pcap_earpiece(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output pcap earpiece. \n"); +#endif + + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL_6DB); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path = BOOMER_IN_MONO_OUT_MONO_LINEOUT; + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1_EN); + set_boomer_mode_control_reg(); + + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_pcap_carkit(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output pcap carkit. \n"); +#endif + + Set_EMU_Mux_Switch(MONO_AUDIO_MODE); + + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path=BOOMER_IN_STEREO_OUT_HEADPHONE; + + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + + set_boomer_mode_control_reg(); + + set_output_gain_hw_reg(); + + EIHF_Mute(EIHF_UNMUTE); + + return ret; +} + + +int open_output_pcap_headjack(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output pcap headjack. \n"); +#endif + + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path = BOOMER_IN_STEREO_OUT_HEADPHONE; + + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + set_boomer_mode_control_reg(); + + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_pcap_bluetooth(long val) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output pcap bluetooth. \n"); +#endif + + return 0; +} + + +int open_output_pcap_louderspeaker_mixed(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output pcap louderspeaker mixed. \n"); +#endif + + /* set pcap output path register AR_EN=1, AL_EN=1 */ + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path = BOOMER_IN_MONO_AND_STEREO_OUT_LOUDER_SPEAKER; + + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + set_boomer_mode_control_reg(); + + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_ma3_headset(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output ma3 headset. \n"); +#endif + + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path = BOOMER_IN_STEREO_OUT_HEADPHONE; + + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); + + set_boomer_mode_control_reg(); + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_ma3_louderspeaker(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output ma3 louderspeaker. \n"); +#endif + + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path = BOOMER_IN_STEREO_OUT_LOUDER_SPEAKER; + + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); + + set_boomer_mode_control_reg(); + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_ma3_earpiece(long val) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output ma3 earpiece. \n"); +#endif + + return 0; +} + + +int open_output_ma3_carkit(long val) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output ma3 carkit. \n"); +#endif + + return 0; +} + + +int open_output_ma3_headjack(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output ma3 headjack. \n"); +#endif + + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path = BOOMER_IN_STEREO_OUT_HEADPHONE; + + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); + + set_boomer_mode_control_reg(); + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_ma3_bluetooth(long val) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output ma3 bluetooth. \n"); +#endif + + return 0; +} + + +int open_output_ma3_louderspeaker_mixed(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output ma3 louderspeaker mixed. \n"); +#endif + + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path = BOOMER_IN_MONO_AND_STEREO_OUT_LOUDER_SPEAKER; + + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); + + set_boomer_mode_control_reg(); + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_fm_headset(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output fm headset. \n"); +#endif + + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path = BOOMER_IN_STEREO_OUT_HEADPHONE; + + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); + + set_boomer_mode_control_reg(); + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_fm_louderspeaker(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output fm louderspeaker. \n"); +#endif + + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path = BOOMER_IN_STEREO_OUT_LOUDER_SPEAKER; + + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); + + set_boomer_mode_control_reg(); + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_fm_earpiece(long val) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output fm earpiece. \n"); +#endif + + return 0; +} + + +int open_output_fm_carkit(long val) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output fm carkit. \n"); +#endif + + return 0; +} + + +int open_output_fm_headjack(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output fm headjack. \n"); +#endif + + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL_6DB); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path = BOOMER_IN_STEREO_OUT_HEADPHONE; + + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); + + set_boomer_mode_control_reg(); + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_fm_bluetooth(long val) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output fm bluetooth. \n"); +#endif + + return 0; +} + + +int open_output_fm_louderspeaker_mixed(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output fm louderspeaker mixed. \n"); +#endif + + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path = BOOMER_IN_MONO_AND_STEREO_OUT_LOUDER_SPEAKER; + + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); + + set_boomer_mode_control_reg(); + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_mixed_headset(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output mixed headset. \n"); +#endif + + /* set pcap output path register AR_EN=1, AL_EN=1 */ + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path = BOOMER_IN_STEREO_OUT_HEADPHONE; + + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); + + set_boomer_mode_control_reg(); + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_mixed_louderspeaker(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output mixed louderspeaker. \n"); +#endif + + /* set pcap output path register AR_EN=1, AL_EN=1 */ + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path = BOOMER_IN_STEREO_OUT_LOUDER_SPEAKER; + + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); + + set_boomer_mode_control_reg(); + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_mixed_earpiece(long val) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output mixed earpiece. \n"); +#endif + + return 0; +} + + +int open_output_mixed_carkit(long val) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output mixed carkit. \n"); +#endif + + return 0; +} + + +int open_output_mixed_headjack(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output mixed headjack. \n"); +#endif + + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL_6DB); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path = BOOMER_IN_STEREO_OUT_HEADPHONE; + + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); + + set_boomer_mode_control_reg(); + set_output_gain_hw_reg(); + + return ret; +} + + +int open_output_mixed_bluetooth(long val) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output mixed bluetooth. \n"); +#endif + + return 0; +} + + +int open_output_mixed_louderspeaker_mixed(long val) +{ + int ret; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open output mixed louderspeaker mixed. \n"); +#endif + + /* set pcap output path register AR_EN=1, AL_EN=1 */ + if(MIXERISSTEREO) + SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); + else + SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); + e680boomer.path = BOOMER_IN_MONO_AND_STEREO_OUT_LOUDER_SPEAKER; + + codec_output_path = GET_OUTPUT_PATH(val); + codec_output_base = GET_OUTPUT_BASE(val); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); + + set_boomer_mode_control_reg(); + set_output_gain_hw_reg(); + + return ret; +} + + +void kernel_set_oscc_13m_clock(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "midi set oscc 13m clock \n" ); +#endif + + if( DSPUSE13MCLK == 0 ) + OSCC |= 0x00000008; +} + + +void kernel_clr_oscc_13m_clock(void) +{ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "midi clr oscc 13m clock \n"); +#endif + + if( (DSPUSE13MCLK == 0 ) && (DSP16USE13MCLK == 0) ) /* for app will close midi after dsp16 opened under some cases */ + OSCC &= ~0x00000008; +} + + +void pcap_use_ap_13m_clock(void) +{ + if( MIDIUSE13MCLK == 0 ) + OSCC |= 0x00000008; + set_GPIO_mode(AP_13MHZ_OUTPUT_PIN | GPIO_ALT_FN_3_OUT); + + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_CLK_IN_SEL); +} + + +void pcap_use_bp_13m_clock(void) +{ + if( MIDIUSE13MCLK == 0 ) + OSCC &= ~0x00000008; + set_GPIO_mode(AP_13MHZ_OUTPUT_PIN | GPIO_IN); + + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_CLK_IN_SEL); +} + + +#ifdef CONFIG_PM +int mixer_hw_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +{ + switch(req){ + case PM_SUSPEND: +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " E680 boomer path = 0X%X before AP sleep. \n", e680boomer.path); +#endif + if( (audioonflag & (PHONE_DEVICE|FM_DEVICE)) == 0 ){ + e680_boomer_path_tmp_shutdown(); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR); + } + break; + case PM_RESUME: +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " E680 after AP sleep.\n"); +#endif + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR); + set_output_gain_hw_reg(); + if( gpio_flt_sel_status ) + Clear_Haptics_GPIO(); + else + Set_Haptics_GPIO(); + if(audioonflag) + (*mixer_open_output_path[OUTPUT_BASE_TYPE(codec_output_base)][codec_output_path])(codec_output_base|codec_output_path); + e680_boomer_path_restore(); + break; + } + return 0; +} +#endif + + +void mute_output_to_avoid_pcap_noise(void) +{ + e680_boomer_path_tmp_mono_lineout(); +} + + +void undo_mute_output_to_avoid_pcap_noise(void) +{ + e680_boomer_path_restore(); +} + + +void Set_Haptics_GPIO(void) +{ + e680_boomer_path_tmp_mono_lineout(); + + set_GPIO_mode(GPIO_FLT_SEL_BUL | GPIO_OUT); + clr_GPIO(GPIO_FLT_SEL_BUL); + PGSR(GPIO_FLT_SEL_BUL) &= ~GPIO_bit(GPIO_FLT_SEL_BUL); + gpio_flt_sel_status = 0; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " set haptics GPIO \n"); +#endif + + e680_boomer_path_restore(); +} + + +void Clear_Haptics_GPIO(void) +{ + e680_boomer_path_tmp_mono_lineout(); + + set_GPIO_mode(GPIO_FLT_SEL_BUL | GPIO_OUT); + set_GPIO(GPIO_FLT_SEL_BUL); + PGSR(GPIO_FLT_SEL_BUL) |= GPIO_bit(GPIO_FLT_SEL_BUL); + gpio_flt_sel_status = 1; + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG " clear haptics GPIO \n"); +#endif + + e680_boomer_path_restore(); +} + + +#endif /* CONFIG_ARCH_EZX_E680 */ + + + diff -Nru --exclude-from=/sunbeam/home/laforge/scripts/dontdiff linux-2.6.16.5/sound/oss/ezx-e680.h linux-2.6.16.5-exz/sound/oss/ezx-e680.h --- linux-2.6.16.5/sound/oss/ezx-e680.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.5-exz/sound/oss/ezx-e680.h 2006-04-16 18:49:29.000000000 +0200 @@ -0,0 +1,183 @@ +/* + * linux/drivers/sound/ezx-e680.h + * + * + * Description: header file for ezx-e680.c + * + * + * Copyright: BJDC motorola. + * + * This program 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. + * + * + * History: + * Jin Lihong(w20076) Jan 12,2004,LIBdd68327 Created,Make the e680 louder speaker work. + * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs + * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix + * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 close dsp protection,and add 3d control interface for app + * Jin Lihong(w20076) Apr.24,2004,LIBee03164 reduce music noise, add new pathes for haptics + * Jin Lihong(w20076) Jun.15,2004,LIBee21625 boomer's power management + * Jin Lihong(w20076) Jun.22,2004,LIBee24284 mixer power save + * Wu Hongxing(w20691)Jul.07,2004 LIBee29664 ap 13m clock usage. + * + */ + +#ifndef EZX_E680_H +#define EZX_E680_H + +#include +#include + +#ifdef CONFIG_PXA_EZX_E680 + +//#define EZX_OSS_DEBUG /* debug switch for all ezx oss src files excluding ezx-audio.c */ +#undef EZX_OSS_DEBUG +//#define EZX_OSS_AUDIO_DEBUG /* debug switch for src file ezx-audio.c */ +#undef EZX_OSS_AUDIO_DEBUG + +/* +#ifdef EZX_OSS_DBG +#define OSSPRINTF(fmt,args...) printf(fmt,##args) +#else +#define OSSPRINTF(fmt,args...) { } +#endif +*/ + + +#define MIXERISSTEREO ( audioonflag & (DSP_DEVICE|MIDI_DEVICE|FM_DEVICE) ) +#define MIDIUSE13MCLK ( audioonflag & MIDI_DEVICE ) +#define DSPUSE13MCLK ( audioonflag & DSP_DEVICE ) +#define DSP16USE13MCLK ( audioonflag & DSP16_DEVICE ) + + +typedef enum{ + PHONE_DEVICE = 0x01, + DSP_DEVICE = 0x02, + DSP16_DEVICE = 0x04, + AUDIO_DEVICE = 0x08, + MIDI_DEVICE = 0x10, + FM_DEVICE = 0x20 +}audio_dev_type; + +typedef enum{ + LOUDERSPEAKER_ON_HEADSET_ON_3D, + LOUDERSPEAKER_ON_HEADSET_OFF_3D, + LOUDERSPEAKER_OFF_HEADSET_ON_3D, + LOUDERSPEAKER_OFF_HEADSET_OFF_3D +}boomer_3d_status; + + +void e680_boomer_init(void); +void e680_boomer_shutdown(void); +void e680_boomer_path_mono_lineout(void); +void e680_boomer_path_tmp_mono_lineout(void); +void e680_boomer_path_tmp_shutdown(void); +void e680_boomer_path_restore(void); + +void poweron_mixer( audio_dev_type type ); +void shutdown_mixer( audio_dev_type type ); +void mixer_not_in_use(void); + +void set_output_gain_hw_reg(void); +void set_input_gain_hw_reg(void); + +void set_boomer_3d_status(boomer_3d_status status); +boomer_3d_status get_boomer_3d_status(void); + +void set_gpio_va_sel_out_high(void); +void set_gpio_va_sel_out_low(void); + +void close_input_carkit(void); +void close_input_handset(void); +void close_input_headset(void); +void close_input_funlight(void); + +void open_input_carkit(void); +void open_input_handset(void); +void open_input_headset(void); +void open_input_funlight(void); + +void close_output_pcap_headset(void); +void close_output_pcap_louderspeaker(void); +void close_output_pcap_earpiece(void); +void close_output_pcap_carkit(void); +void close_output_pcap_headjack(void); +void close_output_pcap_bluetooth(void); +void close_output_pcap_louderspeaker_mixed(void); + +void close_output_ma3_headset(void); +void close_output_ma3_louderspeaker(void); +void close_output_ma3_earpiece(void); +void close_output_ma3_carkit(void); +void close_output_ma3_headjack(void); +void close_output_ma3_bluetooth(void); +void close_output_ma3_louderspeaker_mixed(void); + +void close_output_fm_headset(void); +void close_output_fm_louderspeaker(void); +void close_output_fm_earpiece(void); +void close_output_fm_carkit(void); +void close_output_fm_headjack(void); +void close_output_fm_bluetooth(void); +void close_output_fm_louderspeaker_mixed(void); + +void close_output_mixed_headset(void); +void close_output_mixed_louderspeaker(void); +void close_output_mixed_earpiece(void); +void close_output_mixed_carkit(void); +void close_output_mixed_headjack(void); +void close_output_mixed_bluetooth(void); +void close_output_mixed_louderspeaker_mixed(void); + +int open_output_pcap_headset(long val); +int open_output_pcap_louderspeaker(long val); +int open_output_pcap_earpiece(long val); +int open_output_pcap_carkit(long val); +int open_output_pcap_headjack(long val); +int open_output_pcap_bluetooth(long val); +int open_output_pcap_louderspeaker_mixed(long val); + +int open_output_ma3_headset(long val); +int open_output_ma3_louderspeaker(long val); +int open_output_ma3_earpiece(long val); +int open_output_ma3_carkit(long val); +int open_output_ma3_headjack(long val); +int open_output_ma3_bluetooth(long val); +int open_output_ma3_louderspeaker_mixed(long val); + +int open_output_fm_headset(long val); +int open_output_fm_louderspeaker(long val); +int open_output_fm_earpiece(long val); +int open_output_fm_carkit(long val); +int open_output_fm_headjack(long val); +int open_output_fm_bluetooth(long val); +int open_output_fm_louderspeaker_mixed(long val); + +int open_output_mixed_headset(long val); +int open_output_mixed_louderspeaker(long val); +int open_output_mixed_earpiece(long val); +int open_output_mixed_carkit(long val); +int open_output_mixed_headjack(long val); +int open_output_mixed_bluetooth(long val); +int open_output_mixed_louderspeaker_mixed(long val); + +void kernel_set_oscc_13m_clock(void); +void kernel_clr_oscc_13m_clock(void); +void pcap_use_ap_13m_clock(void); +void pcap_use_bp_13m_clock(void); + +int mixer_hw_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data); +void mute_output_to_avoid_pcap_noise(void); +void undo_mute_output_to_avoid_pcap_noise(void); + +void Set_Haptics_GPIO(void); +void Clear_Haptics_GPIO(void); + + +#endif /* CONFIG_ARCH_EZX_E680 */ + + +#endif + diff -Nru --exclude-from=/sunbeam/home/laforge/scripts/dontdiff linux-2.6.16.5/sound/oss/ezx-nssp.c linux-2.6.16.5-exz/sound/oss/ezx-nssp.c --- linux-2.6.16.5/sound/oss/ezx-nssp.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.5-exz/sound/oss/ezx-nssp.c 2006-04-16 18:49:29.000000000 +0200 @@ -0,0 +1,358 @@ +/* + * linux/drivers/sound/ezx-nssp.c + * + * + * Description: nssp interface for the ezx platform + * + * + * Copyright: BJDC motorola. + * + * This program 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. + * + * + * History: + * zhouqiong, Motorola Jun 20,2002 created + * zhouqiong, Motorola Sep 19,2002 according code review meeting minutes. + * zhouqiong, Motorola Oct 30,2002 according new requirement for VA. + * zhouqiong, Motorola Nov 05,2002 according code review meeting minutes. + * zhouqiong, Motorola Mar 04,2003 (1) don't close headset interrupt; + * (2) when headset in, output gain decrease 6db + * LiYong, Motorola Sep 23,2003 (1)Port from EZX; (2)Modify the NSSP port inital + * Jin Lihong(w20076), Motorola Jan 02,2004 (1) Port from UDC e680 kernel of jem vob. + * (2) Move audio driver DEBUG macro definition to ezx-audio.h + * header file,and redefine DEBUG to EZX_OSS_DEBUG + * (3) reorganize file header + * Jin Lihong(w20076),Motorola Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs + * Jin Lihong(w20076),Motorola Mar.15,2004,LIBdd86574 mixer bug fix + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ezx-audio.h" +#include "ezx-common.h" + + +static DECLARE_MUTEX(cotulla_nssp_mutex); + +static int nssp_init(void); +static void nssp_shutdown(void); + + +/*initialize hardware, nssp controller and pcap register*/ +static int nssp_init(void) +{ + unsigned long flags; + unsigned long ssp_pcap_register_val; + unsigned int ssp_pcap_bit_status; + volatile unsigned long audiostatus; + unsigned long timeout; + + down(&cotulla_nssp_mutex); + + ssp_pcap_open(SSP_PCAP_AUDIO_OPEN); + if( MONODEVOPENED == 0 ) + pcap_use_ap_13m_clock(); + audioonflag |= AUDIO_DEVICE; + +#ifdef EZX_OSS_DEBUG + printk("setup nssp controller register \n"); +#endif + local_irq_save(flags); + CKEN |= CKEN3_NSSP; /* need enable cken3 */ + + set_GPIO_mode(GPIO_BITCLK_IN_NSSP_MD); /* BitCLK */ + set_GPIO_mode(GPIO_SYNC_IN_NSSP_MD); /* FS */ + /*At E680,the NSSP TX and RX pins are single direction */ +// set_GPIO_mode(GPIO_SDATA_OUT_NSSP_MD); /* TXD ssp2 ALF out 2 */ + set_GPIO_mode(GPIO_SDATA_IN_NSSP_MD); /* RXD ssp2 ALF in 1*/ + /* setup nssp port */ + NSSCR0 = NSSCR0_FRF_PSP | NSSCR0_DSS_16bit; /* PSP mode, 16bit */ + NSSCR1 = NSSCR1_TTE | NSSCR1_EBCEI | NSSCR1_SCLKDIR | NSSCR1_SFRMDIR | NSSCR1_TFTH_4 | NSSCR1_RFTH_14; + NSSPSP = NSSPSP_SFRMWDTH_1 | NSSPSP_STRTDLY_1 | NSSPSP_SFRMP_HIGH | NSSPSP_SCMODE; + NSSCR1 |= NSSCR1_TSRE | NSSCR1_RSRE; /* enable dma request */ + NSSCR0 |= NSSCR0_SSE; /* enable nssp controller */ + local_irq_restore(flags); + +#ifdef EZX_OSS_DEBUG + audiostatus = NSSCR0; + printk("NSSCR0 = 0x%lx\n", audiostatus); + audiostatus = NSSCR1; + printk("NSSCR1 = 0x%lx\n", audiostatus); + audiostatus = NSSPSP; + printk("NSSPSP = 0x%lx\n", audiostatus); +#endif + +#ifdef EZX_OSS_DEBUG + SSP_PCAP_read_data_from_PCAP(0x0d,&ssp_pcap_register_val); + printk("pcap register 13 = 0x%lx\n", ssp_pcap_register_val); + SSP_PCAP_read_data_from_PCAP(0x0c,&ssp_pcap_register_val); + printk("pcap register 12 = 0x%lx\n", ssp_pcap_register_val); + SSP_PCAP_read_data_from_PCAP(0x0b,&ssp_pcap_register_val); + printk("pcap register 11 = 0x%lx\n", ssp_pcap_register_val); + SSP_PCAP_read_data_from_PCAP(0x1a,&ssp_pcap_register_val); + printk("pcap register 26 = 0x%lx\n", ssp_pcap_register_val); +#endif + + timeout = 0; + /* check if ssp is ready for slave operation */ + while(((audiostatus = NSSSR) & NSSSR_CSS) !=0){ + if((timeout++) > 10000000) + goto err; + } +#ifdef EZX_OSS_DEBUG + printk(" complete all hardware init \n"); +#endif + up(&cotulla_nssp_mutex); + return 0; + +err: + up(&cotulla_nssp_mutex); + printk("audio panic: ssp don't ready for slave operation!!! "); + return -ENODEV; +} + + +static void nssp_shutdown(void) +{ + down(&cotulla_nssp_mutex); + + audioonflag &= ~AUDIO_DEVICE; + if( MONODEVOPENED == 0 ) + pcap_use_bp_13m_clock(); + +#ifdef EZX_OSS_DEBUG + printk("close nssp port\n"); +#endif + NSSCR0 = 0; + NSSCR1 = 0; + NSSPSP = 0; + CKEN &= ~CKEN3_NSSP; /* SSP2 need control the CKEN3 */ + + set_GPIO_mode(GPIO_NSSP_SCLK2 | GPIO_IN); /* BitCLK */ + set_GPIO_mode(GPIO_NSSP_SFRM2 | GPIO_IN); /* FS */ + set_GPIO_mode(GPIO_NSSP_TXD2 | GPIO_IN); + set_GPIO_mode(GPIO_NSSP_RXD2 | GPIO_IN); + +#ifdef EZX_OSS_DEBUG + printk("close pcap register\n"); +#endif + + up(&cotulla_nssp_mutex); +} + + +/* + * nssp codec ioctls + */ +static int codec_adc_rate = PHONE_CODEC_DEFAULT_RATE; /* default 8k sample rate */ +static int codec_dac_rate = PHONE_CODEC_DEFAULT_RATE; /* default 8k sample rate */ + +static int nssp_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret; + long val; + int audiostatus, timeout; + + switch(cmd) { + case SNDCTL_DSP_STEREO: +#ifdef EZX_OSS_DEBUG + printk(" check if support stereo\n"); +#endif + ret = get_user(val, (int *) arg); + if (ret) + return ret; + if(val) /* not support stereo mode */ + ret = -EINVAL; + else + ret = 1; + return put_user(ret, (int *) arg); + + case SNDCTL_DSP_CHANNELS: + case SOUND_PCM_READ_CHANNELS: +#ifdef EZX_OSS_DEBUG + printk(" check if 2 channels \n"); +#endif + return put_user(1, (long *) arg); + + case SNDCTL_DSP_SPEED: +#ifdef EZX_OSS_DEBUG + printk(" set sample frequency \n"); +#endif + ret = get_user(val, (long *) arg); + if (ret) + return ret; + + down(&cotulla_nssp_mutex); + NSSCR0 &= ~NSSCR0_SSE; + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); + switch(val) + { + case PHONE_CODEC_16K_RATE: /*16K sample rate */ + ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_8K_16K); + codec_adc_rate = val; + codec_dac_rate = val; + break; + case PHONE_CODEC_DEFAULT_RATE: /*8K sample rate */ + ret = SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_8K_16K); + codec_adc_rate = val; + codec_dac_rate = val; + break; + default: + ret = -EINVAL; + break; + } + /* reset digital filter(DF_RESET=1) */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); + + NSSCR0 |= NSSCR0_SSE; /* enable nssp controller */ + timeout = 0; + /* check if ssp is ready for slave operation */ + while(((audiostatus = NSSSR) & NSSSR_CSS) !=0) + { + if((timeout++) > 10000000) + { + printk("audio panic: can't be slave mode!!!"); + ret =-ENODEV; + break; + } + } + up(&cotulla_nssp_mutex); +#ifdef EZX_OSS_DEBUG + printk("AD sample freq = %d\n", codec_adc_rate); + printk("DA sample freq = %d\n", codec_dac_rate); +#endif + return put_user(codec_adc_rate, (long *) arg); + + case SOUND_PCM_READ_RATE: + if (file->f_mode & FMODE_WRITE) + { +#ifdef EZX_OSS_DEBUG + printk("read DA sample freq\n"); +#endif + val = codec_dac_rate; + } + if (file->f_mode & FMODE_READ) + { +#ifdef EZX_OSS_DEBUG + printk("read AD sample freq\n"); +#endif + val = codec_adc_rate; + } + return put_user(val, (long *) arg); + + case SNDCTL_DSP_SETFMT: + case SNDCTL_DSP_GETFMTS: + /* SUPPORT little endian signed 16 */ +#ifdef EZX_OSS_DEBUG + printk("data format is AFMT_S16_LEd\n"); +#endif + return put_user(AFMT_S16_LE, (long *) arg); + + default: + return mixer_ioctl(inode, file, cmd, arg); + } + return 0; +} + + +/* + * Audio stuff + */ + +static audio_stream_t nssp_audio_out = { + name: "nssp audio out", + dcmd: DCMD_TXNSSDR, + drcmr: &DRCMRTXNSSDR, /* nssp dma map register */ + dev_addr: __PREG(NSSDR), +}; + +static audio_stream_t nssp_audio_in = { + name: "nssp audio in", + dcmd: DCMD_RXNSSDR, + drcmr: &DRCMRRXNSSDR, /* nssp dma map register */ + dev_addr: __PREG(NSSDR), +}; + +static audio_state_t nssp_audio_state = { + output_stream: &nssp_audio_out, + input_stream: &nssp_audio_in, + client_ioctl: nssp_ioctl, + hw_init: nssp_init, + hw_shutdown: nssp_shutdown, + sem: __MUTEX_INITIALIZER(nssp_audio_state.sem), +}; + + +static int nssp_audio_open(struct inode *inode, struct file *file) +{ +#ifdef EZX_OSS_DEBUG + printk("nssp audio open \n"); +#endif + return cotulla_audio_attach(inode, file, &nssp_audio_state); +} + + +/* + * Missing fields of this structure will be patched with the call + * to cotulla_audio_attach(). + */ + + +static struct file_operations nssp_audio_fops = { + open: nssp_audio_open, + owner: THIS_MODULE +}; + + +static int __init cotulla_nssp_init(void) +{ + nssp_audio_state.dev_dsp = register_sound_audio(&nssp_audio_fops, -1); + + set_GPIO_mode(GPIO_NSSP_SCLK2 | GPIO_IN); /* BitCLK */ + set_GPIO_mode(GPIO_NSSP_SFRM2 | GPIO_IN); /* FS */ + set_GPIO_mode(GPIO_NSSP_TXD2 | GPIO_IN); + set_GPIO_mode(GPIO_NSSP_RXD2 | GPIO_IN); /* RXD ssp2 ALF in 1*/ + +#ifdef EZX_OSS_DEBUG + printk("cotulla-nssp-init ok\n"); +#endif + return 0; +} + + +static void __exit cotulla_nssp_exit(void) +{ + unregister_sound_audio(nssp_audio_state.dev_dsp); +#ifdef EZX_OSS_DEBUG + printk("cotulla-nssp-exit ok\n"); +#endif +} + + +module_init(cotulla_nssp_init); +module_exit(cotulla_nssp_exit); + + + diff -Nru --exclude-from=/sunbeam/home/laforge/scripts/dontdiff linux-2.6.16.5/sound/oss/ezx-phone.c linux-2.6.16.5-exz/sound/oss/ezx-phone.c --- linux-2.6.16.5/sound/oss/ezx-phone.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.5-exz/sound/oss/ezx-phone.c 2006-04-16 18:49:29.000000000 +0200 @@ -0,0 +1,280 @@ +/* + * linux/drivers/sound/ezx-phone + * + * + * Description: phone interface for EZX. for application can't direct call interface in kernel space from + * user space.so phone controll realize a char device. + * + * + * copyright: Motorola + * + * This program 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. + * + * + * History: + * zhouqiong Aug 02,2002 created + * zhouqiong Mar 03,2003 (1) don't close headset interrupt; + * (2) move bluetooth to phone device ioctl + * LiYong Sep 23,2003 Port from EZX + * Jin Lihong(w20076) Jan 02,2004,LIBdd66088 (1) Port from UDC e680 kernel of jem vob. + * (2) Move audio driver DEBUG macro definition to ezx-audio.h + * header file,and redefine DEBUG to EZX_OSS_DEBUG + * (3) reorganize file header + * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Make the e680 louder speaker work. + * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix + * Jin Lihong(w20076) Mar.25,2004,LIBdd90336 play music noise tmp solution + * Jin Lihong(w20076) Mar.25,2004,LIBdd90846 a780 new gain setting interface + * Jin Lihong(w20076) Apr.20,2004,LIBee01165 va of a phone call for e680 + * Jin Lihong(w20076) Apr.24,2004,LIBee03164 a780 bitclock restore to normal because pcap2 upgraded + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ezx-common.h" + + +#ifdef CONFIG_PM +static struct pm_dev *pm_dev; +#endif + +static DECLARE_MUTEX(phone_mutex); + +#ifdef CONFIG_PM +#ifdef CONFIG_ARCH_EZX_E680 +extern u32 gpio_va_sel_status; +#endif + + +static int phone_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +{ + switch(req) + { + case PM_SUSPEND: + break; + case PM_RESUME: +#ifdef CONFIG_ARCH_EZX_E680 + set_GPIO_mode(GPIO_VA_SEL_BUL | GPIO_OUT); + if(gpio_va_sel_status) + { + set_GPIO(GPIO_VA_SEL_BUL); + } + else + { + clr_GPIO(GPIO_VA_SEL_BUL); + } +#endif + break; + } + return 0; +} +#endif + + +void bluetoothaudio_open(void) +{} +void bluetoothaudio_close(void) +{} + +static int phone_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned long ssp_pcap_register_val; + + switch(cmd) { + case BLUETOOTH_AUDIO_ON: +#ifdef EZX_OSS_DEBUG + printk("bluetooth audio on\n"); +#endif + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); +#ifdef EZX_OSS_DEBUG + SSP_PCAP_read_data_from_PCAP(SSP_PCAP_ADJ_AUD_CODEC_REGISTER, &ssp_pcap_register_val); + printk("AUD_CODEC=0x%x\n", ssp_pcap_register_val); +#endif + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN); + (*mixer_close_output_path[OUTPUT_BASE_TYPE(codec_output_base)][codec_output_path])(); + break; + + case BLUETOOTH_AUDIO_OFF: +#ifdef EZX_OSS_DEBUG + printk("bluetooth audio off\n"); +#endif + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); +#ifdef EZX_OSS_DEBUG + SSP_PCAP_read_data_from_PCAP(SSP_PCAP_ADJ_AUD_CODEC_REGISTER, &ssp_pcap_register_val); + printk("AUD_CODEC=0x%x\n", ssp_pcap_register_val); +#endif + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN); + (*mixer_open_output_path[OUTPUT_BASE_TYPE(codec_output_base)][codec_output_path])(codec_output_base|codec_output_path ); + break; + + default: + return mixer_ioctl(inode, file, cmd, arg); + } + return 0; +} + + +/* + * there is a supposition: + * when run phone_open, other audio device is stopped, pcap is free + */ +static int count = 0; +static int phone_open(struct inode *inode, struct file *file) +{ + unsigned int ssp_pcap_register_val; + +/* +#ifdef CONFIG_ARCH_EZX_E680 + if( audioonflag & FM_DEVICE ){ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "E680 open phone EBUSY because 0x%X device is using the sound hardware.\n",audioonflag ); +#endif + return -EBUSY; + } +#endif +*/ + + if(!count){ + count ++; + + down(&phone_mutex); + + mute_output_to_avoid_pcap_noise(); + audioonflag |= PHONE_DEVICE; + ssp_pcap_open(SSP_PCAP_AUDIO_OPEN); + pcap_use_bp_13m_clock(); + + +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "open phone device, init pcap register\n"); +#endif + set_pcap_telephone_codec(0); + set_pcap_output_path(); + set_pcap_input_path(); + + undo_mute_output_to_avoid_pcap_noise(); + +#ifdef EZX_OSS_DEBUG + SSP_PCAP_read_data_from_PCAP(0x0b, &ssp_pcap_register_val); + printk("reg 11=0x%x\n", ssp_pcap_register_val); + SSP_PCAP_read_data_from_PCAP(0x0d, &ssp_pcap_register_val); + printk("reg 13=0x%x\n", ssp_pcap_register_val); + SSP_PCAP_read_data_from_PCAP(0x0c, &ssp_pcap_register_val); + printk("reg 12=0x%x\n", ssp_pcap_register_val); + SSP_PCAP_read_data_from_PCAP(0x1a, &ssp_pcap_register_val); + printk("reg 26=0x%x\n", ssp_pcap_register_val); +#endif + up(&phone_mutex); + +#ifdef CONFIG_ARCH_EZX_E680 + set_gpio_va_sel_out_low(); +#endif + +#ifdef CONFIG_PM + pm_dev = pm_register(PM_SYS_DEV, 0, phone_pm_callback); +#endif + return 0; + } + else + return -EBUSY; +} + + +static int phone_release(struct inode *inode, struct file *file) +{ + count --; + if(!count){ + down(&phone_mutex); + + mute_output_to_avoid_pcap_noise(); + + /* close pcap input path */ + if(micinflag) + SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER,SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2); + else + SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER, 0); + /* close pcap output path */ + SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER,SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); + /* disable PCAP mono codec */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_SMB); + + /* set fsync, tx, bitclk are tri-stated */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CD_TS); + + up(&phone_mutex); + +#ifdef CONFIG_ARCH_EZX_E680 + set_gpio_va_sel_out_high(); + e680_boomer_path_mono_lineout(); /* mute hw noise and save power for e680 */ +#endif + + pcap_use_bp_13m_clock(); + audioonflag &= ~PHONE_DEVICE; + +#ifdef CONFIG_PM + pm_unregister(pm_dev); +#endif + } + + return 0; +} + + +static struct file_operations device_fops = { + owner: THIS_MODULE, + open: phone_open, + release: phone_release, + ioctl: phone_ioctl, +}; + +static int __init phone_init(void) +{ + int ret; + ret = register_chrdev(MYPHONE_MAJOR,"phone", &device_fops); + if(ret) + { + printk("can't register phone device with kernel"); + } +#ifdef EZX_OSS_DEBUG + printk("register phone device with kernel ok \n"); +#endif + return 0; +} + +static void __exit phone_exit(void) +{ + unregister_chrdev(MYPHONE_MAJOR, "phone"); +#ifdef EZX_OSS_DEBUG + printk("unregister phone device \n"); +#endif +} + + +module_init(phone_init); +module_exit(phone_exit); + + diff -Nru --exclude-from=/sunbeam/home/laforge/scripts/dontdiff linux-2.6.16.5/sound/oss/ezx-vibrator.c linux-2.6.16.5-exz/sound/oss/ezx-vibrator.c --- linux-2.6.16.5/sound/oss/ezx-vibrator.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.5-exz/sound/oss/ezx-vibrator.c 2006-04-16 18:49:29.000000000 +0200 @@ -0,0 +1,245 @@ +/* + * linux/drivers/sound/vibrator.c + * + * + * Description: vibrator interface for EZX. for application can't direct call interface in kernel space from + * user space.so vibrator still realize a char device. + * + * + * (c) Copyright Motorola 2003, All rights reserved. + * + * + * History: + * zhouqiong Jun 20,2002 created + * Kin Wong Nov 05,2003 Renamed ezx-vibrator.h to vibrator.h + * Jin Lihong(w20076) Jan 02,2004 (1) Port from UDC e680 kernel of jem vob. + * (2) Move audio driver DEBUG macro definition to ezx-audio.h + * header file,and redefine DEBUG to EZX_OSS_DEBUG + * (3) reorganize file header + * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 reorganise file header + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../misc/ssp_pcap.h" +#include "ezx-vibrator.h" + + +#ifdef CONFIG_PM +static struct pm_dev *pm_dev; +#endif + +static int active=0; +static int voltage=0; + +static int vibrator_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret; + long val; + + switch(cmd) + { + case VIBRATOR_ENABLE: +#ifdef EZX_OSS_DEBUG + printk("enable vibrator \n"); +#endif + ret = get_user(val, (int *) arg); + if (ret) + return ret; + switch(val) + { + case 0: +#ifdef EZX_OSS_DEBUG + printk("vibrator level 0 \n"); +#endif + ret = SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL0); + ret = SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL0); + active = 1; + voltage = 0; + SSP_vibrate_start_command(); + break; + case 1: +#ifdef EZX_OSS_DEBUG + printk("vibrator level 1 \n"); +#endif + ret = SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL1); + ret = SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL1); + active = 1; + voltage = 1; + SSP_vibrate_start_command(); + break; + case 2: +#ifdef EZX_OSS_DEBUG + printk("vibrator level 2 \n"); +#endif + ret = SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL2); + ret = SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL2); + active = 1; + voltage = 2; + SSP_vibrate_start_command(); + break; + case 3: +#ifdef EZX_OSS_DEBUG + printk("vibrator level 3 \n"); +#endif + ret = SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL3); + ret = SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL3); + active = 1; + voltage = 3; + SSP_vibrate_start_command(); + break; + default: +#ifdef EZX_OSS_DEBUG + printk("vibrator level error \n"); +#endif + return -EINVAL; + } + return put_user(ret, (int *) arg); + + case VIBRATOR_DISABLE: +#ifdef EZX_OSS_DEBUG + printk("disable vibrator \n"); +#endif + ret = 0; + active = 0; + SSP_vibrate_stop_command(); + return put_user(ret, (int *) arg); + default: + return -EINVAL; + } + return 0; +} + +#ifdef CONFIG_PM +static int vibrator_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +{ + switch(req) + { + case PM_SUSPEND: + if(active) + { + SSP_vibrate_stop_command(); + } + break; + case PM_RESUME: + if(active) + { + switch(voltage) + { + case 0: + SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL0); + SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL0); + break; + case 1: + SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL1); + SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL1); + break; + case 2: + SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL2); + SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL2); + break; + case 3: + SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL3); + SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL3); + break; + default: + break; + } + SSP_vibrate_start_command(); + } + break; + } + return 0; +} +#endif + +static int count=0; +static int vibrator_open(struct inode *inode, struct file *file) +{ + if(!count) + { + count ++; + //ssp_pcap_init(); + ssp_pcap_open(SSP_PCAP_AUDIO_OPEN); +#ifdef CONFIG_PM + pm_dev = pm_register(PM_SYS_DEV, 0, vibrator_pm_callback); +#endif +#ifdef EZX_OSS_DEBUG + printk("open vibrator \n"); +#endif + return 0; + } + else + return -EBUSY; +} + +static int vibrator_release(struct inode *inode, struct file *file) +{ + count --; + if(!count) + { +#ifdef CONFIG_PM + pm_unregister(pm_dev); +#endif +#ifdef EZX_OSS_DEBUG + printk("close vibrator \n"); +#endif + } + return 0; +} + + +static struct file_operations device_fops = { + owner: THIS_MODULE, + open: vibrator_open, + release: vibrator_release, + ioctl: vibrator_ioctl, +}; + +static int __init vibrator_init(void) +{ + int ret; +#ifdef EZX_OSS_DEBUG + printk("enter vibrator init...\n"); +#endif + ret = register_chrdev(VIBRATOR_MAJOR,"vibrator", &device_fops); + if(ret){ + printk("can't register vibrator device with kernel"); + } +#ifdef EZX_OSS_DEBUG + printk("vibrator init ok\n"); +#endif + return 0; +} + +static void __exit vibrator_exit(void) +{ + unregister_chrdev(VIBRATOR_MAJOR, "vibrator"); +#ifdef EZX_OSS_DEBUG + printk("vibrator exit ok\n"); +#endif + return; +} + + +module_init(vibrator_init); +module_exit(vibrator_exit); + + diff -Nru --exclude-from=/sunbeam/home/laforge/scripts/dontdiff linux-2.6.16.5/sound/oss/ezx-vibrator.h linux-2.6.16.5-exz/sound/oss/ezx-vibrator.h --- linux-2.6.16.5/sound/oss/ezx-vibrator.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.5-exz/sound/oss/ezx-vibrator.h 2006-04-16 18:49:29.000000000 +0200 @@ -0,0 +1,33 @@ +/* + * linux/drivers/sound/ezx-vibrator.h + * + * Copyright: BJDC motorola. + * + * This program 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. + * + * + * History: + * zhouqiong Jun 20,2002 created + * Jin Lihong(w20076) Jan 02,2004 (1) Port from UDC e680 kernel of jem vob. + * (2) reorganize file header + * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 reorganise file header + * + */ + +#ifndef EZX_VIBRATOR_H +#define EZX_VIBRATOR_H + +#include + + +#define VIBRATOR_MAJOR 108 +#define VIBRATOR_IOCTL_BASE 0xbb +#define VIBRATOR_ENABLE _IOW (VIBRATOR_IOCTL_BASE,1,int) +#define VIBRATOR_DISABLE _IO (VIBRATOR_IOCTL_BASE,2) + + +#endif + +