From: Mika Laitio Date: Mon, 19 Jan 2009 23:15:09 +0000 (+0200) Subject: h63xx: tsc2101 alsa sound support X-Git-Tag: v2.6.16-omap1-h63xx-1 X-Git-Url: http://pilppa.com/gitweb/?a=commitdiff_plain;h=c872ebcdd22885f52cb1123472b0a7335f872785;p=linux-2.6-omap-h63xx.git h63xx: tsc2101 alsa sound support --- diff --git a/arch/arm/configs/omap_h63xx_defconfig b/arch/arm/configs/omap_h63xx_defconfig index 2bc595da2a8..b3f0625a222 100644 --- a/arch/arm/configs/omap_h63xx_defconfig +++ b/arch/arm/configs/omap_h63xx_defconfig @@ -1043,7 +1043,49 @@ CONFIG_LCD_DEVICE=y # # Sound # -# CONFIG_SOUND is not set +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set + +# +# ALSA ARM devices +# +# CONFIG_SND_OMAP_AIC23 is not set +CONFIG_SND_OMAP_TSC2101=m + +# +# USB devices +# +# CONFIG_SND_USB_AUDIO is not set + +# +# PCMCIA devices +# + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set # # USB support @@ -1074,6 +1116,7 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y # # USB Device Class drivers # +# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set CONFIG_USB_ACM=y # CONFIG_USB_PRINTER is not set diff --git a/arch/arm/mach-omap1/board-h6300.c b/arch/arm/mach-omap1/board-h6300.c index 09f14777f1f..888e654549d 100644 --- a/arch/arm/mach-omap1/board-h6300.c +++ b/arch/arm/mach-omap1/board-h6300.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #define _h6300_KEY_CALENDAR 67 // xmodmap 75 aka F9 @@ -117,15 +119,48 @@ static struct platform_omap_serial_funcs h6300_omap_platform__uart_bt_funcs = { .get_txrx = NULL, }; -struct platform_device btuart_device = { +struct platform_device h63xx_uart_bt_device = { .name = "h6300_bt", .id = 1, }; -EXPORT_SYMBOL(btuart_device); +EXPORT_SYMBOL(h63xx_uart_bt_device); + +static struct omap_mcbsp_reg_cfg mcbsp_regs = { + .spcr2 = 0x0000, + .spcr1 = 0x0000, + .rcr2 = 0x8041, + .rcr1 = 0x0040, + .xcr2 = 0x00a1, + .xcr1 = 0x00a0, + .srgr2 = 0xb000, + .srgr1 = 0x0000, + .pcr0 = 0x0081, +}; + +static struct omap_alsa_codec_config alsa_config = { + .name = "iPAQ h6300 TSC2101", + .mcbsp_regs_alsa = &mcbsp_regs, + .codec_configure_dev = NULL, //tsc2101_configure, + .codec_set_samplerate = NULL, //tsc2101_set_samplerate, + .codec_clock_setup = NULL, //tsc2101_clock_setup, + .codec_clock_on = NULL, //tsc2101_clock_on, + .codec_clock_off = NULL, //tsc2101_clock_off, + .get_default_samplerate = NULL, //tsc2101_get_default_samplerate, +}; + +static struct platform_device h6300_mcbsp1_sound_device = { + .name = "omap_alsa_mcbsp", + .id = 1, + .dev = { + .platform_data = &alsa_config, + }, +}; static struct platform_device *h6300_devices[] __initdata = { &h6300_lcd_device, &h6300_kp_device, + &h63xx_uart_bt_device, + &h6300_mcbsp1_sound_device, }; static struct omap_lcd_config h6300_lcd_config __initdata = { diff --git a/include/asm-arm/arch-omap/omap_serial.h b/include/asm-arm/arch-omap/omap_serial.h index add09dc3580..90e683434aa 100644 --- a/include/asm-arm/arch-omap/omap_serial.h +++ b/include/asm-arm/arch-omap/omap_serial.h @@ -54,9 +54,8 @@ struct platform_omap_serial_funcs { /* * The variables below are located in arch/arm/mach-omap/board_h6300.c * Machine-specific code may want to put a pointer to a static - * platform_pxa_serial_funcs structure in the dev.platform_data - * field of the respective port device. + * 63xx_uart_bt_device.dev.platform_data */ -extern struct platform_device btuart_device; +extern struct platform_device h63xx_uart_bt_device; #endif diff --git a/sound/arm/omap/omap-alsa-tsc2101-mixer.c b/sound/arm/omap/omap-alsa-tsc2101-mixer.c index 9dfaea8d7bd..0f922661a98 100644 --- a/sound/arm/omap/omap-alsa-tsc2101-mixer.c +++ b/sound/arm/omap/omap-alsa-tsc2101-mixer.c @@ -50,47 +50,53 @@ //#define M_DPRINTK(ARGS...) printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS) #define M_DPRINTK(ARGS...) /* nop */ +#define CHECK_BIT(INDX, ARG) (((ARG) & TSC2101_BIT(INDX)) >> INDX) +#define IS_UNMUTED(INDX, ARG) (((CHECK_BIT(INDX, ARG)) == 0)) + #define DGC_DALVL_EXTRACT(ARG) ((ARG & 0x7f00) >> 8) #define DGC_DARVL_EXTRACT(ARG) ((ARG & 0x007f)) -#define GET_DGC_DALMU_BIT_VALUE(ARG) (((ARG) & TSC2101_BIT(15)) >> 15) -#define GET_DGC_DARMU_BIT_VALUE(ARG) (((ARG) & TSC2101_BIT(7)) >> 7) -#define IS_DGC_DALMU_UNMUTED(ARG) (((GET_DGC_DALMU_BIT_VALUE(ARG)) == 0)) -#define IS_DGC_DARMU_UNMUTED(ARG) (((GET_DGC_DARMU_BIT_VALUE(ARG)) == 0)) #define HGC_ADPGA_HED_EXTRACT(ARG) ((ARG & 0x7f00) >> 8) -#define GET_DGC_HGCMU_BIT_VALUE(ARG) (((ARG) & TSC2101_BIT(15)) >> 15) -#define IS_DGC_HGCMU_UNMUTED(ARG) (((GET_DGC_HGCMU_BIT_VALUE(ARG)) == 0)) - #define HNGC_ADPGA_HND_EXTRACT(ARG) ((ARG & 0x7f00) >> 8) -#define GET_DGC_HNGCMU_BIT_VALUE(ARG) (((ARG) & TSC2101_BIT(15)) >> 15) -#define IS_DGC_HNGCMU_UNMUTED(ARG) (((GET_DGC_HNGCMU_BIT_VALUE(ARG)) == 0)) +#define BGC_ADPGA_BGC_EXTRACT(ARG) ((ARG & 0x7f00) >> 8) static int current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER; static int current_rec_src = REC_SRC_SINGLE_ENDED_MICIN_HED; +/* + * Simplified write for the tsc2101 audio registers. + */ +inline void omap_tsc2101_audio_write(u8 address, u16 data) +{ + omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS, address, data); +} + +/* + * Simplified read for the tsc2101 audio registers. + */ +inline u16 omap_tsc2101_audio_read(u8 address) +{ + return (omap_tsc2101_read(PAGE2_AUDIO_CODEC_REGISTERS, address)); +} + /* - * Used for switching between TSC2101 recourd sources. - * Logic is adjusted from the TSC2101 OSS code. + * For selecting tsc2101 recourd source. */ -static int set_record_source(int val) +static void set_record_source(int val) { u16 data; - int maskedVal; - FN_IN; - maskedVal = 0xe0 & val; - - data = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_MIXER_PGA_CTRL); + /* Mute Analog Sidetone + * Analog sidetone gain db? + * Input selected by MICSEL connected to ADC + */ + data = MPC_ASTMU | MPC_ASTG(0x45); data &= ~MPC_MICSEL(7); /* clear all MICSEL bits */ - data |= maskedVal; - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_MIXER_PGA_CTRL, - data); + data |= MPC_MICSEL(val); + data |= MPC_MICADC; + omap_tsc2101_audio_write(TSC2101_MIXER_PGA_CTRL, data); + current_rec_src = val; - - FN_OUT(0); - return 0; } /* @@ -147,32 +153,34 @@ int set_mixer_volume_as_dac_gain_control_volume(int mixerVolL, int mixerVolR) volL = get_mixer_volume_as_dac_gain_control_volume(mixerVolL); volR = get_mixer_volume_as_dac_gain_control_volume(mixerVolR); - val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL); + val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL); /* keep the old mute bit settings */ val &= ~(DGC_DALVL(OUTPUT_VOLUME_MIN) | DGC_DARVL(OUTPUT_VOLUME_MIN)); val |= DGC_DALVL(volL) | DGC_DARVL(volR); retVal = 2; if (retVal) { - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_DAC_GAIN_CTRL, - val); + omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val); } M_DPRINTK("to registry: left = %d, right = %d, total = %d\n", DGC_DALVL_EXTRACT(val), DGC_DARVL_EXTRACT(val), val); return retVal; } -int dac_gain_control_unmute_control(int muteLeft, int muteRight) +/** + * If unmuteLeft/unmuteRight == 0 --> mute + * If unmuteLeft/unmuteRight == 1 --> unmute + */ +int dac_gain_control_unmute(int unmuteLeft, int unmuteRight) { u16 val; int count; count = 0; - val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL); + val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL); /* in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on * so if values are same, it's time to change the registry value. */ - if (muteLeft == GET_DGC_DALMU_BIT_VALUE(val)) { - if (muteLeft == 0) { + if (unmuteLeft != IS_UNMUTED(15, val)) { + if (unmuteLeft == 0) { /* mute --> turn bit on */ val = val | DGC_DALMU; } @@ -182,8 +190,8 @@ int dac_gain_control_unmute_control(int muteLeft, int muteRight) } count++; } /* L */ - if (muteRight == GET_DGC_DARMU_BIT_VALUE(val)) { - if (muteRight == 0) { + if (unmuteRight != IS_UNMUTED(7, val)) { + if (unmuteRight == 0) { /* mute --> turn bit on */ val = val | DGC_DARMU; } @@ -194,14 +202,47 @@ int dac_gain_control_unmute_control(int muteLeft, int muteRight) count++; } /* R */ if (count) { - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL, val); + omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val); M_DPRINTK("changed value, is_unmuted left = %d, right = %d\n", - IS_DGC_DALMU_UNMUTED(val), - IS_DGC_DARMU_UNMUTED(val)); + IS_UNMUTED(15, val), + IS_UNMUTED(7, val)); } return count; } +/** + * unmute: 0 --> mute, 1 --> unmute + * page2RegIndx: Registry index in tsc2101 page2. + * muteBitIndx: Index number for the bit in registry that indicates whether muted or unmuted. + */ +int adc_pga_unmute_control(int unmute, int page2regIndx, int muteBitIndx) +{ + int count; + u16 val; + + count = 0; + val = omap_tsc2101_audio_read(page2regIndx); + /* in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on + * so if the values are same, it's time to change the registry value... + */ + if (unmute != IS_UNMUTED(muteBitIndx, val)) { + if (unmute == 0) { + /* mute --> turn bit on */ + val = val | TSC2101_BIT(muteBitIndx); + } + else { + /* unmute --> turn bit off */ + val = val & ~TSC2101_BIT(muteBitIndx); + } + M_DPRINTK("changed value, is_unmuted = %d\n", IS_UNMUTED(muteBitIndx, val)); + count++; + } + if (count) { + omap_tsc2101_audio_write(page2regIndx, val); + } + return count; +} + /* * Converts the DGC registry value read from the TSC2101 registry to * Alsa mixer volume format (0 - 100). @@ -271,14 +312,11 @@ int set_mixer_volume_as_headset_gain_control_volume(int mixerVol) /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */ /* NOTE: 0 is minimum volume and not mute */ volume = get_mixer_volume_as_headset_gain_control_volume(mixerVol); - val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_HEADSET_GAIN_CTRL); + val = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL); /* preserve the old mute settings */ val &= ~(HGC_ADPGA_HED(INPUT_VOLUME_MAX)); val |= HGC_ADPGA_HED(volume); - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_HEADSET_GAIN_CTRL, - val); + omap_tsc2101_audio_write(TSC2101_HEADSET_GAIN_CTRL, val); retVal = 1; M_DPRINTK("to registry = %d\n", val); @@ -305,71 +343,37 @@ int set_mixer_volume_as_handset_gain_control_volume(int mixerVol) * NOTE: 0 is minimum volume and not mute */ volume = get_mixer_volume_as_headset_gain_control_volume(mixerVol); - val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HANDSET_GAIN_CTRL); + val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL); /* preserve the old mute settigns */ val &= ~(HNGC_ADPGA_HND(INPUT_VOLUME_MAX)); val |= HNGC_ADPGA_HND(volume); - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_HANDSET_GAIN_CTRL, - val); + omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val); retVal = 1; M_DPRINTK("to registry = %d\n", val); return retVal; } -void init_record_sources(void) -{ - /* Mute Analog Sidetone - * analog sidetone gain db? - * Cell Phone In not connected to ADC - * Input selected by MICSEL connected to ADC - */ - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_MIXER_PGA_CTRL, - MPC_ASTMU | MPC_ASTG(0x40) | ~MPC_CPADC | MPC_MICADC); - /* Set record source, Select MIC_INHED input for headset */ - set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED); -} - void set_loudspeaker_to_playback_target(void) { - u16 val; - - /* power down sp1, sp2 and loudspeaker */ - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_CODEC_POWER_CTRL, + /* power down SPK1, SPK2 and loudspeaker */ + omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL, CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF); /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled * 1dB AGC hysteresis * MICes bias 2V */ - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_AUDIO_CTRL_4, - AC4_MB_HED(0)); + omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0)); /* DAC left and right routed to SPK1/SPK2 * SPK1/SPK2 unmuted - * keyclicks routed to SPK1/SPK2 - */ - val = AC5_DIFFIN | + * Keyclicks routed to SPK1/SPK2 */ + omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5, + AC5_DIFFIN | AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 | - AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 | - AC5_HDSCPTC; - val = val & ~AC5_HDSCPTC; - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_AUDIO_CTRL_5, - val); + AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2); - /* powerdown spk1/out32n and spk2 */ - val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_POWERDOWN_STS); - val = val & ~(~PS_SPK1FL | ~PS_HNDFL | PS_LSPKFL); - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_POWERDOWN_STS, - val); - - /* routing selected to SPK1 goes to OUT8P/OUT84 alsa. (loudspeaker) + /* routing selected to SPK1 goes also to OUT8P/OUT8N. (loudspeaker) * analog sidetone routed to loudspeaker * buzzer pga routed to loudspeaker * keyclick routing to loudspeaker @@ -381,43 +385,242 @@ void set_loudspeaker_to_playback_target(void) * Enable loudspeaker short protection control (0 = enable protection) * VGND short protection control (0 = enable protection) */ - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_AUDIO_CTRL_6, + omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6, AC6_SPL2LSK | AC6_AST2LSK | AC6_BUZ2LSK | AC6_KCL2LSK | - AC6_CPI2LSK | AC6_MIC2CPO | AC6_SPL2CPO | - ~AC6_MUTLSPK | ~AC6_MUTSPK2 | ~AC6_LDSCPTC | ~AC6_VGNDSCPTC); + AC6_CPI2LSK | AC6_MIC2CPO | AC6_SPL2CPO); current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER; } void set_headphone_to_playback_target(void) { - /* power down sp1, sp2 and loudspeaker */ - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_CODEC_POWER_CTRL, + /* power down SPK1, SPK2 and loudspeaker */ + omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL, CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF); /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */ /* 1dB AGC hysteresis */ /* MICes bias 2V */ - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_AUDIO_CTRL_4, - AC4_MB_HED(0)); - - /* DAC left and right routed to SPK2 */ - /* SPK1/2 unmuted */ - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_AUDIO_CTRL_5, + omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0)); + + /* DAC left and right routed to SPK1/SPK2 + * SPK1/SPK2 unmuted + * Keyclicks routed to SPK1/SPK2 */ + omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5, AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 | AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 | AC5_HDSCPTC); - - /* OUT8P/N muted, CPOUT muted */ - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_AUDIO_CTRL_6, + + /* OUT8P/OUT8N muted, CPOUT muted */ + omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6, AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC | AC6_VGNDSCPTC); current_playback_target = PLAYBACK_TARGET_HEADPHONE; } +void set_telephone_to_playback_target(void) +{ + /* + * 0110 1101 0101 1100 + * power down MICBIAS_HED, Analog sidetone, SPK2, DAC, + * Driver virtual ground, loudspeaker. Values D2-d5 are flags. + */ + omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL, + CPC_MBIAS_HED | CPC_ASTPWD | CPC_SP2PWDN | CPC_DAPWDN | + CPC_VGPWDN | CPC_LSPWDN); + + /* + * 0010 1010 0100 0000 + * ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled + * 1dB AGC hysteresis + * MICes bias 2V + */ + omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, + AC4_MB_HND | AC4_MB_HED(0) | AC4_AGCHYS(1) | + AC4_BISTPD | AC4_ASSTPD | AC4_DASTPD); + printk("set_telephone_to_playback_target(), TSC2101_AUDIO_CTRL_4 = %d\n", omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4)); + + /* + * 1110 0010 0000 0010 + * DAC left and right routed to SPK1/SPK2 + * SPK1/SPK2 unmuted + * keyclicks routed to SPK1/SPK2 + */ + omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5, + AC5_DIFFIN | AC5_DAC2SPK1(3) | + AC5_CPI2SPK1 | AC5_MUTSPK2); + + omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6, + AC6_MIC2CPO | AC6_MUTLSPK | + AC6_LDSCPTC | AC6_VGNDSCPTC | AC6_CAPINTF); + current_playback_target = PLAYBACK_TARGET_CELLPHONE; +} + +/* + * 1100 0101 1101 0000 + * + * #define MPC_ASTMU TSC2101_BIT(15) + * #define MPC_ASTG(ARG) (((ARG) & 0x7F) << 8) + * #define MPC_MICSEL(ARG) (((ARG) & 0x07) << 5) + * #define MPC_MICADC TSC2101_BIT(4) + * #define MPC_CPADC TSC2101_BIT(3) + * #define MPC_ASTGF (0x01) + */ +static void set_telephone_to_record_source(void) +{ + u16 val; + + /* + * D0 = 0: + * --> AGC is off for handset input. + * --> ADC PGA is controlled by the ADMUT_HDN + ADPGA_HND + * (D15, D14-D8) + * D4 - D1 = 0000 + * --> AGC time constant for handset input, + * attack time = 8 mc, decay time = 100 ms + * D7 - D5 = 000 + * --> AGC Target gain for handset input = -5.5 db + * D14 - D8 = 011 1100 + * --> ADC handset PGA settings = 60 = 30 db + * D15 = 0 + * --> Handset input ON (unmuted) + */ + val = 0x3c00; // 0011 1100 0000 0000 = 60 = 30 + omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val); + + /* + * D0 = 0 + * --> AGC is off for headset/Aux input + * --> ADC headset/Aux PGA is contoller by ADMUT_HED + ADPGA_HED + * (D15, D14-D8) + * D4 - D1 = 0000 + * --> Agc constant for headset/Aux input, + * attack time = 8 mc, decay time = 100 ms + * D7 - D5 = 000 + * --> AGC target gain for headset input = -5.5 db + * D14 - D8 = 000 0000 + * --> Adc headset/AUX pga settings = 0 db + * D15 = 1 + * --> Headset/AUX input muted + * + * Mute headset aux input + */ + val = 0x8000; // 1000 0000 0000 0000 + omap_tsc2101_audio_write(TSC2101_HEADSET_GAIN_CTRL, val); + set_record_source(REC_SRC_MICIN_HND_AND_AUX1); + + // hacks start + /* D0 = flag, Headset/Aux or handset PGA flag + * --> & with 1 (= 1 -->gain applied == pga register settings) + * D1 = 0, DAC channel PGA soft stepping control + * --> 0.5 db change every WCLK + * D2 = flag, DAC right channel PGA flag + * --> & with 1 + * D3 = flag, DAC left channel PGA flag + * -- > & with 1 + * D7 - D4 = 0001, keyclick length + * --> 4 periods key clicks + * D10 - D8 = 100, keyclick frequenzy + * --> 1 kHz, + * D11 = 0, Headset/Aux or handset soft stepping control + * --> 0,5 db change every WCLK or ADWS + * D14 -D12 = 100, Keyclick applitude control + * --> Medium amplitude + * D15 = 0, keyclick disabled + */ + val = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_2); + val = val & 0x441d; + val = val | 0x4410; // D14, D10, D4 bits == 1 + omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_2, val); + + /* + * D0 = 0 (reserved, write always 0) + * D1 = flag, + * --> & with 1 + * D2 - D5 = 0000 (reserved, write always 0000) + * D6 = 1 + * --> MICBIAS_HND = 2.0 v + * D8 - D7 = 00 + * --> MICBIAS_HED = 3.3 v + * D10 - D9 = 01, + * --> Mic AGC hysteric selection = 2 db + * D11 = 1, + * --> Disable buzzer PGA soft stepping + * D12 = 0, + * --> Enable CELL phone PGA soft stepping control + * D13 = 1 + * --> Disable analog sidetone soft stepping control + * D14 = 0 + * --> Enable DAC PGA soft stepping control + * D15 = 0, + * --> Enable headset/Aux or Handset soft stepping control + */ + val = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4); + val = val & 0x2a42; // 0010 1010 0100 0010 + val = val | 0x2a40; // bits D13, D11, D9, D6 == 1 + omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, val); + printk("set_telephone_to_record_source(), TSC2101_AUDIO_CTRL_4 = %d\n", omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4)); + /* + * D0 = 0 + * --> reserved, write always = 0 + * D1 = flag, read only + * --> & with 1 + * D5 - D2 = 1111, Buzzer input PGA settings + * --> 0 db + * D6 = 1, + * --> power down buzzer input pga + * D7 = flag, read only + * --> & with 1 + * D14 - D8 = 101 1101 + * --> 12 DB + * D15 = 0 + * --> power up cell phone input PGA + */ + val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL); + val = val & 0x5dfe; + val = val | 0x5dfe; // bits, D14, D12, D11, D10, D8, D6, D5,D4,D3,D2 + omap_tsc2101_audio_write(TSC2101_BUZZER_GAIN_CTRL, val); + + /* D6 - D0 = 000 1001 + * --> -4.5 db for DAC right channel volume control + * D7 = 1 + * --> DAC right channel muted + * D14 - D8 = 000 1001 + * --> -4.5 db for DAC left channel volume control + * D15 = 1 + * --> DAC left channel muted + */ + //val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL); + val = 0x8989; + omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val); + + /* 0000 0000 0100 0000 + * + * D1 - D0 = 0 + * --> GPIO 1 pin output is three stated + * D2 = 0 + * --> Disaple GPIO2 for CLKOUT mode + * D3 = 0 + * --> Disable GPUI1 for interrupt detection + * D4 = 0 + * --> Disable GPIO2 for headset detection interrupt + * D5 = reserved, always 0 + * D7 - D6 = 01 + * --> 8 ms clitch detection + * D8 = reserved, write only 0 + * D10 -D9 = 00 + * --> 16 ms de bouncing programmatitily + * for glitch detection during headset detection + * D11 = flag for button press + * D12 = flag for headset detection + * D14-D13 = 00 + * --> type of headset detected = 00 == no stereo headset deected + * D15 = 0 + * --> Disable headset detection + * + * */ + val = 0x40; + omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_7, val); +} + /* * Checks whether the headset is detected. * If headset is detected, the type is returned. Type can be @@ -433,8 +636,7 @@ u16 get_headset_detected(void) u16 curVal; curType = 0; /* not detected */ - curVal = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_AUDIO_CTRL_7); + curVal = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_7); curDetected = curVal & AC7_HDDETFL; if (curDetected) { printk("headset detected, checking type from %d \n", curVal); @@ -461,13 +663,10 @@ void init_playback_targets(void) * AGC enable for handset input * Handset input not muted */ - val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_HANDSET_GAIN_CTRL); + val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL); val = val | HNGC_AGCEN_HND; val = val & ~HNGC_ADMUT_HND; - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_HANDSET_GAIN_CTRL, - val); + omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val); /* mic input volume control * SET_MIC in the OSS driver @@ -479,7 +678,7 @@ void init_playback_targets(void) */ set_mixer_volume_as_dac_gain_control_volume(DEFAULT_OUTPUT_VOLUME, DEFAULT_OUTPUT_VOLUME); /* unmute */ - dac_gain_control_unmute_control(1, 1); + dac_gain_control_unmute(1, 1); } /* @@ -490,11 +689,11 @@ void snd_omap_init_mixer(void) FN_IN; /* Headset/Hook switch detect enabled */ - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_AUDIO_CTRL_7, - AC7_DETECT); + omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_7, AC7_DETECT); - init_record_sources(); + /* Select headset to record source (MIC_INHED)*/ + set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED); + /* Init loudspeaker as a default playback target*/ init_playback_targets(); FN_OUT(0); @@ -503,7 +702,7 @@ void snd_omap_init_mixer(void) static int __pcm_playback_target_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { static char *texts[PLAYBACK_TARGET_COUNT] = { - "Loudspeaker", "Headphone" + "Loudspeaker", "Headphone", "Cellphone" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; @@ -533,12 +732,18 @@ static int __pcm_playback_target_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_valu if ((curVal >= 0) && (curVal < PLAYBACK_TARGET_COUNT) && (curVal != current_playback_target)) { - if (curVal == 0) { - set_loudspeaker_to_playback_target(); + if (curVal == PLAYBACK_TARGET_LOUDSPEAKER) { + set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED); + set_loudspeaker_to_playback_target(); } - else { + else if (curVal == PLAYBACK_TARGET_HEADPHONE) { + set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HND); set_headphone_to_playback_target(); } + else if (curVal == PLAYBACK_TARGET_CELLPHONE) { + set_telephone_to_record_source(); + set_telephone_to_playback_target(); + } retVal = 1; } return retVal; @@ -563,7 +768,7 @@ static int __pcm_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_valu u16 volR; u16 val; - val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL); + val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL); M_DPRINTK("registry value = %d!\n", val); volL = DGC_DALVL_EXTRACT(val); volR = DGC_DARVL_EXTRACT(val); @@ -603,16 +808,16 @@ static int __pcm_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_inf */ static int __pcm_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL); + u16 val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL); - ucontrol->value.integer.value[0] = IS_DGC_DALMU_UNMUTED(val); - ucontrol->value.integer.value[1] = IS_DGC_DARMU_UNMUTED(val); + ucontrol->value.integer.value[0] = IS_UNMUTED(15, val); // left + ucontrol->value.integer.value[1] = IS_UNMUTED(7, val); // right return 0; } static int __pcm_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - return dac_gain_control_unmute_control(ucontrol->value.integer.value[0], + return dac_gain_control_unmute(ucontrol->value.integer.value[0], ucontrol->value.integer.value[1]); } @@ -630,8 +835,7 @@ static int __headset_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_ u16 val; u16 vol; - val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_HEADSET_GAIN_CTRL); + val = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL); M_DPRINTK("registry value = %d\n", val); vol = HGC_ADPGA_HED_EXTRACT(val); vol = vol & ~HGC_ADMUT_HED; @@ -662,38 +866,17 @@ static int __headset_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem */ static int __headset_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_HEADSET_GAIN_CTRL); - ucontrol->value.integer.value[0] = IS_DGC_HGCMU_UNMUTED(val); + u16 val = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL); + ucontrol->value.integer.value[0] = IS_UNMUTED(15, val); return 0; } static int __headset_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - int count = 0; - u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_HEADSET_GAIN_CTRL); - /* in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on - * so if values are same, it's time to change the registry value... - */ - if (ucontrol->value.integer.value[0] == GET_DGC_HGCMU_BIT_VALUE(val)) { - if (ucontrol->value.integer.value[0] == 0) { - /* mute --> turn bit on */ - val = val | HGC_ADMUT_HED; - } - else { - /* unmute --> turn bit off */ - val = val & ~HGC_ADMUT_HED; - } - count++; - M_DPRINTK("changed value, is_unmuted = %d\n", IS_DGC_HGCMU_UNMUTED(val)); - } - if (count) { - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_HEADSET_GAIN_CTRL, - val); - } - return count; + // mute/unmute headset + return adc_pga_unmute_control(ucontrol->value.integer.value[0], + TSC2101_HEADSET_GAIN_CTRL, + 15); } static int __handset_playback_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) @@ -710,7 +893,7 @@ static int __handset_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_ u16 val; u16 vol; - val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HANDSET_GAIN_CTRL); + val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL); M_DPRINTK("registry value = %d\n", val); vol = HNGC_ADPGA_HND_EXTRACT(val); vol = vol & ~HNGC_ADMUT_HND; @@ -740,42 +923,74 @@ static int __handset_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem */ static int __handset_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HANDSET_GAIN_CTRL); - ucontrol->value.integer.value[0] = IS_DGC_HNGCMU_UNMUTED(val); + u16 val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL); + ucontrol->value.integer.value[0] = IS_UNMUTED(15, val); return 0; } static int __handset_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - int count = 0; - u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HANDSET_GAIN_CTRL); - - /* in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on - * so if values are same, it's time to change the registry value... - */ - if (ucontrol->value.integer.value[0] == GET_DGC_HNGCMU_BIT_VALUE(val)) { - if (ucontrol->value.integer.value[0] == 0) { - /* mute --> turn bit on */ - val = val | HNGC_ADMUT_HND; - } - else { - /* unmute --> turn bit off */ - val = val & ~HNGC_ADMUT_HND; - } - M_DPRINTK("changed value, is_unmuted = %d\n", IS_DGC_HNGCMU_UNMUTED(val)); - count++; - } - if (count) { - omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, - TSC2101_HANDSET_GAIN_CTRL, - val); - } - return count; + // handset mute/unmute + return adc_pga_unmute_control(ucontrol->value.integer.value[0], + TSC2101_HANDSET_GAIN_CTRL, + 15); +} + +static int __cellphone_input_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +/* When BGC_MUT_CP (bit 15) = 1, power down cellphone input pga. + * When BGC_MUT_CP = 0, power up cellphone input pga. + */ +static int __cellphone_input_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + u16 val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL); + ucontrol->value.integer.value[0] = IS_UNMUTED(15, val); + return 0; +} + +static int __cellphone_input_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + return adc_pga_unmute_control(ucontrol->value.integer.value[0], + TSC2101_BUZZER_GAIN_CTRL, + 15); +} + +static int __buzzer_input_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +/* When BGC_MUT_BU (bit 6) = 1, power down cellphone input pga. + * When BGC_MUT_BU = 0, power up cellphone input pga. + */ +static int __buzzer_input_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + u16 val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL); + ucontrol->value.integer.value[0] = IS_UNMUTED(6, val); + return 0; +} + +static int __buzzer_input_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + return adc_pga_unmute_control(ucontrol->value.integer.value[0], + TSC2101_BUZZER_GAIN_CTRL, + 6); } static snd_kcontrol_new_t tsc2101_control[] __devinitdata = { { - .name = "Playback Playback Route", + .name = "Target Playback Route", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .index = 0, .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -801,7 +1016,7 @@ static snd_kcontrol_new_t tsc2101_control[] __devinitdata = { }, { .name = "Headset Playback Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .index = 1, + .index = 0, .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = __headset_playback_volume_info, .get = __headset_playback_volume_get, @@ -809,7 +1024,7 @@ static snd_kcontrol_new_t tsc2101_control[] __devinitdata = { }, { .name = "Headset Playback Switch", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .index = 1, + .index = 0, .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = __headset_playback_switch_info, .get = __headset_playback_switch_get, @@ -817,7 +1032,7 @@ static snd_kcontrol_new_t tsc2101_control[] __devinitdata = { }, { .name = "Handset Playback Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .index = 2, + .index = 0, .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = __handset_playback_volume_info, .get = __handset_playback_volume_get, @@ -825,12 +1040,28 @@ static snd_kcontrol_new_t tsc2101_control[] __devinitdata = { }, { .name = "Handset Playback Switch", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .index = 2, + .index = 0, .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = __handset_playback_switch_info, .get = __handset_playback_switch_get, .put = __handset_playback_switch_put, - } + }, { + .name = "Cellphone Input Switch", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .index = 0, + .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = __cellphone_input_switch_info, + .get = __cellphone_input_switch_get, + .put = __cellphone_input_switch_put, + }, { + .name = "Buzzer Input Switch", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .index = 0, + .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = __buzzer_input_switch_info, + .get = __buzzer_input_switch_get, + .put = __buzzer_input_switch_put, + } }; #ifdef CONFIG_PM diff --git a/sound/arm/omap/omap-alsa-tsc2101-mixer.h b/sound/arm/omap/omap-alsa-tsc2101-mixer.h index f68f33dd864..3f27e27df6e 100644 --- a/sound/arm/omap/omap-alsa-tsc2101-mixer.h +++ b/sound/arm/omap/omap-alsa-tsc2101-mixer.h @@ -56,20 +56,21 @@ #define INPUT_VOLUME_MAX 0x7D #define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN) -#define PLAYBACK_TARGET_COUNT 0x02 +#define PLAYBACK_TARGET_COUNT 0x03 #define PLAYBACK_TARGET_LOUDSPEAKER 0x00 #define PLAYBACK_TARGET_HEADPHONE 0x01 +#define PLAYBACK_TARGET_CELLPHONE 0x02 /* following are used for register 03h Mixer PGA control bits D7-D5 for selecting record source */ #define REC_SRC_TARGET_COUNT 0x08 -#define REC_SRC_SINGLE_ENDED_MICIN_HED MPC_MICSEL(0) // oss code referred to MIXER_LINE -#define REC_SRC_SINGLE_ENDED_MICIN_HND MPC_MICSEL(1) // oss code referred to MIXER_MIC -#define REC_SRC_SINGLE_ENDED_AUX1 MPC_MICSEL(2) -#define REC_SRC_SINGLE_ENDED_AUX2 MPC_MICSEL(3) -#define REC_SRC_MICIN_HED_AND_AUX1 MPC_MICSEL(4) -#define REC_SRC_MICIN_HED_AND_AUX2 MPC_MICSEL(5) -#define REC_SRC_MICIN_HND_AND_AUX1 MPC_MICSEL(6) -#define REC_SRC_MICIN_HND_AND_AUX2 MPC_MICSEL(7) +#define REC_SRC_SINGLE_ENDED_MICIN_HED 0x00 // oss code referred to MIXER_LINE +#define REC_SRC_SINGLE_ENDED_MICIN_HND 0x01 // oss code referred to MIXER_MIC +#define REC_SRC_SINGLE_ENDED_AUX1 0x02 +#define REC_SRC_SINGLE_ENDED_AUX2 0x03 +#define REC_SRC_MICIN_HED_AND_AUX1 0x04 +#define REC_SRC_MICIN_HED_AND_AUX2 0x05 +#define REC_SRC_MICIN_HND_AND_AUX1 0x06 +#define REC_SRC_MICIN_HND_AND_AUX2 0x07 #define DEFAULT_OUTPUT_VOLUME 90 // default output volume to dac dgc #define DEFAULT_INPUT_VOLUME 20 // default record volume diff --git a/sound/arm/omap/omap-alsa-tsc2101.c b/sound/arm/omap/omap-alsa-tsc2101.c index a0096cb62fc..14afcc6550f 100644 --- a/sound/arm/omap/omap-alsa-tsc2101.c +++ b/sound/arm/omap/omap-alsa-tsc2101.c @@ -96,7 +96,11 @@ static const struct tsc2101_samplerate_reg_info static snd_pcm_hardware_t tsc2101_snd_omap_alsa_playback = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), - .formats = (SNDRV_PCM_FMTBIT_S16_LE), +#ifdef CONFIG_MACH_OMAP_H6300 + .formats = (SNDRV_PCM_FMTBIT_S8), +#else + .formats = (SNDRV_PCM_FMTBIT_S16_LE), +#endif .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | @@ -136,7 +140,7 @@ static snd_pcm_hardware_t tsc2101_snd_omap_alsa_capture = { }; /* - * Simplified write for tsc Audio + * Simplified write for tsc2101 audio registers. */ inline void tsc2101_audio_write(u8 address, u16 data) { @@ -144,7 +148,7 @@ inline void tsc2101_audio_write(u8 address, u16 data) } /* - * Simplified read for tsc Audio + * Simplified read for tsc2101 audio registers. */ inline u16 tsc2101_audio_read(u8 address) { @@ -246,14 +250,17 @@ void tsc2101_set_samplerate(long sample_rate) #endif /* #ifdef TSC_MASTER */ tsc2101_audio_write(TSC2101_AUDIO_CTRL_3, data); - /* program the PLLs */ + /* Program the PLLs. This code assumes that the 12 Mhz MCLK is in use. + * If MCLK rate is something else, these values must be changed. + * See the tsc2101 specification for the details. + */ if (rate_reg_info[count].fs_44kHz) { - /* 44.1 khz - 12 MHz Mclk */ + /* samplerate = (44.1kHZ / x), where x is int. */ tsc2101_audio_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(7)); /* PVAL 1; I_VAL 7 */ tsc2101_audio_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490)); /* D_VAL 5264 */ } else { - /* 48 khz - 12 Mhz Mclk */ + /* samplerate = (48.kHZ / x), where x is int. */ tsc2101_audio_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(8)); /* PVAL 1; I_VAL 8 */ tsc2101_audio_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780)); /* D_VAL 1920 */ @@ -317,21 +324,14 @@ int tsc2101_clock_on(void) CODEC_CLOCK); } curRate = (uint)clk_get_rate(tsc2101_mclk); - DPRINTK("old clock rate = %d\n", curRate); if (curRate != CODEC_CLOCK) { err = clk_set_rate(tsc2101_mclk, CODEC_CLOCK); if (err) { printk(KERN_WARNING "Cannot set MCLK clock rate for TSC2101 CODEC, error code = %d\n", err); - //return -ECANCELED; + return -ECANCELED; } } - else - { - printk(KERN_INFO - "omap_alsa_tsc2101_clock_on(), no need to change rate, no need to change clock rate, rate already %d Hz.\n", - CODEC_CLOCK); - } err = clk_enable(tsc2101_mclk); curRate = (uint)clk_get_rate(tsc2101_mclk); curUseCount = clk_get_usecount(tsc2101_mclk); @@ -349,8 +349,7 @@ int tsc2101_clock_on(void) } /* - * Do some sanity check, turn clock off and then turn - * codec audio off + * Do some sanity check, turn clock off and then turn codec audio off */ int tsc2101_clock_off(void) { @@ -374,10 +373,6 @@ int tsc2101_clock_off(void) tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL, ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC)); DPRINTK("audio codec off\n"); -#ifdef DUMP_TSC2101_AUDIO_REGISTERS - printk("tsc2101_clock_off()\n"); - dump_tsc2101_audio_reg(); -#endif return 0; } @@ -420,18 +415,22 @@ static struct platform_driver omap_alsa_driver = { }; static int __init omap_alsa_tsc2101_init(void) -{ - int err; - +{ ADEBUG(); - err = platform_driver_register(&omap_alsa_driver); - - return err; +#ifdef DUMP_TSC2101_AUDIO_REGISTERS + printk("omap_alsa_tsc2101_init()\n"); + dump_tsc2101_audio_reg(); +#endif + return platform_driver_register(&omap_alsa_driver); } static void __exit omap_alsa_tsc2101_exit(void) { ADEBUG(); +#ifdef DUMP_TSC2101_AUDIO_REGISTERS + printk("omap_alsa_tsc2101_exit()\n"); + dump_tsc2101_audio_reg(); +#endif platform_driver_unregister(&omap_alsa_driver); } diff --git a/sound/arm/omap/omap-alsa.c b/sound/arm/omap/omap-alsa.c index 328003be2bc..5a68471efdd 100644 --- a/sound/arm/omap/omap-alsa.c +++ b/sound/arm/omap/omap-alsa.c @@ -190,7 +190,7 @@ static void audio_process_dma(struct audio_stream *s) unsigned int dma_size; unsigned int offset; int ret; -#ifdef CONFIG_MACH_OMAP_H6300 +#ifdef CONFIG_ARCH_OMAP15XX unsigned long flags; #endif @@ -200,7 +200,13 @@ static void audio_process_dma(struct audio_stream *s) dma_size = frames_to_bytes(runtime, runtime->period_size); offset = dma_size * s->period; snd_assert(dma_size <= DMA_BUF_SIZE,); -#ifdef CONFIG_MACH_OMAP_H6300 +#ifdef CONFIG_ARCH_OMAP15XX + /* + * On omap1510 based devices, we need to call the stop_dma + * before calling the start_dma or we will not receive the + * irq from DMA after the first transfered/played buffer. + * (invocation of callback_omap_alsa_sound_dma() method). + */ spin_lock_irqsave(&s->dma_lock, flags); omap_stop_alsa_sound_dma(s); spin_unlock_irqrestore(&s->dma_lock, flags); diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index 448f50f54e7..74cbb833a0c 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -13,8 +13,8 @@ config SOUND_OMAP config SOUND_OMAP_TSC2101 tristate "TSC2101 Stereo Codec" - depends on SOUND_OMAP && ( MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4 || MACH_OMAP_APOLLON) - select OMAP_TSC2101 if ( MACH_OMAP_H2 || MACH_OMAP_H3 ) + depends on SOUND_OMAP && ( MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4 || MACH_OMAP_APOLLON || MACH_OMAP_H6300) + select OMAP_TSC2101 if ( MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H6300 ) select OMAP_UWIRE if ARCH_OMAP1 ---help--- Tsc2101 Audio Codec Driver for OMAP will be enabled. diff --git a/sound/oss/omap-audio-tsc2101.c b/sound/oss/omap-audio-tsc2101.c index f8e6dacf1ff..55d131a832d 100644 --- a/sound/oss/omap-audio-tsc2101.c +++ b/sound/oss/omap-audio-tsc2101.c @@ -48,7 +48,7 @@ #include "omap-audio.h" #include "omap-audio-dma-intfc.h" #include -#ifdef CONFIG_ARCH_OMAP16XX +#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_MACH_OMAP_H6300) #include <../drivers/ssi/omap-uwire.h> #include #elif defined(CONFIG_ARCH_OMAP24XX) @@ -73,10 +73,16 @@ #ifdef CONFIG_ARCH_OMAP16XX #define PLATFORM_NAME "OMAP16XX" +#elif CONFIG_MACH_OMAP_H6300 +#define PLATFORM_NAME "OMAP15XX" #elif defined(CONFIG_ARCH_OMAP24XX) #define PLATFORM_NAME "OMAP2" #endif +#if CONFIG_ARCH_OMAP16XX +#define OMAP_DSP_BASE 0xE0000000 +#endif + /* Define to set the tsc as the master w.r.t McBSP */ #define TSC_MASTER @@ -123,7 +129,7 @@ /*********** Debug Macros ********/ /* To Generate a rather shrill tone -test the entire path */ //#define TONE_GEN -/* To Generate a tone for each keyclick - test the tsc,spi paths*/ +///* To Generate a tone for each keyclick - test the tsc,spi paths*/ //#define TEST_KEYCLICK /* To dump the tsc registers for debug */ //#define TSC_DUMP_REGISTERS @@ -230,6 +236,17 @@ static const struct sample_rate_reg_info }; static struct omap_mcbsp_reg_cfg initial_config = { +#ifdef CONFIG_MACH_OMAP_H6300 + .spcr2 = 0x0005, + .spcr1 = 0x0005, + .rcr2 = 0x8041, + .rcr1 = 0x8041, + .xcr2 = 0x00a1, + .xcr1 = 0x00a1, + .srgr2 = 0xb000, + .srgr1 = 0xb000, + .pcr0 = 0x0081, +#else .spcr2 = FREE | FRST | GRST | XRST | XINTM(3), .spcr1 = RINTM(3) | RRST, .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) | @@ -253,6 +270,7 @@ static struct omap_mcbsp_reg_cfg initial_config = { #endif /* tsc Master defs */ #endif /* platform specific inits */ +#endif /* CONFIG_MACH_OMAP_H6300 */ }; /***************************** MODULES SPECIFIC FUNCTION PROTOTYPES ********************/