diff options
Diffstat (limited to 'sound')
42 files changed, 30946 insertions, 3 deletions
diff --git a/sound/Kconfig b/sound/Kconfig index 1fef141ef8e..35bb190ed54 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -23,6 +23,66 @@ menuconfig SOUND and read <file:Documentation/sound/oss/README.modules>; the module will be called soundcore. +# added for U8500 audio codec device +config U8500_ACODEC + tristate "U8500 audio codec generic module (used both by SAA and ALSA)" + depends on STM_MSP_I2S + default Y + help + Say Y here if you have a U8500 based device + and want to use its audio codec chip. + + To compile this driver as a module, choose M here: the module + will be called u8500mod_acodec. + +choice + prompt "Audio codec type" + depends on U8500_ACODEC + default U8500_AB8500_ED + + config U8500_AB8500_ED + bool "U8500 ab8500 v0 audio codec" + + config U8500_AB8500_CUT10 + bool "U8500 ab8500 v1.x audio codec" + +endchoice + +menu "Debug level for ux500 audio drivers" +config STM_ACODEC_DEBUG + int "STM ACODEC Debug Level" + depends on U8500_ACODEC + default 0 + help + Sets the ACODEC debug ON/OFF for U8500 SoC + * 0 OFF + * 1 ON + +config STM_ALSA_DEBUG + int "STM ALSA Debug Level" + depends on SND_U8500_ALSA || SND_U8500_ALSA_AB8500 + default 0 + help + Sets the ALSA debug ON/OFF for U8500 SoC + * 0 OFF + * 1 ON +endmenu + +choice + prompt "Driver mode" + depends on U8500_ACODEC + default U8500_ACODEC_DMA + + config U8500_ACODEC_DMA + bool "DMA mode" + + config U8500_ACODEC_POLL + bool "Polling mode" + + config U8500_ACODEC_INTR + bool "Interrupt mode" +endchoice + if SOUND config SOUND_OSS_CORE diff --git a/sound/Makefile b/sound/Makefile index ce9132b1c39..b5963c8b70d 100644 --- a/sound/Makefile +++ b/sound/Makefile @@ -16,4 +16,11 @@ ifeq ($(CONFIG_SND),y) obj-y += last.o endif +obj-$(CONFIG_U8500_ACODEC) += u8500mod_acodec.o +ifeq ($(CONFIG_U8500_AB8500_CUT10),y) + u8500mod_acodec-objs := u8500_acodec_ab8500.o ab8500_codec_v1_0.o +else + u8500mod_acodec-objs := u8500_acodec_ab8500.o ab8500_codec.o +endif + soundcore-objs := sound_core.o diff --git a/sound/ab8500_codec.c b/sound/ab8500_codec.c new file mode 100644 index 00000000000..fd4975bbdce --- /dev/null +++ b/sound/ab8500_codec.c @@ -0,0 +1,6697 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: ST-Ericsson + * + * License terms: + * + * 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. + */ + + /*---------------------------------------------------------------------------- + * Includes + *---------------------------------------------------------------------------*/ +#include <mach/ab8500_codec.h> +#include <mach/ab8500_codec_p.h> + +/*--------------------------------------------------------------------------* + * debug stuff * + *--------------------------------------------------------------------------*/ +#ifdef __DEBUG +#define MY_DEBUG_LEVEL_VAR_NAME myDebugLevel_AB8500_CODEC +#define MY_DEBUG_ID myDebugID_AB8500_CODEC +PRIVATE t_dbg_level MY_DEBUG_LEVEL_VAR_NAME = DEBUG_LEVEL0; +PRIVATE t_dbg_id MY_DEBUG_ID = AB8500_CODEC_HCL_DBG_ID; +#endif + +/*--------------------------------------------------------------------------* + * Global data for interrupt mode management * + *--------------------------------------------------------------------------*/ +PRIVATE t_ab8500_codec_system_context g_ab8500_codec_system_context; + +/*--------------------------------------------------------------------------* + * Default Values * + *--------------------------------------------------------------------------*/ +#define AB8500_CODEC_DEFAULT_SLAVE_ADDRESS_OF_CODEC 0xD +#define AB8500_CODEC_DEFAULT_DIRECTION AB8500_CODEC_DIRECTION_OUT + +#define AB8500_CODEC_DEFAULT_MODE_IN AB8500_CODEC_MODE_VOICE +#define AB8500_CODEC_DEFAULT_MODE_OUT AB8500_CODEC_MODE_VOICE + +#define AB8500_CODEC_DEFAULT_INPUT_SRC AB8500_CODEC_SRC_MICROPHONE_1A +#define AB8500_CODEC_DEFAULT_OUTPUT_DEST AB8500_CODEC_DEST_HEADSET + +#define AB8500_CODEC_DEFAULT_VOLUME_LEFT_IN 75 +#define AB8500_CODEC_DEFAULT_VOLUME_RIGHT_IN 75 +#define AB8500_CODEC_DEFAULT_VOLUME_LEFT_OUT 75 +#define AB8500_CODEC_DEFAULT_VOLUME_RIGHT_OUT 75 + +/*--------------------------------------------------------------------- + * PRIVATE APIs + *--------------------------------------------------------------------*/ +PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch1(IN + t_ab8500_codec_slot + ad_slot, + IN + t_ab8500_codec_cr31_to_cr46_ad_data_allocation + value); +PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch2(IN + t_ab8500_codec_slot + ad_slot, + IN + t_ab8500_codec_cr31_to_cr46_ad_data_allocation + value); +PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch3(IN + t_ab8500_codec_slot + ad_slot, + IN + t_ab8500_codec_cr31_to_cr46_ad_data_allocation + value); +PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch4(IN + t_ab8500_codec_slot + ad_slot, + IN + t_ab8500_codec_cr31_to_cr46_ad_data_allocation + value); +PRIVATE t_ab8500_codec_error ab8500_codec_SrcPowerControlSwitch1(IN + t_ab8500_codec_src + src_device, + t_ab8500_codec_src_state + state); +PRIVATE t_ab8500_codec_error ab8500_codec_SrcPowerControlSwitch2(IN + t_ab8500_codec_src + src_device, + t_ab8500_codec_src_state + state); +PRIVATE t_ab8500_codec_error ab8500_codec_SetModeAndDirectionUpdateCR(void); +PRIVATE t_ab8500_codec_error ab8500_codec_SetSrcVolumeUpdateCR(void); +PRIVATE t_ab8500_codec_error ab8500_codec_SetDestVolumeUpdateCR(void); +PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirectionIN(void); +PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirectionOUT(void); +PRIVATE t_ab8500_codec_error ab8500_codec_DestPowerControlUpdateCR(void); + +/********************************************************************************************/ +/* Name: ab8500_codec_SingleWrite */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_SingleWrite(t_uint8 register_offset, + t_uint8 data) +{ + return (t_ab8500_codec_error) (AB8500_CODEC_Write + (register_offset, 0x01, &data)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_SingleRead */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_SingleRead(t_uint8 register_offset, + t_uint8 data) +{ + t_uint8 dummy_data = 0xAA; + + return (t_ab8500_codec_error) (AB8500_CODEC_Read + (register_offset, 0x01, &dummy_data, + &data)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR0 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR0(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr0_powerup, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR0_POWERUP); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr0_enaana, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR0_ENAANA); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR0, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR1 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR1(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr1_swreset, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR1_SWRESET); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR1, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR2 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR2(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr2_enad1, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR2_ENAD1); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr2_enad2, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR2_ENAD2); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr2_enad3, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR2_ENAD3); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr2_enad4, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR2_ENAD4); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr2_enad5, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR2_ENAD5); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr2_enad6, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR2_ENAD6); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR2, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR3 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR3(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr3_enda1, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR3_ENDA1); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr3_enda2, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR3_ENDA2); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr3_enda3, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR3_ENDA3); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr3_enda4, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR3_ENDA4); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr3_enda5, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR3_ENDA5); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr3_enda6, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR3_ENDA6); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR3, value)); +} + +#if 0 + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR4 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR4(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr4_lowpowhs, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR4_LOWPOWHS); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr4_lowpowdachs, + AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR4_LOWPOWDACHS); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr4_lowpowear, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR4_LOWPOWEAR); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr4_ear_sel_cm, + AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR4_EAR_SEL_CM); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr4_hs_hp_dis, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR4_HS_HP_DIS); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr4_ear_hp_dis, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR4_EAR_HP_DIS); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR4, value)); +} +#endif + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR5 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR5(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr5_enmic1, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR5_ENMIC1); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr5_enmic2, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR5_ENMIC2); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr5_enlinl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR5_ENLINL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr5_enlinr, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR5_ENLINR); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr5_mutmic1, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR5_MUTMIC1); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr5_mutmic2, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR5_MUTMIC2); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr5_mutlinl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR5_MUTELINL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr5_mutlinr, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR5_MUTELINR); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR5, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR6 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR6(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr6_endmic1, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR6_ENDMIC1); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr6_endmic2, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR6_ENDMIC2); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr6_endmic3, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR6_ENDMIC3); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr6_endmic4, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR6_ENDMIC4); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr6_endmic5, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR6_ENDMIC5); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr6_endmic6, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR6_ENDMIC6); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR6, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR7 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR7(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr7_mic1sel, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR7_MIC1SEL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr7_linrsel, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR7_LINRSEL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr7_endrvhsl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR7_ENDRVHSL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr7_endrvhsr, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR7_ENDRVHSR); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr7_enadcmic, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR7_ENADCMIC); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr7_enadclinl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR7_ENADCLINL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr7_enadclinr, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR7_ENADCLINR); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR7, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR8 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR8(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr8_cp_dis_pldwn, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR8_CP_DIS_PLDWN); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr8_enear, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR8_ENEAR); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr8_enhsl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR8_ENHSL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr8_enhsr, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR8_ENHSR); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr8_enhfl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR8_ENHFL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr8_enhfr, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR8_ENHFR); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr8_envibl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR8_ENVIBL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr8_envibr, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR8_ENVIBR); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR8, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR9 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR9(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr9_endacear, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR9_ENADACEAR); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr9_endachsl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR9_ENADACHSL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr9_endachsr, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR9_ENADACHSR); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr9_endachfl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR9_ENADACHFL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr9_endachfr, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR9_ENADACHFR); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr9_endacvibl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR9_ENADACVIBL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr9_endacvibr, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR9_ENADACVIBR); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR9, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR10 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR10(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr10_muteear, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR10_MUTEEAR); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr10_mutehsl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR10_MUTEHSL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr10_mutehsr, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR10_MUTEHSR); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr10_mutehfl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR10_MUTEHFL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr10_mutehfr, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR10_MUTEHFR); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr10_mutevibl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR10_MUTEVIBL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr10_mutevibr, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR10_MUTEVIBR); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR10, value)); +} + +#if 0 + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR11 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR11(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr11_earshortpwd, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR11_ENSHORTPWD); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr11_earshortdis, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR11_EARSHORTDIS); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr11_hslshortdis, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR11_HSLSHORTDIS); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr11_hsrshortdis, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR11_HSRSHORTDIS); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr11_hflshortdis, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR11_HFLSHORTDIS); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr11_hfrshortdis, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR11_HFRSHORTDIS); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr11_viblshortdis, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR11_VIBLSHORTDIS); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr11_vibrshortdis, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR11_VIBRSHORTDIS); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR11, value)); +} + +#endif + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR12 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR12(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr12_encphs, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR12_ENCPHS); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr12_hsautotime, + AB8500_CODEC_MASK_THREE_BITS, AB8500_CODEC_CR12_HSAUTOTIME); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr12_hsautoensel, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR12_HSAUTOENSEL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr12_hsautoen, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR12_HSAUTOEN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR12, value)); +} + +#if 0 + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR13 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR13(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr13_envdet_hthresh, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR13_ENVDET_HTHRESH); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr13_envdet_lthresh, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR13_ENVDET_LTHRESH); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR13, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR14 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR14(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr14_smpslven, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR14_SMPSLVEN); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr14_envdetsmpsen, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR14_ENVDETSMPSEN); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr14_cplven, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR14_CPLVEN); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr14_envdetcpen, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR14_ENVDETCPEN); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr14_envet_time, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR14_ENVDET_TIME); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR14, value)); +} +#endif + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR15 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR15(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr15_pwmtovibl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR15_PWMTOVIBL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr15_pwmtovibr, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR15_PWMTOVIBR); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr15_pwmlctrl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR15_PWMLCTRL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr15_pwmrctrl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR15_PWMRCTRL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr15_pwmnlctrl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR15_PWMNLCTRL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr15_pwmplctrl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR15_PWMPLCTRL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr15_pwmnrctrl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR15_PWMNRCTRL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr15_pwmprctrl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR15_PWMPRCTRL); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR15, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR16 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR16(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr16_pwmnlpol, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR16_PWMNLPOL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr16_pwmnldutycycle, + AB8500_CODEC_MASK_SEVEN_BITS, AB8500_CODEC_CR16_PWMNLDUTYCYCLE); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR16, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR17 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR17(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr17_pwmplpol, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR17_PWMPLPOL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr17_pwmpldutycycle, + AB8500_CODEC_MASK_SEVEN_BITS, AB8500_CODEC_CR17_PWMLPDUTYCYCLE); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR17, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR18 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR18(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr18_pwmnrpol, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR18_PWMNRPOL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr18_pwmnrdutycycle, + AB8500_CODEC_MASK_SEVEN_BITS, AB8500_CODEC_CR18_PWMNRDUTYCYCLE); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR18, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR19 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR19(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr19_pwmprpol, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR19_PWMPRPOL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr19_pwmprdutycycle, + AB8500_CODEC_MASK_SEVEN_BITS, AB8500_CODEC_CR19_PWMRPDUTYCYCLE); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR19, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR20 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR20(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr20_en_se_mic1, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR20_EN_SE_MIC1); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr20_mic1_gain, + AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR20_MIC1_GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR20, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR21 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR21(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr21_en_se_mic2, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR21_EN_SE_MIC2); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr21_mic2_gain, + AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR21_MIC2_GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR21, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR22 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR22(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr22_hsl_gain, + AB8500_CODEC_MASK_THREE_BITS, AB8500_CODEC_CR22_HSL_GAIN); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr22_linl_gain, + AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR22_LINL_GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR22, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR23 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR23(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr23_hsr_gain, + AB8500_CODEC_MASK_THREE_BITS, AB8500_CODEC_CR23_HSR_GAIN); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr23_linr_gain, + AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR23_LINR_GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR23, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR24 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR24(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr24_lintohsl_gain, + AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR24_LINTOHSL_GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR24, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR25 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR25(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr25_lintohsr_gain, + AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR25_LINTOHSR_GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR25, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR26 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR26(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr26_ad1nh, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR26_AD1NH); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr26_ad2nh, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR26_AD2NH); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr26_ad3nh, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR26_AD3NH); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr26_ad4nh, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR26_AD4NH); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr26_ad1_voice, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR26_AD1_VOICE); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr26_ad2_voice, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR26_AD2_VOICE); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr26_ad3_voice, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR26_AD3_VOICE); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr26_ad4_voice, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR26_AD4_VOICE); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR26, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR27 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR27(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr27_en_mastgen, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR27_EN_MASTGEN); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr27_if1_bitclk_osr, + AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR27_IF1_BITCLK_OSR); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr27_enfs_bitclk1, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR27_ENFS_BITCLK1); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr27_if0_bitclk_osr, + AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR27_IF0_BITCLK_OSR); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr27_enfs_bitclk0, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR27_ENFS_BITCLK0); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR27, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR28 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR28(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr28_fsync0p, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR28_FSYNC0P); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr28_bitclk0p, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR28_BITCLK0P); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr28_if0del, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR28_IF0DEL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr28_if0format, + AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR28_IF0FORMAT); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr28_if0wl, + AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR28_IF0WL); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR28, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR29 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR29(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr29_if0datoif1ad, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR29_IF0DATOIF1AD); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr29_if0cktoif1ck, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR29_IF0CKTOIF1CK); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr29_if1master, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR29_IF1MASTER); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr29_if1datoif0ad, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR29_IF1DATOIF0AD); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr29_if1cktoif0ck, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR29_IF1CKTOIF0CK); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr29_if0master, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR29_IF0MASTER); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr29_if0bfifoen, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR29_IF0BFIFOEN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR29, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR30 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR30(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr30_fsync1p, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR30_FSYNC1P); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr30_bitclk1p, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR30_BITCLK1P); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr30_if1del, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR30_IF1DEL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr30_if1format, + AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR30_IF1FORMAT); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr30_if1wl, + AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR30_IF1WL); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR30, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR31 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR31(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr31_adotoslot1, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR31_ADOTOSLOT1); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr31_adotoslot0, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR31_ADOTOSLOT0); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR31, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR32 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR32(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr32_adotoslot3, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR32_ADOTOSLOT3); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr32_adotoslot2, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR32_ADOTOSLOT2); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR32, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR33 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR33(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr33_adotoslot5, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR33_ADOTOSLOT5); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr33_adotoslot4, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR33_ADOTOSLOT4); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR33, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR34 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR34(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr34_adotoslot7, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR34_ADOTOSLOT7); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr34_adotoslot6, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR34_ADOTOSLOT6); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR34, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR35 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR35(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr35_adotoslot9, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR35_ADOTOSLOT9); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr35_adotoslot8, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR35_ADOTOSLOT8); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR35, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR36 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR36(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr36_adotoslot11, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR36_ADOTOSLOT11); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr36_adotoslot10, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR36_ADOTOSLOT10); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR36, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR37 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR37(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr37_adotoslot13, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR37_ADOTOSLOT13); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr37_adotoslot12, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR37_ADOTOSLOT12); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR37, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR38 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR38(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr38_adotoslot15, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR38_ADOTOSLOT15); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr38_adotoslot14, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR38_ADOTOSLOT14); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR38, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR39 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR39(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr39_adotoslot17, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR39_ADOTOSLOT17); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr39_adotoslot16, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR39_ADOTOSLOT16); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR39, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR40 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR40(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr40_adotoslot19, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR40_ADOTOSLOT19); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr40_adotoslot18, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR40_ADOTOSLOT18); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR40, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR41 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR41(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr41_adotoslot21, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR41_ADOTOSLOT21); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr41_adotoslot20, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR41_ADOTOSLOT20); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR41, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR42 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR42(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr42_adotoslot23, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR42_ADOTOSLOT23); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr42_adotoslot22, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR42_ADOTOSLOT22); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR42, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR43 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR43(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr43_adotoslot25, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR43_ADOTOSLOT25); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr43_adotoslot24, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR43_ADOTOSLOT24); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR43, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR44 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR44(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr44_adotoslot27, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR44_ADOTOSLOT27); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr44_adotoslot26, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR44_ADOTOSLOT26); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR44, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR45 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR45(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr45_adotoslot29, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR45_ADOTOSLOT29); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr45_adotoslot28, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR45_ADOTOSLOT28); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR45, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR46 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR46(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr46_adotoslot31, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR46_ADOTOSLOT31); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr46_adotoslot30, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR46_ADOTOSLOT30); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR46, value)); +} + +#if 0 + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR47 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR47(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr47_hiz_sl7, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR47_HIZ_SL7); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr47_hiz_sl6, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR47_HIZ_SL6); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr47_hiz_sl5, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR47_HIZ_SL5); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr47_hiz_sl4, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR47_HIZ_SL4); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr47_hiz_sl3, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR47_HIZ_SL3); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr47_hiz_sl2, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR47_HIZ_SL2); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr47_hiz_sl1, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR47_HIZ_SL1); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr47_hiz_sl0, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR47_HIZ_SL0); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR47, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR48 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR48(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr48_hiz_sl15, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR48_HIZ_SL15); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr48_hiz_sl14, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR48_HIZ_SL14); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr48_hiz_sl13, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR48_HIZ_SL13); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr48_hiz_sl12, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR48_HIZ_SL12); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr48_hiz_sl11, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR48_HIZ_SL11); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr48_hiz_sl10, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR48_HIZ_SL10); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr48_hiz_sl9, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR48_HIZ_SL9); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr48_hiz_sl8, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR48_HIZ_SL8); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR48, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR49 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR49(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr49_hiz_sl23, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR49_HIZ_SL23); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr49_hiz_sl22, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR49_HIZ_SL22); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr49_hiz_sl21, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR49_HIZ_SL21); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr49_hiz_sl20, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR49_HIZ_SL20); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr49_hiz_sl19, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR49_HIZ_SL19); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr49_hiz_sl18, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR49_HIZ_SL18); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr49_hiz_sl17, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR49_HIZ_SL17); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr49_hiz_sl16, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR49_HIZ_SL16); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR49, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR50 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR50(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr50_hiz_sl31, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR50_HIZ_SL31); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr50_hiz_sl30, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR50_HIZ_SL30); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr50_hiz_sl29, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR50_HIZ_SL29); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr50_hiz_sl28, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR50_HIZ_SL28); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr50_hiz_sl27, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR50_HIZ_SL27); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr50_hiz_sl26, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR50_HIZ_SL26); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr50_hiz_sl25, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR50_HIZ_SL25); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr50_hiz_sl24, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR50_HIZ_SL24); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR50, value)); +} + +#endif + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR51 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR51(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr51_da12_voice, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR51_DA12_VOICE); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr51_sldai1toslado1, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR51_SLDAI1TOSLADO1); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr51_sltoda1, + AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR51_SLTODA1); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR51, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR52 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR52(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr52_sldai2toslado2, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR52_SLDAI1TOSLADO2); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr52_sltoda2, + AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR52_SLTODA2); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR52, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR53 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR53(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr53_da34_voice, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR53_DA34_VOICE); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr53_sldai3toslado3, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR53_SLDAI1TOSLADO3); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr53_sltoda3, + AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR53_SLTODA3); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR53, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR54 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR54(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr54_sldai4toslado4, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR54_SLDAI1TOSLADO4); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr54_sltoda4, + AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR54_SLTODA4); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR54, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR55 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR55(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr55_da56_voice, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR55_DA56_VOICE); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr55_sldai5toslado5, + AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR55_SLDAI1TOSLADO5); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr55_sltoda5, + AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR55_SLTODA5); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR55, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR56 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR56(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr56_sldai6toslado7, + AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR56_SLDAI1TOSLADO6); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr56_sltoda6, + AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR56_SLTODA6); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR56, value)); +} + +#if 0 + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR57 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR57(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr57_bfifull_msk, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR57_BFIFULL_MSK); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr57_bfiempt_msk, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR57_BFIEMPT_MSK); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr57_dachan_msk, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR57_DACHAN_MSK); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr57_gain_msk, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR57_GAIN_MSK); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr57_dspad_msk, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR57_DSPAD_MSK); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr57_dspda_msk, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR57_DSPDA_MSK); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr57_stfir_msk, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR57_STFIR_MSK); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR57, value)); +} + +/* CR58 is Read Only */ +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR59 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR59(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr59_vssready_msk, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR59_VSSREADY_MSK); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr59_shrtvibl_msk, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR59_SHRTVIBL_MSK); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr59_shrtvibr_msk, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR59_SHRTVIBR_MSK); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr59_shrthfl_msk, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR59_SHRTHFL_MSK); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr59_shrthfr_msk, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR59_SHRTHFR_MSK); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr59_shrthsl_msk, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR59_SHRTHSL_MSK); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr59_shrthsr_msk, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR59_SHRTHSR_MSK); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr59_shrtear_msk, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR59_SHRTEAR_MSK); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR59, value)); +} + +/* CR60 is Read Only */ +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR61 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR61(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + /* 5 bits are Read Only */ + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr61_fade_speed, + AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR61_FADE_SPEED); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR61, value)); +} +#endif +/* CR62 is Read Only */ +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR63 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR63(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr63_datohslen, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR63_DATOHSLEN); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr63_datohsren, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR63_DATOHSREN); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr63_ad1sel, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR63_AD1SEL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr63_ad2sel, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR63_AD2SEL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr63_ad3sel, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR63_AD3SEL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr63_ad5sel, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR63_AD5SEL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr63_ad6sel, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR63_AD6SEL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr63_ancsel, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR63_ANCSEL); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR63, value)); +} + +#if 0 +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR64 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR64(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr64_datohfren, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR64_DATOHFREN); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr64_datohflen, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR64_DATOHFLEN); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr64_hfrsel, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR64_HFRSEL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr64_hflsel, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR64_HFLSEL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr64_stfir1sel, + AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR64_STFIR1SEL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr64_stfir2sel, + AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR64_STFIR2SEL); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR64, value)); +} + +#endif + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR65 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR65(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr65_fadedis_ad1, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR65_FADEDIS_AD1); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr65_ad1gain, + AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR65_AD1GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR65, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR66 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR66(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr66_fadedis_ad2, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR66_FADEDIS_AD2); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr66_ad2gain, + AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR66_AD2GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR66, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR67 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR67(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr67_fadedis_ad3, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR67_FADEDIS_AD3); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr67_ad3gain, + AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR67_AD3GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR67, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR68 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR68(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr68_fadedis_ad4, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR68_FADEDIS_AD4); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr68_ad4gain, + AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR68_AD4GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR68, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR69 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR69(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr69_fadedis_ad5, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR69_FADEDIS_AD5); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr69_ad5gain, + AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR69_AD5GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR69, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR70 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR70(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr70_fadedis_ad6, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR70_FADEDIS_AD6); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr70_ad6gain, + AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR70_AD6GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR70, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR71 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR71(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr71_fadedis_da1, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR71_FADEDIS_DA1); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr71_da1gain, + AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR71_DA1GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR71, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR72 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR72(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr72_fadedis_da2, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR72_FADEDIS_DA2); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr72_da2gain, + AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR72_DA2GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR72, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR73 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR73(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr73_fadedis_da3, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR73_FADEDIS_DA3); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr73_da3gain, + AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR73_DA3GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR73, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR74 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR74(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr74_fadedis_da4, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR74_FADEDIS_DA4); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr74_da4gain, + AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR74_DA4GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR74, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR75 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR75(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr75_fadedis_da5, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR75_FADEDIS_DA5); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr75_da5gain, + AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR75_DA5GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR75, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR76 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR76(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr76_fadedis_da6, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR76_FADEDIS_DA6); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr76_da6gain, + AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR76_DA6GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR76, value)); +} + +#if 0 + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR77 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR77(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr77_fadedis_ad1l, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR77_FADEDIS_AD1L); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr77_ad1lbgain_to_hfl, + AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR77_AD1LBGAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR77, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR78 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR78(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr78_fadedis_ad2l, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR78_FADEDIS_AD2L); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr78_ad2lbgain_to_hfr, + AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR78_AD2LBGAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR78, value)); +} +#endif + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR79 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR79(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr79_hssinc1, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR79_HSSINC1); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr79_fadedis_hsl, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR79_FADEDIS_HSL); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr79_hsldgain, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR79_HSLDGAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR79, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR80 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR80(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr80_fadedis_hsr, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR80_FADEDIS_HSR); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr80_hsrdgain, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR80_HSRDGAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR80, value)); +} + +#if 0 + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR81 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR81(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr81_stfir1gain, + AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR81_STFIR1GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR81, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR82 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR82(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr82_stfir2gain, + AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR82_STFIR2GAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR82, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR83 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR83(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr83_enanc, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR83_ENANC); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr83_anciirinit, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR83_ANCIIRINIT); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr83_ancfirupdate, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR83_ANCFIRUPDATE); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR83, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR84 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR84(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr84_ancinshift, + AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR84_ANCINSHIFT); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR84, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR85 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR85(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr85_ancfiroutshift, + AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR85_ANCFIROUTSHIFT); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR85, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR86 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR86(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr86_ancshiftout, + AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR86_ANCSHIFTOUT); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR86, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR87 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR87(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr87_ancfircoeff_msb, + AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR87_ANCFIRCOEFF_MSB); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR87, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR88 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR88(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr88_ancfircoeff_lsb, + AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR88_ANCFIRCOEFF_LSB); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR88, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR89 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR89(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr89_anciircoeff_msb, + AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR89_ANCIIRCOEFF_MSB); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR89, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR90 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR90(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr90_anciircoeff_lsb, + AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR90_ANCIIRCOEFF_LSB); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR90, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR91 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR91(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr91_ancwarpdel_msb, + AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR91_ANCWARPDEL_MSB); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR91, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR92 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR92(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr92_ancwarpdel_lsb, + AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR92_ANCWARPDEL_LSB); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR92, value)); +} + +/* CR93 is Read Only */ +/* CR94 is Read Only */ +/* CR95 is Read Only */ +/* CR96 is Read Only */ +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR97 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR97(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr97_stfir_set, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR97_STFIR_SET); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr97_stfir_addr, + AB8500_CODEC_MASK_SEVEN_BITS, AB8500_CODEC_CR97_STFIR_ADDR); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR97, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR98 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR98(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr98_stfir_coeff_msb, + AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR98_STFIR_COEFF_MSB); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR98, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR99 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR99(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr99_stfir_coeff_lsb, + AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR99_STFIR_COEFF_LSB); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR99, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR100 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR100(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr100_enstfirs, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR100_ENSTFIRS); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr100_stfirstoif1, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR100_STFIRSTOIF1); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr100_stfir_busy, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR100_STFIR_BUSY); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR100, value)); +} + +#endif +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR101 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR101(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr101_parlhf, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR101_PARLHF); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr101_parlvib, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR101_PARLVIB); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr101_classd_viblswapen, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR101_CLASSDVIBLSWAPEN); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr101_classd_vibrswapen, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR101_CLASSDVIBRSWAPEN); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr101_classd_hflswapen, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR101_CLASSDHFLSWAPEN); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr101_classd_hfrswapen, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR101_CLASSDHFRSWAPEN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR101, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR102 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR102(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr102_classd_firbyp, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR102_CLASSD_FIRBYP); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr102_classd_highvolen, + AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR102_CLASSD_HIGHVOLEN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR102, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR103 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR103(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr103_classd_ditherhpgain, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR103_CLASSD_DITHERHPGAIN); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr103_classd_ditherwgain, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR103_CLASSD_DITHERWGAIN); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR103, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR104 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR104(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr104_bfifoint, + AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR104_BFIFOINT); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR104, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR105 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR105(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr105_bfifotx, + AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR105_BFIFOTX); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR105, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR106 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR106(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr106_bfifofsext, + AB8500_CODEC_MASK_THREE_BITS, AB8500_CODEC_CR106_BFIFOFSEXT); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr106_bfifomsk, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR106_BFIFOMSK); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr106_bfifomstr, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR106_BFIFOMSTR); + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr106_bfifostrt, + AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR106_BFIFOSTRT); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR106, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR107 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR107(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr107_bfifosampnr, + AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR107_BFIFOSAMPNR); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR107, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR108 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR108(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr108_bfifowakeup, + AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR108_BFIFOWAKEUP); + + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR108, value)); +} + +/* CR109 is Read Only */ +/********************************************************************************************/ +/* Name: ab8500_codec_Reset() */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_Reset(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + p_ab8500_codec_configuration->cr1_swreset = + AB8500_CODEC_CR1_SWRESET_ENABLED; + + ab8500_codec_error = ab8500_codec_UpdateCR1(); + if (AB8500_CODEC_OK != ab8500_codec_error) { + return (ab8500_codec_error); + } + + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirection(IN + t_ab8500_codec_direction + ab8500_codec_direction) +{ /*only IN or OUT must be passed (not INOUT) */ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + + if (AB8500_CODEC_DIRECTION_IN == ab8500_codec_direction) { + ab8500_codec_error = ab8500_codec_ProgramDirectionIN(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } + + if (AB8500_CODEC_DIRECTION_OUT == ab8500_codec_direction) { + ab8500_codec_error = ab8500_codec_ProgramDirectionOUT(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } + + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_SetDirection(IN + t_ab8500_codec_direction + ab8500_codec_direction) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + switch (ab8500_codec_direction) { + case AB8500_CODEC_DIRECTION_IN: + ab8500_codec_error = + ab8500_codec_ProgramDirection(AB8500_CODEC_DIRECTION_IN); + break; + + case AB8500_CODEC_DIRECTION_OUT: + ab8500_codec_error = + ab8500_codec_ProgramDirection(AB8500_CODEC_DIRECTION_OUT); + break; + + case AB8500_CODEC_DIRECTION_INOUT: + ab8500_codec_error = + ab8500_codec_ProgramDirection(AB8500_CODEC_DIRECTION_IN); + if (AB8500_CODEC_OK == ab8500_codec_error) { + ab8500_codec_error = + ab8500_codec_ProgramDirection + (AB8500_CODEC_DIRECTION_OUT); + } + break; + } + + if (ab8500_codec_error != AB8500_CODEC_OK) { + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR5(); + if (AB8500_CODEC_OK != ab8500_codec_error) { + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR6(); + if (AB8500_CODEC_OK != ab8500_codec_error) { + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR7(); + if (AB8500_CODEC_OK != ab8500_codec_error) { + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR8(); + if (AB8500_CODEC_OK != ab8500_codec_error) { + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR9(); + if (AB8500_CODEC_OK != ab8500_codec_error) { + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR10(); + if (AB8500_CODEC_OK != ab8500_codec_error) { + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR12(); + if (AB8500_CODEC_OK != ab8500_codec_error) { + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR15(); + if (AB8500_CODEC_OK != ab8500_codec_error) { + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR63(); + if (AB8500_CODEC_OK != ab8500_codec_error) { + return (ab8500_codec_error); + } + + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_Init */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Initialize the global variables & stores the slave address of codec. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* slave_address_of_ab8500_codec: Audio codec slave address */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* Returns AB8500_CODEC_OK */ +/* COMMENTS: */ +/* 1) Saves the supplied slave_address_of_codec in global variable */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_Init(IN t_uint8 + slave_address_of_ab8500_codec) +{ + DBGENTER1(" (%lx)", slave_address_of_ab8500_codec); + + g_ab8500_codec_system_context.slave_address_of_ab8500_codec = + slave_address_of_ab8500_codec; + + DBGEXIT(AB8500_CODEC_OK); + return (AB8500_CODEC_OK); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_Reset */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Reset the global variables and clear audiocodec settings to default. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_Reset(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + + DBGENTER(); + + g_ab8500_codec_system_context.ab8500_codec_direction = + AB8500_CODEC_DEFAULT_DIRECTION; + g_ab8500_codec_system_context.ab8500_codec_mode_in = + AB8500_CODEC_DEFAULT_MODE_IN; + g_ab8500_codec_system_context.ab8500_codec_mode_out = + AB8500_CODEC_DEFAULT_MODE_OUT; + + g_ab8500_codec_system_context.ab8500_codec_src = + AB8500_CODEC_DEFAULT_INPUT_SRC; + g_ab8500_codec_system_context.ab8500_codec_dest = + AB8500_CODEC_DEFAULT_OUTPUT_DEST; + + g_ab8500_codec_system_context.in_left_volume = + AB8500_CODEC_DEFAULT_VOLUME_LEFT_IN; + g_ab8500_codec_system_context.in_right_volume = + AB8500_CODEC_DEFAULT_VOLUME_RIGHT_IN; + g_ab8500_codec_system_context.out_left_volume = + AB8500_CODEC_DEFAULT_VOLUME_LEFT_OUT; + g_ab8500_codec_system_context.out_right_volume = + AB8500_CODEC_DEFAULT_VOLUME_RIGHT_OUT; + + ab8500_codec_error = ab8500_codec_Reset(); + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SetModeAndDirection */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Configures the whole audio codec to work in audio mode */ +/* (using I2S protocol). */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* direction: select the direction (IN, OUT or INOUT) */ +/* in_mode: codec mode for recording. If direction is OUT only, */ +/* this parameter is ignored. */ +/* out_mode: codec mode for playing. If direction is IN only, */ +/* this parameter is ignored. */ +/* p_tdm_config: TDM configuration required to be configured by user */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_UNSUPPORTED_FEATURE: The API may not allow setting */ +/* 2 different modes, in which case it should return this value. */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SetModeAndDirection + (IN t_ab8500_codec_direction ab8500_codec_direction, + IN t_ab8500_codec_mode ab8500_codec_mode_in, + IN t_ab8500_codec_mode ab8500_codec_mode_out, + IN t_ab8500_codec_tdm_config const *const p_tdm_config) { + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + DBGENTER3(" (%lx %lx %lx)", ab8500_codec_direction, + ab8500_codec_mode_in, ab8500_codec_mode_out); + + if (AB8500_CODEC_AUDIO_INTERFACE_1 == + g_ab8500_codec_system_context.audio_interface) { + if (AB8500_CODEC_DIRECTION_OUT == ab8500_codec_direction + || AB8500_CODEC_DIRECTION_INOUT == ab8500_codec_direction) { + p_ab8500_codec_configuration->cr3_enda1 = + AB8500_CODEC_CR3_ENDA1_ENABLED; + p_ab8500_codec_configuration->cr3_enda2 = + AB8500_CODEC_CR3_ENDA2_ENABLED; + p_ab8500_codec_configuration->cr3_enda3 = + AB8500_CODEC_CR3_ENDA3_ENABLED; + p_ab8500_codec_configuration->cr3_enda4 = + AB8500_CODEC_CR3_ENDA4_ENABLED; + p_ab8500_codec_configuration->cr3_enda5 = + AB8500_CODEC_CR3_ENDA5_ENABLED; + p_ab8500_codec_configuration->cr3_enda6 = + AB8500_CODEC_CR3_ENDA6_ENABLED; + + p_ab8500_codec_configuration->cr27_if1_bitclk_osr = + p_tdm_config->cr27_if1_bitclk_osr; + + if (AB8500_CODEC_MODE_HIFI == ab8500_codec_mode_out) { + p_ab8500_codec_configuration->cr30_fsync1p = + AB8500_CODEC_CR30_FSYNC1P_FALLING_EDGE; + p_ab8500_codec_configuration->cr30_bitclk1p = + AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE; + p_ab8500_codec_configuration->cr30_if1del = + AB8500_CODEC_CR30_IF1DEL_DELAYED; + p_ab8500_codec_configuration->cr30_if1format = + AB8500_CODEC_CR30_IF1FORMAT_I2S_LEFTALIGNED; + p_ab8500_codec_configuration->cr30_if1wl = + p_tdm_config->cr30_if1wl; + } else { + p_ab8500_codec_configuration->cr30_fsync1p = + AB8500_CODEC_CR30_FSYNC1P_FALLING_EDGE; + p_ab8500_codec_configuration->cr30_bitclk1p = + AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE; + p_ab8500_codec_configuration->cr30_if1del = + AB8500_CODEC_CR30_IF1DEL_DELAYED; + p_ab8500_codec_configuration->cr30_if1format = + AB8500_CODEC_CR30_IF1FORMAT_TDM; + p_ab8500_codec_configuration->cr30_if1wl = + p_tdm_config->cr30_if1wl; + } + } + + if (AB8500_CODEC_DIRECTION_IN == ab8500_codec_direction + || AB8500_CODEC_DIRECTION_INOUT == ab8500_codec_direction) { + p_ab8500_codec_configuration->cr2_enad1 = + AB8500_CODEC_CR2_ENAD1_ENABLED; + p_ab8500_codec_configuration->cr2_enad2 = + AB8500_CODEC_CR2_ENAD2_ENABLED; + p_ab8500_codec_configuration->cr2_enad3 = + AB8500_CODEC_CR2_ENAD3_ENABLED; + p_ab8500_codec_configuration->cr2_enad4 = + AB8500_CODEC_CR2_ENAD4_ENABLED; + p_ab8500_codec_configuration->cr2_enad5 = + AB8500_CODEC_CR2_ENAD5_ENABLED; + p_ab8500_codec_configuration->cr2_enad6 = + AB8500_CODEC_CR2_ENAD6_ENABLED; + + p_ab8500_codec_configuration->cr27_if1_bitclk_osr = + p_tdm_config->cr27_if1_bitclk_osr; + + if (AB8500_CODEC_MODE_HIFI == ab8500_codec_mode_in) { + p_ab8500_codec_configuration->cr30_fsync1p = + AB8500_CODEC_CR30_FSYNC1P_FALLING_EDGE; + p_ab8500_codec_configuration->cr30_bitclk1p = + AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE; + p_ab8500_codec_configuration->cr30_if1del = + AB8500_CODEC_CR30_IF1DEL_DELAYED; + p_ab8500_codec_configuration->cr30_if1format = + AB8500_CODEC_CR30_IF1FORMAT_I2S_LEFTALIGNED; + p_ab8500_codec_configuration->cr30_if1wl = + p_tdm_config->cr30_if1wl; + } else { + p_ab8500_codec_configuration->cr30_fsync1p = + AB8500_CODEC_CR30_FSYNC1P_RISING_EDGE; + p_ab8500_codec_configuration->cr30_bitclk1p = + AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE; + p_ab8500_codec_configuration->cr30_if1del = + AB8500_CODEC_CR30_IF1DEL_NOT_DELAYED; + p_ab8500_codec_configuration->cr30_if1format = + AB8500_CODEC_CR30_IF1FORMAT_TDM; + p_ab8500_codec_configuration->cr30_if1wl = + p_tdm_config->cr30_if1wl; + } + } + } else { + if (AB8500_CODEC_DIRECTION_OUT == ab8500_codec_direction + || AB8500_CODEC_DIRECTION_INOUT == ab8500_codec_direction) { + p_ab8500_codec_configuration->cr3_enda1 = + AB8500_CODEC_CR3_ENDA1_ENABLED; + p_ab8500_codec_configuration->cr3_enda2 = + AB8500_CODEC_CR3_ENDA2_ENABLED; + p_ab8500_codec_configuration->cr3_enda3 = + AB8500_CODEC_CR3_ENDA3_ENABLED; + p_ab8500_codec_configuration->cr3_enda4 = + AB8500_CODEC_CR3_ENDA4_ENABLED; + p_ab8500_codec_configuration->cr3_enda5 = + AB8500_CODEC_CR3_ENDA5_ENABLED; + p_ab8500_codec_configuration->cr3_enda6 = + AB8500_CODEC_CR3_ENDA6_ENABLED; + + p_ab8500_codec_configuration->cr27_if0_bitclk_osr = + p_tdm_config->cr27_if0_bitclk_osr; + + p_ab8500_codec_configuration->cr63_datohslen = + AB8500_CODEC_CR63_DATOHSLEN_ENABLED; + p_ab8500_codec_configuration->cr63_datohsren = + AB8500_CODEC_CR63_DATOHSREN_ENABLED; + + if (AB8500_CODEC_MODE_HIFI == ab8500_codec_mode_out) { + p_ab8500_codec_configuration->cr28_fsync0p = + AB8500_CODEC_CR28_FSYNC0P_FALLING_EDGE; + p_ab8500_codec_configuration->cr28_bitclk0p = p_tdm_config->cr28_bitclk0p; /*AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE; */ + p_ab8500_codec_configuration->cr28_if0del = p_tdm_config->cr28_if0del; /*AB8500_CODEC_CR28_IF0DEL_DELAYED; */ + p_ab8500_codec_configuration->cr28_if0format = + AB8500_CODEC_CR28_IF0FORMAT_I2S_LEFTALIGNED; + p_ab8500_codec_configuration->cr28_if0wl = + p_tdm_config->cr28_if0wl; + } else { + p_ab8500_codec_configuration->cr28_fsync0p = + AB8500_CODEC_CR28_FSYNC0P_FALLING_EDGE; + p_ab8500_codec_configuration->cr28_bitclk0p = p_tdm_config->cr28_bitclk0p; /*AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE; */ + p_ab8500_codec_configuration->cr28_if0del = p_tdm_config->cr28_if0del; /*AB8500_CODEC_CR28_IF0DEL_DELAYED; */ + p_ab8500_codec_configuration->cr28_if0format = + AB8500_CODEC_CR28_IF0FORMAT_TDM; + p_ab8500_codec_configuration->cr28_if0wl = + p_tdm_config->cr28_if0wl; + } + } + + if (AB8500_CODEC_DIRECTION_IN == ab8500_codec_direction + || AB8500_CODEC_DIRECTION_INOUT == ab8500_codec_direction) { + p_ab8500_codec_configuration->cr2_enad1 = + AB8500_CODEC_CR2_ENAD1_ENABLED; + p_ab8500_codec_configuration->cr2_enad2 = + AB8500_CODEC_CR2_ENAD2_ENABLED; + p_ab8500_codec_configuration->cr2_enad3 = + AB8500_CODEC_CR2_ENAD3_ENABLED; + p_ab8500_codec_configuration->cr2_enad4 = + AB8500_CODEC_CR2_ENAD4_ENABLED; + p_ab8500_codec_configuration->cr2_enad5 = + AB8500_CODEC_CR2_ENAD5_ENABLED; + p_ab8500_codec_configuration->cr2_enad6 = + AB8500_CODEC_CR2_ENAD6_ENABLED; + + p_ab8500_codec_configuration->cr26_ad1_voice = + AB8500_CODEC_CR26_AD1_VOICE_LOWLATENCYFILTER; + p_ab8500_codec_configuration->cr26_ad2_voice = + AB8500_CODEC_CR26_AD2_VOICE_LOWLATENCYFILTER; + p_ab8500_codec_configuration->cr26_ad3_voice = + AB8500_CODEC_CR26_AD3_VOICE_LOWLATENCYFILTER; + p_ab8500_codec_configuration->cr26_ad4_voice = + AB8500_CODEC_CR26_AD4_VOICE_LOWLATENCYFILTER; + + p_ab8500_codec_configuration->cr27_if0_bitclk_osr = + p_tdm_config->cr27_if0_bitclk_osr; + + if (AB8500_CODEC_MODE_HIFI == ab8500_codec_mode_in) { + p_ab8500_codec_configuration->cr28_fsync0p = + AB8500_CODEC_CR28_FSYNC0P_RISING_EDGE; + p_ab8500_codec_configuration->cr28_bitclk0p = p_tdm_config->cr28_bitclk0p; /*AB8500_CODEC_CR28_BITCLK0P_RISING_EDGE; */ + p_ab8500_codec_configuration->cr28_if0del = p_tdm_config->cr28_if0del; /*AB8500_CODEC_CR28_IF0DEL_NOT_DELAYED; */ + p_ab8500_codec_configuration->cr28_if0format = + AB8500_CODEC_CR28_IF0FORMAT_I2S_LEFTALIGNED; + p_ab8500_codec_configuration->cr28_if0wl = + p_tdm_config->cr28_if0wl; + } else { + p_ab8500_codec_configuration->cr28_fsync0p = + AB8500_CODEC_CR28_FSYNC0P_RISING_EDGE; + p_ab8500_codec_configuration->cr28_bitclk0p = p_tdm_config->cr28_bitclk0p; /*AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE; */ + p_ab8500_codec_configuration->cr28_if0del = p_tdm_config->cr28_if0del; /*AB8500_CODEC_CR28_IF0DEL_NOT_DELAYED; */ + p_ab8500_codec_configuration->cr28_if0format = + AB8500_CODEC_CR28_IF0FORMAT_TDM; + p_ab8500_codec_configuration->cr28_if0wl = + p_tdm_config->cr28_if0wl; + } + } + } + + ab8500_codec_error = ab8500_codec_SetModeAndDirectionUpdateCR(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + g_ab8500_codec_system_context.ab8500_codec_direction = + ab8500_codec_direction; + g_ab8500_codec_system_context.ab8500_codec_mode_in = + ab8500_codec_mode_in; + g_ab8500_codec_system_context.ab8500_codec_mode_out = + ab8500_codec_mode_out; + + ab8500_codec_error = ab8500_codec_SetDirection(ab8500_codec_direction); + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SetSrcVolume */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Sets the record volumes. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* t_ab8500_codec_src: select source device for recording. */ +/* in_left_volume: record volume for left channel. */ +/* in_right_volume: record volume for right channel. */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SetSrcVolume + (IN t_ab8500_codec_src src_device, + IN t_uint8 in_left_volume, IN t_uint8 in_right_volume) { + t_ab8500_codec_error ab8500_codec_error; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + DBGENTER3(" (%lx %lx %lx)", src_device, in_left_volume, + in_right_volume); + + if (in_left_volume > AB8500_CODEC_MAX_VOLUME) { + in_left_volume = AB8500_CODEC_MAX_VOLUME; + } + + if (in_right_volume > AB8500_CODEC_MAX_VOLUME) { + in_right_volume = AB8500_CODEC_MAX_VOLUME; + } + + g_ab8500_codec_system_context.in_left_volume = in_left_volume; + g_ab8500_codec_system_context.in_right_volume = in_right_volume; + + p_ab8500_codec_configuration->cr65_ad1gain = + AB8500_CODEC_AD_D_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_AD_D_VOLUME_MAX - + AB8500_CODEC_AD_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr66_ad2gain = + AB8500_CODEC_AD_D_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_AD_D_VOLUME_MAX - + AB8500_CODEC_AD_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr67_ad3gain = + AB8500_CODEC_AD_D_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_AD_D_VOLUME_MAX - + AB8500_CODEC_AD_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr68_ad4gain = + AB8500_CODEC_AD_D_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_AD_D_VOLUME_MAX - + AB8500_CODEC_AD_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr69_ad5gain = + AB8500_CODEC_AD_D_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_AD_D_VOLUME_MAX - + AB8500_CODEC_AD_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr70_ad6gain = + AB8500_CODEC_AD_D_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_AD_D_VOLUME_MAX - + AB8500_CODEC_AD_D_VOLUME_MIN)) / 100; + + /* Set mininimum volume if volume is zero */ + switch (src_device) { + case AB8500_CODEC_SRC_LINEIN: + p_ab8500_codec_configuration->cr22_linl_gain = + AB8500_CODEC_LINEIN_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_LINEIN_VOLUME_MAX - + AB8500_CODEC_LINEIN_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr23_linr_gain = + AB8500_CODEC_LINEIN_VOLUME_MIN + + (in_right_volume * + (AB8500_CODEC_LINEIN_VOLUME_MAX - + AB8500_CODEC_LINEIN_VOLUME_MIN)) / 100; + break; + + case AB8500_CODEC_SRC_MICROPHONE_1A: + case AB8500_CODEC_SRC_MICROPHONE_1B: + p_ab8500_codec_configuration->cr20_mic1_gain = + AB8500_CODEC_MIC_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_MIC_VOLUME_MAX - + AB8500_CODEC_MIC_VOLUME_MIN)) / 100; + break; + + case AB8500_CODEC_SRC_MICROPHONE_2: + p_ab8500_codec_configuration->cr21_mic2_gain = + AB8500_CODEC_MIC_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_MIC_VOLUME_MAX - + AB8500_CODEC_MIC_VOLUME_MIN)) / 100; + break; + + case AB8500_CODEC_SRC_D_MICROPHONE_1: + break; + + case AB8500_CODEC_SRC_D_MICROPHONE_2: + break; + + case AB8500_CODEC_SRC_D_MICROPHONE_3: + break; + + case AB8500_CODEC_SRC_D_MICROPHONE_4: + break; + + case AB8500_CODEC_SRC_D_MICROPHONE_5: + break; + + case AB8500_CODEC_SRC_D_MICROPHONE_6: + break; + + case AB8500_CODEC_SRC_ALL: + p_ab8500_codec_configuration->cr22_linl_gain = + AB8500_CODEC_LINEIN_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_LINEIN_VOLUME_MAX - + AB8500_CODEC_LINEIN_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr23_linr_gain = + AB8500_CODEC_LINEIN_VOLUME_MIN + + (in_right_volume * + (AB8500_CODEC_LINEIN_VOLUME_MAX - + AB8500_CODEC_LINEIN_VOLUME_MIN)) / 100; + + p_ab8500_codec_configuration->cr20_mic1_gain = + AB8500_CODEC_MIC_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_MIC_VOLUME_MAX - + AB8500_CODEC_MIC_VOLUME_MIN)) / 100; + + p_ab8500_codec_configuration->cr21_mic2_gain = + AB8500_CODEC_MIC_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_MIC_VOLUME_MAX - + AB8500_CODEC_MIC_VOLUME_MIN)) / 100; + break; + + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_SetSrcVolumeUpdateCR(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SetDestVolume */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Sets the play volumes. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* out_left_volume: play volume for left channel. */ +/* out_right_volume: play volume for right channel. */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SetDestVolume + (IN t_ab8500_codec_dest dest_device, + IN t_uint8 out_left_volume, IN t_uint8 out_right_volume) { + t_ab8500_codec_error ab8500_codec_error; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + DBGENTER3(" (%lx %lx %lx)", dest_device, out_left_volume, + out_right_volume); + + if (out_left_volume > AB8500_CODEC_MAX_VOLUME) { + out_left_volume = AB8500_CODEC_MAX_VOLUME; + } + + if (out_right_volume > AB8500_CODEC_MAX_VOLUME) { + out_right_volume = AB8500_CODEC_MAX_VOLUME; + } + + g_ab8500_codec_system_context.out_left_volume = out_left_volume; + g_ab8500_codec_system_context.out_right_volume = out_right_volume; + + p_ab8500_codec_configuration->cr71_da1gain = + AB8500_CODEC_DA_D_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_DA_D_VOLUME_MAX - + AB8500_CODEC_DA_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr72_da2gain = + AB8500_CODEC_DA_D_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_DA_D_VOLUME_MAX - + AB8500_CODEC_DA_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr73_da3gain = + AB8500_CODEC_DA_D_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_DA_D_VOLUME_MAX - + AB8500_CODEC_DA_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr74_da4gain = + AB8500_CODEC_DA_D_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_DA_D_VOLUME_MAX - + AB8500_CODEC_DA_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr75_da5gain = + AB8500_CODEC_DA_D_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_DA_D_VOLUME_MAX - + AB8500_CODEC_DA_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr76_da6gain = + AB8500_CODEC_DA_D_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_DA_D_VOLUME_MAX - + AB8500_CODEC_DA_D_VOLUME_MIN)) / 100; + + /* Set mininimum volume if volume is zero */ + switch (dest_device) { + case AB8500_CODEC_DEST_HEADSET: + p_ab8500_codec_configuration->cr22_hsl_gain = + AB8500_CODEC_HEADSET_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_HEADSET_VOLUME_MAX - + AB8500_CODEC_HEADSET_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr23_hsr_gain = + AB8500_CODEC_HEADSET_VOLUME_MIN + + (out_right_volume * + (AB8500_CODEC_HEADSET_VOLUME_MAX - + AB8500_CODEC_HEADSET_VOLUME_MIN)) / 100; + + p_ab8500_codec_configuration->cr79_hsldgain = + AB8500_CODEC_HEADSET_D_VOLUME_0DB; + p_ab8500_codec_configuration->cr80_hsrdgain = + AB8500_CODEC_HEADSET_D_VOLUME_0DB; + break; + + case AB8500_CODEC_DEST_EARPIECE: + p_ab8500_codec_configuration->cr79_hsldgain = + AB8500_CODEC_HEADSET_D_VOLUME_0DB; + break; + + case AB8500_CODEC_DEST_HANDSFREE: + + p_ab8500_codec_configuration->cr101_parlhf = + AB8500_CODEC_CR101_PARLHF_INDEPENDENT; + p_ab8500_codec_configuration->cr101_parlvib = + AB8500_CODEC_CR101_PARLVIB_INDEPENDENT; + p_ab8500_codec_configuration->cr101_classd_viblswapen = + AB8500_CODEC_CR101_CLASSD_VIBLSWAPEN_DISABLED; + p_ab8500_codec_configuration->cr101_classd_vibrswapen = + AB8500_CODEC_CR101_CLASSD_VIBRSWAPEN_DISABLED; + p_ab8500_codec_configuration->cr101_classd_hflswapen = + AB8500_CODEC_CR101_CLASSD_HFLSWAPEN_DISABLED; + p_ab8500_codec_configuration->cr101_classd_hfrswapen = + AB8500_CODEC_CR101_CLASSD_HFRSWAPEN_DISABLED; + + p_ab8500_codec_configuration->cr102_classd_firbyp = + AB8500_CODEC_CR102_CLASSD_FIRBYP_ALL_ENABLED; + p_ab8500_codec_configuration->cr102_classd_highvolen = + AB8500_CODEC_CR102_CLASSD_HIGHVOLEN_DISABLED; + + p_ab8500_codec_configuration->cr103_classd_ditherhpgain = 0x8; + p_ab8500_codec_configuration->cr103_classd_ditherwgain = 0x4; + + break; + + case AB8500_CODEC_DEST_VIBRATOR_L: + p_ab8500_codec_configuration->cr16_pwmnldutycycle = + AB8500_CODEC_VIBRATOR_VOLUME_MIN; + p_ab8500_codec_configuration->cr17_pwmpldutycycle = + AB8500_CODEC_VIBRATOR_VOLUME_MIN + + (out_right_volume * + (AB8500_CODEC_VIBRATOR_VOLUME_MAX - + AB8500_CODEC_VIBRATOR_VOLUME_MIN)) / 100; + break; + + case AB8500_CODEC_DEST_VIBRATOR_R: + p_ab8500_codec_configuration->cr18_pwmnrdutycycle = + AB8500_CODEC_VIBRATOR_VOLUME_MIN; + p_ab8500_codec_configuration->cr19_pwmprdutycycle = + AB8500_CODEC_VIBRATOR_VOLUME_MIN + + (out_right_volume * + (AB8500_CODEC_VIBRATOR_VOLUME_MAX - + AB8500_CODEC_VIBRATOR_VOLUME_MIN)) / 100; + break; + + case AB8500_CODEC_DEST_ALL: + p_ab8500_codec_configuration->cr22_hsl_gain = + AB8500_CODEC_HEADSET_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_HEADSET_VOLUME_MAX - + AB8500_CODEC_HEADSET_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr23_hsr_gain = + AB8500_CODEC_HEADSET_VOLUME_MIN + + (out_right_volume * + (AB8500_CODEC_HEADSET_VOLUME_MAX - + AB8500_CODEC_HEADSET_VOLUME_MIN)) / 100; + + p_ab8500_codec_configuration->cr79_hsldgain = + AB8500_CODEC_HEADSET_D_VOLUME_0DB; + break; + + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_SetDestVolumeUpdateCR(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SetMasterMode */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Set the Audio Codec in Master mode. */ +/* */ +/* ARGUMENTS */ +/* IN: t_codec_master_mode: Enable/disable master mode */ +/* OUT: */ +/* None */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/* REMARK: Call this API after calling AB8500_CODEC_SetModeAndDirection() API*/ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SetMasterMode(IN + t_ab8500_codec_master_mode + mode) +{ + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + DBGENTER0(); + + if (AB8500_CODEC_AUDIO_INTERFACE_1 == + g_ab8500_codec_system_context.audio_interface) { + + p_ab8500_codec_configuration->cr27_en_mastgen = + AB8500_CODEC_CR27_EN_MASTGEN_ENABLED; + p_ab8500_codec_configuration->cr27_enfs_bitclk1 = + AB8500_CODEC_CR27_ENFS_BITCLK1_ENABLED; + + if (AB8500_CODEC_MASTER_MODE_ENABLE == mode) { + p_ab8500_codec_configuration->cr29_if1master = + AB8500_CODEC_CR29_IF1MASTER_FS1CK1_OUTPUT; + } else { + p_ab8500_codec_configuration->cr29_if1master = + AB8500_CODEC_CR29_IF1MASTER_FS1CK1_INPUT; + } + + } else { + + p_ab8500_codec_configuration->cr27_en_mastgen = + AB8500_CODEC_CR27_EN_MASTGEN_ENABLED; + p_ab8500_codec_configuration->cr27_enfs_bitclk0 = + AB8500_CODEC_CR27_ENFS_BITCLK0_ENABLED; + + if (AB8500_CODEC_MASTER_MODE_ENABLE == mode) { + p_ab8500_codec_configuration->cr29_if0master = + AB8500_CODEC_CR29_IF0MASTER_FS0CK0_OUTPUT; + } else { + p_ab8500_codec_configuration->cr29_if0master = + AB8500_CODEC_CR29_IF0MASTER_FS0CK0_INPUT; + } + + } + + ab8500_codec_error = ab8500_codec_UpdateCR27(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR29(); + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SelectInput */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Select input source for recording. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* input_src: select input source for recording when several sources */ +/* are supported in codec. */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_INVALID_PARAMETER: If input_src provided is invalid */ +/* by the codec hardware in use. */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SelectInput(IN t_ab8500_codec_src + ab8500_codec_src) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + DBGENTER1(" (%lx)", ab8500_codec_src); + + g_ab8500_codec_system_context.ab8500_codec_src = ab8500_codec_src; + + ab8500_codec_error = + ab8500_codec_SetDirection(AB8500_CODEC_DIRECTION_IN); + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SelectOutput */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Select output desination for playing. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* output_dest: select output destination for playing when several are */ +/* supported by codec hardware. */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_INVALID_PARAMETER: If output_src provided is invalid */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SelectOutput(IN t_ab8500_codec_dest + ab8500_codec_dest) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + g_ab8500_codec_system_context.ab8500_codec_dest = ab8500_codec_dest; + DBGENTER1(" (%lx)", ab8500_codec_dest); + + ab8500_codec_error = + ab8500_codec_SetDirection(AB8500_CODEC_DIRECTION_OUT); + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_PowerDown */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Shuts the audio codec down completely. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* OUT: */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_PowerDown(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + + g_ab8500_codec_system_context.ab8500_codec_configuration.cr0_powerup = + AB8500_CODEC_CR0_POWERUP_OFF; + + ab8500_codec_error = ab8500_codec_UpdateCR0(); + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_PowerUp */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Switch on the audio codec. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* None */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_PowerUp(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + + DBGENTER(); + + /*g_ab8500_codec_system_context.ab8500_codec_configuration.cr1_swreset = AB8500_CODEC_CR1_SWRESET_ENABLED; Removed by kardad + ab8500_codec_error = ab8500_codec_UpdateCR1(); + if (AB8500_CODEC_OK != ab8500_codec_error) + { + return(ab8500_codec_error); + } */ + + g_ab8500_codec_system_context.ab8500_codec_configuration.cr0_powerup = + AB8500_CODEC_CR0_POWERUP_ON; + g_ab8500_codec_system_context.ab8500_codec_configuration.cr0_enaana = + AB8500_CODEC_CR0_ENAANA_ON; + + ab8500_codec_error = ab8500_codec_UpdateCR0(); + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SelectInterface */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Select the Audio Interface 0 or 1. */ +/* */ +/* ARGUMENTS */ +/* IN: t_ab8500_codec_audio_interface: The selected interface */ +/* */ +/* OUT: */ +/* None */ +/* RETURN: */ +/* AB8500_CODEC_OK: Always. */ +/* REMARK: Call this API before using a function of the low level drivers */ +/* to select the interface that you want to configure */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SelectInterface(IN + t_ab8500_codec_audio_interface + audio_interface) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + DBGENTER0(); + + g_ab8500_codec_system_context.audio_interface = audio_interface; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_GetInterface */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Get the Audio Interface 0 or 1. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: p_audio_interface: Store the selected interface */ +/* RETURN: */ +/* AB8500_CODEC_OK: Always */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Re-Entrant */ +/* REENTRANCY ISSUES: No Issues */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_GetInterface(OUT + t_ab8500_codec_audio_interface + * p_audio_interface) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + DBGENTER0(); + + *p_audio_interface = g_ab8500_codec_system_context.audio_interface; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SetAnalogLoopback */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Sets Line-In to HeadSet loopback with the required gain. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* out_left_volume: play volume for left channel. */ +/* out_right_volume: play volume for right channel. */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SetAnalogLoopback(IN t_uint8 + out_left_volume, + IN t_uint8 + out_right_volume) +{ + t_ab8500_codec_error ab8500_codec_error; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + DBGENTER2(" (%lx %lx)", out_left_volume, out_right_volume); + + if (out_left_volume > AB8500_CODEC_MAX_VOLUME) { + out_left_volume = AB8500_CODEC_MAX_VOLUME; + } + + if (out_right_volume > AB8500_CODEC_MAX_VOLUME) { + out_right_volume = AB8500_CODEC_MAX_VOLUME; + } + + g_ab8500_codec_system_context.out_left_volume = out_left_volume; + g_ab8500_codec_system_context.out_right_volume = out_right_volume; + + p_ab8500_codec_configuration->cr24_lintohsl_gain = + AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MAX - + AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr25_lintohsr_gain = + AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN + + (out_right_volume * + (AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MAX - + AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN)) / 100; + + ab8500_codec_error = ab8500_codec_UpdateCR24(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR25(); + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_RemoveAnalogLoopback */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Remove Line-In to HeadSet loopback. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_RemoveAnalogLoopback(void) +{ + t_ab8500_codec_error ab8500_codec_error; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + DBGENTER0(); + + p_ab8500_codec_configuration->cr24_lintohsl_gain = + AB8500_CODEC_LINEIN_TO_HS_L_R_LOOP_OPEN; + p_ab8500_codec_configuration->cr25_lintohsr_gain = + AB8500_CODEC_LINEIN_TO_HS_L_R_LOOP_OPEN; + + ab8500_codec_error = ab8500_codec_UpdateCR24(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR25(); + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_EnableBypassMode */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Enables IF0 to IF1 path or vice versa */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_EnableBypassMode(void) +{ + t_ab8500_codec_error ab8500_codec_error; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + DBGENTER0(); + + if (AB8500_CODEC_AUDIO_INTERFACE_1 == + g_ab8500_codec_system_context.audio_interface) { + p_ab8500_codec_configuration->cr29_if1datoif0ad = + AB8500_CODEC_CR29_IF1DATOIF0AD_SENT; + p_ab8500_codec_configuration->cr29_if1cktoif0ck = + AB8500_CODEC_CR29_IF1CKTOIF0CK_SENT; + } else { + p_ab8500_codec_configuration->cr29_if0datoif1ad = + AB8500_CODEC_CR29_IF0DATOIF1AD_SENT; + p_ab8500_codec_configuration->cr29_if0cktoif1ck = + AB8500_CODEC_CR29_IF0CKTOIF1CK_SENT; + } + + ab8500_codec_error = ab8500_codec_UpdateCR29(); + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_DisableBypassMode */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Disables IF0 to IF1 path or vice versa */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_DisableBypassMode(void) +{ + t_ab8500_codec_error ab8500_codec_error; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + DBGENTER0(); + + if (AB8500_CODEC_AUDIO_INTERFACE_1 == + g_ab8500_codec_system_context.audio_interface) { + p_ab8500_codec_configuration->cr29_if1datoif0ad = + AB8500_CODEC_CR29_IF1DATOIF0AD_NOTSENT; + p_ab8500_codec_configuration->cr29_if1cktoif0ck = + AB8500_CODEC_CR29_IF1CKTOIF0CK_NOTSENT; + } else { + p_ab8500_codec_configuration->cr29_if0datoif1ad = + AB8500_CODEC_CR29_IF0DATOIF1AD_NOTSENT; + p_ab8500_codec_configuration->cr29_if0cktoif1ck = + AB8500_CODEC_CR29_IF0CKTOIF1CK_NOTSENT; + } + + ab8500_codec_error = ab8500_codec_UpdateCR29(); + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SrcPowerControl */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Enables/Disables & UnMute/Mute the desired source */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* t_ab8500_codec_src: select source device for enabling/disabling. */ +/* t_ab8500_codec_src_state: Enable/Disable */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SrcPowerControl(IN t_ab8500_codec_src + src_device, + t_ab8500_codec_src_state + state) +{ + t_ab8500_codec_error ab8500_codec_error; + + DBGENTER2(" (%lx %lx)", src_device, state); + + if (src_device <= AB8500_CODEC_SRC_D_MICROPHONE_2) { + ab8500_codec_error = + ab8500_codec_SrcPowerControlSwitch1(src_device, state); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } else if (src_device <= AB8500_CODEC_SRC_ALL) { + ab8500_codec_error = + ab8500_codec_SrcPowerControlSwitch2(src_device, state); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } else { + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR5(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR6(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR7(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR63(); + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_DestPowerControl */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Enables/Disables & UnMute/Mute the desired destination */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* t_ab8500_codec_dest: select destination device for enabling/disabling. */ +/* t_ab8500_codec_dest_state: Enable/Disable */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_DestPowerControl(IN t_ab8500_codec_dest + dest_device, + t_ab8500_codec_dest_state + state) +{ + t_ab8500_codec_error ab8500_codec_error; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + DBGENTER2(" (%lx %lx)", dest_device, state); + + switch (dest_device) { + case AB8500_CODEC_DEST_HEADSET: + + if (AB8500_CODEC_DEST_STATE_ENABLE == state) { + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_ENABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_DISABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_DISABLED; + } else { + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_DISABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_DISABLED; + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_ENABLED; + } + break; + + case AB8500_CODEC_DEST_EARPIECE: + + if (AB8500_CODEC_DEST_STATE_ENABLE == state) { + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_ENABLED; + p_ab8500_codec_configuration->cr9_endacear = + AB8500_CODEC_CR9_ENDACEAR_ENABLED; + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_DISABLED; + } else { + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_DISABLED; + p_ab8500_codec_configuration->cr9_endacear = + AB8500_CODEC_CR9_ENDACEAR_DISABLED; + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_ENABLED; + } + break; + + case AB8500_CODEC_DEST_HANDSFREE: + + if (AB8500_CODEC_DEST_STATE_ENABLE == state) { + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_ENABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_ENABLED; + p_ab8500_codec_configuration->cr9_endachfl = + AB8500_CODEC_CR9_ENDACHFL_ENABLED; + p_ab8500_codec_configuration->cr9_endachfr = + AB8500_CODEC_CR9_ENDACHFR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehfl = + AB8500_CODEC_CR10_MUTEHFL_DISABLED; + p_ab8500_codec_configuration->cr10_mutehfr = + AB8500_CODEC_CR10_MUTEHFR_DISABLED; + } else { + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_DISABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_DISABLED; + p_ab8500_codec_configuration->cr9_endachfl = + AB8500_CODEC_CR9_ENDACHFL_DISABLED; + p_ab8500_codec_configuration->cr9_endachfr = + AB8500_CODEC_CR9_ENDACHFR_DISABLED; + p_ab8500_codec_configuration->cr10_mutehfl = + AB8500_CODEC_CR10_MUTEHFL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehfr = + AB8500_CODEC_CR10_MUTEHFR_ENABLED; + } + break; + + case AB8500_CODEC_DEST_VIBRATOR_L: + + if (AB8500_CODEC_DEST_STATE_ENABLE == state) { + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_ENABLED; + p_ab8500_codec_configuration->cr9_endacvibl = + AB8500_CODEC_CR9_ENDACVIBL_ENABLED; + p_ab8500_codec_configuration->cr10_mutevibl = + AB8500_CODEC_CR10_MUTEVIBL_DISABLED; + p_ab8500_codec_configuration->cr15_pwmtovibl = + AB8500_CODEC_CR15_PWMTOVIBL_PWM; + p_ab8500_codec_configuration->cr15_pwmlctrl = + AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmnlctrl = + AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmplctrl = + AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE; + } else { + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_DISABLED; + p_ab8500_codec_configuration->cr9_endacvibl = + AB8500_CODEC_CR9_ENDACVIBL_DISABLED; + p_ab8500_codec_configuration->cr10_mutevibl = + AB8500_CODEC_CR10_MUTEVIBL_ENABLED; + p_ab8500_codec_configuration->cr15_pwmtovibl = + AB8500_CODEC_CR15_PWMTOVIBL_DA_PATH; + p_ab8500_codec_configuration->cr15_pwmlctrl = + AB8500_CODEC_CR15_PWMLCTRL_PWMNPLGPOL; + p_ab8500_codec_configuration->cr15_pwmnlctrl = + AB8500_CODEC_CR15_PWMNLCTRL_PWMNLGPOL; + p_ab8500_codec_configuration->cr15_pwmplctrl = + AB8500_CODEC_CR15_PWMPLCTRL_PWMPLGPOL; + } + break; + + case AB8500_CODEC_DEST_VIBRATOR_R: + + if (AB8500_CODEC_DEST_STATE_ENABLE == state) { + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_ENABLED; + p_ab8500_codec_configuration->cr9_endacvibr = + AB8500_CODEC_CR9_ENDACVIBR_ENABLED; + p_ab8500_codec_configuration->cr10_mutevibr = + AB8500_CODEC_CR10_MUTEVIBR_DISABLED; + p_ab8500_codec_configuration->cr15_pwmtovibr = + AB8500_CODEC_CR15_PWMTOVIBR_PWM; + p_ab8500_codec_configuration->cr15_pwmrctrl = + AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmnrctrl = + AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmprctrl = + AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE; + } else { + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_DISABLED; + p_ab8500_codec_configuration->cr9_endacvibr = + AB8500_CODEC_CR9_ENDACVIBR_DISABLED; + p_ab8500_codec_configuration->cr10_mutevibr = + AB8500_CODEC_CR10_MUTEVIBR_ENABLED; + p_ab8500_codec_configuration->cr15_pwmtovibr = + AB8500_CODEC_CR15_PWMTOVIBR_DA_PATH; + p_ab8500_codec_configuration->cr15_pwmrctrl = + AB8500_CODEC_CR15_PWMRCTRL_PWMNPRGPOL; + p_ab8500_codec_configuration->cr15_pwmnrctrl = + AB8500_CODEC_CR15_PWMNRCTRL_PWMNRGPOL; + p_ab8500_codec_configuration->cr15_pwmprctrl = + AB8500_CODEC_CR15_PWMPRCTRL_PWMPRGPOL; + } + break; + + case AB8500_CODEC_DEST_ALL: + + if (AB8500_CODEC_DEST_STATE_ENABLE == state) { + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_ENABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_ENABLED; + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_ENABLED; + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_ENABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_ENABLED; + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_ENABLED; + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_ENABLED; + + p_ab8500_codec_configuration->cr9_endacear = + AB8500_CODEC_CR9_ENDACEAR_ENABLED; + p_ab8500_codec_configuration->cr9_endachfl = + AB8500_CODEC_CR9_ENDACHFL_ENABLED; + p_ab8500_codec_configuration->cr9_endachfr = + AB8500_CODEC_CR9_ENDACHFR_ENABLED; + p_ab8500_codec_configuration->cr9_endacvibl = + AB8500_CODEC_CR9_ENDACVIBL_ENABLED; + p_ab8500_codec_configuration->cr9_endacvibr = + AB8500_CODEC_CR9_ENDACVIBR_ENABLED; + + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_DISABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_DISABLED; + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_DISABLED; + p_ab8500_codec_configuration->cr10_mutehfl = + AB8500_CODEC_CR10_MUTEHFL_DISABLED; + p_ab8500_codec_configuration->cr10_mutehfr = + AB8500_CODEC_CR10_MUTEHFR_DISABLED; + p_ab8500_codec_configuration->cr10_mutevibl = + AB8500_CODEC_CR10_MUTEVIBL_DISABLED; + p_ab8500_codec_configuration->cr10_mutevibr = + AB8500_CODEC_CR10_MUTEVIBR_DISABLED; + + p_ab8500_codec_configuration->cr15_pwmtovibl = + AB8500_CODEC_CR15_PWMTOVIBL_PWM; + p_ab8500_codec_configuration->cr15_pwmlctrl = + AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmnlctrl = + AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmplctrl = + AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmtovibr = + AB8500_CODEC_CR15_PWMTOVIBR_PWM; + p_ab8500_codec_configuration->cr15_pwmrctrl = + AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmnrctrl = + AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmprctrl = + AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE; + } else { + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_DISABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_DISABLED; + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_DISABLED; + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_DISABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_DISABLED; + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_DISABLED; + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_DISABLED; + + p_ab8500_codec_configuration->cr9_endacear = + AB8500_CODEC_CR9_ENDACEAR_DISABLED; + p_ab8500_codec_configuration->cr9_endachfl = + AB8500_CODEC_CR9_ENDACHFL_DISABLED; + p_ab8500_codec_configuration->cr9_endachfr = + AB8500_CODEC_CR9_ENDACHFR_DISABLED; + p_ab8500_codec_configuration->cr9_endacvibl = + AB8500_CODEC_CR9_ENDACVIBL_DISABLED; + p_ab8500_codec_configuration->cr9_endacvibr = + AB8500_CODEC_CR9_ENDACVIBR_DISABLED; + + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_ENABLED; + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehfl = + AB8500_CODEC_CR10_MUTEHFL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehfr = + AB8500_CODEC_CR10_MUTEHFR_ENABLED; + p_ab8500_codec_configuration->cr10_mutevibl = + AB8500_CODEC_CR10_MUTEVIBL_ENABLED; + p_ab8500_codec_configuration->cr10_mutevibr = + AB8500_CODEC_CR10_MUTEVIBR_ENABLED; + + p_ab8500_codec_configuration->cr15_pwmtovibl = + AB8500_CODEC_CR15_PWMTOVIBL_DA_PATH; + p_ab8500_codec_configuration->cr15_pwmlctrl = + AB8500_CODEC_CR15_PWMLCTRL_PWMNPLGPOL; + p_ab8500_codec_configuration->cr15_pwmnlctrl = + AB8500_CODEC_CR15_PWMNLCTRL_PWMNLGPOL; + p_ab8500_codec_configuration->cr15_pwmplctrl = + AB8500_CODEC_CR15_PWMPLCTRL_PWMPLGPOL; + p_ab8500_codec_configuration->cr15_pwmtovibr = + AB8500_CODEC_CR15_PWMTOVIBR_DA_PATH; + p_ab8500_codec_configuration->cr15_pwmrctrl = + AB8500_CODEC_CR15_PWMRCTRL_PWMNPRGPOL; + p_ab8500_codec_configuration->cr15_pwmnrctrl = + AB8500_CODEC_CR15_PWMNRCTRL_PWMNRGPOL; + p_ab8500_codec_configuration->cr15_pwmprctrl = + AB8500_CODEC_CR15_PWMPRCTRL_PWMPRGPOL; + + } + break; + + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_DestPowerControlUpdateCR(); + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_GetVersion */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* This routine populates the pVersion structure with */ +/* the current version of HCL. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* p_version: this parameter is used to return current HCL version. */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_ERROR: if p_version is NULL. */ +/* AB8500_CODEC_OK: if successful */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Re-Entrant */ +/* REENTRANCY ISSUES: No Issues */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_GetVersion(OUT t_version * p_version) +{ + DBGENTER1(" (%lx)", p_version); + if (p_version != NULL) { + p_version->minor = AB8500_CODEC_HCL_MINOR_ID; + p_version->major = AB8500_CODEC_HCL_MAJOR_ID; + p_version->version = AB8500_CODEC_HCL_VERSION_ID; + DBGEXIT0(AB8500_CODEC_OK); + return (AB8500_CODEC_OK); + } else { + DBGEXIT0(AB8500_CODEC_INVALID_PARAMETER); + return (AB8500_CODEC_INVALID_PARAMETER); + } +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SetDbgLevel */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Set the debug level used by the debug module (mask-like value). */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* debug_level: debug level to be set */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_OK: always */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Re-Entrant */ +/* REENTRANCY ISSUES: No Issues */ + +/****************************************************************************/ +/* +PUBLIC t_ab8500_codec_error AB8500_CODEC_SetDbgLevel(IN t_dbg_level dbg_level) +{ + DBGENTER1(" (%d)", dbg_level); + dbg_level = dbg_level; +#ifdef __DEBUG + MY_DEBUG_LEVEL_VAR_NAME = dbg_level; +#endif + DBGEXIT(AB8500_CODEC_OK); + return(AB8500_CODEC_OK); +}*/ + +/****************************************************************************/ +/* NAME: AB8500_CODEC_GetDbgLevel */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Set the debug level used by the debug module (mask-like value). */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* p_dbg_level: this parameter is used to return debug level. */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_ERROR: if p_version is NULL. */ +/* AB8500_CODEC_OK: if successful */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Re-Entrant */ +/* REENTRANCY ISSUES: No Issues */ + +/****************************************************************************/ +/* +PUBLIC t_ab8500_codec_error AB8500_CODEC_GetDbgLevel(OUT t_dbg_level *p_dbg_level) +{ + if (NULL == p_dbg_level) + { + DBGEXIT(AB8500_CODEC_INVALID_PARAMETER); + return(AB8500_CODEC_INVALID_PARAMETER); + } + +#ifdef __DEBUG + * p_dbg_level = MY_DEBUG_LEVEL_VAR_NAME; +#endif + DBGEXIT(AB8500_CODEC_OK); + return(AB8500_CODEC_OK); +} +*/ +/****************************************************************************/ +/* NAME: AB8500_CODEC_ADSlotAllocation */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* AD Data Allocation in slots. */ +/* */ +/* ARGUMENTS */ +/* IN: t_ab8500_codec_slot: The slot to be allocated. */ +/* IN: t_ab8500_codec_cr31_to_cr46_ad_data_allocation: The value */ +/* to be allocated. */ +/* OUT: */ +/* None */ +/* RETURN: */ +/* AB8500_CODEC_INVALID_PARAMETER: If invalid slot number */ +/* AB8500_CODEC_OK: if successful. */ +/* REMARK: */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_ADSlotAllocation + (IN t_ab8500_codec_slot ad_slot, + IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value) { + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + + DBGENTER2(" (%lx %lx)", ad_slot, value); + + if (ad_slot <= AB8500_CODEC_SLOT7) { + ab8500_codec_error = + ab8500_codec_ADSlotAllocationSwitch1(ad_slot, value); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } else if (ad_slot <= AB8500_CODEC_SLOT15) { + ab8500_codec_error = + ab8500_codec_ADSlotAllocationSwitch2(ad_slot, value); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } else if (ad_slot <= AB8500_CODEC_SLOT23) { + ab8500_codec_error = + ab8500_codec_ADSlotAllocationSwitch3(ad_slot, value); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } else if (ad_slot <= AB8500_CODEC_SLOT31) { + ab8500_codec_error = + ab8500_codec_ADSlotAllocationSwitch4(ad_slot, value); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } else { + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + } + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_DASlotAllocation */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Allocate the Audio Interface slot for DA paths. */ +/* */ +/* ARGUMENTS */ +/* IN: t_ab8500_codec_da_channel_number: Channel number 1/2/3/4/5/6 */ +/* IN: t_ab8500_codec_cr51_to_cr56_sltoda: Slot number */ +/* */ +/* OUT: */ +/* None */ +/* RETURN: */ +/* AB8500_CODEC_INVALID_PARAMETER: If invalid channel number */ +/* AB8500_CODEC_OK: if successful. */ +/* REMARK: */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_DASlotAllocation + (IN t_ab8500_codec_da_channel_number channel_number, + IN t_ab8500_codec_cr51_to_cr56_sltoda slot) { + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + t_ab8500_codec_cr0_powerup ab8500_codec_cr0_powerup; + + DBGENTER2(" (%lx %lx)", channel_number, slot); + + p_ab8500_codec_configuration->cr51_da12_voice = + AB8500_CODEC_CR51_DA12_VOICE_LOWLATENCYFILTER; + + switch (channel_number) { + case AB8500_CODEC_DA_CHANNEL_NUMBER_1: + p_ab8500_codec_configuration->cr51_sltoda1 = slot; + break; + + case AB8500_CODEC_DA_CHANNEL_NUMBER_2: + p_ab8500_codec_configuration->cr52_sltoda2 = slot; + break; + + case AB8500_CODEC_DA_CHANNEL_NUMBER_3: + p_ab8500_codec_configuration->cr53_sltoda3 = slot; + break; + + case AB8500_CODEC_DA_CHANNEL_NUMBER_4: + p_ab8500_codec_configuration->cr54_sltoda4 = slot; + break; + + case AB8500_CODEC_DA_CHANNEL_NUMBER_5: + p_ab8500_codec_configuration->cr55_sltoda5 = slot; + break; + + case AB8500_CODEC_DA_CHANNEL_NUMBER_6: + p_ab8500_codec_configuration->cr56_sltoda6 = slot; + break; + + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_cr0_powerup = p_ab8500_codec_configuration->cr0_powerup; + + p_ab8500_codec_configuration->cr0_powerup = + AB8500_CODEC_CR0_POWERUP_OFF; + + ab8500_codec_error = ab8500_codec_UpdateCR0(); + if (AB8500_CODEC_OK != ab8500_codec_error) { + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR51(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR52(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR53(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR54(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR55(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR56(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + p_ab8500_codec_configuration->cr0_powerup = ab8500_codec_cr0_powerup; + + ab8500_codec_error = ab8500_codec_UpdateCR0(); + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_ConfigureBurstFifo */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Configuration for Burst FIFO control */ +/* */ +/* ARGUMENTS */ +/* IN: t_ab8500_codec_burst_fifo_config: structure for configuration of */ +/* burst FIFO */ +/* OUT: */ +/* None */ +/* RETURN: */ +/* AB8500_CODEC_INVALID_PARAMETER: If invalid parameter */ +/* AB8500_CODEC_UNSUPPORTED_FEATURE: If interface 1 selected */ +/* AB8500_CODEC_OK: if successful. */ +/* REMARK: */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +t_ab8500_codec_error AB8500_CODEC_ConfigureBurstFifo(IN + t_ab8500_codec_burst_fifo_config + const *const + p_burst_fifo_config) +{ + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + DBGENTER1(" (%lx)", p_burst_fifo_config); + + if (AB8500_CODEC_AUDIO_INTERFACE_0 == + g_ab8500_codec_system_context.audio_interface) { + if (AB8500_CODEC_CR27_EN_MASTGEN_ENABLED == + p_ab8500_codec_configuration->cr27_en_mastgen) { + p_ab8500_codec_configuration->cr104_bfifoint = + p_burst_fifo_config->cr104_bfifoint; + + p_ab8500_codec_configuration->cr105_bfifotx = + p_burst_fifo_config->cr105_bfifotx; + + p_ab8500_codec_configuration->cr106_bfifofsext = + p_burst_fifo_config->cr106_bfifofsext; + p_ab8500_codec_configuration->cr106_bfifomsk = + p_burst_fifo_config->cr106_bfifomsk; + p_ab8500_codec_configuration->cr106_bfifomstr = + p_burst_fifo_config->cr106_bfifomstr; + p_ab8500_codec_configuration->cr106_bfifostrt = + p_burst_fifo_config->cr106_bfifostrt; + + p_ab8500_codec_configuration->cr107_bfifosampnr = + p_burst_fifo_config->cr107_bfifosampnr; + + p_ab8500_codec_configuration->cr108_bfifowakeup = + p_burst_fifo_config->cr108_bfifowakeup; + + ab8500_codec_error = ab8500_codec_UpdateCR104(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR105(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR106(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR107(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR108(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } else { + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } else { + ab8500_codec_error = AB8500_CODEC_UNSUPPORTED_FEATURE; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_EnableBurstFifo */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Enable the Burst FIFO for Interface 0 */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* None */ +/* RETURN: */ +/* AB8500_CODEC_UNSUPPORTED_FEATURE: If Interface 1 is selected */ +/* AB8500_CODEC_OK: if successful. */ +/* REMARK: */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_EnableBurstFifo(void) +{ + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + DBGENTER0(); + + if (AB8500_CODEC_AUDIO_INTERFACE_0 == + g_ab8500_codec_system_context.audio_interface) { + p_ab8500_codec_configuration->cr29_if0bfifoen = + AB8500_CODEC_CR29_IF0BFIFOEN_BURST_MODE; + + ab8500_codec_error = ab8500_codec_UpdateCR29(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } else { + ab8500_codec_error = AB8500_CODEC_UNSUPPORTED_FEATURE; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_DisableBurstFifo */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Disable the Burst FIFO for Interface 0 */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* None */ +/* RETURN: */ +/* AB8500_CODEC_UNSUPPORTED_FEATURE: If Interface 1 is selected */ +/* AB8500_CODEC_OK: if successful. */ +/* REMARK: */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_DisableBurstFifo(void) +{ + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + DBGENTER0(); + + if (AB8500_CODEC_AUDIO_INTERFACE_0 == + g_ab8500_codec_system_context.audio_interface) { + p_ab8500_codec_configuration->cr29_if0bfifoen = + AB8500_CODEC_CR29_IF0BFIFOEN_NORMAL_MODE; + + ab8500_codec_error = ab8500_codec_UpdateCR29(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } else { + ab8500_codec_error = AB8500_CODEC_UNSUPPORTED_FEATURE; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch1 + (IN t_ab8500_codec_slot ad_slot, + IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value) { + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + switch (ad_slot) { + case AB8500_CODEC_SLOT0: + p_ab8500_codec_configuration->cr31_adotoslot0 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR31(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT1: + p_ab8500_codec_configuration->cr31_adotoslot1 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR31(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT2: + p_ab8500_codec_configuration->cr32_adotoslot2 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR32(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT3: + p_ab8500_codec_configuration->cr32_adotoslot3 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR32(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT4: + p_ab8500_codec_configuration->cr33_adotoslot4 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR33(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT5: + p_ab8500_codec_configuration->cr33_adotoslot5 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR33(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT6: + p_ab8500_codec_configuration->cr34_adotoslot6 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR34(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT7: + p_ab8500_codec_configuration->cr34_adotoslot7 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR34(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch2 + (IN t_ab8500_codec_slot ad_slot, + IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value) { + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + switch (ad_slot) { + case AB8500_CODEC_SLOT8: + p_ab8500_codec_configuration->cr35_adotoslot8 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR35(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT9: + p_ab8500_codec_configuration->cr35_adotoslot9 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR35(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT10: + p_ab8500_codec_configuration->cr36_adotoslot10 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR36(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT11: + p_ab8500_codec_configuration->cr36_adotoslot11 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR36(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT12: + p_ab8500_codec_configuration->cr37_adotoslot12 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR37(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT13: + p_ab8500_codec_configuration->cr37_adotoslot13 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR37(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT14: + p_ab8500_codec_configuration->cr38_adotoslot14 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR38(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT15: + p_ab8500_codec_configuration->cr38_adotoslot15 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR38(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch3 + (IN t_ab8500_codec_slot ad_slot, + IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value) { + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + switch (ad_slot) { + case AB8500_CODEC_SLOT16: + p_ab8500_codec_configuration->cr39_adotoslot16 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR39(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT17: + p_ab8500_codec_configuration->cr39_adotoslot17 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR39(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT18: + p_ab8500_codec_configuration->cr40_adotoslot18 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR40(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT19: + p_ab8500_codec_configuration->cr40_adotoslot19 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR40(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT20: + p_ab8500_codec_configuration->cr41_adotoslot20 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR41(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT21: + p_ab8500_codec_configuration->cr41_adotoslot21 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR41(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT22: + p_ab8500_codec_configuration->cr42_adotoslot22 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR42(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT23: + p_ab8500_codec_configuration->cr42_adotoslot23 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR42(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch4 + (IN t_ab8500_codec_slot ad_slot, + IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value) { + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + switch (ad_slot) { + case AB8500_CODEC_SLOT24: + p_ab8500_codec_configuration->cr43_adotoslot24 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR43(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT25: + p_ab8500_codec_configuration->cr43_adotoslot25 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR43(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT26: + p_ab8500_codec_configuration->cr44_adotoslot26 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR44(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT27: + p_ab8500_codec_configuration->cr44_adotoslot27 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR44(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT28: + p_ab8500_codec_configuration->cr45_adotoslot28 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR45(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT29: + p_ab8500_codec_configuration->cr45_adotoslot29 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR45(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT30: + p_ab8500_codec_configuration->cr46_adotoslot30 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR46(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + case AB8500_CODEC_SLOT31: + p_ab8500_codec_configuration->cr46_adotoslot31 = value; + + ab8500_codec_error = ab8500_codec_UpdateCR46(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_SrcPowerControlSwitch1(IN + t_ab8500_codec_src + src_device, + t_ab8500_codec_src_state + state) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + switch (src_device) { + case AB8500_CODEC_SRC_LINEIN: + + if (AB8500_CODEC_SRC_STATE_ENABLE == state) { + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_ENABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_DISABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_DISABLED; + + p_ab8500_codec_configuration->cr7_linrsel = + AB8500_CODEC_CR7_LINRSEL_LINR; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_ENABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_ENABLED; + } else { + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + + p_ab8500_codec_configuration->cr7_linrsel = + AB8500_CODEC_CR7_LINRSEL_MIC2; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + } + break; + + case AB8500_CODEC_SRC_MICROPHONE_1A: + + if (AB8500_CODEC_SRC_STATE_ENABLE == state) { + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_DISABLED; + + p_ab8500_codec_configuration->cr7_mic1sel = + AB8500_CODEC_CR7_MIC1SEL_MIC1A; + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_ENABLED; + } else { + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_DISABLED; + } + break; + + case AB8500_CODEC_SRC_MICROPHONE_1B: + + if (AB8500_CODEC_SRC_STATE_ENABLE == state) { + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_DISABLED; + + p_ab8500_codec_configuration->cr7_mic1sel = + AB8500_CODEC_CR7_MIC1SEL_MIC1B; + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_ENABLED; + } else { + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_DISABLED; + } + break; + + case AB8500_CODEC_SRC_MICROPHONE_2: + + if (AB8500_CODEC_SRC_STATE_ENABLE == state) { + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_DISABLED; + + p_ab8500_codec_configuration->cr7_linrsel = + AB8500_CODEC_CR7_LINRSEL_MIC2; + } else { + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + + p_ab8500_codec_configuration->cr7_linrsel = + AB8500_CODEC_CR7_LINRSEL_LINR; + } + break; + + case AB8500_CODEC_SRC_D_MICROPHONE_1: + + if (AB8500_CODEC_SRC_STATE_ENABLE == state) { + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_ENABLED; + + p_ab8500_codec_configuration->cr63_ad1sel = + AB8500_CODEC_CR63_AD1SEL_DMIC1_SELECTED; + } else { + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + + p_ab8500_codec_configuration->cr63_ad1sel = + AB8500_CODEC_CR63_AD1SEL_LINLADL_SELECTED; + } + break; + + case AB8500_CODEC_SRC_D_MICROPHONE_2: + + if (AB8500_CODEC_SRC_STATE_ENABLE == state) { + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_ENABLED; + + p_ab8500_codec_configuration->cr63_ad2sel = + AB8500_CODEC_CR63_AD2SEL_DMIC2_SELECTED; + } else { + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + + p_ab8500_codec_configuration->cr63_ad2sel = + AB8500_CODEC_CR63_AD2SEL_LINRADR_SELECTED; + } + break; + + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_SrcPowerControlSwitch2(IN + t_ab8500_codec_src + src_device, + t_ab8500_codec_src_state + state) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + switch (src_device) { + case AB8500_CODEC_SRC_D_MICROPHONE_3: + + if (AB8500_CODEC_SRC_STATE_ENABLE == state) { + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_ENABLED; + + p_ab8500_codec_configuration->cr63_ad3sel = + AB8500_CODEC_CR63_AD3SEL_DMIC3_SELECTED; + } else { + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + + p_ab8500_codec_configuration->cr63_ad3sel = + AB8500_CODEC_CR63_AD3SEL_ADMO_SELECTED; + } + break; + + case AB8500_CODEC_SRC_D_MICROPHONE_4: + + if (AB8500_CODEC_SRC_STATE_ENABLE == state) { + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_ENABLED; + } else { + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + } + break; + + case AB8500_CODEC_SRC_D_MICROPHONE_5: + + if (AB8500_CODEC_SRC_STATE_ENABLE == state) { + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_ENABLED; + + p_ab8500_codec_configuration->cr63_ad5sel = + AB8500_CODEC_CR63_AD5SEL_DMIC5_SELECTED; + } else { + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + + p_ab8500_codec_configuration->cr63_ad5sel = + AB8500_CODEC_CR63_AD5SEL_AMADR_SELECTED; + } + break; + + case AB8500_CODEC_SRC_D_MICROPHONE_6: + + if (AB8500_CODEC_SRC_STATE_ENABLE == state) { + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_ENABLED; + + p_ab8500_codec_configuration->cr63_ad6sel = + AB8500_CODEC_CR63_AD6SEL_DMIC6_SELECTED; + } else { + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + + p_ab8500_codec_configuration->cr63_ad6sel = + AB8500_CODEC_CR63_AD6SEL_ADMO_SELECTED; + } + break; + + case AB8500_CODEC_SRC_ALL: + + if (AB8500_CODEC_SRC_STATE_ENABLE == state) { + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_ENABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_ENABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_ENABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_ENABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_ENABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_ENABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_ENABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_ENABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_ENABLED; + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_ENABLED; + + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_DISABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_DISABLED; + } else { + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_DISABLED; + + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + } + break; + case AB8500_CODEC_SRC_FM_RX: + break; + + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_SetModeAndDirectionUpdateCR(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + t_ab8500_codec_cr0_powerup ab8500_codec_cr0_powerup; + + ab8500_codec_cr0_powerup = p_ab8500_codec_configuration->cr0_powerup; + + p_ab8500_codec_configuration->cr0_powerup = + AB8500_CODEC_CR0_POWERUP_OFF; + + ab8500_codec_error = ab8500_codec_UpdateCR0(); + if (AB8500_CODEC_OK != ab8500_codec_error) { + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR2(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR3(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR26(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR28(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR30(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR63(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + p_ab8500_codec_configuration->cr0_powerup = ab8500_codec_cr0_powerup; + + ab8500_codec_error = ab8500_codec_UpdateCR0(); + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_SetSrcVolumeUpdateCR(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + + ab8500_codec_error = ab8500_codec_UpdateCR20(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR21(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR22(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR23(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR65(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR66(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR67(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR68(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR69(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR70(); + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_SetDestVolumeUpdateCR(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + + ab8500_codec_error = ab8500_codec_UpdateCR16(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR17(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR18(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR19(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR22(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR23(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR71(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR72(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR73(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR74(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR75(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR76(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR79(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR80(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR101(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR102(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR103(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirectionIN(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + switch (g_ab8500_codec_system_context.ab8500_codec_src) { + case AB8500_CODEC_SRC_LINEIN: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_ENABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_ENABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + + p_ab8500_codec_configuration->cr7_linrsel = + AB8500_CODEC_CR7_LINRSEL_LINR; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_ENABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_ENABLED; + + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_DISABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + + break; + + case AB8500_CODEC_SRC_MICROPHONE_1A: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + + p_ab8500_codec_configuration->cr7_mic1sel = + AB8500_CODEC_CR7_MIC1SEL_MIC1A; + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_ENABLED; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + + break; + + case AB8500_CODEC_SRC_MICROPHONE_1B: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + + p_ab8500_codec_configuration->cr7_mic1sel = + AB8500_CODEC_CR7_MIC1SEL_MIC1B; + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_ENABLED; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + + break; + + case AB8500_CODEC_SRC_MICROPHONE_2: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_ENABLED; + + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_ENABLED; + p_ab8500_codec_configuration->cr7_linrsel = + AB8500_CODEC_CR7_LINRSEL_MIC2; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_DISABLED; + + break; + + case AB8500_CODEC_SRC_D_MICROPHONE_1: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_ENABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + + p_ab8500_codec_configuration->cr63_ad1sel = + AB8500_CODEC_CR63_AD1SEL_DMIC1_SELECTED; + + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + + break; + + case AB8500_CODEC_SRC_D_MICROPHONE_2: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_ENABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + + p_ab8500_codec_configuration->cr63_ad2sel = + AB8500_CODEC_CR63_AD2SEL_DMIC2_SELECTED; + + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + + break; + + case AB8500_CODEC_SRC_D_MICROPHONE_3: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_ENABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + + p_ab8500_codec_configuration->cr63_ad3sel = + AB8500_CODEC_CR63_AD3SEL_DMIC3_SELECTED; + + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + + break; + + case AB8500_CODEC_SRC_D_MICROPHONE_4: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_ENABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + + break; + + case AB8500_CODEC_SRC_D_MICROPHONE_5: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_ENABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + + p_ab8500_codec_configuration->cr63_ad5sel = + AB8500_CODEC_CR63_AD5SEL_DMIC5_SELECTED; + + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + + break; + + case AB8500_CODEC_SRC_D_MICROPHONE_6: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_ENABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + + p_ab8500_codec_configuration->cr63_ad6sel = + AB8500_CODEC_CR63_AD6SEL_DMIC6_SELECTED; + + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + + break; + + case AB8500_CODEC_SRC_ALL: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_ENABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_ENABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_ENABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_ENABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_ENABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_ENABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_ENABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_ENABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_ENABLED; + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_ENABLED; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_ENABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_ENABLED; + + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_DISABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_DISABLED; + + break; + + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirectionOUT(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration *p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + + switch (g_ab8500_codec_system_context.ab8500_codec_dest) { + case AB8500_CODEC_DEST_HEADSET: + p_ab8500_codec_configuration->cr7_endrvhsl = + AB8500_CODEC_CR7_ENDRVHSL_ENABLED; + p_ab8500_codec_configuration->cr7_endrvhsr = + AB8500_CODEC_CR7_ENDRVHSR_ENABLED; + + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_DISABLED; + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_ENABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_ENABLED; + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_DISABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_DISABLED; + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_DISABLED; + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_DISABLED; + + p_ab8500_codec_configuration->cr9_endachsl = + AB8500_CODEC_CR9_ENDACHSL_ENABLED; + p_ab8500_codec_configuration->cr9_endachsr = + AB8500_CODEC_CR9_ENDACHSR_ENABLED; + + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_DISABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_DISABLED; + p_ab8500_codec_configuration->cr10_mutehfl = + AB8500_CODEC_CR10_MUTEHFL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehfr = + AB8500_CODEC_CR10_MUTEHFR_ENABLED; + p_ab8500_codec_configuration->cr10_mutevibl = + AB8500_CODEC_CR10_MUTEVIBL_ENABLED; + p_ab8500_codec_configuration->cr10_mutevibr = + AB8500_CODEC_CR10_MUTEVIBR_ENABLED; + + p_ab8500_codec_configuration->cr12_encphs = + AB8500_CODEC_CR12_ENCPHS_ENABLED; + + break; + + case AB8500_CODEC_DEST_EARPIECE: + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_ENABLED; + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_DISABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_DISABLED; + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_DISABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_DISABLED; + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_DISABLED; + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_DISABLED; + + p_ab8500_codec_configuration->cr9_endacear = + AB8500_CODEC_CR9_ENDACEAR_ENABLED; + + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_DISABLED; + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehfl = + AB8500_CODEC_CR10_MUTEHFL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehfr = + AB8500_CODEC_CR10_MUTEHFR_ENABLED; + p_ab8500_codec_configuration->cr10_mutevibl = + AB8500_CODEC_CR10_MUTEVIBL_ENABLED; + p_ab8500_codec_configuration->cr10_mutevibr = + AB8500_CODEC_CR10_MUTEVIBR_ENABLED; + + break; + + case AB8500_CODEC_DEST_HANDSFREE: + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_DISABLED; + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_DISABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_DISABLED; + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_ENABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_ENABLED; + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_DISABLED; + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_DISABLED; + + p_ab8500_codec_configuration->cr9_endachfl = + AB8500_CODEC_CR9_ENDACHFL_ENABLED; + p_ab8500_codec_configuration->cr9_endachfr = + AB8500_CODEC_CR9_ENDACHFR_ENABLED; + + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehfl = + AB8500_CODEC_CR10_MUTEHFL_DISABLED; + p_ab8500_codec_configuration->cr10_mutehfr = + AB8500_CODEC_CR10_MUTEHFR_DISABLED; + p_ab8500_codec_configuration->cr10_mutevibl = + AB8500_CODEC_CR10_MUTEVIBL_ENABLED; + p_ab8500_codec_configuration->cr10_mutevibr = + AB8500_CODEC_CR10_MUTEVIBR_ENABLED; + + break; + + case AB8500_CODEC_DEST_VIBRATOR_L: + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_DISABLED; + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_DISABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_DISABLED; + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_DISABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_DISABLED; + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_ENABLED; + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_DISABLED; + + p_ab8500_codec_configuration->cr9_endacvibl = + AB8500_CODEC_CR9_ENDACVIBL_ENABLED; + + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehfl = + AB8500_CODEC_CR10_MUTEHFL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehfr = + AB8500_CODEC_CR10_MUTEHFR_ENABLED; + p_ab8500_codec_configuration->cr10_mutevibl = + AB8500_CODEC_CR10_MUTEVIBL_DISABLED; + p_ab8500_codec_configuration->cr10_mutevibr = + AB8500_CODEC_CR10_MUTEVIBR_ENABLED; + + p_ab8500_codec_configuration->cr15_pwmtovibl = + AB8500_CODEC_CR15_PWMTOVIBL_PWM; + p_ab8500_codec_configuration->cr15_pwmlctrl = + AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmnlctrl = + AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmplctrl = + AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE; + + break; + + case AB8500_CODEC_DEST_VIBRATOR_R: + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_DISABLED; + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_DISABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_DISABLED; + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_DISABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_DISABLED; + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_DISABLED; + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_ENABLED; + + p_ab8500_codec_configuration->cr9_endacvibr = + AB8500_CODEC_CR9_ENDACVIBR_ENABLED; + + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehfl = + AB8500_CODEC_CR10_MUTEHFL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehfr = + AB8500_CODEC_CR10_MUTEHFR_ENABLED; + p_ab8500_codec_configuration->cr10_mutevibl = + AB8500_CODEC_CR10_MUTEVIBL_ENABLED; + p_ab8500_codec_configuration->cr10_mutevibr = + AB8500_CODEC_CR10_MUTEVIBR_DISABLED; + + p_ab8500_codec_configuration->cr15_pwmtovibr = + AB8500_CODEC_CR15_PWMTOVIBR_PWM; + p_ab8500_codec_configuration->cr15_pwmrctrl = + AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmnrctrl = + AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmprctrl = + AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE; + + break; + + case AB8500_CODEC_DEST_ALL: + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_ENABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_ENABLED; + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_ENABLED; + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_ENABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_ENABLED; + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_ENABLED; + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_ENABLED; + + p_ab8500_codec_configuration->cr9_endacear = + AB8500_CODEC_CR9_ENDACEAR_ENABLED; + p_ab8500_codec_configuration->cr9_endachfl = + AB8500_CODEC_CR9_ENDACHFL_ENABLED; + p_ab8500_codec_configuration->cr9_endachfr = + AB8500_CODEC_CR9_ENDACHFR_ENABLED; + p_ab8500_codec_configuration->cr9_endacvibl = + AB8500_CODEC_CR9_ENDACVIBL_ENABLED; + p_ab8500_codec_configuration->cr9_endacvibr = + AB8500_CODEC_CR9_ENDACVIBR_ENABLED; + + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_DISABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_DISABLED; + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_DISABLED; + p_ab8500_codec_configuration->cr10_mutehfl = + AB8500_CODEC_CR10_MUTEHFL_DISABLED; + p_ab8500_codec_configuration->cr10_mutehfr = + AB8500_CODEC_CR10_MUTEHFR_DISABLED; + p_ab8500_codec_configuration->cr10_mutevibl = + AB8500_CODEC_CR10_MUTEVIBL_DISABLED; + p_ab8500_codec_configuration->cr10_mutevibr = + AB8500_CODEC_CR10_MUTEVIBR_DISABLED; + + p_ab8500_codec_configuration->cr15_pwmtovibl = + AB8500_CODEC_CR15_PWMTOVIBL_PWM; + p_ab8500_codec_configuration->cr15_pwmlctrl = + AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmnlctrl = + AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmplctrl = + AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmtovibr = + AB8500_CODEC_CR15_PWMTOVIBR_PWM; + p_ab8500_codec_configuration->cr15_pwmrctrl = + AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmnrctrl = + AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmprctrl = + AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE; + + break; + + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_DestPowerControlUpdateCR(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + + ab8500_codec_error = ab8500_codec_UpdateCR8(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR9(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR10(); + if (ab8500_codec_error != AB8500_CODEC_OK) { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + + ab8500_codec_error = ab8500_codec_UpdateCR15(); + + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} diff --git a/sound/ab8500_codec_v1_0.c b/sound/ab8500_codec_v1_0.c new file mode 100644 index 00000000000..5df1ca3eae4 --- /dev/null +++ b/sound/ab8500_codec_v1_0.c @@ -0,0 +1,6405 @@ +/*****************************************************************************/ + +/** +* © ST-Ericsson, 2009 - All rights reserved +* Reproduction and Communication of this document is strictly prohibited +* unless specifically authorized in writing by ST-Ericsson +* +* \brief This module provides some support routines for the AB8500 CODEC +* \author ST-Ericsson +*/ +/*****************************************************************************/ + +/*---------------------------------------------------------------------------- + * Includes + *---------------------------------------------------------------------------*/ + +#ifdef CONFIG_U8500_AB8500_CUT10 +#include <mach/ab8500_codec_v1_0.h> +#include <mach/ab8500_codec_p_v1_0.h> +#else /* */ +#include <mach/ab8500_codec.h> +#include <mach/ab8500_codec_p.h> +#endif /* */ + +/*--------------------------------------------------------------------------* + * debug stuff * + *--------------------------------------------------------------------------*/ +#ifdef __DEBUG +#define MY_DEBUG_LEVEL_VAR_NAME myDebugLevel_AB8500_CODEC +#define MY_DEBUG_ID myDebugID_AB8500_CODEC +PRIVATE t_dbg_level MY_DEBUG_LEVEL_VAR_NAME = DEBUG_LEVEL0; +PRIVATE t_dbg_id MY_DEBUG_ID = AB8500_CODEC_HCL_DBG_ID; + +#endif /* */ + +/*--------------------------------------------------------------------------* + * Global data for interrupt mode management * + *--------------------------------------------------------------------------*/ +PRIVATE t_ab8500_codec_system_context g_ab8500_codec_system_context; + +/*--------------------------------------------------------------------------* + * Default Values * + *--------------------------------------------------------------------------*/ +#define AB8500_CODEC_DEFAULT_SLAVE_ADDRESS_OF_CODEC 0xD +#define AB8500_CODEC_DEFAULT_DIRECTION AB8500_CODEC_DIRECTION_OUT + +#define AB8500_CODEC_DEFAULT_MODE_IN AB8500_CODEC_MODE_VOICE +#define AB8500_CODEC_DEFAULT_MODE_OUT AB8500_CODEC_MODE_VOICE + +#define AB8500_CODEC_DEFAULT_INPUT_SRC AB8500_CODEC_SRC_MICROPHONE_1A +#define AB8500_CODEC_DEFAULT_OUTPUT_DEST AB8500_CODEC_DEST_HEADSET + +#define AB8500_CODEC_DEFAULT_VOLUME_LEFT_IN 75 +#define AB8500_CODEC_DEFAULT_VOLUME_RIGHT_IN 75 +#define AB8500_CODEC_DEFAULT_VOLUME_LEFT_OUT 75 +#define AB8500_CODEC_DEFAULT_VOLUME_RIGHT_OUT 75 + +/*--------------------------------------------------------------------- + * PRIVATE APIs + *--------------------------------------------------------------------*/ +PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch1(IN + t_ab8500_codec_slot + ad_slot, + IN + t_ab8500_codec_cr31_to_cr46_ad_data_allocation + value); +PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch2(IN + t_ab8500_codec_slot + ad_slot, + IN + t_ab8500_codec_cr31_to_cr46_ad_data_allocation + value); +PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch3(IN + t_ab8500_codec_slot + ad_slot, + IN + t_ab8500_codec_cr31_to_cr46_ad_data_allocation + value); +PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch4(IN + t_ab8500_codec_slot + ad_slot, + IN + t_ab8500_codec_cr31_to_cr46_ad_data_allocation + value); +PRIVATE t_ab8500_codec_error ab8500_codec_SrcPowerControlSwitch1(IN + t_ab8500_codec_src + src_device, + t_ab8500_codec_src_state + state); +PRIVATE t_ab8500_codec_error ab8500_codec_SrcPowerControlSwitch2(IN + t_ab8500_codec_src + src_device, + t_ab8500_codec_src_state + state); +PRIVATE t_ab8500_codec_error ab8500_codec_SetModeAndDirectionUpdateCR(void); +PRIVATE t_ab8500_codec_error ab8500_codec_SetSrcVolumeUpdateCR(void); +PRIVATE t_ab8500_codec_error ab8500_codec_SetDestVolumeUpdateCR(void); +PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirectionIN(void); +PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirectionOUT(void); +PRIVATE t_ab8500_codec_error ab8500_codec_DestPowerControlUpdateCR(void); + +/********************************************************************************************/ +/* Name: ab8500_codec_SingleWrite */ +/********************************************************************************************/ + PRIVATE t_ab8500_codec_error ab8500_codec_SingleWrite(t_uint8 + register_offset, + t_uint8 data) +{ + return (t_ab8500_codec_error) (AB8500_CODEC_Write + (register_offset, 0x01, &data)); +} + +#if 0 + +/********************************************************************************************/ +/* Name: ab8500_codec_SingleRead */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_SingleRead(t_uint8 + register_offset, + t_uint8 data) +{ + t_uint8 dummy_data = 0xAA; + return (t_ab8500_codec_error) (AB8500_CODEC_Read + (register_offset, 0x01, &dummy_data, + &data)); +} + +#endif /* */ + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR0 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR0(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr0_powerup, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR0_POWERUP ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr0_enaana, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR0_ENAANA ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR0, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR1 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR1(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr1_swreset, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR1_SWRESET ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR1, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR2 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR2(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr2_enad1, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR2_ENAD1 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr2_enad2, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR2_ENAD2 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr2_enad3, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR2_ENAD3 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr2_enad4, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR2_ENAD4 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr2_enad5, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR2_ENAD5 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr2_enad6, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR2_ENAD6 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR2, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR3 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR3(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr3_enda1, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR3_ENDA1 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr3_enda2, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR3_ENDA2 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr3_enda3, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR3_ENDA3 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr3_enda4, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR3_ENDA4 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr3_enda5, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR3_ENDA5 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr3_enda6, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR3_ENDA6 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR3, value)); +} + +#if 0 + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR4 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR4(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr4_lowpowhs, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR4_LOWPOWHS ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr4_lowpowdachs, + AB8500_CODEC_MASK_TWO_BITS, + AB8500_CODEC_CR4_LOWPOWDACHS ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr4_lowpowear, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR4_LOWPOWEAR ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr4_ear_sel_cm, AB8500_CODEC_MASK_TWO_BITS, + AB8500_CODEC_CR4_EAR_SEL_CM ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr4_hs_hp_en, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR4_HS_HP_EN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR4, value)); +} + +#endif /* */ + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR5 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR5(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr5_enmic1, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR5_ENMIC1 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr5_enmic2, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR5_ENMIC2 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr5_enlinl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR5_ENLINL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr5_enlinr, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR5_ENLINR ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr5_mutmic1, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR5_MUTMIC1 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr5_mutmic2, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR5_MUTMIC2 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr5_mutlinl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR5_MUTELINL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr5_mutlinr, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR5_MUTELINR ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR5, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR6 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR6(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr6_endmic1, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR6_ENDMIC1 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr6_endmic2, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR6_ENDMIC2 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr6_endmic3, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR6_ENDMIC3 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr6_endmic4, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR6_ENDMIC4 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr6_endmic5, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR6_ENDMIC5 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr6_endmic6, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR6_ENDMIC6 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR6, value)); +} + + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR7 */ +/********************************************************************************************/ + PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR7(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr7_mic1sel, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR7_MIC1SEL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr7_linrsel, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR7_LINRSEL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr7_endrvhsl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR7_ENDRVHSL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr7_endrvhsr, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR7_ENDRVHSR ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr7_enadcmic, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR7_ENADCMIC ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr7_enadclinl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR7_ENADCLINL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr7_enadclinr, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR7_ENADCLINR ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR7, value)); +} + + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR8 */ +/********************************************************************************************/ + PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR8(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr8_cp_dis_pldwn, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR8_CP_DIS_PLDWN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr8_enear, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR8_ENEAR ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr8_enhsl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR8_ENHSL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr8_enhsr, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR8_ENHSR ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr8_enhfl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR8_ENHFL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr8_enhfr, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR8_ENHFR ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr8_envibl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR8_ENVIBL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr8_envibr, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR8_ENVIBR ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR8, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR9 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR9(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr9_endacear, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR9_ENADACEAR ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr9_endachsl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR9_ENADACHSL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr9_endachsr, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR9_ENADACHSR ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr9_endachfl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR9_ENADACHFL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr9_endachfr, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR9_ENADACHFR ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr9_endacvibl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR9_ENADACVIBL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr9_endacvibr, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR9_ENADACVIBR ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR9, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR10 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR10(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr10_muteear, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR10_MUTEEAR ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr10_mutehsl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR10_MUTEHSL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr10_mutehsr, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR10_MUTEHSR ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR10, value)); +} + +#if 0 + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR11 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR11(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr11_earshortpwd, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR11_ENSHORTPWD ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr11_earshortdis, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR11_EARSHORTDIS ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr11_hsshortdis, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR11_HSSHORTDIS ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr11_hspullden, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR11_HSPULLDEN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr11_hsoscen, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR11_HSOSCEN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr11_hsfaden, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR11_HSFADEN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr11_hszcddis, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR11_HSZCDDIS ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR11, value)); +} + +#endif /* */ + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR12 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR12(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr12_encphs, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR12_ENCPHS ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr12_hsautoen, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR12_HSAUTOEN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR12, value)); +} + +#if 0 + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR13 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR13(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr13_envdet_hthresh, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR13_ENVDET_HTHRESH ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr13_envdet_lthresh, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR13_ENVDET_LTHRESH ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR13, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR14 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR14(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr14_smpslven, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR14_SMPSLVEN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr14_envdetsmpsen, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR14_ENVDETSMPSEN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr14_cplven, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR14_CPLVEN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr14_envdetcpen, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR14_ENVDETCPEN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr14_envet_time, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR14_ENVDET_TIME ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR14, value)); +} + +#endif /* */ + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR15 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR15(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr15_pwmtovibl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR15_PWMTOVIBL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr15_pwmtovibr, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR15_PWMTOVIBR ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr15_pwmlctrl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR15_PWMLCTRL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr15_pwmrctrl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR15_PWMRCTRL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr15_pwmnlctrl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR15_PWMNLCTRL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr15_pwmplctrl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR15_PWMPLCTRL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr15_pwmnrctrl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR15_PWMNRCTRL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr15_pwmprctrl, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR15_PWMPRCTRL ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR15, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR16 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR16(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr16_pwmnlpol, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR16_PWMNLPOL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr16_pwmnldutycycle, + AB8500_CODEC_MASK_SEVEN_BITS, + AB8500_CODEC_CR16_PWMNLDUTYCYCLE ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR16, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR17 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR17(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr17_pwmplpol, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR17_PWMPLPOL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr17_pwmpldutycycle, + AB8500_CODEC_MASK_SEVEN_BITS, + AB8500_CODEC_CR17_PWMLPDUTYCYCLE ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR17, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR18 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR18(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr18_pwmnrpol, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR18_PWMNRPOL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr18_pwmnrdutycycle, + AB8500_CODEC_MASK_SEVEN_BITS, + AB8500_CODEC_CR18_PWMNRDUTYCYCLE ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR18, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR19 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR19(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr19_pwmprpol, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR19_PWMPRPOL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr19_pwmprdutycycle, + AB8500_CODEC_MASK_SEVEN_BITS, + AB8500_CODEC_CR19_PWMRPDUTYCYCLE ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR19, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR20 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR20(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr20_en_se_mic1, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR20_EN_SE_MIC1 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr20_low_pow_mic1, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR20_LOW_POW_MIC1 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr20_mic1_gain, + AB8500_CODEC_MASK_FIVE_BITS, + AB8500_CODEC_CR20_MIC1_GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR20, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR21 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR21(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr21_en_se_mic2, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR21_EN_SE_MIC2 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr21_low_pow_mic2, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR21_LOW_POW_MIC2 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr21_mic2_gain, + AB8500_CODEC_MASK_FIVE_BITS, + AB8500_CODEC_CR21_MIC2_GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR21, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR22 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR22(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr22_hsl_gain, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR22_HSL_GAIN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr22_hsr_gain, AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR22_HSR_GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR22, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR23 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR23(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr23_linl_gain, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR23_LINL_GAIN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr23_linr_gain, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR23_LINR_GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR23, value)); +} + + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR24 */ +/********************************************************************************************/ + PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR24(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr24_lintohsl_gain, + AB8500_CODEC_MASK_FIVE_BITS, + AB8500_CODEC_CR24_LINTOHSL_GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR24, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR25 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR25(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr25_lintohsr_gain, + AB8500_CODEC_MASK_FIVE_BITS, + AB8500_CODEC_CR25_LINTOHSR_GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR25, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR26 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR26(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr26_ad1nh, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR26_AD1NH ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr26_ad2nh, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR26_AD2NH ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr26_ad3nh, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR26_AD3NH ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr26_ad4nh, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR26_AD4NH ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr26_ad1_voice, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR26_AD1_VOICE ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr26_ad2_voice, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR26_AD2_VOICE ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr26_ad3_voice, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR26_AD3_VOICE ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr26_ad4_voice, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR26_AD4_VOICE ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR26, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR27 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR27(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr27_en_mastgen, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR27_EN_MASTGEN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr27_if1_bitclk_osr, + AB8500_CODEC_MASK_TWO_BITS, + AB8500_CODEC_CR27_IF1_BITCLK_OSR ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr27_enfs_bitclk1, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR27_ENFS_BITCLK1 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr27_if0_bitclk_osr, + AB8500_CODEC_MASK_TWO_BITS, + AB8500_CODEC_CR27_IF0_BITCLK_OSR ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr27_enfs_bitclk0, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR27_ENFS_BITCLK0 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR27, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR28 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR28(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr28_fsync0p, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR28_FSYNC0P ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr28_bitclk0p, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR28_BITCLK0P ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr28_if0del, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR28_IF0DEL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr28_if0format, AB8500_CODEC_MASK_TWO_BITS, + AB8500_CODEC_CR28_IF0FORMAT ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr28_if0wl, AB8500_CODEC_MASK_TWO_BITS, + AB8500_CODEC_CR28_IF0WL ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR28, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR29 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR29(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr29_if0datoif1ad, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR29_IF0DATOIF1AD ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr29_if0cktoif1ck, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR29_IF0CKTOIF1CK ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr29_if1master, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR29_IF1MASTER ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr29_if1datoif0ad, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR29_IF1DATOIF0AD ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr29_if1cktoif0ck, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR29_IF1CKTOIF0CK ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr29_if0master, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR29_IF0MASTER ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr29_if0bfifoen, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR29_IF0BFIFOEN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR29, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR30 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR30(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr30_fsync1p, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR30_FSYNC1P ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr30_bitclk1p, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR30_BITCLK1P ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr30_if1del, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR30_IF1DEL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr30_if1format, AB8500_CODEC_MASK_TWO_BITS, + AB8500_CODEC_CR30_IF1FORMAT ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr30_if1wl, AB8500_CODEC_MASK_TWO_BITS, + AB8500_CODEC_CR30_IF1WL ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR30, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR31 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR31(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr31_adotoslot1, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR31_ADOTOSLOT1 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr31_adotoslot0, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR31_ADOTOSLOT0 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR31, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR32 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR32(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr32_adotoslot3, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR32_ADOTOSLOT3 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr32_adotoslot2, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR32_ADOTOSLOT2 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR32, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR33 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR33(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr33_adotoslot5, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR33_ADOTOSLOT5 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr33_adotoslot4, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR33_ADOTOSLOT4 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR33, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR34 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR34(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr34_adotoslot7, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR34_ADOTOSLOT7 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr34_adotoslot6, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR34_ADOTOSLOT6 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR34, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR35 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR35(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr35_adotoslot9, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR35_ADOTOSLOT9 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr35_adotoslot8, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR35_ADOTOSLOT8 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR35, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR36 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR36(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr36_adotoslot11, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR36_ADOTOSLOT11 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr36_adotoslot10, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR36_ADOTOSLOT10 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR36, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR37 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR37(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr37_adotoslot13, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR37_ADOTOSLOT13 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr37_adotoslot12, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR37_ADOTOSLOT12 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR37, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR38 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR38(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr38_adotoslot15, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR38_ADOTOSLOT15 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr38_adotoslot14, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR38_ADOTOSLOT14 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR38, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR39 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR39(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr39_adotoslot17, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR39_ADOTOSLOT17 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr39_adotoslot16, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR39_ADOTOSLOT16 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR39, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR40 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR40(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr40_adotoslot19, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR40_ADOTOSLOT19 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr40_adotoslot18, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR40_ADOTOSLOT18 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR40, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR41 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR41(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr41_adotoslot21, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR41_ADOTOSLOT21 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr41_adotoslot20, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR41_ADOTOSLOT20 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR41, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR42 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR42(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr42_adotoslot23, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR42_ADOTOSLOT23 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr42_adotoslot22, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR42_ADOTOSLOT22 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR42, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR43 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR43(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr43_adotoslot25, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR43_ADOTOSLOT25 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr43_adotoslot24, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR43_ADOTOSLOT24 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR43, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR44 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR44(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr44_adotoslot27, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR44_ADOTOSLOT27 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr44_adotoslot26, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR44_ADOTOSLOT26 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR44, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR45 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR45(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr45_adotoslot29, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR45_ADOTOSLOT29 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr45_adotoslot28, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR45_ADOTOSLOT28 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR45, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR46 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR46(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr46_adotoslot31, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR46_ADOTOSLOT31 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr46_adotoslot30, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR46_ADOTOSLOT30 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR46, value)); +} + +#if 0 + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR47 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR47(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr47_hiz_sl7, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR47_HIZ_SL7 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr47_hiz_sl6, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR47_HIZ_SL6 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr47_hiz_sl5, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR47_HIZ_SL5 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr47_hiz_sl4, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR47_HIZ_SL4 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr47_hiz_sl3, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR47_HIZ_SL3 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr47_hiz_sl2, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR47_HIZ_SL2 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr47_hiz_sl1, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR47_HIZ_SL1 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr47_hiz_sl0, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR47_HIZ_SL0 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR47, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR48 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR48(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr48_hiz_sl15, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR48_HIZ_SL15 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr48_hiz_sl14, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR48_HIZ_SL14 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr48_hiz_sl13, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR48_HIZ_SL13 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr48_hiz_sl12, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR48_HIZ_SL12 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr48_hiz_sl11, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR48_HIZ_SL11 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr48_hiz_sl10, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR48_HIZ_SL10 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr48_hiz_sl9, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR48_HIZ_SL9 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr48_hiz_sl8, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR48_HIZ_SL8 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR48, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR49 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR49(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr49_hiz_sl23, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR49_HIZ_SL23 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr49_hiz_sl22, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR49_HIZ_SL22 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr49_hiz_sl21, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR49_HIZ_SL21 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr49_hiz_sl20, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR49_HIZ_SL20 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr49_hiz_sl19, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR49_HIZ_SL19 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr49_hiz_sl18, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR49_HIZ_SL18 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr49_hiz_sl17, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR49_HIZ_SL17 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr49_hiz_sl16, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR49_HIZ_SL16 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR49, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR50 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR50(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr50_hiz_sl31, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR50_HIZ_SL31 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr50_hiz_sl30, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR50_HIZ_SL30 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr50_hiz_sl29, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR50_HIZ_SL29 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr50_hiz_sl28, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR50_HIZ_SL28 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr50_hiz_sl27, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR50_HIZ_SL27 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr50_hiz_sl26, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR50_HIZ_SL26 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr50_hiz_sl25, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR50_HIZ_SL25 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr50_hiz_sl24, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR50_HIZ_SL24 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR50, value)); +} + +#endif /* */ + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR51 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR51(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr51_da12_voice, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR51_DA12_VOICE ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr51_swapda12_34, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR51_SWAP_DA12_34 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr51_sldai7toslado1, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR51_SLDAI7TOSLADO1 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr51_sltoda1, AB8500_CODEC_MASK_FIVE_BITS, + AB8500_CODEC_CR51_SLTODA1 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR51, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR52 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR52(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr52_sldai8toslado2, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR52_SLDAI8TOSLADO2 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr52_sltoda2, AB8500_CODEC_MASK_FIVE_BITS, + AB8500_CODEC_CR52_SLTODA2 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR52, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR53 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR53(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr53_da34_voice, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR53_DA34_VOICE ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr53_sldai7toslado3, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR53_SLDAI7TOSLADO3 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr53_sltoda3, AB8500_CODEC_MASK_FIVE_BITS, + AB8500_CODEC_CR53_SLTODA3 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR53, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR54 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR54(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr54_sldai8toslado4, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR54_SLDAI8TOSLADO4 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr54_sltoda4, AB8500_CODEC_MASK_FIVE_BITS, + AB8500_CODEC_CR54_SLTODA4 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR54, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR55 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR55(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr55_da56_voice, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR55_DA56_VOICE ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr55_sldai7toslado5, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR55_SLDAI7TOSLADO5 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr55_sltoda5, AB8500_CODEC_MASK_FIVE_BITS, + AB8500_CODEC_CR55_SLTODA5 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR55, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR56 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR56(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr56_sldai8toslado6, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR56_SLDAI8TOSLADO6 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr56_sltoda6, AB8500_CODEC_MASK_FIVE_BITS, + AB8500_CODEC_CR56_SLTODA6 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR56, value)); +} + + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR57 */ +/********************************************************************************************/ + PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR57(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr57_sldai8toslado7, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR57_SLDAI8TOSLADO7 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr57_sltoda7, AB8500_CODEC_MASK_FIVE_BITS, + AB8500_CODEC_CR57_SLTODA7 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR57, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR58 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR58(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr58_sldai7toslado8, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR58_SLDAI7TOSLADO8 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr58_sltoda8, AB8500_CODEC_MASK_FIVE_BITS, + AB8500_CODEC_CR58_SLTODA8 ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR58, value)); +} + +#if 0 + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR59 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR59(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr59_parlhf, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR59_PARLHF ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr59_parlvib, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR59_PARLVIB ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr59_classdvib1_swapen, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR59_CLASSDVIB1SWAPEN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr59_classdvib2_swapen, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR59_CLASSDVIB2SWAPEN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr59_classdhfl_swapen, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR59_CLASSDHFLSWAPEN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr59_classdhfr_swapen, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR59_CLASSDHFRSWAPEN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR59, value)); +} + + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR60 */ +/********************************************************************************************/ + PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR60(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr60_classd_firbyp, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR60_CLASSD_FIR_BYP ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr60_classd_highvolen, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR60_CLASSD_HIGHVOL_EN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR60, value)); +} + + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR61 */ +/********************************************************************************************/ + PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR61(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + + /* 5 bits are Read Only */ + AB8500_CODEC_WRITE_BITS + (value, + (t_uint8) p_ab8500_codec_configuration->cr61_classddith_hpgain, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR61_CLASSD_DITH_HPGAIN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr61_classddith_wgain, + AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR61_CLASSD_DITH_WGAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR61, value)); +} + +#endif /* */ + +/* CR62 is Read Only */ +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR63 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR63(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr63_datohslen, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR63_DATOHSLEN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr63_datohsren, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR63_DATOHSREN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr63_ad1sel, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR63_AD1SEL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr63_ad2sel, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR63_AD2SEL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr63_ad3sel, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR63_AD3SEL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr63_ad5sel, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR63_AD5SEL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr63_ad6sel, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR63_AD6SEL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr63_ancsel, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR63_ANCSEL ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR63, value)); +} + +#if 0 +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR64 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR64(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr64_datohfren, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR64_DATOHFREN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr64_datohflen, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR64_DATOHFLEN ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr64_hfrsel, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR64_HFRSEL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr64_hflsel, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR64_HFLSEL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr64_stfir1sel, AB8500_CODEC_MASK_TWO_BITS, + AB8500_CODEC_CR64_STFIR1SEL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr64_stfir2sel, AB8500_CODEC_MASK_TWO_BITS, + AB8500_CODEC_CR64_STFIR2SEL ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR64, value)); +} + +#endif /* */ + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR65 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR65(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr65_fadedis_ad1, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR65_FADEDIS_AD1 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr65_ad1gain, AB8500_CODEC_MASK_SIX_BITS, + AB8500_CODEC_CR65_AD1GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR65, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR66 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR66(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr66_fadedis_ad2, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR66_FADEDIS_AD2 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr66_ad2gain, AB8500_CODEC_MASK_SIX_BITS, + AB8500_CODEC_CR66_AD2GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR66, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR67 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR67(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr67_fadedis_ad3, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR67_FADEDIS_AD3 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr67_ad3gain, AB8500_CODEC_MASK_SIX_BITS, + AB8500_CODEC_CR67_AD3GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR67, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR68 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR68(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr68_fadedis_ad4, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR68_FADEDIS_AD4 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr68_ad4gain, AB8500_CODEC_MASK_SIX_BITS, + AB8500_CODEC_CR68_AD4GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR68, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR69 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR69(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr69_fadedis_ad5, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR69_FADEDIS_AD5 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr69_ad5gain, AB8500_CODEC_MASK_SIX_BITS, + AB8500_CODEC_CR69_AD5GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR69, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR70 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR70(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr70_fadedis_ad6, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR70_FADEDIS_AD6 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr70_ad6gain, AB8500_CODEC_MASK_SIX_BITS, + AB8500_CODEC_CR70_AD6GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR70, value)); +} + + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR71 */ +/********************************************************************************************/ + PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR71(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr71_fadedis_da1, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR71_FADEDIS_DA1 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr71_da1gain, AB8500_CODEC_MASK_SIX_BITS, + AB8500_CODEC_CR71_DA1GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR71, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR72 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR72(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr72_fadedis_da2, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR72_FADEDIS_DA2 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr72_da2gain, AB8500_CODEC_MASK_SIX_BITS, + AB8500_CODEC_CR72_DA2GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR72, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR73 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR73(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr73_fadedis_da3, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR73_FADEDIS_DA3 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr73_da3gain, AB8500_CODEC_MASK_SIX_BITS, + AB8500_CODEC_CR73_DA3GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR73, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR74 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR74(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr74_fadedis_da4, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR74_FADEDIS_DA4 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr74_da4gain, AB8500_CODEC_MASK_SIX_BITS, + AB8500_CODEC_CR74_DA4GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR74, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR75 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR75(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr75_fadedis_da5, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR75_FADEDIS_DA5 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr75_da5gain, AB8500_CODEC_MASK_SIX_BITS, + AB8500_CODEC_CR75_DA5GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR75, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR76 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR76(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr76_fadedis_da6, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR76_FADEDIS_DA6 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr76_da6gain, AB8500_CODEC_MASK_SIX_BITS, + AB8500_CODEC_CR76_DA6GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR76, value)); +} + +#if 0 + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR77 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR77(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr77_fadedis_ad1l, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR77_FADEDIS_AD1L ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr77_ad1lbgain_to_hfl, + AB8500_CODEC_MASK_SIX_BITS, + AB8500_CODEC_CR77_AD1LBGAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR77, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR78 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR78(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr78_fadedis_ad2l, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR78_FADEDIS_AD2L ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr78_ad2lbgain_to_hfr, + AB8500_CODEC_MASK_SIX_BITS, + AB8500_CODEC_CR78_AD2LBGAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR78, value)); +} + +#endif /* */ + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR79 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR79(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr79_hssinc1, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR79_HSSINC1 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr79_fadedis_hsl, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR79_FADEDIS_HSL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr79_hsldgain, AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR79_HSLDGAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR79, value)); +} + + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR80 */ +/********************************************************************************************/ + PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR80(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr80_fade_speed, + AB8500_CODEC_MASK_TWO_BITS, + AB8500_CODEC_CR80_FADE_SPEED ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr80_fadedis_hsr, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR80_FADEDIS_HSR ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr80_hsrdgain, AB8500_CODEC_MASK_FOUR_BITS, + AB8500_CODEC_CR80_HSRDGAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR80, value)); +} + +#if 0 + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR81 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR81(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr81_stfir1gain, + AB8500_CODEC_MASK_FIVE_BITS, + AB8500_CODEC_CR81_STFIR1GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR81, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR82 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR82(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr82_stfir2gain, + AB8500_CODEC_MASK_FIVE_BITS, + AB8500_CODEC_CR82_STFIR2GAIN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR82, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR83 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR83(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr83_enanc, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR83_ENANC ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr83_anciirinit, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR83_ANCIIRINIT ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr83_ancfirupdate, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR83_ANCFIRUPDATE ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR83, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR84 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR84(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr84_ancinshift, + AB8500_CODEC_MASK_FIVE_BITS, + AB8500_CODEC_CR84_ANCINSHIFT ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR84, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR85 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR85(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr85_ancfiroutshift, + AB8500_CODEC_MASK_FIVE_BITS, + AB8500_CODEC_CR85_ANCFIROUTSHIFT ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR85, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR86 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR86(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr86_ancshiftout, + AB8500_CODEC_MASK_FIVE_BITS, + AB8500_CODEC_CR86_ANCSHIFTOUT ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR86, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR87 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR87(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr87_ancfircoeff_msb, + AB8500_CODEC_MASK_EIGHT_BITS, + AB8500_CODEC_CR87_ANCFIRCOEFF_MSB ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR87, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR88 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR88(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr88_ancfircoeff_lsb, + AB8500_CODEC_MASK_EIGHT_BITS, + AB8500_CODEC_CR88_ANCFIRCOEFF_LSB ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR88, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR89 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR89(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr89_anciircoeff_msb, + AB8500_CODEC_MASK_EIGHT_BITS, + AB8500_CODEC_CR89_ANCIIRCOEFF_MSB ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR89, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR90 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR90(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr90_anciircoeff_lsb, + AB8500_CODEC_MASK_EIGHT_BITS, + AB8500_CODEC_CR90_ANCIIRCOEFF_LSB ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR90, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR91 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR91(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr91_ancwarpdel_msb, + AB8500_CODEC_MASK_EIGHT_BITS, + AB8500_CODEC_CR91_ANCWARPDEL_MSB ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR91, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR92 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR92(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr92_ancwarpdel_lsb, + AB8500_CODEC_MASK_EIGHT_BITS, + AB8500_CODEC_CR92_ANCWARPDEL_LSB ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR92, value)); +} + +/* CR93 is Read Only */ +/* CR94 is Read Only */ +/* CR95 is Read Only */ +/* CR96 is Read Only */ +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR97 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR97(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr97_stfir_set, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR97_STFIR_SET ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr97_stfir_addr, + AB8500_CODEC_MASK_SEVEN_BITS, + AB8500_CODEC_CR97_STFIR_ADDR ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR97, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR98 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR98(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr98_stfir_coeff_msb, + AB8500_CODEC_MASK_EIGHT_BITS, + AB8500_CODEC_CR98_STFIR_COEFF_MSB ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR98, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR99 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR99(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr99_stfir_coeff_lsb, + AB8500_CODEC_MASK_EIGHT_BITS, + AB8500_CODEC_CR99_STFIR_COEFF_LSB ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR99, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR100 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR100(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr100_enstfirs, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR100_ENSTFIRS ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr100_stfirstoif1, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR100_STFIRSTOIF1 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr100_stfir_busy, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR100_STFIR_BUSY ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR100, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR101 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR101(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr101_hsoffst_mask, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR101_HSOFFSTMASK ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr101_fifofull_mask, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR101_FIFOFULLMASK ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr101_fifoempty_mask, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR101_FIFOEMPTYMASK ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr101_dasat_mask, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR101_DASATMASK ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr101_adsat_mask, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR101_ADSATMASK ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr101_addsp_mask, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR101_ADDSPMASK ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr101_dadsp_mask, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR101_DADSPMASK ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr101_firsid_mask, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR101_FIRSIDMASK ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR101, value)); +} + +/* CR102 is Read Only */ + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR103 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR103(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr103_vssready_mask, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR103_VSSREADYMASK ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr103_shorthsl_mask, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR103_SHORTHSLMASK ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr103_shorthsr_mask, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR103_SHORTHSRMASK ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr103_shortear_mask, + AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR103_SHORTEARMASK ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR103, value)); +} + +#endif /* */ + +/* CR104 is Read Only */ + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR105 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR105(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr105_bfifomsk, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR105_BFIFOMASK ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr105_bfifoint, AB8500_CODEC_MASK_SIX_BITS, + AB8500_CODEC_CR105_BFIFOINT ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR105, value)); +} + + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR106 */ +/********************************************************************************************/ + PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR106(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr106_bfifotx, + AB8500_CODEC_MASK_EIGHT_BITS, + AB8500_CODEC_CR106_BFIFOTX ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR106, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR107 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR107(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr107_bfifoexsl, + AB8500_CODEC_MASK_THREE_BITS, + AB8500_CODEC_CR107_BFIFOEXSL ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr107_prebitclk0, + AB8500_CODEC_MASK_THREE_BITS, + AB8500_CODEC_CR107_PREBITCLK0 ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr107_bfifomast, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR107_BFIFOMAST ); + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr107_bfiforun, AB8500_CODEC_MASK_ONE_BIT, + AB8500_CODEC_CR107_BFIFORUN ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR107, value)); +} + + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR108 */ +/********************************************************************************************/ + PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR108(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr108_bfifoframsw, + AB8500_CODEC_MASK_EIGHT_BITS, + AB8500_CODEC_CR108_BFIFOFRAMESW ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR108, value)); +} + +/********************************************************************************************/ +/* Name: ab8500_codec_UpdateCR109 */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR109(void) +{ + t_uint8 value = 0x00; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + AB8500_CODEC_WRITE_BITS (value, + (t_uint8) p_ab8500_codec_configuration-> + cr109_bfifowakeup, + AB8500_CODEC_MASK_EIGHT_BITS, + AB8500_CODEC_CR109_BFIFOWAKEUP ); + return (ab8500_codec_SingleWrite(AB8500_CODEC_CR109, value)); +} + +/* CR110 is Read Only */ + +/* CR111 is Read Only */ + +/********************************************************************************************/ +/* Name: ab8500_codec_Reset() */ + +/********************************************************************************************/ +PRIVATE t_ab8500_codec_error ab8500_codec_Reset(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + p_ab8500_codec_configuration->cr1_swreset = + AB8500_CODEC_CR1_SWRESET_ENABLED; + ab8500_codec_error = ab8500_codec_UpdateCR1(); + if (AB8500_CODEC_OK != ab8500_codec_error) + { + return (ab8500_codec_error); + } + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirection(IN + t_ab8500_codec_direction + ab8500_codec_direction) + /*only IN or OUT must be passed (not INOUT) */ +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + if (AB8500_CODEC_DIRECTION_IN == ab8500_codec_direction) + { + ab8500_codec_error = ab8500_codec_ProgramDirectionIN(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } + if (AB8500_CODEC_DIRECTION_OUT == ab8500_codec_direction) + { + ab8500_codec_error = ab8500_codec_ProgramDirectionOUT(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_SetDirection(IN + t_ab8500_codec_direction + ab8500_codec_direction) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + switch (ab8500_codec_direction) + { + case AB8500_CODEC_DIRECTION_IN: + ab8500_codec_error = + ab8500_codec_ProgramDirection(AB8500_CODEC_DIRECTION_IN); + break; + case AB8500_CODEC_DIRECTION_OUT: + ab8500_codec_error = + ab8500_codec_ProgramDirection(AB8500_CODEC_DIRECTION_OUT); + break; + case AB8500_CODEC_DIRECTION_INOUT: + ab8500_codec_error = + ab8500_codec_ProgramDirection(AB8500_CODEC_DIRECTION_IN); + if (AB8500_CODEC_OK == ab8500_codec_error) + { + ab8500_codec_error = + ab8500_codec_ProgramDirection + (AB8500_CODEC_DIRECTION_OUT); + } + break; + } + if (ab8500_codec_error != AB8500_CODEC_OK) + { + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR5(); + if (AB8500_CODEC_OK != ab8500_codec_error) + { + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR6(); + if (AB8500_CODEC_OK != ab8500_codec_error) + { + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR7(); + if (AB8500_CODEC_OK != ab8500_codec_error) + { + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR8(); + if (AB8500_CODEC_OK != ab8500_codec_error) + { + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR9(); + if (AB8500_CODEC_OK != ab8500_codec_error) + { + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR10(); + if (AB8500_CODEC_OK != ab8500_codec_error) + { + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR12(); + if (AB8500_CODEC_OK != ab8500_codec_error) + { + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR15(); + if (AB8500_CODEC_OK != ab8500_codec_error) + { + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR63(); + if (AB8500_CODEC_OK != ab8500_codec_error) + { + return (ab8500_codec_error); + } + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_Init */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Initialize the global variables & stores the slave address of codec. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* slave_address_of_ab8500_codec: Audio codec slave address */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* Returns AB8500_CODEC_OK */ +/* COMMENTS: */ +/* 1) Saves the supplied slave_address_of_codec in global variable */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_Init(IN t_uint8 + slave_address_of_ab8500_codec) +{ + DBGENTER1(" (%lx)", slave_address_of_ab8500_codec); + g_ab8500_codec_system_context.slave_address_of_ab8500_codec = + slave_address_of_ab8500_codec; + DBGEXIT(AB8500_CODEC_OK); + return (AB8500_CODEC_OK); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_Reset */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Reset the global variables and clear audiocodec settings to default. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_Reset(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + DBGENTER(); + g_ab8500_codec_system_context.ab8500_codec_direction = + AB8500_CODEC_DEFAULT_DIRECTION; + g_ab8500_codec_system_context.ab8500_codec_mode_in = + AB8500_CODEC_DEFAULT_MODE_IN; + g_ab8500_codec_system_context.ab8500_codec_mode_out = + AB8500_CODEC_DEFAULT_MODE_OUT; + g_ab8500_codec_system_context.ab8500_codec_src = + AB8500_CODEC_DEFAULT_INPUT_SRC; + g_ab8500_codec_system_context.ab8500_codec_dest = + AB8500_CODEC_DEFAULT_OUTPUT_DEST; + g_ab8500_codec_system_context.in_left_volume = + AB8500_CODEC_DEFAULT_VOLUME_LEFT_IN; + g_ab8500_codec_system_context.in_right_volume = + AB8500_CODEC_DEFAULT_VOLUME_RIGHT_IN; + g_ab8500_codec_system_context.out_left_volume = + AB8500_CODEC_DEFAULT_VOLUME_LEFT_OUT; + g_ab8500_codec_system_context.out_right_volume = + AB8500_CODEC_DEFAULT_VOLUME_RIGHT_OUT; + ab8500_codec_error = ab8500_codec_Reset(); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SetModeAndDirection */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Configures the whole audio codec to work in audio mode */ +/* (using I2S protocol). */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* direction: select the direction (IN, OUT or INOUT) */ +/* in_mode: codec mode for recording. If direction is OUT only, */ +/* this parameter is ignored. */ +/* out_mode: codec mode for playing. If direction is IN only, */ +/* this parameter is ignored. */ +/* p_tdm_config: TDM configuration required to be configured by user */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_UNSUPPORTED_FEATURE: The API may not allow setting */ +/* 2 different modes, in which case it should return this value. */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SetModeAndDirection + (IN t_ab8500_codec_direction ab8500_codec_direction, + IN t_ab8500_codec_mode ab8500_codec_mode_in, + IN t_ab8500_codec_mode ab8500_codec_mode_out, + IN t_ab8500_codec_tdm_config const *const p_tdm_config ) { + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + DBGENTER3(" (%lx %lx %lx)", ab8500_codec_direction, + ab8500_codec_mode_in, ab8500_codec_mode_out); + if (AB8500_CODEC_AUDIO_INTERFACE_1 == + g_ab8500_codec_system_context.audio_interface) + { + if (AB8500_CODEC_DIRECTION_OUT == ab8500_codec_direction + || AB8500_CODEC_DIRECTION_INOUT == + ab8500_codec_direction ) + { + p_ab8500_codec_configuration->cr3_enda1 = + AB8500_CODEC_CR3_ENDA1_ENABLED; + p_ab8500_codec_configuration->cr3_enda2 = + AB8500_CODEC_CR3_ENDA2_ENABLED; + p_ab8500_codec_configuration->cr3_enda3 = + AB8500_CODEC_CR3_ENDA3_ENABLED; + p_ab8500_codec_configuration->cr3_enda4 = + AB8500_CODEC_CR3_ENDA4_ENABLED; + p_ab8500_codec_configuration->cr3_enda5 = + AB8500_CODEC_CR3_ENDA5_ENABLED; + p_ab8500_codec_configuration->cr3_enda6 = + AB8500_CODEC_CR3_ENDA6_ENABLED; + p_ab8500_codec_configuration->cr27_if1_bitclk_osr = + p_tdm_config->cr27_if1_bitclk_osr; + if (AB8500_CODEC_MODE_HIFI == ab8500_codec_mode_out) + { + p_ab8500_codec_configuration->cr30_fsync1p = + AB8500_CODEC_CR30_FSYNC1P_FALLING_EDGE; + p_ab8500_codec_configuration->cr30_bitclk1p = + AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE; + p_ab8500_codec_configuration->cr30_if1del = + AB8500_CODEC_CR30_IF1DEL_DELAYED; + p_ab8500_codec_configuration->cr30_if1format = + AB8500_CODEC_CR30_IF1FORMAT_I2S_LEFTALIGNED; + p_ab8500_codec_configuration->cr30_if1wl = + p_tdm_config->cr30_if1wl; + } + + else + { + p_ab8500_codec_configuration->cr30_fsync1p = + AB8500_CODEC_CR30_FSYNC1P_FALLING_EDGE; + p_ab8500_codec_configuration->cr30_bitclk1p = + AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE; + p_ab8500_codec_configuration->cr30_if1del = + AB8500_CODEC_CR30_IF1DEL_DELAYED; + p_ab8500_codec_configuration->cr30_if1format = + AB8500_CODEC_CR30_IF1FORMAT_TDM; + p_ab8500_codec_configuration->cr30_if1wl = + p_tdm_config->cr30_if1wl; + } + } + if (AB8500_CODEC_DIRECTION_IN == ab8500_codec_direction + || AB8500_CODEC_DIRECTION_INOUT == + ab8500_codec_direction ) + { + p_ab8500_codec_configuration->cr2_enad1 = + AB8500_CODEC_CR2_ENAD1_ENABLED; + p_ab8500_codec_configuration->cr2_enad2 = + AB8500_CODEC_CR2_ENAD2_ENABLED; + p_ab8500_codec_configuration->cr2_enad3 = + AB8500_CODEC_CR2_ENAD3_ENABLED; + p_ab8500_codec_configuration->cr2_enad4 = + AB8500_CODEC_CR2_ENAD4_ENABLED; + p_ab8500_codec_configuration->cr2_enad5 = + AB8500_CODEC_CR2_ENAD5_ENABLED; + p_ab8500_codec_configuration->cr2_enad6 = + AB8500_CODEC_CR2_ENAD6_ENABLED; + p_ab8500_codec_configuration->cr27_if1_bitclk_osr = + p_tdm_config->cr27_if1_bitclk_osr; + if (AB8500_CODEC_MODE_HIFI == ab8500_codec_mode_in) + { + p_ab8500_codec_configuration->cr30_fsync1p = + AB8500_CODEC_CR30_FSYNC1P_FALLING_EDGE; + p_ab8500_codec_configuration->cr30_bitclk1p = + AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE; + p_ab8500_codec_configuration->cr30_if1del = + AB8500_CODEC_CR30_IF1DEL_DELAYED; + p_ab8500_codec_configuration->cr30_if1format = + AB8500_CODEC_CR30_IF1FORMAT_I2S_LEFTALIGNED; + p_ab8500_codec_configuration->cr30_if1wl = + p_tdm_config->cr30_if1wl; + } + + else + { + p_ab8500_codec_configuration->cr30_fsync1p = + AB8500_CODEC_CR30_FSYNC1P_RISING_EDGE; + p_ab8500_codec_configuration->cr30_bitclk1p = + AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE; + p_ab8500_codec_configuration->cr30_if1del = + AB8500_CODEC_CR30_IF1DEL_NOT_DELAYED; + p_ab8500_codec_configuration->cr30_if1format = + AB8500_CODEC_CR30_IF1FORMAT_TDM; + p_ab8500_codec_configuration->cr30_if1wl = + p_tdm_config->cr30_if1wl; + } + } + } + + else + { + if (AB8500_CODEC_DIRECTION_OUT == ab8500_codec_direction + || AB8500_CODEC_DIRECTION_INOUT == + ab8500_codec_direction ) + { + p_ab8500_codec_configuration->cr3_enda1 = + AB8500_CODEC_CR3_ENDA1_ENABLED; + p_ab8500_codec_configuration->cr3_enda2 = + AB8500_CODEC_CR3_ENDA2_ENABLED; + p_ab8500_codec_configuration->cr3_enda3 = + AB8500_CODEC_CR3_ENDA3_ENABLED; + p_ab8500_codec_configuration->cr3_enda4 = + AB8500_CODEC_CR3_ENDA4_ENABLED; + p_ab8500_codec_configuration->cr3_enda5 = + AB8500_CODEC_CR3_ENDA5_ENABLED; + p_ab8500_codec_configuration->cr3_enda6 = + AB8500_CODEC_CR3_ENDA6_ENABLED; + p_ab8500_codec_configuration->cr27_if0_bitclk_osr = + p_tdm_config->cr27_if0_bitclk_osr; + p_ab8500_codec_configuration->cr63_datohslen = + AB8500_CODEC_CR63_DATOHSLEN_ENABLED; + p_ab8500_codec_configuration->cr63_datohsren = + AB8500_CODEC_CR63_DATOHSREN_ENABLED; + if (AB8500_CODEC_MODE_HIFI == ab8500_codec_mode_out) + { + p_ab8500_codec_configuration->cr28_fsync0p = + AB8500_CODEC_CR28_FSYNC0P_FALLING_EDGE; + p_ab8500_codec_configuration->cr28_bitclk0p = p_tdm_config->cr28_bitclk0p; /*AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE; */ + p_ab8500_codec_configuration->cr28_if0del = p_tdm_config->cr28_if0del; /*AB8500_CODEC_CR28_IF0DEL_DELAYED; */ + p_ab8500_codec_configuration->cr28_if0format = + AB8500_CODEC_CR28_IF0FORMAT_I2S_LEFTALIGNED; + p_ab8500_codec_configuration->cr28_if0wl = + p_tdm_config->cr28_if0wl; + } + + else + { + p_ab8500_codec_configuration->cr28_fsync0p = + AB8500_CODEC_CR28_FSYNC0P_FALLING_EDGE; + p_ab8500_codec_configuration->cr28_bitclk0p = p_tdm_config->cr28_bitclk0p; /*AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE; */ + p_ab8500_codec_configuration->cr28_if0del = p_tdm_config->cr28_if0del; /*AB8500_CODEC_CR28_IF0DEL_DELAYED; */ + p_ab8500_codec_configuration->cr28_if0format = + AB8500_CODEC_CR28_IF0FORMAT_TDM; + p_ab8500_codec_configuration->cr28_if0wl = + p_tdm_config->cr28_if0wl; + } + } + if (AB8500_CODEC_DIRECTION_IN == ab8500_codec_direction + || AB8500_CODEC_DIRECTION_INOUT == + ab8500_codec_direction ) + { + p_ab8500_codec_configuration->cr2_enad1 = + AB8500_CODEC_CR2_ENAD1_ENABLED; + p_ab8500_codec_configuration->cr2_enad2 = + AB8500_CODEC_CR2_ENAD2_ENABLED; + p_ab8500_codec_configuration->cr2_enad3 = + AB8500_CODEC_CR2_ENAD3_ENABLED; + p_ab8500_codec_configuration->cr2_enad4 = + AB8500_CODEC_CR2_ENAD4_ENABLED; + p_ab8500_codec_configuration->cr2_enad5 = + AB8500_CODEC_CR2_ENAD5_ENABLED; + p_ab8500_codec_configuration->cr2_enad6 = + AB8500_CODEC_CR2_ENAD6_ENABLED; + p_ab8500_codec_configuration->cr26_ad1_voice = + AB8500_CODEC_CR26_AD1_VOICE_LOWLATENCYFILTER; + p_ab8500_codec_configuration->cr26_ad2_voice = + AB8500_CODEC_CR26_AD2_VOICE_LOWLATENCYFILTER; + p_ab8500_codec_configuration->cr26_ad3_voice = + AB8500_CODEC_CR26_AD3_VOICE_LOWLATENCYFILTER; + p_ab8500_codec_configuration->cr26_ad4_voice = + AB8500_CODEC_CR26_AD4_VOICE_LOWLATENCYFILTER; + p_ab8500_codec_configuration->cr27_if0_bitclk_osr = + p_tdm_config->cr27_if0_bitclk_osr; + if (AB8500_CODEC_MODE_HIFI == ab8500_codec_mode_in) + { + p_ab8500_codec_configuration->cr28_fsync0p = + AB8500_CODEC_CR28_FSYNC0P_RISING_EDGE; + p_ab8500_codec_configuration->cr28_bitclk0p = p_tdm_config->cr28_bitclk0p; /*AB8500_CODEC_CR28_BITCLK0P_RISING_EDGE; */ + p_ab8500_codec_configuration->cr28_if0del = p_tdm_config->cr28_if0del; /*AB8500_CODEC_CR28_IF0DEL_NOT_DELAYED; */ + p_ab8500_codec_configuration->cr28_if0format = + AB8500_CODEC_CR28_IF0FORMAT_I2S_LEFTALIGNED; + p_ab8500_codec_configuration->cr28_if0wl = + p_tdm_config->cr28_if0wl; + } + + else + { + p_ab8500_codec_configuration->cr28_fsync0p = + AB8500_CODEC_CR28_FSYNC0P_RISING_EDGE; + p_ab8500_codec_configuration->cr28_bitclk0p = p_tdm_config->cr28_bitclk0p; /*AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE; */ + p_ab8500_codec_configuration->cr28_if0del = p_tdm_config->cr28_if0del; /*AB8500_CODEC_CR28_IF0DEL_NOT_DELAYED; */ + p_ab8500_codec_configuration->cr28_if0format = + AB8500_CODEC_CR28_IF0FORMAT_TDM; + p_ab8500_codec_configuration->cr28_if0wl = + p_tdm_config->cr28_if0wl; + } + } + } + ab8500_codec_error = ab8500_codec_SetModeAndDirectionUpdateCR(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + g_ab8500_codec_system_context.ab8500_codec_direction = + ab8500_codec_direction; + g_ab8500_codec_system_context.ab8500_codec_mode_in = + ab8500_codec_mode_in; + g_ab8500_codec_system_context.ab8500_codec_mode_out = + ab8500_codec_mode_out; + ab8500_codec_error = + ab8500_codec_SetDirection(ab8500_codec_direction); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SetSrcVolume */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Sets the record volumes. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* t_ab8500_codec_src: select source device for recording. */ +/* in_left_volume: record volume for left channel. */ +/* in_right_volume: record volume for right channel. */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SetSrcVolume + (IN t_ab8500_codec_src src_device, IN t_uint8 in_left_volume, + IN t_uint8 in_right_volume ) { + t_ab8500_codec_error ab8500_codec_error; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + DBGENTER3(" (%lx %lx %lx)", src_device, in_left_volume, + in_right_volume); + if (in_left_volume > AB8500_CODEC_MAX_VOLUME) + { + in_left_volume = AB8500_CODEC_MAX_VOLUME; + } + if (in_right_volume > AB8500_CODEC_MAX_VOLUME) + { + in_right_volume = AB8500_CODEC_MAX_VOLUME; + } + g_ab8500_codec_system_context.in_left_volume = in_left_volume; + g_ab8500_codec_system_context.in_right_volume = in_right_volume; + p_ab8500_codec_configuration->cr65_ad1gain = + AB8500_CODEC_AD_D_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_AD_D_VOLUME_MAX - + AB8500_CODEC_AD_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr66_ad2gain = + AB8500_CODEC_AD_D_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_AD_D_VOLUME_MAX - + AB8500_CODEC_AD_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr67_ad3gain = + AB8500_CODEC_AD_D_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_AD_D_VOLUME_MAX - + AB8500_CODEC_AD_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr68_ad4gain = + AB8500_CODEC_AD_D_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_AD_D_VOLUME_MAX - + AB8500_CODEC_AD_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr69_ad5gain = + AB8500_CODEC_AD_D_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_AD_D_VOLUME_MAX - + AB8500_CODEC_AD_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr70_ad6gain = + AB8500_CODEC_AD_D_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_AD_D_VOLUME_MAX - + AB8500_CODEC_AD_D_VOLUME_MIN)) / 100; + + /* Set mininimum volume if volume is zero */ + switch (src_device) + { + case AB8500_CODEC_SRC_LINEIN: + p_ab8500_codec_configuration->cr23_linl_gain = + AB8500_CODEC_LINEIN_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_LINEIN_VOLUME_MAX - + AB8500_CODEC_LINEIN_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr23_linr_gain = + AB8500_CODEC_LINEIN_VOLUME_MIN + + (in_right_volume * + (AB8500_CODEC_LINEIN_VOLUME_MAX - + AB8500_CODEC_LINEIN_VOLUME_MIN)) / 100; + break; + case AB8500_CODEC_SRC_MICROPHONE_1A: + case AB8500_CODEC_SRC_MICROPHONE_1B: + p_ab8500_codec_configuration->cr20_mic1_gain = + AB8500_CODEC_MIC_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_MIC_VOLUME_MAX - + AB8500_CODEC_MIC_VOLUME_MIN)) / 100; + break; + case AB8500_CODEC_SRC_MICROPHONE_2: + p_ab8500_codec_configuration->cr21_mic2_gain = + AB8500_CODEC_MIC_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_MIC_VOLUME_MAX - + AB8500_CODEC_MIC_VOLUME_MIN)) / 100; + break; + case AB8500_CODEC_SRC_D_MICROPHONE_1: + break; + case AB8500_CODEC_SRC_D_MICROPHONE_2: + break; + case AB8500_CODEC_SRC_D_MICROPHONE_3: + break; + case AB8500_CODEC_SRC_D_MICROPHONE_4: + break; + case AB8500_CODEC_SRC_D_MICROPHONE_5: + break; + case AB8500_CODEC_SRC_D_MICROPHONE_6: + break; + case AB8500_CODEC_SRC_ALL: + p_ab8500_codec_configuration->cr23_linl_gain = + AB8500_CODEC_LINEIN_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_LINEIN_VOLUME_MAX - + AB8500_CODEC_LINEIN_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr23_linr_gain = + AB8500_CODEC_LINEIN_VOLUME_MIN + + (in_right_volume * + (AB8500_CODEC_LINEIN_VOLUME_MAX - + AB8500_CODEC_LINEIN_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr20_mic1_gain = + AB8500_CODEC_MIC_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_MIC_VOLUME_MAX - + AB8500_CODEC_MIC_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr21_mic2_gain = + AB8500_CODEC_MIC_VOLUME_MIN + + (in_left_volume * + (AB8500_CODEC_MIC_VOLUME_MAX - + AB8500_CODEC_MIC_VOLUME_MIN)) / 100; + break; + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_SetSrcVolumeUpdateCR(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SetDestVolume */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Sets the play volumes. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* out_left_volume: play volume for left channel. */ +/* out_right_volume: play volume for right channel. */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SetDestVolume + (IN t_ab8500_codec_dest dest_device, IN t_uint8 out_left_volume, + IN t_uint8 out_right_volume ) { + t_ab8500_codec_error ab8500_codec_error; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + DBGENTER3(" (%lx %lx %lx)", dest_device, out_left_volume, + out_right_volume); + if (out_left_volume > AB8500_CODEC_MAX_VOLUME) + { + out_left_volume = AB8500_CODEC_MAX_VOLUME; + } + if (out_right_volume > AB8500_CODEC_MAX_VOLUME) + { + out_right_volume = AB8500_CODEC_MAX_VOLUME; + } + g_ab8500_codec_system_context.out_left_volume = out_left_volume; + g_ab8500_codec_system_context.out_right_volume = out_right_volume; + p_ab8500_codec_configuration->cr71_da1gain = + AB8500_CODEC_DA_D_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_DA_D_VOLUME_MAX - + AB8500_CODEC_DA_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr72_da2gain = + AB8500_CODEC_DA_D_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_DA_D_VOLUME_MAX - + AB8500_CODEC_DA_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr73_da3gain = + AB8500_CODEC_DA_D_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_DA_D_VOLUME_MAX - + AB8500_CODEC_DA_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr74_da4gain = + AB8500_CODEC_DA_D_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_DA_D_VOLUME_MAX - + AB8500_CODEC_DA_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr75_da5gain = + AB8500_CODEC_DA_D_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_DA_D_VOLUME_MAX - + AB8500_CODEC_DA_D_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr76_da6gain = + AB8500_CODEC_DA_D_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_DA_D_VOLUME_MAX - + AB8500_CODEC_DA_D_VOLUME_MIN)) / 100; + + /* Set mininimum volume if volume is zero */ + switch (dest_device) + { + case AB8500_CODEC_DEST_HEADSET: + p_ab8500_codec_configuration->cr22_hsl_gain = + AB8500_CODEC_HEADSET_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_HEADSET_VOLUME_MAX - + AB8500_CODEC_HEADSET_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr22_hsr_gain = + AB8500_CODEC_HEADSET_VOLUME_MIN + + (out_right_volume * + (AB8500_CODEC_HEADSET_VOLUME_MAX - + AB8500_CODEC_HEADSET_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr79_hsldgain = + AB8500_CODEC_HEADSET_D_VOLUME_0DB; + p_ab8500_codec_configuration->cr80_hsrdgain = + AB8500_CODEC_HEADSET_D_VOLUME_0DB; + break; + case AB8500_CODEC_DEST_EARPIECE: + p_ab8500_codec_configuration->cr79_hsldgain = + AB8500_CODEC_HEADSET_D_VOLUME_0DB; + break; + case AB8500_CODEC_DEST_HANDSFREE: + break; + case AB8500_CODEC_DEST_VIBRATOR_L: + p_ab8500_codec_configuration->cr16_pwmnldutycycle = + AB8500_CODEC_VIBRATOR_VOLUME_MIN; + p_ab8500_codec_configuration->cr17_pwmpldutycycle = + AB8500_CODEC_VIBRATOR_VOLUME_MIN + + (out_right_volume * + (AB8500_CODEC_VIBRATOR_VOLUME_MAX - + AB8500_CODEC_VIBRATOR_VOLUME_MIN)) / 100; + break; + case AB8500_CODEC_DEST_VIBRATOR_R: + p_ab8500_codec_configuration->cr18_pwmnrdutycycle = + AB8500_CODEC_VIBRATOR_VOLUME_MIN; + p_ab8500_codec_configuration->cr19_pwmprdutycycle = + AB8500_CODEC_VIBRATOR_VOLUME_MIN + + (out_right_volume * + (AB8500_CODEC_VIBRATOR_VOLUME_MAX - + AB8500_CODEC_VIBRATOR_VOLUME_MIN)) / 100; + break; + case AB8500_CODEC_DEST_ALL: + p_ab8500_codec_configuration->cr22_hsl_gain = + AB8500_CODEC_HEADSET_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_HEADSET_VOLUME_MAX - + AB8500_CODEC_HEADSET_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr22_hsr_gain = + AB8500_CODEC_HEADSET_VOLUME_MIN + + (out_right_volume * + (AB8500_CODEC_HEADSET_VOLUME_MAX - + AB8500_CODEC_HEADSET_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr79_hsldgain = + AB8500_CODEC_HEADSET_D_VOLUME_0DB; + break; + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_SetDestVolumeUpdateCR(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SetMasterMode */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Set the Audio Codec in Master mode. */ +/* */ +/* ARGUMENTS */ +/* IN: t_codec_master_mode: Enable/disable master mode */ +/* OUT: */ +/* None */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/* REMARK: Call this API after calling AB8500_CODEC_SetModeAndDirection() API*/ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SetMasterMode(IN + t_ab8500_codec_master_mode + mode) +{ + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + DBGENTER0(); + if (AB8500_CODEC_AUDIO_INTERFACE_1 == + g_ab8500_codec_system_context.audio_interface) + { + p_ab8500_codec_configuration->cr27_en_mastgen = + AB8500_CODEC_CR27_EN_MASTGEN_ENABLED; + p_ab8500_codec_configuration->cr27_enfs_bitclk1 = + AB8500_CODEC_CR27_ENFS_BITCLK1_ENABLED; + if (AB8500_CODEC_MASTER_MODE_ENABLE == mode) + { + p_ab8500_codec_configuration->cr29_if1master = + AB8500_CODEC_CR29_IF1MASTER_FS1CK1_OUTPUT; + } + + else + { + p_ab8500_codec_configuration->cr29_if1master = + AB8500_CODEC_CR29_IF1MASTER_FS1CK1_INPUT; + } + } + + else + { + p_ab8500_codec_configuration->cr27_en_mastgen = + AB8500_CODEC_CR27_EN_MASTGEN_ENABLED; + p_ab8500_codec_configuration->cr27_enfs_bitclk0 = + AB8500_CODEC_CR27_ENFS_BITCLK0_ENABLED; + if (AB8500_CODEC_MASTER_MODE_ENABLE == mode) + { + p_ab8500_codec_configuration->cr29_if0master = + AB8500_CODEC_CR29_IF0MASTER_FS0CK0_OUTPUT; + } + + else + { + p_ab8500_codec_configuration->cr29_if0master = + AB8500_CODEC_CR29_IF0MASTER_FS0CK0_INPUT; + } + } + ab8500_codec_error = ab8500_codec_UpdateCR27(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR29(); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SelectInput */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Select input source for recording. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* input_src: select input source for recording when several sources */ +/* are supported in codec. */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_INVALID_PARAMETER: If input_src provided is invalid */ +/* by the codec hardware in use. */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SelectInput(IN t_ab8500_codec_src + ab8500_codec_src) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + DBGENTER1(" (%lx)", ab8500_codec_src); + g_ab8500_codec_system_context.ab8500_codec_src = ab8500_codec_src; + ab8500_codec_error = + ab8500_codec_SetDirection(AB8500_CODEC_DIRECTION_IN); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SelectOutput */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Select output desination for playing. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* output_dest: select output destination for playing when several are */ +/* supported by codec hardware. */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_INVALID_PARAMETER: If output_src provided is invalid */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SelectOutput(IN t_ab8500_codec_dest + ab8500_codec_dest) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + g_ab8500_codec_system_context.ab8500_codec_dest = ab8500_codec_dest; + DBGENTER1(" (%lx)", ab8500_codec_dest); + ab8500_codec_error = + ab8500_codec_SetDirection(AB8500_CODEC_DIRECTION_OUT); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_PowerDown */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Shuts the audio codec down completely. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* OUT: */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_PowerDown(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + g_ab8500_codec_system_context.ab8500_codec_configuration.cr0_powerup = + AB8500_CODEC_CR0_POWERUP_OFF; + ab8500_codec_error = ab8500_codec_UpdateCR0(); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_PowerUp */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Switch on the audio codec. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* None */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_PowerUp(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + DBGENTER(); + g_ab8500_codec_system_context.ab8500_codec_configuration.cr0_powerup = + AB8500_CODEC_CR0_POWERUP_ON; + g_ab8500_codec_system_context.ab8500_codec_configuration.cr0_enaana = + AB8500_CODEC_CR0_ENAANA_ON; + ab8500_codec_error = ab8500_codec_UpdateCR0(); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SelectInterface */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Select the Audio Interface 0 or 1. */ +/* */ +/* ARGUMENTS */ +/* IN: t_ab8500_codec_audio_interface: The selected interface */ +/* */ +/* OUT: */ +/* None */ +/* RETURN: */ +/* AB8500_CODEC_OK: Always. */ +/* REMARK: Call this API before using a function of the low level drivers */ +/* to select the interface that you want to configure */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SelectInterface(IN + t_ab8500_codec_audio_interface + audio_interface) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + DBGENTER0(); + g_ab8500_codec_system_context.audio_interface = audio_interface; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_GetInterface */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Get the Audio Interface 0 or 1. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: p_audio_interface: Store the selected interface */ +/* RETURN: */ +/* AB8500_CODEC_OK: Always */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Re-Entrant */ +/* REENTRANCY ISSUES: No Issues */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_GetInterface(OUT + t_ab8500_codec_audio_interface + * p_audio_interface) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + DBGENTER0(); + *p_audio_interface = g_ab8500_codec_system_context.audio_interface; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SetAnalogLoopback */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Sets Line-In to HeadSet loopback with the required gain. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* out_left_volume: play volume for left channel. */ +/* out_right_volume: play volume for right channel. */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SetAnalogLoopback(IN t_uint8 + out_left_volume, + IN t_uint8 + out_right_volume) +{ + t_ab8500_codec_error ab8500_codec_error; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + DBGENTER2(" (%lx %lx)", out_left_volume, out_right_volume); + if (out_left_volume > AB8500_CODEC_MAX_VOLUME) + { + out_left_volume = AB8500_CODEC_MAX_VOLUME; + } + if (out_right_volume > AB8500_CODEC_MAX_VOLUME) + { + out_right_volume = AB8500_CODEC_MAX_VOLUME; + } + g_ab8500_codec_system_context.out_left_volume = out_left_volume; + g_ab8500_codec_system_context.out_right_volume = out_right_volume; + p_ab8500_codec_configuration->cr24_lintohsl_gain = + AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN + + (out_left_volume * + (AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MAX - + AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN)) / 100; + p_ab8500_codec_configuration->cr25_lintohsr_gain = + AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN + + (out_right_volume * + (AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MAX - + AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN)) / 100; + ab8500_codec_error = ab8500_codec_UpdateCR24(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR25(); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_RemoveAnalogLoopback */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Remove Line-In to HeadSet loopback. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_RemoveAnalogLoopback(void) +{ + t_ab8500_codec_error ab8500_codec_error; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + DBGENTER0(); + p_ab8500_codec_configuration->cr24_lintohsl_gain = + AB8500_CODEC_LINEIN_TO_HS_L_R_LOOP_OPEN; + p_ab8500_codec_configuration->cr25_lintohsr_gain = + AB8500_CODEC_LINEIN_TO_HS_L_R_LOOP_OPEN; + ab8500_codec_error = ab8500_codec_UpdateCR24(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR25(); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_EnableBypassMode */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Enables IF0 to IF1 path or vice versa */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_EnableBypassMode(void) +{ + t_ab8500_codec_error ab8500_codec_error; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + DBGENTER0(); + if (AB8500_CODEC_AUDIO_INTERFACE_1 == + g_ab8500_codec_system_context.audio_interface) + { + p_ab8500_codec_configuration->cr29_if1datoif0ad = + AB8500_CODEC_CR29_IF1DATOIF0AD_SENT; + p_ab8500_codec_configuration->cr29_if1cktoif0ck = + AB8500_CODEC_CR29_IF1CKTOIF0CK_SENT; + } + + else + { + p_ab8500_codec_configuration->cr29_if0datoif1ad = + AB8500_CODEC_CR29_IF0DATOIF1AD_SENT; + p_ab8500_codec_configuration->cr29_if0cktoif1ck = + AB8500_CODEC_CR29_IF0CKTOIF1CK_SENT; + } + ab8500_codec_error = ab8500_codec_UpdateCR29(); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_DisableBypassMode */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Disables IF0 to IF1 path or vice versa */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_DisableBypassMode(void) +{ + t_ab8500_codec_error ab8500_codec_error; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + DBGENTER0(); + if (AB8500_CODEC_AUDIO_INTERFACE_1 == + g_ab8500_codec_system_context.audio_interface) + { + p_ab8500_codec_configuration->cr29_if1datoif0ad = + AB8500_CODEC_CR29_IF1DATOIF0AD_NOTSENT; + p_ab8500_codec_configuration->cr29_if1cktoif0ck = + AB8500_CODEC_CR29_IF1CKTOIF0CK_NOTSENT; + } + + else + { + p_ab8500_codec_configuration->cr29_if0datoif1ad = + AB8500_CODEC_CR29_IF0DATOIF1AD_NOTSENT; + p_ab8500_codec_configuration->cr29_if0cktoif1ck = + AB8500_CODEC_CR29_IF0CKTOIF1CK_NOTSENT; + } + ab8500_codec_error = ab8500_codec_UpdateCR29(); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SrcPowerControl */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Enables/Disables & UnMute/Mute the desired source */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* t_ab8500_codec_src: select source device for enabling/disabling. */ +/* t_ab8500_codec_src_state: Enable/Disable */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_SrcPowerControl(IN + t_ab8500_codec_src + src_device, + t_ab8500_codec_src_state + state) +{ + t_ab8500_codec_error ab8500_codec_error; + DBGENTER2(" (%lx %lx)", src_device, state); + if (src_device <= AB8500_CODEC_SRC_D_MICROPHONE_2) + { + ab8500_codec_error = + ab8500_codec_SrcPowerControlSwitch1(src_device, state); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } + + else if (src_device <= AB8500_CODEC_SRC_ALL) + { + ab8500_codec_error = + ab8500_codec_SrcPowerControlSwitch2(src_device, state); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } + + else + { + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR5(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR6(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR7(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR63(); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_DestPowerControl */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Enables/Disables & UnMute/Mute the desired destination */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* t_ab8500_codec_dest: select destination device for enabling/disabling. */ +/* t_ab8500_codec_dest_state: Enable/Disable */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */ +/* AB8500_CODEC_OK: if successful. */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_DestPowerControl(IN + t_ab8500_codec_dest + dest_device, + t_ab8500_codec_dest_state + state) +{ + t_ab8500_codec_error ab8500_codec_error; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context.ab8500_codec_configuration; + DBGENTER2(" (%lx %lx)", dest_device, state); + switch (dest_device) + { + case AB8500_CODEC_DEST_HEADSET: + if (AB8500_CODEC_DEST_STATE_ENABLE == state) + { + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_ENABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_DISABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_DISABLED; + p_ab8500_codec_configuration->cr9_endachsl = + AB8500_CODEC_CR9_ENDACHSL_ENABLED; + p_ab8500_codec_configuration->cr9_endachsr = + AB8500_CODEC_CR9_ENDACHSR_ENABLED; + } + + else + { + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_DISABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_DISABLED; + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_ENABLED; + p_ab8500_codec_configuration->cr9_endachsl = + AB8500_CODEC_CR9_ENDACHSL_DISABLED; + p_ab8500_codec_configuration->cr9_endachsr = + AB8500_CODEC_CR9_ENDACHSR_DISABLED; + } + break; + case AB8500_CODEC_DEST_EARPIECE: + if (AB8500_CODEC_DEST_STATE_ENABLE == state) + { + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_ENABLED; + p_ab8500_codec_configuration->cr9_endacear = + AB8500_CODEC_CR9_ENDACEAR_ENABLED; + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_DISABLED; + } + + else + { + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_DISABLED; + p_ab8500_codec_configuration->cr9_endacear = + AB8500_CODEC_CR9_ENDACEAR_DISABLED; + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_ENABLED; + } + break; + case AB8500_CODEC_DEST_HANDSFREE: + if (AB8500_CODEC_DEST_STATE_ENABLE == state) + { + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_ENABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_ENABLED; + p_ab8500_codec_configuration->cr9_endachfl = + AB8500_CODEC_CR9_ENDACHFL_ENABLED; + p_ab8500_codec_configuration->cr9_endachfr = + AB8500_CODEC_CR9_ENDACHFR_ENABLED; + } + + else + { + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_DISABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_DISABLED; + p_ab8500_codec_configuration->cr9_endachfl = + AB8500_CODEC_CR9_ENDACHFL_DISABLED; + p_ab8500_codec_configuration->cr9_endachfr = + AB8500_CODEC_CR9_ENDACHFR_DISABLED; + } + break; + case AB8500_CODEC_DEST_VIBRATOR_L: + if (AB8500_CODEC_DEST_STATE_ENABLE == state) + { + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_ENABLED; + p_ab8500_codec_configuration->cr9_endacvibl = + AB8500_CODEC_CR9_ENDACVIBL_ENABLED; + p_ab8500_codec_configuration->cr15_pwmtovibl = + AB8500_CODEC_CR15_PWMTOVIBL_PWM; + p_ab8500_codec_configuration->cr15_pwmlctrl = + AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmnlctrl = + AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmplctrl = + AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE; + } + + else + { + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_DISABLED; + p_ab8500_codec_configuration->cr9_endacvibl = + AB8500_CODEC_CR9_ENDACVIBL_DISABLED; + p_ab8500_codec_configuration->cr15_pwmtovibl = + AB8500_CODEC_CR15_PWMTOVIBL_DA_PATH; + p_ab8500_codec_configuration->cr15_pwmlctrl = + AB8500_CODEC_CR15_PWMLCTRL_PWMNPLGPOL; + p_ab8500_codec_configuration->cr15_pwmnlctrl = + AB8500_CODEC_CR15_PWMNLCTRL_PWMNLGPOL; + p_ab8500_codec_configuration->cr15_pwmplctrl = + AB8500_CODEC_CR15_PWMPLCTRL_PWMPLGPOL; + } + break; + case AB8500_CODEC_DEST_VIBRATOR_R: + if (AB8500_CODEC_DEST_STATE_ENABLE == state) + { + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_ENABLED; + p_ab8500_codec_configuration->cr9_endacvibr = + AB8500_CODEC_CR9_ENDACVIBR_ENABLED; + p_ab8500_codec_configuration->cr15_pwmtovibr = + AB8500_CODEC_CR15_PWMTOVIBR_PWM; + p_ab8500_codec_configuration->cr15_pwmrctrl = + AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmnrctrl = + AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmprctrl = + AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE; + } + + else + { + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_DISABLED; + p_ab8500_codec_configuration->cr9_endacvibr = + AB8500_CODEC_CR9_ENDACVIBR_DISABLED; + p_ab8500_codec_configuration->cr15_pwmtovibr = + AB8500_CODEC_CR15_PWMTOVIBR_DA_PATH; + p_ab8500_codec_configuration->cr15_pwmrctrl = + AB8500_CODEC_CR15_PWMRCTRL_PWMNPRGPOL; + p_ab8500_codec_configuration->cr15_pwmnrctrl = + AB8500_CODEC_CR15_PWMNRCTRL_PWMNRGPOL; + p_ab8500_codec_configuration->cr15_pwmprctrl = + AB8500_CODEC_CR15_PWMPRCTRL_PWMPRGPOL; + } + break; + case AB8500_CODEC_DEST_ALL: + if (AB8500_CODEC_DEST_STATE_ENABLE == state) + { + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_ENABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_ENABLED; + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_ENABLED; + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_ENABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_ENABLED; + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_ENABLED; + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_ENABLED; + p_ab8500_codec_configuration->cr9_endacear = + AB8500_CODEC_CR9_ENDACEAR_ENABLED; + p_ab8500_codec_configuration->cr9_endachfl = + AB8500_CODEC_CR9_ENDACHFL_ENABLED; + p_ab8500_codec_configuration->cr9_endachfr = + AB8500_CODEC_CR9_ENDACHFR_ENABLED; + p_ab8500_codec_configuration->cr9_endacvibl = + AB8500_CODEC_CR9_ENDACVIBL_ENABLED; + p_ab8500_codec_configuration->cr9_endacvibr = + AB8500_CODEC_CR9_ENDACVIBR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_DISABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_DISABLED; + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_DISABLED; + p_ab8500_codec_configuration->cr15_pwmtovibl = + AB8500_CODEC_CR15_PWMTOVIBL_PWM; + p_ab8500_codec_configuration->cr15_pwmlctrl = + AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmnlctrl = + AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmplctrl = + AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmtovibr = + AB8500_CODEC_CR15_PWMTOVIBR_PWM; + p_ab8500_codec_configuration->cr15_pwmrctrl = + AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmnrctrl = + AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmprctrl = + AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE; + } + + else + { + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_DISABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_DISABLED; + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_DISABLED; + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_DISABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_DISABLED; + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_DISABLED; + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_DISABLED; + p_ab8500_codec_configuration->cr9_endacear = + AB8500_CODEC_CR9_ENDACEAR_DISABLED; + p_ab8500_codec_configuration->cr9_endachfl = + AB8500_CODEC_CR9_ENDACHFL_DISABLED; + p_ab8500_codec_configuration->cr9_endachfr = + AB8500_CODEC_CR9_ENDACHFR_DISABLED; + p_ab8500_codec_configuration->cr9_endacvibl = + AB8500_CODEC_CR9_ENDACVIBL_DISABLED; + p_ab8500_codec_configuration->cr9_endacvibr = + AB8500_CODEC_CR9_ENDACVIBR_DISABLED; + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_ENABLED; + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_ENABLED; + p_ab8500_codec_configuration->cr15_pwmtovibl = + AB8500_CODEC_CR15_PWMTOVIBL_DA_PATH; + p_ab8500_codec_configuration->cr15_pwmlctrl = + AB8500_CODEC_CR15_PWMLCTRL_PWMNPLGPOL; + p_ab8500_codec_configuration->cr15_pwmnlctrl = + AB8500_CODEC_CR15_PWMNLCTRL_PWMNLGPOL; + p_ab8500_codec_configuration->cr15_pwmplctrl = + AB8500_CODEC_CR15_PWMPLCTRL_PWMPLGPOL; + p_ab8500_codec_configuration->cr15_pwmtovibr = + AB8500_CODEC_CR15_PWMTOVIBR_DA_PATH; + p_ab8500_codec_configuration->cr15_pwmrctrl = + AB8500_CODEC_CR15_PWMRCTRL_PWMNPRGPOL; + p_ab8500_codec_configuration->cr15_pwmnrctrl = + AB8500_CODEC_CR15_PWMNRCTRL_PWMNRGPOL; + p_ab8500_codec_configuration->cr15_pwmprctrl = + AB8500_CODEC_CR15_PWMPRCTRL_PWMPRGPOL; + } + break; + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_DestPowerControlUpdateCR(); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_GetVersion */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* This routine populates the pVersion structure with */ +/* the current version of HCL. */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* p_version: this parameter is used to return current HCL version. */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_ERROR: if p_version is NULL. */ +/* AB8500_CODEC_OK: if successful */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Re-Entrant */ +/* REENTRANCY ISSUES: No Issues */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_GetVersion(OUT t_version * p_version) +{ + DBGENTER1(" (%lx)", p_version); + if (p_version != NULL) + { + p_version->minor = AB8500_CODEC_HCL_MINOR_ID; + p_version->major = AB8500_CODEC_HCL_MAJOR_ID; + p_version->version = AB8500_CODEC_HCL_VERSION_ID; + DBGEXIT0(AB8500_CODEC_OK); + return (AB8500_CODEC_OK); + } + + else + { + DBGEXIT0(AB8500_CODEC_INVALID_PARAMETER); + return (AB8500_CODEC_INVALID_PARAMETER); + } +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_SetDbgLevel */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Set the debug level used by the debug module (mask-like value). */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* debug_level: debug level to be set */ +/* OUT: */ +/* None */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_OK: always */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Re-Entrant */ +/* REENTRANCY ISSUES: No Issues */ + +/****************************************************************************/ +/* +PUBLIC t_ab8500_codec_error AB8500_CODEC_SetDbgLevel(IN t_dbg_level dbg_level) +{ + DBGENTER1(" (%d)", dbg_level); + dbg_level = dbg_level; +#ifdef __DEBUG + MY_DEBUG_LEVEL_VAR_NAME = dbg_level; +#endif + DBGEXIT(AB8500_CODEC_OK); + return(AB8500_CODEC_OK); +} + */ + +/****************************************************************************/ +/* NAME: AB8500_CODEC_GetDbgLevel */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Set the debug level used by the debug module (mask-like value). */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* p_dbg_level: this parameter is used to return debug level. */ +/* */ +/* RETURN: */ +/* AB8500_CODEC_ERROR: if p_version is NULL. */ +/* AB8500_CODEC_OK: if successful */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Re-Entrant */ +/* REENTRANCY ISSUES: No Issues */ + +/****************************************************************************/ +/* +PUBLIC t_ab8500_codec_error AB8500_CODEC_GetDbgLevel(OUT t_dbg_level *p_dbg_level) +{ + if (NULL == p_dbg_level) + { + DBGEXIT(AB8500_CODEC_INVALID_PARAMETER); + return(AB8500_CODEC_INVALID_PARAMETER); + } + +#ifdef __DEBUG + * p_dbg_level = MY_DEBUG_LEVEL_VAR_NAME; +#endif + DBGEXIT(AB8500_CODEC_OK); + return(AB8500_CODEC_OK); +} +*/ +/****************************************************************************/ +/* NAME: AB8500_CODEC_ADSlotAllocation */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* AD Data Allocation in slots. */ +/* */ +/* ARGUMENTS */ +/* IN: t_ab8500_codec_slot: The slot to be allocated. */ +/* IN: t_ab8500_codec_cr31_to_cr46_ad_data_allocation: The value */ +/* to be allocated. */ +/* OUT: */ +/* None */ +/* RETURN: */ +/* AB8500_CODEC_INVALID_PARAMETER: If invalid slot number */ +/* AB8500_CODEC_OK: if successful. */ +/* REMARK: */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_ADSlotAllocation + (IN t_ab8500_codec_slot ad_slot, + IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value ) { + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + DBGENTER2(" (%lx %lx)", ad_slot, value); + if (ad_slot <= AB8500_CODEC_SLOT7) + { + ab8500_codec_error = + ab8500_codec_ADSlotAllocationSwitch1(ad_slot, value); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } + + else if (ad_slot <= AB8500_CODEC_SLOT15) + { + ab8500_codec_error = + ab8500_codec_ADSlotAllocationSwitch2(ad_slot, value); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } + + else if (ad_slot <= AB8500_CODEC_SLOT23) + { + ab8500_codec_error = + ab8500_codec_ADSlotAllocationSwitch3(ad_slot, value); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } + + else if (ad_slot <= AB8500_CODEC_SLOT31) + { + ab8500_codec_error = + ab8500_codec_ADSlotAllocationSwitch4(ad_slot, value); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } + + else + { + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + } + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_DASlotAllocation */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Allocate the Audio Interface slot for DA paths. */ +/* */ +/* ARGUMENTS */ +/* IN: t_ab8500_codec_da_channel_number: Channel number 1/2/3/4/5/6 */ +/* IN: t_ab8500_codec_cr51_to_cr56_sltoda: Slot number */ +/* */ +/* OUT: */ +/* None */ +/* RETURN: */ +/* AB8500_CODEC_INVALID_PARAMETER: If invalid channel number */ +/* AB8500_CODEC_OK: if successful. */ +/* REMARK: */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_DASlotAllocation + (IN t_ab8500_codec_da_channel_number channel_number, + IN t_ab8500_codec_cr51_to_cr58_sltoda slot ) { + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + t_ab8500_codec_cr0_powerup ab8500_codec_cr0_powerup; + DBGENTER2(" (%lx %lx)", channel_number, slot); + p_ab8500_codec_configuration->cr51_da12_voice = + AB8500_CODEC_CR51_DA12_VOICE_LOWLATENCYFILTER; + switch (channel_number) + { + case AB8500_CODEC_DA_CHANNEL_NUMBER_1: + p_ab8500_codec_configuration->cr51_sltoda1 = slot; + break; + case AB8500_CODEC_DA_CHANNEL_NUMBER_2: + p_ab8500_codec_configuration->cr52_sltoda2 = slot; + break; + case AB8500_CODEC_DA_CHANNEL_NUMBER_3: + p_ab8500_codec_configuration->cr53_sltoda3 = slot; + break; + case AB8500_CODEC_DA_CHANNEL_NUMBER_4: + p_ab8500_codec_configuration->cr54_sltoda4 = slot; + break; + case AB8500_CODEC_DA_CHANNEL_NUMBER_5: + p_ab8500_codec_configuration->cr55_sltoda5 = slot; + break; + case AB8500_CODEC_DA_CHANNEL_NUMBER_6: + p_ab8500_codec_configuration->cr56_sltoda6 = slot; + break; + case AB8500_CODEC_DA_CHANNEL_NUMBER_7: + p_ab8500_codec_configuration->cr57_sltoda7 = slot; + break; + case AB8500_CODEC_DA_CHANNEL_NUMBER_8: + p_ab8500_codec_configuration->cr58_sltoda8 = slot; + break; + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_cr0_powerup = p_ab8500_codec_configuration->cr0_powerup; + p_ab8500_codec_configuration->cr0_powerup = + AB8500_CODEC_CR0_POWERUP_OFF; + ab8500_codec_error = ab8500_codec_UpdateCR0(); + if (AB8500_CODEC_OK != ab8500_codec_error) + { + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR51(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR52(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR53(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR54(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR55(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR56(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR57(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR58(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + p_ab8500_codec_configuration->cr0_powerup = ab8500_codec_cr0_powerup; + ab8500_codec_error = ab8500_codec_UpdateCR0(); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_ConfigureBurstFifo */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Configuration for Burst FIFO control */ +/* */ +/* ARGUMENTS */ +/* IN: t_ab8500_codec_burst_fifo_config: structure for configuration of */ +/* burst FIFO */ +/* OUT: */ +/* None */ +/* RETURN: */ +/* AB8500_CODEC_INVALID_PARAMETER: If invalid parameter */ +/* AB8500_CODEC_UNSUPPORTED_FEATURE: If interface 1 selected */ +/* AB8500_CODEC_OK: if successful. */ +/* REMARK: */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +t_ab8500_codec_error AB8500_CODEC_ConfigureBurstFifo(IN + t_ab8500_codec_burst_fifo_config + const *const + p_burst_fifo_config) +{ + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + DBGENTER1(" (%lx)", p_burst_fifo_config); + if (AB8500_CODEC_AUDIO_INTERFACE_0 == + g_ab8500_codec_system_context.audio_interface) + { + if (AB8500_CODEC_CR27_EN_MASTGEN_ENABLED == + p_ab8500_codec_configuration->cr27_en_mastgen) + { + p_ab8500_codec_configuration->cr105_bfifomsk = + p_burst_fifo_config->cr105_bfifomsk; + p_ab8500_codec_configuration->cr105_bfifoint = + p_burst_fifo_config->cr105_bfifoint; + p_ab8500_codec_configuration->cr106_bfifotx = + p_burst_fifo_config->cr106_bfifotx; + p_ab8500_codec_configuration->cr107_bfifoexsl = + p_burst_fifo_config->cr107_bfifoexsl; + p_ab8500_codec_configuration->cr107_bfifomast = + p_burst_fifo_config->cr107_bfifomast; + p_ab8500_codec_configuration->cr107_bfiforun = + p_burst_fifo_config->cr107_bfiforun; + p_ab8500_codec_configuration->cr108_bfifoframsw = + p_burst_fifo_config->cr108_bfifoframsw; + p_ab8500_codec_configuration->cr109_bfifowakeup = + p_burst_fifo_config->cr109_bfifowakeup; + ab8500_codec_error = ab8500_codec_UpdateCR105(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR106(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR107(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR108(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR109(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } + + else + { + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } + + else + { + ab8500_codec_error = AB8500_CODEC_UNSUPPORTED_FEATURE; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_EnableBurstFifo */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Enable the Burst FIFO for Interface 0 */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* None */ +/* RETURN: */ +/* AB8500_CODEC_UNSUPPORTED_FEATURE: If Interface 1 is selected */ +/* AB8500_CODEC_OK: if successful. */ +/* REMARK: */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_EnableBurstFifo(void) +{ + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + DBGENTER0(); + if (AB8500_CODEC_AUDIO_INTERFACE_0 == + g_ab8500_codec_system_context.audio_interface) + { + p_ab8500_codec_configuration->cr29_if0bfifoen = + AB8500_CODEC_CR29_IF0BFIFOEN_BURST_MODE; + ab8500_codec_error = ab8500_codec_UpdateCR29(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } + + else + { + ab8500_codec_error = AB8500_CODEC_UNSUPPORTED_FEATURE; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +/****************************************************************************/ +/* NAME: AB8500_CODEC_DisableBurstFifo */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: */ +/* Disable the Burst FIFO for Interface 0 */ +/* */ +/* ARGUMENTS */ +/* IN: */ +/* None */ +/* OUT: */ +/* None */ +/* RETURN: */ +/* AB8500_CODEC_UNSUPPORTED_FEATURE: If Interface 1 is selected */ +/* AB8500_CODEC_OK: if successful. */ +/* REMARK: */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY: Non Re-Entrant */ + +/****************************************************************************/ +PUBLIC t_ab8500_codec_error AB8500_CODEC_DisableBurstFifo(void) +{ + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + DBGENTER0(); + if (AB8500_CODEC_AUDIO_INTERFACE_0 == + g_ab8500_codec_system_context.audio_interface) + { + p_ab8500_codec_configuration->cr29_if0bfifoen = + AB8500_CODEC_CR29_IF0BFIFOEN_NORMAL_MODE; + ab8500_codec_error = ab8500_codec_UpdateCR29(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + } + + else + { + ab8500_codec_error = AB8500_CODEC_UNSUPPORTED_FEATURE; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch1 + (IN t_ab8500_codec_slot ad_slot, + IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value ) { + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + switch (ad_slot) + { + case AB8500_CODEC_SLOT0: + p_ab8500_codec_configuration->cr31_adotoslot0 = value; + ab8500_codec_error = ab8500_codec_UpdateCR31(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT1: + p_ab8500_codec_configuration->cr31_adotoslot1 = value; + ab8500_codec_error = ab8500_codec_UpdateCR31(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT2: + p_ab8500_codec_configuration->cr32_adotoslot2 = value; + ab8500_codec_error = ab8500_codec_UpdateCR32(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT3: + p_ab8500_codec_configuration->cr32_adotoslot3 = value; + ab8500_codec_error = ab8500_codec_UpdateCR32(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT4: + p_ab8500_codec_configuration->cr33_adotoslot4 = value; + ab8500_codec_error = ab8500_codec_UpdateCR33(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT5: + p_ab8500_codec_configuration->cr33_adotoslot5 = value; + ab8500_codec_error = ab8500_codec_UpdateCR33(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT6: + p_ab8500_codec_configuration->cr34_adotoslot6 = value; + ab8500_codec_error = ab8500_codec_UpdateCR34(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT7: + p_ab8500_codec_configuration->cr34_adotoslot7 = value; + ab8500_codec_error = ab8500_codec_UpdateCR34(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch2 + (IN t_ab8500_codec_slot ad_slot, + IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value ) { + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + switch (ad_slot) + { + case AB8500_CODEC_SLOT8: + p_ab8500_codec_configuration->cr35_adotoslot8 = value; + ab8500_codec_error = ab8500_codec_UpdateCR35(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT9: + p_ab8500_codec_configuration->cr35_adotoslot9 = value; + ab8500_codec_error = ab8500_codec_UpdateCR35(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT10: + p_ab8500_codec_configuration->cr36_adotoslot10 = value; + ab8500_codec_error = ab8500_codec_UpdateCR36(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT11: + p_ab8500_codec_configuration->cr36_adotoslot11 = value; + ab8500_codec_error = ab8500_codec_UpdateCR36(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT12: + p_ab8500_codec_configuration->cr37_adotoslot12 = value; + ab8500_codec_error = ab8500_codec_UpdateCR37(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT13: + p_ab8500_codec_configuration->cr37_adotoslot13 = value; + ab8500_codec_error = ab8500_codec_UpdateCR37(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT14: + p_ab8500_codec_configuration->cr38_adotoslot14 = value; + ab8500_codec_error = ab8500_codec_UpdateCR38(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT15: + p_ab8500_codec_configuration->cr38_adotoslot15 = value; + ab8500_codec_error = ab8500_codec_UpdateCR38(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch3 + (IN t_ab8500_codec_slot ad_slot, + IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value ) { + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + switch (ad_slot) + { + case AB8500_CODEC_SLOT16: + p_ab8500_codec_configuration->cr39_adotoslot16 = value; + ab8500_codec_error = ab8500_codec_UpdateCR39(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT17: + p_ab8500_codec_configuration->cr39_adotoslot17 = value; + ab8500_codec_error = ab8500_codec_UpdateCR39(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT18: + p_ab8500_codec_configuration->cr40_adotoslot18 = value; + ab8500_codec_error = ab8500_codec_UpdateCR40(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT19: + p_ab8500_codec_configuration->cr40_adotoslot19 = value; + ab8500_codec_error = ab8500_codec_UpdateCR40(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT20: + p_ab8500_codec_configuration->cr41_adotoslot20 = value; + ab8500_codec_error = ab8500_codec_UpdateCR41(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT21: + p_ab8500_codec_configuration->cr41_adotoslot21 = value; + ab8500_codec_error = ab8500_codec_UpdateCR41(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT22: + p_ab8500_codec_configuration->cr42_adotoslot22 = value; + ab8500_codec_error = ab8500_codec_UpdateCR42(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT23: + p_ab8500_codec_configuration->cr42_adotoslot23 = value; + ab8500_codec_error = ab8500_codec_UpdateCR42(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch4 + (IN t_ab8500_codec_slot ad_slot, + IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value ) { + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + switch (ad_slot) + { + case AB8500_CODEC_SLOT24: + p_ab8500_codec_configuration->cr43_adotoslot24 = value; + ab8500_codec_error = ab8500_codec_UpdateCR43(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT25: + p_ab8500_codec_configuration->cr43_adotoslot25 = value; + ab8500_codec_error = ab8500_codec_UpdateCR43(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT26: + p_ab8500_codec_configuration->cr44_adotoslot26 = value; + ab8500_codec_error = ab8500_codec_UpdateCR44(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT27: + p_ab8500_codec_configuration->cr44_adotoslot27 = value; + ab8500_codec_error = ab8500_codec_UpdateCR44(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT28: + p_ab8500_codec_configuration->cr45_adotoslot28 = value; + ab8500_codec_error = ab8500_codec_UpdateCR45(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT29: + p_ab8500_codec_configuration->cr45_adotoslot29 = value; + ab8500_codec_error = ab8500_codec_UpdateCR45(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT30: + p_ab8500_codec_configuration->cr46_adotoslot30 = value; + ab8500_codec_error = ab8500_codec_UpdateCR46(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + case AB8500_CODEC_SLOT31: + p_ab8500_codec_configuration->cr46_adotoslot31 = value; + ab8500_codec_error = ab8500_codec_UpdateCR46(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + break; + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_SrcPowerControlSwitch1(IN + t_ab8500_codec_src + src_device, + t_ab8500_codec_src_state + state) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + switch (src_device) + { + case AB8500_CODEC_SRC_LINEIN: + if (AB8500_CODEC_SRC_STATE_ENABLE == state) + { + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_ENABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_DISABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_DISABLED; + p_ab8500_codec_configuration->cr7_linrsel = + AB8500_CODEC_CR7_LINRSEL_LINR; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_ENABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_ENABLED; + } + + else + { + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr7_linrsel = + AB8500_CODEC_CR7_LINRSEL_MIC2; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + } + break; + case AB8500_CODEC_SRC_MICROPHONE_1A: + if (AB8500_CODEC_SRC_STATE_ENABLE == state) + { + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_DISABLED; + p_ab8500_codec_configuration->cr7_mic1sel = + AB8500_CODEC_CR7_MIC1SEL_MIC1A; + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_ENABLED; + } + + else + { + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_DISABLED; + } + break; + case AB8500_CODEC_SRC_MICROPHONE_1B: + if (AB8500_CODEC_SRC_STATE_ENABLE == state) + { + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_DISABLED; + p_ab8500_codec_configuration->cr7_mic1sel = + AB8500_CODEC_CR7_MIC1SEL_MIC1B; + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_ENABLED; + } + + else + { + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_DISABLED; + } + break; + case AB8500_CODEC_SRC_MICROPHONE_2: + if (AB8500_CODEC_SRC_STATE_ENABLE == state) + { + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_DISABLED; + p_ab8500_codec_configuration->cr7_linrsel = + AB8500_CODEC_CR7_LINRSEL_MIC2; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_ENABLED; + } + + else + { + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + p_ab8500_codec_configuration->cr7_linrsel = + AB8500_CODEC_CR7_LINRSEL_LINR; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_1: + if (AB8500_CODEC_SRC_STATE_ENABLE == state) + { + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_ENABLED; + p_ab8500_codec_configuration->cr63_ad1sel = + AB8500_CODEC_CR63_AD1SEL_DMIC1_SELECTED; + } + + else + { + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr63_ad1sel = + AB8500_CODEC_CR63_AD1SEL_LINLADL_SELECTED; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_2: + if (AB8500_CODEC_SRC_STATE_ENABLE == state) + { + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_ENABLED; + p_ab8500_codec_configuration->cr63_ad2sel = + AB8500_CODEC_CR63_AD2SEL_DMIC2_SELECTED; + } + + else + { + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr63_ad2sel = + AB8500_CODEC_CR63_AD2SEL_LINRADR_SELECTED; + } + break; + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_SrcPowerControlSwitch2(IN + t_ab8500_codec_src + src_device, + t_ab8500_codec_src_state + state) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + switch (src_device) + { + case AB8500_CODEC_SRC_D_MICROPHONE_3: + if (AB8500_CODEC_SRC_STATE_ENABLE == state) + { + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_ENABLED; + p_ab8500_codec_configuration->cr63_ad3sel = + AB8500_CODEC_CR63_AD3SEL_DMIC3_SELECTED; + } + + else + { + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr63_ad3sel = + AB8500_CODEC_CR63_AD3SEL_ADMO_SELECTED; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_4: + if (AB8500_CODEC_SRC_STATE_ENABLE == state) + { + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_ENABLED; + } + + else + { + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_5: + if (AB8500_CODEC_SRC_STATE_ENABLE == state) + { + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_ENABLED; + p_ab8500_codec_configuration->cr63_ad5sel = + AB8500_CODEC_CR63_AD5SEL_DMIC5_SELECTED; + } + + else + { + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr63_ad5sel = + AB8500_CODEC_CR63_AD5SEL_AMADR_SELECTED; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_6: + if (AB8500_CODEC_SRC_STATE_ENABLE == state) + { + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_ENABLED; + p_ab8500_codec_configuration->cr63_ad6sel = + AB8500_CODEC_CR63_AD6SEL_DMIC6_SELECTED; + } + + else + { + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr63_ad6sel = + AB8500_CODEC_CR63_AD6SEL_ADMO_SELECTED; + } + break; + case AB8500_CODEC_SRC_ALL: + if (AB8500_CODEC_SRC_STATE_ENABLE == state) + { + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_ENABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_ENABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_ENABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_ENABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_ENABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_ENABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_ENABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_ENABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_ENABLED; + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_DISABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_DISABLED; + } + + else + { + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_DISABLED; + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + } + break; + case AB8500_CODEC_SRC_FM_RX: + break; + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_SetModeAndDirectionUpdateCR(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + t_ab8500_codec_cr0_powerup ab8500_codec_cr0_powerup; + ab8500_codec_cr0_powerup = p_ab8500_codec_configuration->cr0_powerup; + p_ab8500_codec_configuration->cr0_powerup = + AB8500_CODEC_CR0_POWERUP_OFF; + ab8500_codec_error = ab8500_codec_UpdateCR0(); + if (AB8500_CODEC_OK != ab8500_codec_error) + { + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR2(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR3(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR26(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR27(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR28(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR30(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR63(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + p_ab8500_codec_configuration->cr0_powerup = ab8500_codec_cr0_powerup; + ab8500_codec_error = ab8500_codec_UpdateCR0(); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_SetSrcVolumeUpdateCR(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + ab8500_codec_error = ab8500_codec_UpdateCR20(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR21(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR23(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR65(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR66(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR67(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR68(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR69(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR70(); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_SetDestVolumeUpdateCR(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + ab8500_codec_error = ab8500_codec_UpdateCR16(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR17(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR18(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR19(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR22(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR71(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR72(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR73(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR74(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR75(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR76(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR79(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR80(); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirectionIN(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + switch (g_ab8500_codec_system_context.ab8500_codec_src) + { + case AB8500_CODEC_SRC_LINEIN: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_ENABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_ENABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + p_ab8500_codec_configuration->cr7_linrsel = + AB8500_CODEC_CR7_LINRSEL_LINR; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_ENABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_DISABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + break; + case AB8500_CODEC_SRC_MICROPHONE_1A: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + p_ab8500_codec_configuration->cr7_mic1sel = + AB8500_CODEC_CR7_MIC1SEL_MIC1A; + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_ENABLED; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + break; + case AB8500_CODEC_SRC_MICROPHONE_1B: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + p_ab8500_codec_configuration->cr7_mic1sel = + AB8500_CODEC_CR7_MIC1SEL_MIC1B; + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_ENABLED; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + break; + case AB8500_CODEC_SRC_MICROPHONE_2: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_ENABLED; + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_ENABLED; + p_ab8500_codec_configuration->cr7_linrsel = + AB8500_CODEC_CR7_LINRSEL_MIC2; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_DISABLED; + break; + case AB8500_CODEC_SRC_D_MICROPHONE_1: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_ENABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + p_ab8500_codec_configuration->cr63_ad1sel = + AB8500_CODEC_CR63_AD1SEL_DMIC1_SELECTED; + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + break; + case AB8500_CODEC_SRC_D_MICROPHONE_2: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_ENABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + p_ab8500_codec_configuration->cr63_ad2sel = + AB8500_CODEC_CR63_AD2SEL_DMIC2_SELECTED; + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + break; + case AB8500_CODEC_SRC_D_MICROPHONE_3: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_ENABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + p_ab8500_codec_configuration->cr63_ad3sel = + AB8500_CODEC_CR63_AD3SEL_DMIC3_SELECTED; + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + break; + case AB8500_CODEC_SRC_D_MICROPHONE_4: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_ENABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + break; + case AB8500_CODEC_SRC_D_MICROPHONE_5: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_ENABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_DISABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + p_ab8500_codec_configuration->cr63_ad5sel = + AB8500_CODEC_CR63_AD5SEL_DMIC5_SELECTED; + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + break; + case AB8500_CODEC_SRC_D_MICROPHONE_6: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_DISABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_DISABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_DISABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_DISABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_DISABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_DISABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_DISABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_ENABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_DISABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_DISABLED; + p_ab8500_codec_configuration->cr63_ad6sel = + AB8500_CODEC_CR63_AD6SEL_DMIC6_SELECTED; + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_ENABLED; + break; + case AB8500_CODEC_SRC_ALL: + p_ab8500_codec_configuration->cr5_enlinl = + AB8500_CODEC_CR5_ENLINL_ENABLED; + p_ab8500_codec_configuration->cr5_enlinr = + AB8500_CODEC_CR5_ENLINR_ENABLED; + p_ab8500_codec_configuration->cr5_enmic1 = + AB8500_CODEC_CR5_ENMIC1_ENABLED; + p_ab8500_codec_configuration->cr5_enmic2 = + AB8500_CODEC_CR5_ENMIC2_ENABLED; + p_ab8500_codec_configuration->cr6_endmic1 = + AB8500_CODEC_CR6_ENDMIC1_ENABLED; + p_ab8500_codec_configuration->cr6_endmic2 = + AB8500_CODEC_CR6_ENDMIC2_ENABLED; + p_ab8500_codec_configuration->cr6_endmic3 = + AB8500_CODEC_CR6_ENDMIC3_ENABLED; + p_ab8500_codec_configuration->cr6_endmic4 = + AB8500_CODEC_CR6_ENDMIC4_ENABLED; + p_ab8500_codec_configuration->cr6_endmic5 = + AB8500_CODEC_CR6_ENDMIC5_ENABLED; + p_ab8500_codec_configuration->cr6_endmic6 = + AB8500_CODEC_CR6_ENDMIC6_ENABLED; + p_ab8500_codec_configuration->cr7_enadcmic = + AB8500_CODEC_CR7_ENADCMIC_ENABLED; + p_ab8500_codec_configuration->cr7_enadclinl = + AB8500_CODEC_CR7_ENADCLINL_ENABLED; + p_ab8500_codec_configuration->cr7_enadclinr = + AB8500_CODEC_CR7_ENADCLINR_ENABLED; + p_ab8500_codec_configuration->cr5_mutlinl = + AB8500_CODEC_CR5_MUTLINL_DISABLED; + p_ab8500_codec_configuration->cr5_mutlinr = + AB8500_CODEC_CR5_MUTLINR_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic1 = + AB8500_CODEC_CR5_MUTMIC1_DISABLED; + p_ab8500_codec_configuration->cr5_mutmic2 = + AB8500_CODEC_CR5_MUTMIC2_DISABLED; + break; + case AB8500_CODEC_SRC_D_MICROPHONE_12: + case AB8500_CODEC_SRC_D_MICROPHONE_34: + case AB8500_CODEC_SRC_D_MICROPHONE_56: + break; + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirectionOUT(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + t_ab8500_codec_configuration * p_ab8500_codec_configuration = + &g_ab8500_codec_system_context. ab8500_codec_configuration; + switch (g_ab8500_codec_system_context.ab8500_codec_dest) + { + case AB8500_CODEC_DEST_HEADSET: + p_ab8500_codec_configuration->cr7_endrvhsl = + AB8500_CODEC_CR7_ENDRVHSL_ENABLED; + p_ab8500_codec_configuration->cr7_endrvhsr = + AB8500_CODEC_CR7_ENDRVHSR_ENABLED; + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_DISABLED; + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_ENABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_ENABLED; + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_DISABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_DISABLED; + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_DISABLED; + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_DISABLED; + p_ab8500_codec_configuration->cr9_endachsl = + AB8500_CODEC_CR9_ENDACHSL_ENABLED; + p_ab8500_codec_configuration->cr9_endachsr = + AB8500_CODEC_CR9_ENDACHSR_ENABLED; + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_DISABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_DISABLED; + p_ab8500_codec_configuration->cr12_encphs = + AB8500_CODEC_CR12_ENCPHS_ENABLED; + break; + case AB8500_CODEC_DEST_EARPIECE: + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_ENABLED; + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_DISABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_DISABLED; + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_DISABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_DISABLED; + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_DISABLED; + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_DISABLED; + p_ab8500_codec_configuration->cr9_endacear = + AB8500_CODEC_CR9_ENDACEAR_ENABLED; + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_DISABLED; + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_ENABLED; + break; + case AB8500_CODEC_DEST_HANDSFREE: + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_DISABLED; + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_DISABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_DISABLED; + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_ENABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_ENABLED; + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_DISABLED; + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_DISABLED; + p_ab8500_codec_configuration->cr9_endachfl = + AB8500_CODEC_CR9_ENDACHFL_ENABLED; + p_ab8500_codec_configuration->cr9_endachfr = + AB8500_CODEC_CR9_ENDACHFR_ENABLED; + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_ENABLED; + break; + case AB8500_CODEC_DEST_VIBRATOR_L: + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_DISABLED; + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_DISABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_DISABLED; + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_DISABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_DISABLED; + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_ENABLED; + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_DISABLED; + p_ab8500_codec_configuration->cr9_endacvibl = + AB8500_CODEC_CR9_ENDACVIBL_ENABLED; + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_ENABLED; + p_ab8500_codec_configuration->cr15_pwmtovibl = + AB8500_CODEC_CR15_PWMTOVIBL_PWM; + p_ab8500_codec_configuration->cr15_pwmlctrl = + AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmnlctrl = + AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmplctrl = + AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE; + break; + case AB8500_CODEC_DEST_VIBRATOR_R: + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_DISABLED; + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_DISABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_DISABLED; + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_DISABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_DISABLED; + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_DISABLED; + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_ENABLED; + p_ab8500_codec_configuration->cr9_endacvibr = + AB8500_CODEC_CR9_ENDACVIBR_ENABLED; + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_ENABLED; + p_ab8500_codec_configuration->cr15_pwmtovibr = + AB8500_CODEC_CR15_PWMTOVIBR_PWM; + p_ab8500_codec_configuration->cr15_pwmrctrl = + AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmnrctrl = + AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmprctrl = + AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE; + break; + case AB8500_CODEC_DEST_ALL: + p_ab8500_codec_configuration->cr8_enhsl = + AB8500_CODEC_CR8_ENHSL_ENABLED; + p_ab8500_codec_configuration->cr8_enhsr = + AB8500_CODEC_CR8_ENHSR_ENABLED; + p_ab8500_codec_configuration->cr8_enear = + AB8500_CODEC_CR8_ENEAR_ENABLED; + p_ab8500_codec_configuration->cr8_enhfl = + AB8500_CODEC_CR8_ENHFL_ENABLED; + p_ab8500_codec_configuration->cr8_enhfr = + AB8500_CODEC_CR8_ENHFR_ENABLED; + p_ab8500_codec_configuration->cr8_envibl = + AB8500_CODEC_CR8_ENVIBL_ENABLED; + p_ab8500_codec_configuration->cr8_envibr = + AB8500_CODEC_CR8_ENVIBR_ENABLED; + p_ab8500_codec_configuration->cr9_endacear = + AB8500_CODEC_CR9_ENDACEAR_ENABLED; + p_ab8500_codec_configuration->cr9_endachfl = + AB8500_CODEC_CR9_ENDACHFL_ENABLED; + p_ab8500_codec_configuration->cr9_endachfr = + AB8500_CODEC_CR9_ENDACHFR_ENABLED; + p_ab8500_codec_configuration->cr9_endacvibl = + AB8500_CODEC_CR9_ENDACVIBL_ENABLED; + p_ab8500_codec_configuration->cr9_endacvibr = + AB8500_CODEC_CR9_ENDACVIBR_ENABLED; + p_ab8500_codec_configuration->cr10_mutehsl = + AB8500_CODEC_CR10_MUTEHSL_DISABLED; + p_ab8500_codec_configuration->cr10_mutehsr = + AB8500_CODEC_CR10_MUTEHSR_DISABLED; + p_ab8500_codec_configuration->cr10_muteear = + AB8500_CODEC_CR10_MUTEEAR_DISABLED; + p_ab8500_codec_configuration->cr15_pwmtovibl = + AB8500_CODEC_CR15_PWMTOVIBL_PWM; + p_ab8500_codec_configuration->cr15_pwmlctrl = + AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmnlctrl = + AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmplctrl = + AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmtovibr = + AB8500_CODEC_CR15_PWMTOVIBR_PWM; + p_ab8500_codec_configuration->cr15_pwmrctrl = + AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmnrctrl = + AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE; + p_ab8500_codec_configuration->cr15_pwmprctrl = + AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE; + break; + default: + ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER; + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} + +PRIVATE t_ab8500_codec_error ab8500_codec_DestPowerControlUpdateCR(void) +{ + t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK; + ab8500_codec_error = ab8500_codec_UpdateCR8(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR9(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR10(); + if (ab8500_codec_error != AB8500_CODEC_OK) + { + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); + } + ab8500_codec_error = ab8500_codec_UpdateCR15(); + DBGEXIT(ab8500_codec_error); + return (ab8500_codec_error); +} diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig index 885683a3b0b..86cd48bfd8d 100644 --- a/sound/arm/Kconfig +++ b/sound/arm/Kconfig @@ -39,5 +39,17 @@ config SND_PXA2XX_AC97 Say Y or M if you want to support any AC97 codec attached to the PXA2xx AC97 interface. +config SND_U8500_ALSA_AB8500 + tristate "U8500 alsa support for AB8500" + depends on SND && STE_DMA40 && U8500_ACODEC && (U8500_AB8500_ED || U8500_AB8500_CUT10) + default y + select SND_PCM + help + Say Y here if you have a u8500 based device + and want to use alsa for pcm playback and capture. + + To compile this driver as a module, choose M here: the module + will be called u8500mod_alsa. + endif # SND_ARM diff --git a/sound/arm/Makefile b/sound/arm/Makefile index 8c0c851d464..e41f1f4db14 100644 --- a/sound/arm/Makefile +++ b/sound/arm/Makefile @@ -14,3 +14,7 @@ snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97) += pxa2xx-ac97-lib.o obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o snd-pxa2xx-ac97-objs := pxa2xx-ac97.o +obj-$(CONFIG_SND_U8500_ALSA_AB8500) += u8500mod_alsa.o +ifneq ($(CONFIG_SND_U8500_ALSA_AB8500),n) +u8500mod_alsa-objs := u8500_alsa_ab8500.o u8500_alsa_hdmi.o +endif diff --git a/sound/arm/u8500_alsa_ab8500.c b/sound/arm/u8500_alsa_ab8500.c new file mode 100644 index 00000000000..39752388ab1 --- /dev/null +++ b/sound/arm/u8500_alsa_ab8500.c @@ -0,0 +1,2691 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Deepak Karda + * for ST-Ericsson. + * + * License terms: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.1 as published + * by the Free Software Foundation. + */ + +/* This include must be defined at this point */ +//#include <sound/driver.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/errno.h> +#include <linux/ioctl.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <mach/hardware.h> +#include <asm/uaccess.h> +#include <asm/io.h> + +/* alsa system */ +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/control.h> +#include "u8500_alsa_ab8500.h" +#include <mach/msp.h> +#include <mach/debug.h> + +#define ALSA_NAME "DRIVER ALSA" + +#define DRIVER_DEBUG CONFIG_STM_ALSA_DEBUG /* enables/disables debug msgs */ +#define DRIVER_DEBUG_PFX ALSA_NAME /* msg header represents this module */ +#define DRIVER_DBG KERN_ERR /* message level */ + +static struct platform_device *device; +static int active_user = 0; + +/* +** Externel references +*/ +#if DRIVER_DEBUG > 0 +t_ab8500_codec_error dump_acodec_registers(void); +t_ab8500_codec_error dump_msp_registers(void); +#endif + +extern int u8500_acodec_rates[MAX_NO_OF_RATES]; +extern char *lpbk_state_in_texts[NUMBER_LOOPBACK_STATE]; +extern char *switch_state_in_texts[NUMBER_SWITCH_STATE]; +extern char *power_state_in_texts[NUMBER_POWER_STATE]; +extern char *tdm_mode_state_in_texts[NUMBER_TDM_MODE_STATE]; +extern char *direct_rendering_state_in_texts[NUMBER_DIRECT_RENDERING_STATE]; +extern char *pcm_rendering_state_in_texts[NUMBER_PCM_RENDERING_STATE]; +extern char *codec_dest_texts[NUMBER_OUTPUT_DEVICE]; +extern char *codec_in_texts[NUMBER_INPUT_DEVICE]; +extern struct driver_debug_st DBG_ST; +extern int second_config; +extern int u8500_register_alsa_hdmi_controls(struct snd_card *card, + u8500_acodec_chip_t * u8500_chip); +extern int snd_card_u8500_alsa_hdmi_new(u8500_acodec_chip_t * chip, int device); +/* +** Declaration for local functions +*/ +static int u8500_analog_lpbk_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int u8500_analog_lpbk_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); +static int u8500_analog_lpbk_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); + +static int u8500_digital_lpbk_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int u8500_digital_lpbk_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); +static int u8500_digital_lpbk_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); + +static int u8500_playback_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int u8500_playback_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); +static int u8500_playback_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); + +static int u8500_capture_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int u8500_capture_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); +static int u8500_capture_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); + +static int u8500_playback_sink_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int u8500_playback_sink_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); +static int u8500_playback_sink_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); + +static int u8500_capture_src_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int u8500_capture_src_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); +static int u8500_capture_src_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); + +static int u8500_playback_switch_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int u8500_playback_switch_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); +static int u8500_playback_switch_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); + +static int u8500_capture_switch_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int u8500_capture_switch_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); +static int u8500_capture_switch_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); + +static int u8500_playback_power_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int u8500_playback_power_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); +static int u8500_playback_power_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); + +static int u8500_capture_power_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int u8500_capture_power_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); +static int u8500_capture_power_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); + +static int u8500_tdm_mode_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int u8500_tdm_mode_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); +static int u8500_tdm_mode_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); + +static int u8500_direct_rendering_mode_ctrl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info + *uinfo); +static int u8500_direct_rendering_mode_ctrl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value + *uinfo); +static int u8500_direct_rendering_mode_ctrl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value + *uinfo); +static int u8500_register_alsa_controls(struct snd_card *card, + u8500_acodec_chip_t * u8500_chip); + +static int u8500_pcm_rendering_mode_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int u8500_pcm_rendering_mode_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); +static int u8500_pcm_rendering_mode_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); + +#if 0 /* DUMP REGISTER CONTROL */ +static int u8500_dump_register_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int u8500_dump_register_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); +static int u8500_dump_register_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); +#endif /* DUMP REGISTER CONTROL */ + +static int configure_rate(struct snd_pcm_substream *, + t_u8500_acodec_config_need acodec_config_need); +static void dma_eot_handler(void *data); +/** +* configure_rate +* @substream - pointer to the playback/capture substream structure +* +* This functions configures audio codec in to stream frequency frequency +*/ + +static int configure_rate(struct snd_pcm_substream *substream, + t_u8500_acodec_config_need acodec_config_need) +{ + u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream); + t_codec_sample_frequency sampling_frequency = 0; + t_ab8500_codec_direction direction = 0; + struct acodec_configuration acodec_config; + int stream_id = substream->pstr->stream; + + FUNC_ENTER(); + switch (chip->freq) { + case 48000: + sampling_frequency = CODEC_SAMPLING_FREQ_48KHZ; + break; + default: + printk("not supported frequnecy \n"); + stm_error("not supported frequnecy \n"); + return -EINVAL; + } + + switch (stream_id) { + case SNDRV_PCM_STREAM_PLAYBACK: + direction = AB8500_CODEC_DIRECTION_OUT; + break; + case SNDRV_PCM_STREAM_CAPTURE: + direction = AB8500_CODEC_DIRECTION_IN; + break; + default: + stm_error(": wrong pcm stream\n"); + return -EINVAL; + } + + stm_dbg(DBG_ST.alsa, "enabling audiocodec audio mode\n"); + acodec_config.direction = direction; + acodec_config.input_frequency = T_CODEC_SAMPLING_FREQ_48KHZ; + acodec_config.output_frequency = T_CODEC_SAMPLING_FREQ_48KHZ; + acodec_config.mspClockSel = CODEC_MSP_APB_CLOCK; + acodec_config.mspInClockFreq = CODEC_MSP_INPUT_FREQ_48MHZ; + acodec_config.channels = chip->channels; + acodec_config.user = 2; + acodec_config.acodec_config_need = acodec_config_need; + acodec_config.handler = dma_eot_handler; + acodec_config.tx_callback_data = + &chip->stream[ALSA_PCM_DEV][SNDRV_PCM_STREAM_PLAYBACK]; + acodec_config.rx_callback_data = + &chip->stream[ALSA_PCM_DEV][SNDRV_PCM_STREAM_CAPTURE]; + acodec_config.direct_rendering_mode = chip->direct_rendering_mode; + acodec_config.tdm8_ch_mode = chip->tdm8_ch_mode; + acodec_config.digital_loopback = DISABLE; + u8500_acodec_enable_audio_mode(&acodec_config); + FUNC_EXIT(); + + return 0; +} + +/* +**************************************************************************************** +* playback vol control * +**************************************************************************************** +*/ + +struct snd_kcontrol_new u8500_playback_vol_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .device = 0, + .subdevice = 0, + .name = "PCM Playback Volume", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0xfff, + .info = u8500_playback_vol_info, + .get = u8500_playback_vol_get, + .put = u8500_playback_vol_put +}; + +/** +* u8500_playback_vol_info +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions fills playback volume info into user structure. +*/ + +static int u8500_playback_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 100; + uinfo->value.integer.step = 10; + return 0; +} + +/** +* u8500_playback_vol_get +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions fills the current volume setting to user structure. +*/ + +static int u8500_playback_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + + int *p_left_volume = NULL; + int *p_right_volume = NULL; + + p_left_volume = (int *)&uinfo->value.integer.value[0]; + p_right_volume = (int *)&uinfo->value.integer.value[1]; + + u8500_acodec_get_output_volume(chip->output_device, p_left_volume, + p_right_volume, USER_ALSA); + return 0; +} + +/** +* u8500_playback_vol_put +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure. +* +* This functions sets the playback audio codec volume . +*/ + +static int u8500_playback_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + int changed = 0, error = 0; + + if (chip->output_lvolume != uinfo->value.integer.value[0] + || chip->output_rvolume != uinfo->value.integer.value[1]) { + chip->output_lvolume = uinfo->value.integer.value[0]; + chip->output_rvolume = uinfo->value.integer.value[1]; + + if (chip->output_lvolume > 100) + chip->output_lvolume = 100; + else if (chip->output_lvolume < 0) + chip->output_lvolume = 0; + + if (chip->output_rvolume > 100) + chip->output_rvolume = 100; + else if (chip->output_rvolume < 0) + chip->output_rvolume = 0; + + error = + u8500_acodec_set_output_volume(chip->output_device, + chip->output_lvolume, + chip->output_rvolume, + USER_ALSA); + + if (error) { + stm_error + (" : set volume for speaker/headphone failed\n"); + return changed; + } + changed = 1; + } + + return changed; +} + +/* +**************************************************************************************** +* capture vol control * +**************************************************************************************** +*/ + +struct snd_kcontrol_new u8500_capture_vol_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .device = 0, + .subdevice = 1, + .name = "PCM Capture Volume", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0xfff, + .info = u8500_capture_vol_info, + .get = u8500_capture_vol_get, + .put = u8500_capture_vol_put +}; + +/** +* u8500_capture_vol_info +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions fills capture volume info into user structure. +*/ +static int u8500_capture_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 100; + uinfo->value.integer.step = 10; + return 0; +} + +/** +* u8500_capture_vol_get +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions returns the current capture volume setting to user structure. +*/ + +static int u8500_capture_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + + int *p_left_volume = NULL; + int *p_right_volume = NULL; + + p_left_volume = (int *)&uinfo->value.integer.value[0]; + p_right_volume = (int *)&uinfo->value.integer.value[1]; + + u8500_acodec_get_input_volume(chip->input_device, p_left_volume, + p_right_volume, USER_ALSA); + return 0; +} + +/** +* u8500_capture_vol_put +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure. +* +* This functions sets the capture audio codec volume with values provided. +*/ + +static int u8500_capture_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + int changed = 0, error = 0; + + if (chip->input_lvolume != uinfo->value.integer.value[0] + || chip->input_rvolume != uinfo->value.integer.value[1]) { + chip->input_lvolume = uinfo->value.integer.value[0]; + chip->input_rvolume = uinfo->value.integer.value[1]; + + if (chip->input_lvolume > 100) + chip->input_lvolume = 100; + else if (chip->input_lvolume < 0) + chip->input_lvolume = 0; + + if (chip->input_rvolume > 100) + chip->input_rvolume = 100; + else if (chip->input_rvolume < 0) + chip->input_rvolume = 0; + + error = u8500_acodec_set_input_volume(chip->input_device, + chip->input_rvolume, + chip->input_lvolume, + USER_ALSA); + if (error) { + stm_error(" : set input volume failed\n"); + return changed; + } + changed = 1; + } + + return changed; +} + +/* +**************************************************************************************** +* playback sink control * +**************************************************************************************** +*/ + +static struct snd_kcontrol_new u8500_playback_sink_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .device = 0, + .subdevice = 0, + .name = "PCM Playback Sink", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0xffff, + .info = u8500_playback_sink_info, + .get = u8500_playback_sink_get, + .put = u8500_playback_sink_put +}; + +/** +* u8500_playback_sink_info +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions fills playback device info into user structure. +*/ +static int u8500_playback_sink_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = NUMBER_OUTPUT_DEVICE; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= NUMBER_OUTPUT_DEVICE) + uinfo->value.enumerated.item = NUMBER_OUTPUT_DEVICE - 1; + strcpy(uinfo->value.enumerated.name, + codec_dest_texts[uinfo->value.enumerated.item]); + return 0; +} + +/** +* u8500_playback_sink_get +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions returns the current playback device selected. +*/ +static int u8500_playback_sink_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + uinfo->value.enumerated.item[0] = chip->output_device; + return 0; +} + +/** +* u8500_playback_sink_put +* @kcontrol - pointer to the snd_kcontrol structure +* @ . +* +* This functions sets the playback device. +*/ +static int u8500_playback_sink_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + int changed = 0, error; + + if (chip->output_device != uinfo->value.enumerated.item[0]) { + chip->output_device = uinfo->value.enumerated.item[0]; + error = + u8500_acodec_select_output(chip->output_device, + USER_ALSA, chip->tdm8_ch_mode); + if (error) { + stm_error(" : select output failed\n"); + return changed; + } + changed = 1; + } + return changed; +} + +/* +**************************************************************************************** +* capture src control * +**************************************************************************************** +*/ + +static struct snd_kcontrol_new u8500_capture_src_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .device = 0, + .subdevice = 1, + .name = "PCM Capture Source", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0xffff, + .info = u8500_capture_src_ctrl_info, + .get = u8500_capture_src_ctrl_get, + .put = u8500_capture_src_ctrl_put +}; + +/** +* u8500_capture_src_ctrl_info +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions fills capture device info into user structure. +*/ +static int u8500_capture_src_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = NUMBER_INPUT_DEVICE; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= NUMBER_INPUT_DEVICE) + uinfo->value.enumerated.item = NUMBER_INPUT_DEVICE - 1; + strcpy(uinfo->value.enumerated.name, + codec_in_texts[uinfo->value.enumerated.item]); + return 0; +} + +/** +* u8500_capture_src_ctrl_get +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions returns the current capture device selected. +*/ +static int u8500_capture_src_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + uinfo->value.enumerated.item[0] = chip->input_device; + return 0; +} + +/** +* u8500_capture_src_ctrl_put +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, +* +* This functions sets the capture device. +*/ +static int u8500_capture_src_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + int changed = 0, error; + + if (chip->input_device != uinfo->value.enumerated.item[0]) { + chip->input_device = uinfo->value.enumerated.item[0]; + error = + u8500_acodec_select_input(chip->input_device, USER_ALSA, + chip->tdm8_ch_mode); + if (error) { + stm_error(" : select input failed\n"); + return changed; + } + changed = 1; + } + return changed; +} + +/* +*************************************************************************************** +* analog lpbk control * +*************************************************************************************** +*/ + +struct snd_kcontrol_new u8500_analog_lpbk_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .device = 0, + .name = "Analog Loopback", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0xfff, + .info = u8500_analog_lpbk_info, + .get = u8500_analog_lpbk_get, + .put = u8500_analog_lpbk_put +}; + +/** +* u8500_analog_lpbk_info +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions fills playback device info into user structure. +*/ +static int u8500_analog_lpbk_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = NUMBER_LOOPBACK_STATE; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= NUMBER_LOOPBACK_STATE) + uinfo->value.enumerated.item = NUMBER_LOOPBACK_STATE - 1; + strcpy(uinfo->value.enumerated.name, + lpbk_state_in_texts[uinfo->value.enumerated.item]); + return 0; +} + +/** +* u8500_analog_lpbk_get +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions returns the current playback device selected. +*/ +static int u8500_analog_lpbk_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + uinfo->value.enumerated.item[0] = chip->analog_lpbk; + return 0; +} + +/** +* u8500_analog_lpbk_put +* @kcontrol - pointer to the snd_kcontrol structure +* @ . +* +* This functions sets the playback device. +*/ +static int u8500_analog_lpbk_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + int changed = 0; + t_ab8500_codec_error error; + + if (chip->analog_lpbk != uinfo->value.enumerated.item[0]) { + chip->analog_lpbk = uinfo->value.enumerated.item[0]; + + error = + u8500_acodec_toggle_analog_lpbk(chip->analog_lpbk, + USER_ALSA); + + if (AB8500_CODEC_OK != error) { + stm_error + (" : select u8500_acodec_set_analog_lpbk_state failed\n"); + return changed; + } + changed = 1; + } + return changed; +} + +/* +**************************************************************************************** +* digital lpbk control * +**************************************************************************************** +*/ + +struct snd_kcontrol_new u8500_digital_lpbk_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .device = 0, + .name = "Digital Loopback", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0xfff, + .info = u8500_digital_lpbk_info, + .get = u8500_digital_lpbk_get, + .put = u8500_digital_lpbk_put +}; + +/** +* u8500_digital_lpbk_info +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions fills playback device info into user structure. +*/ +static int u8500_digital_lpbk_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = NUMBER_LOOPBACK_STATE; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= NUMBER_LOOPBACK_STATE) + uinfo->value.enumerated.item = NUMBER_LOOPBACK_STATE - 1; + strcpy(uinfo->value.enumerated.name, + lpbk_state_in_texts[uinfo->value.enumerated.item]); + return 0; +} + +/** +* u8500_digital_lpbk_get +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions returns the current playback device selected. +*/ +static int u8500_digital_lpbk_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + uinfo->value.enumerated.item[0] = chip->digital_lpbk; + return 0; +} + +/** +* u8500_analog_lpbk_put +* @kcontrol - pointer to the snd_kcontrol structure +* @ . +* +* This functions sets the playback device. +*/ +static int u8500_digital_lpbk_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + int changed = 0; + t_ab8500_codec_error error; + + if (chip->digital_lpbk != uinfo->value.enumerated.item[0]) { + chip->digital_lpbk = uinfo->value.enumerated.item[0]; + + error = u8500_acodec_toggle_digital_lpbk(chip->digital_lpbk, + chip->output_device, + chip->input_device, + USER_ALSA, + chip->tdm8_ch_mode); + + /*if((error = u8500_acodec_set_output_volume(chip->output_device,50,50,USER_ALSA))) + { + stm_error(" : set output volume failed\n"); + return error; + } + + if ((error = u8500_acodec_set_input_volume(chip->input_device,50,50,USER_ALSA))) + { + stm_error(" : set input volume failed\n"); + return error; + } */ + + if (AB8500_CODEC_OK != error) { + stm_error + (" : select u8500_acodec_set_digital_lpbk_state failed\n"); + return changed; + } + changed = 1; + } + return changed; +} + +/* +**************************************************************************************** +* playback switch control * +**************************************************************************************** +*/ + +struct snd_kcontrol_new u8500_playback_switch_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .device = 0, + .subdevice = 0, + .name = "PCM Playback Mute", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0xfff, + .info = u8500_playback_switch_ctrl_info, + .get = u8500_playback_switch_ctrl_get, + .put = u8500_playback_switch_ctrl_put +}; + +/** +* u8500_playback_switch_ctrl_info +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions fills playback device info into user structure. +*/ +static int u8500_playback_switch_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = NUMBER_SWITCH_STATE; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= NUMBER_SWITCH_STATE) + uinfo->value.enumerated.item = NUMBER_SWITCH_STATE - 1; + strcpy(uinfo->value.enumerated.name, + switch_state_in_texts[uinfo->value.enumerated.item]); + return 0; +} + +/** +* u8500_playback_switch_ctrl_get +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions returns the current playback device selected. +*/ +static int u8500_playback_switch_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + uinfo->value.enumerated.item[0] = chip->playback_switch; + return 0; +} + +/** +* u8500_playback_switch_ctrl_put +* @kcontrol - pointer to the snd_kcontrol structure +* @ . +* +* This functions sets the playback device. +*/ +static int u8500_playback_switch_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + int changed = 0; + t_ab8500_codec_error error; + + if (chip->playback_switch != uinfo->value.enumerated.item[0]) { + chip->playback_switch = uinfo->value.enumerated.item[0]; + + error = + u8500_acodec_toggle_playback_mute_control(chip-> + output_device, + chip-> + playback_switch, + USER_ALSA); + + if (AB8500_CODEC_OK != error) { + stm_error + (" : select u8500_playback_switch_ctrl_put failed\n"); + return changed; + } + changed = 1; + } + return changed; +} + +/* +**************************************************************************************** +* Capture switch control * +**************************************************************************************** +*/ + +struct snd_kcontrol_new u8500_capture_switch_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .device = 0, + .subdevice = 1, + .name = "PCM Capture Mute", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0xfff, + .info = u8500_capture_switch_ctrl_info, + .get = u8500_capture_switch_ctrl_get, + .put = u8500_capture_switch_ctrl_put +}; + +/** +* u8500_capture_switch_ctrl_info +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions fills playback device info into user structure. +*/ +static int u8500_capture_switch_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = NUMBER_SWITCH_STATE; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= NUMBER_SWITCH_STATE) + uinfo->value.enumerated.item = NUMBER_SWITCH_STATE - 1; + strcpy(uinfo->value.enumerated.name, + switch_state_in_texts[uinfo->value.enumerated.item]); + return 0; +} + +/** +* u8500_capture_switch_ctrl_get +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions returns the current playback device selected. +*/ +static int u8500_capture_switch_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + uinfo->value.enumerated.item[0] = chip->capture_switch; + return 0; +} + +/** +* u8500_capture_switch_ctrl_put +* @kcontrol - pointer to the snd_kcontrol structure +* @ . +* +* This functions sets the playback device. +*/ +static int u8500_capture_switch_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + int changed = 0; + t_ab8500_codec_error error; + + if (chip->capture_switch != uinfo->value.enumerated.item[0]) { + chip->capture_switch = uinfo->value.enumerated.item[0]; + + error = + u8500_acodec_toggle_capture_mute_control(chip->input_device, + chip-> + capture_switch, + USER_ALSA); + + if (AB8500_CODEC_OK != error) { + stm_error + (" : select u8500_capture_switch_ctrl_put failed\n"); + return changed; + } + changed = 1; + } + return changed; +} + +/* +**************************************************************************************** +* playback power control * +**************************************************************************************** +*/ + +struct snd_kcontrol_new u8500_playback_power_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .device = 0, + .subdevice = 0, + .name = "PCM Playback Power", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0xfff, + .info = u8500_playback_power_ctrl_info, + .get = u8500_playback_power_ctrl_get, + .put = u8500_playback_power_ctrl_put +}; + +/** +* u8500_playback_power_ctrl_info +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions fills playback device info into user structure. +*/ +static int u8500_playback_power_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = NUMBER_POWER_STATE; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= NUMBER_POWER_STATE) + uinfo->value.enumerated.item = NUMBER_POWER_STATE - 1; + strcpy(uinfo->value.enumerated.name, + power_state_in_texts[uinfo->value.enumerated.item]); + return 0; +} + +/** +* u8500_playback_power_ctrl_get +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions returns the current playback device selected. +*/ +static int u8500_playback_power_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + uinfo->value.enumerated.item[0] = + u8500_acodec_get_dest_power_state(chip->output_device); + return 0; +} + +/** +* u8500_playback_power_ctrl_put +* @kcontrol - pointer to the snd_kcontrol structure +* @ . +* +* This functions sets the playback device. +*/ +static int u8500_playback_power_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + int changed = 0; + t_ab8500_codec_error error; + t_u8500_bool_state power_state; + + power_state = u8500_acodec_get_dest_power_state(chip->output_device); + + if (power_state != uinfo->value.enumerated.item[0]) { + power_state = uinfo->value.enumerated.item[0]; + + error = + u8500_acodec_set_dest_power_cntrl(chip->output_device, + power_state); + + if (AB8500_CODEC_OK != error) { + stm_error + (" : select u8500_acodec_set_dest_power_cntrl failed\n"); + return changed; + } + + /* configure the volume settings for the acodec */ + if ((error = + u8500_acodec_set_output_volume(chip->output_device, + chip->output_lvolume, + chip->output_rvolume, + USER_ALSA))) { + stm_error(" : set output volume failed\n"); + return error; + } + changed = 1; + } + return changed; +} + +/* +**************************************************************************************** +* capture power control * +**************************************************************************************** +*/ + +struct snd_kcontrol_new u8500_capture_power_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .device = 0, + .subdevice = 0, + .name = "PCM Capture Power", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0xfff, + .info = u8500_capture_power_ctrl_info, + .get = u8500_capture_power_ctrl_get, + .put = u8500_capture_power_ctrl_put +}; + +/** +* u8500_capture_power_ctrl_info +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions fills playback device info into user structure. +*/ +static int u8500_capture_power_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = NUMBER_POWER_STATE; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= NUMBER_POWER_STATE) + uinfo->value.enumerated.item = NUMBER_POWER_STATE - 1; + strcpy(uinfo->value.enumerated.name, + power_state_in_texts[uinfo->value.enumerated.item]); + return 0; +} + +/** +* u8500_capture_power_ctrl_get +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions returns the current playback device selected. +*/ +static int u8500_capture_power_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + uinfo->value.enumerated.item[0] = + u8500_acodec_get_src_power_state(chip->input_device); + return 0; +} + +/** +* u8500_capture_power_ctrl_put +* @kcontrol - pointer to the snd_kcontrol structure +* @ . +* +* This functions sets the playback device. +*/ +static int u8500_capture_power_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + int changed = 0; + t_ab8500_codec_error error; + t_u8500_bool_state power_state; + + power_state = u8500_acodec_get_src_power_state(chip->input_device); + + if (power_state != uinfo->value.enumerated.item[0]) { + power_state = uinfo->value.enumerated.item[0]; + + error = + u8500_acodec_set_src_power_cntrl(chip->input_device, + power_state); + + if (AB8500_CODEC_OK != error) { + stm_error + (" : select u8500_acodec_set_src_power_cntrl failed\n"); + return changed; + } + changed = 1; + } + return changed; +} + +/* +**************************************************************************************** +* TDM 8 channel mode control * +**************************************************************************************** +*/ + +struct snd_kcontrol_new u8500_tdm_mode_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .device = 0, + .subdevice = 0, + .name = "TDM 8 Channel Mode", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0xfff, + .info = u8500_tdm_mode_ctrl_info, + .get = u8500_tdm_mode_ctrl_get, + .put = u8500_tdm_mode_ctrl_put +}; + +/** +* u8500_tdm_mode_ctrl_info +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions fills playback device info into user structure. +*/ +static int u8500_tdm_mode_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = NUMBER_TDM_MODE_STATE; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= NUMBER_TDM_MODE_STATE) + uinfo->value.enumerated.item = NUMBER_TDM_MODE_STATE - 1; + strcpy(uinfo->value.enumerated.name, + tdm_mode_state_in_texts[uinfo->value.enumerated.item]); + return 0; +} + +/** +* u8500_tdm_mode_ctrl_get +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions returns the current playback device selected. +*/ +static int u8500_tdm_mode_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + uinfo->value.enumerated.item[0] = chip->tdm8_ch_mode; + return 0; +} + +/** +* u8500_tdm_mode_ctrl_put +* @kcontrol - pointer to the snd_kcontrol structure +* @ . +* +* This functions sets the playback device. +*/ +static int u8500_tdm_mode_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + int changed = 0; + t_ab8500_codec_error error; + + chip->tdm8_ch_mode = uinfo->value.enumerated.item[0]; + + if (ENABLE == chip->tdm8_ch_mode) + printk("\n TDM 8 channel mode enabled\n"); + else + printk("\n TDM 8 channel mode disabled\n"); + + changed = 1; + + return changed; +} + +/* +**************************************************************************************** +* Direct Rendering Mode control * +**************************************************************************************** +*/ + +struct snd_kcontrol_new u8500_direct_rendering_mode_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .device = 0, + .name = "Direct Rendering Mode", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0xfff, + .info = u8500_direct_rendering_mode_ctrl_info, + .get = u8500_direct_rendering_mode_ctrl_get, + .put = u8500_direct_rendering_mode_ctrl_put +}; + +/** +* u8500_direct_rendering_mode_ctrl_info +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions fills playback device info into user structure. +*/ +static int u8500_direct_rendering_mode_ctrl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info + *uinfo) +{ + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = NUMBER_DIRECT_RENDERING_STATE; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= NUMBER_DIRECT_RENDERING_STATE) + uinfo->value.enumerated.item = + NUMBER_DIRECT_RENDERING_STATE - 1; + strcpy(uinfo->value.enumerated.name, + direct_rendering_state_in_texts[uinfo->value.enumerated.item]); + return 0; +} + +/** +* u8500_direct_rendering_mode_ctrl_get +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions returns the current playback device selected. +*/ +static int u8500_direct_rendering_mode_ctrl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value + *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + uinfo->value.enumerated.item[0] = chip->direct_rendering_mode; + return 0; +} + +/** +* u8500_direct_rendering_mode_ctrl_put +* @kcontrol - pointer to the snd_kcontrol structure +* @ . +* +* This functions sets the playback device. +*/ +static int u8500_direct_rendering_mode_ctrl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value + *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + int changed = 0; + t_ab8500_codec_error error; + + chip->direct_rendering_mode = uinfo->value.enumerated.item[0]; + changed = 1; + + return changed; +} + +/* +**************************************************************************************** +* PCM Rendering Mode control * +**************************************************************************************** +*/ + +struct snd_kcontrol_new u8500_pcm_rendering_mode_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .device = 0, + .name = "PCM Rendering Mode", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0xfff, + .info = u8500_pcm_rendering_mode_ctrl_info, + .get = u8500_pcm_rendering_mode_ctrl_get, + .put = u8500_pcm_rendering_mode_ctrl_put +}; + +/** +* u8500_pcm_rendering_mode_ctrl_info +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions fills playback device info into user structure. +*/ +static int u8500_pcm_rendering_mode_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = NUMBER_PCM_RENDERING_STATE; + uinfo->count = 3; + if (uinfo->value.enumerated.item >= NUMBER_PCM_RENDERING_STATE) + uinfo->value.enumerated.item = NUMBER_PCM_RENDERING_STATE - 1; + strcpy(uinfo->value.enumerated.name, + pcm_rendering_state_in_texts[uinfo->value.enumerated.item]); + return 0; +} + +/** +* u8500_pcm_rendering_mode_ctrl_get +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions returns the current playback device selected. +*/ +static int u8500_pcm_rendering_mode_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + uinfo->value.enumerated.item[0] = chip->burst_fifo_mode; + uinfo->value.enumerated.item[1] = chip->fm_playback_mode; + uinfo->value.enumerated.item[2] = chip->fm_tx_mode; + return 0; +} + +/** +* u8500_pcm_rendering_mode_ctrl_put +* @kcontrol - pointer to the snd_kcontrol structure +* @ . +* +* This functions sets the playback device. +*/ +static int u8500_pcm_rendering_mode_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + int changed = 0; + t_ab8500_codec_error error; + + if (RENDERING_PENDING == uinfo->value.enumerated.item[0]) { + return changed; + } + if (chip->burst_fifo_mode != uinfo->value.enumerated.item[0]) { + chip->burst_fifo_mode = uinfo->value.enumerated.item[0]; + u8500_acodec_set_burst_mode_fifo(chip->burst_fifo_mode); + } + + chip->fm_playback_mode = uinfo->value.enumerated.item[1]; + chip->fm_tx_mode = uinfo->value.enumerated.item[2]; + + changed = 1; + + return changed; +} + +#if 0 /* DUMP REGISTER CONTROL */ +/* +**************************************************************************************** +* dump registers control * +**************************************************************************************** +*/ + +struct snd_kcontrol_new u8500_dump_register_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .device = 0, + .name = "", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0xfff, + .info = u8500_dump_register_ctrl_info, + .get = u8500_dump_register_ctrl_get, + .put = u8500_dump_register_ctrl_put +}; + +/** +* u8500_dump_register_ctrl_info +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions fills playback device info into user structure. +*/ +static int u8500_dump_register_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = NUMBER_PCM_RENDERING_STATE; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= NUMBER_PCM_RENDERING_STATE) + uinfo->value.enumerated.item = NUMBER_PCM_RENDERING_STATE - 1; + strcpy(uinfo->value.enumerated.name, + pcm_rendering_state_in_texts[uinfo->value.enumerated.item]); + return 0; +} + +/** +* u8500_dump_register_ctrl_get +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions returns the current playback device selected. +*/ +static int u8500_dump_register_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + uinfo->value.enumerated.item[0] = chip->burst_fifo_mode; + uinfo->value.enumerated.item[1] = chip->fm_playback_mode; + uinfo->value.enumerated.item[2] = chip->fm_tx_mode; + return 0; +} + +/** +* u8500_dump_register_ctrl_put +* @kcontrol - pointer to the snd_kcontrol structure +* @ . +* +* This functions sets the playback device. +*/ +static int u8500_dump_register_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + int changed = 0; + t_ab8500_codec_error error; + + if (RENDERING_PENDING == uinfo->value.enumerated.item[0]) { + return changed; + } + if (chip->burst_fifo_mode != uinfo->value.enumerated.item[0]) { + chip->burst_fifo_mode = uinfo->value.enumerated.item[0]; + //u8500_acodec_set_burst_mode_fifo(chip->burst_fifo_mode); + } + + chip->fm_playback_mode = uinfo->value.enumerated.item[1]; + chip->fm_tx_mode = uinfo->value.enumerated.item[2]; + + changed = 1; + + return changed; +} + +#endif /* DUMP REGISTER CONTROL */ + +/* Hardware description , this structure (struct snd_pcm_hardware ) + * contains the definitions of the fundamental hardware configuration. + * This configuration will be applied on the runtime structure + */ +static struct snd_pcm_hardware snd_u8500_playback_hw = { + .info = + (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_PAUSE), + .formats = + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | + SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U16_BE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE | + SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_U24_BE | + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE | + SNDRV_PCM_FMTBIT_S32_BE | SNDRV_PCM_FMTBIT_U32_BE, + .rates = SNDRV_PCM_RATE_KNOT, + .rate_min = MIN_RATE_PLAYBACK, + .rate_max = MAX_RATE_PLAYBACK, + .channels_min = 1, + .channels_max = 8, + .buffer_bytes_max = NMDK_BUFFER_SIZE, + .period_bytes_min = 128, + .period_bytes_max = PAGE_SIZE, + .periods_min = NMDK_BUFFER_SIZE / PAGE_SIZE, + .periods_max = NMDK_BUFFER_SIZE / 128 +}; + +static struct snd_pcm_hardware snd_u8500_capture_hw = { + .info = + (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_PAUSE), + .formats = + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | + SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U16_BE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE | + SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_U24_BE | + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE | + SNDRV_PCM_FMTBIT_S32_BE | SNDRV_PCM_FMTBIT_U32_BE, + .rates = SNDRV_PCM_RATE_KNOT, + .rate_min = MIN_RATE_CAPTURE, + .rate_max = MAX_RATE_CAPTURE, + .channels_min = 1, + .channels_max = 8, + .buffer_bytes_max = NMDK_BUFFER_SIZE, + .period_bytes_min = 128, + .period_bytes_max = PAGE_SIZE, + .periods_min = NMDK_BUFFER_SIZE / PAGE_SIZE, + .periods_max = NMDK_BUFFER_SIZE / 128 +}; + +static struct snd_pcm_hw_constraint_list constraints_rate = { + .count = sizeof(u8500_acodec_rates) / sizeof(u8500_acodec_rates[0]), + .list = u8500_acodec_rates, + .mask = 0, +}; + +/** + * snd_u8500_alsa_pcm_close + * @substream - pointer to the playback/capture substream structure + * + * This routine is used by alsa framework to close a pcm stream . + * Here a dma pipe is disabled and freed. + */ +static int snd_u8500_alsa_pcm_close(struct snd_pcm_substream *substream) +{ + int stream_id, error = 0; + u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream); + audio_stream_t *ptr_audio_stream = NULL; + + stream_id = substream->pstr->stream; + ptr_audio_stream = &chip->stream[ALSA_PCM_DEV][stream_id]; + + if (ENABLE == chip->direct_rendering_mode) { + ptr_audio_stream->substream = NULL; + return 0; + } else { + stm_close_alsa(chip, ALSA_PCM_DEV, stream_id); + + /* reset the different variables to default */ + + ptr_audio_stream->active = 0; + ptr_audio_stream->period = 0; + ptr_audio_stream->periods = 0; + ptr_audio_stream->old_offset = 0; + ptr_audio_stream->substream = NULL; + if (!(--active_user)) { + /* Disable the MSP1 */ + error = u8500_acodec_unsetuser(USER_ALSA); + u8500_acodec_close(I2S_CLIENT_MSP1, ACODEC_DISABLE_ALL); + } else { + if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) + u8500_acodec_close(I2S_CLIENT_MSP1, + ACODEC_DISABLE_TRANSMIT); + else if (stream_id == SNDRV_PCM_STREAM_CAPTURE) + u8500_acodec_close(I2S_CLIENT_MSP1, + ACODEC_DISABLE_RECEIVE); + } + + stm_hw_free(substream); + + return error; + } +} + +void my_write(u32 address, u8 data) +{ + ab8500_write(AB8500_AUDIO, address, data); +} + +void dsp_configure_audio_codec(void) +{ + //4500 config for both record DMIC1&2 and playback HS stereo + //data width is 16 bits + + my_write(0x200, 0x02); // Start-up audio unreset + my_write(0x20B, 0x10); // Start-up audio clk audio enable + my_write(0x383, 0x06); // Start-up audio Vaudio supply + + my_write(0xD00, 0x88); // General power up=0x88 + my_write(0xD01, 0x00); // Software Reset=0x0 + my_write(0xD02, 0xC0); // Digital AD Channels Enable=0xC0 + my_write(0xD03, 0xC0); // Digital DA Channels Enable=0xC0 + my_write(0xD04, 0x00); // Low Power and Conf=0x0 + my_write(0xD05, 0x0F); // Line in Conf=0xF + my_write(0xD06, 0xC0); // Analog Inputs Enable=0xC0 + my_write(0xD07, 0x30); // ADC Enable=0x30 + my_write(0xD08, 0x30); // Analog Output Enable=0x30 + my_write(0xD09, 0x30); // Digital Output Enable=0x30 + my_write(0xD0A, 0x4F); // Mute Enable=0x4F + my_write(0xD0B, 0x7F); // Short Circuit Disable=0x7F + my_write(0xD0C, 0x80); // Power-up for Headset=0x80 + my_write(0xD0D, 0x00); // Envelope Threshold=0x0 + my_write(0xD0E, 0x00); // Envelope Decay Time=0x0 + my_write(0xD0F, 0xF0); // Class-D Configuration=0xF0 + my_write(0xD10, 0x32); // PWM VIBNL Configuration=0x32 + my_write(0xD11, 0x32); // PWM VIBPL Configuration=0x32 + my_write(0xD12, 0x32); // PWM VIBNR Configuration=0x32 + my_write(0xD13, 0x32); // PWM VIBPR Configuration=0x32 + my_write(0xD14, 0x00); // Microphone 1 Gain=0x0 + my_write(0xD15, 0x00); // Microphone 2 Gain=0x0 + my_write(0xD16, 0x00); // Left line-in and HS Analog Gain=0x0 + my_write(0xD17, 0x00); // Right line-in and HS Analog Gain=0x0 + my_write(0xD18, 0x1F); // Line-in to HSL Gain=0x1F + my_write(0xD19, 0x1F); // Line-in to HSR Gain=0x1F + my_write(0xD1A, 0xF0); // AD Channel Filters Configuration=0xF0 + my_write(0xD1B, 0x85); // TDM Configuration 1=0x85 + my_write(0xD1C, 0x94); // TDM Configuration 2=0x94 + my_write(0xD1D, 0x02); // TDM loopback control=0x2 + my_write(0xD1E, 0x00); // TDM format=0x0 + my_write(0xD1F, 0x10); // AD Data allocation in Slot 0 to 1=0x10 + my_write(0xD20, 0xCC); // AD Data allocation in Slot 2 to 3=0xCC + my_write(0xD21, 0xCC); // AD Data allocation in Slots 4 to 5=0xCC + my_write(0xD22, 0xCC); // AD Data allocation in Slots 6 to 7=0xCC + my_write(0xD23, 0xCC); // AD Data allocation in Slots 8 to 9=0xCC + my_write(0xD24, 0xCC); // AD Data allocation in Slots 10 to 11=0xCC + my_write(0xD25, 0xCC); // AD Data allocation in Slots 12 to 13=0xCC + my_write(0xD26, 0xCC); // AD Data allocation in Slots 14 to 15=0xCC + my_write(0xD27, 0xCC); // AD Data allocation in Slots 16 to 17=0xCC + my_write(0xD28, 0xCC); // AD Data allocation in Slots 18 to 19=0xCC + my_write(0xD29, 0xCC); // AD Data allocation in Slots 20 to 21=0xCC + my_write(0xD2A, 0xCC); // AD Data allocation in Slots 22 to 23=0xCC + my_write(0xD2B, 0xCC); // AD Data allocation in Slots 24 to 25=0xCC + my_write(0xD2C, 0xCC); // AD Data allocation in Slots 26 to 27=0xCC + my_write(0xD2D, 0xCC); // AD Data allocation in Slots 28 to 29=0xCC + my_write(0xD2E, 0xCC); // AD Data allocation in Slots 30 to 31=0xCC + my_write(0xD2F, 0x00); // AD slot 0/7 tristate=0x0 + my_write(0xD30, 0x00); // AD slot 8/15 tristate=0x0 + my_write(0xD31, 0x00); // AD slot 16/23 tristate=0x0 + my_write(0xD32, 0x00); // AD slot 24/31 tristate=0x0 + my_write(0xD33, 0x08); // Slots selection for DA path 1=0x8 + my_write(0xD34, 0x09); // Slots selection for DA path 2=0x9 + my_write(0xD35, 0x00); // Slots selection for DA path 3=0x0 + my_write(0xD36, 0x00); // Slots selection for DA path 4=0x0 + my_write(0xD37, 0x00); // Slots selection for DA path 5=0x0 + my_write(0xD38, 0x00); // Slots selection for DA path 6=0x0 + my_write(0xD39, 0x00); // IRQ mask lsb=0x0 + my_write(0xD3A, 0x00); // IRQ status lsb=0x0 + my_write(0xD3B, 0x00); // IRQ mask msb=0x0 + my_write(0xD3C, 0x00); // IRQ status msb=0x0 + my_write(0xD3D, 0x00); // Fade speed=0x0 + my_write(0xD3E, 0x00); // DMIC decimator filter=0x0 + my_write(0xD3F, 0xF0); // muxing lsb=0xF0 + my_write(0xD40, 0x00); // muxing msb=0x0 + my_write(0xD41, 0x1F); // AD1 Digital Gain=0x1F + my_write(0xD42, 0x1F); // AD2 Digital Gain=0x1F + my_write(0xD43, 0x1F); // AD3 Digital Gain=0x1F + my_write(0xD44, 0x1F); // AD4 Digital Gain=0x1F + my_write(0xD45, 0x1F); // AD5 Digital Gain=0x1F + my_write(0xD46, 0x1F); // AD6 Digital Gain=0x1F + my_write(0xD47, 0x00); // DA1 digital Gain=0x00 + my_write(0xD48, 0x00); // DA2 digital Gain=0x00 + my_write(0xD49, 0x3F); // DA3 digital Gain=0x3F + my_write(0xD4A, 0x3F); // DA4 digital Gain=0x3F + my_write(0xD4B, 0x3F); // DA5 digital Gain=0x3F + my_write(0xD4C, 0x3F); // DA6 digital Gain=0x3F + my_write(0xD4D, 0x3F); // AD1 loopback to HFL digital gain=0x3F + my_write(0xD4E, 0x3F); // AD2 loopback to HFR digital gain=0x3F + my_write(0xD4F, 0x08); // HSL and EAR digital gain=0x8 + my_write(0xD50, 0x08); // HSR digital gain=0x8 + my_write(0xD51, 0x1F); // Side tone FIR1 gain=0x1F + my_write(0xD52, 0x1F); // Side tone FIR2 gain=0x1F + my_write(0xD53, 0x00); // ANC filter control=0x0 + my_write(0xD54, 0x00); // ANC Warped Delay Line Shift=0x0 + my_write(0xD55, 0x00); // ANC FIR output Shift=0x0 + my_write(0xD56, 0x00); // ANC IIR output Shift=0x0 + my_write(0xD57, 0x00); // ANC FIR coefficients msb=0x0 + my_write(0xD58, 0x00); // ANC FIR coefficients lsb=0x0 + my_write(0xD59, 0x00); // ANC IIR coefficients msb=0x0 + my_write(0xD5A, 0x00); // ANC IIR coefficients lsb=0x0 + my_write(0xD5B, 0x00); // ANC Warp delay msb=0x0 + my_write(0xD5C, 0x00); // ANC Warp delay lsb=0x0 + my_write(0xD5D, 0x00); // ANC FIR peak register MSB=0x0 + my_write(0xD5E, 0x00); // ANC FIR peak register LSB=0x0 + my_write(0xD5F, 0x00); // ANC IIR peak register. MSB part=0x0 + my_write(0xD60, 0x00); // ANC IIR peak register. LSB part=0x0 + my_write(0xD61, 0x00); // Side tone FIR address=0x0 + my_write(0xD62, 0x00); // Side tone FIR coefficient MSB=0x0 + my_write(0xD63, 0x00); // Side tone FIR coefficient LSB=0x0 + my_write(0xD64, 0x00); // Filters control=0x0 + my_write(0xD65, 0x00); // Class D EMI Control=0x0 + my_write(0xD66, 0x00); // Class D control path=0x0 + my_write(0xD67, 0x00); // Class D control gain=0x0 + my_write(0xD68, 0x00); // Burst FIFO int control=0x0 + my_write(0xD69, 0x00); // Burst FIFO length=0x0 + my_write(0xD6A, 0x00); // Burst FIFO control=0x0 + my_write(0xD6B, 0x00); // Burst FIFO switch frame=0x0 + my_write(0xD6C, 0x00); // Burst FIFO wake up delay=0x0 + my_write(0xD6D, 0x00); // Burst FIFO samples number=0x0 + my_write(0xD70, 0x00); // CR112=0x0 + my_write(0xD71, 0x04); // CR113=0x4 + my_write(0xD72, 0x00); // CR114=0x0 + my_write(0xD73, 0x00); // CR115=0x0 + my_write(0xD74, 0x00); // CR116=0x0 + my_write(0xD75, 0x00); // CR117=0x0 + my_write(0xD76, 0x00); // CR118=0x0 + my_write(0xD77, 0x00); // CR119=0x0 + my_write(0xD78, 0x00); // CR120=0x0 + my_write(0xD79, 0x00); // CR121=0x0 + my_write(0xD7A, 0x00); // CR122=0x0 + my_write(0xD7B, 0x00); // CR123=0x0 +} + +static int configure_direct_rendering(struct snd_pcm_substream *substream) +{ + int error = 0, stream_id; + int status = 0; + struct snd_pcm_runtime *runtime = substream->runtime; + u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream); + audio_stream_t *ptr_audio_stream = NULL; + + stream_id = substream->pstr->stream; + + if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) { + runtime->hw = snd_u8500_playback_hw; + } else { + runtime->hw = snd_u8500_capture_hw; + } + + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x04))); //MSP_GCR + + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x08))); //MSP + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x0C))); //MSP + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x10))); //MSP + + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x30))); //MSP + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x34))); //MSP + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x38))); //MSP + + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x40))); //MSP + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x44))); //MSP + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x48))); //MSP + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x4C))); //MSP + + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x60))); //MSP + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x64))); //MSP + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x68))); //MSP + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x6C))); //MSP + + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x18))); //MSP + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x20))); //MSP + writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x2C))); //MSP + + dsp_configure_audio_codec(); + +#if DRIVER_DEBUG > 0 + { + dump_msp_registers(); + dump_acodec_registers(); + } +#endif + + ptr_audio_stream = &chip->stream[ALSA_PCM_DEV][stream_id]; + + ptr_audio_stream->substream = substream; + + FUNC_EXIT(); + return 0; +} + +/** + * snd_u8500_alsa_pcm_open + * @substream - pointer to the playback/capture substream structure + * + * This routine is used by alsa framework to open a pcm stream . + * Here a dma pipe is requested and device is configured(default). + */ +static int snd_u8500_alsa_pcm_open(struct snd_pcm_substream *substream) +{ + int error = 0, stream_id, status = 0; + u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + audio_stream_t *ptr_audio_stream = NULL; + + FUNC_ENTER(); + + if (ENABLE == chip->direct_rendering_mode) { + configure_direct_rendering(substream); + return 0; + } else { + stream_id = substream->pstr->stream; + status = u8500_acodec_open(I2S_CLIENT_MSP1, stream_id); + + if (status) { + printk("failed in getting open\n"); + return -1; + } + + if (!active_user) + error = u8500_acodec_setuser(USER_ALSA); + if (error) + return error; + else + active_user++; + + error = + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_rate); + if (error < 0) { + stm_error + (": error initializing hw sample rate constraint\n"); + return error; + } + + /* configure the default sampling rate for the acodec */ + second_config = 0; + + if ((error = configure_rate(substream, ACODEC_CONFIG_REQUIRED))) + return error; + + /* Set the hardware configuration */ + stream_id = substream->pstr->stream; + if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) { + runtime->hw = snd_u8500_playback_hw; + /* configure the output sink for the acodec */ + if ((error = + u8500_acodec_select_output(chip->output_device, + USER_ALSA, + chip->tdm8_ch_mode))) { + stm_error(" : select output failed\n"); + return error; + } + + /* configure the volume settings for the acodec */ + if ((error = + u8500_acodec_set_output_volume(chip->output_device, + chip-> + output_lvolume, + chip-> + output_rvolume, + USER_ALSA))) { + stm_error(" : set output volume failed\n"); + return error; + } + } else { + runtime->hw = snd_u8500_capture_hw; + /* configure the input source for the acodec */ + if ((error = + u8500_acodec_select_input(chip->input_device, + USER_ALSA, + chip->tdm8_ch_mode))) { + stm_error(" : select input failed\n"); + return error; + } + /*u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_D_MICROPHONE_1,ENABLE); + u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_D_MICROPHONE_2,ENABLE); + + u8500_acodec_set_input_volume(AB8500_CODEC_SRC_D_MICROPHONE_1, + chip->input_lvolume, + chip->input_rvolume, + USER_ALSA); + + u8500_acodec_set_input_volume(AB8500_CODEC_SRC_D_MICROPHONE_2, + chip->input_lvolume, + chip->input_rvolume, + USER_ALSA); + */ + + if ((error = + u8500_acodec_set_input_volume(chip->input_device, + chip->input_lvolume, + chip->input_rvolume, + USER_ALSA))) { + stm_error(" : set input volume failed\n"); + return error; + } + } + + u8500_acodec_set_burst_mode_fifo(chip->burst_fifo_mode); + +#if DRIVER_DEBUG > 0 + { + dump_msp_registers(); + dump_acodec_registers(); + } +#endif + + ptr_audio_stream = &chip->stream[ALSA_PCM_DEV][stream_id]; + + ptr_audio_stream->substream = substream; + + if (DISABLE == chip->direct_rendering_mode) { + stm_config_hw(chip, substream, ALSA_PCM_DEV, stream_id); + } + sema_init(&(ptr_audio_stream->alsa_sem), 1); + init_completion(&(ptr_audio_stream->alsa_com)); + ptr_audio_stream->state = ALSA_STATE_UNPAUSE; + + FUNC_EXIT(); + return 0; + } +} + +/** + * snd_u8500_alsa_pcm_hw_params + * @substream - pointer to the playback/capture substream structure + * @hw_params - specifies the hw parameters like format/no of channels etc + * + * This routine is used by alsa framework to allocate a dma buffer + * used to transfer the data from user space to kernel space + * + */ +static int snd_u8500_alsa_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); +} + +/** + * snd_u8500_alsa_pcm_hw_free + * @substream - pointer to the playback/capture substream structure + * + * This routine is used by alsa framework to deallocate a dma buffer + * allocated berfore by snd_u8500_alsa_pcm_hw_params + */ +static int snd_u8500_alsa_pcm_hw_free(struct snd_pcm_substream *substream) +{ + stm_hw_free(substream); + return 0; +} + +/** + * snd_u8500_alsa_pcm_prepare + * @substream - pointer to the playback/capture substream structure + * + * This callback is called whene the pcm is "prepared" Here is possible + * to set the format type ,sample rate ,etc.The callback is called as + * well everytime a recovery after an underrun happens. + */ + +static int snd_u8500_alsa_pcm_prepare(struct snd_pcm_substream *substream) +{ + u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int error, stream_id; + + FUNC_ENTER(); + + if (chip->freq != runtime->rate || chip->channels != runtime->channels) { + stm_dbg(DBG_ST.alsa, " freq not same, %d %d\n", chip->freq, + runtime->rate); + stm_dbg(DBG_ST.alsa, " channels not same, %d %d\n", + chip->channels, runtime->channels); + if (chip->channels != runtime->channels) { + chip->channels = runtime->channels; + if ((error = + stm_config_hw(chip, substream, ALSA_PCM_DEV, + -1))) { + stm_dbg(DBG_ST.alsa, + "In func %s, stm_config_hw fails", + __FUNCTION__); + return error; + } + } + chip->freq = runtime->rate; + second_config = 1; + stream_id = substream->pstr->stream; + if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) + u8500_acodec_close(I2S_CLIENT_MSP1, + ACODEC_DISABLE_TRANSMIT); + else if (stream_id == SNDRV_PCM_STREAM_CAPTURE) + u8500_acodec_close(I2S_CLIENT_MSP1, + ACODEC_DISABLE_RECEIVE); + + error = u8500_acodec_open(I2S_CLIENT_MSP1, stream_id); + if (error) { + printk("failed in getting open\n"); + return -1; + } + if ((error = + configure_rate(substream, ACODEC_CONFIG_NOT_REQUIRED))) { + stm_dbg(DBG_ST.alsa, "In func %s, configure_rate fails", + __FUNCTION__); + return error; + } + } + + FUNC_EXIT(); + return 0; +} + +/** + * snd_u8500_alsa_pcm_trigger + * @substream - pointer to the playback/capture substream structure + * @cmd - specifies the command : start/stop/pause/resume + * + * This callback is called whene the pcm is started ,stopped or paused + * The action is specified in the second argument, SND_PCM_TRIGGER_XXX in + * <sound/pcm.h>. + * This callback is atomic and the interrupts are disabled , so you can't + * call other functions that need interrupts without possible risks + */ +static int snd_u8500_alsa_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + int stream_id = substream->pstr->stream; + audio_stream_t *stream = NULL; + u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream); + int error = 0; + + FUNC_ENTER(); + + stream = &chip->stream[ALSA_PCM_DEV][stream_id]; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + /* Start the pcm engine */ + stm_dbg(DBG_ST.alsa, " TRIGGER START\n"); + if (stream->active == 0) { + stream->active = 1; + stm_trigger_alsa(stream); + break; + } + stm_error(": H/w is busy\n"); + return -EINVAL; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + stm_dbg(DBG_ST.alsa, " SNDRV_PCM_TRIGGER_PAUSE_PUSH\n"); + if (stream->active == 1) { + stm_pause_alsa(stream); + } + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + stm_dbg(DBG_ST.alsa, " SNDRV_PCM_TRIGGER_PAUSE_RELEASE\n"); + if (stream->active == 1) + stm_unpause_alsa(stream); + break; + case SNDRV_PCM_TRIGGER_STOP: + /* Stop the pcm engine */ + stm_dbg(DBG_ST.alsa, " TRIGGER STOP\n"); + if (stream->active == 1) + stm_stop_alsa(stream); + break; + default: + stm_error(": invalid command in pcm trigger\n"); + return -EINVAL; + } + + FUNC_EXIT(); + return error; +} + +/** + * snd_u8500_alsa_pcm_pointer + * @substream - pointer to the playback/capture substream structure + * + * This callback is called whene the pcm middle layer inquires the current + * hardware position on the buffer .The position is returned in frames + * ranged from 0 to buffer_size -1 + */ +static snd_pcm_uframes_t snd_u8500_alsa_pcm_pointer(struct snd_pcm_substream + *substream) +{ + unsigned int offset; + u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream); + audio_stream_t *stream = + &chip->stream[ALSA_PCM_DEV][substream->pstr->stream]; + struct snd_pcm_runtime *runtime = stream->substream->runtime; + + offset = bytes_to_frames(runtime, stream->old_offset); + if (offset < 0 || stream->old_offset < 0) + stm_dbg(DBG_ST.alsa, " Offset=%i %i\n", offset, + stream->old_offset); + + return offset; +} + +static struct snd_pcm_ops snd_u8500_alsa_playback_ops = { + .open = snd_u8500_alsa_pcm_open, + .close = snd_u8500_alsa_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_u8500_alsa_pcm_hw_params, + .hw_free = snd_u8500_alsa_pcm_hw_free, + .prepare = snd_u8500_alsa_pcm_prepare, + .trigger = snd_u8500_alsa_pcm_trigger, + .pointer = snd_u8500_alsa_pcm_pointer, +}; + +static struct snd_pcm_ops snd_u8500_alsa_capture_ops = { + .open = snd_u8500_alsa_pcm_open, + .close = snd_u8500_alsa_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_u8500_alsa_pcm_hw_params, + .hw_free = snd_u8500_alsa_pcm_hw_free, + .prepare = snd_u8500_alsa_pcm_prepare, + .trigger = snd_u8500_alsa_pcm_trigger, + .pointer = snd_u8500_alsa_pcm_pointer, +}; + +#ifdef CONFIG_U8500_ACODEC_POLL + +/** +* u8500_alsa_pio_start +* @stream - pointer to the playback/capture audio_stream_t structure +* +* This function sends/receive one chunck of stream data to/from MSP +*/ +static void u8500_alsa_pio_start(audio_stream_t * stream) +{ + unsigned int offset, dma_size, stream_id; + int ret_val; + struct snd_pcm_substream *substream = stream->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + stream_id = substream->pstr->stream; + + FUNC_ENTER(); + dma_size = frames_to_bytes(runtime, runtime->period_size); + offset = dma_size * stream->period; + stream->old_offset = offset; + + stm_dbg(DBG_ST.alsa, " Transfer started\n"); + stm_dbg(DBG_ST.alsa, " address = %x size=%d\n", + (runtime->dma_addr + offset), dma_size); + + /* Send our stuff */ + if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) +#ifdef CONFIG_U8500_ACODEC_DMA + u8500_acodec_send_data(I2S_CLIENT_MSP1, + (void *)(runtime->dma_addr + offset), + dma_size, 1); +#else + u8500_acodec_send_data(I2S_CLIENT_MSP1, + (void *)(runtime->dma_area + offset), + dma_size, 0); +#endif + else +#ifdef CONFIG_U8500_ACODEC_DMA + u8500_acodec_receive_data(I2S_CLIENT_MSP1, + (void *)(runtime->dma_addr + offset), + dma_size, 1); +#else + u8500_acodec_receive_data(I2S_CLIENT_MSP1, + (void *)(runtime->dma_area + offset), + dma_size, 0); +#endif + + stream->period++; + stream->period %= runtime->periods; + stream->periods++; + + FUNC_EXIT(); + +} + +/** +* acodec_feeding_thread +* @data - void pointer to the playback/capture audio_stream_t structure +* +* This thread sends/receive data to MSP while stream is active +*/ +static int acodec_feeding_thread(void *data) +{ + audio_stream_t *stream = (audio_stream_t *) data; + + FUNC_ENTER(); + daemonize("acodec_feeding_thread"); + allow_signal(SIGKILL); + down(&stream->alsa_sem); + + while ((!signal_pending(current)) && (stream->active)) { + if (stream->state == ALSA_STATE_PAUSE) + wait_for_completion(&(stream->alsa_com)); + + u8500_alsa_pio_start(stream); + if (stream->substream) + snd_pcm_period_elapsed(stream->substream); + } + + up(&stream->alsa_sem); + + FUNC_EXIT(); + return 0; +} + +/** +* acodec_feeding_thread +* @stream - pointer to the playback/capture audio_stream_t structure +* +* This function creates a kernel thread . +*/ + +int spawn_acodec_feeding_thread(audio_stream_t * stream) +{ + pid_t pid; + + FUNC_ENTER(); + + pid = + kernel_thread(acodec_feeding_thread, stream, + CLONE_FS | CLONE_SIGHAND); + + FUNC_EXIT(); + return 0; +} +#endif + +/** + * dma_eot_handler + * @data - pointer to structure set in the dma callback handler + * + * This is the PCM tasklet handler linked to a pipe, its role is to tell + * the PCM middler layer whene the buffer position goes across the prescribed + * period size.To inform of this the snd_pcm_period_elapsed is called. + * + * this callback will be called in case of DMA_EVENT_TC only + */ +static void dma_eot_handler(void *data) +{ + audio_stream_t *stream = data; + + /* snd_pcm_period_elapsed() is _not_ to be protected + */ + stm_dbg(DBG_ST.alsa, + "One transfer complete.. going to start the next one\n"); + + if (stream->substream) + snd_pcm_period_elapsed(stream->substream); + if (stream->state == ALSA_STATE_PAUSE) + return; + if (stream->active == 1) { + u8500_alsa_dma_start(stream); + } +} + +/** + * u8500_alsa_dma_start - used to transmit or recive a dma chunk + * @stream - specifies the playback/record stream structure + */ +void u8500_alsa_dma_start(audio_stream_t * stream) +{ + unsigned int offset, dma_size, stream_id; + + struct snd_pcm_substream *substream = stream->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + u8500_acodec_chip_t *u8500_chip = NULL; + stream_id = substream->pstr->stream; + u8500_chip = snd_pcm_substream_chip(substream); + + dma_size = frames_to_bytes(runtime, runtime->period_size); + offset = dma_size * stream->period; + stream->old_offset = offset; + + if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) +#ifdef CONFIG_U8500_ACODEC_DMA + u8500_acodec_send_data(I2S_CLIENT_MSP1, + (void *)(runtime->dma_addr + offset), + dma_size, 1); +#else + u8500_acodec_send_data(I2S_CLIENT_MSP1, + (void *)(runtime->dma_area + offset), + dma_size, 0); +#endif + else +#ifdef CONFIG_U8500_ACODEC_DMA + u8500_acodec_receive_data(I2S_CLIENT_MSP1, + (void *)(runtime->dma_addr + offset), + dma_size, 1); +#else + u8500_acodec_receive_data(I2S_CLIENT_MSP1, + (void *)(runtime->dma_area + offset), + dma_size, 0); +#endif + + stm_dbg(DBG_ST.alsa, " DMA Transfer started\n"); + stm_dbg(DBG_ST.alsa, " address = %x size=%d\n", + (runtime->dma_addr + offset), dma_size); + + stream->period++; + stream->period %= runtime->periods; + stream->periods++; +} + +/** +* u8500_audio_init +* @chip - pointer to u8500_acodec_chip_t structure. +* +* This function intialises the u8500 chip structure with default values +*/ +static void u8500_audio_init(u8500_acodec_chip_t * chip) +{ + audio_stream_t *ptr_audio_stream = NULL; + + ptr_audio_stream = + &chip->stream[ALSA_PCM_DEV][SNDRV_PCM_STREAM_PLAYBACK]; + /* Setup DMA stuff */ + strlcpy(ptr_audio_stream->id, "u8500 playback", + sizeof(ptr_audio_stream->id)); + ptr_audio_stream->stream_id = SNDRV_PCM_STREAM_PLAYBACK; + + /* default initialization for playback */ + ptr_audio_stream->active = 0; + ptr_audio_stream->period = 0; + ptr_audio_stream->periods = 0; + ptr_audio_stream->old_offset = 0; + + ptr_audio_stream = + &chip->stream[ALSA_PCM_DEV][SNDRV_PCM_STREAM_CAPTURE]; + strlcpy(ptr_audio_stream->id, "u8500 capture", + sizeof(ptr_audio_stream->id)); + ptr_audio_stream->stream_id = SNDRV_PCM_STREAM_CAPTURE; + + /* default initialization for capture */ + ptr_audio_stream->active = 0; + ptr_audio_stream->period = 0; + ptr_audio_stream->periods = 0; + ptr_audio_stream->old_offset = 0; + + chip->freq = DEFAULT_SAMPLE_RATE; + chip->channels = 1; + chip->input_lvolume = DEFAULT_GAIN; + chip->input_rvolume = DEFAULT_GAIN; + chip->output_lvolume = DEFAULT_VOLUME; + chip->output_rvolume = DEFAULT_VOLUME; + chip->output_device = DEFAULT_OUTPUT_DEVICE; + chip->input_device = DEFAULT_INPUT_DEVICE; + chip->analog_lpbk = DEFAULT_LOOPBACK_STATE; + chip->digital_lpbk = DEFAULT_LOOPBACK_STATE; + chip->playback_switch = DEFAULT_SWITCH_STATE; + chip->capture_switch = DEFAULT_SWITCH_STATE; + chip->tdm8_ch_mode = DEFAULT_TDM8_CH_MODE_STATE; + chip->direct_rendering_mode = DEFAULT_DIRECT_RENDERING_STATE; + chip->burst_fifo_mode = DEFAULT_BURST_FIFO_STATE; + chip->fm_playback_mode = DEFAULT_FM_PLAYBACK_STATE; + chip->fm_tx_mode = DEFAULT_FM_TX_STATE; + + //HDMI Default params set + chip->hdmi_params.sampling_freq = 48000; + chip->hdmi_params.channel_count = 2; +} + +/** + * snd_card_u8500_alsa_pcm_new - constructor for a new pcm cmponent + * @chip - pointer to chip specific data + * @device - specifies the card number + */ +static int snd_card_u8500_alsa_pcm_new(u8500_acodec_chip_t * chip, int device) +{ + struct snd_pcm *pcm; + int err; + + if ((err = snd_pcm_new(chip->card, "u8500", device, 1, 1, &pcm)) < 0) { + stm_error(": error in snd_pcm_new\n"); + return err; + } + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_u8500_alsa_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_u8500_alsa_capture_ops); + + pcm->private_data = chip; + pcm->info_flags = 0; + chip->pcm = pcm; + strcpy(pcm->name, "u8500_alsa"); + + u8500_audio_init(pcm->private_data); + return 0; +} + +static int u8500_register_alsa_controls(struct snd_card *card, + u8500_acodec_chip_t * u8500_chip) +{ + int error; + + if ((error = + snd_ctl_add(card, + snd_ctl_new1(&u8500_playback_vol_ctrl, + u8500_chip))) < 0) { + stm_error + (": error initializing u8500_playback_vol_ctrl interface \n\n"); + return (-1); + } + + if ((error = + snd_ctl_add(card, + snd_ctl_new1(&u8500_capture_vol_ctrl, + u8500_chip))) < 0) { + stm_error + (": error initializing u8500_capture_vol_ctrl interface \n\n"); + return (-1); + } + + if ((error = + snd_ctl_add(card, + snd_ctl_new1(&u8500_playback_sink_ctrl, + u8500_chip))) < 0) { + stm_error(": error initializing playback ctrl interface \n\n"); + return (-1); + } + + if ((error = + snd_ctl_add(card, + snd_ctl_new1(&u8500_capture_src_ctrl, + u8500_chip))) < 0) { + stm_error + (": error initializing u8500_playback_sink_ctrl interface \n\n"); + return (-1); + } + + if ((error = + snd_ctl_add(card, + snd_ctl_new1(&u8500_analog_lpbk_ctrl, + u8500_chip))) < 0) { + stm_error + (": error initializing u8500_analog_lpbk_ctrl interface \n\n"); + return (-1); + } + + if ((error = + snd_ctl_add(card, + snd_ctl_new1(&u8500_digital_lpbk_ctrl, + u8500_chip))) < 0) { + stm_error + (": error initializing u8500_digital_lpbk_ctrl interface \n\n"); + return (-1); + } + + if ((error = + snd_ctl_add(card, + snd_ctl_new1(&u8500_playback_switch_ctrl, + u8500_chip))) < 0) { + stm_error + (": error initializing u8500_playback_switch_ctrl interface \n\n"); + return (-1); + } + + if ((error = + snd_ctl_add(card, + snd_ctl_new1(&u8500_capture_switch_ctrl, + u8500_chip))) < 0) { + stm_error + (": error initializing u8500_capture_switch_ctrl interface \n\n"); + return (-1); + } + + if ((error = + snd_ctl_add(card, + snd_ctl_new1(&u8500_playback_power_ctrl, + u8500_chip))) < 0) { + stm_error + (": error initializing u8500_playback_power_ctrl interface \n\n"); + return (-1); + } + + if ((error = + snd_ctl_add(card, + snd_ctl_new1(&u8500_capture_power_ctrl, + u8500_chip))) < 0) { + stm_error + (": error initializing u8500_capture_power_ctrl interface \n\n"); + return (-1); + } + + if ((error = + snd_ctl_add(card, + snd_ctl_new1(&u8500_tdm_mode_ctrl, u8500_chip))) < 0) { + stm_error + (": error initializing u8500_tdm_mode_ctrl interface \n\n"); + return (-1); + } + + if ((error = + snd_ctl_add(card, + snd_ctl_new1(&u8500_direct_rendering_mode_ctrl, + u8500_chip))) < 0) { + stm_error + (": error initializing u8500_direct_rendering_mode_ctrl interface \n\n"); + return (-1); + } + + if ((error = + snd_ctl_add(card, + snd_ctl_new1(&u8500_pcm_rendering_mode_ctrl, + u8500_chip))) < 0) { + stm_error + (": error initializing u8500_pcm_rendering_mode_ctrl interface \n\n"); + return (-1); + } + + return 0; +} + +static int __init u8500_alsa_probe(struct platform_device *devptr) +{ + //static int card_count=0; + int error; + struct snd_card *card, *hdmi_card; + u8500_acodec_chip_t *u8500_chip; + + /*Set currently active users to 0 */ + active_user = 0; + + error = snd_card_create(0, NULL, THIS_MODULE, sizeof(u8500_acodec_chip_t), &card); + if (error < 0) { + stm_error(": error in snd_card_create\n"); + return error; + } + + u8500_chip = (u8500_acodec_chip_t *) card->private_data; + u8500_chip->card = card; + + if ((error = snd_card_u8500_alsa_pcm_new(u8500_chip, 0)) < 0) { + stm_error(": pcm interface can't be initialized\n\n"); + goto nodev; + } + + if ((error = snd_card_u8500_alsa_hdmi_new(u8500_chip, 1)) < 0) { + stm_error(": alsa HDMI interface can't be initialized\n\n"); + goto nodev; + } + + if (u8500_register_alsa_controls(card, u8500_chip) < 0) { + goto nodev; + } + + if (u8500_register_alsa_hdmi_controls(card, u8500_chip) < 0) { + goto nodev; + } +#if 0 + ///////////////////////////////$ H D M I $////////////////////////////////////// + + if (card_count == 1) { + hdmi_card = + snd_card_new(1, NULL, THIS_MODULE, + sizeof(u8500_acodec_chip_t)); + if (hdmi_card == NULL) { + stm_error(": error in hdmi - snd_card_new\n"); + return -ENOMEM; + } + + u8500_chip = (u8500_acodec_chip_t *) hdmi_card->private_data; + u8500_chip->card = hdmi_card; + + if ((error = snd_card_u8500_alsa_hdmi_new(u8500_chip, 0)) < 0) { + stm_error + (": alsa HDMI interface can't be initialized\n\n"); + goto nodev; + } + + if (u8500_register_alsa_hdmi_controls(card, u8500_chip) < 0) { + goto nodev; + } + } +#endif //////////////////////////////////////////////////////// + + /*char driver[16]; driver name + char shortname[32]; short name of this soundcard + char longname[80]; name of this soundcard + char mixername[80]; mixer name + char components[80]; card components delimited withspace */ + + strcpy(card->driver, "u8500 alsa"); + strcpy(card->shortname, "u8500 alsa pcm hdmi driver"); + strcpy(card->longname, "u8500 alsa pcm hdmi driver"); + + snd_card_set_dev(card, &devptr->dev); + + if ((error = snd_card_register(card)) == 0) { + stm_info("u8500 audio <hdmi> support running..\n"); + platform_set_drvdata(devptr, card); + return 0; + } + + nodev: + snd_card_free(card); + return error; +} + +static int __devexit u8500_alsa_remove(struct platform_device *devptr) +{ + snd_card_free(platform_get_drvdata(devptr)); + platform_set_drvdata(devptr, NULL); + stm_info("u8500 audio support stopped\n"); + + /*Set currently active users to 0 */ + active_user = 0; + + return 0; +} + +static struct platform_driver u8500_alsa_driver = { + .probe = u8500_alsa_probe, + .remove = __devexit_p(u8500_alsa_remove), + .driver = { + .name = U8500_ALSA_DRIVER, + }, +}; + +/** +* u8500_alsa_init - Entry function of AB8500 alsa driver +* +* This function registers u8500 alsa driver with linux framework +*/ +static int __init u8500_alsa_init(void) +{ + int err; + + if ((err = platform_driver_register(&u8500_alsa_driver)) < 0) + return err; + device = + platform_device_register_simple(U8500_ALSA_DRIVER, -1, NULL, 0); + if (IS_ERR(device)) { + platform_driver_unregister(&u8500_alsa_driver); + return PTR_ERR(device); + } + //DBG_ST.acodec = 1; + //DBG_ST.alsa = 1; + + return 0; +} + +static void __exit u8500_alsa_exit(void) +{ + platform_device_unregister(device); + platform_driver_unregister(&u8500_alsa_driver); +} + +module_init(u8500_alsa_init); +module_exit(u8500_alsa_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AB8500 ALSA driver"); diff --git a/sound/arm/u8500_alsa_ab8500.h b/sound/arm/u8500_alsa_ab8500.h new file mode 100644 index 00000000000..dda802c2156 --- /dev/null +++ b/sound/arm/u8500_alsa_ab8500.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Deepak Karda + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#ifndef _U8500_ALSA_H_ +#define _U8500_ALSA_H_ + +#ifdef CONFIG_U8500_AB8500_CUT10 +#include <mach/ab8500_codec_v1_0.h> +//#include <mach/ab8500_codec_p_v1_0.h> +#else +//#include <mach/ab8500_codec_p.h> +#include <mach/ab8500_codec.h> +#endif +#include <mach/u8500_acodec_ab8500.h> + +#define DEFAULT_SAMPLE_RATE 48000 +#define NMDK_BUFFER_SIZE (64*1024) +#define U8500_ALSA_DRIVER "u8500_alsa" + +#define MAX_NUMBER_OF_DEVICES 3 /* ALSA_PCM, ALSA_BT, ALSA_HDMI */ +#define MAX_NUMBER_OF_STREAMS 2 /* PLAYBACK, CAPTURE */ + +#define ALSA_PCM_DEV 0 +#define ALSA_BT_DEV 2 +#define ALSA_HDMI_DEV 1 + +/* Debugging stuff */ +#ifndef CONFIG_DEBUG_USER +#define DEBUG_LEVEL 0 +#else +#define DEBUG_LEVEL 10 +#endif + +#if DEBUG_LEVEL > 0 +static int u8500_acodec_debug = DEBUG_LEVEL; +#define DEBUG(n, args...) do { if (u8500_acodec_debug>(n)) printk(args); } while (0) +#else +#define DEBUG(n, args...) do { } while (0) +#endif +enum alsa_state { + ALSA_STATE_PAUSE, + ALSA_STATE_UNPAUSE +}; + +/* audio stream definition */ +typedef struct audio_stream_s { + char id[64]; /* module identifier string */ + int stream_id; /* stream identifier */ + int status; + int active; /* we are using this stream for transfer now */ + int period; /* current transfer period */ + int periods; /* current count of periods registerd in the DMA engine */ + enum alsa_state state; + unsigned int old_offset; + struct snd_pcm_substream *substream; + unsigned int exchId; + snd_pcm_uframes_t played_frame; + struct semaphore alsa_sem; + struct completion alsa_com; + +} audio_stream_t; + +typedef struct hdmi_params_s { + int sampling_freq; + int channel_count; +} hdmi_params_t; + +/* chip structure definition */ +typedef struct u8500_acodec_s { + struct snd_card *card; + struct snd_pcm *pcm; + struct snd_pcm *pcm_hdmi; + struct snd_pcm *pcm_bt; + unsigned int freq; + unsigned int channels; + unsigned int input_lvolume; + unsigned int input_rvolume; + unsigned int output_lvolume; + unsigned int output_rvolume; + t_ab8500_codec_src input_device; + t_ab8500_codec_dest output_device; + t_u8500_bool_state analog_lpbk; + t_u8500_bool_state digital_lpbk; + t_u8500_bool_state playback_switch; + t_u8500_bool_state capture_switch; + t_u8500_bool_state tdm8_ch_mode; + t_u8500_bool_state direct_rendering_mode; + t_u8500_pmc_rendering_state burst_fifo_mode; + t_u8500_pmc_rendering_state fm_playback_mode; + t_u8500_pmc_rendering_state fm_tx_mode; + audio_stream_t stream[MAX_NUMBER_OF_DEVICES][MAX_NUMBER_OF_STREAMS]; + hdmi_params_t hdmi_params; +} u8500_acodec_chip_t; + +void u8500_alsa_dma_start(audio_stream_t * stream); + +#if (defined(CONFIG_U8500_ACODEC_DMA) || defined(CONFIG_U8500_ACODEC_INTR)) + +#define stm_trigger_alsa(x) u8500_alsa_dma_start(x) +static void inline stm_pause_alsa(audio_stream_t * stream) +{ + if (stream->state == ALSA_STATE_UNPAUSE) { + stream->state = ALSA_STATE_PAUSE; + } + +} +static void inline stm_unpause_alsa(audio_stream_t * stream) +{ + if (stream->state == ALSA_STATE_PAUSE) { + stream->state = ALSA_STATE_UNPAUSE; + stm_trigger_alsa(stream); + } +} +static void inline stm_stop_alsa(audio_stream_t * stream) +{ + stream->active = 0; + stream->period = 0; + +} +static void inline stm_hw_free(struct snd_pcm_substream *substream) +{ + snd_pcm_lib_free_pages(substream); +} + +#define stm_close_alsa(x, y,z) +#define stm_config_hw(w,x, y, z) 0 + +#else ////// CONFIG_U8500_ACODEC_POLL //////////// + +int spawn_acodec_feeding_thread(audio_stream_t * stream); +//static int configure_dmadev_acodec(struct snd_pcm_substream *substream); + +#define stm_trigger_alsa(x) spawn_acodec_feeding_thread(x) +#define stm_close_alsa(x, y,z) +#define stm_config_hw(w,x, y, z) 0 +#define stm_hw_free(x) +static void inline stm_pause_alsa(audio_stream_t * stream) +{ + stream->state = ALSA_STATE_PAUSE; +} +static void inline stm_unpause_alsa(audio_stream_t * stream) +{ + stream->state = ALSA_STATE_UNPAUSE; + complete(&stream->alsa_com); +} +static void inline stm_stop_alsa(audio_stream_t * stream) +{ + stream->active = 0; + stream->period = 0; + if (stream->state == ALSA_STATE_PAUSE) + complete(&stream->alsa_com); +} + +#endif +#endif /*END OF HEADER FILE */ diff --git a/sound/arm/u8500_alsa_hdmi.c b/sound/arm/u8500_alsa_hdmi.c new file mode 100644 index 00000000000..dcbc3583ba7 --- /dev/null +++ b/sound/arm/u8500_alsa_hdmi.c @@ -0,0 +1,936 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License terms: GNU General Public License (GPL), + * version 2. + */ + +/* This include must be defined at this point */ +//#include <sound/driver.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/errno.h> +#include <linux/ioctl.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <mach/hardware.h> +#include <asm/uaccess.h> +#include <asm/io.h> + +/* alsa system */ +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/control.h> +#include "u8500_alsa_ab8500.h" +#include <mach/msp.h> +#include <mach/debug.h> + +#define ALSA_NAME "DRIVER ALSA HDMI" + +/* enables/disables debug msgs */ +#define DRIVER_DEBUG CONFIG_STM_ALSA_DEBUG +/* msg header represents this module */ +#define DRIVER_DEBUG_PFX ALSA_NAME +/* message level */ +#define DRIVER_DBG KERN_ERR +#define ELEMENT_SIZE 0 + +extern char *power_state_in_texts[NUMBER_POWER_STATE]; + +static int u8500_hdmi_power_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int u8500_hdmi_power_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); +static int u8500_hdmi_power_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo); + +void dump_msp2_registers(); + +#ifdef CONFIG_U8500_ACODEC_DMA + +static void u8500_alsa_hdmi_dma_start(audio_stream_t * stream); +#define stm_trigger_hdmi(x) u8500_alsa_hdmi_dma_start(x) +static void inline stm_pause_hdmi(audio_stream_t * stream) +{ + if (stream->state == ALSA_STATE_UNPAUSE) { + stream->state = ALSA_STATE_PAUSE; + } +} +static void inline stm_unpause_hdmi(audio_stream_t * stream) +{ + if (stream->state == ALSA_STATE_PAUSE) { + stream->state = ALSA_STATE_UNPAUSE; + stm_trigger_hdmi(stream); + } +} +static void inline stm_stop_hdmi(audio_stream_t * stream) +{ + stream->active = 0; + stream->period = 0; +} +#else /* Polling */ + +static int spawn_hdmi_feeding_thread(audio_stream_t * stream); +static int hdmi_feeding_thread(void *data); +static void u8500_hdmi_pio_start(audio_stream_t * stream); + +#define stm_trigger_hdmi(x) spawn_hdmi_feeding_thread(x); + +static void inline stm_pause_hdmi(audio_stream_t * stream) +{ + stream->state = ALSA_STATE_PAUSE; +} +static void inline stm_unpause_hdmi(audio_stream_t * stream) +{ + stream->state = ALSA_STATE_UNPAUSE; + complete(&stream->alsa_com); +} +static void inline stm_stop_hdmi(audio_stream_t * stream) +{ + stream->active = 0; + stream->period = 0; + if (stream->state == ALSA_STATE_PAUSE) + complete(&stream->alsa_com); +} + +#endif + +extern struct driver_debug_st DBG_ST; +extern struct i2sdrv_data *i2sdrv[MAX_I2S_CLIENTS]; + +static void u8500_audio_hdmi_init(u8500_acodec_chip_t * chip); +int u8500_register_alsa_hdmi_controls(struct snd_card *card, + u8500_acodec_chip_t * u8500_chip); +static int snd_u8500_alsa_hdmi_open(struct snd_pcm_substream *substream); +static int snd_u8500_alsa_hdmi_close(struct snd_pcm_substream *substream); +static int snd_u8500_alsa_hdmi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params); +static int snd_u8500_alsa_hdmi_hw_free(struct snd_pcm_substream *substream); +static int snd_u8500_alsa_hdmi_prepare(struct snd_pcm_substream *substream); +static int snd_u8500_alsa_hdmi_trigger(struct snd_pcm_substream *substream, + int cmd); +static snd_pcm_uframes_t snd_u8500_alsa_hdmi_pointer(struct snd_pcm_substream + *substream); +static int configure_hdmi_rate(struct snd_pcm_substream *); +static int configure_msp_hdmi(int sampling_freq, int channel_count); + +int u8500_hdmi_rates[] = { 32000, 44100, 48000, 64000, 88200, + 96000, 128000, 176100, 192000 +}; + +typedef enum { + HDMI_SAMPLING_FREQ_32KHZ = 32, + HDMI_SAMPLING_FREQ_44_1KHZ = 44, + HDMI_SAMPLING_FREQ_48KHZ = 48, + HDMI_SAMPLING_FREQ_64KHZ = 64, + HDMI_SAMPLING_FREQ_88_2KHZ = 88, + HDMI_SAMPLING_FREQ_96KHZ = 96, + HDMI_SAMPLING_FREQ_128KHZ = 128, + HDMI_SAMPLING_FREQ_176_1KHZ = 176, + HDMI_SAMPLING_FREQ_192KHZ = 192 +} t_hdmi_sample_freq; + +static struct snd_pcm_ops snd_u8500_alsa_hdmi_playback_ops = { + .open = snd_u8500_alsa_hdmi_open, + .close = snd_u8500_alsa_hdmi_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_u8500_alsa_hdmi_hw_params, + .hw_free = snd_u8500_alsa_hdmi_hw_free, + .prepare = snd_u8500_alsa_hdmi_prepare, + .trigger = snd_u8500_alsa_hdmi_trigger, + .pointer = snd_u8500_alsa_hdmi_pointer, +}; + +static struct snd_pcm_ops snd_u8500_alsa_hdmi_capture_ops = { + .open = snd_u8500_alsa_hdmi_open, + .close = snd_u8500_alsa_hdmi_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_u8500_alsa_hdmi_hw_params, + .hw_free = snd_u8500_alsa_hdmi_hw_free, + .prepare = snd_u8500_alsa_hdmi_prepare, + .trigger = snd_u8500_alsa_hdmi_trigger, + .pointer = snd_u8500_alsa_hdmi_pointer, +}; + +/* Hardware description , this structure (struct snd_pcm_hardware ) + * contains the definitions of the fundamental hardware configuration. + * This configuration will be applied on the runtime structure + */ +static struct snd_pcm_hardware snd_u8500_hdmi_playback_hw = { + .info = + (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_PAUSE), + .formats = + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | + SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U16_BE, + .rates = SNDRV_PCM_RATE_KNOT, + .rate_min = MIN_RATE_PLAYBACK, + .rate_max = MAX_RATE_PLAYBACK, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = NMDK_BUFFER_SIZE, + .period_bytes_min = 128, + .period_bytes_max = PAGE_SIZE, + .periods_min = NMDK_BUFFER_SIZE / PAGE_SIZE, + .periods_max = NMDK_BUFFER_SIZE / 128 +}; + +static struct snd_pcm_hardware snd_u8500_hdmi_capture_hw = { + .info = + (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_PAUSE), + .formats = + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | + SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U16_BE, + .rates = SNDRV_PCM_RATE_KNOT, + .rate_min = MIN_RATE_CAPTURE, + .rate_max = MAX_RATE_CAPTURE, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = NMDK_BUFFER_SIZE, + .period_bytes_min = 128, + .period_bytes_max = PAGE_SIZE, + .periods_min = NMDK_BUFFER_SIZE / PAGE_SIZE, + .periods_max = NMDK_BUFFER_SIZE / 128 +}; + +static struct snd_pcm_hw_constraint_list constraints_hdmi_rate = { + .count = sizeof(u8500_hdmi_rates) / sizeof(u8500_hdmi_rates[0]), + .list = u8500_hdmi_rates, + .mask = 0, +}; + +/** + * snd_card_u8500_alsa_hdmi_new - constructor for a new pcm cmponent + * @chip - pointer to chip specific data + * @device - specifies the card number + */ +int snd_card_u8500_alsa_hdmi_new(u8500_acodec_chip_t * chip, int device) +{ + struct snd_pcm *pcm; + int err; + + if ((err = + snd_pcm_new(chip->card, "u8500_hdmi", device, 1, 1, &pcm)) < 0) { + stm_error(" : error in snd_pcm_new\n"); + return err; + } + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_u8500_alsa_hdmi_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_u8500_alsa_hdmi_capture_ops); + + pcm->private_data = chip; + pcm->info_flags = 0; + chip->pcm_hdmi = pcm; + strcpy(pcm->name, "u8500_alsa_hdmi"); + + u8500_audio_hdmi_init(pcm->private_data); + return 0; +} + +/** +* u8500_audio_hdmi_init +* @chip - pointer to u8500_acodec_chip_t structure. +* +* This function intialises the u8500 chip structure with default values +*/ +static void u8500_audio_hdmi_init(u8500_acodec_chip_t * chip) +{ + audio_stream_t *ptr_audio_stream = NULL; + + ptr_audio_stream = + &chip->stream[ALSA_HDMI_DEV][SNDRV_PCM_STREAM_PLAYBACK]; + /* Setup DMA stuff */ + + strlcpy(ptr_audio_stream->id, "u8500 hdmi playback", + sizeof(ptr_audio_stream->id)); + + ptr_audio_stream->stream_id = SNDRV_PCM_STREAM_PLAYBACK; + + /* default initialization for playback */ + ptr_audio_stream->active = 0; + ptr_audio_stream->period = 0; + ptr_audio_stream->periods = 0; + ptr_audio_stream->old_offset = 0; + + ptr_audio_stream = + &chip->stream[ALSA_HDMI_DEV][SNDRV_PCM_STREAM_CAPTURE]; + + strlcpy(ptr_audio_stream->id, "u8500 hdmi capture", + sizeof(ptr_audio_stream->id)); + + ptr_audio_stream->stream_id = SNDRV_PCM_STREAM_CAPTURE; + + /* default initialization for capture */ + ptr_audio_stream->active = 0; + ptr_audio_stream->period = 0; + ptr_audio_stream->periods = 0; + ptr_audio_stream->old_offset = 0; + +} + +/** + * snd_u8500_alsa_hdmi_open + * @substream - pointer to the playback/capture substream structure + * + * This routine is used by alsa framework to open a pcm stream . + * Here a dma pipe is requested and device is configured(default). + */ +static int snd_u8500_alsa_hdmi_open(struct snd_pcm_substream *substream) +{ + int error = 0, stream_id, status = 0; + u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + audio_stream_t *ptr_audio_stream = NULL; + + stream_id = substream->pstr->stream; + error = u8500_acodec_setuser(USER_ALSA); + status = u8500_acodec_open(I2S_CLIENT_MSP2, stream_id); + if (status) { + printk("failed in getting open\n"); + return (-1); + } + + error = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_hdmi_rate); + if (error < 0) { + stm_error + (": error initializing hdmi hw sample rate constraint\n"); + return error; + } + + if ((error = configure_hdmi_rate(substream))) + return error; + + if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) { + runtime->hw = snd_u8500_hdmi_playback_hw; + } else { + runtime->hw = snd_u8500_hdmi_capture_hw; + } + + ptr_audio_stream = &chip->stream[ALSA_HDMI_DEV][stream_id]; + + ptr_audio_stream->substream = substream; + + stm_config_hw(chip, substream, ALSA_HDMI_DEV, stream_id); + sema_init(&(ptr_audio_stream->alsa_sem), 1); + init_completion(&(ptr_audio_stream->alsa_com)); + + ptr_audio_stream->state = ALSA_STATE_UNPAUSE; + return 0; +} + +/** + * snd_u8500_alsa_hdmi_close + * @substream - pointer to the playback/capture substream structure + * + * This routine is used by alsa framework to close a pcm stream . + * Here a dma pipe is disabled and freed. + */ + +static int snd_u8500_alsa_hdmi_close(struct snd_pcm_substream *substream) +{ + int stream_id, error = 0; + u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream); + audio_stream_t *ptr_audio_stream = NULL; + + stream_id = substream->pstr->stream; + ptr_audio_stream = &chip->stream[ALSA_HDMI_DEV][stream_id]; + + stm_close_alsa(chip, ALSA_HDMI_DEV, stream_id); + + /* reset the different variables to default */ + + ptr_audio_stream->active = 0; + ptr_audio_stream->period = 0; + ptr_audio_stream->periods = 0; + ptr_audio_stream->old_offset = 0; + ptr_audio_stream->substream = NULL; + + /* Disable the MSP2 */ + error = u8500_acodec_unsetuser(USER_ALSA); + u8500_acodec_close(I2S_CLIENT_MSP2, ACODEC_DISABLE_ALL); + + return error; + +} + +/** + * snd_u8500_alsa_hdmi_hw_params + * @substream - pointer to the playback/capture substream structure + * @hw_params - specifies the hw parameters like format/no of channels etc + * + * This routine is used by alsa framework to allocate a dma buffer + * used to transfer the data from user space to kernel space + * + */ +static int snd_u8500_alsa_hdmi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); +} + +/** + * snd_u8500_alsa_hdmi_hw_free + * @substream - pointer to the playback/capture substream structure + * + * This routine is used by alsa framework to deallocate a dma buffer + * allocated berfore by snd_u8500_alsa_pcm_hw_params + */ +static int snd_u8500_alsa_hdmi_hw_free(struct snd_pcm_substream *substream) +{ + stm_hw_free(substream); + return 0; +} + +/** + * snd_u8500_alsa_hdmi_pointer + * @substream - pointer to the playback/capture substream structure + * + * This callback is called whene the pcm middle layer inquires the current + * hardware position on the buffer .The position is returned in frames + * ranged from 0 to buffer_size -1 + */ +static snd_pcm_uframes_t snd_u8500_alsa_hdmi_pointer(struct snd_pcm_substream + *substream) +{ + unsigned int offset; + u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream); + audio_stream_t *stream = + &chip->stream[ALSA_HDMI_DEV][substream->pstr->stream]; + struct snd_pcm_runtime *runtime = stream->substream->runtime; + + offset = bytes_to_frames(runtime, stream->old_offset); + if (offset < 0 || stream->old_offset < 0) + stm_dbg(DBG_ST.alsa, " Offset=%i %i\n", offset, + stream->old_offset); + + return offset; +} + +/** + * snd_u8500_alsa_hdmi_prepare + * @substream - pointer to the playback/capture substream structure + * + * This callback is called whene the pcm is "prepared" Here is possible + * to set the format type ,sample rate ,etc.The callback is called as + * well everytime a recovery after an underrun happens. + */ + +static int snd_u8500_alsa_hdmi_prepare(struct snd_pcm_substream *substream) +{ + u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int error; + + if (chip->hdmi_params.sampling_freq != runtime->rate + || chip->hdmi_params.channel_count != runtime->channels) { + stm_dbg(DBG_ST.alsa, " freq not same, %d %d\n", + chip->hdmi_params.sampling_freq, runtime->rate); + stm_dbg(DBG_ST.alsa, " channels not same, %d %d\n", + chip->hdmi_params.channel_count, runtime->channels); + if (chip->hdmi_params.channel_count != runtime->channels) { + chip->hdmi_params.channel_count = runtime->channels; + if ((error = + stm_config_hw(chip, substream, ALSA_HDMI_DEV, + -1))) { + stm_dbg(DBG_ST.alsa, + "In func %s, stm_config_hw fails", + __FUNCTION__); + return error; + } + } + chip->hdmi_params.sampling_freq = runtime->rate; + if ((error = configure_hdmi_rate(substream))) { + stm_dbg(DBG_ST.alsa, "In func %s, configure_rate fails", + __FUNCTION__); + return error; + } + } + + return 0; +} + +/** + * snd_u8500_alsa_hdmi_trigger + * @substream - pointer to the playback/capture substream structure + * @cmd - specifies the command : start/stop/pause/resume + * + * This callback is called whene the pcm is started ,stopped or paused + * The action is specified in the second argument, SND_PCM_TRIGGER_XXX in + * <sound/pcm.h>. + * This callback is atomic and the interrupts are disabled , so you can't + * call other functions that need interrupts without possible risks + */ +static int snd_u8500_alsa_hdmi_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + int stream_id = substream->pstr->stream; + audio_stream_t *stream = NULL; + u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream); + int error = 0; + + stream = &chip->stream[ALSA_HDMI_DEV][stream_id]; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + /* Start the pcm engine */ + stm_dbg(DBG_ST.alsa, " TRIGGER START\n"); + if (stream->active == 0) { + stream->active = 1; + stm_trigger_hdmi(stream); + break; + } + stm_error(": H/w is busy\n"); + return -EINVAL; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + stm_dbg(DBG_ST.alsa, " SNDRV_PCM_TRIGGER_PAUSE_PUSH\n"); + if (stream->active == 1) { + stm_pause_hdmi(stream); + } + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + stm_dbg(DBG_ST.alsa, " SNDRV_PCM_TRIGGER_PAUSE_RELEASE\n"); + if (stream->active == 1) + stm_unpause_hdmi(stream); + break; + case SNDRV_PCM_TRIGGER_STOP: + /* Stop the pcm engine */ + stm_dbg(DBG_ST.alsa, " TRIGGER STOP\n"); + if (stream->active == 1) + stm_stop_hdmi(stream); + break; + default: + stm_error(": invalid command in pcm trigger\n"); + return -EINVAL; + } + + return error; + +} + +struct snd_kcontrol_new u8500_hdmi_power_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .device = 1, + .subdevice = 0, + .name = "HDMI Power", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0xfff, + .info = u8500_hdmi_power_ctrl_info, + .get = u8500_hdmi_power_ctrl_get, + .put = u8500_hdmi_power_ctrl_put +}; + +/** +* u8500_hdmi_power_ctrl_info +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions fills playback device info into user structure. +*/ +static int u8500_hdmi_power_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = NUMBER_POWER_STATE; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= NUMBER_POWER_STATE) + uinfo->value.enumerated.item = NUMBER_POWER_STATE - 1; + strcpy(uinfo->value.enumerated.name, + power_state_in_texts[uinfo->value.enumerated.item]); + return 0; +} + +/** +* u8500_hdmi_power_ctrl_get +* @kcontrol - pointer to the snd_kcontrol structure +* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function +* +* This functions returns the current playback device selected. +*/ +static int u8500_hdmi_power_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + uinfo->value.enumerated.item[0] = 0; + return 0; +} + +/** +* u8500_hdmi_power_ctrl_put +* @kcontrol - pointer to the snd_kcontrol structure +* @ . +* +* This functions sets the playback device. +*/ +static int u8500_hdmi_power_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uinfo) +{ + u8500_acodec_chip_t *chip = + (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol); + int changed = 0; + t_ab8500_codec_error error; + t_u8500_bool_state power_state; + + power_state = uinfo->value.enumerated.item[0]; + + changed = 1; + + return changed; +} + +int u8500_register_alsa_hdmi_controls(struct snd_card *card, + u8500_acodec_chip_t * u8500_chip) +{ + int error; + + if ((error = + snd_ctl_add(card, + snd_ctl_new1(&u8500_hdmi_power_ctrl, + u8500_chip))) < 0) { + stm_error + (": error initializing u8500_hdmi_power_ctrl interface \n\n"); + return (-1); + } + + return 0; +} + +/** +* configure_hdmi_rate +* @substream - pointer to the playback/capture substream structure +* +* This functions configures audio codec in to stream frequency frequency +*/ +static int configure_hdmi_rate(struct snd_pcm_substream *substream) +{ + t_hdmi_sample_freq hdmi_sampling_freq; + + u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream); + + switch (chip->hdmi_params.sampling_freq) { + case 32000: + hdmi_sampling_freq = HDMI_SAMPLING_FREQ_32KHZ; + break; + case 44100: + hdmi_sampling_freq = HDMI_SAMPLING_FREQ_44_1KHZ; + break; + case 48000: + hdmi_sampling_freq = HDMI_SAMPLING_FREQ_48KHZ; + break; + case 64000: + hdmi_sampling_freq = HDMI_SAMPLING_FREQ_64KHZ; + break; + case 88200: + hdmi_sampling_freq = HDMI_SAMPLING_FREQ_88_2KHZ; + break; + case 96000: + hdmi_sampling_freq = HDMI_SAMPLING_FREQ_96KHZ; + break; + case 128000: + hdmi_sampling_freq = HDMI_SAMPLING_FREQ_128KHZ; + break; + case 176100: + hdmi_sampling_freq = HDMI_SAMPLING_FREQ_176_1KHZ; + break; + case 192000: + hdmi_sampling_freq = HDMI_SAMPLING_FREQ_192KHZ; + default: + stm_error("not supported frequnecy\n"); + return -EINVAL; + } + + configure_msp_hdmi(hdmi_sampling_freq, chip->hdmi_params.channel_count); + + return 0; + +} + +static int configure_msp_hdmi(int sampling_freq, int channel_count) +{ + struct i2s_device *i2s_dev = i2sdrv[I2S_CLIENT_MSP2]->i2s; + struct msp_config msp_config; + t_ab8500_codec_error error_status = AB8500_CODEC_OK; + + memset(&msp_config, 0, sizeof(msp_config)); + + + if (i2sdrv[I2S_CLIENT_MSP2]->flag) { + stm_dbg(DBG_ST.acodec, " I2S controller not available\n"); + return -1; + } + + /* MSP configuration */ + + msp_config.tx_clock_sel = 0; + msp_config.rx_clock_sel = 0; + + msp_config.tx_frame_sync_sel = 0; + msp_config.rx_frame_sync_sel = 0; + + msp_config.input_clock_freq = MSP_INPUT_FREQ_48MHZ; + msp_config.srg_clock_sel = 0; + + msp_config.rx_frame_sync_pol = RX_FIFO_SYNC_HI; + msp_config.tx_frame_sync_pol = TX_FIFO_SYNC_HI; + + msp_config.rx_fifo_config = 0; + msp_config.tx_fifo_config = TX_FIFO_ENABLE; + + msp_config.spi_clk_mode = SPI_CLK_MODE_NORMAL; + msp_config.spi_burst_mode = 0; + msp_config.tx_data_enable = 0; + msp_config.loopback_enable = 0; + msp_config.default_protocol_desc = 1; + msp_config.direction = MSP_TRANSMIT_MODE; + msp_config.protocol = MSP_I2S_PROTOCOL; + msp_config.frame_size = ELEMENT_SIZE; + msp_config.frame_freq = sampling_freq; + msp_config.def_elem_len = 0; + /* enable msp for both tr and rx mode with dma data transfer. + THIS IS NOW DONE SEPARATELY from SAA. */ + msp_config.data_size = MSP_DATA_SIZE_16BIT; + +#ifdef CONFIG_U8500_ACODEC_DMA + msp_config.work_mode = MSP_DMA_MODE; +#elif defined(CONFIG_U8500_ACODEC_POLL) + msp_config.work_mode = MSP_POLLING_MODE; +#else + msp_config.work_mode = MSP_INTERRUPT_MODE; +#endif + msp_config.default_protocol_desc = 0; + + msp_config.protocol_desc.rx_phase_mode = MSP_DUAL_PHASE; + msp_config.protocol_desc.tx_phase_mode = MSP_DUAL_PHASE; + msp_config.protocol_desc.rx_phase2_start_mode = + MSP_PHASE2_START_MODE_FRAME_SYNC; + msp_config.protocol_desc.tx_phase2_start_mode = + MSP_PHASE2_START_MODE_FRAME_SYNC; + msp_config.protocol_desc.rx_bit_transfer_format = MSP_BTF_MS_BIT_FIRST; + msp_config.protocol_desc.tx_bit_transfer_format = MSP_BTF_MS_BIT_FIRST; + msp_config.protocol_desc.rx_frame_length_1 = MSP_FRAME_LENGTH_1; + msp_config.protocol_desc.rx_frame_length_2 = MSP_FRAME_LENGTH_1; + msp_config.protocol_desc.tx_frame_length_1 = MSP_FRAME_LENGTH_1; + msp_config.protocol_desc.tx_frame_length_2 = MSP_FRAME_LENGTH_1; + msp_config.protocol_desc.rx_element_length_1 = MSP_ELEM_LENGTH_16; + msp_config.protocol_desc.rx_element_length_2 = MSP_ELEM_LENGTH_16; + msp_config.protocol_desc.tx_element_length_1 = MSP_ELEM_LENGTH_16; + msp_config.protocol_desc.tx_element_length_2 = MSP_ELEM_LENGTH_16; + msp_config.protocol_desc.rx_data_delay = MSP_DELAY_1; + msp_config.protocol_desc.tx_data_delay = MSP_DELAY_1; + msp_config.protocol_desc.rx_clock_pol = MSP_RISING_EDGE; + msp_config.protocol_desc.tx_clock_pol = 0; + msp_config.protocol_desc.rx_frame_sync_pol = + MSP_FRAME_SYNC_POL_ACTIVE_HIGH; + msp_config.protocol_desc.tx_frame_sync_pol = + MSP_FRAME_SYNC_POL_ACTIVE_HIGH; + msp_config.protocol_desc.rx_half_word_swap = MSP_HWS_NO_SWAP; + msp_config.protocol_desc.tx_half_word_swap = MSP_HWS_NO_SWAP; + msp_config.protocol_desc.compression_mode = MSP_COMPRESS_MODE_LINEAR; + msp_config.protocol_desc.expansion_mode = MSP_EXPAND_MODE_LINEAR; + msp_config.protocol_desc.spi_clk_mode = MSP_SPI_CLOCK_MODE_NON_SPI; + msp_config.protocol_desc.spi_burst_mode = MSP_SPI_BURST_MODE_DISABLE; + msp_config.protocol_desc.frame_period = 63; + msp_config.protocol_desc.frame_width = 31; + msp_config.protocol_desc.total_clocks_for_one_frame = 64; + msp_config.multichannel_configured = 0; + msp_config.multichannel_config.tx_multichannel_enable = 0; + /* Channel 1 and channel 3 */ + msp_config.multichannel_config.tx_channel_0_enable = 0x0000005; + msp_config.multichannel_config.tx_channel_1_enable = 0x0000000; + msp_config.multichannel_config.tx_channel_2_enable = 0x0000000; + msp_config.multichannel_config.tx_channel_3_enable = 0x0000000; + error_status = i2s_setup(i2s_dev->controller, &msp_config); + +#ifdef CONFIG_DEBUG + { + dump_msp2_registers(); + } +#endif + + if (error_status < 0) { + printk("error in msp enable, error_status is %d\n", + error_status); + return error_status; + } + + return 0; + +} + +#ifdef CONFIG_U8500_ACODEC_DMA +/** + * u8500_alsa_hdmi_dma_start - used to transmit or recive a dma chunk + * @stream - specifies the playback/record stream structure + */ +static void u8500_alsa_hdmi_dma_start(audio_stream_t * stream) +{ + unsigned int offset, dma_size, stream_id; + + struct snd_pcm_substream *substream = stream->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + + stream_id = substream->pstr->stream; + + dma_size = frames_to_bytes(runtime, runtime->period_size); + offset = dma_size * stream->period; + stream->old_offset = offset; + + if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) +#ifdef CONFIG_U8500_ACODEC_DMA + u8500_acodec_send_data(I2S_CLIENT_MSP2, + (void *)(runtime->dma_addr + offset), + dma_size, 1); +#else + u8500_acodec_send_data(I2S_CLIENT_MSP2, + (void *)(runtime->dma_area + offset), + dma_size, 0); +#endif + else +#ifdef CONFIG_U8500_ACODEC_DMA + u8500_acodec_receive_data(I2S_CLIENT_MSP2, + (void *)(runtime->dma_addr + offset), + dma_size, 1); +#else + u8500_acodec_receive_data(I2S_CLIENT_MSP2, + (void *)(runtime->dma_area + offset), + dma_size, 0); +#endif + + stm_dbg(DBG_ST.alsa, " DMA Transfer started\n"); + stm_dbg(DBG_ST.alsa, " address = %x size=%d\n", + (runtime->dma_addr + offset), dma_size); + + stream->period++; + stream->period %= runtime->periods; + stream->periods++; + + +} + +#else + +/** +* acodec_feeding_thread +* @stream - pointer to the playback/capture audio_stream_t structure +* +* This function creates a kernel thread . +*/ + +static int spawn_hdmi_feeding_thread(audio_stream_t * stream) +{ + pid_t pid; + + pid = + kernel_thread(hdmi_feeding_thread, stream, + CLONE_FS | CLONE_SIGHAND); + + return 0; +} + +/** +* hdmi_feeding_thread +* @data - void pointer to the playback/capture audio_stream_t structure +* +* This thread sends/receive data to MSP while stream is active +*/ +static int hdmi_feeding_thread(void *data) +{ + audio_stream_t *stream = (audio_stream_t *) data; + + daemonize("hdmi_feeding_thread"); + allow_signal(SIGKILL); + down(&stream->alsa_sem); + + while ((!signal_pending(current)) && (stream->active)) { + if (stream->state == ALSA_STATE_PAUSE) + wait_for_completion(&(stream->alsa_com)); + + u8500_hdmi_pio_start(stream); + if (stream->substream) + snd_pcm_period_elapsed(stream->substream); + } + + up(&stream->alsa_sem); + + return 0; +} + +/** +* u8500_hdmi_pio_start +* @stream - pointer to the playback/capture audio_stream_t structure +* +* This function sends/receive one chunck of stream data to/from MSP +*/ +static void u8500_hdmi_pio_start(audio_stream_t * stream) +{ + unsigned int offset, dma_size, stream_id; + struct snd_pcm_substream *substream = stream->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + stream_id = substream->pstr->stream; + + dma_size = frames_to_bytes(runtime, runtime->period_size); + offset = dma_size * stream->period; + stream->old_offset = offset; + + stm_dbg(DBG_ST.alsa, " Transfer started\n"); + stm_dbg(DBG_ST.alsa, " address = %x size=%d\n", + (runtime->dma_addr + offset), dma_size); + + /* Send our stuff */ + if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) +#ifdef CONFIG_U8500_ACODEC_DMA + u8500_acodec_send_data(I2S_CLIENT_MSP2, + (void *)(runtime->dma_addr + offset), + dma_size, 1); +#else + u8500_acodec_send_data(I2S_CLIENT_MSP2, + (void *)(runtime->dma_area + offset), + dma_size, 0); +#endif + else +#ifdef CONFIG_U8500_ACODEC_DMA + u8500_acodec_receive_data(I2S_CLIENT_MSP2, + (void *)(runtime->dma_addr + offset), + dma_size, 1); +#else + u8500_acodec_receive_data(I2S_CLIENT_MSP2, + (void *)(runtime->dma_area + offset), + dma_size, 0); +#endif + + stream->period++; + stream->period %= runtime->periods; + stream->periods++; +} +#endif + +void dump_msp2_registers() +{ + int i; + + stm_dbg(DBG_ST.acodec, "\nMSP_2 base add = 0x%x\n", + (unsigned int)U8500_MSP2_BASE); + + for (i = 0; i < 0x40; i += 4) + stm_dbg(DBG_ST.acodec, "msp[0x%x]=0x%x\n", i, + readl((char *)(IO_ADDRESS(U8500_MSP2_BASE) + i))); + + return 0; +} diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b48fb43b544..d2c82caa6cc 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -19491,6 +19491,10 @@ static const struct alc_fixup alc662_fixups[] = { .type = ALC_FIXUP_SKU, .v.sku = ALC_FIXUP_SKU_IGNORE, }, + [ALC662_FIXUP_SKU_IGNORE] = { + .type = ALC_FIXUP_SKU, + .v.sku = ALC_FIXUP_SKU_IGNORE, + }, }; static const struct snd_pci_quirk alc662_fixup_tbl[] = { diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 8224db5f043..adcbc43276d 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -11,7 +11,7 @@ menuconfig SND_SOC If you want ASoC support, you should say Y here and also to the specific driver for your SoC platform below. - + ASoC provides power efficient ALSA support for embedded battery powered SoC based systems like PDA's, Phones and Personal Media Players. @@ -57,6 +57,7 @@ source "sound/soc/s6000/Kconfig" source "sound/soc/sh/Kconfig" source "sound/soc/tegra/Kconfig" source "sound/soc/txx9/Kconfig" +source "sound/soc/ux500/Kconfig" # Supported codecs source "sound/soc/codecs/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 1ed61c5df2c..79a9e203e94 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -20,3 +20,4 @@ obj-$(CONFIG_SND_SOC) += s6000/ obj-$(CONFIG_SND_SOC) += sh/ obj-$(CONFIG_SND_SOC) += tegra/ obj-$(CONFIG_SND_SOC) += txx9/ +obj-$(CONFIG_SND_SOC) += ux500/ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 98175a096df..4ac475d51bd 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -96,7 +96,12 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM9705 if SND_SOC_AC97_BUS select SND_SOC_WM9712 if SND_SOC_AC97_BUS select SND_SOC_WM9713 if SND_SOC_AC97_BUS - help + select SND_SOC_AB3550 + select SND_SOC_AB5500 + select SND_SOC_AB8500 + select SND_SOC_CG29XX + select SND_SOC_AV8100 + help Normally ASoC codec drivers are only built if a machine driver which uses them is also built since they are only usable with a machine driver. Selecting this option will allow these drivers to be built @@ -371,6 +376,21 @@ config SND_SOC_WM9712 config SND_SOC_WM9713 tristate +config SND_SOC_AB3550 + tristate + +config SND_SOC_AB5500 + tristate + +config SND_SOC_AB8500 + tristate + +config SND_SOC_CG29XX + tristate + +config SND_SOC_AV8100 + tristate + # Amp config SND_SOC_LM4857 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index fd8558406ef..a8e4d5c6cde 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -1,4 +1,7 @@ snd-soc-88pm860x-objs := 88pm860x-codec.o +snd-soc-ab3550-objs := ab3550.o +snd-soc-ab5500-objs := ab5500.o +snd-soc-ab8500_audio-objs := ab8500_audio.o snd-soc-ac97-objs := ac97.o snd-soc-ad1836-objs := ad1836.o snd-soc-ad193x-objs := ad193x.o @@ -10,6 +13,8 @@ snd-soc-ak4535-objs := ak4535.o snd-soc-ak4641-objs := ak4641.o snd-soc-ak4642-objs := ak4642.o snd-soc-ak4671-objs := ak4671.o +snd-soc-av8100_audio-objs := av8100_audio.o +snd-soc-cg29xx-objs := cg29xx.o snd-soc-cq93vc-objs := cq93vc.o snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs4270-objs := cs4270.o @@ -89,6 +94,9 @@ snd-soc-tpa6130a2-objs := tpa6130a2.o snd-soc-wm2000-objs := wm2000.o snd-soc-wm9090-objs := wm9090.o +obj-$(CONFIG_SND_SOC_AB3550) += snd-soc-ab3550.o +obj-$(CONFIG_SND_SOC_AB5500) += snd-soc-ab5500.o +obj-$(CONFIG_SND_SOC_AB8500) += snd-soc-ab8500_audio.o obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o @@ -102,6 +110,8 @@ obj-$(CONFIG_SND_SOC_AK4641) += snd-soc-ak4641.o obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o +obj-$(CONFIG_SND_SOC_AV8100) += snd-soc-av8100_audio.o +obj-$(CONFIG_SND_SOC_CG29XX) += snd-soc-cg29xx.o obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o @@ -178,4 +188,9 @@ obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o -obj-$(CONFIG_SND_SOC_WM9090) += snd-soc-wm9090.o +ifdef CONFIG_SND_SOC_UX500_DEBUG +CFLAGS_av8100_audio.o := -DDEBUG +CFLAGS_ab3550.o := -DDEBUG +CFLAGS_cg29xx.o := -DDEBUG +CFLAGS_ab8500_audio.o := -DDEBUG +endif diff --git a/sound/soc/codecs/ab3550.c b/sound/soc/codecs/ab3550.c new file mode 100644 index 00000000000..4a15ab64d32 --- /dev/null +++ b/sound/soc/codecs/ab3550.c @@ -0,0 +1,1429 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Xie Xiaolei <xie.xiaolei@etericsson.com>, + * Roger Nilsson <roger.xr.nilsson@stericsson.com>, + * Ola Lilja <ola.o.lilja@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <linux/mfd/abx500.h> +#include <linux/bitmap.h> +#include <linux/bitops.h> +#include <asm/atomic.h> +#include <linux/rwsem.h> +#include <linux/mutex.h> +#include <stdarg.h> +#include "ab3550.h" + + +#define I2C_BANK 0 + +/* codec private data */ +struct ab3550_codec_dai_data { +}; + +static struct device *ab3550_dev; + +static u8 virtual_regs[] = { + 0, 0 +}; + +static void set_reg(u8 reg, u8 val) +{ + if (!ab3550_dev) { + pr_err("%s: The AB3550 codec driver not initialized.\n", + __func__); + return; + } + if (reg < AB3550_FIRST_REG) + return; + else if (reg <= AB3550_LAST_REG) { + abx500_set_register_interruptible( + ab3550_dev, I2C_BANK, reg, val); + } else if (reg - AB3550_LAST_REG - 1 < ARRAY_SIZE(virtual_regs)) { + virtual_regs[reg - AB3550_LAST_REG - 1] = val; + } +} + +static void mask_set_reg(u8 reg, u8 mask, u8 val) +{ + if (!ab3550_dev) { + pr_err("%s: The AB3550 codec driver not initialized.\n", + __func__); + return; + } + if (reg < AB3550_FIRST_REG) + return; + else if (reg <= AB3550_LAST_REG) { + abx500_mask_and_set_register_interruptible( + ab3550_dev, I2C_BANK, reg, mask, val); + } else if (reg - AB3550_LAST_REG - 1 < ARRAY_SIZE(virtual_regs)) { + virtual_regs[reg - AB3550_LAST_REG - 1] &= ~mask; + virtual_regs[reg - AB3550_LAST_REG - 1] |= val & mask; + } +} + +static u8 read_reg(u8 reg) +{ + if (!ab3550_dev) { + pr_err("%s: The AB3550 codec driver not initialized.\n", + __func__); + return 0; + } + if (reg < AB3550_FIRST_REG) + return 0; + else if (reg <= AB3550_LAST_REG) { + u8 val; + abx500_get_register_interruptible( + ab3550_dev, I2C_BANK, reg, &val); + return val; + } else if (reg - AB3550_LAST_REG - 1 < ARRAY_SIZE(virtual_regs)) + return virtual_regs[reg - AB3550_LAST_REG - 1]; + dev_warn(ab3550_dev, "%s: out-of-scope reigster %u.\n", + __func__, reg); + return 0; +} + +/* Components that can be powered up/down */ +enum enum_widget { + widget_ear = 0, + widget_auxo1, + widget_auxo2, + + widget_spkr, + widget_line1, + widget_line2, + + widget_dac1, + widget_dac2, + widget_dac3, + + widget_rx1, + widget_rx2, + widget_rx3, + + widget_mic1, + widget_mic2, + + widget_micbias1, + widget_micbias2, + + widget_apga1, + widget_apga2, + + widget_tx1, + widget_tx2, + + widget_adc1, + widget_adc2, + + widget_if0_dld_l, + widget_if0_dld_r, + widget_if0_uld_l, + widget_if0_uld_r, + widget_if1_dld_l, + widget_if1_dld_r, + widget_if1_uld_l, + widget_if1_uld_r, + + widget_mic1p1, + widget_mic1n1, + widget_mic1p2, + widget_mic1n2, + + widget_mic2p1, + widget_mic2n1, + widget_mic2p2, + widget_mic2n2, + + widget_clock, + + number_of_widgets +}; + +/* This is only meant for debugging */ +static const char *widget_names[] = { + "EAR", "AUXO1", "AUXO2", "SPKR", "LINE1", "LINE2", + "DAC1", "DAC2", "DAC3", + "RX1", "RX2", "RX3", + "MIC1", "MIC2", + "MIC-BIAS1", "MIC-BIAS2", + "APGA1", "APGA2", + "TX1", "TX2", + "ADC1", "ADC2", + "IF0-DLD-L", "IF0-DLD-R", "IF0-ULD-L", "IF0-ULD-R", + "IF1-DLD-L", "IF1-DLD-R", "IF1-ULD-L", "IF1-ULD-R", + "MIC1P1", "MIC1N1", "MIC1P2", "MIC1N2", + "MIC2P1", "MIC2N1", "MIC2P2", "MIC2N2", + "CLOCK" +}; + +struct widget_pm { + enum enum_widget widget; + u8 reg; + u8 shift; + + unsigned long source_list[BIT_WORD(number_of_widgets) + 1]; + unsigned long sink_list[BIT_WORD(number_of_widgets) + 1]; +}; + +static struct widget_pm widget_pm_array[] = { + {.widget = widget_ear, .reg = EAR, .shift = EAR_PWR_SHIFT}, + {.widget = widget_auxo1, .reg = AUXO1, .shift = AUXOx_PWR_SHIFT}, + {.widget = widget_auxo2, .reg = AUXO2, .shift = AUXOx_PWR_SHIFT}, + {.widget = widget_spkr, .reg = SPKR, .shift = SPKR_PWR_SHIFT}, + {.widget = widget_line1, .reg = LINE1, .shift = LINEx_PWR_SHIFT}, + {.widget = widget_line2, .reg = LINE2, .shift = LINEx_PWR_SHIFT}, + + {.widget = widget_dac1, .reg = RX1, .shift = DACx_PWR_SHIFT}, + {.widget = widget_dac2, .reg = RX2, .shift = DACx_PWR_SHIFT}, + {.widget = widget_dac3, .reg = RX3, .shift = DACx_PWR_SHIFT}, + + {.widget = widget_rx1, .reg = RX1, .shift = RXx_PWR_SHIFT}, + {.widget = widget_rx2, .reg = RX2, .shift = RXx_PWR_SHIFT}, + {.widget = widget_rx3, .reg = RX3, .shift = RXx_PWR_SHIFT}, + + {.widget = widget_mic1, .reg = MIC1_GAIN, .shift = MICx_PWR_SHIFT}, + {.widget = widget_mic2, .reg = MIC2_GAIN, .shift = MICx_PWR_SHIFT}, + + {.widget = widget_micbias1, .reg = MIC_BIAS1, + .shift = MBIAS_PWR_SHIFT}, + {.widget = widget_micbias2, .reg = MIC_BIAS2, + .shift = MBIAS_PWR_SHIFT}, + + {.widget = widget_apga1, .reg = ANALOG_LOOP_PGA1, + .shift = APGAx_PWR_SHIFT}, + {.widget = widget_apga2, .reg = ANALOG_LOOP_PGA2, + .shift = APGAx_PWR_SHIFT}, + + {.widget = widget_tx1, .reg = TX1, .shift = TXx_PWR_SHIFT}, + {.widget = widget_tx2, .reg = TX2, .shift = TXx_PWR_SHIFT}, + + {.widget = widget_adc1, .reg = TX1, .shift = ADCx_PWR_SHIFT}, + {.widget = widget_adc2, .reg = TX2, .shift = ADCx_PWR_SHIFT}, + + {.widget = widget_if0_dld_l, .reg = AB3550_VIRTUAL_REG1, + .shift = IF0_DLD_L_PW_SHIFT}, + {.widget = widget_if0_dld_r, .reg = AB3550_VIRTUAL_REG1, + .shift = IF0_DLD_R_PW_SHIFT}, + {.widget = widget_if0_uld_l, .reg = AB3550_VIRTUAL_REG1, + .shift = IF0_ULD_L_PW_SHIFT}, + {.widget = widget_if0_uld_r, .reg = AB3550_VIRTUAL_REG1, + .shift = IF0_ULD_R_PW_SHIFT}, + + {.widget = widget_if1_dld_l, .reg = AB3550_VIRTUAL_REG1, + .shift = IF1_DLD_L_PW_SHIFT}, + {.widget = widget_if1_dld_r, .reg = AB3550_VIRTUAL_REG1, + .shift = IF1_DLD_R_PW_SHIFT}, + {.widget = widget_if1_uld_l, .reg = AB3550_VIRTUAL_REG1, + .shift = IF1_ULD_L_PW_SHIFT}, + {.widget = widget_if1_uld_r, .reg = AB3550_VIRTUAL_REG1, + .shift = IF1_ULD_R_PW_SHIFT}, + + {.widget = widget_mic1p1, .reg = AB3550_VIRTUAL_REG2, + .shift = MIC1P1_PW_SHIFT}, + {.widget = widget_mic1n1, .reg = AB3550_VIRTUAL_REG2, + .shift = MIC1N1_PW_SHIFT}, + {.widget = widget_mic1p2, .reg = AB3550_VIRTUAL_REG2, + .shift = MIC1P2_PW_SHIFT}, + {.widget = widget_mic1n2, .reg = AB3550_VIRTUAL_REG2, + .shift = MIC1N2_PW_SHIFT}, + + {.widget = widget_mic2p1, .reg = AB3550_VIRTUAL_REG2, + .shift = MIC2P1_PW_SHIFT}, + {.widget = widget_mic2n1, .reg = AB3550_VIRTUAL_REG2, + .shift = MIC2N1_PW_SHIFT}, + {.widget = widget_mic2p2, .reg = AB3550_VIRTUAL_REG2, + .shift = MIC2P2_PW_SHIFT}, + {.widget = widget_mic2n2, .reg = AB3550_VIRTUAL_REG2, + .shift = MIC2N2_PW_SHIFT}, + + {.widget = widget_clock, .reg = CLOCK, .shift = CLOCK_ENABLE_SHIFT}, +}; + +DEFINE_MUTEX(ab3550_pm_mutex); + +static struct { + enum enum_widget stack[number_of_widgets]; + int p; +} pm_stack; + +struct ab3550_dai_private { + unsigned int fmt; +}; + +#define pm_stack_as_bitmap ({ \ + unsigned long bitmap[BIT_WORD(number_of_widgets) + 1]; \ + int i; \ + memset(bitmap, 0, sizeof(bitmap)); \ + for (i = 0; i < pm_stack.p; i++) { \ + set_bit(pm_stack.stack[i], bitmap); \ + } \ + bitmap; \ + }) + +/* These are only meant to meet the obligations of DAPM */ +static const struct snd_soc_dapm_widget ab3550_dapm_widgets[] = { +}; + +static const struct snd_soc_dapm_route intercon[] = { +}; + + +static const char *enum_rx2_select[] = {"I2S0", "I2S1"}; +static const char *enum_i2s_input_select[] = { + "tri-state", "MIC1", "MIC2", "mute" +}; +static const char *enum_apga1_source[] = {"LINEIN1", "MIC1", "MIC2"}; +static const char *enum_apga2_source[] = {"LINEIN2", "MIC1", "MIC2"}; +static const char *enum_dac_side_tone[] = {"TX1", "TX2"}; +static const char *enum_dac_power_mode[] = {"100%", "75%", "55%"}; +static const char *enum_ear_power_mode[] = {"100%", "70%"}; +static const char *enum_auxo_power_mode[] = { + "100%", "67%", "50%", "25%", "auto" +}; +static const char *enum_onoff[] = {"Off", "On"}; +static const char *enum_mbias_hiz_option[] = {"GND", "HiZ"}; +static const char *enum_mbias2_output_voltage[] = {"2.0v", "2.2v"}; +static const char *enum_mic_input_impedance[] = { + "12.5 kohm", "25 kohm", "50 kohm" +}; +static const char *enum_hp_filter[] = {"HP3", "HP1", "bypass"}; +static const char *enum_i2s_word_length[] = {"16 bits", "24 bits"}; +static const char *enum_i2s_mode[] = {"Master Mode", "Slave Mode"}; +static const char *enum_i2s_tristate[] = {"Normal", "Tri-state"}; +static const char *enum_optional_resistor[] = {"disconnected", "connected"}; +static const char *enum_i2s_sample_rate[] = { + "8 kHz", "16 kHz", "44.1 kHz", "48 kHz" +}; +static const char *enum_signal_inversion[] = {"normal", "inverted"}; + +/* RX2 Select */ +static struct soc_enum soc_enum_rx2_select = + SOC_ENUM_SINGLE(RX2, 4, ARRAY_SIZE(enum_rx2_select), enum_rx2_select); + +/* I2S0 Input Select */ +static struct soc_enum soc_enum_i2s0_input_select = + SOC_ENUM_DOUBLE(INTERFACE0_DATA, 0, 2, + ARRAY_SIZE(enum_i2s_input_select), + enum_i2s_input_select); +/* I2S1 Input Select */ +static struct soc_enum soc_enum_i2s1_input_select = + SOC_ENUM_DOUBLE(INTERFACE1_DATA, 0, 2, + ARRAY_SIZE(enum_i2s_input_select), + enum_i2s_input_select); + +/* APGA1 Source */ +static struct soc_enum soc_enum_apga1_source = + SOC_ENUM_SINGLE(ANALOG_LOOP_PGA1, APGAx_MUX_SHIFT, + ARRAY_SIZE(enum_apga1_source), enum_apga1_source); + +/* APGA2 Source */ +static struct soc_enum soc_enum_apga2_source = + SOC_ENUM_SINGLE(ANALOG_LOOP_PGA2, APGAx_MUX_SHIFT, + ARRAY_SIZE(enum_apga2_source), enum_apga2_source); + +static struct soc_enum soc_enum_apga1_enable = + SOC_ENUM_SINGLE(ANALOG_LOOP_PGA1, APGAx_PWR_SHIFT, + ARRAY_SIZE(enum_onoff), enum_onoff); + +static struct soc_enum soc_enum_apga2_enable = + SOC_ENUM_SINGLE(ANALOG_LOOP_PGA2, APGAx_PWR_SHIFT, + ARRAY_SIZE(enum_onoff), enum_onoff); + +/* DAC1 Side Tone */ +static struct soc_enum soc_enum_dac1_side_tone = + SOC_ENUM_SINGLE(SIDETONE1_PGA, STx_MUX_SHIFT, + ARRAY_SIZE(enum_dac_side_tone), enum_dac_side_tone); + +/* DAC2 Side Tone */ +static struct soc_enum soc_enum_dac2_side_tone = + SOC_ENUM_SINGLE(SIDETONE2_PGA, STx_MUX_SHIFT, + ARRAY_SIZE(enum_dac_side_tone), enum_dac_side_tone); + +/* DAC1 Power Mode */ +static struct soc_enum soc_enum_dac1_power_mode = + SOC_ENUM_SINGLE(RX1, DACx_PWR_MODE_SHIFT, + ARRAY_SIZE(enum_dac_power_mode), enum_dac_power_mode); + +/* DAC2 Power Mode */ +static struct soc_enum soc_enum_dac2_power_mode = + SOC_ENUM_SINGLE(RX2, DACx_PWR_MODE_SHIFT, + ARRAY_SIZE(enum_dac_power_mode), enum_dac_power_mode); + +/* DAC3 Power Mode */ +static struct soc_enum soc_enum_dac3_power_mode = + SOC_ENUM_SINGLE(RX3, DACx_PWR_MODE_SHIFT, + ARRAY_SIZE(enum_dac_power_mode), enum_dac_power_mode); + +/* EAR Power Mode */ +static struct soc_enum soc_enum_ear_power_mode = + SOC_ENUM_SINGLE(EAR, EAR_PWR_MODE_SHIFT, + ARRAY_SIZE(enum_ear_power_mode), enum_ear_power_mode); + +/* AUXO Power Mode */ +static struct soc_enum soc_enum_auxo_power_mode = + SOC_ENUM_SINGLE(AUXO_PWR_MODE, AUXO_PWR_MODE_SHIFT, + ARRAY_SIZE(enum_auxo_power_mode), + enum_auxo_power_mode); + +/* MBIAS1 HiZ Option */ +static struct soc_enum soc_enum_mbias1_hiz_option = + SOC_ENUM_SINGLE(MIC_BIAS1, MBIAS_PDN_IMP_SHIFT, + ARRAY_SIZE(enum_mbias_hiz_option), + enum_mbias_hiz_option); + +/* MBIAS1 HiZ Option */ +static struct soc_enum soc_enum_mbias2_hiz_option = + SOC_ENUM_SINGLE(MIC_BIAS2, MBIAS_PDN_IMP_SHIFT, + ARRAY_SIZE(enum_mbias_hiz_option), + enum_mbias_hiz_option); + +/* MBIAS2 Output voltage */ +static struct soc_enum soc_enum_mbias2_output_voltage = + SOC_ENUM_SINGLE(MIC_BIAS2, MBIAS2_OUT_V_SHIFT, + ARRAY_SIZE(enum_mbias2_output_voltage), + enum_mbias2_output_voltage); + +static struct soc_enum soc_enum_mbias2_internal_resistor = + SOC_ENUM_SINGLE(MIC_BIAS2_VAD, MBIAS2_R_INT_SHIFT, + ARRAY_SIZE(enum_optional_resistor), + enum_optional_resistor); + +static struct soc_enum soc_enum_mic1_input_impedance = + SOC_ENUM_SINGLE(MIC1_GAIN, MICx_IN_IMP_SHIFT, + ARRAY_SIZE(enum_mic_input_impedance), + enum_mic_input_impedance); + +static struct soc_enum soc_enum_mic2_input_impedance = + SOC_ENUM_SINGLE(MIC2_GAIN, MICx_IN_IMP_SHIFT, + ARRAY_SIZE(enum_mic_input_impedance), + enum_mic_input_impedance); + +static struct soc_enum soc_enum_tx1_hp_filter = + SOC_ENUM_SINGLE(TX1, TXx_HP_FILTER_SHIFT, + ARRAY_SIZE(enum_hp_filter), + enum_hp_filter); + +static struct soc_enum soc_enum_tx2_hp_filter = + SOC_ENUM_SINGLE(TX2, TXx_HP_FILTER_SHIFT, + ARRAY_SIZE(enum_hp_filter), + enum_hp_filter); + +static struct soc_enum soc_enum_st1_hp_filter = + SOC_ENUM_SINGLE(SIDETONE1_PGA, STx_HP_FILTER_SHIFT, + ARRAY_SIZE(enum_hp_filter), + enum_hp_filter); + +static struct soc_enum soc_enum_st2_hp_filter = + SOC_ENUM_SINGLE(SIDETONE2_PGA, STx_HP_FILTER_SHIFT, + ARRAY_SIZE(enum_hp_filter), + enum_hp_filter); + +static struct soc_enum soc_enum_i2s0_word_length = + SOC_ENUM_SINGLE(INTERFACE0, I2Sx_WORDLENGTH_SHIFT, + ARRAY_SIZE(enum_i2s_word_length), + enum_i2s_word_length); + +static struct soc_enum soc_enum_i2s1_word_length = + SOC_ENUM_SINGLE(INTERFACE1, I2Sx_WORDLENGTH_SHIFT, + ARRAY_SIZE(enum_i2s_word_length), + enum_i2s_word_length); + +static struct soc_enum soc_enum_i2s0_mode = + SOC_ENUM_SINGLE(INTERFACE0, I2Sx_MODE_SHIFT, + ARRAY_SIZE(enum_i2s_mode), + enum_i2s_mode); + +static struct soc_enum soc_enum_i2s1_mode = + SOC_ENUM_SINGLE(INTERFACE1, I2Sx_MODE_SHIFT, + ARRAY_SIZE(enum_i2s_mode), + enum_i2s_mode); + +static struct soc_enum soc_enum_i2s0_tristate = + SOC_ENUM_SINGLE(INTERFACE0, I2Sx_TRISTATE_SHIFT, + ARRAY_SIZE(enum_i2s_tristate), + enum_i2s_tristate); + +static struct soc_enum soc_enum_i2s1_tristate = + SOC_ENUM_SINGLE(INTERFACE1, I2Sx_TRISTATE_SHIFT, + ARRAY_SIZE(enum_i2s_tristate), + enum_i2s_tristate); + +static struct soc_enum soc_enum_i2s0_pulldown_resistor = + SOC_ENUM_SINGLE(INTERFACE0, I2Sx_PULLDOWN_SHIFT, + ARRAY_SIZE(enum_optional_resistor), + enum_optional_resistor); + +static struct soc_enum soc_enum_i2s1_pulldown_resistor = + SOC_ENUM_SINGLE(INTERFACE1, I2Sx_PULLDOWN_SHIFT, + ARRAY_SIZE(enum_optional_resistor), + enum_optional_resistor); + +static struct soc_enum soc_enum_i2s0_sample_rate = + SOC_ENUM_SINGLE(INTERFACE0, I2Sx_SR_SHIFT, + ARRAY_SIZE(enum_i2s_sample_rate), + enum_i2s_sample_rate); + +static struct soc_enum soc_enum_i2s1_sample_rate = + SOC_ENUM_SINGLE(INTERFACE1, I2Sx_SR_SHIFT, + ARRAY_SIZE(enum_i2s_sample_rate), + enum_i2s_sample_rate); + +static struct soc_enum soc_enum_line1_inversion = + SOC_ENUM_SINGLE(LINE1, LINEx_INV_SHIFT, + ARRAY_SIZE(enum_signal_inversion), + enum_signal_inversion); + +static struct soc_enum soc_enum_line2_inversion = + SOC_ENUM_SINGLE(LINE2, LINEx_INV_SHIFT, + ARRAY_SIZE(enum_signal_inversion), + enum_signal_inversion); + +static struct soc_enum soc_enum_auxo1_inversion = + SOC_ENUM_SINGLE(AUXO1, AUXOx_INV_SHIFT, + ARRAY_SIZE(enum_signal_inversion), + enum_signal_inversion); + +static struct soc_enum soc_enum_auxo2_inversion = + SOC_ENUM_SINGLE(AUXO1, AUXOx_INV_SHIFT, + ARRAY_SIZE(enum_signal_inversion), + enum_signal_inversion); + +static struct soc_enum soc_enum_auxo1_pulldown_resistor = + SOC_ENUM_SINGLE(AUXO1, AUXOx_PULLDOWN_SHIFT, + ARRAY_SIZE(enum_optional_resistor), + enum_optional_resistor); + +static struct soc_enum soc_enum_auxo2_pulldown_resistor = + SOC_ENUM_SINGLE(AUXO1, AUXOx_PULLDOWN_SHIFT, + ARRAY_SIZE(enum_optional_resistor), + enum_optional_resistor); + +static struct snd_kcontrol_new ab3550_snd_controls[] = { + /* RX Routing */ + SOC_ENUM("RX2 Select", soc_enum_rx2_select), + SOC_SINGLE("LINE1 Adder", LINE1_ADDER, 0, 0x07, 0), + SOC_SINGLE("LINE2 Adder", LINE2_ADDER, 0, 0x07, 0), + SOC_SINGLE("EAR Adder", EAR_ADDER, 0, 0x07, 0), + SOC_SINGLE("SPKR Adder", SPKR_ADDER, 0, 0x07, 0), + SOC_SINGLE("AUXO1 Adder", AUXO1_ADDER, 0, 0x07, 0), + SOC_SINGLE("AUXO2 Adder", AUXO2_ADDER, 0, 0x07, 0), + /* TX Routing */ + SOC_SINGLE("MIC1 Input Select", MIC1_INPUT_SELECT, 0, 0xff, 0), + SOC_SINGLE("MIC2 Input Select", MIC1_INPUT_SELECT, 0, 0xff, 0), + SOC_SINGLE("MIC2 to MIC1", MIC2_TO_MIC1, 0, 0x03, 0), + SOC_ENUM("I2S0 Input Select", soc_enum_i2s0_input_select), + SOC_ENUM("I2S1 Input Select", soc_enum_i2s1_input_select), + /* Routing of Side Tone and Analop Loop */ + SOC_ENUM("APGA1 Source", soc_enum_apga1_source), + SOC_ENUM("APGA2 Source", soc_enum_apga2_source), + SOC_ENUM("APGA1 Enable", soc_enum_apga1_enable), + SOC_ENUM("APGA2 Enable", soc_enum_apga2_enable), + SOC_SINGLE("APGA1 Destination", APGA1_ADDER, 0, 0x3f, 0), + SOC_SINGLE("APGA2 Destination", APGA2_ADDER, 0, 0x3f, 0), + SOC_ENUM("DAC1 Side Tone", soc_enum_dac1_side_tone), + SOC_ENUM("DAC2 Side Tone", soc_enum_dac2_side_tone), + /* RX Volume Control */ + SOC_SINGLE("RX-DPGA1 Gain", RX1_DIGITAL_PGA, 0, 0x43, 0), + SOC_SINGLE("RX-DPGA2 Gain", RX1_DIGITAL_PGA, 0, 0x43, 0), + SOC_SINGLE("RX-DPGA3 Gain", RX3_DIGITAL_PGA, 0, 0x43, 0), + SOC_SINGLE("LINE1 Gain", LINE1, LINEx_GAIN_SHIFT, 0x0a, 0), + SOC_SINGLE("LINE2 Gain", LINE2, LINEx_GAIN_SHIFT, 0x0a, 0), + SOC_SINGLE("SPKR Gain", SPKR, SPKR_GAIN_SHIFT, 0x16, 0), + SOC_SINGLE("EAR Gain", EAR, EAR_GAIN_SHIFT, 0x0e, 0), + SOC_SINGLE("AUXO1 Gain", AUXO1, AUXOx_GAIN_SHIFT, 0x0c, 0), + SOC_SINGLE("AUXO2 Gain", AUXO2, AUXOx_GAIN_SHIFT, 0x0c, 0), + /* TX Volume Control */ + SOC_SINGLE("MIC1 Gain", MIC1_GAIN, MICx_GAIN_SHIFT, 0x0a, 0), + SOC_SINGLE("MIC2 Gain", MIC2_GAIN, MICx_GAIN_SHIFT, 0x0a, 0), + SOC_SINGLE("TX-DPGA1 Gain", TX_DIGITAL_PGA1, TXDPGAx_SHIFT, 0x0f, 0), + SOC_SINGLE("TX-DPGA2 Gain", TX_DIGITAL_PGA2, TXDPGAx_SHIFT, 0x0f, 0), + /* Volume Control of Side Tone and Analog Loop */ + SOC_SINGLE("ST-PGA1 Gain", SIDETONE1_PGA, STx_PGA_SHIFT, 0x0a, 0), + SOC_SINGLE("ST-PGA2 Gain", SIDETONE2_PGA, STx_PGA_SHIFT, 0x0a, 0), + SOC_SINGLE("APGA1 Gain", ANALOG_LOOP_PGA1, APGAx_GAIN_SHIFT, 0x1d, 0), + SOC_SINGLE("APGA2 Gain", ANALOG_LOOP_PGA2, APGAx_GAIN_SHIFT, 0x1d, 0), + /* RX Properties */ + SOC_ENUM("DAC1 Power Mode", soc_enum_dac1_power_mode), + SOC_ENUM("DAC2 Power Mode", soc_enum_dac2_power_mode), + SOC_ENUM("DAC3 Power Mode", soc_enum_dac3_power_mode), + SOC_ENUM("EAR Power Mode", soc_enum_ear_power_mode), + SOC_ENUM("AUXO Power Mode", soc_enum_auxo_power_mode), + SOC_ENUM("LINE1 Inversion", soc_enum_line1_inversion), + SOC_ENUM("LINE2 Inversion", soc_enum_line2_inversion), + SOC_ENUM("AUXO1 Inversion", soc_enum_auxo1_inversion), + SOC_ENUM("AUXO2 Inversion", soc_enum_auxo2_inversion), + SOC_ENUM("AUXO1 Pulldown Resistor", soc_enum_auxo1_pulldown_resistor), + SOC_ENUM("AUXO2 Pulldown Resistor", soc_enum_auxo2_pulldown_resistor), + /* TX Properties */ + SOC_SINGLE("MIC1 VMID", MIC1_VMID_SELECT, 0, 0xff, 0), + SOC_SINGLE("MIC2 VMID", MIC2_VMID_SELECT, 0, 0xff, 0), + SOC_ENUM("MBIAS1 HiZ Option", soc_enum_mbias1_hiz_option), + SOC_ENUM("MBIAS2 HiZ Option", soc_enum_mbias2_hiz_option), + SOC_ENUM("MBIAS2 Output Voltage", soc_enum_mbias2_output_voltage), + SOC_ENUM("MBIAS2 Internal Resistor", soc_enum_mbias2_internal_resistor), + SOC_ENUM("MIC1 Input Impedance", soc_enum_mic1_input_impedance), + SOC_ENUM("MIC2 Input Impedance", soc_enum_mic2_input_impedance), + SOC_ENUM("TX1 HP Filter", soc_enum_tx1_hp_filter), + SOC_ENUM("TX2 HP Filter", soc_enum_tx2_hp_filter), + /* Side Tone and Analog Loop Properties */ + SOC_ENUM("ST1 HP Filter", soc_enum_st1_hp_filter), + SOC_ENUM("ST2 HP Filter", soc_enum_st2_hp_filter), + /* I2S Interface Properties */ + SOC_ENUM("I2S0 Word Length", soc_enum_i2s0_word_length), + SOC_ENUM("I2S1 Word Length", soc_enum_i2s1_word_length), + SOC_ENUM("I2S0 Mode", soc_enum_i2s0_mode), + SOC_ENUM("I2S1 Mode", soc_enum_i2s1_mode), + SOC_ENUM("I2S0 tri-state", soc_enum_i2s0_tristate), + SOC_ENUM("I2S1 tri-state", soc_enum_i2s1_tristate), + SOC_ENUM("I2S0 Pulldown Resistor", soc_enum_i2s0_pulldown_resistor), + SOC_ENUM("I2S1 Pulldown Resistor", soc_enum_i2s1_pulldown_resistor), + SOC_ENUM("I2S0 Sample Rate", soc_enum_i2s0_sample_rate), + SOC_ENUM("I2S1 Sample Rate", soc_enum_i2s1_sample_rate), + SOC_SINGLE("Interface Loop", INTERFACE_LOOP, 0, 0x0f, 0), + SOC_SINGLE("Interface Swap", INTERFACE_SWAP, 0, 0x1f, 0), + /* Miscellaneous */ + SOC_SINGLE("Negative Charge Pump", NEGATIVE_CHARGE_PUMP, 0, 0x03, 0) +}; + +/* count the number of 1 */ +#define count_ones(x) ({ \ + int num; \ + for (num = 0; x; (x) &= (x) - 1, num++) \ + ; \ + num; \ + }) + +enum enum_power { + POWER_OFF = 0, + POWER_ON = 1 +}; + +enum enum_link { + UNLINK = 0, + LINK = 1 +}; + +static enum enum_power get_widget_power_status(enum enum_widget widget) +{ + u8 val; + + if (widget >= number_of_widgets) + return POWER_OFF; + val = read_reg(widget_pm_array[widget].reg); + if (val & (1 << widget_pm_array[widget].shift)) + return POWER_ON; + else + return POWER_OFF; +} + +static int count_powered_neighbors(const unsigned long *neighbors) +{ + unsigned long i; + int n = 0; + for_each_set_bit(i, neighbors, number_of_widgets) { + if (get_widget_power_status(i) == POWER_ON) + n++; + } + return n; +} + +static int has_powered_neighbors(const unsigned long *neighbors) +{ + unsigned int i; + for_each_set_bit(i, neighbors, number_of_widgets) { + if (get_widget_power_status(i) == POWER_ON) + return 1; + } + return 0; +} + + +static int has_stacked_neighbors(const unsigned long *neighbors) +{ + unsigned long *stack_map = pm_stack_as_bitmap; + return bitmap_intersects(stack_map, neighbors, number_of_widgets); +} + +static void power_widget_unlocked(enum enum_power onoff, + enum enum_widget widget) +{ + enum enum_widget w; + int done; + + if (widget >= number_of_widgets) + return; + if (get_widget_power_status(widget) == onoff) + return; + + for (w = widget, done = 0; !done;) { + unsigned long i; + unsigned long *srcs = widget_pm_array[w].source_list; + unsigned long *sinks = widget_pm_array[w].sink_list; + dev_dbg(ab3550_dev, "%s: processing widget %s.\n", + __func__, widget_names[w]); + + if (onoff == POWER_ON && + !bitmap_empty(srcs, number_of_widgets) && + !has_powered_neighbors(srcs)) { + pm_stack.stack[pm_stack.p++] = w; + for_each_set_bit(i, srcs, number_of_widgets) { + pm_stack.stack[pm_stack.p++] = i; + } + w = pm_stack.stack[--pm_stack.p]; + continue; + } else if (onoff == POWER_OFF && + has_powered_neighbors(sinks)) { + int n = 0; + pm_stack.stack[pm_stack.p++] = w; + for_each_set_bit(i, sinks, number_of_widgets) { + if (count_powered_neighbors( + widget_pm_array[i].source_list) + == 1 && + get_widget_power_status(i) == POWER_ON) { + pm_stack.stack[pm_stack.p++] = i; + n++; + } + } + if (n) { + w = pm_stack.stack[--pm_stack.p]; + continue; + } else + --pm_stack.p; + } + mask_set_reg(widget_pm_array[w].reg, + 1 << widget_pm_array[w].shift, + onoff == POWER_ON ? 0xff : 0); + dev_dbg(ab3550_dev, "%s: widget %s powered %s.\n", + __func__, widget_names[w], + onoff == POWER_ON ? "on" : "off"); + + if (onoff == POWER_ON && + !bitmap_empty(sinks, number_of_widgets) && + !has_powered_neighbors(sinks) && + !has_stacked_neighbors(sinks)) { + for_each_set_bit(i, sinks, number_of_widgets) { + pm_stack.stack[pm_stack.p++] = i; + } + w = pm_stack.stack[--pm_stack.p]; + continue; + } else if (onoff == POWER_OFF) { + for_each_set_bit(i, srcs, number_of_widgets) { + if (!has_powered_neighbors( + widget_pm_array[i].sink_list) + && get_widget_power_status(i) == POWER_ON + && !test_bit(i, pm_stack_as_bitmap)) { + pm_stack.stack[pm_stack.p++] = i; + } + } + } + if (pm_stack.p > 0) + w = pm_stack.stack[--pm_stack.p]; + else + done = 1; + } +} + +static void power_widget_locked(enum enum_power onoff, + enum enum_widget widget) +{ + if (mutex_lock_interruptible(&ab3550_pm_mutex)) { + dev_warn(ab3550_dev, + "%s: Signal received while waiting on the PM mutex.\n", + __func__); + return; + } + power_widget_unlocked(onoff, widget); + mutex_unlock(&ab3550_pm_mutex); +} + +static void dump_registers(const char *where, ...) +{ + va_list ap; + va_start(ap, where); + do { + short reg = va_arg(ap, int); + if (reg < 0) + break; + dev_dbg(ab3550_dev, "%s from %s> 0x%02X : 0x%02X.\n", + __func__, where, reg, read_reg(reg)); + } while (1); + va_end(ap); +} + +/** + * update the link between two widgets. + * @op: 1 - connect; 0 - disconnect + * @src: source of the connection + * @sink: sink of the connection + */ +static int update_widgets_link(enum enum_link op, enum enum_widget src, + enum enum_widget sink, + u8 reg, u8 mask, u8 newval) +{ + int ret = 0; + + if (mutex_lock_interruptible(&ab3550_pm_mutex)) { + dev_warn(ab3550_dev, "%s: A signal is received while waiting on" + " the PM mutex.\n", __func__); + return -EINTR; + } + + switch (op << 2 | test_bit(sink, widget_pm_array[src].sink_list) << 1 | + test_bit(src, widget_pm_array[sink].source_list)) { + case 3: /* UNLINK, sink in sink_list, src in source_list */ + case 4: /* LINK, sink not in sink_list, src not in source_list */ + break; + default: + ret = -EINVAL; + goto end; + } + switch (((int)op) << 2 | get_widget_power_status(src) << 1 | + get_widget_power_status(sink)) { + case 3: /* op = 0, src on, sink on */ + if (count_powered_neighbors(widget_pm_array[sink].source_list) + == 1) + power_widget_unlocked(POWER_OFF, sink); + mask_set_reg(reg, mask, newval); + break; + case 6: /* op = 1, src on, sink off */ + mask_set_reg(reg, mask, newval); + power_widget_unlocked(POWER_ON, sink); + break; + default: + /* op = 0, src off, sink off */ + /* op = 0, src off, sink on */ + /* op = 0, src on, sink off */ + /* op = 1, src off, sink off */ + /* op = 1, src off, sink on */ + /* op = 1, src on, sink on */ + mask_set_reg(reg, mask, newval); + } + change_bit(sink, widget_pm_array[src].sink_list); + change_bit(src, widget_pm_array[sink].source_list); +end: + mutex_unlock(&ab3550_pm_mutex); + return ret; +}; + +static enum enum_widget apga_source_translate(u8 reg_value) +{ + switch (reg_value) { + case 1: + return widget_mic1; + case 2: + return widget_mic2; + default: + return number_of_widgets; + } +} + +static enum enum_widget adder_sink_translate(u8 reg) +{ + switch (reg) { + case EAR_ADDER: + return widget_ear; + case AUXO1_ADDER: + return widget_auxo1; + case AUXO2_ADDER: + return widget_auxo2; + case SPKR_ADDER: + return widget_spkr; + case LINE1_ADDER: + return widget_line1; + case LINE2_ADDER: + return widget_line2; + case APGA1_ADDER: + return widget_apga1; + case APGA2_ADDER: + return widget_apga2; + default: + return number_of_widgets; + } +} + +static int ab3550_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(&codec->dapm, ab3550_dapm_widgets, + ARRAY_SIZE(ab3550_dapm_widgets)); + + snd_soc_dapm_add_routes(&codec->dapm, intercon, ARRAY_SIZE(intercon)); + + snd_soc_dapm_new_widgets(&codec->dapm); + return 0; +} + +static void power_for_playback(enum enum_power onoff, int ifsel) +{ + dev_dbg(ab3550_dev, "%s: interface %d power %s.\n", __func__, + ifsel, onoff == POWER_ON ? "on" : "off"); + + if (mutex_lock_interruptible(&ab3550_pm_mutex)) { + dev_warn(ab3550_dev, + "%s: Signal received while waiting on the PM mutex.\n", + __func__); + return; + } + power_widget_unlocked(onoff, ifsel == 0 ? + widget_if0_dld_l : widget_if1_dld_l); + power_widget_unlocked(onoff, ifsel == 0 ? + widget_if0_dld_r : widget_if1_dld_r); + mutex_unlock(&ab3550_pm_mutex); +} + +static void power_for_capture(enum enum_power onoff, int ifsel) +{ + dev_dbg(ab3550_dev, "%s: interface %d power %s", __func__, + ifsel, onoff == POWER_ON ? "on" : "off"); + if (mutex_lock_interruptible(&ab3550_pm_mutex)) { + dev_warn(ab3550_dev, + "%s: Signal received while waiting on the PM mutex.\n", + __func__); + return; + } + power_widget_unlocked(onoff, ifsel == 0 ? + widget_if0_uld_l : widget_if1_uld_l); + power_widget_unlocked(onoff, ifsel == 0 ? + widget_if0_uld_r : widget_if1_uld_r); + mutex_unlock(&ab3550_pm_mutex); +} + +static int ab3550_add_controls(struct snd_soc_codec *codec) +{ + int err = 0, i, n = ARRAY_SIZE(ab3550_snd_controls); + + pr_debug("%s: %s called.\n", __FILE__, __func__); + for (i = 0; i < n; i++) { + err = snd_ctl_add(codec->card->snd_card, snd_ctl_new1( + &ab3550_snd_controls[i], codec)); + if (err < 0) { + pr_err("%s failed to add control No.%d of %d.\n", + __func__, i, n); + return err; + } + } + return err; +} + +static int ab3550_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params, + struct snd_soc_dai *dai) +{ + u8 val; + u8 reg = dai->id == 0 ? INTERFACE0 : INTERFACE1; + + if (!ab3550_dev) { + pr_err("%s: The AB3550 codec driver not initialized.\n", + __func__); + return -EAGAIN; + } + dev_info(ab3550_dev, "%s called.\n", __func__); + switch (params_rate(hw_params)) { + case 8000: + val = I2Sx_SR_8000Hz; + break; + case 16000: + val = I2Sx_SR_16000Hz; + break; + case 44100: + val = I2Sx_SR_44100Hz; + break; + case 48000: + val = I2Sx_SR_48000Hz; + break; + default: + return -EINVAL; + } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + !dai->capture_active : !dai->playback_active) { + + mask_set_reg(reg, I2Sx_SR_MASK, val << I2Sx_SR_SHIFT); + if ((read_reg(reg) & I2Sx_MODE_MASK) == 0) { + mask_set_reg(reg, MASTER_GENx_PWR_MASK, + 1 << MASTER_GENx_PWR_SHIFT); + } + } + return 0; +} + +static int ab3550_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + dai->playback_active : dai->capture_active) { + + dev_err(ab3550_dev, "%s: A %s stream is already active.\n", + __func__, + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + "PLAYBACK" : "CAPTURE"); + return -EBUSY; + } + return 0; +} +static int ab3550_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + dev_info(ab3550_dev, "%s called.\n", __func__); + + /* Configure registers for either playback or capture */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + power_for_playback(POWER_ON, dai->id); + dump_registers(__func__, + dai->id == 0 ? INTERFACE0 : INTERFACE1, + RX1, RX2, SPKR, EAR, -1); + } else { + power_for_capture(POWER_ON, dai->id); + dump_registers(__func__, MIC_BIAS1, MIC_BIAS2, MIC1_GAIN, TX1, + dai->id == 0 ? INTERFACE0 : INTERFACE1, -1); + } + return 0; +} + +static void ab3550_pcm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + u8 iface = dai->id == 0 ? INTERFACE0 : INTERFACE1; + dev_info(ab3550_dev, "%s called.\n", __func__); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + power_for_playback(POWER_OFF, dai->id); + else + power_for_capture(POWER_OFF, dai->id); + if (!dai->playback_active && !dai->capture_active && + (read_reg(iface) & I2Sx_MODE_MASK) == 0) + mask_set_reg(iface, MASTER_GENx_PWR_MASK, 0); +} + +static int ab3550_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + return 0; +} + +static int ab3550_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + u8 iface = (codec_dai->id == 0) ? INTERFACE0 : INTERFACE1; + u8 val = 0; + dev_info(ab3550_dev, "%s called.\n", __func__); + + switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK | + SND_SOC_DAIFMT_MASTER_MASK)) { + + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: + val |= 1 << I2Sx_MODE_SHIFT; + break; + + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: + break; + + default: + dev_warn(ab3550_dev, "AB3550_dai: unsupported DAI format " + "0x%x\n", fmt); + return -EINVAL; + } + if (codec_dai->playback_active && codec_dai->capture_active) { + if ((read_reg(iface) & I2Sx_MODE_MASK) == val) + return 0; + else { + dev_err(ab3550_dev, + "%s: DAI format set differently " + "by an existing stream.\n", __func__); + return -EINVAL; + } + } + mask_set_reg(iface, I2Sx_MODE_MASK, val); + return 0; +} + +struct snd_soc_dai_driver ab3550_dai_drv[] = { + { + .name = "ab3550-codec-dai.0", + .id = 0, + .playback = { + .stream_name = "AB3550.0 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = AB3550_SUPPORTED_RATE, + .formats = AB3550_SUPPORTED_FMT, + }, + .capture = { + .stream_name = "AB3550.0 Capture", + .channels_min = 2, + .channels_max = 2, + .rates = AB3550_SUPPORTED_RATE, + .formats = AB3550_SUPPORTED_FMT, + }, + .ops = (struct snd_soc_dai_ops[]) { + { + .startup = ab3550_pcm_startup, + .prepare = ab3550_pcm_prepare, + .hw_params = ab3550_pcm_hw_params, + .shutdown = ab3550_pcm_shutdown, + .set_sysclk = ab3550_set_dai_sysclk, + .set_fmt = ab3550_set_dai_fmt, + } + }, + .symmetric_rates = 1, + }, + { + .name = "ab3550-codec-dai.1", + .id = 1, + .playback = { + .stream_name = "AB3550.1 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = AB3550_SUPPORTED_RATE, + .formats = AB3550_SUPPORTED_FMT, + }, + .capture = { + .stream_name = "AB3550.0 Capture", + .channels_min = 2, + .channels_max = 2, + .rates = AB3550_SUPPORTED_RATE, + .formats = AB3550_SUPPORTED_FMT, + }, + .ops = (struct snd_soc_dai_ops[]) { + { + .startup = ab3550_pcm_startup, + .prepare = ab3550_pcm_prepare, + .hw_params = ab3550_pcm_hw_params, + .shutdown = ab3550_pcm_shutdown, + .set_sysclk = ab3550_set_dai_sysclk, + .set_fmt = ab3550_set_dai_fmt, + } + }, + .symmetric_rates = 1, + } +}; +EXPORT_SYMBOL_GPL(ab3550_dai_drv); + +static int ab3550_codec_probe(struct snd_soc_codec *codec) +{ + int ret; + + pr_info("%s: Enter.\n", __func__); + + /* Add controls */ + if (ab3550_add_controls(codec) < 0) + return ret; + + /* Add widgets */ + ab3550_add_widgets(codec); + + return 0; +} + +static int ab3550_codec_remove(struct snd_soc_codec *codec) +{ + snd_soc_dapm_free(&codec->dapm); + + return 0; +} + +#ifdef CONFIG_PM +static int ab3550_codec_suspend(struct snd_soc_codec *codec, pm_message_t state) +{ + mask_set_reg(CLOCK, CLOCK_ENABLE_MASK, 0); + + return 0; +} + +static int ab3550_codec_resume(struct snd_soc_codec *codec) +{ + mask_set_reg(CLOCK, CLOCK_ENABLE_MASK, 0xff); + + return 0; +} +#else +#define ab3550_codec_resume NULL +#define ab3550_codec_suspend NULL +#endif + +/* + * This function is only called by the SOC framework to + * set registers associated to the mixer controls. + */ +static int ab3550_codec_write_reg(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + if (reg < MIC_BIAS1 || reg > INTERFACE_SWAP) + return -EINVAL; + switch (reg) { + u8 diff, oldval; + case ANALOG_LOOP_PGA1: + case ANALOG_LOOP_PGA2: { + enum enum_widget apga = reg == ANALOG_LOOP_PGA1 ? + widget_apga1 : widget_apga2; + + oldval = read_reg(reg); + diff = value ^ oldval; + + /* The APGA is to be turned on/off. + * The power bit and the other bits in the + * same register won't be changed at the same time + * since they belong to different controls. + */ + if (diff & (1 << APGAx_PWR_SHIFT)) { + power_widget_locked(value >> APGAx_PWR_SHIFT & 1, + apga); + } else if (diff & APGAx_MUX_MASK) { + enum enum_widget old_source = + apga_source_translate(oldval); + enum enum_widget new_source = + apga_source_translate(value); + update_widgets_link(UNLINK, old_source, apga, + reg, APGAx_MUX_MASK, 0); + update_widgets_link(LINK, new_source, apga, + reg, APGAx_MUX_MASK, value); + } else { + set_reg(reg, value); + } + break; + } + + case APGA1_ADDER: + case APGA2_ADDER: { + int i; + enum enum_widget apga; + enum enum_widget apga_dst[] = { + widget_auxo2, widget_auxo1, widget_ear, widget_spkr, + widget_line2, widget_line1 + }; + + apga = adder_sink_translate(reg); + oldval = read_reg(reg); + diff = value ^ oldval; + for (i = 0; diff; i++) { + if (!(diff & 1 << i)) + continue; + diff ^= 1 << i; + update_widgets_link(value >> i & 1, apga, apga_dst[i], + reg, 1 << i, value); + } + break; + } + + case EAR_ADDER: + case AUXO1_ADDER: + case AUXO2_ADDER: + case SPKR_ADDER: + case LINE1_ADDER: + case LINE2_ADDER: { + int i; + enum enum_widget widgets[] = { + widget_dac1, widget_dac2, widget_dac3, + }; + oldval = read_reg(reg); + diff = value ^ oldval; + for (i = 0; diff; i++) { + if (!(diff & 1 << i)) + continue; + diff ^= 1 << i; + update_widgets_link(value >> i & 1, widgets[i], + adder_sink_translate(reg), + reg, 1 << i, value); + } + break; + } + + default: + set_reg(reg, value); + } + return 0; +} + +static unsigned int ab3550_codec_read_reg(struct snd_soc_codec *codec, + unsigned int reg) +{ + return read_reg(reg); +} + +static struct snd_soc_codec_driver ab3550_codec_drv = { + .probe = ab3550_codec_probe, + .remove = ab3550_codec_remove, + .suspend = ab3550_codec_suspend, + .resume = ab3550_codec_resume, + .read = ab3550_codec_read_reg, + .write = ab3550_codec_write_reg, +}; +EXPORT_SYMBOL_GPL(ab3550_codec_drv); + +static inline void init_playback_route(void) +{ + update_widgets_link(LINK, widget_if0_dld_l, widget_rx1, 0, 0, 0); + update_widgets_link(LINK, widget_rx1, widget_dac1, 0, 0, 0); + update_widgets_link(LINK, widget_dac1, widget_spkr, + SPKR_ADDER, DAC1_TO_ADDER_MASK, 0xff); + + update_widgets_link(LINK, widget_if0_dld_r, widget_rx2, + RX2, RX2_IF_SELECT_MASK, 0); + update_widgets_link(LINK, widget_rx2, widget_dac2, 0, 0, 0); + update_widgets_link(LINK, widget_dac2, widget_ear, + EAR_ADDER, DAC2_TO_ADDER_MASK, 0xff); +} + +static inline void init_capture_route(void) +{ + update_widgets_link(LINK, widget_micbias2, widget_mic1p1, + 0, 0, 0); + update_widgets_link(LINK, widget_micbias2, widget_mic1n1, + 0, 0, 0); + update_widgets_link(LINK, widget_mic1p1, widget_mic1, + MIC1_INPUT_SELECT, MICxP1_SEL_MASK, 0xff); + update_widgets_link(LINK, widget_mic1n1, widget_mic1, + MIC1_INPUT_SELECT, MICxN1_SEL_MASK, 0xff); + update_widgets_link(LINK, widget_mic1, widget_adc1, + 0, 0, 0); + update_widgets_link(LINK, widget_adc1, widget_tx1, + 0, 0, 0); + update_widgets_link(LINK, widget_tx1, widget_if0_uld_l, + INTERFACE0_DATA, I2Sx_L_DATA_MASK, + I2Sx_L_DATA_TX1_MASK); + update_widgets_link(LINK, widget_tx1, widget_if0_uld_r, + INTERFACE0_DATA, I2Sx_R_DATA_MASK, + I2Sx_R_DATA_TX1_MASK); +} + +static inline void init_playback_gain(void) +{ + mask_set_reg(RX1_DIGITAL_PGA, RXx_PGA_GAIN_MASK, + 0x40 << RXx_PGA_GAIN_SHIFT); + mask_set_reg(RX2_DIGITAL_PGA, RXx_PGA_GAIN_MASK, + 0x40 << RXx_PGA_GAIN_SHIFT); + mask_set_reg(EAR, EAR_GAIN_MASK, 0x06 << EAR_GAIN_SHIFT); + mask_set_reg(SPKR, SPKR_GAIN_MASK, 0x6 << SPKR_GAIN_SHIFT); +} + +static inline void init_capture_gain(void) +{ + mask_set_reg(MIC1_GAIN, MICx_GAIN_MASK, 0x06 << MICx_GAIN_SHIFT); + mask_set_reg(TX_DIGITAL_PGA1, TXDPGAx_MASK, 0x0f << TXDPGAx_SHIFT); +} + +static __devinit int ab3550_codec_drv_probe(struct platform_device *pdev) +{ + struct ab3550_codec_dai_data *codec_drvdata; + int ret = 0; + u8 reg; + + pr_debug("%s: Enter.\n", __func__); + + pr_info("%s: Init codec private data.\n", __func__); + codec_drvdata = kzalloc(sizeof(struct ab3550_codec_dai_data), GFP_KERNEL); + if (codec_drvdata == NULL) + return -ENOMEM; + + /* TODO: Add private data to codec_drvdata */ + + platform_set_drvdata(pdev, codec_drvdata); + + pr_info("%s: Register codec.\n", __func__); + ret = snd_soc_register_codec(&pdev->dev, &ab3550_codec_drv, &ab3550_dai_drv[0], 2); + if (ret < 0) { + pr_debug("%s: Error: Failed to register codec (ret = %d).\n", + __func__, + ret); + snd_soc_unregister_codec(&pdev->dev); + kfree(platform_get_drvdata(pdev)); + return ret; + } + + ab3550_dev = &pdev->dev; + /* Initialize the codec registers */ + for (reg = AB3550_FIRST_REG; reg <= AB3550_LAST_REG; reg++) + set_reg(reg, 0); + + mask_set_reg(CLOCK, CLOCK_REF_SELECT_MASK | CLOCK_ENABLE_MASK, + 1 << CLOCK_REF_SELECT_SHIFT | 1 << CLOCK_ENABLE_SHIFT); + init_playback_route(); + init_playback_gain(); + init_capture_route(); + init_capture_gain(); + memset(&pm_stack, 0, sizeof(pm_stack)); + + return 0; +} + +static int __devexit ab3550_codec_drv_remove(struct platform_device *pdev) +{ + mask_set_reg(CLOCK, CLOCK_ENABLE_MASK, 0); + + ab3550_dev = NULL; + + snd_soc_unregister_codec(&pdev->dev); + kfree(platform_get_drvdata(pdev)); + + return 0; +} + +static int ab3550_codec_drv_suspend(struct platform_device *pdev, + pm_message_t state) +{ + return 0; +} + +static int ab3550_codec_drv_resume(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver ab3550_codec_platform_drv = { + .driver = { + .name = "ab3550-codec", + .owner = THIS_MODULE, + }, + .probe = ab3550_codec_drv_probe, + .remove = __devexit_p(ab3550_codec_drv_remove), + .suspend = ab3550_codec_drv_suspend, + .resume = ab3550_codec_drv_resume, +}; + + +static int __devinit ab3550_codec_platform_drv_init(void) +{ + int ret; + + pr_debug("%s: Enter.\n", __func__); + + ab3550_dev = NULL; + + ret = platform_driver_register(&ab3550_codec_platform_drv); + if (ret != 0) + pr_err("Failed to register AB3550 platform driver (%d)!\n", ret); + + return ret; +} + +static void __exit ab3550_codec_platform_drv_exit(void) +{ + pr_debug("%s: Enter.\n", __func__); + + platform_driver_unregister(&ab3550_codec_platform_drv); +} + + +module_init(ab3550_codec_platform_drv_init); +module_exit(ab3550_codec_platform_drv_exit); + +MODULE_DESCRIPTION("AB3550 Codec driver"); +MODULE_AUTHOR("Xie Xiaolei <xie.xiaolei@stericsson.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/ab3550.h b/sound/soc/codecs/ab3550.h new file mode 100644 index 00000000000..fe9c77b1a62 --- /dev/null +++ b/sound/soc/codecs/ab3550.h @@ -0,0 +1,333 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Xie Xiaolei <xie.xiaolei@etericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ +#ifndef AB3550_CODEC_REGISTERS_H +#define AB3550_CODEC_REGISTERS_H + +#define AB3550_SUPPORTED_RATE (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) + +#define AB3550_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +/* MIC BIAS */ + +#define MIC_BIAS1 0X31 +#define MIC_BIAS2 0X32 +#define MBIAS2_OUT_V_MASK 0x04 +#define MBIAS2_OUT_V_SHIFT 2 +#define MBIAS_PWR_MASK 0x02 +#define MBIAS_PWR_SHIFT 1 +#define MBIAS_PDN_IMP_MASK 0x01 +#define MBIAS_PDN_IMP_SHIFT 0 + +#define MIC_BIAS2_VAD 0x33 +#define MBIAS2_R_INT_MASK 0x01 +#define MBIAS2_R_INT_SHIFT 0 + +/* MIC */ +#define MIC1_GAIN 0x34 +#define MIC2_GAIN 0x35 +#define MICx_GAIN_MASK 0xF0 +#define MICx_GAIN_SHIFT 4 +#define MICx_IN_IMP_MASK 0x0C +#define MICx_IN_IMP_SHIFT 2 +#define MICx_PWR_MASK 0x01 +#define MICx_PWR_SHIFT 0 + +#define MIC1_INPUT_SELECT 0x36 +#define MIC2_INPUT_SELECT 0x37 +#define MICxP1_SEL_MASK 0x80 +#define MICxP1_SEL_SHIFT 7 +#define MICxN1_SEL_MASK 0x40 +#define MICxN1_SEL_SHIFT 6 +#define MICxP2_SEL_MASK 0x20 +#define MICxP2_SEL_SHIFT 5 +#define MICxN2_SEL_MASK 0x10 +#define MICxN2_SEL_SHIFT 4 +#define LINEIN_SEL_MASK 0x03 +#define LINEIN_SEL_SHIFT 0 + +#define MIC1_VMID_SELECT 0x38 +#define MIC2_VMID_SELECT 0x39 +#define VMIDx_ENABLE_MASK 0xC0 +#define VMIDx_ENABLE_SHIFT 6 +#define VMIDx_LINEIN1_N_MASK 0x20 +#define VMIDx_LINEIN1_N_SHIFT 5 +#define VMIDx_LINEIN2_N_MASK 0x10 +#define VMIDx_LINEIN2_N_SHIFT 4 +#define VMIDx_MICxP1_MASK 0x08 +#define VMIDx_MICxP1_SHIFT 3 +#define VMIDx_MICxP2_MASK 0x04 +#define VMIDx_MICxP2_SHIFT 2 +#define VMIDx_MICxN1_MASK 0x02 +#define VMIDx_MICxN1_SHIFT 1 +#define VMIDx_MICxN2_MASK 0x01 +#define VMIDx_MICxN2_SHIFT 0 + +#define MIC2_TO_MIC1 0x3A +#define MIC2_TO_MIC1_MASK 0x03 +#define MIC2_TO_MIC1_SHIFT 0 + +/* Analog Loop */ +#define ANALOG_LOOP_PGA1 0x3B +#define ANALOG_LOOP_PGA2 0x3C +#define APGAx_GAIN_MASK 0xF8 +#define APGAx_GAIN_SHIFT 3 +#define APGAx_PWR_MASK 0x04 +#define APGAx_PWR_SHIFT 2 +#define APGAx_MUX_MASK 0x03 +#define APGAx_MUX_SHIFT 0 +#define APGAx_MUX_MIC1_MASK 0x01 +#define APGAx_MUX_MIC1_SHIFT 0 +#define APGAx_MUX_MIC2_MASK 0x02 +#define APGAx_MUX_MIC2_SHIFT 1 + + +#define APGA_VMID_SELECT 0x3D +#define VMID_APGA1_ENABLE_MASK 0xC0 +#define VMID_APGA1_ENABLE_SHIFT 6 +#define VMID_APGA1_LINEIN1_MASK 0x20 +#define VMID_APGA1_LINEIN1_SHIFT 5 +#define VMID_APGA2_ENABLE_MASK 0x0C +#define VMID_APGA2_ENABLE_SHIFT 2 +#define VMID_APGA2_LINEIN2_MASK 0x02 +#define VMID_APGA2_LINEIN2_SHIFT 1 + +/* Output Amplifiers */ +#define EAR 0x3E +#define EAR_PWR_MODE_MASK 0x20 +#define EAR_PWR_MODE_SHIFT 5 +#define EAR_PWR_MASK 0x10 +#define EAR_PWR_SHIFT 4 +#define EAR_GAIN_MASK 0x0F +#define EAR_GAIN_SHIFT 0 + +#define AUXO1 0x3F +#define AUXO2 0x40 +#define AUXOx_PWR_MASK 0x80 +#define AUXOx_PWR_SHIFT 7 +#define AUXOx_INV_MASK 0x40 +#define AUXOx_INV_SHIFT 6 +#define AUXOx_PULLDOWN_MASK 0x20 +#define AUXOx_PULLDOWN_SHIFT 5 +#define AUXOx_GAIN_MASK 0x0F +#define AUXOx_GAIN_SHIFT 0 + +#define AUXO_PWR_MODE 0x41 +#define AUT_PWR_MODE_MASK 0x04 +#define AUT_PWR_MODE_SHIFT 2 +#define AUXO_PWR_MODE_MASK 0x03 +#define AUXO_PWR_MODE_SHIFT 0 + +#define OFFSET_CANCEL 0x42 +#define SPKR_OFF_CANC_MASK 0x04 +#define SPKR_OFF_CANC_SHIFT 2 +#define AUXO_OFF_CANC_MASK 0x02 +#define AUXO_OFF_CANC_SHIFT 1 +#define OFFSET_CLOCK_MASK 0x01 +#define OFFSET_CLOCK_SHIFT 0 + +#define SPKR 0x43 +#define OVR_CURR_PROT_MASK 0x80 +#define OVR_CURR_PROT_SHIFT 7 +#define SPKR_PWR_MASK 0x40 +#define SPKR_PWR_SHIFT 6 +#define SPKR_GAIN_MASK 0x1F +#define SPKR_GAIN_SHIFT 0 + +#define LINE1 0x44 +#define LINE2 0x45 +#define LINEx_PWR_MASK 0x80 +#define LINEx_PWR_SHIFT 7 +#define LINEx_INV_MASK 0x40 +#define LINEx_INV_SHIFT 6 +#define VMID_BUFFx_MASK 0x10 +#define VMID_BUFFx_SHIFT 4 +#define LINEx_GAIN_MASK 0x0F +#define LINEx_GAIN_SHIFT 0 + +/* Analog loop Routing */ + +#define APGA1_ADDER 0x46 +#define APGA2_ADDER 0x47 +#define APGAx_TO_LINE1_MASK 0x20 +#define APGAx_TO_LINE1_SHIFT 0x5F +#define APGAx_TO_LINE2_MASK 0x10 +#define APGAx_TO_LINE2_SHIFT 4 +#define APGAx_TO_SPKR_MASK 0x08 +#define APGAx_TO_SPKR_SHIFT 3 +#define APGAx_TO_EAR_MASK 0x04 +#define APGAx_TO_EAR_SHIFT 2 +#define APGAx_TO_AUXO1_MASK 0x02 +#define APGAx_TO_AUXO1_SHIFT 1 +#define APGAx_TO_AUXO2_MASK 0x01 +#define APGAx_TO_AUXO2_SHIFT 0 +#define APGAx_ADDER_VALID_BITS_MASK 0x3F + +/* Output Amplifiers Routing */ + +#define EAR_ADDER 0x48 +#define AUXO1_ADDER 0x49 +#define AUXO2_ADDER 0x4A +#define SPKR_ADDER 0x4B +#define LINE1_ADDER 0x4C +#define LINE2_ADDER 0x4D +#define DAC3_TO_ADDER_MASK 0x04 +#define DAC3_TO_ADDER_SHIFT 2 +#define DAC2_TO_ADDER_MASK 0x02 +#define DAC2_TO_ADDER_SHIFT 1 +#define DAC1_TO_ADDER_MASK 0x01 +#define DAC1_TO_ADDER_SHIFT 0 + +#define EAR_TO_MIC2 0x4E +#define EAR_TO_MIC2_MASK 0x01 +#define EAR_TO_MIC2_SHIFT 0 + +#define SPKR_TO_MIC2 0x4F +#define SPKR_TO_MIC2_MASK 0x01 +#define SPKR_TO_MIC2_SHIFT 0 + +#define NEGATIVE_CHARGE_PUMP 0x50 +#define NCP_MODE_MASK 0x02 +#define NCP_MODE_SHIFT 1 +#define NCP_PWR_MASK 0x01 +#define NCP_PWR_SHIFT 0 + +#define TX1 0x51 +#define TX2 0x52 +#define TXx_HP_FILTER_MASK 0x0C +#define TXx_HP_FILTER_SHIFT 2 +#define TXx_PWR_MASK 0x02 +#define TXx_PWR_SHIFT 1 +#define ADCx_PWR_MASK 0x01 +#define ADCx_PWR_SHIFT 0 + +#define RX1 0x53 +#define RX2 0x54 +#define RX2_IF_SELECT_MASK 0x10 +#define RX2_IF_SELECT_SHIFT 4 +#define RX3 0x55 +#define RXx_PWR_MASK 0x08 +#define RXx_PWR_SHIFT 3 +#define DACx_PWR_MASK 0x04 +#define DACx_PWR_SHIFT 2 +#define DACx_PWR_MODE_MASK 0x03 +#define DACx_PWR_MODE_SHIFT 0 + +#define TX_DIGITAL_PGA1 0X56 +#define TX_DIGITAL_PGA2 0X57 +#define TXDPGAx_MASK 0x0F +#define TXDPGAx_SHIFT 0 + +#define RX1_DIGITAL_PGA 0x58 +#define RX2_DIGITAL_PGA 0x59 +#define RX3_DIGITAL_PGA 0x5A +#define RXx_PGA_GAIN_MASK 0x7F +#define RXx_PGA_GAIN_SHIFT 0 + +#define SIDETONE1_PGA 0x5B +#define SIDETONE2_PGA 0x5C +#define STx_HP_FILTER_MASK 0x60 +#define STx_HP_FILTER_SHIFT 5 +#define STx_MUX_MASK 0x10 +#define STx_MUX_SHIFT 4 +#define STx_PGA_MASK 0x0F +#define STx_PGA_SHIFT 0 + +/* clock */ + +#define CLOCK 0x5D +#define CLOCK_REF_SELECT_MASK 0x02 +#define CLOCK_REF_SELECT_SHIFT 1 +#define CLOCK_ENABLE_MASK 0x01 +#define CLOCK_ENABLE_SHIFT 0 + +/* Interface */ + +#define INTERFACE0 0x5E +#define INTERFACE1 0x60 +#define I2Sx_WORDLENGTH_MASK 0x40 +#define I2Sx_WORDLENGTH_SHIFT 6 +#define MASTER_GENx_PWR_MASK 0x20 +#define MASTER_GENx_PWR_SHIFT 5 +#define I2Sx_MODE_MASK 0x10 +#define I2Sx_MODE_SHIFT 4 +#define I2Sx_TRISTATE_MASK 0x08 +#define I2Sx_TRISTATE_SHIFT 3 +#define I2Sx_PULLDOWN_MASK 0x04 +#define I2Sx_PULLDOWN_SHIFT 2 +#define I2Sx_SR_MASK 0x03 +#define I2Sx_SR_SHIFT 0 +#define I2Sx_SR_8000Hz 0 +#define I2Sx_SR_16000Hz 1 +#define I2Sx_SR_44100Hz 2 +#define I2Sx_SR_48000Hz 3 + +#define INTERFACE0_DATA 0x5F +#define INTERFACE1_DATA 0x61 +#define I2Sx_L_DATA_MASK 0x0C +#define I2Sx_L_DATA_TX1_MASK 0x04 +#define I2Sx_L_DATA_TX2_MASK 0x08 +#define I2Sx_L_DATA_SHIFT 2 +#define I2Sx_R_DATA_MASK 0x03 +#define I2Sx_R_DATA_TX1_MASK 0x01 +#define I2Sx_R_DATA_TX2_MASK 0x02 +#define I2Sx_R_DATA_SHIFT 0 + +#define INTERFACE_LOOP 0x62 +#define I2S0_INT_LOOP_MASK 0x08 +#define I2S0_INT_LOOP_SHIFT 3 +#define I2S0_EXT_LOOP_MASK 0x04 +#define I2S0_EXT_LOOP_SHIFT 2 +#define I2S1_INT_LOOP_MASK 0x02 +#define I2S1_INT_LOOP_SHIFT 1 +#define I2S1_EXT_LOOP_MASK 0x01 +#define I2S1_EXT_LOOP_SHIFT 0 + +#define INTERFACE_SWAP 0x63 +#define RX_SWAP0_MASK 0x10 +#define RX_SWAP0_SHIFT 4 +#define RX_SWAP1_MASK 0x08 +#define RX_SWAP1_SHIFT 3 +#define IF_SWAP_MASK 0x04 +#define IF_SWAP_SHIFT 2 +#define IO_SWAP0_MASK 0x02 +#define IO_SWAP0_SHIFT 1 +#define IO_SWAP1_MASK 0x01 +#define IO_SWAP1_SHIFT 0 + +#define AB3550_FIRST_REG MIC_BIAS1 +#define AB3550_LAST_REG INTERFACE_SWAP + +#define AB3550_VIRTUAL_REG1 (AB3550_LAST_REG + 1) +#define IF0_DLD_L_PW_SHIFT 0 +#define IF0_DLD_R_PW_SHIFT 1 +#define IF0_ULD_L_PW_SHIFT 2 +#define IF0_ULD_R_PW_SHIFT 3 +#define IF1_DLD_L_PW_SHIFT 4 +#define IF1_DLD_R_PW_SHIFT 5 +#define IF1_ULD_L_PW_SHIFT 6 +#define IF1_ULD_R_PW_SHIFT 7 + +#define AB3550_VIRTUAL_REG2 (AB3550_LAST_REG + 2) +#define MIC1P1_PW_SHIFT 0 +#define MIC1N1_PW_SHIFT 1 +#define MIC1P2_PW_SHIFT 2 +#define MIC1N2_PW_SHIFT 3 +#define MIC2P1_PW_SHIFT 4 +#define MIC2N1_PW_SHIFT 5 +#define MIC2P2_PW_SHIFT 6 +#define MIC2N2_PW_SHIFT 7 + + +#endif diff --git a/sound/soc/codecs/ab5500.c b/sound/soc/codecs/ab5500.c new file mode 100644 index 00000000000..1875db4fc77 --- /dev/null +++ b/sound/soc/codecs/ab5500.c @@ -0,0 +1,1691 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Author: Xie Xiaolei <xie.xiaolei@etericsson.com>, + * Ola Lilja <ola.o.lilja@stericsson.com>, + * Roger Nilsson <roger.xr.nilsson@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <linux/mfd/abx500.h> +#include <linux/bitmap.h> +#include <linux/bitops.h> +#include <asm/atomic.h> +#include <linux/rwsem.h> +#include <linux/mutex.h> +#include <stdarg.h> +#include "ab5500.h" + +/* No of digital interface on the Codec */ +#define NO_CODEC_DAI_IF 2 + +/* codec private data */ +struct ab5500_codec_dai_data { + bool playback_active; + bool capture_active; + +}; + +static struct device *ab5500_dev; + +static u8 virtual_regs[] = { + 0, 0, 0, 0, 0 +}; + +#define set_reg(reg, val) mask_set_reg((reg), 0xff, (val)) + +static void mask_set_reg(u8 reg, u8 mask, u8 val) +{ + u8 newval = mask & val; + u8 oldval, diff; + + if (!ab5500_dev) { + pr_err("%s: The AB5500 codec driver not initialized.\n", + __func__); + return; + } + /* Check if the reg value falls within the + * range of AB5500 real registers. If + * so, set the mask */ + if (reg < AB5500_FIRST_REG) + return; + if (reg <= AB5500_LAST_REG) { + abx500_mask_and_set_register_interruptible( + ab5500_dev, AB5500_BANK_AUDIO_HEADSETUSB, + reg, mask, val); + return; + } + if (reg - AB5500_LAST_REG - 1 >= ARRAY_SIZE(virtual_regs)) + return; + + /* treatment of virtual registers follows */ + /*Compute the difference between the new value and the old value. + *1.If there is no difference, do nothing. + *2.If the difference is in the PWR_SHIFT, + *set the PWR masks appropriately. + */ + oldval = virtual_regs[reg - AB5500_LAST_REG - 1]; + diff = (val ^ oldval) & mask; + if (!diff) + return; + + switch (reg) { + case AB5500_VIRTUAL_REG3: + if ((diff & (1 << SPKR1_PWR_SHIFT))) { + if ((val & (1 << SPKR1_PWR_SHIFT)) == 0) { + /* + * If the new value has PWR_SHIFT + * disabled, set the + * PWR_MASK to 0 + */ + mask_set_reg(SPKR1, SPKRx_PWR_MASK, 0); + } + else { + /* Else, set the PWR_MASK values based on the old value. */ + switch (oldval & SPKR1_MODE_MASK) { + case 0: + mask_set_reg(SPKR1, SPKRx_PWR_MASK, + SPKRx_PWR_VBR_VALUE); + break; + case 1: + mask_set_reg(SPKR1, SPKRx_PWR_MASK, + SPKRx_PWR_CLS_D_VALUE); + break; + case 2: + mask_set_reg(SPKR1, SPKRx_PWR_MASK, + SPKRx_PWR_CLS_AB_VALUE); + break; + } + } + } + if ((diff & (1 << SPKR2_PWR_SHIFT))) { + if ((val & (1 << SPKR2_PWR_SHIFT)) == 0) { + /* + * If the new value has PWR_SHIFT + * disabled, set the + * PWR_MASK to 0 + */ + mask_set_reg(SPKR2, SPKRx_PWR_MASK, 0); + } + else { + /* Else, set the PWR_MASK values based on the old value. */ + switch (oldval & SPKR2_MODE_MASK) { + case 0: + mask_set_reg(SPKR2, SPKRx_PWR_MASK, + SPKRx_PWR_VBR_VALUE); + break; + case 1: + mask_set_reg(SPKR2, SPKRx_PWR_MASK, + SPKRx_PWR_CLS_D_VALUE); + break; + } + } + } + + break; + case AB5500_VIRTUAL_REG4: + ; + /* configure PWMCTRL_SPKR1, PWMCTRL_SPKR2, etc. */ + } + virtual_regs[reg - AB5500_LAST_REG - 1] &= ~mask; + virtual_regs[reg - AB5500_LAST_REG - 1] |= newval; +} + +static u8 read_reg(u8 reg) +{ + if (!ab5500_dev) { + pr_err("%s: The AB5500 codec driver not initialized.\n", + __func__); + return 0; + } + /* Check if the reg value falls within the range of AB5500 real + * registers.If so, set the mask */ + if (reg < AB5500_FIRST_REG) + return 0; + else if (reg <= AB5500_LAST_REG) { + u8 val; + abx500_get_register_interruptible( + ab5500_dev, AB5500_BANK_AUDIO_HEADSETUSB, reg, &val); + return val; + } else if (reg - AB5500_LAST_REG - 1 < ARRAY_SIZE(virtual_regs)) + return virtual_regs[reg - AB5500_LAST_REG - 1]; + dev_warn(ab5500_dev, "%s: out-of-scope reigster %u.\n", + __func__, reg); + return 0; +} + +/* Components that can be powered up/down */ +enum enum_widget { + widget_ear = 0, + widget_auxo1, + widget_auxo2, + widget_auxo3, + widget_auxo4, + widget_spkr1, + widget_spkr2, + widget_spkr1_adder, + widget_spkr2_adder, + widget_pwm_spkr1, + widget_pwm_spkr2, + widget_pwm_spkr1n, + widget_pwm_spkr1p, + widget_pwm_spkr2n, + widget_pwm_spkr2p, + widget_line1, + widget_line2, + widget_dac1, + widget_dac2, + widget_dac3, + widget_rx1, + widget_rx2, + widget_rx3, + widget_mic1, + widget_mic2, + widget_micbias1, + widget_micbias2, + widget_apga1, + widget_apga2, + widget_tx1, + widget_tx2, + widget_adc1, + widget_adc2, + widget_if0_dld_l, + widget_if0_dld_r, + widget_if0_uld_l, + widget_if0_uld_r, + widget_if1_dld_l, + widget_if1_dld_r, + widget_if1_uld_l, + widget_if1_uld_r, + widget_mic1p1, + widget_mic1n1, + widget_mic1p2, + widget_mic1n2, + widget_mic2p1, + widget_mic2n1, + widget_mic2p2, + widget_mic2n2, + widget_clock, + number_of_widgets +}; + +/* This is only meant for debugging */ +static const char *widget_names[] = { + "EAR", "AUXO1", "AUXO2", "AUXO3", "AUXO4", + "SPKR1", "SPKR2", "SPKR1_ADDER", "SPKR2_ADDER", + "PWM_SPKR1", "PWM_SPKR2", + "PWM_SPKR1N", "PWM_SPKR1P", + "PWM_SPKR2N", "PWM_SPKR2P", + "LINE1", "LINE2", + "DAC1", "DAC2", "DAC3", + "RX1", "RX2", "RX3", + "MIC1", "MIC2", + "MIC-BIAS1", "MIC-BIAS2", + "APGA1", "APGA2", + "TX1", "TX2", + "ADC1", "ADC2", + "IF0-DLD-L", "IF0-DLD-R", "IF0-ULD-L", "IF0-ULD-R", + "IF1-DLD-L", "IF1-DLD-R", "IF1-ULD-L", "IF1-ULD-R", + "MIC1P1", "MIC1N1", "MIC1P2", "MIC1N2", + "MIC2P1", "MIC2N1", "MIC2P2", "MIC2N2", + "CLOCK" +}; + +struct widget_pm { + enum enum_widget widget; + u8 reg; + u8 shift; + + unsigned long source_list[BIT_WORD(number_of_widgets) + 1]; + unsigned long sink_list[BIT_WORD(number_of_widgets) + 1]; +}; + +static struct widget_pm widget_pm_array[] = { + {.widget = widget_ear, .reg = EAR_PWR, .shift = EAR_PWR_SHIFT}, + + {.widget = widget_auxo1, .reg = AUXO1, .shift = AUXOx_PWR_SHIFT}, + {.widget = widget_auxo2, .reg = AUXO2, .shift = AUXOx_PWR_SHIFT}, + {.widget = widget_auxo3, .reg = AUXO3, .shift = AUXOx_PWR_SHIFT}, + {.widget = widget_auxo4, .reg = AUXO4, .shift = AUXOx_PWR_SHIFT}, + + {.widget = widget_spkr1, .reg = AB5500_VIRTUAL_REG3, + .shift = SPKR1_PWR_SHIFT}, + {.widget = widget_spkr2, .reg = AB5500_VIRTUAL_REG3, + .shift = SPKR2_PWR_SHIFT}, + + {.widget = widget_spkr1_adder, .reg = AB5500_VIRTUAL_REG3, + .shift = SPKR1_ADDER_PWR_SHIFT}, + {.widget = widget_spkr2_adder, .reg = AB5500_VIRTUAL_REG3, + .shift = SPKR2_ADDER_PWR_SHIFT}, + + {.widget = widget_pwm_spkr1, .reg = AB5500_VIRTUAL_REG4, + .shift = PWM_SPKR1_PWR_SHIFT}, + {.widget = widget_pwm_spkr2, .reg = AB5500_VIRTUAL_REG4, + .shift = PWM_SPKR2_PWR_SHIFT}, + + {.widget = widget_pwm_spkr1n, .reg = AB5500_VIRTUAL_REG4, + .shift = PWM_SPKR1N_PWR_SHIFT}, + {.widget = widget_pwm_spkr1p, .reg = AB5500_VIRTUAL_REG4, + .shift = PWM_SPKR1P_PWR_SHIFT}, + + {.widget = widget_pwm_spkr2n, .reg = AB5500_VIRTUAL_REG4, + .shift = PWM_SPKR2N_PWR_SHIFT}, + {.widget = widget_pwm_spkr2p, .reg = AB5500_VIRTUAL_REG4, + .shift = PWM_SPKR2P_PWR_SHIFT}, + + + {.widget = widget_line1, .reg = LINE1, .shift = LINEx_PWR_SHIFT}, + {.widget = widget_line2, .reg = LINE2, .shift = LINEx_PWR_SHIFT}, + + {.widget = widget_dac1, .reg = RX1, .shift = DACx_PWR_SHIFT}, + {.widget = widget_dac2, .reg = RX2, .shift = DACx_PWR_SHIFT}, + {.widget = widget_dac3, .reg = RX3, .shift = DACx_PWR_SHIFT}, + + {.widget = widget_rx1, .reg = RX1, .shift = RXx_PWR_SHIFT}, + {.widget = widget_rx2, .reg = RX2, .shift = RXx_PWR_SHIFT}, + {.widget = widget_rx3, .reg = RX3, .shift = RXx_PWR_SHIFT}, + + {.widget = widget_mic1, .reg = MIC1_GAIN, .shift = MICx_PWR_SHIFT}, + {.widget = widget_mic2, .reg = MIC2_GAIN, .shift = MICx_PWR_SHIFT}, + + {.widget = widget_micbias1, .reg = MIC_BIAS1, + .shift = MBIASx_PWR_SHIFT}, + {.widget = widget_micbias2, .reg = MIC_BIAS2, + .shift = MBIASx_PWR_SHIFT}, + + {.widget = widget_apga1, .reg = ANALOG_LOOP_PGA1, + .shift = APGAx_PWR_SHIFT}, + {.widget = widget_apga2, .reg = ANALOG_LOOP_PGA2, + .shift = APGAx_PWR_SHIFT}, + + {.widget = widget_tx1, .reg = TX1, .shift = TXx_PWR_SHIFT}, + {.widget = widget_tx2, .reg = TX2, .shift = TXx_PWR_SHIFT}, + + {.widget = widget_adc1, .reg = TX1, .shift = ADCx_PWR_SHIFT}, + {.widget = widget_adc2, .reg = TX2, .shift = ADCx_PWR_SHIFT}, + + {.widget = widget_if0_dld_l, .reg = AB5500_VIRTUAL_REG1, + .shift = IF0_DLD_L_PW_SHIFT}, + {.widget = widget_if0_dld_r, .reg = AB5500_VIRTUAL_REG1, + .shift = IF0_DLD_R_PW_SHIFT}, + {.widget = widget_if0_uld_l, .reg = AB5500_VIRTUAL_REG1, + .shift = IF0_ULD_L_PW_SHIFT}, + {.widget = widget_if0_uld_r, .reg = AB5500_VIRTUAL_REG1, + .shift = IF0_ULD_R_PW_SHIFT}, + + {.widget = widget_if1_dld_l, .reg = AB5500_VIRTUAL_REG1, + .shift = IF1_DLD_L_PW_SHIFT}, + {.widget = widget_if1_dld_r, .reg = AB5500_VIRTUAL_REG1, + .shift = IF1_DLD_R_PW_SHIFT}, + {.widget = widget_if1_uld_l, .reg = AB5500_VIRTUAL_REG1, + .shift = IF1_ULD_L_PW_SHIFT}, + {.widget = widget_if1_uld_r, .reg = AB5500_VIRTUAL_REG1, + .shift = IF1_ULD_R_PW_SHIFT}, + + {.widget = widget_mic1p1, .reg = AB5500_VIRTUAL_REG2, + .shift = MIC1P1_PW_SHIFT}, + {.widget = widget_mic1n1, .reg = AB5500_VIRTUAL_REG2, + .shift = MIC1N1_PW_SHIFT}, + {.widget = widget_mic1p2, .reg = AB5500_VIRTUAL_REG2, + .shift = MIC1P2_PW_SHIFT}, + {.widget = widget_mic1n2, .reg = AB5500_VIRTUAL_REG2, + .shift = MIC1N2_PW_SHIFT}, + + {.widget = widget_mic2p1, .reg = AB5500_VIRTUAL_REG2, + .shift = MIC2P1_PW_SHIFT}, + {.widget = widget_mic2n1, .reg = AB5500_VIRTUAL_REG2, + .shift = MIC2N1_PW_SHIFT}, + {.widget = widget_mic2p2, .reg = AB5500_VIRTUAL_REG2, + .shift = MIC2P2_PW_SHIFT}, + {.widget = widget_mic2n2, .reg = AB5500_VIRTUAL_REG2, + .shift = MIC2N2_PW_SHIFT}, + + {.widget = widget_clock, .reg = CLOCK, .shift = CLOCK_ENABLE_SHIFT}, +}; + +DEFINE_MUTEX(ab5500_pm_mutex); + +static struct { + enum enum_widget stack[number_of_widgets]; + int p; +} pm_stack; + +#define pm_stack_as_bitmap ({ \ + unsigned long bitmap[BIT_WORD(number_of_widgets) + 1]; \ + int i; \ + memset(bitmap, 0, sizeof(bitmap)); \ + for (i = 0; i < pm_stack.p; i++) { \ + set_bit(pm_stack.stack[i], bitmap); \ + } \ + bitmap; \ + }) + +/* These are only meant to meet the obligations of DAPM */ +static const struct snd_soc_dapm_widget ab5500_dapm_widgets[] = { +}; + +static const struct snd_soc_dapm_route intercon[] = { +}; + + +struct ab5500_codec_dai_data ab5500_codec_privates[NO_CODEC_DAI_IF] = { + { + .playback_active = false, + .capture_active = false, + }, + { + .playback_active = false, + .capture_active = false, + } +}; + +static const char *enum_rx_input_select[] = { + "Mute", "TX1", "TX2", "I2S0_DLD_L", + "I2S0_DLD_R", "I2S1_DLD_L", "I2S1_DLD_R" +}; + +static const char *enum_i2s_uld_select[] = { + "Mute", "TX1", "TX2", "I2S0_DLD_L", + "I2S0_DLD_R", "I2S1_DLD_L", "I2S1_DLD_R", "tri-state" +}; +static const char *enum_apga1_source[] = {"LINEIN1", "MIC1", "MIC2", "None"}; +static const char *enum_apga2_source[] = {"LINEIN2", "MIC1", "MIC2", "None"}; +static const char *enum_rx_side_tone[] = {"TX1", "TX2"}; +static const char *enum_dac_power_mode[] = {"100%", "75%", "55%"}; +static const char *enum_ear_power_mode[] = {"100%", "70%", "50%"}; +static const char *enum_auxo_power_mode[] = { + "100%", "67%", "50%", "25%", "auto" +}; +static const char *enum_onoff[] = {"Off", "On"}; +static const char *enum_mbias_pdn_imp[] = {"GND", "HiZ"}; +static const char *enum_mbias2_out_v[] = {"2.0v", "2.2v"}; +static const char *enum_mic_in_imp[] = { + "12.5 kohm", "25 kohm", "50 kohm" +}; +static const char *enum_hp_filter[] = {"HP3", "HP1", "bypass"}; +static const char *enum_i2s_word_length[] = {"16 bits", "24 bits"}; +static const char *enum_i2s_mode[] = {"Master Mode", "Slave Mode"}; +static const char *enum_i2s_tristate[] = {"Normal", "Tri-state"}; +static const char *enum_optional_resistor[] = {"disconnected", "connected"}; +static const char *enum_i2s_sample_rate[] = { + "8 kHz", "16 kHz", "44.1 kHz", "48 kHz" +}; +static const char *enum_tx1_input_select[] = { + "ADC1", "DIGMIC1", "DIGMIC2" +}; +static const char *enum_tx2_input_select[] = { + "ADC2", "DIGMIC1", "DIGMIC2" +}; +static const char *enum_signal_inversion[] = {"normal", "inverted"}; +static const char *enum_spkr1_mode[] = { + "Vibra PWM", "class D amplifier", "class AB amplifier" +}; +static const char *enum_spkr2_mode[] = { + "Vibra PWM", "class D amplifier", +}; +static const char *enum_pwm_pol[] = { + "GND", "VDD" +}; +/* RX1 Input Select */ +static struct soc_enum soc_enum_rx1_in_sel = + SOC_ENUM_SINGLE(RX1, RXx_DATA_SHIFT, + ARRAY_SIZE(enum_rx_input_select), + enum_rx_input_select); + +/* RX2 Input Select */ +static struct soc_enum soc_enum_rx2_in_sel = + SOC_ENUM_SINGLE(RX2, RXx_DATA_SHIFT, + ARRAY_SIZE(enum_rx_input_select), + enum_rx_input_select); +/* RX3 Input Select */ +static struct soc_enum soc_enum_rx3_in_sel = + SOC_ENUM_SINGLE(RX3, RXx_DATA_SHIFT, + ARRAY_SIZE(enum_rx_input_select), + enum_rx_input_select); +/* TX1 Input Select */ +static struct soc_enum soc_enum_tx1_in_sel = + SOC_ENUM_SINGLE(TX1, TXx_MUX_SHIFT, + ARRAY_SIZE(enum_tx1_input_select), + enum_tx1_input_select); +/* TX2 Input Select */ +static struct soc_enum soc_enum_tx2_in_sel = + SOC_ENUM_SINGLE(TX2, TXx_MUX_SHIFT, + ARRAY_SIZE(enum_tx2_input_select), + enum_tx2_input_select); + +/* I2S0 ULD Select */ +static struct soc_enum soc_enum_i2s0_input_select = + SOC_ENUM_DOUBLE(INTERFACE0_ULD, 0, 4, + ARRAY_SIZE(enum_i2s_uld_select), + enum_i2s_uld_select); +/* I2S1 ULD Select */ +static struct soc_enum soc_enum_i2s1_input_select = + SOC_ENUM_DOUBLE(INTERFACE1_ULD, 0, 4, + ARRAY_SIZE(enum_i2s_uld_select), + enum_i2s_uld_select); + +/* APGA1 Source */ +static struct soc_enum soc_enum_apga1_source = + SOC_ENUM_SINGLE(ANALOG_LOOP_PGA1, APGAx_MUX_SHIFT, + ARRAY_SIZE(enum_apga1_source), + enum_apga1_source); + +/* APGA2 Source */ +static struct soc_enum soc_enum_apga2_source = + SOC_ENUM_SINGLE(ANALOG_LOOP_PGA2, APGAx_MUX_SHIFT, + ARRAY_SIZE(enum_apga2_source), + enum_apga2_source); + +static struct soc_enum soc_enum_apga1_enable = + SOC_ENUM_SINGLE(ANALOG_LOOP_PGA1, APGAx_PWR_SHIFT, + ARRAY_SIZE(enum_onoff), enum_onoff); + +static struct soc_enum soc_enum_apga2_enable = + SOC_ENUM_SINGLE(ANALOG_LOOP_PGA2, APGAx_PWR_SHIFT, + ARRAY_SIZE(enum_onoff), enum_onoff); + +/* RX1 Side Tone */ +static struct soc_enum soc_enum_dac1_side_tone = + SOC_ENUM_SINGLE(ST1_PGA, STx_MUX_SHIFT, + ARRAY_SIZE(enum_rx_side_tone), + enum_rx_side_tone); + +/* RX2 Side Tone */ +static struct soc_enum soc_enum_dac2_side_tone = + SOC_ENUM_SINGLE(ST2_PGA, STx_MUX_SHIFT, + ARRAY_SIZE(enum_rx_side_tone), + enum_rx_side_tone); + +/* DAC1 Power Mode */ +static struct soc_enum soc_enum_dac1_power_mode = + SOC_ENUM_SINGLE(RX1, DACx_PWR_MODE_SHIFT, + ARRAY_SIZE(enum_dac_power_mode), + enum_dac_power_mode); + +/* DAC2 Power Mode */ +static struct soc_enum soc_enum_dac2_power_mode = + SOC_ENUM_SINGLE(RX2, DACx_PWR_MODE_SHIFT, + ARRAY_SIZE(enum_dac_power_mode), + enum_dac_power_mode); + +/* DAC3 Power Mode */ +static struct soc_enum soc_enum_dac3_power_mode = + SOC_ENUM_SINGLE(RX3, DACx_PWR_MODE_SHIFT, + ARRAY_SIZE(enum_dac_power_mode), + enum_dac_power_mode); + +/* EAR Power Mode */ +static struct soc_enum soc_enum_ear_power_mode = + SOC_ENUM_SINGLE(EAR_PWR, EAR_PWR_MODE_SHIFT, + ARRAY_SIZE(enum_ear_power_mode), + enum_ear_power_mode); + +/* AUXO12 Power Mode */ +static struct soc_enum soc_enum_auxo12_power_mode = + SOC_ENUM_SINGLE(AUXO12_PWR_MODE, AUXOxy_PWR_MODE_SHIFT, + ARRAY_SIZE(enum_auxo_power_mode), + enum_auxo_power_mode); + +/* AUXO34 Power Mode */ +static struct soc_enum soc_enum_auxo34_power_mode = + SOC_ENUM_SINGLE(AUXO34_PWR_MODE, AUXOxy_PWR_MODE_SHIFT, + ARRAY_SIZE(enum_auxo_power_mode), + enum_auxo_power_mode); + +/* MBIAS1 PDN Impedance */ +static struct soc_enum soc_enum_mbias1_pdn_imp = + SOC_ENUM_SINGLE(MIC_BIAS1, MBIASx_PDN_IMP_SHIFT, + ARRAY_SIZE(enum_mbias_pdn_imp), + enum_mbias_pdn_imp); + +/* MBIAS2 PDN Impedance */ +static struct soc_enum soc_enum_mbias2_pdn_imp = + SOC_ENUM_SINGLE(MIC_BIAS2, MBIASx_PDN_IMP_SHIFT, + ARRAY_SIZE(enum_mbias_pdn_imp), + enum_mbias_pdn_imp); + +/* MBIAS2 Output voltage */ +static struct soc_enum soc_enum_mbias2_out_v = + SOC_ENUM_SINGLE(MIC_BIAS2, MBIAS2_OUT_V_SHIFT, + ARRAY_SIZE(enum_mbias2_out_v), + enum_mbias2_out_v); + +static struct soc_enum soc_enum_mbias2_int_r = + SOC_ENUM_SINGLE(MIC_BIAS2_VAD, MBIAS2_R_INT_SHIFT, + ARRAY_SIZE(enum_optional_resistor), + enum_optional_resistor); + +static struct soc_enum soc_enum_mic1_in_imp = + SOC_ENUM_SINGLE(MIC1_GAIN, MICx_IN_IMP_SHIFT, + ARRAY_SIZE(enum_mic_in_imp), + enum_mic_in_imp); + +static struct soc_enum soc_enum_mic2_in_imp = + SOC_ENUM_SINGLE(MIC2_GAIN, MICx_IN_IMP_SHIFT, + ARRAY_SIZE(enum_mic_in_imp), + enum_mic_in_imp); + +static struct soc_enum soc_enum_tx1_hp_filter = + SOC_ENUM_SINGLE(TX1, TXx_HP_FILTER_SHIFT, + ARRAY_SIZE(enum_hp_filter), + enum_hp_filter); + +static struct soc_enum soc_enum_tx2_hp_filter = + SOC_ENUM_SINGLE(TX2, TXx_HP_FILTER_SHIFT, + ARRAY_SIZE(enum_hp_filter), + enum_hp_filter); + +static struct soc_enum soc_enum_st1_hp_filter = + SOC_ENUM_SINGLE(ST1_PGA, STx_HP_FILTER_SHIFT, + ARRAY_SIZE(enum_hp_filter), + enum_hp_filter); + +static struct soc_enum soc_enum_st2_hp_filter = + SOC_ENUM_SINGLE(ST2_PGA, STx_HP_FILTER_SHIFT, + ARRAY_SIZE(enum_hp_filter), + enum_hp_filter); + +static struct soc_enum soc_enum_i2s0_word_length = + SOC_ENUM_SINGLE(INTERFACE0, I2Sx_WORDLENGTH_SHIFT, + ARRAY_SIZE(enum_i2s_word_length), + enum_i2s_word_length); + +static struct soc_enum soc_enum_i2s1_word_length = + SOC_ENUM_SINGLE(INTERFACE1, I2Sx_WORDLENGTH_SHIFT, + ARRAY_SIZE(enum_i2s_word_length), + enum_i2s_word_length); + +static struct soc_enum soc_enum_i2s0_mode = + SOC_ENUM_SINGLE(INTERFACE0, I2Sx_MODE_SHIFT, + ARRAY_SIZE(enum_i2s_mode), + enum_i2s_mode); + +static struct soc_enum soc_enum_i2s1_mode = + SOC_ENUM_SINGLE(INTERFACE1, I2Sx_MODE_SHIFT, + ARRAY_SIZE(enum_i2s_mode), + enum_i2s_mode); + +static struct soc_enum soc_enum_i2s0_tristate = + SOC_ENUM_SINGLE(INTERFACE0, I2Sx_TRISTATE_SHIFT, + ARRAY_SIZE(enum_i2s_tristate), + enum_i2s_tristate); + +static struct soc_enum soc_enum_i2s1_tristate = + SOC_ENUM_SINGLE(INTERFACE1, I2Sx_TRISTATE_SHIFT, + ARRAY_SIZE(enum_i2s_tristate), + enum_i2s_tristate); + +static struct soc_enum soc_enum_i2s0_pulldown_resistor = + SOC_ENUM_SINGLE(INTERFACE0, I2Sx_PULLDOWN_SHIFT, + ARRAY_SIZE(enum_optional_resistor), + enum_optional_resistor); + +static struct soc_enum soc_enum_i2s1_pulldown_resistor = + SOC_ENUM_SINGLE(INTERFACE1, I2Sx_PULLDOWN_SHIFT, + ARRAY_SIZE(enum_optional_resistor), + enum_optional_resistor); + +static struct soc_enum soc_enum_i2s0_sample_rate = + SOC_ENUM_SINGLE(INTERFACE0, I2Sx_SR_SHIFT, + ARRAY_SIZE(enum_i2s_sample_rate), + enum_i2s_sample_rate); + +static struct soc_enum soc_enum_i2s1_sample_rate = + SOC_ENUM_SINGLE(INTERFACE1, I2Sx_SR_SHIFT, + ARRAY_SIZE(enum_i2s_sample_rate), + enum_i2s_sample_rate); + +static struct soc_enum soc_enum_line1_inversion = + SOC_ENUM_SINGLE(LINE1, LINEx_INV_SHIFT, + ARRAY_SIZE(enum_signal_inversion), + enum_signal_inversion); + +static struct soc_enum soc_enum_line2_inversion = + SOC_ENUM_SINGLE(LINE2, LINEx_INV_SHIFT, + ARRAY_SIZE(enum_signal_inversion), + enum_signal_inversion); + +static struct soc_enum soc_enum_auxo1_inversion = + SOC_ENUM_SINGLE(AUXO1, AUXOx_INV_SHIFT, + ARRAY_SIZE(enum_signal_inversion), + enum_signal_inversion); + +static struct soc_enum soc_enum_auxo2_inversion = + SOC_ENUM_SINGLE(AUXO2, AUXOx_INV_SHIFT, + ARRAY_SIZE(enum_signal_inversion), + enum_signal_inversion); + +static struct soc_enum soc_enum_auxo3_inversion = + SOC_ENUM_SINGLE(AUXO3, AUXOx_INV_SHIFT, + ARRAY_SIZE(enum_signal_inversion), + enum_signal_inversion); + +static struct soc_enum soc_enum_auxo4_inversion = + SOC_ENUM_SINGLE(AUXO4, AUXOx_INV_SHIFT, + ARRAY_SIZE(enum_signal_inversion), + enum_signal_inversion); + +static struct soc_enum soc_enum_auxo1_pulldown_resistor = + SOC_ENUM_SINGLE(AUXO1, AUXOx_PULLDOWN_SHIFT, + ARRAY_SIZE(enum_optional_resistor), + enum_optional_resistor); + +static struct soc_enum soc_enum_auxo2_pulldown_resistor = + SOC_ENUM_SINGLE(AUXO2, AUXOx_PULLDOWN_SHIFT, + ARRAY_SIZE(enum_optional_resistor), + enum_optional_resistor); + +static struct soc_enum soc_enum_spkr1_mode = + SOC_ENUM_SINGLE(AB5500_VIRTUAL_REG3, SPKR1_MODE_SHIFT, + ARRAY_SIZE(enum_spkr1_mode), + enum_spkr1_mode); + +static struct soc_enum soc_enum_spkr2_mode = + SOC_ENUM_SINGLE(AB5500_VIRTUAL_REG3, SPKR2_MODE_SHIFT, + ARRAY_SIZE(enum_spkr2_mode), + enum_spkr2_mode); + +static struct soc_enum soc_enum_pwm_spkr1n_pol = + SOC_ENUM_SINGLE(PWMCTRL_SPKR1, PWMCTRL_SPKRx_N1_POL_SHIFT, + ARRAY_SIZE(enum_pwm_pol), enum_pwm_pol); + +static struct soc_enum soc_enum_pwm_spkr1p_pol = + SOC_ENUM_SINGLE(PWMCTRL_SPKR1, PWMCTRL_SPKRx_P1_POL_SHIFT, + ARRAY_SIZE(enum_pwm_pol), enum_pwm_pol); + +static struct soc_enum soc_enum_pwm_spkr2n_pol = + SOC_ENUM_SINGLE(PWMCTRL_SPKR2, PWMCTRL_SPKRx_N1_POL_SHIFT, + ARRAY_SIZE(enum_pwm_pol), enum_pwm_pol); + +static struct soc_enum soc_enum_pwm_spkr2p_pol = + SOC_ENUM_SINGLE(PWMCTRL_SPKR2, PWMCTRL_SPKRx_P1_POL_SHIFT, + ARRAY_SIZE(enum_pwm_pol), enum_pwm_pol); + +static struct snd_kcontrol_new ab5500_snd_controls[] = { + /* RX Routing */ + SOC_ENUM("RX1 Input Select", soc_enum_rx1_in_sel), + SOC_ENUM("RX2 Input Select", soc_enum_rx2_in_sel), + SOC_ENUM("RX3 Input Select", soc_enum_rx3_in_sel), + SOC_SINGLE("LINE1 Adder", LINE1_ADDER, 0, 0x1F, 0), + SOC_SINGLE("LINE2 Adder", LINE2_ADDER, 0, 0x1F, 0), + SOC_SINGLE("EAR Adder", EAR_ADDER, 0, 0x1F, 0), + SOC_SINGLE("SPKR1 Adder", SPKR1_ADDER, 0, 0x1F, 0), + SOC_SINGLE("SPKR2 Adder", SPKR2_ADDER, 0, 0x1F, 0), + SOC_SINGLE("AUXO1 Adder", AUXO1_ADDER, 0, 0x1F, 0), + SOC_SINGLE("AUXO2 Adder", AUXO2_ADDER, 0, 0x1F, 0), + SOC_SINGLE("AUXO3 Adder", AUXO3_ADDER, 0, 0x1F, 0), + SOC_SINGLE("AUXO4 Adder", AUXO4_ADDER, 0, 0x1F, 0), + SOC_SINGLE("SPKR1 PWM Select", AB5500_VIRTUAL_REG5, 0, 0x03, 0), + SOC_SINGLE("SPKR2 PWM Select", AB5500_VIRTUAL_REG5, 2, 0x0C, 0), + /* TX Routing */ + SOC_ENUM("TX1 Input Select", soc_enum_tx1_in_sel), + SOC_ENUM("TX2 Input Select", soc_enum_tx2_in_sel), + SOC_SINGLE("MIC1 Input Select", MIC1_INPUT_SELECT, 0, 0xff, 0), + SOC_SINGLE("MIC2 Input Select", MIC2_INPUT_SELECT, 0, 0xff, 0), + SOC_SINGLE("MIC2 to MIC1", MIC2_TO_MIC1, 0, 0x03, 0), + SOC_ENUM("I2S0 Input Select", soc_enum_i2s0_input_select), + SOC_ENUM("I2S1 Input Select", soc_enum_i2s1_input_select), + /* Routing of Side Tone and Analop Loop */ + SOC_ENUM("APGA1 Source", soc_enum_apga1_source), + SOC_ENUM("APGA2 Source", soc_enum_apga2_source), + SOC_ENUM("APGA1 Enable", soc_enum_apga1_enable), + SOC_ENUM("APGA2 Enable", soc_enum_apga2_enable), + SOC_ENUM("DAC1 Side Tone", soc_enum_dac1_side_tone), + SOC_ENUM("DAC2 Side Tone", soc_enum_dac2_side_tone), + /* RX Volume Control */ + SOC_SINGLE("RX-DPGA1 Gain", RX1_DPGA, 0, 0x43, 0), + SOC_SINGLE("RX-DPGA2 Gain", RX1_DPGA, 0, 0x43, 0), + SOC_SINGLE("RX-DPGA3 Gain", RX3_DPGA, 0, 0x43, 0), + SOC_SINGLE("LINE1 Gain", LINE1, LINEx_GAIN_SHIFT, 0x0a, 0), + SOC_SINGLE("LINE2 Gain", LINE2, LINEx_GAIN_SHIFT, 0x0a, 0), + SOC_SINGLE("SPKR1 Gain", SPKR1, SPKRx_GAIN_SHIFT, 0x16, 0), + SOC_SINGLE("SPKR2 Gain", SPKR2, SPKRx_GAIN_SHIFT, 0x16, 0), + SOC_SINGLE("EAR Gain", EAR_GAIN, EAR_GAIN_SHIFT, 0x12, 0), + SOC_SINGLE("AUXO1 Gain", AUXO1, AUXOx_GAIN_SHIFT, 0x0c, 0), + SOC_SINGLE("AUXO2 Gain", AUXO2, AUXOx_GAIN_SHIFT, 0x0c, 0), + SOC_SINGLE("AUXO3 Gain", AUXO3, AUXOx_GAIN_SHIFT, 0x0c, 0), + SOC_SINGLE("AUXO4 Gain", AUXO4, AUXOx_GAIN_SHIFT, 0x0c, 0), + /* TX Volume Control */ + SOC_SINGLE("MIC1 Gain", MIC1_GAIN, MICx_GAIN_SHIFT, 0x0a, 0), + SOC_SINGLE("MIC2 Gain", MIC2_GAIN, MICx_GAIN_SHIFT, 0x0a, 0), + SOC_SINGLE("TX-DPGA1 Gain", TX_DPGA1, TX_DPGAx_SHIFT, 0x0f, 0), + SOC_SINGLE("TX-DPGA2 Gain", TX_DPGA2, TX_DPGAx_SHIFT, 0x0f, 0), + /* Volume Control of Side Tone and Analog Loop */ + SOC_SINGLE("ST-PGA1 Gain", ST1_PGA, STx_PGA_SHIFT, 0x0a, 0), + SOC_SINGLE("ST-PGA2 Gain", ST2_PGA, STx_PGA_SHIFT, 0x0a, 0), + SOC_SINGLE("APGA1 Gain", ANALOG_LOOP_PGA1, APGAx_GAIN_SHIFT, 0x1d, 0), + SOC_SINGLE("APGA2 Gain", ANALOG_LOOP_PGA2, APGAx_GAIN_SHIFT, 0x1d, 0), + /* RX Properties */ + SOC_ENUM("DAC1 Power Mode", soc_enum_dac1_power_mode), + SOC_ENUM("DAC2 Power Mode", soc_enum_dac2_power_mode), + SOC_ENUM("DAC3 Power Mode", soc_enum_dac3_power_mode), + SOC_ENUM("EAR Power Mode", soc_enum_ear_power_mode), + SOC_ENUM("AUXO12 Power Mode", soc_enum_auxo12_power_mode), + SOC_ENUM("AUXO34 Power Mode", soc_enum_auxo34_power_mode), + SOC_ENUM("LINE1 Inversion", soc_enum_line1_inversion), + SOC_ENUM("LINE2 Inversion", soc_enum_line2_inversion), + SOC_ENUM("AUXO1 Inversion", soc_enum_auxo1_inversion), + SOC_ENUM("AUXO2 Inversion", soc_enum_auxo2_inversion), + SOC_ENUM("AUXO3 Inversion", soc_enum_auxo3_inversion), + SOC_ENUM("AUXO4 Inversion", soc_enum_auxo4_inversion), + SOC_ENUM("AUXO1 Pulldown Resistor", soc_enum_auxo1_pulldown_resistor), + SOC_ENUM("AUXO2 Pulldown Resistor", soc_enum_auxo2_pulldown_resistor), + SOC_ENUM("SPKR1 Mode", soc_enum_spkr1_mode), + SOC_ENUM("SPKR2 Mode", soc_enum_spkr2_mode), + SOC_ENUM("PWM SPKR1N POL", soc_enum_pwm_spkr1n_pol), + SOC_ENUM("PWM SPKR1P POL", soc_enum_pwm_spkr1p_pol), + SOC_ENUM("PWM SPKR2N POL", soc_enum_pwm_spkr2n_pol), + SOC_ENUM("PWM SPKR2P POL", soc_enum_pwm_spkr2p_pol), + /* TX Properties */ + SOC_SINGLE("MIC1 VMID", MIC1_VMID_SELECT, 0, 0x3f, 0), + SOC_SINGLE("MIC2 VMID", MIC2_VMID_SELECT, 0, 0x3f, 0), + SOC_ENUM("MBIAS1 PDN Impedance", soc_enum_mbias1_pdn_imp), + SOC_ENUM("MBIAS2 PDN Impedance", soc_enum_mbias2_pdn_imp), + SOC_ENUM("MBIAS2 Output Voltage", soc_enum_mbias2_out_v), + SOC_ENUM("MBIAS2 Internal Resistor", soc_enum_mbias2_int_r), + SOC_ENUM("MIC1 Input Impedance", soc_enum_mic1_in_imp), + SOC_ENUM("MIC2 Input Impedance", soc_enum_mic2_in_imp), + SOC_ENUM("TX1 HP Filter", soc_enum_tx1_hp_filter), + SOC_ENUM("TX2 HP Filter", soc_enum_tx2_hp_filter), + /* Side Tone and Analog Loop Properties */ + SOC_ENUM("ST1 HP Filter", soc_enum_st1_hp_filter), + SOC_ENUM("ST2 HP Filter", soc_enum_st2_hp_filter), + /* I2S Interface Properties */ + SOC_ENUM("I2S0 Word Length", soc_enum_i2s0_word_length), + SOC_ENUM("I2S1 Word Length", soc_enum_i2s1_word_length), + SOC_ENUM("I2S0 Mode", soc_enum_i2s0_mode), + SOC_ENUM("I2S1 Mode", soc_enum_i2s1_mode), + SOC_ENUM("I2S0 tri-state", soc_enum_i2s0_tristate), + SOC_ENUM("I2S1 tri-state", soc_enum_i2s1_tristate), + SOC_ENUM("I2S0 Pulldown Resistor", soc_enum_i2s0_pulldown_resistor), + SOC_ENUM("I2S1 Pulldown Resistor", soc_enum_i2s1_pulldown_resistor), + SOC_ENUM("I2S0 Sample Rate", soc_enum_i2s0_sample_rate), + SOC_ENUM("I2S1 Sample Rate", soc_enum_i2s1_sample_rate), + SOC_SINGLE("Interface Swap", INTERFACE_SWAP, 0, 0x03, 0), + /* Miscellaneous */ + SOC_SINGLE("Negative Charge Pump", NEG_CHARGE_PUMP, 0, 0x03, 0) +}; + +/* count the number of 1 */ +#define count_ones(x) ({ \ + int num; \ + typeof(x) y = x; \ + for (num = 0; y; y &= y - 1, num++) \ + ; \ + num; \ + }) + +enum enum_power { + POWER_OFF = 0, + POWER_ON = 1 +}; + +enum enum_link { + UNLINK = 0, + LINK = 1 +}; + +static enum enum_power get_widget_power_status(enum enum_widget widget) +{ + u8 val; + + if (widget >= number_of_widgets) + return POWER_OFF; + val = read_reg(widget_pm_array[widget].reg); + if (val & (1 << widget_pm_array[widget].shift)) + return POWER_ON; + else + return POWER_OFF; +} + +static int count_powered_neighbors(const unsigned long *neighbors) +{ + unsigned long i; + int n = 0; + for_each_set_bit(i, neighbors, number_of_widgets) { + if (get_widget_power_status(i) == POWER_ON) + n++; + } + return n; +} + +static int has_powered_neighbors(const unsigned long *neighbors) +{ + unsigned int i; + for_each_set_bit(i, neighbors, number_of_widgets) { + if (get_widget_power_status(i) == POWER_ON) + return 1; + } + return 0; +} + + +static int has_stacked_neighbors(const unsigned long *neighbors) +{ + unsigned long *stack_map = pm_stack_as_bitmap; + return bitmap_intersects(stack_map, neighbors, number_of_widgets); +} + +static void power_widget_unlocked(enum enum_power onoff, enum enum_widget widget) +{ + enum enum_widget w; + int done; + + if (widget >= number_of_widgets) + return; + if (get_widget_power_status(widget) == onoff) + return; + + for (w = widget, done = 0; !done;) { + unsigned long i; + unsigned long *srcs = widget_pm_array[w].source_list; + unsigned long *sinks = widget_pm_array[w].sink_list; + dev_dbg(ab5500_dev, "%s: processing widget %s.\n", + __func__, widget_names[w]); + + if (onoff == POWER_ON && + !bitmap_empty(srcs, number_of_widgets) && + !has_powered_neighbors(srcs)) { + pm_stack.stack[pm_stack.p++] = w; + for_each_set_bit(i, srcs, number_of_widgets) { + pm_stack.stack[pm_stack.p++] = i; + } + w = pm_stack.stack[--pm_stack.p]; + continue; + } else if (onoff == POWER_OFF && + has_powered_neighbors(sinks)) { + int n = 0; + pm_stack.stack[pm_stack.p++] = w; + for_each_set_bit(i, sinks, number_of_widgets) { + if (count_powered_neighbors( + widget_pm_array[i].source_list) + == 1 && + get_widget_power_status(i) == POWER_ON) { + pm_stack.stack[pm_stack.p++] = i; + n++; + } + } + if (n) { + w = pm_stack.stack[--pm_stack.p]; + continue; + } else + --pm_stack.p; + } + mask_set_reg(widget_pm_array[w].reg, + 1 << widget_pm_array[w].shift, + onoff == POWER_ON ? 0xff : 0); + dev_dbg(ab5500_dev, "%s: widget %s powered %s.\n", + __func__, widget_names[w], + onoff == POWER_ON ? "on" : "off"); + if (onoff == POWER_ON && + !bitmap_empty(sinks, number_of_widgets) && + !has_powered_neighbors(sinks) && + !has_stacked_neighbors(sinks)) { + for_each_set_bit(i, sinks, number_of_widgets) { + pm_stack.stack[pm_stack.p++] = i; + } + w = pm_stack.stack[--pm_stack.p]; + continue; + } else if (onoff == POWER_OFF) { + for_each_set_bit(i, srcs, number_of_widgets) { + if (!has_powered_neighbors( + widget_pm_array[i].sink_list) + && get_widget_power_status(i) == POWER_ON + && !test_bit(i, pm_stack_as_bitmap)) { + pm_stack.stack[pm_stack.p++] = i; + } + } + } + if (pm_stack.p > 0) + w = pm_stack.stack[--pm_stack.p]; + else + done = 1; + } +} + +static void power_widget_locked(enum enum_power onoff, + enum enum_widget widget) +{ + if (mutex_lock_interruptible(&ab5500_pm_mutex)) { + dev_warn(ab5500_dev, + "%s: Signal received while waiting on the PM mutex.\n", + __func__); + return; + } + power_widget_unlocked(onoff, widget); + mutex_unlock(&ab5500_pm_mutex); +} + + +static void dump_registers(const char *where, ...) +{ + va_list ap; + va_start(ap, where); + do { + short reg = va_arg(ap, int); + if (reg < 0) + break; + dev_dbg(ab5500_dev, "%s from %s> 0x%02X : 0x%02X.\n", + __func__, where, reg, read_reg(reg)); + } while (1); + va_end(ap); +} + +/** + * update the link two widgets. + * @op: 1 - connect; 0 - disconnect + * @src: source of the connection + * @sink: sink of the connection + */ +static int update_widgets_link(enum enum_link op, enum enum_widget src, + enum enum_widget sink, + u8 reg, u8 mask, u8 newval) +{ + int ret = 0; + + if (mutex_lock_interruptible(&ab5500_pm_mutex)) { + dev_warn(ab5500_dev, "%s: A signal is received while waiting on" + " the PM mutex.\n", __func__); + return -EINTR; + } + + switch (op << 2 | test_bit(sink, widget_pm_array[src].sink_list) << 1 | + test_bit(src, widget_pm_array[sink].source_list)) { + case 3: /* UNLINK, sink in sink_list, src in source_list */ + case 4: /* LINK, sink not in sink_list, src not in source_list */ + break; + default: + ret = -EINVAL; + goto end; + } + switch (((int)op) << 2 | get_widget_power_status(src) << 1 | + get_widget_power_status(sink)) { + case 3: /* op = 0, src on, sink on */ + if (count_powered_neighbors(widget_pm_array[sink].source_list) + == 1) + power_widget_unlocked(POWER_OFF, sink); + mask_set_reg(reg, mask, newval); + break; + case 6: /* op = 1, src on, sink off */ + mask_set_reg(reg, mask, newval); + power_widget_unlocked(POWER_ON, sink); + break; + default: + /* op = 0, src off, sink off */ + /* op = 0, src off, sink on */ + /* op = 0, src on, sink off */ + /* op = 1, src off, sink off */ + /* op = 1, src off, sink on */ + /* op = 1, src on, sink on */ + mask_set_reg(reg, mask, newval); + } + change_bit(sink, widget_pm_array[src].sink_list); + change_bit(src, widget_pm_array[sink].source_list); +end: + mutex_unlock(&ab5500_pm_mutex); + return ret; +}; + +static enum enum_widget apga_source_translate(u8 reg_value) +{ + switch (reg_value) { + case 1: + return widget_mic1; + case 2: + return widget_mic2; + default: + return number_of_widgets; + } +} + +static enum enum_widget adder_sink_translate(u8 reg) +{ + switch (reg) { + case EAR_ADDER: + return widget_ear; + case AUXO1_ADDER: + return widget_auxo1; + case AUXO2_ADDER: + return widget_auxo2; + case AUXO3_ADDER: + return widget_auxo3; + case AUXO4_ADDER: + return widget_auxo4; + case SPKR1_ADDER: + return widget_spkr1; + case SPKR2_ADDER: + return widget_spkr2; + case LINE1_ADDER: + return widget_line1; + case LINE2_ADDER: + return widget_line2; + default: + return number_of_widgets; + } +} + +static int ab5500_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(&codec->dapm, ab5500_dapm_widgets, + ARRAY_SIZE(ab5500_dapm_widgets)); + + snd_soc_dapm_add_routes(&codec->dapm, intercon, ARRAY_SIZE(intercon)); + + snd_soc_dapm_new_widgets(&codec->dapm); + return 0; +} + +static void power_for_playback(enum enum_power onoff, int ifsel) +{ + dev_dbg(ab5500_dev, "%s: interface %d power %s.\n", __func__, + ifsel, onoff == POWER_ON ? "on" : "off"); + if (mutex_lock_interruptible(&ab5500_pm_mutex)) { + dev_warn(ab5500_dev, + "%s: Signal received while waiting on the PM mutex.\n", + __func__); + return; + } + power_widget_unlocked(onoff, ifsel == 0 ? + widget_if0_dld_l : widget_if1_dld_l); + power_widget_unlocked(onoff, ifsel == 0 ? + widget_if0_dld_r : widget_if1_dld_r); + mutex_unlock(&ab5500_pm_mutex); +} + +static void power_for_capture(enum enum_power onoff, int ifsel) +{ + dev_info(ab5500_dev, "%s: interface %d power %s", __func__, + ifsel, onoff == POWER_ON ? "on" : "off"); + if (mutex_lock_interruptible(&ab5500_pm_mutex)) { + dev_warn(ab5500_dev, + "%s: Signal received while waiting on the PM mutex.\n", + __func__); + return; + } + power_widget_unlocked(onoff, ifsel == 0 ? + widget_if0_uld_l : widget_if1_uld_l); + power_widget_unlocked(onoff, ifsel == 0 ? + widget_if0_uld_r : widget_if1_uld_r); + mutex_unlock(&ab5500_pm_mutex); +} + +static int ab5500_add_controls(struct snd_soc_codec *codec) +{ + int err = 0, i, n = ARRAY_SIZE(ab5500_snd_controls); + + pr_info("%s: %s called.\n", __FILE__, __func__); + for (i = 0; i < n; i++) { + err = snd_ctl_add(codec->card->snd_card, snd_ctl_new1( + &ab5500_snd_controls[i], codec)); + if (err < 0) { + pr_err("%s failed to add control No.%d of %d.\n", + __func__, i, n); + return err; + } + } + return err; +} + +static int ab5500_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + dai->playback_active : dai->capture_active) { + dev_err(dai->dev, "A %s stream is already active.\n", + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + "playback" : "capture"); + return -EBUSY; + } + return 0; +} + +static int ab5500_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params, + struct snd_soc_dai *dai) +{ + u8 val; + u8 reg = dai->id == 0 ? INTERFACE0 : INTERFACE1; + + if (!ab5500_dev) { + pr_err("%s: The AB5500 codec driver not initialized.\n", + __func__); + return -EAGAIN; + } + dev_info(ab5500_dev, "%s called.\n", __func__); + switch (params_rate(hw_params)) { + case 8000: + val = I2Sx_SR_8000Hz; + break; + case 16000: + val = I2Sx_SR_16000Hz; + break; + case 44100: + val = I2Sx_SR_44100Hz; + break; + case 48000: + val = I2Sx_SR_48000Hz; + break; + default: + return -EINVAL; + } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + !dai->capture_active : !dai->playback_active) { + + mask_set_reg(reg, I2Sx_SR_MASK, val << I2Sx_SR_SHIFT); + if ((read_reg(reg) & I2Sx_MODE_MASK) == 0) { + mask_set_reg(reg, MASTER_GENx_PWR_MASK, + 1 << MASTER_GENx_PWR_SHIFT); + } + } + return 0; +} + +static int ab5500_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + dev_dbg(ab5500_dev, "%s called.\n", __func__); + /* Configure registers for either playback or capture */ + if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) && + !(ab5500_codec_privates[dai->id].playback_active == true)) { + power_for_playback(POWER_ON, dai->id); + ab5500_codec_privates[dai->id].playback_active = true; + } else if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) && + !(ab5500_codec_privates[dai->id].capture_active == true)) { + power_for_capture(POWER_ON, dai->id); + ab5500_codec_privates[dai->id].capture_active = true; + } + dump_registers(__func__, RX1, AUXO1_ADDER, RX2, + AUXO2_ADDER, RX1_DPGA, RX2_DPGA, AUXO1, AUXO2, -1); + return 0; +} + +static void ab5500_pcm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + u8 iface = dai->id == 0 ? INTERFACE0 : INTERFACE1; + dev_info(ab5500_dev, "%s called.\n", __func__); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + power_for_playback(POWER_OFF, dai->id); + ab5500_codec_privates[dai->id].playback_active = false; + } else { + power_for_capture(POWER_OFF, dai->id); + ab5500_codec_privates[dai->id].capture_active = false; + + } + if (!dai->playback_active && !dai->capture_active && + (read_reg(iface) & I2Sx_MODE_MASK) == 0) + mask_set_reg(iface, MASTER_GENx_PWR_MASK, 0); +} + +static int ab5500_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + return 0; +} + +static int ab5500_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + u8 iface = (codec_dai->id == 0) ? INTERFACE0 : INTERFACE1; + u8 val = 0; + dev_info(ab5500_dev, "%s called.\n", __func__); + + switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK | + SND_SOC_DAIFMT_MASTER_MASK)) { + + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: + val |= 1 << I2Sx_MODE_SHIFT; + break; + + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: + break; + + default: + dev_warn(ab5500_dev, "AB5500_dai: unsupported DAI format " + "0x%x\n", fmt); + return -EINVAL; + } + if (codec_dai->playback_active && codec_dai->capture_active) { + if ((read_reg(iface) & I2Sx_MODE_MASK) == val) + return 0; + else { + dev_err(ab5500_dev, + "%s: DAI format set differently " + "by an existing stream.\n", __func__); + return -EINVAL; + } + } + mask_set_reg(iface, I2Sx_MODE_MASK, val); + return 0; +} + +struct snd_soc_dai_driver ab5500_dai_drv[] = { + { + .name = "ab5500-codec-dai.0", + .id = 0, + .playback = { + .stream_name = "ab5500.0 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = AB5500_SUPPORTED_RATE, + .formats = AB5500_SUPPORTED_FMT, + }, + .capture = { + .stream_name = "ab5500.0 Capture", + .channels_min = 2, + .channels_max = 2, + .rates = AB5500_SUPPORTED_RATE, + .formats = AB5500_SUPPORTED_FMT, + }, + .ops = (struct snd_soc_dai_ops[]) { + { + .startup = ab5500_pcm_startup, + .prepare = ab5500_pcm_prepare, + .hw_params = ab5500_pcm_hw_params, + .shutdown = ab5500_pcm_shutdown, + .set_sysclk = ab5500_set_dai_sysclk, + .set_fmt = ab5500_set_dai_fmt, + } + }, + .symmetric_rates = 1, + }, + { + .name = "ab5500-codec-dai.1", + .id = 1, + .playback = { + .stream_name = "ab5500.1 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = AB5500_SUPPORTED_RATE, + .formats = AB5500_SUPPORTED_FMT, + }, + .capture = { + .stream_name = "ab5500.1 Capture", + .channels_min = 2, + .channels_max = 2, + .rates = AB5500_SUPPORTED_RATE, + .formats = AB5500_SUPPORTED_FMT, + }, + .ops = (struct snd_soc_dai_ops[]) { + { + .startup = ab5500_pcm_startup, + .prepare = ab5500_pcm_prepare, + .hw_params = ab5500_pcm_hw_params, + .shutdown = ab5500_pcm_shutdown, + .set_sysclk = ab5500_set_dai_sysclk, + .set_fmt = ab5500_set_dai_fmt, + } + }, + .symmetric_rates = 1, + } +}; + +static int ab5500_codec_probe(struct snd_soc_codec *codec) +{ + int ret = ab5500_add_controls(codec); + if (ret < 0) + return ret; + ab5500_add_widgets(codec); + return 0; +} + +static int ab5500_codec_remove(struct snd_soc_codec *codec) +{ + snd_soc_dapm_free(&codec->dapm); + return 0; +} + +#ifdef CONFIG_PM +static int ab5500_codec_suspend(struct snd_soc_codec *codec, + pm_message_t state) +{ + mask_set_reg(CLOCK, CLOCK_ENABLE_MASK, 0); + return 0; +} + +static int ab5500_codec_resume(struct snd_soc_codec *codec) +{ + mask_set_reg(CLOCK, CLOCK_ENABLE_MASK, 0xff); + return 0; +} +#else +#define ab5500_codec_resume NULL +#define ab5500_codec_suspend NULL +#endif + +/** + This function is only called by the SOC framework to + set registers associated to the mixer controls. +*/ +static int ab5500_codec_write_reg(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + if (reg < MIC_BIAS1 || reg > INTERFACE_SWAP) + return -EINVAL; + switch (reg) { + u8 diff, oldval; + case ANALOG_LOOP_PGA1: + case ANALOG_LOOP_PGA2: { + enum enum_widget apga = reg == ANALOG_LOOP_PGA1 ? + widget_apga1 : widget_apga2; + + oldval = read_reg(reg); + diff = value ^ oldval; + + /* + * The APGA is to be turned on/off. The power bit and the + * other bits in the same register won't be changed at the + * same time since they belong to different controls. + */ + if (diff & (1 << APGAx_PWR_SHIFT)) { + power_widget_locked(value >> APGAx_PWR_SHIFT & 1, + apga); + } else if (diff & APGAx_MUX_MASK) { + enum enum_widget old_source = + apga_source_translate(oldval); + enum enum_widget new_source = + apga_source_translate(value); + update_widgets_link(UNLINK, old_source, apga, + reg, APGAx_MUX_MASK, 0); + update_widgets_link(LINK, new_source, apga, + reg, APGAx_MUX_MASK, value); + } else { + set_reg(reg, value); + } + break; + } + + case EAR_ADDER: + case AUXO1_ADDER: + case AUXO2_ADDER: + case AUXO3_ADDER: + case AUXO4_ADDER: + case SPKR1_ADDER: + case SPKR2_ADDER: + case LINE1_ADDER: + case LINE2_ADDER: { + int i; + enum enum_widget widgets[] = { + widget_dac1, widget_dac2, widget_dac3, + widget_apga1, widget_apga2 + }; + oldval = read_reg(reg); + diff = value ^ oldval; + for (i = 0; diff; i++) { + if (!(diff & 1 << i)) + continue; + diff ^= 1 << i; + update_widgets_link(value >> i & 1, widgets[i], + adder_sink_translate(reg), + reg, 1 << i, value); + } + break; + } + case AB5500_VIRTUAL_REG3: + oldval = read_reg(reg); + diff = value ^ oldval; + /* + * The following changes won't take place in the same call, + * since they are arranged into different mixer controls. + */ + + /* changed between the two amplifier modes */ + if (hweight8(diff & SPKR1_MODE_MASK) == 2) { + set_reg(reg, value); + break; + } + + if (diff & SPKR1_MODE_MASK) { + update_widgets_link( + UNLINK, + (oldval & SPKR1_MODE_MASK) == 0 ? + widget_pwm_spkr1 : widget_spkr1_adder, + widget_spkr1, + reg, SPKR1_MODE_MASK, value); + update_widgets_link( + LINK, + (value & SPKR1_MODE_MASK) == 0 ? + widget_pwm_spkr1 : widget_spkr1_adder, + widget_spkr1, + DUMMY_REG, 0, 0); + + } + if (diff & SPKR2_MODE_MASK) { + update_widgets_link( + UNLINK, + (oldval & SPKR2_MODE_MASK) == 0 ? + widget_pwm_spkr2 : widget_spkr2_adder, + widget_spkr2, + reg, SPKR2_MODE_MASK, value); + update_widgets_link( + LINK, + (value & SPKR2_MODE_MASK) == 0 ? + widget_pwm_spkr2 : widget_spkr2_adder, + widget_spkr2, + DUMMY_REG, 0, 0); + + } + break; + + case AB5500_VIRTUAL_REG4: + /* configure PWMCTRL_SPKR1, PWMCTRL_SPKR2, etc. */ + break; + default: + set_reg(reg, value); + } + return 0; +} + +static unsigned int ab5500_codec_read_reg(struct snd_soc_codec *codec, + unsigned int reg) +{ + return read_reg(reg); +} + + +static struct snd_soc_codec_driver ab5500_codec_drv = { + .probe = ab5500_codec_probe, + .remove = ab5500_codec_remove, + .suspend = ab5500_codec_suspend, + .resume = ab5500_codec_resume, + .read = ab5500_codec_read_reg, + .write = ab5500_codec_write_reg, +}; +EXPORT_SYMBOL_GPL(ab5500_codec_drv); + +static inline void init_playback_route(void) +{ + /* if0_dld_l -> rx1 -> dac1 -> auxo1 */ + update_widgets_link(LINK, widget_if0_dld_l, widget_rx1, + RX1, RXx_DATA_MASK, 0x03 << RXx_DATA_SHIFT); + update_widgets_link(LINK, widget_rx1, widget_dac1, 0, 0, 0); + update_widgets_link(LINK, widget_dac1, widget_auxo1, + AUXO1_ADDER, DAC1_TO_X_MASK, 0xff); + + /* if0_dld_r -> rx2 -> dac2 -> auxo2 */ + update_widgets_link(LINK, widget_if0_dld_r, widget_rx2, + RX2, RXx_DATA_MASK, 0x04 << RXx_DATA_SHIFT); + update_widgets_link(LINK, widget_rx2, widget_dac2, 0, 0, 0); + update_widgets_link(LINK, widget_dac2, widget_auxo2, + AUXO2_ADDER, DAC2_TO_X_MASK, 0xff); + +} + +static inline void init_capture_route(void) +{ + /* mic bias - > mic2 inputs */ + update_widgets_link(LINK, widget_micbias1, widget_mic2p2, + 0, 0, 0); + update_widgets_link(LINK, widget_micbias1, widget_mic2n2, + 0, 0, 0); + update_widgets_link(LINK, widget_micbias2, widget_mic2p2, + 0, 0, 0); + update_widgets_link(LINK, widget_micbias2, widget_mic2n2, + 0, 0, 0); + + + /* mic2 inputs -> mic2 */ + update_widgets_link(LINK, widget_mic2p2, widget_mic2, + MIC2_INPUT_SELECT, MICxP2_SEL_MASK, 0xff); + update_widgets_link(LINK, widget_mic2n2, widget_mic2, + MIC2_INPUT_SELECT, MICxN2_SEL_MASK, 0xff); + + /* mic2 -> adc2 -> tx2 */ + update_widgets_link(LINK, widget_mic2, widget_adc2, + 0, 0, 0); + update_widgets_link(LINK, widget_adc2, widget_tx2, + TX2, TXx_MUX_MASK, 0); + + /* tx2 -> if0_uld_l & if0_uld_r */ + update_widgets_link(LINK, widget_tx2, widget_if0_uld_l, + INTERFACE0_ULD, I2Sx_ULD_L_MASK, + 0x02 << I2Sx_ULD_L_SHIFT); + update_widgets_link(LINK, widget_tx2, widget_if0_uld_r, + INTERFACE0_ULD, I2Sx_ULD_R_MASK, + 0x02 << I2Sx_ULD_R_SHIFT); + + /* mic2 -> apga2 */ + update_widgets_link(LINK, widget_mic2, widget_apga2, + ANALOG_LOOP_PGA2, APGAx_MUX_MIC2_MASK, + 1 << APGAx_MUX_MIC2_SHIFT); + + /* apga2 -> auxo1 & auxo2 */ + update_widgets_link(LINK, widget_apga2, widget_auxo1, + AUXO1_ADDER, APGA2_TO_X_MASK, + 1 << APGA2_TO_X_SHIFT); + update_widgets_link(LINK, widget_apga2, widget_auxo2, + AUXO2_ADDER, APGA2_TO_X_MASK, + 1 << APGA2_TO_X_SHIFT); +} + +static inline void init_playback_gain(void) +{ + /* 0x43, 0x0C: pure gain values */ + mask_set_reg(RX1_DPGA, RXx_DPGA_MASK, + 0x43 << RXx_DPGA_SHIFT); + mask_set_reg(RX2_DPGA, RXx_DPGA_MASK, + 0x43 << RXx_DPGA_SHIFT); + mask_set_reg(AUXO1, AUXOx_GAIN_MASK, 0x0C << AUXOx_GAIN_SHIFT); + mask_set_reg(AUXO2, AUXOx_GAIN_MASK, 0x0C << AUXOx_GAIN_SHIFT); +} + +static inline void init_capture_gain(void) +{ + /* 0x06, 0x0f: pure gain values */ + mask_set_reg(MIC1_GAIN, MICx_GAIN_MASK, 0x06 << MICx_GAIN_SHIFT); + mask_set_reg(TX_DPGA1, TX_DPGAx_MASK, 0x0f << TX_DPGAx_SHIFT); +} + +static int __devinit ab5500_platform_probe(struct platform_device *pdev) +{ + int ret = 0; + u8 reg; + struct ab5500_codec_dai_data *codec_drvdata; + + pr_info("%s invoked with pdev = %p.\n", __func__, pdev); + ab5500_dev = &pdev->dev; + codec_drvdata = kzalloc(sizeof(struct ab5500_codec_dai_data), + GFP_KERNEL); + if (codec_drvdata == NULL) + return -ENOMEM; + platform_set_drvdata(pdev, codec_drvdata); + ret = snd_soc_register_codec(ab5500_dev, &ab5500_codec_drv, + ab5500_dai_drv, + ARRAY_SIZE(ab5500_dai_drv)); + if (ret < 0) { + dev_err(ab5500_dev, "%s: Failed to register codec. " + "Error %d.\n", __func__, ret); + snd_soc_unregister_codec(ab5500_dev); + kfree(codec_drvdata); + } + /* Initialize the codec registers */ + for (reg = AB5500_FIRST_REG; reg <= AB5500_LAST_REG; reg++) + set_reg(reg, 0); + + mask_set_reg(CLOCK, CLOCK_REF_SELECT_MASK | CLOCK_ENABLE_MASK, + 1 << CLOCK_REF_SELECT_SHIFT | 1 << CLOCK_ENABLE_SHIFT); + printk(KERN_ERR "Clock Setting ab5500\n"); + init_playback_route(); + init_playback_gain(); + init_capture_route(); + init_capture_gain(); + memset(&pm_stack, 0, sizeof(pm_stack)); + return ret; +} + +static int __devexit ab5500_platform_remove(struct platform_device *pdev) +{ + pr_info("%s called.\n", __func__); + mask_set_reg(CLOCK, CLOCK_ENABLE_MASK, 0); + snd_soc_unregister_codec(ab5500_dev); + kfree(platform_get_drvdata(pdev)); + ab5500_dev = NULL; + return 0; +} + +static int ab5500_platform_suspend(struct platform_device *pdev, + pm_message_t state) +{ + return 0; +} + +static int ab5500_platform_resume(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver ab5500_platform_driver = { + .driver = { + .name = "ab5500-codec", + .owner = THIS_MODULE, + }, + .probe = ab5500_platform_probe, + .remove = ab5500_platform_remove, + .suspend = ab5500_platform_suspend, + .resume = ab5500_platform_resume, +}; + +static int __devinit ab5500_init(void) +{ + int ret; + + pr_info("%s called.\n", __func__); + + /* Register codec platform driver. */ + ret = platform_driver_register(&ab5500_platform_driver); + if (ret) { + pr_err("%s: Error %d: Failed to register codec platform " + "driver.\n", __func__, ret); + } + return ret; +} + +static void __devexit ab5500_exit(void) +{ + pr_info("%s called.\n", __func__); + platform_driver_unregister(&ab5500_platform_driver); +} + +module_init(ab5500_init); +module_exit(ab5500_exit); + +MODULE_DESCRIPTION("AB5500 Codec driver"); +MODULE_AUTHOR("Xie Xiaolei <xie.xiaolei@stericsson.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ab5500.h b/sound/soc/codecs/ab5500.h new file mode 100644 index 00000000000..c410259d73a --- /dev/null +++ b/sound/soc/codecs/ab5500.h @@ -0,0 +1,408 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Register definitions for AB5500 codec + * Author: Xie Xiaolei <xie.xiaolei@etericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ +#ifndef AB5500_CODEC_REGISTERS_H +#define AB5500_CODEC_REGISTERS_H + +#define AB5500_SUPPORTED_RATE (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) + +#define AB5500_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + + +/* MIC BIAS */ + +#define MIC_BIAS1 0x00 +#define MIC_BIAS2 0x01 +#define MBIAS2_OUT_V_MASK 0x04 +#define MBIAS2_OUT_V_SHIFT 2 +#define MBIASx_PWR_MASK 0x02 +#define MBIASx_PWR_SHIFT 1 +#define MBIASx_PDN_IMP_MASK 0x01 +#define MBIASx_PDN_IMP_SHIFT 0 + +#define MIC_BIAS2_VAD 0x02 +#define MBIAS2_R_INT_MASK 0x01 +#define MBIAS2_R_INT_SHIFT 0 + +/* MIC */ +#define MIC1_GAIN 0x03 +#define MIC2_GAIN 0x04 +#define MICx_GAIN_MASK 0xF0 +#define MICx_GAIN_SHIFT 4 +#define MICx_IN_IMP_MASK 0x0C +#define MICx_IN_IMP_SHIFT 2 +#define MICx_PWR_MASK 0x01 +#define MICx_PWR_SHIFT 0 + +#define MIC1_INPUT_SELECT 0x05 +#define MIC2_INPUT_SELECT 0x06 +#define MICxP1_SEL_MASK 0x80 +#define MICxP1_SEL_SHIFT 7 +#define MICxN1_SEL_MASK 0x40 +#define MICxN1_SEL_SHIFT 6 +#define MICxP2_SEL_MASK 0x20 +#define MICxP2_SEL_SHIFT 5 +#define MICxN2_SEL_MASK 0x10 +#define MICxN2_SEL_SHIFT 4 +#define LINEIN_SEL_MASK 0x03 +#define LINEIN_SEL_SHIFT 0 + +#define MIC1_VMID_SELECT 0x07 +#define MIC2_VMID_SELECT 0x08 +#define VMIDx_ENABLE_MASK 0xC0 +#define VMIDx_ENABLE_SHIFT 6 +#define VMIDx_LINEIN1_N_MASK 0x20 +#define VMIDx_LINEIN1_N_SHIFT 5 +#define VMIDx_LINEIN2_N_MASK 0x10 +#define VMIDx_LINEIN2_N_SHIFT 4 +#define VMIDx_MICxP1_MASK 0x08 +#define VMIDx_MICxP1_SHIFT 3 +#define VMIDx_MICxP2_MASK 0x04 +#define VMIDx_MICxP2_SHIFT 2 +#define VMIDx_MICxN1_MASK 0x02 +#define VMIDx_MICxN1_SHIFT 1 +#define VMIDx_MICxN2_MASK 0x01 +#define VMIDx_MICxN2_SHIFT 0 + +#define MIC2_TO_MIC1 0x09 +#define MIC2_TO_MIC1_MASK 0x03 +#define MIC2_TO_MIC1_SHIFT 0 + +/* Analog Loop */ +#define ANALOG_LOOP_PGA1 0x0A +#define ANALOG_LOOP_PGA2 0x0B +#define APGAx_GAIN_MASK 0xF8 +#define APGAx_GAIN_SHIFT 3 +#define APGAx_PWR_MASK 0x04 +#define APGAx_PWR_SHIFT 2 +#define APGAx_MUX_MASK 0x03 +#define APGAx_MUX_SHIFT 0 +#define APGAx_MUX_MIC1_MASK 0x01 +#define APGAx_MUX_MIC1_SHIFT 0 +#define APGAx_MUX_MIC2_MASK 0x02 +#define APGAx_MUX_MIC2_SHIFT 1 + +#define APGA_VMID_SELECT 0x0C +#define VMID_APGA1_ENABLE_MASK 0xC0 +#define VMID_APGA1_ENABLE_SHIFT 6 +#define VMID_APGA1_LINEIN1_MASK 0x20 +#define VMID_APGA1_LINEIN1_SHIFT 5 +#define VMID_APGA2_ENABLE_MASK 0x0C +#define VMID_APGA2_ENABLE_SHIFT 2 +#define VMID_APGA2_LINEIN2_MASK 0x02 +#define VMID_APGA2_LINEIN2_SHIFT 1 + +/* Output Amplifiers */ +#define EAR_PWR 0x0D +#define EAR_PWR_MODE_MASK 0xC0 +#define EAR_PWR_MODE_SHIFT 6 +#define EAR_PWR_VMID_MASK 0x30 +#define EAR_PWR_VMID_SHIFT 4 +#define EAR_PWR_MASK 0x01 +#define EAR_PWR_SHIFT 0 + +#define EAR_GAIN 0x0E +#define EAR_GAIN_MASK 0x1F +#define EAR_GAIN_SHIFT 0 + +#define AUXO1 0x0F +#define AUXO2 0x10 +#define AUXO3 0x11 +#define AUXO4 0x12 +#define AUXOx_PWR_MASK 0x80 +#define AUXOx_PWR_SHIFT 7 +#define AUXOx_INV_MASK 0x40 +#define AUXOx_INV_SHIFT 6 +#define AUXOx_PULLDOWN_MASK 0x20 +#define AUXOx_PULLDOWN_SHIFT 5 +#define AUXOx_GAIN_MASK 0x0F +#define AUXOx_GAIN_SHIFT 0 + +#define AUXO12_PWR_MODE 0x13 +#define AUXO34_PWR_MODE 0x14 +#define AUXOxy_PWR_MODE_MASK 0x07 +#define AUXOxy_PWR_MODE_SHIFT 0 + +#define NEG_CHARGE_PUMP 0x15 +#define NEG_CHARGE_PUMP_MODE_MASK 0x02 +#define NEG_CHARGE_PUMP_MODE_SHIFT 1 +#define NEG_CHARGE_PUMP_PWR_MASK 0x01 +#define NEG_CHARGE_PUMP_PWR_SHIFT 0 + +#define ENV_THR 0x16 +#define ENV_THR_HIGH_MASK 0xF0 +#define ENV_THR_HIGH_SHIFT 4 +#define ENV_THR_LOW_MASK 0x0F +#define ENV_THR_LOW_SHIFT 0 + +#define ENV_DECAY_TIME 0x17 +#define ENV_DECAY_TIME_CP_LV_MASK 0x20 +#define ENV_DECAY_TIME_CP_LV_SHIFT 5 +#define ENV_DECAY_TIME_DET_CP_MASK 0x10 +#define ENV_DECAY_TIME_DET_CP_SHIFT 4 +#define ENV_DECAY_TIME_MASK 0x0F +#define ENV_DECAY_TIME_SHIFT 0 + +#define DC_CANCEL 0x18 +#define DC_CANCEL_SPKR2_MASK 0x10 +#define DC_CANCEL_SPKR2_SHIFT 4 +#define DC_CANCEL_SPKR1_MASK 0x08 +#define DC_CANCEL_SPKR1_SHIFT 3 +#define DC_CANCEL_AUXO34_MASK 0x04 +#define DC_CANCEL_AUXO34_SHIFT 2 +#define DC_CANCEL_AUXO12_MASK 0x02 +#define DC_CANCEL_AUXO12_SHIFT 1 +#define DC_CANCEL_OFFSET_CLOCK_MASK 0x01 +#define DC_CANCEL_OFFSET_CLOCK_SHIFT 0 + +#define SPKR1 0x19 +#define SPKR2 0x1A +#define SPKRx_PWR_MASK 0xC0 +#define SPKRx_PWR_SHIFT 6 +#define SPKRx_PWR_VBR_VALUE 0x40 +#define SPKRx_PWR_CLS_D_VALUE 0x80 +#define SPKRx_PWR_CLS_AB_VALUE 0xC0 +#define SPKR1_VMID_MASK 0x20 +#define SPKR1_VMID_SHIFT 5 +#define SPKRx_GAIN_MASK 0x1F +#define SPKRx_GAIN_SHIFT 0 + +#define SPKR_OVCR 0x1B +#define SPKR_OVCR_PROT2_MASK 0x80 +#define SPKR_OVCR_PROT2_SHIFT 7 +#define SPKR_OVCR_TRIM2_MASK 0x70 +#define SPKR_OVCR_TRIM2_SHIFT 4 +#define SPKR_OVCR_PROT1_MASK 0x08 +#define SPKR_OVCR_PROT1_SHIFT 3 +#define SPKR_OVCR_TRIM1_MASK 0x07 +#define SPKR_OVCR_TRIM1_SHIFT 0 + +#define PWMCTRL_SPKR1 0x1C +#define PWMCTRL_SPKR2 0x1F +#define PWMCTRL_SPKRx_N1_POL_MASK 0x80 +#define PWMCTRL_SPKRx_N1_POL_SHIFT 7 +#define PWMCTRL_SPKRx_P1_POL_MASK 0x40 +#define PWMCTRL_SPKRx_P1_POL_SHIFT 6 +#define PWMCTRL_SPKRx_MASK 0x04 +#define PWMCTRL_SPKRx_SHIFT 2 +#define PWMCTRL_SPKRxN_MASK 0x02 +#define PWMCTRL_SPKRxN_SHIFT 1 +#define PWMCTRL_SPKRxP_MASK 0x01 +#define PWMCTRL_SPKRxP_SHIFT 0 + +#define PWM_SPKR1N 0x1D +#define PWM_SPKR2N 0x20 +#define PWM_SPKR1P 0x1E +#define PWM_SPKR2P 0x21 +#define PWM_SPKRxy_DUT_CYC_MASK 0xFF +#define PWM_SPKRxy_DUT_CYC_SHIFT 0 + +#define SPKR1_CLK_DIV 0x22 +#define SPKR2_CLK_DIV 0x23 +#define SPKRx_CLK_DIV_MASK 0x3F +#define SPKRx_CLK_DIV_SHIFT 0 + +#define LINE1 0x24 +#define LINE2 0x25 +#define LINEx_PWR_MASK 0x80 +#define LINEx_PWR_SHIFT 7 +#define LINEx_INV_MASK 0x40 +#define LINEx_INV_SHIFT 6 +#define LINEx_TO_USB_MASK 0x20 +#define LINEx_TO_USB_SHIFT 5 +#define LINEx_VMID_BUFF_MASK 0x10 +#define LINEx_VMID_BUFF_SHIFT 4 +#define LINEx_GAIN_MASK 0x0F +#define LINEx_GAIN_SHIFT 0 + +#define USB_AUDIO 0x26 +#define USB_AUDIO_MIC_MUX_MASK 0x03 +#define USB_AUDIO_MIC_MUX_SHIFT 0 + +#define EAR_ADDER 0x28 +#define AUXO1_ADDER 0x29 +#define AUXO2_ADDER 0x2A +#define AUXO3_ADDER 0x2B +#define AUXO4_ADDER 0x2C +#define SPKR1_ADDER 0x2D +#define SPKR2_ADDER 0x2E +#define LINE1_ADDER 0x2F +#define LINE2_ADDER 0x30 +#define APGA2_TO_X_MASK 0x10 +#define APGA2_TO_X_SHIFT 4 +#define APGA1_TO_X_MASK 0x08 +#define APGA1_TO_X_SHIFT 3 +#define DAC3_TO_X_MASK 0x04 +#define DAC3_TO_X_SHIFT 2 +#define DAC2_TO_X_MASK 0x02 +#define DAC2_TO_X_SHIFT 1 +#define DAC1_TO_X_MASK 0x01 +#define DAC1_TO_X_SHIFT 0 + +#define EAR_TO_MIC2 0x31 +#define SPKR1_TO_MIC2 0x32 +#define SPKR2_TO_MIC2 0x33 +#define EAR_TO_MIC2_MASK 0x01 +#define EAR_TO_MIC2_SHIFT 0 + +#define ADC_LOW_PWR 0x35 +#define ADC_LOW_PWR_MASK 0x01 +#define ADC_LOW_PWR_SHIFT 0 + +#define TX1 0x36 +#define TX2 0x37 +#define TXx_MUX_MASK 0x60 +#define TXx_MUX_SHIFT 6 +#define TXx_FS_MASK 0x10 +#define TXx_FS_SHIFT 4 +#define TXx_HP_FILTER_MASK 0x0C +#define TXx_HP_FILTER_SHIFT 2 +#define TXx_PWR_MASK 0x02 +#define TXx_PWR_SHIFT 1 +#define ADCx_PWR_MASK 0x01 +#define ADCx_PWR_SHIFT 0 + +#define RX1 0x38 +#define RX2 0x39 +#define RX3 0x3A +#define RXx_DATA_MASK 0x70 +#define RXx_DATA_SHIFT 4 +#define RXx_PWR_MASK 0x08 +#define RXx_PWR_SHIFT 3 +#define DACx_PWR_MASK 0x04 +#define DACx_PWR_SHIFT 2 +#define DACx_PWR_MODE_MASK 0x03 +#define DACx_PWR_MODE_SHIFT 0 + +#define TX_DPGA1 0x3B +#define TX_DPGA2 0x3C +#define TX_DPGAx_MASK 0x0F +#define TX_DPGAx_SHIFT 0 + +#define RX1_DPGA 0x3D +#define RX2_DPGA 0x3E +#define RX3_DPGA 0x3F +#define RXx_DPGA_MASK 0x7F +#define RXx_DPGA_SHIFT 0 + +#define ST1_PGA 0x40 +#define ST2_PGA 0x41 +#define STx_HP_FILTER_MASK 0x60 +#define STx_HP_FILTER_SHIFT 6 +#define STx_MUX_MASK 0x10 +#define STx_MUX_SHIFT 4 +#define STx_PGA_MASK 0x0F +#define STx_PGA_SHIFT 0 + +#define CLOCK 0x42 +#define CLOCK_REF_SELECT_MASK 0x02 +#define CLOCK_REF_SELECT_SHIFT 1 +#define CLOCK_ENABLE_MASK 0x01 +#define CLOCK_ENABLE_SHIFT 0 + +#define INTERFACE0 0x43 +#define INTERFACE1 0x45 +#define I2Sx_WORDLENGTH_MASK 0x40 +#define I2Sx_WORDLENGTH_SHIFT 6 +#define MASTER_GENx_PWR_MASK 0x20 +#define MASTER_GENx_PWR_SHIFT 5 +#define I2Sx_MODE_MASK 0x10 +#define I2Sx_MODE_SHIFT 4 +#define I2Sx_TRISTATE_MASK 0x08 +#define I2Sx_TRISTATE_SHIFT 3 +#define I2Sx_PULLDOWN_MASK 0x04 +#define I2Sx_PULLDOWN_SHIFT 2 +#define I2Sx_SR_MASK 0x03 +#define I2Sx_SR_SHIFT 0 +#define I2Sx_SR_8000Hz 0 +#define I2Sx_SR_16000Hz 1 +#define I2Sx_SR_44100Hz 2 +#define I2Sx_SR_48000Hz 3 + +#define INTERFACE0_ULD 0x44 +#define INTERFACE1_ULD 0x46 +#define I2Sx_ULD_R_MASK 0x70 +#define I2Sx_ULD_R_SHIFT 4 +#define I2Sx_ULD_L_MASK 0x07 +#define I2Sx_ULD_L_SHIFT 0 + +#define INTERFACE_SWAP 0x47 +#define IO_SWAP0_MASK 0x02 +#define IO_SWAP0_SHIFT 1 +#define IO_SWAP1_MASK 0x01 +#define IO_SWAP1_SHIFT 0 + +#define AB5500_FIRST_REG MIC_BIAS1 +#define AB5500_LAST_REG INTERFACE_SWAP + +#define AB5500_VIRTUAL_REG1 (AB5500_LAST_REG + 1) +#define IF0_DLD_L_PW_SHIFT 0 +#define IF0_DLD_R_PW_SHIFT 1 +#define IF0_ULD_L_PW_SHIFT 2 +#define IF0_ULD_R_PW_SHIFT 3 +#define IF1_DLD_L_PW_SHIFT 4 +#define IF1_DLD_R_PW_SHIFT 5 +#define IF1_ULD_L_PW_SHIFT 6 +#define IF1_ULD_R_PW_SHIFT 7 + +#define AB5500_VIRTUAL_REG2 (AB5500_LAST_REG + 2) +#define MIC1P1_PW_SHIFT 0 +#define MIC1N1_PW_SHIFT 1 +#define MIC1P2_PW_SHIFT 2 +#define MIC1N2_PW_SHIFT 3 +#define MIC2P1_PW_SHIFT 4 +#define MIC2N1_PW_SHIFT 5 +#define MIC2P2_PW_SHIFT 6 +#define MIC2N2_PW_SHIFT 7 + +#define AB5500_VIRTUAL_REG3 (AB5500_LAST_REG + 3) +#define SPKR1_MODE_MASK 0x03 +#define SPKR1_MODE_SHIFT 0 +#define SPKR1_MODE_VBR_VALUE 0 +#define SPKR1_MODE_CLS_D_VALUE 1 +#define SPKR1_MODE_CLS_AB_VALUE 2 +#define SPKR1_ADDER_PWR_SHIFT 2 +#define SPKR1_PWR_SHIFT 3 +#define SPKR2_MODE_MASK 0x10 +#define SPKR2_MODE_SHIFT 4 +#define SPKR2_MODE_VBR_VALUE 0 +#define SPKR2_MODE_CLS_D_VALUE 1 +#define SPKR2_ADDER_PWR_SHIFT 5 +#define SPKR2_PWR_SHIFT 6 + +#define AB5500_VIRTUAL_REG4 (AB5500_LAST_REG + 4) +#define PWM_SPKR1_PWR_SHIFT 0 +#define PWM_SPKR2_PWR_SHIFT 1 +#define PWM_SPKR1N_PWR_SHIFT 2 +#define PWM_SPKR1P_PWR_SHIFT 3 +#define PWM_SPKR2N_PWR_SHIFT 4 +#define PWM_SPKR2P_PWR_SHIFT 5 + +#define AB5500_VIRTUAL_REG5 (AB5500_LAST_REG + 5) +#define PWM_SPKR1N_SEL_SHIFT 0 +#define PWM_SPKR1P_SEL_SHIFT 1 +#define PWM_SPKR2N_SEL_SHIFT 2 +#define PWM_SPKR2P_SEL_SHIFT 3 + +#define DUMMY_REG 0xff + +/* #define SPKR1_PWR_VBR_SHIFT 0 */ +/* #define SPKR1_PWR_CLS_D_SHIFT 1 */ +/* #define SPKR1_PWR_CLS_AB_SHIFT 2 */ +/* #define SPKR2_PWR_VBR_SHIFT 3 */ +/* #define SPKR2_PWR_CLS_D_SHIFT 4 */ +/* #define SPKR2_PWR_CLS_AB_SHIFT 5 */ + +#endif diff --git a/sound/soc/codecs/ab8500_audio.c b/sound/soc/codecs/ab8500_audio.c new file mode 100644 index 00000000000..7a87890507c --- /dev/null +++ b/sound/soc/codecs/ab8500_audio.c @@ -0,0 +1,2476 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Mikko J. Lehto <mikko.lehto@symbio.com>, + * Mikko Sarmanne <mikko.sarmanne@symbio.com>, + * Jarmo K. Kuronen <jarmo.kuronen@symbio.com>, + * Ola Lilja <ola.o.lilja@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/platform_device.h> +#include <linux/mutex.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> +#include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500.h> +#include <linux/mfd/ab8500/sysctrl.h> +#include "ab8500_audio.h" + +/* To convert register definition shifts to masks */ +#define BMASK(bsft) (1 << (bsft)) + +/* Macrocell value definitions */ +#define CLK_32K_OUT2_DISABLE 0x01 +#define INACTIVE_RESET_AUDIO 0x02 +#define ENABLE_AUDIO_CLK_TO_AUDIO_BLK 0x10 +#define ENABLE_VINTCORE12_SUPPLY 0x04 +#define GPIO27_DIR_OUTPUT 0x04 +#define GPIO29_DIR_OUTPUT 0x10 +#define GPIO31_DIR_OUTPUT 0x40 +#define GPIO35_DIR_OUTPUT 0x04 + +/* Macrocell register definitions */ +#define AB8500_CTRL3_REG 0x0200 +#define AB8500_GPIO_DIR4_REG 0x1013 +#define AB8500_GPIO_DIR5_REG 0x1014 +#define AB8500_GPIO_OUT5_REG 0x1024 + +/* + * AB8500 register cache & default register settings + */ +static const u8 ab8500_reg_cache[AB8500_CACHEREGNUM] = { + 0x00, /* REG_POWERUP (0x00) */ + 0x00, /* REG_AUDSWRESET (0x01) */ + 0x00, /* REG_ADPATHENA (0x02) */ + 0x00, /* REG_DAPATHENA (0x03) */ + 0x00, /* REG_ANACONF1 (0x04) */ + 0x0F, /* REG_ANACONF2 (0x05) */ + 0x00, /* REG_DIGMICCONF (0x06) */ + 0x00, /* REG_ANACONF3 (0x07) */ + 0x00, /* REG_ANACONF4 (0x08) */ + 0x00, /* REG_DAPATHCONF (0x09) */ + 0x40, /* REG_MUTECONF (0x0A) */ + 0x00, /* REG_SHORTCIRCONF (0x0B) */ + 0x01, /* REG_ANACONF5 (0x0C) */ + 0x00, /* REG_ENVCPCONF (0x0D) */ + 0x00, /* REG_SIGENVCONF (0x0E) */ + 0x3F, /* REG_PWMGENCONF1 (0x0F) */ + 0x32, /* REG_PWMGENCONF2 (0x10) */ + 0x32, /* REG_PWMGENCONF3 (0x11) */ + 0x32, /* REG_PWMGENCONF4 (0x12) */ + 0x32, /* REG_PWMGENCONF5 (0x13) */ + 0x0F, /* REG_ANAGAIN1 (0x14) */ + 0x0F, /* REG_ANAGAIN2 (0x15) */ + 0x22, /* REG_ANAGAIN3 (0x16) */ + 0x55, /* REG_ANAGAIN4 (0x17) */ + 0x13, /* REG_DIGLINHSLGAIN (0x18) */ + 0x13, /* REG_DIGLINHSRGAIN (0x19) */ + 0x00, /* REG_ADFILTCONF (0x1A) */ + 0x00, /* REG_DIGIFCONF1 (0x1B) */ + 0x02, /* REG_DIGIFCONF2 (0x1C) */ + 0x00, /* REG_DIGIFCONF3 (0x1D) */ + 0x02, /* REG_DIGIFCONF4 (0x1E) */ + 0xCC, /* REG_ADSLOTSEL1 (0xCC) */ + 0xCC, /* REG_ADSLOTSEL2 (0xCC) */ + 0xCC, /* REG_ADSLOTSEL3 (0xCC) */ + 0xCC, /* REG_ADSLOTSEL4 (0xCC) */ + 0xCC, /* REG_ADSLOTSEL5 (0xCC) */ + 0xCC, /* REG_ADSLOTSEL6 (0xCC) */ + 0xCC, /* REG_ADSLOTSEL7 (0xCC) */ + 0xCC, /* REG_ADSLOTSEL8 (0xCC) */ + 0xCC, /* REG_ADSLOTSEL9 (0xCC) */ + 0xCC, /* REG_ADSLOTSEL10 (0xCC) */ + 0xCC, /* REG_ADSLOTSEL11 (0xCC) */ + 0xCC, /* REG_ADSLOTSEL12 (0xCC) */ + 0xCC, /* REG_ADSLOTSEL13 (0xCC) */ + 0xCC, /* REG_ADSLOTSEL14 (0xCC) */ + 0xCC, /* REG_ADSLOTSEL15 (0xCC) */ + 0xCC, /* REG_ADSLOTSEL16 (0xCC) */ + 0x00, /* REG_ADSLOTHIZCTRL1 (0x2F) */ + 0x00, /* REG_ADSLOTHIZCTRL2 (0x30) */ + 0x00, /* REG_ADSLOTHIZCTRL3 (0x31) */ + 0x00, /* REG_ADSLOTHIZCTRL4 (0x32) */ + 0x08, /* REG_DASLOTCONF1 (0x33) */ + 0x08, /* REG_DASLOTCONF2 (0x34) */ + 0x08, /* REG_DASLOTCONF3 (0x35) */ + 0x08, /* REG_DASLOTCONF4 (0x36) */ + 0x08, /* REG_DASLOTCONF5 (0x37) */ + 0x08, /* REG_DASLOTCONF6 (0x38) */ + 0x08, /* REG_DASLOTCONF7 (0x39) */ + 0x08, /* REG_DASLOTCONF8 (0x3A) */ + 0x00, /* REG_CLASSDCONF1 (0x3B) */ + 0x00, /* REG_CLASSDCONF2 (0x3C) */ + 0x84, /* REG_CLASSDCONF3 (0x3D) */ + 0x00, /* REG_DMICFILTCONF (0x3E) */ + 0xFE, /* REG_DIGMULTCONF1 (0x3F) */ + 0xC0, /* REG_DIGMULTCONF2 (0x40) */ + 0x3F, /* REG_ADDIGGAIN1 (0x41) */ + 0x3F, /* REG_ADDIGGAIN2 (0x42) */ + 0x1F, /* REG_ADDIGGAIN3 (0x43) */ + 0x1F, /* REG_ADDIGGAIN4 (0x44) */ + 0x3F, /* REG_ADDIGGAIN5 (0x45) */ + 0x3F, /* REG_ADDIGGAIN6 (0x46) */ + 0x1F, /* REG_DADIGGAIN1 (0x47) */ + 0x1F, /* REG_DADIGGAIN2 (0x48) */ + 0x3F, /* REG_DADIGGAIN3 (0x49) */ + 0x3F, /* REG_DADIGGAIN4 (0x4A) */ + 0x3F, /* REG_DADIGGAIN5 (0x4B) */ + 0x3F, /* REG_DADIGGAIN6 (0x4C) */ + 0x3F, /* REG_ADDIGLOOPGAIN1 (0x4D) */ + 0x3F, /* REG_ADDIGLOOPGAIN2 (0x4E) */ + 0x00, /* REG_HSLEARDIGGAIN (0x4F) */ + 0x00, /* REG_HSRDIGGAIN (0x50) */ + 0x1F, /* REG_SIDFIRGAIN1 (0x51) */ + 0x1F, /* REG_SIDFIRGAIN2 (0x52) */ + 0x00, /* REG_ANCCONF1 (0x53) */ + 0x00, /* REG_ANCCONF2 (0x54) */ + 0x00, /* REG_ANCCONF3 (0x55) */ + 0x00, /* REG_ANCCONF4 (0x56) */ + 0x00, /* REG_ANCCONF5 (0x57) */ + 0x00, /* REG_ANCCONF6 (0x58) */ + 0x00, /* REG_ANCCONF7 (0x59) */ + 0x00, /* REG_ANCCONF8 (0x5A) */ + 0x00, /* REG_ANCCONF9 (0x5B) */ + 0x00, /* REG_ANCCONF10 (0x5C) */ + 0x00, /* REG_ANCCONF11 (0x5D) - read only */ + 0x00, /* REG_ANCCONF12 (0x5E) - read only */ + 0x00, /* REG_ANCCONF13 (0x5F) - read only */ + 0x00, /* REG_ANCCONF14 (0x60) - read only */ + 0x00, /* REG_SIDFIRADR (0x61) */ + 0x00, /* REG_SIDFIRCOEF1 (0x62) */ + 0x00, /* REG_SIDFIRCOEF2 (0x63) */ + 0x00, /* REG_SIDFIRCONF (0x64) */ + 0x00, /* REG_AUDINTMASK1 (0x65) */ + 0x00, /* REG_AUDINTSOURCE1 (0x66) - read only */ + 0x00, /* REG_AUDINTMASK2 (0x67) */ + 0x00, /* REG_AUDINTSOURCE2 (0x68) - read only */ + 0x00, /* REG_FIFOCONF1 (0x69) */ + 0x00, /* REG_FIFOCONF2 (0x6A) */ + 0x00, /* REG_FIFOCONF3 (0x6B) */ + 0x00, /* REG_FIFOCONF4 (0x6C) */ + 0x00, /* REG_FIFOCONF5 (0x6D) */ + 0x00, /* REG_FIFOCONF6 (0x6E) */ + 0x02, /* REG_AUDREV (0x6F) - read only */ +}; + +static struct snd_soc_codec *ab8500_codec; + + +/* Reads an arbitrary register from the ab8500 chip. +*/ +static int ab8500_codec_read_reg(struct snd_soc_codec *codec, unsigned int bank, + unsigned int reg) +{ + u8 value; + int status = abx500_get_register_interruptible( + codec->dev, bank, reg, &value); + + if (status < 0) { + pr_err("%s: Register (%02x:%02x) read failed (%d).\n", + __func__, (u8)bank, (u8)reg, status); + } else { + pr_debug("Read 0x%02x from register %02x:%02x\n", + (u8)value, (u8)bank, (u8)reg); + status = value; + } + + return status; +} + +/* Writes an arbitrary register to the ab8500 chip. + */ +static int ab8500_codec_write_reg(struct snd_soc_codec *codec, unsigned int bank, + unsigned int reg, unsigned int value) +{ + int status = abx500_set_register_interruptible( + codec->dev, bank, reg, value); + + if (status < 0) { + pr_err("%s: Register (%02x:%02x) write failed (%d).\n", + __func__, (u8)bank, (u8)reg, status); + } else { + pr_debug("Wrote 0x%02x into register %02x:%02x\n", + (u8)value, (u8)bank, (u8)reg); + } + + return status; +} + +/* Reads an audio register from the cache. + */ +static unsigned int ab8500_codec_read_reg_audio(struct snd_soc_codec *codec, + unsigned int reg) +{ + u8 *cache = codec->reg_cache; + return cache[reg]; +} + +/* Reads an audio register from the hardware. + */ +static int ab8500_codec_read_reg_audio_nocache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u8 *cache = codec->reg_cache; + int value = ab8500_codec_read_reg(codec, AB8500_AUDIO, reg); + + if (value >= 0) + cache[reg] = value; + + return value; +} + +/* Writes an audio register to the hardware and cache. + */ +static int ab8500_codec_write_reg_audio(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + u8 *cache = codec->reg_cache; + int status = ab8500_codec_write_reg(codec, AB8500_AUDIO, reg, value); + + if (status >= 0) + cache[reg] = value; + + return status; +} + +/* Dumps all audio registers. + */ +static inline void ab8500_codec_dump_all_reg(struct snd_soc_codec *codec) +{ + int i; + + pr_debug("%s Enter.\n", __func__); + + for (i = AB8500_FIRST_REG; i <= AB8500_LAST_REG; i++) + ab8500_codec_read_reg_audio_nocache(codec, i); +} + +/* Updates an audio register. + */ +static inline int ab8500_codec_update_reg_audio(struct snd_soc_codec *codec, + unsigned int reg, unsigned int clr, unsigned int ins) +{ + unsigned int new, old; + + old = ab8500_codec_read_reg_audio(codec, reg); + new = (old & ~clr) | ins; + if (old == new) + return 0; + + return ab8500_codec_write_reg_audio(codec, reg, new); +} + +/* Whether widget's register definitions should be inverted or not */ +enum control_inversion { + NORMAL = 0, + INVERT = 1 +}; + +/* HS left channel mute control */ +static const struct snd_kcontrol_new dapm_hsl_mute[] = { + SOC_DAPM_SINGLE("Playback Switch", REG_MUTECONF, + REG_MUTECONF_MUTHSL, 1, INVERT), +}; + +/* HS right channel mute control */ +static const struct snd_kcontrol_new dapm_hsr_mute[] = { + SOC_DAPM_SINGLE("Playback Switch", REG_MUTECONF, + REG_MUTECONF_MUTHSR, 1, INVERT), +}; + +/* Earpiece mute control */ +static const struct snd_kcontrol_new dapm_ear_mute[] = { + SOC_DAPM_SINGLE("Playback Switch", REG_MUTECONF, + REG_MUTECONF_MUTEAR, 1, INVERT), +}; + +/* IHF left channel mute control */ +static const struct snd_kcontrol_new dapm_ihfl_mute[] = { + SOC_DAPM_SINGLE("Playback Switch", REG_DIGMULTCONF2, + REG_DIGMULTCONF2_DATOHFLEN, 1, NORMAL), +}; + +/* IHF right channel mute control */ +static const struct snd_kcontrol_new dapm_ihfr_mute[] = { + SOC_DAPM_SINGLE("Playback Switch", REG_DIGMULTCONF2, + REG_DIGMULTCONF2_DATOHFREN, 1, NORMAL), +}; + +/* Mic 1 mute control */ +static const struct snd_kcontrol_new dapm_mic1_mute[] = { + SOC_DAPM_SINGLE("Capture Switch", REG_ANACONF2, + REG_ANACONF2_MUTMIC1, 1, INVERT), +}; + +/* Mic 2 mute control */ +static const struct snd_kcontrol_new dapm_mic2_mute[] = { + SOC_DAPM_SINGLE("Capture Switch", REG_ANACONF2, + REG_ANACONF2_MUTMIC2, 1, INVERT), +}; + +/* LineIn left channel mute control */ +static const struct snd_kcontrol_new dapm_linl_mute[] = { + SOC_DAPM_SINGLE("Capture Switch", REG_ANACONF2, + REG_ANACONF2_MUTLINL, 1, INVERT), +}; + +/* LineIn right channel mute control */ +static const struct snd_kcontrol_new dapm_linr_mute[] = { + SOC_DAPM_SINGLE("Capture Switch", REG_ANACONF2, + REG_ANACONF2_MUTLINR, 1, INVERT), +}; + +/* DMic 1 mute control */ +static const struct snd_kcontrol_new dapm_dmic1_mute[] = { + SOC_DAPM_SINGLE("Capture Switch", REG_DIGMICCONF, + REG_DIGMICCONF_ENDMIC1, 1, NORMAL), +}; + +/* DMic 2 mute control */ +static const struct snd_kcontrol_new dapm_dmic2_mute[] = { + SOC_DAPM_SINGLE("Capture Switch", REG_DIGMICCONF, + REG_DIGMICCONF_ENDMIC2, 1, NORMAL), +}; + +/* DMic 3 mute control */ +static const struct snd_kcontrol_new dapm_dmic3_mute[] = { + SOC_DAPM_SINGLE("Capture Switch", REG_DIGMICCONF, + REG_DIGMICCONF_ENDMIC3, 1, NORMAL), +}; + +/* DMic 4 mute control */ +static const struct snd_kcontrol_new dapm_dmic4_mute[] = { + SOC_DAPM_SINGLE("Capture Switch", REG_DIGMICCONF, + REG_DIGMICCONF_ENDMIC4, 1, NORMAL), +}; + +/* DMic 5 mute control */ +static const struct snd_kcontrol_new dapm_dmic5_mute[] = { + SOC_DAPM_SINGLE("Capture Switch", REG_DIGMICCONF, + REG_DIGMICCONF_ENDMIC5, 1, NORMAL), +}; + +/* DMic 6 mute control */ +static const struct snd_kcontrol_new dapm_dmic6_mute[] = { + SOC_DAPM_SINGLE("Capture Switch", REG_DIGMICCONF, + REG_DIGMICCONF_ENDMIC6, 1, NORMAL), +}; + +/* ANC to Earpiece mute control */ +static const struct snd_kcontrol_new dapm_anc_ear_mute[] = { + SOC_DAPM_SINGLE("Playback Switch", REG_DIGMULTCONF1, + REG_DIGMULTCONF1_ANCSEL, 1, NORMAL), +}; + +/* Earpiece source selector control */ +static const char *enum_ear_source[] = {"Headset Left", "IHF Left"}; + +static SOC_ENUM_SINGLE_DECL(dapm_enum_ear_source, REG_DMICFILTCONF, + REG_DMICFILTCONF_DA3TOEAR, enum_ear_source); + +static const struct snd_kcontrol_new dapm_ear_source[] = { + SOC_DAPM_ENUM("Earpiece Source", dapm_enum_ear_source), +}; + +/* IHF / ANC selector control */ +static const char *enum_ihfx_sel[] = {"Audio Path", "ANC"}; + +static SOC_ENUM_SINGLE_DECL(dapm_enum_ihfl_sel, REG_DIGMULTCONF2, + REG_DIGMULTCONF2_HFLSEL, enum_ihfx_sel); + +static const struct snd_kcontrol_new dapm_ihfl_select[] = { + SOC_DAPM_ENUM("IHF Left Source", dapm_enum_ihfl_sel), +}; + +static SOC_ENUM_SINGLE_DECL(dapm_enum_ihfr_sel, REG_DIGMULTCONF2, + REG_DIGMULTCONF2_HFRSEL, enum_ihfx_sel); + +static const struct snd_kcontrol_new dapm_ihfr_select[] = { + SOC_DAPM_ENUM("IHF Right Source", dapm_enum_ihfr_sel), +}; + +/* Mic 1A or 1B selector control */ +static const char *enum_mic1ab_sel[] = {"Mic 1A", "Mic 1B"}; + +static SOC_ENUM_SINGLE_DECL(dapm_enum_mic1ab_sel, REG_ANACONF3, + REG_ANACONF3_MIC1SEL, enum_mic1ab_sel); + +static const struct snd_kcontrol_new dapm_mic1ab_select[] = { + SOC_DAPM_ENUM("Mic 1A or 1B Select", dapm_enum_mic1ab_sel), +}; + +/* Mic 2 or LineIn Right selector control */ +static const char *enum_mic2lr_sel[] = {"Mic 2", "LineIn Right"}; + +static SOC_ENUM_SINGLE_DECL(dapm_enum_mic2lr_sel, REG_ANACONF3, + REG_ANACONF3_LINRSEL, enum_mic2lr_sel); + +static const struct snd_kcontrol_new dapm_mic2lr_select[] = { + SOC_DAPM_ENUM("Mic 2 or LINR Select", dapm_enum_mic2lr_sel), +}; + +/* AD1 selector control */ +static const char *enum_ad1_sel[] = {"LineIn Left", "DMic 1"}; + +static SOC_ENUM_SINGLE_DECL(dapm_enum_ad1_sel, REG_DIGMULTCONF1, + REG_DIGMULTCONF1_AD1SEL, enum_ad1_sel); + +static const struct snd_kcontrol_new dapm_ad1_select[] = { + SOC_DAPM_ENUM("AD 1 Select", dapm_enum_ad1_sel), +}; + +/* AD2 selector control */ +static const char *enum_ad2_sel[] = {"LineIn Right", "DMic 2"}; + +static SOC_ENUM_SINGLE_DECL(dapm_enum_ad2_sel, REG_DIGMULTCONF1, + REG_DIGMULTCONF1_AD2SEL, enum_ad2_sel); + +static const struct snd_kcontrol_new dapm_ad2_select[] = { + SOC_DAPM_ENUM("AD 2 Select", dapm_enum_ad2_sel), +}; + +/* AD3 selector control */ +static const char *enum_ad3_sel[] = {"Mic 1", "DMic 3"}; + +static SOC_ENUM_SINGLE_DECL(dapm_enum_ad3_sel, REG_DIGMULTCONF1, + REG_DIGMULTCONF1_AD3SEL, enum_ad3_sel); + +static const struct snd_kcontrol_new dapm_ad3_select[] = { + SOC_DAPM_ENUM("AD 3 Select", dapm_enum_ad3_sel), +}; + +/* AD5 selector control */ +static const char *enum_ad5_sel[] = {"Mic 2", "DMic 5"}; + +static SOC_ENUM_SINGLE_DECL(dapm_enum_ad5_sel, REG_DIGMULTCONF1, + REG_DIGMULTCONF1_AD5SEL, enum_ad5_sel); + +static const struct snd_kcontrol_new dapm_ad5_select[] = { + SOC_DAPM_ENUM("AD 5 Select", dapm_enum_ad5_sel), +}; + +/* AD6 selector control */ +static const char *enum_ad6_sel[] = {"Mic 1", "DMic 6"}; + +static SOC_ENUM_SINGLE_DECL(dapm_enum_ad6_sel, REG_DIGMULTCONF1, + REG_DIGMULTCONF1_AD6SEL, enum_ad6_sel); + +static const struct snd_kcontrol_new dapm_ad6_select[] = { + SOC_DAPM_ENUM("AD 6 Select", dapm_enum_ad6_sel), +}; + +/* ANC input selector control */ +static const char *enum_anc_in_sel[] = {"Mic 1 / DMic 6", "Mic 2 / DMic 5"}; + +static SOC_ENUM_SINGLE_DECL(dapm_enum_anc_in_sel, REG_DMICFILTCONF, + REG_DMICFILTCONF_ANCINSEL, enum_anc_in_sel); + +static const struct snd_kcontrol_new dapm_anc_in_select[] = { + SOC_DAPM_ENUM("ANC Source", dapm_enum_anc_in_sel), +}; + +/* ANC enable control */ +static const char *enum_anc_dis_ena[] = {"Disabled", "Enabled"}; + +static SOC_ENUM_SINGLE_DECL(dapm_enum_anc_enable, REG_ANCCONF1, + REG_ANCCONF1_ENANC, enum_anc_dis_ena); + +static const struct snd_kcontrol_new dapm_anc_enable[] = { + SOC_DAPM_ENUM("ANC", dapm_enum_anc_enable), +}; + +/* Sidetone left input selector control */ +static const char *enum_stfir1_in_sel[] = { + "LineIn Left", "LineIn Right", "Mic 1", "Headset Left"}; + +static SOC_ENUM_SINGLE_DECL(dapm_enum_stfir1_in_sel, REG_DIGMULTCONF2, + REG_DIGMULTCONF2_FIRSID1SEL, enum_stfir1_in_sel); + +static const struct snd_kcontrol_new dapm_stfir1_in_select[] = { + SOC_DAPM_ENUM("Sidetone Left Source", dapm_enum_stfir1_in_sel), +}; + +/* Sidetone right input selector control */ +static const char *enum_stfir2_in_sel[] = { + "LineIn Right", "Mic 1", "DMic 4", "Headset Right"}; + +static SOC_ENUM_SINGLE_DECL(dapm_enum_stfir2_in_sel, REG_DIGMULTCONF2, + REG_DIGMULTCONF2_FIRSID2SEL, enum_stfir2_in_sel); + +static const struct snd_kcontrol_new dapm_stfir2_in_select[] = { + SOC_DAPM_ENUM("Sidetone Right Source", dapm_enum_stfir2_in_sel), +}; + +/* Vibra path selector control */ +static const char *enum_pwm2vibx[] = {"Audio Path", "PWM Generator"}; + +static SOC_ENUM_SINGLE_DECL(dapm_enum_pwm2vib1, REG_PWMGENCONF1, + REG_PWMGENCONF1_PWMTOVIB1, enum_pwm2vibx); + +static const struct snd_kcontrol_new dapm_pwm2vib1[] = { + SOC_DAPM_ENUM("Vibra 1 Controller", dapm_enum_pwm2vib1), +}; + +static SOC_ENUM_SINGLE_DECL(dapm_enum_pwm2vib2, REG_PWMGENCONF1, + REG_PWMGENCONF1_PWMTOVIB2, enum_pwm2vibx); + +static const struct snd_kcontrol_new dapm_pwm2vib2[] = { + SOC_DAPM_ENUM("Vibra 2 Controller", dapm_enum_pwm2vib2), +}; + +static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = { + /* Headset path */ + + SND_SOC_DAPM_AIF_IN("DA_IN1", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DA_IN2", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), + + /* XXX SwapDA12_34 */ + + SND_SOC_DAPM_MIXER("DA1 Channel Gain", REG_DAPATHENA, + REG_DAPATHENA_ENDA1, 0, NULL, 0), + SND_SOC_DAPM_MIXER("DA2 Channel Gain", REG_DAPATHENA, + REG_DAPATHENA_ENDA2, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("HSL Digital Gain", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("HSR Digital Gain", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("HSL DAC", REG_DAPATHCONF, + REG_DAPATHCONF_ENDACHSL, 0, NULL, 0), + SND_SOC_DAPM_MIXER("HSR DAC", REG_DAPATHCONF, + REG_DAPATHCONF_ENDACHSR, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("HSL DAC Driver", REG_ANACONF3, + REG_ANACONF3_ENDRVHSL, 0, NULL, 0), + SND_SOC_DAPM_MIXER("HSR DAC Driver", REG_ANACONF3, + REG_ANACONF3_ENDRVHSR, 0, NULL, 0), + + SND_SOC_DAPM_SWITCH("Headset Left", SND_SOC_NOPM, 0, 0, dapm_hsl_mute), + SND_SOC_DAPM_SWITCH("Headset Right", SND_SOC_NOPM, 0, 0, dapm_hsr_mute), + + SND_SOC_DAPM_MIXER("HSL Enable", REG_ANACONF4, + REG_ANACONF4_ENHSL, 0, NULL, 0), + SND_SOC_DAPM_MIXER("HSR Enable", REG_ANACONF4, + REG_ANACONF4_ENHSR, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("Charge Pump", REG_ANACONF5, + REG_ANACONF5_ENCPHS, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("HSL"), + SND_SOC_DAPM_OUTPUT("HSR"), + + + /* Earpiece path */ + + SND_SOC_DAPM_MUX("Earpiece Source Playback Route", + SND_SOC_NOPM, 0, 0, dapm_ear_source), + + SND_SOC_DAPM_MIXER("EAR DAC", REG_DAPATHCONF, + REG_DAPATHCONF_ENDACEAR, 0, NULL, 0), + + SND_SOC_DAPM_SWITCH("Earpiece", SND_SOC_NOPM, 0, 0, dapm_ear_mute), + + SND_SOC_DAPM_MIXER("EAR Enable", REG_ANACONF4, + REG_ANACONF4_ENEAR, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("EAR"), + + + /* Handsfree path */ + + SND_SOC_DAPM_AIF_IN("DA_IN3", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DA_IN4", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), + + /* XXX SwapDA12_34 */ + + SND_SOC_DAPM_MIXER("DA3 Channel Gain", REG_DAPATHENA, + REG_DAPATHENA_ENDA3, 0, NULL, 0), + SND_SOC_DAPM_MIXER("DA4 Channel Gain", REG_DAPATHENA, + REG_DAPATHENA_ENDA4, 0, NULL, 0), + + SND_SOC_DAPM_MUX("IHF Left Source Playback Route", + SND_SOC_NOPM, 0, 0, dapm_ihfl_select), + SND_SOC_DAPM_MUX("IHF Right Source Playback Route", + SND_SOC_NOPM, 0, 0, dapm_ihfr_select), + + SND_SOC_DAPM_SWITCH("IHF Left", SND_SOC_NOPM, 0, 0, dapm_ihfl_mute), + SND_SOC_DAPM_SWITCH("IHF Right", SND_SOC_NOPM, 0, 0, dapm_ihfr_mute), + + SND_SOC_DAPM_MIXER("IHFL DAC", REG_DAPATHCONF, + REG_DAPATHCONF_ENDACHFL, 0, NULL, 0), + SND_SOC_DAPM_MIXER("IHFR DAC", REG_DAPATHCONF, + REG_DAPATHCONF_ENDACHFR, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("IHFL Enable", REG_ANACONF4, + REG_ANACONF4_ENHFL, 0, NULL, 0), + SND_SOC_DAPM_MIXER("IHFR Enable", REG_ANACONF4, + REG_ANACONF4_ENHFR, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("IHFL"), + SND_SOC_DAPM_OUTPUT("IHFR"), + + + /* Vibrator path */ + + SND_SOC_DAPM_AIF_IN("DA_IN5", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DA_IN6", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_MIXER("DA5 Channel Gain", REG_DAPATHENA, + REG_DAPATHENA_ENDA5, 0, NULL, 0), + SND_SOC_DAPM_MIXER("DA6 Channel Gain", REG_DAPATHENA, + REG_DAPATHENA_ENDA6, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("VIB1 DAC", REG_DAPATHCONF, + REG_DAPATHCONF_ENDACVIB1, 0, NULL, 0), + SND_SOC_DAPM_MIXER("VIB2 DAC", REG_DAPATHCONF, + REG_DAPATHCONF_ENDACVIB2, 0, NULL, 0), + + SND_SOC_DAPM_INPUT("PWMGEN1"), + SND_SOC_DAPM_INPUT("PWMGEN2"), + + SND_SOC_DAPM_MUX("Vibra 1 Controller Playback Route", + SND_SOC_NOPM, 0, 0, dapm_pwm2vib1), + SND_SOC_DAPM_MUX("Vibra 2 Controller Playback Route", + SND_SOC_NOPM, 0, 0, dapm_pwm2vib2), + + SND_SOC_DAPM_MIXER("VIB1 Enable", REG_ANACONF4, + REG_ANACONF4_ENVIB1, 0, NULL, 0), + SND_SOC_DAPM_MIXER("VIB2 Enable", REG_ANACONF4, + REG_ANACONF4_ENVIB2, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("VIB1"), + SND_SOC_DAPM_OUTPUT("VIB2"), + + + /* LineIn & Microphone 2 path */ + + SND_SOC_DAPM_INPUT("LINL"), + SND_SOC_DAPM_INPUT("LINR"), + SND_SOC_DAPM_INPUT("MIC2"), + + SND_SOC_DAPM_SWITCH("LineIn Left", SND_SOC_NOPM, 0, 0, dapm_linl_mute), + SND_SOC_DAPM_SWITCH("LineIn Right", SND_SOC_NOPM, 0, 0, dapm_linr_mute), + SND_SOC_DAPM_SWITCH("Mic 2", SND_SOC_NOPM, 0, 0, dapm_mic2_mute), + + SND_SOC_DAPM_MIXER("LINL Enable", REG_ANACONF2, + REG_ANACONF2_ENLINL, 0, NULL, 0), + SND_SOC_DAPM_MIXER("LINR Enable", REG_ANACONF2, + REG_ANACONF2_ENLINR, 0, NULL, 0), + SND_SOC_DAPM_MIXER("MIC2 Enable", REG_ANACONF2, + REG_ANACONF2_ENMIC2, 0, NULL, 0), + + SND_SOC_DAPM_MUX("Mic 2 or LINR Select Capture Route", + SND_SOC_NOPM, 0, 0, dapm_mic2lr_select), + + SND_SOC_DAPM_MIXER("LINL ADC", REG_ANACONF3, + REG_ANACONF3_ENADCLINL, 0, NULL, 0), + SND_SOC_DAPM_MIXER("LINR ADC", REG_ANACONF3, + REG_ANACONF3_ENADCLINR, 0, NULL, 0), + + SND_SOC_DAPM_MUX("AD 1 Select Capture Route", + SND_SOC_NOPM, 0, 0, dapm_ad1_select), + SND_SOC_DAPM_MUX("AD 2 Select Capture Route", + SND_SOC_NOPM, 0, 0, dapm_ad2_select), + + SND_SOC_DAPM_MIXER("AD1 Channel Gain", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("AD2 Channel Gain", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("AD1 Enable", REG_ADPATHENA, + REG_ADPATHENA_ENAD12, 0, NULL, 0), + SND_SOC_DAPM_MIXER("AD2 Enable", REG_ADPATHENA, + REG_ADPATHENA_ENAD12, 0, NULL, 0), + + SND_SOC_DAPM_AIF_OUT("AD_OUT1", "ab8500_0c", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AD_OUT2", "ab8500_0c", 0, SND_SOC_NOPM, 0, 0), + + + /* Microphone 1 path */ + + SND_SOC_DAPM_INPUT("MIC1A"), + SND_SOC_DAPM_INPUT("MIC1B"), + + SND_SOC_DAPM_MUX("Mic 1A or 1B Select Capture Route", + SND_SOC_NOPM, 0, 0, dapm_mic1ab_select), + + SND_SOC_DAPM_SWITCH("Mic 1", SND_SOC_NOPM, 0, 0, dapm_mic1_mute), + + SND_SOC_DAPM_MIXER("MIC1 Enable", REG_ANACONF2, + REG_ANACONF2_ENMIC1, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("MIC1 ADC", REG_ANACONF3, + REG_ANACONF3_ENADCMIC, 0, NULL, 0), + + SND_SOC_DAPM_MUX("AD 3 Select Capture Route", + SND_SOC_NOPM, 0, 0, dapm_ad3_select), + + SND_SOC_DAPM_MIXER("AD3 Channel Gain", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("AD3 Enable", REG_ADPATHENA, + REG_ADPATHENA_ENAD34, 0, NULL, 0), + + SND_SOC_DAPM_AIF_OUT("AD_OUT3", "ab8500_0c", 0, SND_SOC_NOPM, 0, 0), + + + /* HD Capture path */ + + SND_SOC_DAPM_MUX("AD 5 Select Capture Route", + SND_SOC_NOPM, 0, 0, dapm_ad5_select), + SND_SOC_DAPM_MUX("AD 6 Select Capture Route", + SND_SOC_NOPM, 0, 0, dapm_ad6_select), + + SND_SOC_DAPM_MIXER("AD5 Channel Gain", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("AD6 Channel Gain", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("AD57 Enable", REG_ADPATHENA, + REG_ADPATHENA_ENAD5768, 0, NULL, 0), + SND_SOC_DAPM_MIXER("AD68 Enable", REG_ADPATHENA, + REG_ADPATHENA_ENAD5768, 0, NULL, 0), + + SND_SOC_DAPM_AIF_OUT("AD_OUT57", "ab8500_0c", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AD_OUT68", "ab8500_0c", 0, SND_SOC_NOPM, 0, 0), + + + /* Digital Microphone path */ + + SND_SOC_DAPM_INPUT("DMIC1"), + SND_SOC_DAPM_INPUT("DMIC2"), + SND_SOC_DAPM_INPUT("DMIC3"), + SND_SOC_DAPM_INPUT("DMIC4"), + SND_SOC_DAPM_INPUT("DMIC5"), + SND_SOC_DAPM_INPUT("DMIC6"), + + SND_SOC_DAPM_SWITCH("DMic 1", SND_SOC_NOPM, 0, 0, dapm_dmic1_mute), + SND_SOC_DAPM_SWITCH("DMic 2", SND_SOC_NOPM, 0, 0, dapm_dmic2_mute), + SND_SOC_DAPM_SWITCH("DMic 3", SND_SOC_NOPM, 0, 0, dapm_dmic3_mute), + SND_SOC_DAPM_SWITCH("DMic 4", SND_SOC_NOPM, 0, 0, dapm_dmic4_mute), + SND_SOC_DAPM_SWITCH("DMic 5", SND_SOC_NOPM, 0, 0, dapm_dmic5_mute), + SND_SOC_DAPM_SWITCH("DMic 6", SND_SOC_NOPM, 0, 0, dapm_dmic6_mute), + + SND_SOC_DAPM_MIXER("AD4 Channel Gain", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("AD4 Enable", REG_ADPATHENA, + REG_ADPATHENA_ENAD34, 0, NULL, 0), + + SND_SOC_DAPM_AIF_OUT("AD_OUT4", "ab8500_0c", 0, SND_SOC_NOPM, 0, 0), + + + /* LineIn Bypass path */ + + SND_SOC_DAPM_MIXER("LINL to HSL Gain", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("LINR to HSR Gain", SND_SOC_NOPM, 0, 0, NULL, 0), + + + /* Analog Loopback path */ + + SND_SOC_DAPM_MIXER("AD1 to IHFL Gain", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("AD2 to IHFR Gain", SND_SOC_NOPM, 0, 0, NULL, 0), + + + /* Acoustical Noise Cancellation path */ + + SND_SOC_DAPM_MUX("ANC Source Playback Route", + SND_SOC_NOPM, 0, 0, dapm_anc_in_select), + + SND_SOC_DAPM_MUX("ANC Playback Switch", + SND_SOC_NOPM, 0, 0, dapm_anc_enable), + + SND_SOC_DAPM_SWITCH("ANC to Earpiece", + SND_SOC_NOPM, 0, 0, dapm_anc_ear_mute), + + + /* Sidetone Filter path */ + + SND_SOC_DAPM_MUX("Sidetone Left Source Playback Route", + SND_SOC_NOPM, 0, 0, dapm_stfir1_in_select), + SND_SOC_DAPM_MUX("Sidetone Right Source Playback Route", + SND_SOC_NOPM, 0, 0, dapm_stfir2_in_select), + + SND_SOC_DAPM_MIXER("STFIR1 Control", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("STFIR2 Control", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("STFIR1 Gain", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("STFIR2 Gain", SND_SOC_NOPM, 0, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_route intercon[] = { + /* Headset path */ + + {"DA1 Channel Gain", NULL, "DA_IN1"}, + {"DA2 Channel Gain", NULL, "DA_IN2"}, + + {"HSL Digital Gain", NULL, "DA1 Channel Gain"}, + {"HSR Digital Gain", NULL, "DA2 Channel Gain"}, + + {"HSL DAC", NULL, "HSL Digital Gain"}, + {"HSR DAC", NULL, "HSR Digital Gain"}, + + {"HSL DAC Driver", NULL, "HSL DAC"}, + {"HSR DAC Driver", NULL, "HSR DAC"}, + + {"Headset Left", "Playback Switch", "HSL DAC Driver"}, + {"Headset Right", "Playback Switch", "HSR DAC Driver"}, + + {"HSL Enable", NULL, "Headset Left"}, + {"HSR Enable", NULL, "Headset Right"}, + + {"Charge Pump", NULL, "HSL Enable"}, + {"Charge Pump", NULL, "HSR Enable"}, + + {"HSL", NULL, "Charge Pump"}, + {"HSR", NULL, "Charge Pump"}, + + + /* Earpiece path */ + + {"Earpiece Source Playback Route", "Headset Left", "HSL Digital Gain"}, + {"Earpiece Source Playback Route", "IHF Left", "IHF Left"}, + + {"EAR DAC", NULL, "Earpiece Source Playback Route"}, + + {"Earpiece", "Playback Switch", "EAR DAC"}, + + {"EAR Enable", NULL, "Earpiece"}, + + {"EAR", NULL, "EAR Enable"}, + + + /* Handsfree path */ + + {"DA3 Channel Gain", NULL, "DA_IN3"}, + {"DA4 Channel Gain", NULL, "DA_IN4"}, + + {"IHF Left Source Playback Route", "Audio Path", "DA3 Channel Gain"}, + {"IHF Right Source Playback Route", "Audio Path", "DA4 Channel Gain"}, + + {"IHF Left", "Playback Switch", "IHF Left Source Playback Route"}, + {"IHF Right", "Playback Switch", "IHF Right Source Playback Route"}, + + {"IHFL DAC", NULL, "IHF Left"}, + {"IHFR DAC", NULL, "IHF Right"}, + + {"IHFL Enable", NULL, "IHFL DAC"}, + {"IHFR Enable", NULL, "IHFR DAC"}, + + {"IHFL", NULL, "IHFL Enable"}, + {"IHFR", NULL, "IHFR Enable"}, + + + /* Vibrator path */ + + {"DA5 Channel Gain", NULL, "DA_IN5"}, + {"DA6 Channel Gain", NULL, "DA_IN6"}, + + {"VIB1 DAC", NULL, "DA5 Channel Gain"}, + {"VIB2 DAC", NULL, "DA6 Channel Gain"}, + + {"Vibra 1 Controller Playback Route", "Audio Path", "VIB1 DAC"}, + {"Vibra 2 Controller Playback Route", "Audio Path", "VIB2 DAC"}, + {"Vibra 1 Controller Playback Route", "PWM Generator", "PWMGEN1"}, + {"Vibra 2 Controller Playback Route", "PWM Generator", "PWMGEN2"}, + + {"VIB1 Enable", NULL, "Vibra 1 Controller Playback Route"}, + {"VIB2 Enable", NULL, "Vibra 2 Controller Playback Route"}, + + {"VIB1", NULL, "VIB1 Enable"}, + {"VIB2", NULL, "VIB2 Enable"}, + + + /* LineIn & Microphone 2 path */ + + {"LineIn Left", "Capture Switch", "LINL"}, + {"LineIn Right", "Capture Switch", "LINR"}, + {"Mic 2", "Capture Switch", "MIC2"}, + + {"LINL Enable", NULL, "LineIn Left"}, + {"LINR Enable", NULL, "LineIn Right"}, + {"MIC2 Enable", NULL, "Mic 2"}, + + {"Mic 2 or LINR Select Capture Route", "LineIn Right", "LINR Enable"}, + {"Mic 2 or LINR Select Capture Route", "Mic 2", "MIC2 Enable"}, + + {"LINL ADC", NULL, "LINL Enable"}, + {"LINR ADC", NULL, "Mic 2 or LINR Select Capture Route"}, + + {"AD 1 Select Capture Route", "LineIn Left", "LINL ADC"}, + {"AD 2 Select Capture Route", "LineIn Right", "LINR ADC"}, + + {"AD1 Channel Gain", NULL, "AD 1 Select Capture Route"}, + {"AD2 Channel Gain", NULL, "AD 2 Select Capture Route"}, + + {"AD1 Enable", NULL, "AD1 Channel Gain"}, + {"AD2 Enable", NULL, "AD2 Channel Gain"}, + + {"AD_OUT1", NULL, "AD1 Enable"}, + {"AD_OUT2", NULL, "AD2 Enable"}, + + + /* Microphone 1 path */ + + {"Mic 1A or 1B Select Capture Route", "Mic 1A", "MIC1A"}, + {"Mic 1A or 1B Select Capture Route", "Mic 1B", "MIC1B"}, + + {"Mic 1", "Capture Switch", "Mic 1A or 1B Select Capture Route"}, + + {"MIC1 Enable", NULL, "Mic 1"}, + + {"MIC1 ADC", NULL, "MIC1 Enable"}, + + {"AD 3 Select Capture Route", "Mic 1", "MIC1 ADC"}, + + {"AD3 Channel Gain", NULL, "AD 3 Select Capture Route"}, + + {"AD3 Enable", NULL, "AD3 Channel Gain"}, + + {"AD_OUT3", NULL, "AD3 Enable"}, + + + /* HD Capture path */ + + {"AD 5 Select Capture Route", "Mic 2", "LINR ADC"}, + {"AD 6 Select Capture Route", "Mic 1", "MIC1 ADC"}, + + {"AD5 Channel Gain", NULL, "AD 5 Select Capture Route"}, + {"AD6 Channel Gain", NULL, "AD 6 Select Capture Route"}, + + {"AD57 Enable", NULL, "AD5 Channel Gain"}, + {"AD68 Enable", NULL, "AD6 Channel Gain"}, + + {"AD_OUT57", NULL, "AD57 Enable"}, + {"AD_OUT68", NULL, "AD68 Enable"}, + + + /* Digital Microphone path */ + + {"DMic 1", "Capture Switch", "DMIC1"}, + {"DMic 2", "Capture Switch", "DMIC2"}, + {"DMic 3", "Capture Switch", "DMIC3"}, + {"DMic 4", "Capture Switch", "DMIC4"}, + {"DMic 5", "Capture Switch", "DMIC5"}, + {"DMic 6", "Capture Switch", "DMIC6"}, + + {"AD 1 Select Capture Route", "DMic 1", "DMic 1"}, + {"AD 2 Select Capture Route", "DMic 2", "DMic 2"}, + {"AD 3 Select Capture Route", "DMic 3", "DMic 3"}, + {"AD 5 Select Capture Route", "DMic 5", "DMic 5"}, + {"AD 6 Select Capture Route", "DMic 6", "DMic 6"}, + + {"AD4 Channel Gain", NULL, "DMic 4"}, + + {"AD4 Enable", NULL, "AD4 Channel Gain"}, + + {"AD_OUT4", NULL, "AD4 Enable"}, + + + /* LineIn Bypass path */ + + {"LINL to HSL Gain", NULL, "LINL Enable"}, + {"LINR to HSR Gain", NULL, "LINR Enable"}, + + {"HSL DAC Driver", NULL, "LINL to HSL Gain"}, + {"HSR DAC Driver", NULL, "LINR to HSR Gain"}, + + + /* Analog Loopback path */ + + {"AD1 to IHFL Gain", NULL, "AD1 Channel Gain"}, + {"AD2 to IHFR Gain", NULL, "AD2 Channel Gain"}, + + {"IHFL DAC", NULL, "AD1 to IHFL Gain"}, + {"IHFR DAC", NULL, "AD2 to IHFR Gain"}, + + + /* Acoustical Noise Cancellation path */ + + {"ANC Source Playback Route", "Mic 2 / DMic 5", "AD5 Channel Gain"}, + {"ANC Source Playback Route", "Mic 1 / DMic 6", "AD6 Channel Gain"}, + + {"ANC Playback Switch", "Enabled", "ANC Source Playback Route"}, + + {"IHF Left Source Playback Route", "ANC", "ANC Playback Switch"}, + {"IHF Right Source Playback Route", "ANC", "ANC Playback Switch"}, + {"ANC to Earpiece", "Playback Switch", "ANC Playback Switch"}, + + {"HSL Digital Gain", NULL, "ANC to Earpiece"}, + + + /* Sidetone Filter path */ + + {"Sidetone Left Source Playback Route", "LineIn Left", "AD1 Enable"}, + {"Sidetone Left Source Playback Route", "LineIn Right", "AD2 Enable"}, + {"Sidetone Left Source Playback Route", "Mic 1", "AD3 Enable"}, + {"Sidetone Left Source Playback Route", "Headset Left", "DA_IN1"}, + {"Sidetone Right Source Playback Route", "LineIn Right", "AD2 Enable"}, + {"Sidetone Right Source Playback Route", "Mic 1", "AD3 Enable"}, + {"Sidetone Right Source Playback Route", "DMic 4", "AD4 Enable"}, + {"Sidetone Right Source Playback Route", "Headset Right", "DA_IN2"}, + + {"STFIR1 Control", NULL, "Sidetone Left Source Playback Route"}, + {"STFIR2 Control", NULL, "Sidetone Right Source Playback Route"}, + + {"STFIR1 Gain", NULL, "STFIR1 Control"}, + {"STFIR2 Gain", NULL, "STFIR2 Control"}, + + {"DA1 Channel Gain", NULL, "STFIR1 Gain"}, + {"DA2 Channel Gain", NULL, "STFIR2 Gain"}, +}; + +/* from -31 to 31 dB in 1 dB steps (mute instead of -32 dB) */ +static DECLARE_TLV_DB_SCALE(adx_dig_gain_tlv, -3200, 100, 1); + +/* from -62 to 0 dB in 1 dB steps (mute instead of -63 dB) */ +static DECLARE_TLV_DB_SCALE(dax_dig_gain_tlv, -6300, 100, 1); + +/* from 0 to 8 dB in 1 dB steps (mute instead of -1 dB) */ +static DECLARE_TLV_DB_SCALE(hs_ear_dig_gain_tlv, -100, 100, 1); + +/* from -30 to 0 dB in 1 dB steps (mute instead of -31 dB) */ +static DECLARE_TLV_DB_SCALE(stfir_dig_gain_tlv, -3100, 100, 1); + +/* from -32 to -20 dB in 4 dB steps / from -18 to 2 dB in 2 dB steps */ +static const unsigned int hs_gain_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0, 3, TLV_DB_SCALE_ITEM(-3200, 400, 0), + 4, 15, TLV_DB_SCALE_ITEM(-1800, 200, 0), +}; + +/* from 0 to 31 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(mic_gain_tlv, 0, 100, 0); + +/* from -10 to 20 dB in 2 dB steps */ +static DECLARE_TLV_DB_SCALE(lin_gain_tlv, -1000, 200, 0); + +/* from -36 to 0 dB in 2 dB steps (mute instead of -38 dB) */ +static DECLARE_TLV_DB_SCALE(lin2hs_gain_tlv, -3800, 200, 1); + +static const char *enum_ena_dis[] = {"Enabled", "Disabled"}; +static const char *enum_dis_ena[] = {"Disabled", "Enabled"}; + +static SOC_ENUM_SINGLE_DECL(soc_enum_hshpen, + REG_ANACONF1, REG_ANACONF1_HSHPEN, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_hslowpow, + REG_ANACONF1, REG_ANACONF1_HSLOWPOW, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_daclowpow1, + REG_ANACONF1, REG_ANACONF1_DACLOWPOW1, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_daclowpow0, + REG_ANACONF1, REG_ANACONF1_DACLOWPOW0, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_eardaclowpow, + REG_ANACONF1, REG_ANACONF1_EARDACLOWPOW, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_eardrvlowpow, + REG_ANACONF1, REG_ANACONF1_EARDRVLOWPOW, enum_dis_ena); + +static const char *enum_earselcm[] = {"0.95V", "1.10V", "1.27V", "1.58V"}; +static SOC_ENUM_SINGLE_DECL(soc_enum_earselcm, + REG_ANACONF1, REG_ANACONF1_EARSELCM, enum_earselcm); + +static const char *enum_hsfadspeed[] = {"2ms", "0.5ms", "10.6ms", "5ms"}; +static SOC_ENUM_SINGLE_DECL(soc_enum_hsfadspeed, + REG_DIGMICCONF, REG_DIGMICCONF_HSFADSPEED, enum_hsfadspeed); + +static const char *enum_envdetthre[] = { + "250mV", "300mV", "350mV", "400mV", + "450mV", "500mV", "550mV", "600mV", + "650mV", "700mV", "750mV", "800mV", + "850mV", "900mV", "950mV", "1.00V" }; +static SOC_ENUM_SINGLE_DECL(soc_enum_envdetcpen, + REG_SIGENVCONF, REG_SIGENVCONF_ENVDETCPEN, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_envdeththre, + REG_ENVCPCONF, REG_ENVCPCONF_ENVDETHTHRE, enum_envdetthre); +static SOC_ENUM_SINGLE_DECL(soc_enum_envdetlthre, + REG_ENVCPCONF, REG_ENVCPCONF_ENVDETLTHRE, enum_envdetthre); + +static const char* enum_envdettime[] = { + "26.6us", "53.2us", "106us", "213us", + "426us", "851us", "1.70ms", "3.40ms", + "6.81ms", "13.6ms", "27.2ms", "54.5ms", + "109ms", "218ms", "436ms", "872ms" }; +static SOC_ENUM_SINGLE_DECL(soc_enum_envdettime, + REG_SIGENVCONF, REG_SIGENVCONF_ENVDETTIME, enum_envdettime); + +static const char *enum_ensemicx[] = {"Differential", "Single Ended"}; +static SOC_ENUM_SINGLE_DECL(soc_enum_ensemic1, + REG_ANAGAIN1, REG_ANAGAINX_ENSEMICX, enum_ensemicx); +static SOC_ENUM_SINGLE_DECL(soc_enum_ensemic2, + REG_ANAGAIN2, REG_ANAGAINX_ENSEMICX, enum_ensemicx); +static SOC_ENUM_SINGLE_DECL(soc_enum_lowpowmic1, + REG_ANAGAIN1, REG_ANAGAINX_LOWPOWMICX, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_lowpowmic2, + REG_ANAGAIN2, REG_ANAGAINX_LOWPOWMICX, enum_dis_ena); + +static SOC_ENUM_DOUBLE_DECL(soc_enum_ad12nh, REG_ADFILTCONF, + REG_ADFILTCONF_AD1NH, REG_ADFILTCONF_AD2NH, enum_ena_dis); +static SOC_ENUM_DOUBLE_DECL(soc_enum_ad34nh, REG_ADFILTCONF, + REG_ADFILTCONF_AD3NH, REG_ADFILTCONF_AD4NH, enum_ena_dis); + +static const char *enum_av_mode[] = {"Audio", "Voice"}; +static SOC_ENUM_DOUBLE_DECL(soc_enum_ad12voice, REG_ADFILTCONF, + REG_ADFILTCONF_AD1VOICE, REG_ADFILTCONF_AD2VOICE, enum_av_mode); +static SOC_ENUM_DOUBLE_DECL(soc_enum_ad34voice, REG_ADFILTCONF, + REG_ADFILTCONF_AD3VOICE, REG_ADFILTCONF_AD4VOICE, enum_av_mode); + +static SOC_ENUM_SINGLE_DECL(soc_enum_da12voice, + REG_DASLOTCONF1, REG_DASLOTCONF1_DA12VOICE, enum_av_mode); +static SOC_ENUM_SINGLE_DECL(soc_enum_da34voice, + REG_DASLOTCONF3, REG_DASLOTCONF3_DA34VOICE, enum_av_mode); +static SOC_ENUM_SINGLE_DECL(soc_enum_da56voice, + REG_DASLOTCONF5, REG_DASLOTCONF5_DA56VOICE, enum_av_mode); + +static SOC_ENUM_SINGLE_DECL(soc_enum_swapda12_34, + REG_DASLOTCONF1, REG_DASLOTCONF1_SWAPDA12_34, enum_dis_ena); + +static SOC_ENUM_DOUBLE_DECL(soc_enum_vib12swap, REG_CLASSDCONF1, + REG_CLASSDCONF1_VIB1SWAPEN, REG_CLASSDCONF1_VIB2SWAPEN, enum_dis_ena); +static SOC_ENUM_DOUBLE_DECL(soc_enum_hflrswap, REG_CLASSDCONF1, + REG_CLASSDCONF1_HFLSWAPEN, REG_CLASSDCONF1_HFRSWAPEN, enum_dis_ena); + +static SOC_ENUM_DOUBLE_DECL(soc_enum_fir01byp, REG_CLASSDCONF2, + REG_CLASSDCONF2_FIRBYP0, REG_CLASSDCONF2_FIRBYP1, enum_dis_ena); +static SOC_ENUM_DOUBLE_DECL(soc_enum_fir23byp, REG_CLASSDCONF2, + REG_CLASSDCONF2_FIRBYP2, REG_CLASSDCONF2_FIRBYP3, enum_dis_ena); +static SOC_ENUM_DOUBLE_DECL(soc_enum_highvol01, REG_CLASSDCONF2, + REG_CLASSDCONF2_HIGHVOLEN0, REG_CLASSDCONF2_HIGHVOLEN1, enum_dis_ena); +static SOC_ENUM_DOUBLE_DECL(soc_enum_highvol23, REG_CLASSDCONF2, + REG_CLASSDCONF2_HIGHVOLEN2, REG_CLASSDCONF2_HIGHVOLEN3, enum_dis_ena); + +static const char *enum_sinc53[] = {"Sinc 5", "Sinc 3"}; +static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic12sinc, REG_DMICFILTCONF, + REG_DMICFILTCONF_DMIC1SINC3, REG_DMICFILTCONF_DMIC2SINC3, enum_sinc53); +static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic34sinc, REG_DMICFILTCONF, + REG_DMICFILTCONF_DMIC3SINC3, REG_DMICFILTCONF_DMIC4SINC3, enum_sinc53); +static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic56sinc, REG_DMICFILTCONF, + REG_DMICFILTCONF_DMIC5SINC3, REG_DMICFILTCONF_DMIC6SINC3, enum_sinc53); + +static const char *enum_da2hslr[] = {"Sidetone", "Audio Path"}; +static SOC_ENUM_DOUBLE_DECL(soc_enum_da2hslr, REG_DIGMULTCONF1, + REG_DIGMULTCONF1_DATOHSLEN, REG_DIGMULTCONF1_DATOHSREN, enum_da2hslr); + +static const char *enum_sinc31[] = {"Sinc 3", "Sinc 1"}; +static SOC_ENUM_SINGLE_DECL(soc_enum_hsesinc, + REG_HSLEARDIGGAIN, REG_HSLEARDIGGAIN_HSSINC1, enum_sinc31); + +static const char *enum_fadespeed[] = {"1ms", "4ms", "8ms", "16ms"}; +static SOC_ENUM_SINGLE_DECL(soc_enum_fadespeed, + REG_HSRDIGGAIN, REG_HSRDIGGAIN_FADESPEED, enum_fadespeed); + +/* Digital interface controls */ + +/* Clocks */ +static SOC_ENUM_SINGLE_DECL(soc_enum_mastgen, + REG_DIGIFCONF1, REG_DIGIFCONF1_ENMASTGEN, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_fsbitclk0, + REG_DIGIFCONF1, REG_DIGIFCONF1_ENFSBITCLK0, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_fsbitclk1, + REG_DIGIFCONF1, REG_DIGIFCONF1_ENFSBITCLK1, enum_dis_ena); + +/* DA from slot mapping */ +static const char *enum_da_from_slot_map[] = {"SLOT0", + "SLOT1", + "SLOT2", + "SLOT3", + "SLOT4", + "SLOT5", + "SLOT6", + "SLOT7", + "SLOT8", + "SLOT9", + "SLOT10", + "SLOT11", + "SLOT12", + "SLOT13", + "SLOT14", + "SLOT15", + "SLOT16", + "SLOT17", + "SLOT18", + "SLOT19", + "SLOT20", + "SLOT21", + "SLOT22", + "SLOT23", + "SLOT24", + "SLOT25", + "SLOT26", + "SLOT27", + "SLOT28", + "SLOT29", + "SLOT30", + "SLOT31"}; +static SOC_ENUM_SINGLE_DECL(soc_enum_da1slotmap, + REG_DASLOTCONF1, REG_DASLOTCONFX_SLTODAX_SHIFT, enum_da_from_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_da2slotmap, + REG_DASLOTCONF2, REG_DASLOTCONFX_SLTODAX_SHIFT, enum_da_from_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_da3slotmap, + REG_DASLOTCONF3, REG_DASLOTCONFX_SLTODAX_SHIFT, enum_da_from_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_da4slotmap, + REG_DASLOTCONF4, REG_DASLOTCONFX_SLTODAX_SHIFT, enum_da_from_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_da5slotmap, + REG_DASLOTCONF5, REG_DASLOTCONFX_SLTODAX_SHIFT, enum_da_from_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_da6slotmap, + REG_DASLOTCONF6, REG_DASLOTCONFX_SLTODAX_SHIFT, enum_da_from_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_da7slotmap, + REG_DASLOTCONF7, REG_DASLOTCONFX_SLTODAX_SHIFT, enum_da_from_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_da8slotmap, + REG_DASLOTCONF8, REG_DASLOTCONFX_SLTODAX_SHIFT, enum_da_from_slot_map); + +/* AD to slot mapping */ +static const char *enum_ad_to_slot_map[] = {"AD_OUT1", + "AD_OUT2", + "AD_OUT3", + "AD_OUT4", + "AD_OUT5", + "AD_OUT6", + "AD_OUT7", + "AD_OUT8", + "zeroes", + "tristate"}; +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot0map, + REG_ADSLOTSEL1, REG_ADSLOTSELX_EVEN_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot1map, + REG_ADSLOTSEL1, REG_ADSLOTSELX_ODD_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot2map, + REG_ADSLOTSEL2, REG_ADSLOTSELX_EVEN_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot3map, + REG_ADSLOTSEL2, REG_ADSLOTSELX_ODD_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot4map, + REG_ADSLOTSEL3, REG_ADSLOTSELX_EVEN_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot5map, + REG_ADSLOTSEL3, REG_ADSLOTSELX_ODD_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot6map, + REG_ADSLOTSEL4, REG_ADSLOTSELX_EVEN_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot7map, + REG_ADSLOTSEL4, REG_ADSLOTSELX_ODD_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot8map, + REG_ADSLOTSEL5, REG_ADSLOTSELX_EVEN_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot9map, + REG_ADSLOTSEL5, REG_ADSLOTSELX_ODD_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot10map, + REG_ADSLOTSEL6, REG_ADSLOTSELX_EVEN_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot11map, + REG_ADSLOTSEL6, REG_ADSLOTSELX_ODD_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot12map, + REG_ADSLOTSEL7, REG_ADSLOTSELX_EVEN_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot13map, + REG_ADSLOTSEL7, REG_ADSLOTSELX_ODD_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot14map, + REG_ADSLOTSEL8, REG_ADSLOTSELX_EVEN_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot15map, + REG_ADSLOTSEL8, REG_ADSLOTSELX_ODD_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot16map, + REG_ADSLOTSEL9, REG_ADSLOTSELX_EVEN_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot17map, + REG_ADSLOTSEL9, REG_ADSLOTSELX_ODD_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot18map, + REG_ADSLOTSEL10, REG_ADSLOTSELX_EVEN_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot19map, + REG_ADSLOTSEL10, REG_ADSLOTSELX_ODD_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot20map, + REG_ADSLOTSEL11, REG_ADSLOTSELX_EVEN_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot21map, + REG_ADSLOTSEL11, REG_ADSLOTSELX_ODD_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot22map, + REG_ADSLOTSEL12, REG_ADSLOTSELX_EVEN_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot23map, + REG_ADSLOTSEL12, REG_ADSLOTSELX_ODD_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot24map, + REG_ADSLOTSEL13, REG_ADSLOTSELX_EVEN_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot25map, + REG_ADSLOTSEL13, REG_ADSLOTSELX_ODD_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot26map, + REG_ADSLOTSEL14, REG_ADSLOTSELX_EVEN_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot27map, + REG_ADSLOTSEL14, REG_ADSLOTSELX_ODD_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot28map, + REG_ADSLOTSEL15, REG_ADSLOTSELX_EVEN_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot29map, + REG_ADSLOTSEL15, REG_ADSLOTSELX_ODD_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot30map, + REG_ADSLOTSEL16, REG_ADSLOTSELX_EVEN_SHIFT, enum_ad_to_slot_map); +static SOC_ENUM_SINGLE_DECL(soc_enum_adslot31map, + REG_ADSLOTSEL16, REG_ADSLOTSELX_ODD_SHIFT, enum_ad_to_slot_map); + +/* Digital loopback */ +static SOC_ENUM_SINGLE_DECL(soc_enum_ad1loop, + REG_DASLOTCONF1, REG_DASLOTCONF1_DAI7TOADO1, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_ad2loop, + REG_DASLOTCONF2, REG_DASLOTCONF2_DAI8TOADO2, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_ad3loop, + REG_DASLOTCONF3, REG_DASLOTCONF3_DAI7TOADO3, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_ad4loop, + REG_DASLOTCONF4, REG_DASLOTCONF4_DAI8TOADO4, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_ad5loop, + REG_DASLOTCONF5, REG_DASLOTCONF5_DAI7TOADO5, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_ad6loop, + REG_DASLOTCONF6, REG_DASLOTCONF6_DAI8TOADO6, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_ad7loop, + REG_DASLOTCONF7, REG_DASLOTCONF7_DAI8TOADO7, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_ad8loop, + REG_DASLOTCONF8, REG_DASLOTCONF8_DAI7TOADO8, enum_dis_ena); + +/* Burst mode */ +static SOC_ENUM_SINGLE_DECL(soc_enum_if0fifoen, + REG_DIGIFCONF3, REG_DIGIFCONF3_IF0BFIFOEN, enum_dis_ena); +static const char *enum_mask[] = {"Unmasked", "Masked"}; +static SOC_ENUM_SINGLE_DECL(soc_enum_bfifomask, + REG_FIFOCONF1, REG_FIFOCONF1_BFIFOMASK, enum_mask); +static const char *enum_bitclk0[] = {"19_2_MHz", "38_4_MHz"}; +static SOC_ENUM_SINGLE_DECL(soc_enum_bfifo19m2, + REG_FIFOCONF1, REG_FIFOCONF1_BFIFO19M2, enum_bitclk0); + +static const char *enum_slavemaster[] = {"Slave", "Master"}; +static SOC_ENUM_SINGLE_DECL(soc_enum_bfifomast, + REG_FIFOCONF3, REG_FIFOCONF3_BFIFOMAST_SHIFT, enum_slavemaster); +static SOC_ENUM_SINGLE_DECL(soc_enum_bfifoint, + REG_FIFOCONF3, REG_FIFOCONF3_BFIFORUN_SHIFT, enum_dis_ena); + +/* Sidetone */ + +static int st_fir_value_control_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = REG_MASK_ALL; + + return 0; +} + +static int st_fir_value_control_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} + +static int st_fir_value_control_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret; + unsigned int val_msb = (int)ucontrol->value.integer.value[0] / 256; + unsigned int val_lsb = (int)ucontrol->value.integer.value[0] - val_msb * 256; + ret = ab8500_codec_write_reg_audio(ab8500_codec, REG_SIDFIRCOEF1, val_msb); + ret |= ab8500_codec_write_reg_audio(ab8500_codec, REG_SIDFIRCOEF2, val_lsb); + if (ret < 0) { + pr_err("%s: ERROR: Failed to write FIR-coeffecient!\n", __func__); + return 0; + } + return 1; +} + +static const struct snd_kcontrol_new st_fir_value_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Sidetone FIR Coeffecient Value", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = st_fir_value_control_info, + .get = st_fir_value_control_get, + .put = st_fir_value_control_put, + .private_value = 1 /* ULPCLK */ +}; + +static int st_fir_apply_control_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item) { + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, "Apply"); + } else { + strcpy(uinfo->value.enumerated.name, "Ready"); + } + return 0; +} + +static int st_fir_apply_control_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int reg = ab8500_codec_read_reg_audio(ab8500_codec, REG_SIDFIRADR); + ucontrol->value.enumerated.item[0] = reg & BMASK(REG_SIDFIRADR_FIRSIDSET); + + return 0; +} + +static int st_fir_apply_control_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret; + + if (ucontrol->value.enumerated.item[0] != 0) { + ret = ab8500_codec_write_reg_audio(ab8500_codec, + REG_SIDFIRADR, + BMASK(REG_SIDFIRADR_FIRSIDSET)); + if (ret < 0) { + pr_err("%s: ERROR: Failed to apply FIR-coeffecients!\n", __func__); + return 0; + } + pr_debug("%s: FIR-coeffecients applied.\n", __func__); + } + + ret = ab8500_codec_write_reg_audio(ab8500_codec, REG_SIDFIRADR, 0); + if (ret < 0) + pr_err("%s: ERROR: Going to ready failed!\n", __func__); + + return 1; +} + +static const struct snd_kcontrol_new st_fir_apply_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Sidetone FIR Apply Coeffecients", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = st_fir_apply_control_info, + .get = st_fir_apply_control_get, + .put = st_fir_apply_control_put, + .private_value = 0 /* Ready */ +}; + +static const char *enum_coeffctrl[] = {"Ready", "Apply"}; +static SOC_ENUM_SINGLE_DECL(soc_enum_coeffctrl, + REG_SIDFIRADR, REG_SIDFIRADR_FIRSIDSET, enum_coeffctrl); + +/* TODO: move to DAPM */ +static SOC_ENUM_SINGLE_DECL(soc_enum_enfirsids, + REG_SIDFIRCONF, REG_SIDFIRCONF_ENFIRSIDS, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_parlhf, + REG_CLASSDCONF1, REG_CLASSDCONF1_PARLHF, enum_dis_ena); +static SOC_ENUM_SINGLE_DECL(soc_enum_parlvib, + REG_CLASSDCONF1, REG_CLASSDCONF1_PARLVIB, enum_dis_ena); + +static struct snd_kcontrol_new ab8500_snd_controls[] = { + SOC_ENUM("Headset High Pass Playback Switch", soc_enum_hshpen), + SOC_ENUM("Headset Low Power Playback Switch", soc_enum_hslowpow), + SOC_ENUM("Headset DAC Low Power Playback Switch", soc_enum_daclowpow1), + SOC_ENUM("Headset DAC Drv Low Power Playback Switch", + soc_enum_daclowpow0), + SOC_ENUM("Earpiece DAC Low Power Playback Switch", + soc_enum_eardaclowpow), + SOC_ENUM("Earpiece DAC Drv Low Power Playback Switch", + soc_enum_eardrvlowpow), + SOC_ENUM("Earpiece Common Mode Playback Switch", soc_enum_earselcm), + + SOC_ENUM("Headset Fade Speed Playback Switch", soc_enum_hsfadspeed), + + SOC_ENUM("Charge Pump High Threshold For Low Voltage", + soc_enum_envdeththre), + SOC_ENUM("Charge Pump Low Threshold For Low Voltage", + soc_enum_envdetlthre), + SOC_ENUM("Charge Pump Envelope Detection", soc_enum_envdetcpen), + SOC_ENUM("Charge Pump Envelope Detection Decay Time", + soc_enum_envdettime), + + SOC_ENUM("Mic 1 Type Capture Switch", soc_enum_ensemic1), + SOC_ENUM("Mic 2 Type Capture Switch", soc_enum_ensemic2), + SOC_ENUM("Mic 1 Low Power Capture Switch", soc_enum_lowpowmic1), + SOC_ENUM("Mic 2 Low Power Capture Switch", soc_enum_lowpowmic2), + + SOC_ENUM("LineIn High Pass Capture Switch", soc_enum_ad12nh), + SOC_ENUM("Mic High Pass Capture Switch", soc_enum_ad34nh), + SOC_ENUM("LineIn Mode Capture Switch", soc_enum_ad12voice), + SOC_ENUM("Mic Mode Capture Switch", soc_enum_ad34voice), + + SOC_ENUM("Headset Mode Playback Switch", soc_enum_da12voice), + SOC_ENUM("IHF Mode Playback Switch", soc_enum_da34voice), + SOC_ENUM("Vibra Mode Playback Switch", soc_enum_da56voice), + + SOC_ENUM("IHF and Headset Swap Playback Switch", soc_enum_swapda12_34), + + SOC_ENUM("IHF Low EMI Mode Playback Switch", soc_enum_hflrswap), + SOC_ENUM("Vibra Low EMI Mode Playback Switch", soc_enum_vib12swap), + + SOC_ENUM("IHF FIR Bypass Playback Switch", soc_enum_fir01byp), + SOC_ENUM("Vibra FIR Bypass Playback Switch", soc_enum_fir23byp), + + /* TODO: Cannot be changed on the fly with digital channel enabled. */ + SOC_ENUM("IHF High Volume Playback Switch", soc_enum_highvol01), + SOC_ENUM("Vibra High Volume Playback Switch", soc_enum_highvol23), + + SOC_SINGLE("ClassD High Pass Gain Playback Volume", + REG_CLASSDCONF3, REG_CLASSDCONF3_DITHHPGAIN, + REG_CLASSDCONF3_DITHHPGAIN_MAX, NORMAL), + SOC_SINGLE("ClassD White Gain Playback Volume", + REG_CLASSDCONF3, REG_CLASSDCONF3_DITHWGAIN, + REG_CLASSDCONF3_DITHWGAIN_MAX, NORMAL), + + SOC_ENUM("LineIn Filter Capture Switch", soc_enum_dmic12sinc), + SOC_ENUM("Mic Filter Capture Switch", soc_enum_dmic34sinc), + SOC_ENUM("HD Mic Filter Capture Switch", soc_enum_dmic56sinc), + + SOC_ENUM("Headset Source Playback Route", soc_enum_da2hslr), + + /* TODO: Cannot be changed on the fly with digital channel enabled. */ + SOC_ENUM("Headset Filter Playback Switch", soc_enum_hsesinc), + + SOC_ENUM("Digital Gain Fade Speed Switch", soc_enum_fadespeed), + + SOC_DOUBLE_R("Vibra PWM Duty Cycle N Playback Volume", + REG_PWMGENCONF3, REG_PWMGENCONF5, + REG_PWMGENCONFX_PWMVIBXDUTCYC, + REG_PWMGENCONFX_PWMVIBXDUTCYC_MAX, NORMAL), + SOC_DOUBLE_R("Vibra PWM Duty Cycle P Playback Volume", + REG_PWMGENCONF2, REG_PWMGENCONF4, + REG_PWMGENCONFX_PWMVIBXDUTCYC, + REG_PWMGENCONFX_PWMVIBXDUTCYC_MAX, NORMAL), + + /* TODO: move to DAPM */ + SOC_ENUM("Sidetone Playback Switch", soc_enum_enfirsids), + SOC_ENUM("IHF L and R Bridge Playback Route", soc_enum_parlhf), + SOC_ENUM("Vibra 1 and 2 Bridge Playback Route", soc_enum_parlvib), + + /* Digital gains for AD side */ + + SOC_DOUBLE_R_TLV("LineIn Master Gain Capture Volume", + REG_ADDIGGAIN1, REG_ADDIGGAIN2, + 0, REG_ADDIGGAINX_ADXGAIN_MAX, INVERT, adx_dig_gain_tlv), + SOC_DOUBLE_R_TLV("Mic Master Gain Capture Volume", + REG_ADDIGGAIN3, REG_ADDIGGAIN4, + 0, REG_ADDIGGAINX_ADXGAIN_MAX, INVERT, adx_dig_gain_tlv), + SOC_DOUBLE_R_TLV("HD Mic Master Gain Capture Volume", + REG_ADDIGGAIN5, REG_ADDIGGAIN6, + 0, REG_ADDIGGAINX_ADXGAIN_MAX, INVERT, adx_dig_gain_tlv), + + /* Digital gains for DA side */ + + SOC_DOUBLE_R_TLV("Headset Master Gain Playback Volume", + REG_DADIGGAIN1, REG_DADIGGAIN2, + 0, REG_DADIGGAINX_DAXGAIN_MAX, INVERT, dax_dig_gain_tlv), + SOC_DOUBLE_R_TLV("IHF Master Gain Playback Volume", + REG_DADIGGAIN3, REG_DADIGGAIN4, + 0, REG_DADIGGAINX_DAXGAIN_MAX, INVERT, dax_dig_gain_tlv), + SOC_DOUBLE_R_TLV("Vibra Master Gain Playback Volume", + REG_DADIGGAIN5, REG_DADIGGAIN6, + 0, REG_DADIGGAINX_DAXGAIN_MAX, INVERT, dax_dig_gain_tlv), + SOC_DOUBLE_R_TLV("Analog Loopback Gain Playback Volume", + REG_ADDIGLOOPGAIN1, REG_ADDIGLOOPGAIN2, + 0, REG_ADDIGLOOPGAINX_ADXLBGAIN_MAX, INVERT, dax_dig_gain_tlv), + SOC_DOUBLE_R_TLV("Headset Digital Gain Playback Volume", + REG_HSLEARDIGGAIN, REG_HSRDIGGAIN, + 0, REG_HSLEARDIGGAIN_HSLDGAIN_MAX, INVERT, hs_ear_dig_gain_tlv), + SOC_DOUBLE_R_TLV("Sidetone Digital Gain Playback Volume", + REG_SIDFIRGAIN1, REG_SIDFIRGAIN2, + 0, REG_SIDFIRGAINX_FIRSIDXGAIN_MAX, INVERT, stfir_dig_gain_tlv), + + /* Analog gains */ + + SOC_DOUBLE_TLV("Headset Gain Playback Volume", + REG_ANAGAIN3, + REG_ANAGAIN3_HSLGAIN, REG_ANAGAIN3_HSRGAIN, + REG_ANAGAIN3_HSXGAIN_MAX, INVERT, hs_gain_tlv), + SOC_SINGLE_TLV("Mic 1 Capture Volume", + REG_ANAGAIN1, + REG_ANAGAINX_MICXGAIN, + REG_ANAGAINX_MICXGAIN_MAX, NORMAL, mic_gain_tlv), + SOC_SINGLE_TLV("Mic 2 Capture Volume", + REG_ANAGAIN2, + REG_ANAGAINX_MICXGAIN, + REG_ANAGAINX_MICXGAIN_MAX, NORMAL, mic_gain_tlv), + SOC_DOUBLE_TLV("LineIn Capture Volume", + REG_ANAGAIN4, + REG_ANAGAIN4_LINLGAIN, REG_ANAGAIN4_LINRGAIN, + REG_ANAGAIN4_LINXGAIN_MAX, NORMAL, lin_gain_tlv), + SOC_DOUBLE_R_TLV("LineIn to Headset Bypass Playback Volume", + REG_DIGLINHSLGAIN, REG_DIGLINHSRGAIN, + REG_DIGLINHSXGAIN_LINTOHSXGAIN, + REG_DIGLINHSXGAIN_LINTOHSXGAIN_MAX, INVERT, lin2hs_gain_tlv), + + /* Digital Interface controls */ + + /* Clocks */ + SOC_ENUM("Digital Interface Master Generator Switch", soc_enum_mastgen), + SOC_ENUM("Digital Interface 0 Bit-clock Switch", soc_enum_fsbitclk0), + SOC_ENUM("Digital Interface 1 Bit-clock Switch", soc_enum_fsbitclk1), + + /* DA from slot mapping */ + SOC_ENUM("Digital Interface DA 1 From Slot Map", soc_enum_da1slotmap), + SOC_ENUM("Digital Interface DA 2 From Slot Map", soc_enum_da2slotmap), + SOC_ENUM("Digital Interface DA 3 From Slot Map", soc_enum_da3slotmap), + SOC_ENUM("Digital Interface DA 4 From Slot Map", soc_enum_da4slotmap), + SOC_ENUM("Digital Interface DA 5 From Slot Map", soc_enum_da5slotmap), + SOC_ENUM("Digital Interface DA 6 From Slot Map", soc_enum_da6slotmap), + SOC_ENUM("Digital Interface DA 7 From Slot Map", soc_enum_da7slotmap), + SOC_ENUM("Digital Interface DA 8 From Slot Map", soc_enum_da8slotmap), + + /* AD to slot mapping */ + SOC_ENUM("Digital Interface AD To Slot 0 Map", soc_enum_adslot0map), + SOC_ENUM("Digital Interface AD To Slot 1 Map", soc_enum_adslot1map), + SOC_ENUM("Digital Interface AD To Slot 2 Map", soc_enum_adslot2map), + SOC_ENUM("Digital Interface AD To Slot 3 Map", soc_enum_adslot3map), + SOC_ENUM("Digital Interface AD To Slot 4 Map", soc_enum_adslot4map), + SOC_ENUM("Digital Interface AD To Slot 5 Map", soc_enum_adslot5map), + SOC_ENUM("Digital Interface AD To Slot 6 Map", soc_enum_adslot6map), + SOC_ENUM("Digital Interface AD To Slot 7 Map", soc_enum_adslot7map), + SOC_ENUM("Digital Interface AD To Slot 8 Map", soc_enum_adslot8map), + SOC_ENUM("Digital Interface AD To Slot 9 Map", soc_enum_adslot9map), + SOC_ENUM("Digital Interface AD To Slot 10 Map", soc_enum_adslot10map), + SOC_ENUM("Digital Interface AD To Slot 11 Map", soc_enum_adslot11map), + SOC_ENUM("Digital Interface AD To Slot 12 Map", soc_enum_adslot12map), + SOC_ENUM("Digital Interface AD To Slot 13 Map", soc_enum_adslot13map), + SOC_ENUM("Digital Interface AD To Slot 14 Map", soc_enum_adslot14map), + SOC_ENUM("Digital Interface AD To Slot 15 Map", soc_enum_adslot15map), + SOC_ENUM("Digital Interface AD To Slot 16 Map", soc_enum_adslot16map), + SOC_ENUM("Digital Interface AD To Slot 17 Map", soc_enum_adslot17map), + SOC_ENUM("Digital Interface AD To Slot 18 Map", soc_enum_adslot18map), + SOC_ENUM("Digital Interface AD To Slot 19 Map", soc_enum_adslot19map), + SOC_ENUM("Digital Interface AD To Slot 20 Map", soc_enum_adslot20map), + SOC_ENUM("Digital Interface AD To Slot 21 Map", soc_enum_adslot21map), + SOC_ENUM("Digital Interface AD To Slot 22 Map", soc_enum_adslot22map), + SOC_ENUM("Digital Interface AD To Slot 23 Map", soc_enum_adslot23map), + SOC_ENUM("Digital Interface AD To Slot 24 Map", soc_enum_adslot24map), + SOC_ENUM("Digital Interface AD To Slot 25 Map", soc_enum_adslot25map), + SOC_ENUM("Digital Interface AD To Slot 26 Map", soc_enum_adslot26map), + SOC_ENUM("Digital Interface AD To Slot 27 Map", soc_enum_adslot27map), + SOC_ENUM("Digital Interface AD To Slot 28 Map", soc_enum_adslot28map), + SOC_ENUM("Digital Interface AD To Slot 29 Map", soc_enum_adslot29map), + SOC_ENUM("Digital Interface AD To Slot 30 Map", soc_enum_adslot30map), + SOC_ENUM("Digital Interface AD To Slot 31 Map", soc_enum_adslot31map), + + /* Loopback */ + SOC_ENUM("Digital Interface AD 1 Loopback Switch", soc_enum_ad1loop), + SOC_ENUM("Digital Interface AD 2 Loopback Switch", soc_enum_ad2loop), + SOC_ENUM("Digital Interface AD 3 Loopback Switch", soc_enum_ad3loop), + SOC_ENUM("Digital Interface AD 4 Loopback Switch", soc_enum_ad4loop), + SOC_ENUM("Digital Interface AD 5 Loopback Switch", soc_enum_ad5loop), + SOC_ENUM("Digital Interface AD 6 Loopback Switch", soc_enum_ad6loop), + SOC_ENUM("Digital Interface AD 7 Loopback Switch", soc_enum_ad7loop), + SOC_ENUM("Digital Interface AD 8 Loopback Switch", soc_enum_ad8loop), + + /* Burst FIFO */ + SOC_ENUM("Digital Interface 0 FIFO Enable Switch", soc_enum_if0fifoen), + SOC_ENUM("Burst FIFO Mask", soc_enum_bfifomask), + SOC_ENUM("Burst FIFO Bit-clock Frequency", soc_enum_bfifo19m2), + SOC_SINGLE("Burst FIFO Threshold", + REG_FIFOCONF1, + REG_FIFOCONF1_BFIFOINT_SHIFT, + REG_FIFOCONF1_BFIFOINT_MAX, + NORMAL), + SOC_SINGLE("Burst FIFO Length", + REG_FIFOCONF2, + REG_FIFOCONF2_BFIFOTX_SHIFT, + REG_FIFOCONF2_BFIFOTX_MAX, + NORMAL), + SOC_SINGLE("Burst FIFO EOS Extra Slots", + REG_FIFOCONF3, + REG_FIFOCONF3_BFIFOEXSL_SHIFT, + REG_FIFOCONF3_BFIFOEXSL_MAX, + NORMAL), + SOC_SINGLE("Burst FIFO FS Extra Bit-clocks", + REG_FIFOCONF3, + REG_FIFOCONF3_PREBITCLK0_SHIFT, + REG_FIFOCONF3_PREBITCLK0_MAX, + NORMAL), + SOC_ENUM("Burst FIFO Interface Mode", soc_enum_bfifomast), + SOC_ENUM("Burst FIFO Interface Switch", soc_enum_bfifoint), + SOC_SINGLE("Burst FIFO Switch Frame Number", + REG_FIFOCONF4, + REG_FIFOCONF4_BFIFOFRAMSW_SHIFT, + REG_FIFOCONF4_BFIFOFRAMSW_MAX, + NORMAL), + SOC_SINGLE("Burst FIFO Wake Up Delay", + REG_FIFOCONF5, + REG_FIFOCONF5_BFIFOWAKEUP_SHIFT, + REG_FIFOCONF5_BFIFOWAKEUP_MAX, + NORMAL), + SOC_SINGLE("Burst FIFO Samples In FIFO", + REG_FIFOCONF6, + REG_FIFOCONF6_BFIFOSAMPLE_SHIFT, + REG_FIFOCONF6_BFIFOSAMPLE_MAX, + NORMAL), + + /* Sidetone */ + SOC_SINGLE("Sidetone FIR Coeffecient Index", + REG_SIDFIRADR, + REG_SIDFIRADR_ADDRESS_SHIFT, + REG_SIDFIRADR_ADDRESS_MAX, + NORMAL), +}; + +static int ab8500_codec_set_format_if1(struct snd_soc_codec *codec, unsigned int fmt) +{ + unsigned int clear_mask, set_mask; + + /* Master or slave */ + + clear_mask = BMASK(REG_DIGIFCONF3_IF1MASTER); + set_mask = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & FRM master */ + pr_debug("%s: IF1 Master-mode: AB8500 master.\n", __func__); + set_mask |= BMASK(REG_DIGIFCONF3_IF1MASTER); + break; + case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & FRM slave */ + pr_debug("%s: IF1 Master-mode: AB8500 slave.\n", __func__); + break; + case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & FRM master */ + case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */ + pr_err("%s: ERROR: The device is either a master or a slave.\n", + __func__); + default: + pr_err("%s: ERROR: Unsupporter master mask 0x%x\n", + __func__, + fmt & SND_SOC_DAIFMT_MASTER_MASK); + return -EINVAL; + } + + ab8500_codec_update_reg_audio(codec, + REG_DIGIFCONF3, + BMASK(REG_DIGIFCONF3_IF1MASTER), + BMASK(REG_DIGIFCONF3_IF1MASTER)); + + /* I2S or TDM */ + + clear_mask = BMASK(REG_DIGIFCONF4_FSYNC1P) | + BMASK(REG_DIGIFCONF4_BITCLK1P) | + BMASK(REG_DIGIFCONF4_IF1FORMAT1) | + BMASK(REG_DIGIFCONF4_IF1FORMAT0); + set_mask = 0; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: /* I2S mode */ + pr_debug("%s: IF1 Protocol: I2S\n", __func__); + set_mask |= BMASK(REG_DIGIFCONF4_IF1FORMAT1); + break; + case SND_SOC_DAIFMT_DSP_B: /* L data MSB during FRM LRC */ + pr_debug("%s: IF1 Protocol: DSP B (TDM)\n", __func__); + set_mask |= BMASK(REG_DIGIFCONF4_IF1FORMAT0); + break; + default: + pr_err("%s: ERROR: Unsupported format (0x%x)!\n", + __func__, + fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return -EINVAL; + } + + ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF4, clear_mask, set_mask); + + return 0; +} + +static int ab8500_codec_set_word_length_if1(struct snd_soc_codec *codec, unsigned int wl) +{ + unsigned int clear_mask, set_mask; + + clear_mask = BMASK(REG_DIGIFCONF4_IF1WL1) | BMASK(REG_DIGIFCONF4_IF1WL0); + set_mask = 0; + + switch (wl) { + case 16: + break; + case 20: + set_mask |= BMASK(REG_DIGIFCONF4_IF1WL0); + break; + case 24: + set_mask |= BMASK(REG_DIGIFCONF4_IF1WL1); + break; + case 32: + set_mask |= BMASK(REG_DIGIFCONF2_IF0WL1) | + BMASK(REG_DIGIFCONF2_IF0WL0); + break; + default: + pr_err("%s: Unsupporter word-length 0x%x\n", __func__, wl); + return -EINVAL; + } + + pr_debug("%s: Word-length: %d bits.\n", __func__, wl); + ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF4, clear_mask, set_mask); + + return 0; +} + +static int ab8500_codec_set_bit_delay_if1(struct snd_soc_codec *codec, unsigned int delay) +{ + unsigned int clear_mask, set_mask; + + clear_mask = BMASK(REG_DIGIFCONF4_IF1DEL); + set_mask = 0; + + switch (delay) { + case 0: + break; + case 1: + set_mask |= BMASK(REG_DIGIFCONF4_IF1DEL); + break; + default: + pr_err("%s: ERROR: Unsupported bit-delay (0x%x)!\n", __func__, delay); + return -EINVAL; + } + + pr_debug("%s: IF1 Bit-delay: %d bits.\n", __func__, delay); + ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF4, clear_mask, set_mask); + + return 0; +} + +/* Configures audio macrocell into the AB8500 Chip */ +static void ab8500_codec_configure_audio_macrocell(struct snd_soc_codec *codec) +{ + int data, ret; + + ret = ab8500_sysctrl_write(AB8500_STW4500CTRL3, + AB8500_STW4500CTRL3_CLK32KOUT2DIS | AB8500_STW4500CTRL3_RESETAUDN, + AB8500_STW4500CTRL3_RESETAUDN); + if (ret < 0) + pr_err("%s: WARN: Unable to set reg STW4500CTRL3!\n", __func__); + + data = ab8500_codec_read_reg(codec, AB8500_MISC, AB8500_GPIO_DIR4_REG); + data |= GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT | GPIO31_DIR_OUTPUT; + ab8500_codec_write_reg(codec, AB8500_MISC, AB8500_GPIO_DIR4_REG, data); +} + +/* Extended interface for codec-driver */ + +void ab8500_audio_power_control(bool power_on) +{ + if (ab8500_codec == NULL) { + pr_err("%s: ERROR: AB8500 ASoC-driver not yet probed!\n", __func__); + return; + } + + if (power_on) { + unsigned int set_mask; + pr_debug("Enabling AB8500."); + set_mask = BMASK(REG_POWERUP_POWERUP) | BMASK(REG_POWERUP_ENANA); + ab8500_codec_update_reg_audio(ab8500_codec, REG_POWERUP, 0x00, set_mask); + } else { + unsigned int clear_mask; + pr_debug("Disabling AB8500."); + clear_mask = BMASK(REG_POWERUP_POWERUP) | BMASK(REG_POWERUP_ENANA); + ab8500_codec_update_reg_audio(ab8500_codec, REG_POWERUP, clear_mask, 0x00); + } +} + +/* Extended interface for codec-driver */ + +int ab8500_audio_set_word_length(struct snd_soc_dai *dai, unsigned int wl) +{ + unsigned int clear_mask, set_mask; + struct snd_soc_codec *codec = dai->codec; + + clear_mask = BMASK(REG_DIGIFCONF2_IF0WL0) | BMASK(REG_DIGIFCONF2_IF0WL1); + set_mask = 0; + + switch (wl) { + case 16: + break; + case 20: + set_mask |= BMASK(REG_DIGIFCONF2_IF0WL0); + break; + case 24: + set_mask |= BMASK(REG_DIGIFCONF2_IF0WL1); + break; + case 32: + set_mask |= BMASK(REG_DIGIFCONF2_IF0WL1) | + BMASK(REG_DIGIFCONF2_IF0WL0); + break; + default: + pr_err("%s: Unsupporter word-length 0x%x\n", __func__, wl); + return -EINVAL; + } + + pr_debug("%s: IF0 Word-length: %d bits.\n", __func__, wl); + ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF2, clear_mask, set_mask); + + return 0; +} + +int ab8500_audio_set_bit_delay(struct snd_soc_dai *dai, unsigned int delay) +{ + unsigned int clear_mask, set_mask; + struct snd_soc_codec *codec = dai->codec; + + clear_mask = BMASK(REG_DIGIFCONF2_IF0DEL); + set_mask = 0; + + switch (delay) { + case 0: + break; + case 1: + set_mask |= BMASK(REG_DIGIFCONF2_IF0DEL); + break; + default: + pr_err("%s: ERROR: Unsupported bit-delay (0x%x)!\n", __func__, delay); + return -EINVAL; + } + + pr_debug("%s: IF0 Bit-delay: %d bits.\n", __func__, delay); + ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF2, clear_mask, set_mask); + + return 0; +} + +int ab8500_audio_setup_if1(struct snd_soc_codec *codec, + unsigned int fmt, + unsigned int wl, + unsigned int delay) +{ + int ret; + + pr_debug("%s: Enter.\n", __func__); + + ret = ab8500_codec_set_format_if1(codec, fmt); + if (ret) + return -1; + + ret = ab8500_codec_set_bit_delay_if1(codec, delay); + if (ret) + return -1; + + + ret = ab8500_codec_set_word_length_if1(codec, wl); + if (ret) + return -1; + + return 0; +} + +bool ab8500_audio_dapm_path_active(enum ab8500_audio_dapm_path dapm_path) +{ + int reg, reg_mask; + + switch (dapm_path) { + case AB8500_AUDIO_DAPM_PATH_DMIC: + reg = ab8500_codec_read_reg_audio(ab8500_codec, REG_DIGMICCONF); + reg_mask = BMASK(REG_DIGMICCONF_ENDMIC1) | + BMASK(REG_DIGMICCONF_ENDMIC2) | + BMASK(REG_DIGMICCONF_ENDMIC3) | + BMASK(REG_DIGMICCONF_ENDMIC4) | + BMASK(REG_DIGMICCONF_ENDMIC5) | + BMASK(REG_DIGMICCONF_ENDMIC6); + return reg & reg_mask; + + case AB8500_AUDIO_DAPM_PATH_AMIC1: + reg = ab8500_codec_read_reg_audio(ab8500_codec, REG_ANACONF2); + reg_mask = BMASK(REG_ANACONF2_MUTMIC1); + return !(reg & reg_mask); + + case AB8500_AUDIO_DAPM_PATH_AMIC2: + reg = ab8500_codec_read_reg_audio(ab8500_codec, REG_ANACONF2); + reg_mask = BMASK(REG_ANACONF2_MUTMIC2); + return !(reg & reg_mask); + + default: + return false; + } +} + +static int ab8500_codec_add_widgets(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_dapm_new_controls(&codec->dapm, ab8500_dapm_widgets, + ARRAY_SIZE(ab8500_dapm_widgets)); + if (ret < 0) { + pr_err("%s: Failed to create DAPM controls (%d).\n", + __func__, ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&codec->dapm, intercon, ARRAY_SIZE(intercon)); + if (ret < 0) { + pr_err("%s: Failed to add DAPM routes (%d).\n", + __func__, ret); + return ret; + } + + return 0; +} + +static int ab8500_codec_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) +{ + pr_debug("%s Enter.\n", __func__); + return 0; +} + +static int ab8500_codec_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + pr_debug("%s Enter.\n", __func__); + + return 0; +} + +static int ab8500_codec_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + pr_debug("%s Enter.\n", __func__); + + /* Clear interrupt status registers by reading them. */ + ab8500_codec_read_reg_audio(dai->codec, REG_AUDINTSOURCE1); + ab8500_codec_read_reg_audio(dai->codec, REG_AUDINTSOURCE2); + + return 0; +} + +static void ab8500_codec_pcm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + pr_debug("%s Enter.\n", __func__); + + ab8500_codec_dump_all_reg(dai->codec); +} + +static int ab8500_codec_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + pr_err("%s Enter.\n", __func__); + + return 0; +} + +/* Gates clocking according format mask */ +static int ab8500_codec_set_dai_clock_gate(struct snd_soc_codec *codec, unsigned int fmt) +{ + unsigned int clear_mask; + unsigned int set_mask; + + clear_mask = BMASK(REG_DIGIFCONF1_ENMASTGEN) | + BMASK(REG_DIGIFCONF1_ENFSBITCLK0); + + set_mask = BMASK(REG_DIGIFCONF1_ENMASTGEN); + + switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) { + case SND_SOC_DAIFMT_CONT: /* continuous clock */ + pr_debug("%s: IF0 Clock is continous.\n", __func__); + set_mask |= BMASK(REG_DIGIFCONF1_ENFSBITCLK0); + break; + case SND_SOC_DAIFMT_GATED: /* clock is gated */ + pr_debug("%s: IF0 Clock is gated.\n", __func__); + break; + default: + pr_err("%s: ERROR: Unsupporter clock mask (0x%x)!\n", + __func__, + fmt & SND_SOC_DAIFMT_CLOCK_MASK); + return -EINVAL; + } + + ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF1, clear_mask, set_mask); + + return 0; +} + +static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + unsigned int clear_mask; + unsigned int set_mask; + struct snd_soc_codec *codec = dai->codec; + int err; + + pr_debug("%s: Enter (fmt = 0x%x)\n", __func__, fmt); + + clear_mask = BMASK(REG_DIGIFCONF3_IF1DATOIF0AD) | + BMASK(REG_DIGIFCONF3_IF1CLKTOIF0CLK) | + BMASK(REG_DIGIFCONF3_IF0BFIFOEN) | + BMASK(REG_DIGIFCONF3_IF0MASTER); + set_mask = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & FRM master */ + pr_debug("%s: IF0 Master-mode: AB8500 master.\n", __func__); + set_mask |= BMASK(REG_DIGIFCONF3_IF0MASTER); + break; + case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & FRM slave */ + pr_debug("%s: IF0 Master-mode: AB8500 slave.\n", __func__); + break; + case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & FRM master */ + case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */ + pr_err("%s: ERROR: The device is either a master or a slave.\n", __func__); + default: + pr_err("%s: ERROR: Unsupporter master mask 0x%x\n", + __func__, + (fmt & SND_SOC_DAIFMT_MASTER_MASK)); + return -EINVAL; + break; + } + + ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF3, clear_mask, set_mask); + + /* Set clock gating */ + err = ab8500_codec_set_dai_clock_gate(codec, fmt); + if (err) { + pr_err("%s: ERRROR: Failed to set clock gate (%d).\n", __func__, err); + return err; + } + + /* Setting data transfer format */ + + clear_mask = BMASK(REG_DIGIFCONF2_IF0FORMAT0) | + BMASK(REG_DIGIFCONF2_IF0FORMAT1) | + BMASK(REG_DIGIFCONF2_FSYNC0P) | + BMASK(REG_DIGIFCONF2_BITCLK0P); + set_mask = 0; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: /* I2S mode */ + pr_debug("%s: IF0 Protocol: I2S\n", __func__); + set_mask |= BMASK(REG_DIGIFCONF2_IF0FORMAT1); + + /* 32 bit, 0 delay */ + ab8500_audio_set_word_length(dai, 32); + ab8500_audio_set_bit_delay(dai, 0); + + break; + case SND_SOC_DAIFMT_DSP_A: /* L data MSB after FRM LRC */ + pr_debug("%s: IF0 Protocol: DSP A (TDM)\n", __func__); + set_mask |= BMASK(REG_DIGIFCONF2_IF0FORMAT1); + break; + case SND_SOC_DAIFMT_DSP_B: /* L data MSB during FRM LRC */ + pr_debug("%s: IF0 Protocol: DSP B (TDM)\n", __func__); + set_mask |= BMASK(REG_DIGIFCONF2_IF0FORMAT0); + break; + default: + pr_err("%s: ERROR: Unsupporter format (0x%x)!\n", + __func__, + fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */ + pr_debug("%s: IF0: Normal bit clock, normal frame\n", __func__); + break; + case SND_SOC_DAIFMT_NB_IF: /* normal BCLK + inv FRM */ + pr_debug("%s: IF0: Normal bit clock, inverted frame\n", __func__); + set_mask |= BMASK(REG_DIGIFCONF2_FSYNC0P); + break; + case SND_SOC_DAIFMT_IB_NF: /* invert BCLK + nor FRM */ + pr_debug("%s: IF0: Inverted bit clock, normal frame\n", __func__); + set_mask |= BMASK(REG_DIGIFCONF2_BITCLK0P); + break; + case SND_SOC_DAIFMT_IB_IF: /* invert BCLK + FRM */ + pr_debug("%s: IF0: Inverted bit clock, inverted frame\n", __func__); + set_mask |= BMASK(REG_DIGIFCONF2_FSYNC0P); + set_mask |= BMASK(REG_DIGIFCONF2_BITCLK0P); + break; + default: + pr_err("%s: ERROR: Unsupported INV mask 0x%x\n", + __func__, + (fmt & SND_SOC_DAIFMT_INV_MASK)); + return -EINVAL; + break; + } + + ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF2, clear_mask, set_mask); + + return 0; +} + +static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int set_mask, clear_mask, slots_active; + + /* Only 16 bit slot width is supported at the moment in TDM mode */ + if (slot_width != 16) { + pr_err("%s: ERROR: Unsupported slot_width %d.\n", + __func__, slot_width); + return -EINVAL; + } + + /* Setup TDM clocking according to slot count */ + pr_debug("%s: Slots, total: %d\n", __func__, slots); + clear_mask = BMASK(REG_DIGIFCONF1_IF0BITCLKOS0) | + BMASK(REG_DIGIFCONF1_IF0BITCLKOS1); + switch (slots) { + case 2: + set_mask = REG_MASK_NONE; + break; + case 4: + set_mask = BMASK(REG_DIGIFCONF1_IF0BITCLKOS0); + break; + case 8: + set_mask = BMASK(REG_DIGIFCONF1_IF0BITCLKOS1); + break; + case 16: + set_mask = BMASK(REG_DIGIFCONF1_IF0BITCLKOS0) | + BMASK(REG_DIGIFCONF1_IF0BITCLKOS1); + break; + default: + pr_err("%s: ERROR: Unsupported number of slots (%d)!\n", __func__, slots); + return -EINVAL; + } + ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF1, clear_mask, set_mask); + + /* Setup TDM DA according to active tx slots */ + clear_mask = REG_DASLOTCONFX_SLTODAX_MASK; + slots_active = hweight32(tx_mask); + pr_debug("%s: Slots, active, TX: %d\n", __func__, slots_active); + switch (slots_active) { + case 0: + break; + case 1: + /* Slot 9 -> DA_IN1 & DA_IN3 */ + ab8500_codec_update_reg_audio(codec, REG_DASLOTCONF1, clear_mask, 9); + ab8500_codec_update_reg_audio(codec, REG_DASLOTCONF3, clear_mask, 9); + break; + case 2: + /* Slot 9 -> DA_IN1 & DA_IN3, Slot 11 -> DA_IN2 & DA_IN4 */ + ab8500_codec_update_reg_audio(codec, REG_DASLOTCONF1, clear_mask, 9); + ab8500_codec_update_reg_audio(codec, REG_DASLOTCONF3, clear_mask, 9); + ab8500_codec_update_reg_audio(codec, REG_DASLOTCONF2, clear_mask, 11); + ab8500_codec_update_reg_audio(codec, REG_DASLOTCONF4, clear_mask, 11); + + break; + case 8: + pr_debug("%s: In 8-channel mode DA-from-slot mapping is set manually.", __func__); + break; + default: + pr_err("%s: Unsupported number of active TX-slots (%d)!\n", __func__, slots_active); + return -EINVAL; + } + + /* Setup TDM AD according to active RX-slots */ + slots_active = hweight32(rx_mask); + pr_debug("%s: Slots, active, RX: %d\n", __func__, slots_active); + switch (slots_active) { + case 0: + break; + case 1: + /* AD_OUT3 -> slot 0 & 1 */ + ab8500_codec_update_reg_audio(codec, REG_ADSLOTSEL1, + REG_MASK_ALL, + REG_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN | + REG_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD); + break; + case 2: + /* AD_OUT3 -> slot 0, AD_OUT2 -> slot 1 */ + ab8500_codec_update_reg_audio(codec, REG_ADSLOTSEL1, + REG_MASK_ALL, + REG_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN | + REG_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD); + break; + case 8: + pr_debug("%s: In 8-channel mode AD-to-slot mapping is set manually.", __func__); + break; + default: + pr_err("%s: Unsupported number of active RX-slots (%d)!\n", __func__, slots_active); + return -EINVAL; + } + + return 0; +} + +struct snd_soc_dai_driver ab8500_codec_dai[] = { + { + .name = "ab8500-codec-dai.0", + .id = 0, + .playback = { + .stream_name = "ab8500_0p", + .channels_min = 1, + .channels_max = 8, + .rates = AB8500_SUPPORTED_RATE, + .formats = AB8500_SUPPORTED_FMT, + }, + .ops = (struct snd_soc_dai_ops[]) { + { + .startup = ab8500_codec_pcm_startup, + .prepare = ab8500_codec_pcm_prepare, + .hw_params = ab8500_codec_pcm_hw_params, + .shutdown = ab8500_codec_pcm_shutdown, + .set_sysclk = ab8500_codec_set_dai_sysclk, + .set_tdm_slot = ab8500_codec_set_dai_tdm_slot, + .set_fmt = ab8500_codec_set_dai_fmt, + } + }, + .symmetric_rates = 1 + }, + { + .name = "ab8500-codec-dai.1", + .id = 1, + .capture = { + .stream_name = "ab8500_0c", + .channels_min = 1, + .channels_max = 8, + .rates = AB8500_SUPPORTED_RATE, + .formats = AB8500_SUPPORTED_FMT, + }, + .ops = (struct snd_soc_dai_ops[]) { + { + .startup = ab8500_codec_pcm_startup, + .prepare = ab8500_codec_pcm_prepare, + .hw_params = ab8500_codec_pcm_hw_params, + .shutdown = ab8500_codec_pcm_shutdown, + .set_sysclk = ab8500_codec_set_dai_sysclk, + .set_tdm_slot = ab8500_codec_set_dai_tdm_slot, + .set_fmt = ab8500_codec_set_dai_fmt, + } + }, + .symmetric_rates = 1 + } +}; + +static int ab8500_codec_probe(struct snd_soc_codec *codec) +{ + int i, ret; + u8 *cache = codec->reg_cache; + + pr_debug("%s: Enter.\n", __func__); + + ab8500_codec_configure_audio_macrocell(codec); + + for (i = REG_AUDREV; i >= REG_POWERUP; i--) + ab8500_codec_write_reg_audio(codec, i, cache[i]); + + /* Add controls */ + ret = snd_soc_add_controls(codec, ab8500_snd_controls, + ARRAY_SIZE(ab8500_snd_controls)); + if (ret < 0) { + pr_err("%s: failed to add soc controls (%d).\n", + __func__, ret); + return ret; + } + + /* Add controls with events */ + snd_ctl_add(codec->card->snd_card, snd_ctl_new1(&st_fir_value_control, codec)); + snd_ctl_add(codec->card->snd_card, snd_ctl_new1(&st_fir_apply_control, codec)); + + /* Add DAPM-widgets */ + ret = ab8500_codec_add_widgets(codec); + if (ret < 0) { + pr_err("%s: Failed add widgets (%d).\n", __func__, ret); + return ret; + } + + ab8500_codec = codec; + + return ret; +} + +static int ab8500_codec_remove(struct snd_soc_codec *codec) +{ + snd_soc_dapm_free(&codec->dapm); + ab8500_codec = NULL; + + return 0; +} + +static int ab8500_codec_suspend(struct snd_soc_codec *codec, + pm_message_t state) +{ + pr_debug("%s Enter.\n", __func__); + + return 0; +} + +static int ab8500_codec_resume(struct snd_soc_codec *codec) +{ + pr_debug("%s Enter.\n", __func__); + + return 0; +} + +struct snd_soc_codec_driver ab8500_codec_driver = { + .probe = ab8500_codec_probe, + .remove = ab8500_codec_remove, + .suspend = ab8500_codec_suspend, + .resume = ab8500_codec_resume, + .read = ab8500_codec_read_reg_audio, + .write = ab8500_codec_write_reg_audio, + .reg_cache_size = ARRAY_SIZE(ab8500_reg_cache), + .reg_word_size = sizeof(u8), + .reg_cache_default = ab8500_reg_cache, +}; + +static int __devinit ab8500_codec_driver_probe(struct platform_device *pdev) +{ + int err; + + pr_debug("%s: Enter.\n", __func__); + + pr_info("%s: Register codec.\n", __func__); + err = snd_soc_register_codec(&pdev->dev, + &ab8500_codec_driver, + ab8500_codec_dai, + ARRAY_SIZE(ab8500_codec_dai)); + + if (err < 0) { + pr_err("%s: Error: Failed to register codec (%d).\n", + __func__, err); + } + + return err; +} + +static int __devexit ab8500_codec_driver_remove(struct platform_device *pdev) +{ + pr_info("%s Enter.\n", __func__); + + snd_soc_unregister_codec(&pdev->dev); + + return 0; +} + +static int ab8500_codec_driver_suspend(struct platform_device *pdev, + pm_message_t state) +{ + pr_debug("%s Enter.\n", __func__); + + return 0; +} + +static int ab8500_codec_driver_resume(struct platform_device *pdev) +{ + pr_debug("%s Enter.\n", __func__); + + return 0; +} + +static struct platform_driver ab8500_codec_platform_driver = { + .driver = { + .name = "ab8500-codec", + .owner = THIS_MODULE, + }, + .probe = ab8500_codec_driver_probe, + .remove = __devexit_p(ab8500_codec_driver_remove), + .suspend = ab8500_codec_driver_suspend, + .resume = ab8500_codec_driver_resume, +}; + +static int __devinit ab8500_codec_platform_driver_init(void) +{ + int ret; + + pr_info("%s: Enter.\n", __func__); + + ret = platform_driver_register(&ab8500_codec_platform_driver); + if (ret != 0) { + pr_err("%s: Failed to register AB8500 platform driver (%d)!\n", + __func__, ret); + } + + return ret; +} + +static void __exit ab8500_codec_platform_driver_exit(void) +{ + pr_info("%s: Enter.\n", __func__); + + platform_driver_unregister(&ab8500_codec_platform_driver); +} + +module_init(ab8500_codec_platform_driver_init); +module_exit(ab8500_codec_platform_driver_exit); + +MODULE_DESCRIPTION("AB8500 Codec driver"); +MODULE_ALIAS("platform:ab8500-codec"); +MODULE_AUTHOR("ST-Ericsson"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/ab8500_audio.h b/sound/soc/codecs/ab8500_audio.h new file mode 100644 index 00000000000..7cfdd1cc13a --- /dev/null +++ b/sound/soc/codecs/ab8500_audio.h @@ -0,0 +1,569 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Mikko J. Lehto <mikko.lehto@symbio.com>, + * Mikko Sarmanne <mikko.sarmanne@symbio.com>, + * Ola Lilja <ola.o.lilja@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#ifndef AB8500_CODEC_REGISTERS_H +#define AB8500_CODEC_REGISTERS_H + +#define AB8500_SUPPORTED_RATE (SNDRV_PCM_RATE_48000) +#define AB8500_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE) + +extern struct snd_soc_dai_driver ab8500_codec_dai[]; +extern struct snd_soc_codec_driver soc_codec_dev_ab8500; + +/* Extended interface for codec-driver */ + +void ab8500_audio_power_control(bool power_on); +int ab8500_audio_set_word_length(struct snd_soc_dai *dai, unsigned int wl); +int ab8500_audio_set_bit_delay(struct snd_soc_dai *dai, unsigned int delay); +int ab8500_audio_setup_if1(struct snd_soc_codec *codec, + unsigned int fmt, + unsigned int wl, + unsigned int delay); + +enum ab8500_audio_dapm_path { + AB8500_AUDIO_DAPM_PATH_DMIC, + AB8500_AUDIO_DAPM_PATH_AMIC1, + AB8500_AUDIO_DAPM_PATH_AMIC2 +}; +bool ab8500_audio_dapm_path_active(enum ab8500_audio_dapm_path dapm_path); + +/* AB8500 audio bank (0x0d) register definitions */ + +#define REG_POWERUP 0x00 +#define REG_AUDSWRESET 0x01 +#define REG_ADPATHENA 0x02 +#define REG_DAPATHENA 0x03 +#define REG_ANACONF1 0x04 +#define REG_ANACONF2 0x05 +#define REG_DIGMICCONF 0x06 +#define REG_ANACONF3 0x07 +#define REG_ANACONF4 0x08 +#define REG_DAPATHCONF 0x09 +#define REG_MUTECONF 0x0A +#define REG_SHORTCIRCONF 0x0B +#define REG_ANACONF5 0x0C +#define REG_ENVCPCONF 0x0D +#define REG_SIGENVCONF 0x0E +#define REG_PWMGENCONF1 0x0F +#define REG_PWMGENCONF2 0x10 +#define REG_PWMGENCONF3 0x11 +#define REG_PWMGENCONF4 0x12 +#define REG_PWMGENCONF5 0x13 +#define REG_ANAGAIN1 0x14 +#define REG_ANAGAIN2 0x15 +#define REG_ANAGAIN3 0x16 +#define REG_ANAGAIN4 0x17 +#define REG_DIGLINHSLGAIN 0x18 +#define REG_DIGLINHSRGAIN 0x19 +#define REG_ADFILTCONF 0x1A +#define REG_DIGIFCONF1 0x1B +#define REG_DIGIFCONF2 0x1C +#define REG_DIGIFCONF3 0x1D +#define REG_DIGIFCONF4 0x1E +#define REG_ADSLOTSEL1 0x1F +#define REG_ADSLOTSEL2 0x20 +#define REG_ADSLOTSEL3 0x21 +#define REG_ADSLOTSEL4 0x22 +#define REG_ADSLOTSEL5 0x23 +#define REG_ADSLOTSEL6 0x24 +#define REG_ADSLOTSEL7 0x25 +#define REG_ADSLOTSEL8 0x26 +#define REG_ADSLOTSEL9 0x27 +#define REG_ADSLOTSEL10 0x28 +#define REG_ADSLOTSEL11 0x29 +#define REG_ADSLOTSEL12 0x2A +#define REG_ADSLOTSEL13 0x2B +#define REG_ADSLOTSEL14 0x2C +#define REG_ADSLOTSEL15 0x2D +#define REG_ADSLOTSEL16 0x2E +#define REG_ADSLOTHIZCTRL1 0x2F +#define REG_ADSLOTHIZCTRL2 0x30 +#define REG_ADSLOTHIZCTRL3 0x31 +#define REG_ADSLOTHIZCTRL4 0x32 +#define REG_DASLOTCONF1 0x33 +#define REG_DASLOTCONF2 0x34 +#define REG_DASLOTCONF3 0x35 +#define REG_DASLOTCONF4 0x36 +#define REG_DASLOTCONF5 0x37 +#define REG_DASLOTCONF6 0x38 +#define REG_DASLOTCONF7 0x39 +#define REG_DASLOTCONF8 0x3A +#define REG_CLASSDCONF1 0x3B +#define REG_CLASSDCONF2 0x3C +#define REG_CLASSDCONF3 0x3D +#define REG_DMICFILTCONF 0x3E +#define REG_DIGMULTCONF1 0x3F +#define REG_DIGMULTCONF2 0x40 +#define REG_ADDIGGAIN1 0x41 +#define REG_ADDIGGAIN2 0x42 +#define REG_ADDIGGAIN3 0x43 +#define REG_ADDIGGAIN4 0x44 +#define REG_ADDIGGAIN5 0x45 +#define REG_ADDIGGAIN6 0x46 +#define REG_DADIGGAIN1 0x47 +#define REG_DADIGGAIN2 0x48 +#define REG_DADIGGAIN3 0x49 +#define REG_DADIGGAIN4 0x4A +#define REG_DADIGGAIN5 0x4B +#define REG_DADIGGAIN6 0x4C +#define REG_ADDIGLOOPGAIN1 0x4D +#define REG_ADDIGLOOPGAIN2 0x4E +#define REG_HSLEARDIGGAIN 0x4F +#define REG_HSRDIGGAIN 0x50 +#define REG_SIDFIRGAIN1 0x51 +#define REG_SIDFIRGAIN2 0x52 +#define REG_ANCCONF1 0x53 +#define REG_ANCCONF2 0x54 +#define REG_ANCCONF3 0x55 +#define REG_ANCCONF4 0x56 +#define REG_ANCCONF5 0x57 +#define REG_ANCCONF6 0x58 +#define REG_ANCCONF7 0x59 +#define REG_ANCCONF8 0x5A +#define REG_ANCCONF9 0x5B +#define REG_ANCCONF10 0x5C +#define REG_ANCCONF11 0x5D +#define REG_ANCCONF12 0x5E +#define REG_ANCCONF13 0x5F +#define REG_ANCCONF14 0x60 +#define REG_SIDFIRADR 0x61 +#define REG_SIDFIRCOEF1 0x62 +#define REG_SIDFIRCOEF2 0x63 +#define REG_SIDFIRCONF 0x64 +#define REG_AUDINTMASK1 0x65 +#define REG_AUDINTSOURCE1 0x66 +#define REG_AUDINTMASK2 0x67 +#define REG_AUDINTSOURCE2 0x68 +#define REG_FIFOCONF1 0x69 +#define REG_FIFOCONF2 0x6A +#define REG_FIFOCONF3 0x6B +#define REG_FIFOCONF4 0x6C +#define REG_FIFOCONF5 0x6D +#define REG_FIFOCONF6 0x6E +#define REG_AUDREV 0x6F + +#define AB8500_FIRST_REG REG_POWERUP +#define AB8500_LAST_REG REG_AUDREV +#define AB8500_CACHEREGNUM (AB8500_LAST_REG + 1) + + +#define REG_MASK_ALL 0xFF +#define REG_MASK_NONE 0x00 + +/* REG_POWERUP */ +#define REG_POWERUP_POWERUP 7 +#define REG_POWERUP_ENANA 3 + +/* REG_AUDSWRESET */ +#define REG_AUDSWRESET_SWRESET 7 + +/* REG_ADPATHENA */ +#define REG_ADPATHENA_ENAD12 7 +#define REG_ADPATHENA_ENAD34 5 +#define REG_ADPATHENA_ENAD5768 3 + +/* REG_DAPATHENA */ +#define REG_DAPATHENA_ENDA1 7 +#define REG_DAPATHENA_ENDA2 6 +#define REG_DAPATHENA_ENDA3 5 +#define REG_DAPATHENA_ENDA4 4 +#define REG_DAPATHENA_ENDA5 3 +#define REG_DAPATHENA_ENDA6 2 + +/* REG_ANACONF1 */ +#define REG_ANACONF1_HSLOWPOW 7 +#define REG_ANACONF1_DACLOWPOW1 6 +#define REG_ANACONF1_DACLOWPOW0 5 +#define REG_ANACONF1_EARDACLOWPOW 4 +#define REG_ANACONF1_EARSELCM 2 +#define REG_ANACONF1_HSHPEN 1 +#define REG_ANACONF1_EARDRVLOWPOW 0 + +/* REG_ANACONF2 */ +#define REG_ANACONF2_ENMIC1 7 +#define REG_ANACONF2_ENMIC2 6 +#define REG_ANACONF2_ENLINL 5 +#define REG_ANACONF2_ENLINR 4 +#define REG_ANACONF2_MUTMIC1 3 +#define REG_ANACONF2_MUTMIC2 2 +#define REG_ANACONF2_MUTLINL 1 +#define REG_ANACONF2_MUTLINR 0 + +/* REG_DIGMICCONF */ +#define REG_DIGMICCONF_ENDMIC1 7 +#define REG_DIGMICCONF_ENDMIC2 6 +#define REG_DIGMICCONF_ENDMIC3 5 +#define REG_DIGMICCONF_ENDMIC4 4 +#define REG_DIGMICCONF_ENDMIC5 3 +#define REG_DIGMICCONF_ENDMIC6 2 +#define REG_DIGMICCONF_HSFADSPEED 0 + +/* REG_ANACONF3 */ +#define REG_ANACONF3_MIC1SEL 7 +#define REG_ANACONF3_LINRSEL 6 +#define REG_ANACONF3_ENDRVHSL 5 +#define REG_ANACONF3_ENDRVHSR 4 +#define REG_ANACONF3_ENADCMIC 2 +#define REG_ANACONF3_ENADCLINL 1 +#define REG_ANACONF3_ENADCLINR 0 + +/* REG_ANACONF4 */ +#define REG_ANACONF4_DISPDVSS 7 +#define REG_ANACONF4_ENEAR 6 +#define REG_ANACONF4_ENHSL 5 +#define REG_ANACONF4_ENHSR 4 +#define REG_ANACONF4_ENHFL 3 +#define REG_ANACONF4_ENHFR 2 +#define REG_ANACONF4_ENVIB1 1 +#define REG_ANACONF4_ENVIB2 0 + +/* REG_DAPATHCONF */ +#define REG_DAPATHCONF_ENDACEAR 6 +#define REG_DAPATHCONF_ENDACHSL 5 +#define REG_DAPATHCONF_ENDACHSR 4 +#define REG_DAPATHCONF_ENDACHFL 3 +#define REG_DAPATHCONF_ENDACHFR 2 +#define REG_DAPATHCONF_ENDACVIB1 1 +#define REG_DAPATHCONF_ENDACVIB2 0 + +/* REG_MUTECONF */ +#define REG_MUTECONF_MUTEAR 6 +#define REG_MUTECONF_MUTHSL 5 +#define REG_MUTECONF_MUTHSR 4 + +/* REG_SHORTCIRCONF */ +/* REG_ANACONF5 */ +#define REG_ANACONF5_ENCPHS 7 +#define REG_ANACONF5_HSAUTOEN 0 + +/* REG_ENVCPCONF */ +#define REG_ENVCPCONF_ENVDETHTHRE 4 +#define REG_ENVCPCONF_ENVDETLTHRE 0 +#define REG_ENVCPCONF_ENVDETHTHRE_MAX 0x0F +#define REG_ENVCPCONF_ENVDETLTHRE_MAX 0x0F + +/* REG_SIGENVCONF */ +#define REG_SIGENVCONF_CPLVEN 5 +#define REG_SIGENVCONF_ENVDETCPEN 4 +#define REG_SIGENVCONF_ENVDETTIME 0 +#define REG_SIGENVCONF_ENVDETTIME_MAX 0x0F + +/* REG_PWMGENCONF1 */ +#define REG_PWMGENCONF1_PWMTOVIB1 7 +#define REG_PWMGENCONF1_PWMTOVIB2 6 +#define REG_PWMGENCONF1_PWM1CTRL 5 +#define REG_PWMGENCONF1_PWM2CTRL 4 +#define REG_PWMGENCONF1_PWM1NCTRL 3 +#define REG_PWMGENCONF1_PWM1PCTRL 2 +#define REG_PWMGENCONF1_PWM2NCTRL 1 +#define REG_PWMGENCONF1_PWM2PCTRL 0 + +/* REG_PWMGENCONF2 */ +/* REG_PWMGENCONF3 */ +/* REG_PWMGENCONF4 */ +/* REG_PWMGENCONF5 */ +#define REG_PWMGENCONFX_PWMVIBXPOL 7 +#define REG_PWMGENCONFX_PWMVIBXDUTCYC 0 +#define REG_PWMGENCONFX_PWMVIBXDUTCYC_MAX 0x64 + +/* REG_ANAGAIN1 */ +/* REG_ANAGAIN2 */ +#define REG_ANAGAINX_ENSEMICX 7 +#define REG_ANAGAINX_LOWPOWMICX 6 +#define REG_ANAGAINX_MICXGAIN 0 +#define REG_ANAGAINX_MICXGAIN_MAX 0x1F + +/* REG_ANAGAIN3 */ +#define REG_ANAGAIN3_HSLGAIN 4 +#define REG_ANAGAIN3_HSRGAIN 0 +#define REG_ANAGAIN3_HSXGAIN_MAX 0x0F + +/* REG_ANAGAIN4 */ +#define REG_ANAGAIN4_LINLGAIN 4 +#define REG_ANAGAIN4_LINRGAIN 0 +#define REG_ANAGAIN4_LINXGAIN_MAX 0x0F + +/* REG_DIGLINHSLGAIN */ +/* REG_DIGLINHSRGAIN */ +#define REG_DIGLINHSXGAIN_LINTOHSXGAIN 0 +#define REG_DIGLINHSXGAIN_LINTOHSXGAIN_MAX 0x13 + +/* REG_ADFILTCONF */ +#define REG_ADFILTCONF_AD1NH 7 +#define REG_ADFILTCONF_AD2NH 6 +#define REG_ADFILTCONF_AD3NH 5 +#define REG_ADFILTCONF_AD4NH 4 +#define REG_ADFILTCONF_AD1VOICE 3 +#define REG_ADFILTCONF_AD2VOICE 2 +#define REG_ADFILTCONF_AD3VOICE 1 +#define REG_ADFILTCONF_AD4VOICE 0 + +/* REG_DIGIFCONF1 */ +#define REG_DIGIFCONF1_ENMASTGEN 7 +#define REG_DIGIFCONF1_IF1BITCLKOS1 6 +#define REG_DIGIFCONF1_IF1BITCLKOS0 5 +#define REG_DIGIFCONF1_ENFSBITCLK1 4 +#define REG_DIGIFCONF1_IF0BITCLKOS1 2 +#define REG_DIGIFCONF1_IF0BITCLKOS0 1 +#define REG_DIGIFCONF1_ENFSBITCLK0 0 + +/* REG_DIGIFCONF2 */ +#define REG_DIGIFCONF2_FSYNC0P 6 +#define REG_DIGIFCONF2_BITCLK0P 5 +#define REG_DIGIFCONF2_IF0DEL 4 +#define REG_DIGIFCONF2_IF0FORMAT1 3 +#define REG_DIGIFCONF2_IF0FORMAT0 2 +#define REG_DIGIFCONF2_IF0WL1 1 +#define REG_DIGIFCONF2_IF0WL0 0 + +/* REG_DIGIFCONF3 */ +#define REG_DIGIFCONF3_IF0DATOIF1AD 7 +#define REG_DIGIFCONF3_IF0CLKTOIF1CLK 6 +#define REG_DIGIFCONF3_IF1MASTER 5 +#define REG_DIGIFCONF3_IF1DATOIF0AD 3 +#define REG_DIGIFCONF3_IF1CLKTOIF0CLK 2 +#define REG_DIGIFCONF3_IF0MASTER 1 +#define REG_DIGIFCONF3_IF0BFIFOEN 0 + +/* REG_DIGIFCONF4 */ +#define REG_DIGIFCONF4_FSYNC1P 6 +#define REG_DIGIFCONF4_BITCLK1P 5 +#define REG_DIGIFCONF4_IF1DEL 4 +#define REG_DIGIFCONF4_IF1FORMAT1 3 +#define REG_DIGIFCONF4_IF1FORMAT0 2 +#define REG_DIGIFCONF4_IF1WL1 1 +#define REG_DIGIFCONF4_IF1WL0 0 + +/* REG_ADSLOTSELX */ +#define REG_ADSLOTSELX_AD_OUT1_TO_SLOT_ODD 0x00 +#define REG_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD 0x01 +#define REG_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD 0x02 +#define REG_ADSLOTSELX_AD_OUT4_TO_SLOT_ODD 0x03 +#define REG_ADSLOTSELX_AD_OUT5_TO_SLOT_ODD 0x04 +#define REG_ADSLOTSELX_AD_OUT6_TO_SLOT_ODD 0x05 +#define REG_ADSLOTSELX_AD_OUT7_TO_SLOT_ODD 0x06 +#define REG_ADSLOTSELX_AD_OUT8_TO_SLOT_ODD 0x07 +#define REG_ADSLOTSELX_ZEROES_TO_SLOT_ODD 0x08 +#define REG_ADSLOTSELX_TRISTATE_TO_SLOT_ODD 0x0F +#define REG_ADSLOTSELX_AD_OUT1_TO_SLOT_EVEN 0x00 +#define REG_ADSLOTSELX_AD_OUT2_TO_SLOT_EVEN 0x10 +#define REG_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN 0x20 +#define REG_ADSLOTSELX_AD_OUT4_TO_SLOT_EVEN 0x30 +#define REG_ADSLOTSELX_AD_OUT5_TO_SLOT_EVEN 0x40 +#define REG_ADSLOTSELX_AD_OUT6_TO_SLOT_EVEN 0x50 +#define REG_ADSLOTSELX_AD_OUT7_TO_SLOT_EVEN 0x60 +#define REG_ADSLOTSELX_AD_OUT8_TO_SLOT_EVEN 0x70 +#define REG_ADSLOTSELX_ZEROES_TO_SLOT_EVEN 0x80 +#define REG_ADSLOTSELX_TRISTATE_TO_SLOT_EVEN 0xF0 +#define REG_ADSLOTSELX_EVEN_SHIFT 0 +#define REG_ADSLOTSELX_ODD_SHIFT 4 + +/* REG_ADSLOTHIZCTRL1 */ +/* REG_ADSLOTHIZCTRL2 */ +/* REG_ADSLOTHIZCTRL3 */ +/* REG_ADSLOTHIZCTRL4 */ +/* REG_DASLOTCONF1 */ +#define REG_DASLOTCONF1_DA12VOICE 7 +#define REG_DASLOTCONF1_SWAPDA12_34 6 +#define REG_DASLOTCONF1_DAI7TOADO1 5 + +/* REG_DASLOTCONF2 */ +#define REG_DASLOTCONF2_DAI8TOADO2 5 + +/* REG_DASLOTCONF3 */ +#define REG_DASLOTCONF3_DA34VOICE 7 +#define REG_DASLOTCONF3_DAI7TOADO3 5 + +/* REG_DASLOTCONF4 */ +#define REG_DASLOTCONF4_DAI8TOADO4 5 + +/* REG_DASLOTCONF5 */ +#define REG_DASLOTCONF5_DA56VOICE 7 +#define REG_DASLOTCONF5_DAI7TOADO5 5 + +/* REG_DASLOTCONF6 */ +#define REG_DASLOTCONF6_DAI8TOADO6 5 + +/* REG_DASLOTCONF7 */ +#define REG_DASLOTCONF7_DAI8TOADO7 5 + +/* REG_DASLOTCONF8 */ +#define REG_DASLOTCONF8_DAI7TOADO8 5 + +#define REG_DASLOTCONFX_SLTODAX_SHIFT 0 +#define REG_DASLOTCONFX_SLTODAX_MASK 0x1F + +/* REG_CLASSDCONF1 */ +#define REG_CLASSDCONF1_PARLHF 7 +#define REG_CLASSDCONF1_PARLVIB 6 +#define REG_CLASSDCONF1_VIB1SWAPEN 3 +#define REG_CLASSDCONF1_VIB2SWAPEN 2 +#define REG_CLASSDCONF1_HFLSWAPEN 1 +#define REG_CLASSDCONF1_HFRSWAPEN 0 + +/* REG_CLASSDCONF2 */ +#define REG_CLASSDCONF2_FIRBYP3 7 +#define REG_CLASSDCONF2_FIRBYP2 6 +#define REG_CLASSDCONF2_FIRBYP1 5 +#define REG_CLASSDCONF2_FIRBYP0 4 +#define REG_CLASSDCONF2_HIGHVOLEN3 3 +#define REG_CLASSDCONF2_HIGHVOLEN2 2 +#define REG_CLASSDCONF2_HIGHVOLEN1 1 +#define REG_CLASSDCONF2_HIGHVOLEN0 0 + +/* REG_CLASSDCONF3 */ +#define REG_CLASSDCONF3_DITHHPGAIN 4 +#define REG_CLASSDCONF3_DITHHPGAIN_MAX 0x0A +#define REG_CLASSDCONF3_DITHWGAIN 0 +#define REG_CLASSDCONF3_DITHWGAIN_MAX 0x0A + +/* REG_DMICFILTCONF */ +#define REG_DMICFILTCONF_ANCINSEL 7 +#define REG_DMICFILTCONF_DA3TOEAR 6 +#define REG_DMICFILTCONF_DMIC1SINC3 5 +#define REG_DMICFILTCONF_DMIC2SINC3 4 +#define REG_DMICFILTCONF_DMIC3SINC3 3 +#define REG_DMICFILTCONF_DMIC4SINC3 2 +#define REG_DMICFILTCONF_DMIC5SINC3 1 +#define REG_DMICFILTCONF_DMIC6SINC3 0 + +/* REG_DIGMULTCONF1 */ +#define REG_DIGMULTCONF1_DATOHSLEN 7 +#define REG_DIGMULTCONF1_DATOHSREN 6 +#define REG_DIGMULTCONF1_AD1SEL 5 +#define REG_DIGMULTCONF1_AD2SEL 4 +#define REG_DIGMULTCONF1_AD3SEL 3 +#define REG_DIGMULTCONF1_AD5SEL 2 +#define REG_DIGMULTCONF1_AD6SEL 1 +#define REG_DIGMULTCONF1_ANCSEL 0 + +/* REG_DIGMULTCONF2 */ +#define REG_DIGMULTCONF2_DATOHFREN 7 +#define REG_DIGMULTCONF2_DATOHFLEN 6 +#define REG_DIGMULTCONF2_HFRSEL 5 +#define REG_DIGMULTCONF2_HFLSEL 4 +#define REG_DIGMULTCONF2_FIRSID1SEL 2 +#define REG_DIGMULTCONF2_FIRSID2SEL 0 + +/* REG_ADDIGGAIN1 */ +/* REG_ADDIGGAIN2 */ +/* REG_ADDIGGAIN3 */ +/* REG_ADDIGGAIN4 */ +/* REG_ADDIGGAIN5 */ +/* REG_ADDIGGAIN6 */ +#define REG_ADDIGGAINX_FADEDISADX 6 +#define REG_ADDIGGAINX_ADXGAIN_MAX 0x3F + +/* REG_DADIGGAIN1 */ +/* REG_DADIGGAIN2 */ +/* REG_DADIGGAIN3 */ +/* REG_DADIGGAIN4 */ +/* REG_DADIGGAIN5 */ +/* REG_DADIGGAIN6 */ +#define REG_DADIGGAINX_FADEDISDAX 6 +#define REG_DADIGGAINX_DAXGAIN_MAX 0x3F + +/* REG_ADDIGLOOPGAIN1 */ +/* REG_ADDIGLOOPGAIN2 */ +#define REG_ADDIGLOOPGAINX_FADEDISADXL 6 +#define REG_ADDIGLOOPGAINX_ADXLBGAIN_MAX 0x3F + +/* REG_HSLEARDIGGAIN */ +#define REG_HSLEARDIGGAIN_HSSINC1 7 +#define REG_HSLEARDIGGAIN_FADEDISHSL 4 +#define REG_HSLEARDIGGAIN_HSLDGAIN_MAX 0x09 + +/* REG_HSRDIGGAIN */ +#define REG_HSRDIGGAIN_FADESPEED 6 +#define REG_HSRDIGGAIN_FADEDISHSR 4 +#define REG_HSRDIGGAIN_HSRDGAIN_MAX 0x09 + +/* REG_SIDFIRGAIN1 */ +/* REG_SIDFIRGAIN2 */ +#define REG_SIDFIRGAINX_FIRSIDXGAIN_MAX 0x1F + +/* REG_ANCCONF1 */ +#define REG_ANCCONF1_ANCIIRUPDATE 3 +#define REG_ANCCONF1_ENANC 2 +#define REG_ANCCONF1_ANCIIRINIT 1 +#define REG_ANCCONF1_ANCFIRUPDATE 0 + +/* REG_ANCCONF2 */ +/* REG_ANCCONF3 */ +/* REG_ANCCONF4 */ +/* REG_ANCCONF5 */ +/* REG_ANCCONF6 */ +/* REG_ANCCONF7 */ +/* REG_ANCCONF8 */ +/* REG_ANCCONF9 */ +/* REG_ANCCONF10 */ +/* REG_ANCCONF11 */ +/* REG_ANCCONF12 */ +/* REG_ANCCONF13 */ +/* REG_ANCCONF14 */ + +/* REG_SIDFIRADR */ +#define REG_SIDFIRADR_FIRSIDSET 7 +#define REG_SIDFIRADR_ADDRESS_SHIFT 0 +#define REG_SIDFIRADR_ADDRESS_MAX 0x7F + +/* REG_SIDFIRCOEF1 */ +/* REG_SIDFIRCOEF2 */ +#define REG_SIDFIRCOEFX_VALUE_SHIFT 0 +#define REG_SIDFIRCOEFX_VALUE_MAX 0xFF + +/* REG_SIDFIRCONF */ +#define REG_SIDFIRCONF_ENFIRSIDS 2 +#define REG_SIDFIRCONF_FIRSIDSTOIF1 1 +#define REG_SIDFIRCONF_FIRSIDBUSY 0 + +/* REG_AUDINTMASK1 */ +/* REG_AUDINTSOURCE1 */ +/* REG_AUDINTMASK2 */ +/* REG_AUDINTSOURCE2 */ + +/* REG_FIFOCONF1 */ +#define REG_FIFOCONF1_BFIFOMASK 0x80 +#define REG_FIFOCONF1_BFIFO19M2 0x40 +#define REG_FIFOCONF1_BFIFOINT_SHIFT 0 +#define REG_FIFOCONF1_BFIFOINT_MAX 0x3F + +/* REG_FIFOCONF2 */ +#define REG_FIFOCONF2_BFIFOTX_SHIFT 0 +#define REG_FIFOCONF2_BFIFOTX_MAX 0xFF + +/* REG_FIFOCONF3 */ +#define REG_FIFOCONF3_BFIFOEXSL_SHIFT 5 +#define REG_FIFOCONF3_BFIFOEXSL_MAX 0x5 +#define REG_FIFOCONF3_PREBITCLK0_SHIFT 2 +#define REG_FIFOCONF3_PREBITCLK0_MAX 0x7 +#define REG_FIFOCONF3_BFIFOMAST_SHIFT 1 +#define REG_FIFOCONF3_BFIFORUN_SHIFT 0 + +/* REG_FIFOCONF4 */ +#define REG_FIFOCONF4_BFIFOFRAMSW_SHIFT 0 +#define REG_FIFOCONF4_BFIFOFRAMSW_MAX 0xFF + +/* REG_FIFOCONF5 */ +#define REG_FIFOCONF5_BFIFOWAKEUP_SHIFT 0 +#define REG_FIFOCONF5_BFIFOWAKEUP_MAX 0xFF + +/* REG_FIFOCONF6 */ +#define REG_FIFOCONF6_BFIFOSAMPLE_SHIFT 0 +#define REG_FIFOCONF6_BFIFOSAMPLE_MAX 0xFF + +/* REG_AUDREV */ + +#endif diff --git a/sound/soc/codecs/av8100_audio.c b/sound/soc/codecs/av8100_audio.c new file mode 100644 index 00000000000..b163151efb7 --- /dev/null +++ b/sound/soc/codecs/av8100_audio.c @@ -0,0 +1,453 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ola Lilja <ola.o.lilja@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/soc.h> +#include <video/av8100.h> +#include <video/hdmi.h> + +#include "av8100_audio.h" + +/* codec private data */ +struct av8100_codec_dai_data { + struct hdmi_audio_settings as; +}; + +static struct av8100_codec_dai_data *get_dai_data_codec(struct snd_soc_codec *codec, + int dai_id) +{ + struct av8100_codec_dai_data *dai_data = snd_soc_codec_get_drvdata(codec); + return &dai_data[dai_id]; +} + +static struct av8100_codec_dai_data *get_dai_data(struct snd_soc_dai *codec_dai) +{ + return get_dai_data_codec(codec_dai->codec, codec_dai->id); +} + +/* Extended interface for codec-driver */ + +int av8100_audio_change_hdmi_audio_settings(struct snd_soc_dai *codec_dai, + struct hdmi_audio_settings *as) +{ + struct av8100_codec_dai_data *dai_data = get_dai_data(codec_dai); + + pr_debug("%s: Enter.\n", __func__); + + dai_data->as.audio_coding_type = as->audio_coding_type; + dai_data->as.audio_channel_count = as->audio_channel_count; + dai_data->as.sampling_frequency = as->sampling_frequency; + dai_data->as.sample_size = as->sample_size; + dai_data->as.channel_allocation = as->channel_allocation; + dai_data->as.level_shift_value = as->level_shift_value; + dai_data->as.downmix_inhibit = as->downmix_inhibit; + + return 0; +} + +static int av8100_codec_powerup(void) +{ + struct av8100_status status; + int ret; + + pr_debug("%s: Enter.\n", __func__); + + status = av8100_status_get(); + if (status.av8100_state < AV8100_OPMODE_STANDBY) { + pr_debug("%s: Powering up AV8100.", __func__); + ret = av8100_powerup(); + if (ret != 0) { + pr_err("%s: Power up AV8100 failed " + "(av8100_powerup returned %d)!\n", + __func__, + ret); + return -EINVAL; + } + } + if (status.av8100_state < AV8100_OPMODE_INIT) { + ret = av8100_download_firmware(NULL, 0, I2C_INTERFACE); + if (ret != 0) { + pr_err("%s: Download firmware failed " + "(av8100_download_firmware returned %d)!\n", + __func__, + ret); + return -EINVAL; + } + } + + return 0; +} + +static int av8100_codec_setup_hdmi_format(void) +{ + union av8100_configuration config; + int ret; + + pr_debug("%s: Enter.\n", __func__); + + pr_debug("%s: hdmi_mode = AV8100_HDMI_ON.", __func__); + pr_debug("%s: hdmi_format = AV8100_HDMI.", __func__); + config.hdmi_format.hdmi_mode = AV8100_HDMI_ON; + config.hdmi_format.hdmi_format = AV8100_HDMI; + ret = av8100_conf_prep(AV8100_COMMAND_HDMI, &config); + if (ret != 0) { + pr_err("%s: Setting hdmi_format failed " + "(av8100_conf_prep returned %d)!\n", + __func__, + ret); + return -EINVAL; + } + ret = av8100_conf_w(AV8100_COMMAND_HDMI, + NULL, + NULL, + I2C_INTERFACE); + if (ret != 0) { + pr_err("%s: Setting hdmi_format failed " + "(av8100_conf_w returned %d)!\n", + __func__, + ret); + return -EINVAL; + } + + return 0; +} + +static int av8100_codec_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + pr_debug("%s: Enter.\n", __func__); + + return 0; +} + +static int av8100_codec_send_audio_infoframe(struct hdmi_audio_settings *as) +{ + union av8100_configuration config; + struct av8100_infoframes_format_cmd info_fr; + int ret; + + pr_debug("%s: Enter.\n", __func__); + + pr_debug("%s: HDMI-settings:\n", __func__); + pr_debug("%s: audio_coding_type = %d\n", __func__, as->audio_coding_type); + pr_debug("%s: audio_channel_count = %d\n", __func__, as->audio_channel_count); + pr_debug("%s: sampling_frequency = %d\n", __func__, as->sampling_frequency); + pr_debug("%s: sample_size = %d\n", __func__, as->sample_size); + pr_debug("%s: channel_allocation = %d\n", __func__, as->channel_allocation); + pr_debug("%s: level_shift_value = %d\n", __func__, as->level_shift_value); + pr_debug("%s: downmix_inhibit = %d\n", __func__, as->downmix_inhibit); + + /* Prepare the infoframe from the hdmi_audio_settings struct */ + pr_info("%s: Preparing audio info-frame.", __func__); + info_fr.type = 0x84; + info_fr.version = 0x01; + info_fr.length = 0x0a; + info_fr.data[0] = (as->audio_coding_type << 4) | as->audio_channel_count; + info_fr.data[1] = (as->sampling_frequency << 2) | as->sample_size; + info_fr.data[2] = 0; + info_fr.data[3] = as->channel_allocation; + info_fr.data[4] = ((int)as->downmix_inhibit << 7) | + (as->level_shift_value << 3); + info_fr.data[5] = 0; + info_fr.data[6] = 0; + info_fr.data[7] = 0; + info_fr.data[8] = 0; + info_fr.data[9] = 0; + info_fr.crc = info_fr.version + + info_fr.length + + info_fr.data[0] + + info_fr.data[1] + + info_fr.data[3] + + info_fr.data[4]; + config.infoframes_format.type = info_fr.type; + config.infoframes_format.version = info_fr.version; + config.infoframes_format.crc = info_fr.crc; + config.infoframes_format.length = info_fr.length; + memcpy(&config.infoframes_format.data, info_fr.data, info_fr.length); + + /* Send audio info-frame */ + pr_info("%s: Sending audio info-frame.", __func__); + ret = av8100_conf_prep(AV8100_COMMAND_INFOFRAMES, &config); + if (ret != 0) { + pr_err("%s: Sending audio info-frame failed " + "(av8100_conf_prep returned %d)!\n", + __func__, + ret); + return -EINVAL; + } + ret = av8100_conf_w(AV8100_COMMAND_INFOFRAMES, + NULL, + NULL, + I2C_INTERFACE); + if (ret != 0) { + pr_err("%s: Sending audio info-frame failed " + "(av8100_conf_w returned %d)!\n", + __func__, + ret); + return -EINVAL; + } + + return 0; +} + +static int av8100_codec_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params, + struct snd_soc_dai *codec_dai) +{ + struct av8100_codec_dai_data *dai_data = get_dai_data(codec_dai); + + pr_debug("%s: Enter.\n", __func__); + + av8100_codec_send_audio_infoframe(&dai_data->as); + + return 0; +} + +static int av8100_codec_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) +{ + int ret; + + pr_debug("%s: Enter.\n", __func__); + + /* Startup AV8100 if it is not already started */ + ret = av8100_codec_powerup(); + if (ret != 0) { + pr_err("%s: Startup of AV8100 failed " + "(av8100_codec_powerupAV8100 returned %d)!\n", + __func__, + ret); + return -EINVAL; + } + + return 0; +} + +static void av8100_codec_pcm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) +{ + pr_debug("%s: Enter.\n", __func__); +} + +static int av8100_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, + unsigned int freq, int dir) +{ + pr_debug("%s: Enter.\n", __func__); + + return 0; +} + +static int av8100_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + union av8100_configuration config; + int ret; + + pr_debug("%s: Enter.\n", __func__); + + /* Set the HDMI format of AV8100 */ + ret = av8100_codec_setup_hdmi_format(); + if (ret != 0) + return ret; + + /* Set the audio input format of AV8100 */ + config.audio_input_format.audio_input_if_format = + ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_B) ? + AV8100_AUDIO_TDM_MODE : AV8100_AUDIO_I2SDELAYED_MODE; + config.audio_input_format.audio_if_mode = + ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) ? + AV8100_AUDIO_MASTER : AV8100_AUDIO_SLAVE; + pr_info("%s: Setting audio_input_format " + "(if_format = %d, if_mode = %d).", + __func__, + config.audio_input_format.audio_input_if_format, + config.audio_input_format.audio_if_mode); + config.audio_input_format.i2s_input_nb = 1; + config.audio_input_format.sample_audio_freq = AV8100_AUDIO_FREQ_48KHZ; + config.audio_input_format.audio_word_lg = AV8100_AUDIO_16BITS; + config.audio_input_format.audio_format = AV8100_AUDIO_LPCM_MODE; + config.audio_input_format.audio_mute = AV8100_AUDIO_MUTE_DISABLE; + ret = av8100_conf_prep(AV8100_COMMAND_AUDIO_INPUT_FORMAT, &config); + if (ret != 0) { + pr_err("%s: Setting audio_input_format failed " + "(av8100_conf_prep returned %d)!\n", + __func__, + ret); + return -EINVAL; + } + ret = av8100_conf_w(AV8100_COMMAND_AUDIO_INPUT_FORMAT, + NULL, + NULL, + I2C_INTERFACE); + if (ret != 0) { + pr_err("%s: Setting audio_input_format failed " + "(av8100_conf_w returned %d)!\n", + __func__, + ret); + return -EINVAL; + } + + return 0; +} + +struct snd_soc_dai_driver av8100_dai_driver = { + .name = "av8100-codec-dai", + .playback = { + .stream_name = "AV8100 Playback", + .channels_min = 1, + .channels_max = 8, + .rates = AV8100_SUPPORTED_RATE, + .formats = AV8100_SUPPORTED_FMT, + }, + .ops = (struct snd_soc_dai_ops[]) { + { + .prepare = av8100_codec_pcm_prepare, + .hw_params = av8100_codec_pcm_hw_params, + .startup = av8100_codec_pcm_startup, + .shutdown = av8100_codec_pcm_shutdown, + .set_sysclk = av8100_codec_set_dai_sysclk, + .set_fmt = av8100_codec_set_dai_fmt, + } + }, +}; +EXPORT_SYMBOL_GPL(av8100_dai_driver); + +static int av8100_codec_probe(struct snd_soc_codec *codec) +{ + pr_debug("%s: Enter (codec->name = %s).\n", __func__, codec->name); + + return 0; +} + +static int av8100_codec_remove(struct snd_soc_codec *codec) +{ + pr_debug("%s: Enter (codec->name = %s).\n", __func__, codec->name); + + return 0; +} + +static int av8100_codec_suspend(struct snd_soc_codec *codec, pm_message_t state) +{ + pr_debug("%s: Enter (codec->name = %s).\n", __func__, codec->name); + + return 0; +} + +static int av8100_codec_resume(struct snd_soc_codec *codec) +{ + pr_debug("%s: Enter (codec->name = %s).\n", __func__, codec->name); + + return 0; +} + +struct snd_soc_codec_driver av8100_codec_drv = { + .probe = av8100_codec_probe, + .remove = av8100_codec_remove, + .suspend = av8100_codec_suspend, + .resume = av8100_codec_resume +}; + +static __devinit int av8100_codec_drv_probe(struct platform_device *pdev) +{ + struct av8100_codec_dai_data *dai_data; + int ret; + + pr_debug("%s: Enter.\n", __func__); + + pr_info("%s: Init codec private data..\n", __func__); + dai_data = kzalloc(sizeof(struct av8100_codec_dai_data), GFP_KERNEL); + if (dai_data == NULL) + return -ENOMEM; + + /* Setup hdmi_audio_settings default values */ + dai_data[0].as.audio_coding_type = AV8100_CODEC_CT_IEC60958_PCM; + dai_data[0].as.audio_channel_count = AV8100_CODEC_CC_2CH; + dai_data[0].as.sampling_frequency = AV8100_CODEC_SF_48KHZ; + dai_data[0].as.sample_size = AV8100_CODEC_SS_16BIT; + dai_data[0].as.channel_allocation = AV8100_CODEC_CA_FL_FR; + dai_data[0].as.level_shift_value = AV8100_CODEC_LSV_0DB; + dai_data[0].as.downmix_inhibit = false; + + platform_set_drvdata(pdev, dai_data); + + pr_info("%s: Register codec.\n", __func__); + ret = snd_soc_register_codec(&pdev->dev, &av8100_codec_drv, &av8100_dai_driver, 1); + if (ret < 0) { + pr_debug("%s: Error: Failed to register codec (ret = %d).\n", + __func__, + ret); + return ret; + } + + return 0; +} + +static int __devexit av8100_codec_drv_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + kfree(platform_get_drvdata(pdev)); + return 0; +} + +static const struct platform_device_id av8100_codec_platform_id[] = { + { "av8100-codec", 0 }, + { } +}; +MODULE_DEVICE_TABLE(platform, av8100_codec_platform_id); + +static struct platform_driver av8100_codec_platform_driver = { + .driver = { + .name = "av8100-codec", + .owner = THIS_MODULE, + }, + .probe = av8100_codec_drv_probe, + .remove = __devexit_p(av8100_codec_drv_remove), + .id_table = av8100_codec_platform_id, +}; + +static int __devinit av8100_codec_platform_drv_init(void) +{ + int ret; + + pr_debug("%s: Enter.\n", __func__); + + ret = platform_driver_register(&av8100_codec_platform_driver); + if (ret != 0) { + pr_err("Failed to register AV8100 platform driver (%d)!\n", ret); + } + + return ret; +} + +static void __exit av8100_codec_platform_drv_exit(void) +{ + pr_debug("%s: Enter.\n", __func__); + + platform_driver_unregister(&av8100_codec_platform_driver); +} + +module_init(av8100_codec_platform_drv_init); +module_exit(av8100_codec_platform_drv_exit); + +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/av8100_audio.h b/sound/soc/codecs/av8100_audio.h new file mode 100644 index 00000000000..594d66e97ee --- /dev/null +++ b/sound/soc/codecs/av8100_audio.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ola Lilja <ola.o.lilja@stericsson.com>, + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ +#ifndef AV8100_AUDIO_CODEC_H +#define AV8100_AUDIO_CODEC_H + +/* Supported sampling rates */ +#define AV8100_SUPPORTED_RATE (SNDRV_PCM_RATE_48000) + +/* Supported data formats */ +#define AV8100_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE) + +/* TDM-slot mask */ +#define AV8100_CODEC_MASK_MONO 0x0001 +#define AV8100_CODEC_MASK_STEREO 0x0005 +#define AV8100_CODEC_MASK_2DOT1 0x0015 +#define AV8100_CODEC_MASK_QUAD 0x0505 +#define AV8100_CODEC_MASK_5DOT0 0x0545 +#define AV8100_CODEC_MASK_5DOT1 0x0555 +#define AV8100_CODEC_MASK_7DOT0 0x5545 +#define AV8100_CODEC_MASK_7DOT1 0x5555 + +enum hdmi_audio_coding_type { + AV8100_CODEC_CT_REFER, + AV8100_CODEC_CT_IEC60958_PCM, + AV8100_CODEC_CT_AC3, + AV8100_CODEC_CT_MP3, + AV8100_CODEC_CT_MPEG2, + AV8100_CODEC_CT_AAC, + AV8100_CODEC_CT_DTS_ATRAC, + AV8100_CODEC_CT_ONE_BIT_AUDIO, + AV8100_CODEC_CT_DOLBY_DIGITAL, + AV8100_CODEC_CT_DTS_HD, + AV8100_CODEC_CT_MAT, + AV8100_CODEC_CT_DTS, + AV8100_CODEC_CT_WMA_PRO +}; + +enum hdmi_audio_channel_count { + AV8100_CODEC_CC_REFER, + AV8100_CODEC_CC_2CH, + AV8100_CODEC_CC_3CH, + AV8100_CODEC_CC_4CH, + AV8100_CODEC_CC_5CH, + AV8100_CODEC_CC_6CH, + AV8100_CODEC_CC_7CH, + AV8100_CODEC_CC_8CH +}; + +enum hdmi_sampling_frequency { + AV8100_CODEC_SF_REFER, + AV8100_CODEC_SF_32KHZ, + AV8100_CODEC_SF_44_1KHZ, + AV8100_CODEC_SF_48KHZ, + AV8100_CODEC_SF_88_2KHZ, + AV8100_CODEC_SF_96KHZ, + AV8100_CODEC_SF_176_4KHZ, + AV8100_CODEC_SF_192KHZ +}; + +enum hdmi_sample_size { + AV8100_CODEC_SS_REFER, + AV8100_CODEC_SS_16BIT, + AV8100_CODEC_SS_20BIT, + AV8100_CODEC_SS_24BIT +}; + +enum hdmi_speaker_placement { + AV8100_CODEC_SP_FL, /* Front Left */ + AV8100_CODEC_SP_FC, /* Front Center */ + AV8100_CODEC_SP_FR, /* Front Right */ + AV8100_CODEC_SP_FLC, /* Front Left Center */ + AV8100_CODEC_SP_FRC, /* Front Right Center */ + AV8100_CODEC_SP_RL, /* Rear Left */ + AV8100_CODEC_SP_RC, /* Rear Center */ + AV8100_CODEC_SP_RR, /* Rear Right */ + AV8100_CODEC_SP_RLC, /* Rear Left Center */ + AV8100_CODEC_SP_RRC, /* Rear Right Center */ + AV8100_CODEC_SP_LFE, /* Low Frequency Effekt */ +}; + +enum hdmi_channel_allocation { + AV8100_CODEC_CA_FL_FR, /* 0x00, Stereo */ + AV8100_CODEC_CA_FL_FR_LFE, /* 0x01, 2.1 */ + AV8100_CODEC_CA_FL_FR_FC, /* 0x02*/ + AV8100_CODEC_CA_FL_FR_LFE_FC, /* 0x03*/ + AV8100_CODEC_CA_FL_FR_RC, /* 0x04*/ + AV8100_CODEC_CA_FL_FR_LFE_RC, /* 0x05*/ + AV8100_CODEC_CA_FL_FR_FC_RC, /* 0x06*/ + AV8100_CODEC_CA_FL_FR_LFE_FC_RC, /* 0x07*/ + AV8100_CODEC_CA_FL_FR_RL_RR, /* 0x08, Quad */ + AV8100_CODEC_CA_FL_FR_LFE_RL_RR, /* 0x09*/ + AV8100_CODEC_CA_FL_FR_FC_RL_RR, /* 0x0a, 5.0*/ + AV8100_CODEC_CA_FL_FR_LFE_FC_RL_RR, /* 0x0b, 5.1*/ + AV8100_CODEC_CA_FL_FR_RL_RR_RC, /* 0x0c*/ + AV8100_CODEC_CA_FL_FR_LFE_RL_RR_RC, /* 0x0d*/ + AV8100_CODEC_CA_FL_FR_RC_RL_RR_RC, /* 0x0e*/ + AV8100_CODEC_CA_FL_FR_LFE_RC_RL_RR_RC, /* 0x0f*/ + AV8100_CODEC_CA_FL_FR_RL_RR_RLC_RRC, /* 0x10*/ + AV8100_CODEC_CA_FL_FR_LFE_RL_RR_RLC_RRC, /* 0x11*/ + AV8100_CODEC_CA_FL_FR_FC_RL_RR_RLC_RRC, /* 0x12*/ + AV8100_CODEC_CA_FL_FR_LFE_FC_RL_RR_RLC_RRC, /* 0x13*/ + AV8100_CODEC_CA_FL_FR_FLC_FRC, /* 0x14*/ + AV8100_CODEC_CA_FL_FR_LFE_FLC_FRC, /* 0x15*/ + AV8100_CODEC_CA_FL_FR_FC_FLC_FRC, /* 0x16*/ + AV8100_CODEC_CA_FL_FR_LFE_FC_FLC_FRC, /* 0x17*/ + AV8100_CODEC_CA_FL_FR_RC_FLC_FRC, /* 0x18*/ + AV8100_CODEC_CA_FL_FR_LFE_RC_FLC_FRC, /* 0x19*/ + AV8100_CODEC_CA_FL_FR_FC_RC_FLC_FRC, /* 0x1a*/ + AV8100_CODEC_CA_FL_FR_LFE_FR_FC_RC_FLC_FRC, /* 0x1b*/ + AV8100_CODEC_CA_FL_FR_RL_RR_FLC_FRC, /* 0x1c*/ + AV8100_CODEC_CA_FL_FR_LFE_RL_RR_FLC_FRC, /* 0x1d*/ + AV8100_CODEC_CA_FL_FR_FC_RL_RR_FLC_FRC, /* 0x1e*/ + AV8100_CODEC_CA_FL_FR_LFE_FC_RL_RR_FLC_FRC /* 0x1f, 7.1 */ +}; + +enum hdmi_level_shift_value { + AV8100_CODEC_LSV_0DB, + AV8100_CODEC_LSV_1DB, + AV8100_CODEC_LSV_2DB, + AV8100_CODEC_LSV_3DB, + AV8100_CODEC_LSV_4DB, + AV8100_CODEC_LSV_5DB, + AV8100_CODEC_LSV_6DB, + AV8100_CODEC_LSV_7DB, + AV8100_CODEC_LSV_8DB, + AV8100_CODEC_LSV_9DB, + AV8100_CODEC_LSV_10DB, + AV8100_CODEC_LSV_11DB, + AV8100_CODEC_LSV_12DB, + AV8100_CODEC_LSV_13DB, + AV8100_CODEC_LSV_14DB, + AV8100_CODEC_LSV_15DB +}; + +struct hdmi_audio_settings { + enum hdmi_audio_coding_type audio_coding_type; + enum hdmi_audio_channel_count audio_channel_count; + enum hdmi_sampling_frequency sampling_frequency; + enum hdmi_sample_size sample_size; + enum hdmi_channel_allocation channel_allocation; + enum hdmi_level_shift_value level_shift_value; + bool downmix_inhibit; +}; + +/* Extended interface for codec-driver */ +int av8100_audio_change_hdmi_audio_settings(struct snd_soc_dai *dai, + struct hdmi_audio_settings *as); + +#endif /* AV8100_AUDIO_CODEC_H */ + + + diff --git a/sound/soc/codecs/cg29xx.c b/sound/soc/codecs/cg29xx.c new file mode 100644 index 00000000000..1ee3f3c38af --- /dev/null +++ b/sound/soc/codecs/cg29xx.c @@ -0,0 +1,773 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Roger Nilsson <roger.xr.nilsson@stericsson.com>, + * Ola Lilja <ola.o.lilja@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + #include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <linux/bitops.h> +#include <../../../drivers/staging/cg2900/include/cg2900_audio.h> + +#include "cg29xx.h" + +#define CG29XX_NBR_OF_DAI 2 +#define CG29XX_SUPPORTED_RATE_PCM (SNDRV_PCM_RATE_8000 | \ + SNDRV_PCM_RATE_16000) + +#define CG29XX_SUPPORTED_RATE (SNDRV_PCM_RATE_8000 | \ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) + +#define CG29XX_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE) + +enum cg29xx_dai_direction { + CG29XX_DAI_DIRECTION_TX, + CG29XX_DAI_DIRECTION_RX +}; + +static int cg29xx_dai_startup( + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); + +static int cg29xx_dai_prepare( + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); + +static int cg29xx_dai_hw_params( + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params, + struct snd_soc_dai *dai); + +static void cg29xx_dai_shutdown( + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); + +static int cg29xx_set_dai_sysclk( + struct snd_soc_dai *codec_dai, + int clk_id, + unsigned int freq, int dir); + +static int cg29xx_set_dai_fmt( + struct snd_soc_dai *codec_dai, + unsigned int fmt); + +static int cg29xx_set_tdm_slot( + struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, + int slot_width); + +static struct cg29xx_codec codec_private = { + .session = 0, +}; + +static struct snd_soc_dai_ops cg29xx_dai_driver_dai_ops = { + .startup = cg29xx_dai_startup, + .prepare = cg29xx_dai_prepare, + .hw_params = cg29xx_dai_hw_params, + .shutdown = cg29xx_dai_shutdown, + .set_sysclk = cg29xx_set_dai_sysclk, + .set_fmt = cg29xx_set_dai_fmt, + .set_tdm_slot = cg29xx_set_tdm_slot +}; + +struct snd_soc_dai_driver cg29xx_dai_driver[] = { + { + .name = "cg29xx-codec-dai.0", + .id = 0, + .playback = { + .stream_name = "CG29xx.0 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = CG29XX_SUPPORTED_RATE, + .formats = CG29XX_SUPPORTED_FMT, + }, + .capture = { + .stream_name = "CG29xx.0 Capture", + .channels_min = 2, + .channels_max = 2, + .rates = CG29XX_SUPPORTED_RATE, + .formats = CG29XX_SUPPORTED_FMT, + }, + .ops = &cg29xx_dai_driver_dai_ops, + .symmetric_rates = 1, + }, + { + .name = "cg29xx-codec-dai.1", + .id = 1, + .playback = { + .stream_name = "CG29xx.1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = CG29XX_SUPPORTED_RATE_PCM, + .formats = CG29XX_SUPPORTED_FMT, + }, + .capture = { + .stream_name = "CG29xx.1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = CG29XX_SUPPORTED_RATE_PCM, + .formats = CG29XX_SUPPORTED_FMT, + }, + .ops = &cg29xx_dai_driver_dai_ops, + .symmetric_rates = 1, + } +}; +EXPORT_SYMBOL_GPL(cg29xx_dai_driver); + +static const char *enum_ifs_input_select[] = { + "BT_SCO", "FM_RX" +}; + +static const char *enum_ifs_output_select[] = { + "BT_SCO", "FM_TX" +}; + +/* If0 Input Select */ +static struct soc_enum if0_input_select = + SOC_ENUM_SINGLE(INTERFACE0_INPUT_SELECT, 0, + ARRAY_SIZE(enum_ifs_input_select), + enum_ifs_input_select); + +/* If1 Input Select */ +static struct soc_enum if1_input_select = + SOC_ENUM_SINGLE(INTERFACE1_INPUT_SELECT, 0, + ARRAY_SIZE(enum_ifs_input_select), + enum_ifs_input_select); + +/* If0 Output Select */ +static struct soc_enum if0_output_select = + SOC_ENUM_SINGLE(INTERFACE0_OUTPUT_SELECT, 0, + ARRAY_SIZE(enum_ifs_output_select), + enum_ifs_output_select); + +/* If1 Output Select */ +static struct soc_enum if1_output_select = + SOC_ENUM_SINGLE(INTERFACE1_OUTPUT_SELECT, 4, + ARRAY_SIZE(enum_ifs_output_select), + enum_ifs_output_select); + +static struct snd_kcontrol_new cg29xx_snd_controls[] = { + SOC_ENUM("If0 Input Select", if0_input_select), + SOC_ENUM("If1 Input Select", if1_input_select), + SOC_ENUM("If0 Output Select", if0_output_select), + SOC_ENUM("If1 Output Select", if1_output_select), +}; + + +static struct cg29xx_codec_dai_data *get_dai_data_codec(struct snd_soc_codec *codec, + int dai_id) +{ + struct cg29xx_codec_dai_data *codec_drvdata = snd_soc_codec_get_drvdata(codec); + return &codec_drvdata[dai_id]; +} + +static struct cg29xx_codec_dai_data *get_dai_data(struct snd_soc_dai *codec_dai) +{ + return get_dai_data_codec(codec_dai->codec, codec_dai->id); +} + +static int cg29xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, + unsigned int freq, int dir) +{ + return 0; +} + +static int cg29xx_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct cg29xx_codec_dai_data *dai_data = get_dai_data(codec_dai); + unsigned int prot; + unsigned int msel; + + prot = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + msel = fmt & SND_SOC_DAIFMT_MASTER_MASK; + + switch (prot) { + case SND_SOC_DAIFMT_I2S: + if (dai_data->config.port != PORT_0_I2S) { + pr_err("cg29xx_dai: unsupported DAI format 0x%x\n", + fmt); + return -EINVAL; + } + + if (msel == SND_SOC_DAIFMT_CBM_CFM) + dai_data->config.conf.i2s.mode = DAI_MODE_MASTER; + else + dai_data->config.conf.i2s.mode = DAI_MODE_SLAVE; + break; + + case SND_SOC_DAIFMT_DSP_A: + if (dai_data->config.port != PORT_1_I2S_PCM || + msel == SND_SOC_DAIFMT_CBM_CFM) { + pr_err("cg29xx_dai: unsupported DAI format 0x%x\n", + fmt); + return -EINVAL; + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int cg29xx_set_tdm_slot(struct snd_soc_dai *codec_dai, + unsigned int tx_mask, + unsigned int rx_mask, + int slots, + int slot_width) +{ + struct cg29xx_codec_dai_data *dai_data = get_dai_data(codec_dai); + + if (dai_data->config.port != PORT_1_I2S_PCM) + return -EINVAL; + + dai_data->config.conf.i2s_pcm.slot_0_used = + (tx_mask | rx_mask) & (1<<CG29XX_DAI_SLOT0_SHIFT) ? + true : false; + dai_data->config.conf.i2s_pcm.slot_1_used = + (tx_mask | rx_mask) & (1<<CG29XX_DAI_SLOT1_SHIFT) ? + true : false; + dai_data->config.conf.i2s_pcm.slot_2_used = + (tx_mask | rx_mask) & (1<<CG29XX_DAI_SLOT2_SHIFT) ? + true : false; + dai_data->config.conf.i2s_pcm.slot_3_used = + (tx_mask | rx_mask) & (1<<CG29XX_DAI_SLOT3_SHIFT) ? + true : false; + + dai_data->config.conf.i2s_pcm.slot_0_start = 0; + dai_data->config.conf.i2s_pcm.slot_1_start = slot_width; + dai_data->config.conf.i2s_pcm.slot_2_start = 2 * slot_width; + dai_data->config.conf.i2s_pcm.slot_3_start = 3 * slot_width; + + return 0; +} + +static int cg29xx_configure_endp(struct cg29xx_codec_dai_data *dai_data, + enum cg2900_audio_endpoint_id endpid) +{ + struct cg2900_endpoint_config config; + int err; + enum cg2900_dai_sample_rate dai_sr; + enum cg2900_endpoint_sample_rate endp_sr; + + switch (dai_data->config.port) { + default: + case PORT_0_I2S: + dai_sr = dai_data->config.conf.i2s.sample_rate; + break; + + case PORT_1_I2S_PCM: + dai_sr = dai_data->config.conf.i2s_pcm.sample_rate; + break; + } + + switch (dai_sr) { + default: + case SAMPLE_RATE_8: + endp_sr = ENDPOINT_SAMPLE_RATE_8_KHZ; + break; + case SAMPLE_RATE_16: + endp_sr = ENDPOINT_SAMPLE_RATE_16_KHZ; + break; + case SAMPLE_RATE_44_1: + endp_sr = ENDPOINT_SAMPLE_RATE_44_1_KHZ; + break; + case SAMPLE_RATE_48: + endp_sr = ENDPOINT_SAMPLE_RATE_48_KHZ; + break; + } + + config.endpoint_id = endpid; + + switch (endpid) { + default: + case ENDPOINT_BT_SCO_INOUT: + config.config.sco.sample_rate = endp_sr; + break; + + case ENDPOINT_FM_TX: + case ENDPOINT_FM_RX: + config.config.fm.sample_rate = endp_sr; + break; + } + + err = cg2900_audio_config_endpoint(codec_private.session, &config); + + return err; +} + +static int cg29xx_stop_if(struct cg29xx_codec_dai_data *dai_data, + enum cg29xx_dai_direction direction) +{ + int err = 0; + unsigned int *stream; + + if (direction == CG29XX_DAI_DIRECTION_TX) + stream = &dai_data->tx_active; + else + stream = &dai_data->rx_active; + + if (*stream) { + err = cg2900_audio_stop_stream( + codec_private.session, + *stream); + if (!err) { + *stream = 0; + } else { + pr_err("asoc cg29xx - %s - Failed to stop stream on interface %d.\n", + __func__, + dai_data->config.port); + } + } + + return err; +} + +static int cg29xx_start_if(struct cg29xx_codec_dai_data *dai_data, + enum cg29xx_dai_direction direction) +{ + enum cg2900_audio_endpoint_id if_endpid; + enum cg2900_audio_endpoint_id endpid; + unsigned int *stream; + int err; + + if (dai_data->config.port == PORT_0_I2S) + if_endpid = ENDPOINT_PORT_0_I2S; + else + if_endpid = ENDPOINT_PORT_1_I2S_PCM; + + if (direction == CG29XX_DAI_DIRECTION_RX) { + switch (dai_data->output_select) { + default: + case 0: + endpid = ENDPOINT_BT_SCO_INOUT; + break; + case 1: + endpid = ENDPOINT_FM_TX; + } + stream = &dai_data->rx_active; + } else { + switch (dai_data->input_select) { + default: + case 0: + endpid = ENDPOINT_BT_SCO_INOUT; + break; + case 1: + endpid = ENDPOINT_FM_RX; + } + + stream = &dai_data->tx_active; + } + + if (*stream || (endpid == ENDPOINT_BT_SCO_INOUT)) { + pr_debug("asoc cg29xx - %s - The interface has already been started.\n", + __func__); + return 0; + } + + pr_debug("asoc cg29xx - %s - direction: %d, if_id: %d endpid: %d\n", + __func__, + direction, + if_endpid, + endpid); + + err = cg29xx_configure_endp(dai_data, endpid); + + if (err) { + pr_err("asoc cg29xx - %s - Configure endpoint id: %d failed.\n", + __func__, + endpid); + + return err; + } + + err = cg2900_audio_start_stream(codec_private.session, + if_endpid, + endpid, + stream); + + return err; +} + +static int cg29xx_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int err = 0; + + if (!codec_private.session) + err = cg2900_audio_open(&codec_private.session, NULL); + + return err; +} + +static int cg29xx_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) +{ + struct cg29xx_codec_dai_data *dai_data = get_dai_data(codec_dai); + int err = 0; + enum cg29xx_dai_direction direction; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + direction = CG29XX_DAI_DIRECTION_RX; + else + direction = CG29XX_DAI_DIRECTION_TX; + + err = cg29xx_start_if(dai_data, direction); + + return err; +} + +static void cg29xx_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) +{ + struct cg29xx_codec_dai_data *dai_data = get_dai_data(codec_dai); + enum cg29xx_dai_direction direction; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + direction = CG29XX_DAI_DIRECTION_RX; + else + direction = CG29XX_DAI_DIRECTION_TX; + + (void) cg29xx_stop_if(dai_data, direction); +} + +static int cg29xx_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params, + struct snd_soc_dai *codec_dai) +{ + struct cg29xx_codec_dai_data *dai_data = get_dai_data(codec_dai); + enum cg2900_dai_fs_duration duration = SYNC_DURATION_32; + enum cg2900_dai_bit_clk bclk = BIT_CLK_512; + int sr; + int err = 0; + enum cg2900_dai_stream_ratio ratio = STREAM_RATIO_FM48_VOICE16; + + pr_debug("cg29xx asoc - %s called. Port: %d.\n", + __func__, + dai_data->config.port); + + switch (params_rate(hw_params)) { + case 8000: + sr = SAMPLE_RATE_8; + bclk = BIT_CLK_512; + duration = SYNC_DURATION_32; + ratio = STREAM_RATIO_FM48_VOICE8; + break; + case 16000: + sr = SAMPLE_RATE_16; + bclk = BIT_CLK_512; + duration = SYNC_DURATION_32; + ratio = STREAM_RATIO_FM48_VOICE16; + break; + case 44100: + sr = SAMPLE_RATE_44_1; + break; + case 48000: + sr = SAMPLE_RATE_48; + break; + default: + return -EINVAL; + } + + if (dai_data->config.port == PORT_0_I2S) { + dai_data->config.conf.i2s.sample_rate = sr; + } else { + dai_data->config.conf.i2s_pcm.sample_rate = sr; + dai_data->config.conf.i2s_pcm.duration = duration; + dai_data->config.conf.i2s_pcm.clk = bclk; + dai_data->config.conf.i2s_pcm.ratio = ratio; + } + + if (!(dai_data->tx_active | dai_data->rx_active) && dai_data->config.port != PORT_1_I2S_PCM) { + err = cg2900_audio_set_dai_config( + codec_private.session, + &dai_data->config); + + pr_debug("asoc cg29xx: cg2900_audio_set_dai_config" + "on port %d completed with result: %d.\n", + dai_data->config.port, + err); + } + + return err; +} + +static unsigned int cg29xx_codec_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + struct cg29xx_codec_dai_data *dai_data; + + switch (reg) { + case INTERFACE0_INPUT_SELECT: + dai_data = get_dai_data_codec(codec, 0); + return dai_data->input_select; + + case INTERFACE1_INPUT_SELECT: + dai_data = get_dai_data_codec(codec, 1); + return dai_data->input_select; + + case INTERFACE0_OUTPUT_SELECT: + dai_data = get_dai_data_codec(codec, 0); + return dai_data->output_select; + + case INTERFACE1_OUTPUT_SELECT: + dai_data = get_dai_data_codec(codec, 1); + return dai_data->output_select; + + default: + return 0; + } + + return 0; +} + +static int cg29xx_codec_write(struct snd_soc_codec *codec, + unsigned int reg, + unsigned int value) +{ + struct cg29xx_codec_dai_data *dai_data; + enum cg29xx_dai_direction direction; + bool restart_if = false; + int old_value; + + switch (reg) { + case INTERFACE0_INPUT_SELECT: + dai_data = get_dai_data_codec(codec, 0); + direction = CG29XX_DAI_DIRECTION_TX; + + old_value = dai_data->input_select; + dai_data->input_select = value; + + if ((old_value ^ value) && dai_data->tx_active) + restart_if = true; + break; + + case INTERFACE1_INPUT_SELECT: + dai_data = get_dai_data_codec(codec, 1); + direction = CG29XX_DAI_DIRECTION_TX; + + old_value = dai_data->input_select; + dai_data->input_select = value; + + if ((old_value ^ value) && dai_data->tx_active) + restart_if = true; + break; + + case INTERFACE0_OUTPUT_SELECT: + dai_data = get_dai_data_codec(codec, 0); + direction = CG29XX_DAI_DIRECTION_RX; + + old_value = dai_data->output_select; + dai_data->output_select = value; + + if ((old_value ^ value) && dai_data->rx_active) + restart_if = true; + break; + + case INTERFACE1_OUTPUT_SELECT: + dai_data = get_dai_data_codec(codec, 1); + direction = CG29XX_DAI_DIRECTION_RX; + + old_value = dai_data->output_select; + dai_data->output_select = value; + + if ((old_value ^ value) && dai_data->rx_active) + restart_if = true; + break; + + default: + return -EINVAL; + } + + if (restart_if) { + (void) cg29xx_stop_if(dai_data, direction); + (void) cg29xx_start_if(dai_data, direction); + } + + return 0; +} + +static int cg29xx_codec_probe(struct snd_soc_codec *codec) +{ + pr_debug("%s: Enter (codec->name = %s).\n", __func__, codec->name); + + snd_soc_add_controls( + codec, + cg29xx_snd_controls, + ARRAY_SIZE(cg29xx_snd_controls)); + + return 0; +} + +static int cg29xx_codec_remove(struct snd_soc_codec *codec) +{ + pr_debug("%s: Enter (codec->name = %s).\n", __func__, codec->name); + + return 0; +} + +static int cg29xx_codec_suspend(struct snd_soc_codec *codec, pm_message_t state) +{ + pr_debug("%s: Enter (codec->name = %s).\n", __func__, codec->name); + + return 0; +} + +static int cg29xx_codec_resume(struct snd_soc_codec *codec) +{ + pr_debug("%s: Enter (codec->name = %s).\n", __func__, codec->name); + + return 0; +} + +struct snd_soc_codec_driver cg29xx_codec_driver = { + .probe = cg29xx_codec_probe, + .remove = cg29xx_codec_remove, + .suspend = cg29xx_codec_suspend, + .resume = cg29xx_codec_resume, + .read = cg29xx_codec_read, + .write = cg29xx_codec_write, +}; + +static int __devinit cg29xx_codec_driver_probe(struct platform_device *pdev) +{ + int ret; + struct cg29xx_codec_dai_data *dai_data; + + pr_debug("%s: Enter.\n", __func__); + + pr_info("%s: Init codec private data..\n", __func__); + dai_data = kzalloc(CG29XX_NBR_OF_DAI * sizeof(struct cg29xx_codec_dai_data), + GFP_KERNEL); + if (dai_data == NULL) + return -ENOMEM; + + dai_data[0].tx_active = 0; + dai_data[0].rx_active = 0; + dai_data[0].input_select = 0; + dai_data[0].output_select = 0; + dai_data[0].config.port = PORT_0_I2S; + dai_data[0].config.conf.i2s.mode = DAI_MODE_SLAVE; + dai_data[0].config.conf.i2s.half_period = HALF_PER_DUR_16; + dai_data[0].config.conf.i2s.channel_sel = CHANNEL_SELECTION_BOTH; + dai_data[0].config.conf.i2s.sample_rate = SAMPLE_RATE_48; + dai_data[0].config.conf.i2s.word_width = WORD_WIDTH_32; + dai_data[1].tx_active = 0; + dai_data[1].rx_active = 0; + dai_data[1].input_select = 0; + dai_data[1].output_select = 0; + dai_data[1].config.port = PORT_1_I2S_PCM; + dai_data[1].config.conf.i2s_pcm.mode = DAI_MODE_SLAVE; + dai_data[1].config.conf.i2s_pcm.slot_0_dir = DAI_DIR_B_RX_A_TX; + dai_data[1].config.conf.i2s_pcm.slot_1_dir = DAI_DIR_B_TX_A_RX; + dai_data[1].config.conf.i2s_pcm.slot_2_dir = DAI_DIR_B_RX_A_TX; + dai_data[1].config.conf.i2s_pcm.slot_3_dir = DAI_DIR_B_RX_A_TX; + dai_data[1].config.conf.i2s_pcm.slot_0_used = true; + dai_data[1].config.conf.i2s_pcm.slot_1_used = false; + dai_data[1].config.conf.i2s_pcm.slot_2_used = false; + dai_data[1].config.conf.i2s_pcm.slot_3_used = false; + dai_data[1].config.conf.i2s_pcm.slot_0_start = 0; + dai_data[1].config.conf.i2s_pcm.slot_1_start = 16; + dai_data[1].config.conf.i2s_pcm.slot_2_start = 32; + dai_data[1].config.conf.i2s_pcm.slot_3_start = 48; + dai_data[1].config.conf.i2s_pcm.protocol = PORT_PROTOCOL_PCM; + dai_data[1].config.conf.i2s_pcm.ratio = STREAM_RATIO_FM48_VOICE16; + dai_data[1].config.conf.i2s_pcm.duration = SYNC_DURATION_32; + dai_data[1].config.conf.i2s_pcm.clk = BIT_CLK_512; + dai_data[1].config.conf.i2s_pcm.sample_rate = SAMPLE_RATE_16; + + platform_set_drvdata(pdev, dai_data); + + pr_info("%s: Register codec.\n", __func__); + ret = snd_soc_register_codec(&pdev->dev, &cg29xx_codec_driver, &cg29xx_dai_driver[0], 2); + if (ret < 0) { + pr_debug("%s: Error: Failed to register codec (ret = %d).\n", + __func__, + ret); + snd_soc_unregister_codec(&pdev->dev); + kfree(platform_get_drvdata(pdev)); + return ret; + } + + return 0; +} + +static int __devexit cg29xx_codec_driver_remove(struct platform_device *pdev) +{ + (void)cg2900_audio_close(&codec_private.session); + + snd_soc_unregister_codec(&pdev->dev); + kfree(platform_get_drvdata(pdev)); + + return 0; +} + +static int cg29xx_codec_driver_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +static int cg29xx_codec_driver_resume(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver cg29xx_codec_platform_driver = { + .driver = { + .name = "cg29xx-codec", + .owner = THIS_MODULE, + }, + .probe = cg29xx_codec_driver_probe, + .remove = __devexit_p(cg29xx_codec_driver_remove), + .suspend = cg29xx_codec_driver_suspend, + .resume = cg29xx_codec_driver_resume, +}; + + +static int __devinit cg29xx_codec_platform_driver_init(void) +{ + int ret; + + pr_debug("%s: Enter.\n", __func__); + + ret = platform_driver_register(&cg29xx_codec_platform_driver); + if (ret != 0) + pr_err("Failed to register CG29xx platform driver (%d)!\n", ret); + + return ret; +} + +static void __exit cg29xx_codec_platform_driver_exit(void) +{ + pr_debug("%s: Enter.\n", __func__); + + platform_driver_unregister(&cg29xx_codec_platform_driver); +} + + +module_init(cg29xx_codec_platform_driver_init); +module_exit(cg29xx_codec_platform_driver_exit); + +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/cg29xx.h b/sound/soc/codecs/cg29xx.h new file mode 100644 index 00000000000..fec52d7cdd7 --- /dev/null +++ b/sound/soc/codecs/cg29xx.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Roger Nilsson roger.xr.nilsson@stericsson.com + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ +#ifndef CG29XX_CODEC_H +#define CG29XX_CODEC_H + +#include <../../../drivers/staging/cg2900/include/cg2900_audio.h> + +struct cg29xx_codec_dai_data { + struct mutex mutex; + unsigned int rx_active; + unsigned int tx_active; + int input_select; + int output_select; + struct cg2900_dai_config config; +}; + +struct cg29xx_codec{ + unsigned int session; +}; + +#define CG29XX_DAI_SLOT0_SHIFT 0 +#define CG29XX_DAI_SLOT1_SHIFT 1 +#define CG29XX_DAI_SLOT2_SHIFT 2 +#define CG29XX_DAI_SLOT3_SHIFT 3 + +#define INTERFACE0_INPUT_SELECT 0x00 +#define INTERFACE1_INPUT_SELECT 0x01 +#define INTERFACE0_OUTPUT_SELECT 0x02 +#define INTERFACE1_OUTPUT_SELECT 0x03 + +#endif /* CG29XX_CODEC_H */ diff --git a/sound/soc/ux500/Kconfig b/sound/soc/ux500/Kconfig new file mode 100644 index 00000000000..02239929879 --- /dev/null +++ b/sound/soc/ux500/Kconfig @@ -0,0 +1,57 @@ +# +# Ux500 SoC audio configuration +# + +menuconfig SND_SOC_UX500 + bool "SoC Audio support for Ux500 platform" + depends on SND_SOC && STM_I2S && STM_MSP_I2S + default n + help + Say Y if you want to add support for the Ux500 platform. + +config SND_SOC_UX500_AB3550 + bool "Codec - AB3550" + depends on SND_SOC_UX500 && (UX500_SOC_DB8500 || UX500_SOC_DB5500) && AB3550_CORE + select SND_SOC_AB3550 + default n + help + Say Y if you want to include the AB3550 codec. + +config SND_SOC_UX500_AB5500 + bool "Codec - AB5500" + depends on SND_SOC_UX500 && (UX500_SOC_DB8500 || UX500_SOC_DB5500) && AB5500_CORE + select SND_SOC_AB5500 + default n + help + Say Y if you want to include the AB5500 codec. + +config SND_SOC_UX500_AB8500 + bool "Codec - AB8500" + depends on SND_SOC_UX500 && UX500_SOC_DB8500 && AB8500_CORE && AB8500_GPADC + select SND_SOC_AB8500 + default n + help + Say Y if you want to include AB8500 audio codec. + +config SND_SOC_UX500_CG29XX + bool "Codec - CG29xx" + depends on SND_SOC_UX500 && (UX500_SOC_DB8500 || UX500_SOC_DB5500) && CG2900_AUDIO + select SND_SOC_CG29XX + default n + help + Say Y if you want to include CG29xx codec (Combo chip). + +config SND_SOC_UX500_AV8100 + bool "Codec - AV8100" + depends on SND_SOC_UX500 && (UX500_SOC_DB8500 || UX500_SOC_DB5500) && AV8100 + select SND_SOC_AV8100 + default n + help + Say Y if you want to include AV8100 codec (HDMI chip). + +config SND_SOC_UX500_DEBUG + bool "Activate Ux500 platform debug-mode (pr_debug)" + depends on SND_SOC_UX500 + default n + help + Say Y if you want to add debug level prints for Ux500 code-files. diff --git a/sound/soc/ux500/Makefile b/sound/soc/ux500/Makefile new file mode 100644 index 00000000000..255c0ecefdb --- /dev/null +++ b/sound/soc/ux500/Makefile @@ -0,0 +1,47 @@ +# Ux500 Platform Support + +ifdef CONFIG_SND_SOC_UX500_DEBUG +CFLAGS_ux500_pcm.o := -DDEBUG +CFLAGS_ux500_msp_dai.o := -DDEBUG +CFLAGS_ux500_ab3550.o := -DDEBUG +CFLAGS_ux500_ab8500.o := -DDEBUG +CFLAGS_ux500_av8100.o := -DDEBUG +CFLAGS_ux500_cg29xx.o := -DDEBUG +endif + +ifdef CONFIG_SND_SOC_UX500_AB3550 +snd-soc-ux500-ab3550-objs := ux500_ab3550.o +obj-$(CONFIG_SND_SOC_UX500_AB3550) += ux500_ab3550.o +endif + +ifdef CONFIG_SND_SOC_UX500_AB5500 +snd-soc-ux500-ab5500-objs := ux500_ab5500.o +obj-$(CONFIG_SND_SOC_UX500_AB5500) += ux500_ab5500.o +endif + +ifdef CONFIG_SND_SOC_UX500_AB8500 +snd-soc-ux500-ab8500-objs := ux500_ab8500.o +obj-$(CONFIG_SND_SOC_UX500_AB8500) += ux500_ab8500.o +endif + +ifdef CONFIG_SND_SOC_UX500_AV8100 +snd-soc-ux500-av8100-objs := ux500_av8100.o +obj-$(CONFIG_SND_SOC_UX500_AV8100) += ux500_av8100.o +endif + +ifdef CONFIG_SND_SOC_UX500_CG29XX +snd-soc-ux500-cg29xx-objs := ux500_cg29xx.o +obj-$(CONFIG_SND_SOC_UX500_CG29XX) += ux500_cg29xx.o +endif + +snd-soc-ux500-objs := ux500_pcm.o ux500_msp_dai.o + +ifdef CONFIG_UX500_SOC_DB8500 +snd-soc-ux500-objs += u8500.o +endif + +ifdef CONFIG_UX500_SOC_DB5500 +snd-soc-ux500-objs += u5500.o +endif + +obj-$(CONFIG_UX500_SOC_DBX500) += snd-soc-ux500.o diff --git a/sound/soc/ux500/u5500.c b/sound/soc/ux500/u5500.c new file mode 100644 index 00000000000..fda8db3472b --- /dev/null +++ b/sound/soc/ux500/u5500.c @@ -0,0 +1,108 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Author: Xie Xiaolei (xie.xiaolei@stericsson.com) + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#include <linux/io.h> +#include <sound/soc.h> +#include <asm/mach-types.h> + +#include "ux500_pcm.h" +#include "ux500_msp_dai.h" + +#include <linux/spi/spi.h> +#include <sound/initval.h> + +#ifdef CONFIG_SND_SOC_UX500_AB5500 +#include "ux500_ab5500.h" +#endif + +static struct platform_device *u5500_platform_dev; +/* Create dummy devices for platform drivers */ + +static struct platform_device ux500_pcm = { + .name = "ux500-pcm", + .id = 0, + .dev = { + .platform_data = NULL, + }, +}; + + +/* Define the whole U5500 soundcard, linking platform to the codec-drivers */ +struct snd_soc_dai_link u5500_dai_links[] = { +#ifdef CONFIG_SND_SOC_UX500_AB5500 + { + .name = "ab5500_0", + .stream_name = "ab5500_0", + .cpu_dai_name = "i2s.0", + .codec_dai_name = "ab5500-codec-dai.0", + .platform_name = "ux500-pcm.0", + .codec_name = "ab5500-codec.9", + .init = NULL, + .ops = (struct snd_soc_ops[]) { + { + .startup = ux500_ab5500_startup, + .shutdown = ux500_ab5500_shutdown, + .hw_params = ux500_ab5500_hw_params, + } + } +#endif + } +}; + +static struct snd_soc_card u5500_drvdata = { + .name = "U5500-card", + .probe = NULL, + .dai_link = u5500_dai_links, + .num_links = ARRAY_SIZE(u5500_dai_links), +}; + +static int __init u5500_soc_init(void) +{ + int ret = 0; + + pr_debug("%s: Enter.\n", __func__); + + if (!machine_is_u5500()) + return 0; + + platform_device_register(&ux500_pcm); + + u5500_platform_dev = platform_device_alloc("soc-audio", -1); + if (!u5500_platform_dev) + return -ENOMEM; + + platform_set_drvdata(u5500_platform_dev, &u5500_drvdata); + u5500_drvdata.dev = &u5500_platform_dev->dev; + + ret = platform_device_add(u5500_platform_dev); + if (ret) { + pr_err("%s: Error: Failed to add platform device (%s).\n", + __func__, + u5500_drvdata.name); + platform_device_put(u5500_platform_dev); + } + + return ret; +} + +static void __exit u5500_soc_exit(void) +{ + pr_debug("%s: Enter.\n", __func__); + + platform_device_unregister(u5500_platform_dev); +} + +module_init(u5500_soc_init); +module_exit(u5500_soc_exit); + +MODULE_LICENSE("GPLv2"); diff --git a/sound/soc/ux500/u8500.c b/sound/soc/ux500/u8500.c new file mode 100644 index 00000000000..59324c878e4 --- /dev/null +++ b/sound/soc/ux500/u8500.c @@ -0,0 +1,244 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ola Lilja (ola.o.lilja@stericsson.com) + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#include <linux/io.h> +#include <sound/soc.h> +#include <asm/mach-types.h> + +#include "ux500_pcm.h" +#include "ux500_msp_dai.h" + +#include <linux/spi/spi.h> +#include <sound/initval.h> + +#ifdef CONFIG_SND_SOC_UX500_AB3550 +#include "ux500_ab3550.h" +#endif + +#ifdef CONFIG_SND_SOC_UX500_AB8500 +#include <sound/ux500_ab8500.h> +#endif + +#ifdef CONFIG_SND_SOC_UX500_AV8100 +#include "ux500_av8100.h" +#endif + +#ifdef CONFIG_SND_SOC_UX500_CG29XX +#include "ux500_cg29xx.h" +#endif + + +static struct platform_device *u8500_platform_dev; + +/* Create dummy devices for platform drivers */ + +static struct platform_device ux500_pcm = { + .name = "ux500-pcm", + .id = 0, + .dev = { + .platform_data = NULL, + }, +}; + +#ifdef CONFIG_SND_SOC_UX500_AV8100 +static struct platform_device av8100_codec = { + .name = "av8100-codec", + .id = 0, + .dev = { + .platform_data = NULL, + }, +}; +#endif + +#ifdef CONFIG_SND_SOC_UX500_CG29XX +static struct platform_device cg29xx_codec = { + .name = "cg29xx-codec", + .id = 0, + .dev = { + .platform_data = NULL, + }, +}; +#endif + +/* Define the whole U8500 soundcard, linking platform to the codec-drivers */ +struct snd_soc_dai_link u8500_dai_links[] = { + #ifdef CONFIG_SND_SOC_UX500_AV8100 + { + .name = "hdmi", + .stream_name = "hdmi", + .cpu_dai_name = "i2s.2", + .codec_dai_name = "av8100-codec-dai", + .platform_name = "ux500-pcm.0", + .codec_name = "av8100-codec.0", + .init = NULL, + .ops = ux500_av8100_ops, + }, + #endif + #ifdef CONFIG_SND_SOC_UX500_AB3550 + { + .name = "ab3550_0", + .stream_name = "ab3550_0", + .cpu_dai_name = "i2s.0", + .codec_dai_name = "ab3550-codec-dai.0", + .platform_name = "ux500-pcm.0", + .codec_name = "ab3550-codec.11", + .init = NULL, + .ops = ux500_ab3550_ops, + }, + { + .name = "ab3550_1", + .stream_name = "ab3550_1", + .cpu_dai_name = "i2s.1", + .codec_dai_name = "ab3550-codec-dai.1", + .platform_name = "ux500-pcm.0", + .codec_name = "ab3550-codec.11", + .init = NULL, + .ops = ux500_ab3550_ops, + }, + #endif + #ifdef CONFIG_SND_SOC_UX500_AB8500 + { + .name = "ab8500_0", + .stream_name = "ab8500_0", + .cpu_dai_name = "i2s.1", + .codec_dai_name = "ab8500-codec-dai.0", + .platform_name = "ux500-pcm.0", + .codec_name = "ab8500-codec.0", + .init = ux500_ab8500_machine_codec_init, + .ops = ux500_ab8500_ops, + }, + { + .name = "ab8500_1", + .stream_name = "ab8500_1", + .cpu_dai_name = "i2s.3", + .codec_dai_name = "ab8500-codec-dai.1", + .platform_name = "ux500-pcm.0", + .codec_name = "ab8500-codec.0", + .init = NULL, + .ops = ux500_ab8500_ops, + }, + #endif + #ifdef CONFIG_SND_SOC_UX500_CG29XX + { + .name = "cg29xx_0", + .stream_name = "cg29xx_0", + .cpu_dai_name = "i2s.0", + .codec_dai_name = "cg29xx-codec-dai.1", + .platform_name = "ux500-pcm.0", + .codec_name = "cg29xx-codec.0", + .init = NULL, + .ops = ux500_cg29xx_ops, + }, + #endif +}; + +static struct snd_soc_card u8500_drvdata = { + .name = "U8500-card", + .probe = NULL, + .dai_link = u8500_dai_links, + .num_links = ARRAY_SIZE(u8500_dai_links), +}; + +static int __init u8500_soc_init(void) +{ + int ret; + + pr_debug("%s: Enter.\n", __func__); + + if (machine_is_u5500()) + return 0; + + #ifdef CONFIG_SND_SOC_UX500_AV8100 + pr_debug("%s: Register device to generate a probe for AV8100 codec.\n", + __func__); + platform_device_register(&av8100_codec); + #endif + + #ifdef CONFIG_SND_SOC_UX500_CG29XX + pr_debug("%s: Register device to generate a probe for CG29xx codec.\n", + __func__); + platform_device_register(&cg29xx_codec); + #endif + + #ifdef CONFIG_SND_SOC_UX500_AB8500 + pr_debug("%s: Calling init-function for AB8500 machine driver.\n", + __func__); + ret = ux500_ab8500_soc_machine_drv_init(); + if (ret) + pr_err("%s: ux500_ab8500_soc_machine_drv_init failed (%d).\n", + __func__, ret); + #endif + + pr_debug("%s: Register device to generate a probe for Ux500-pcm platform.\n", + __func__); + platform_device_register(&ux500_pcm); + + pr_debug("%s: Allocate platform device 'soc-audio'.\n", + __func__); + u8500_platform_dev = platform_device_alloc("soc-audio", -1); + if (!u8500_platform_dev) + return -ENOMEM; + + pr_debug("%s: Card %s: num_links = %d\n", + __func__, + u8500_drvdata.name, + u8500_drvdata.num_links); + pr_debug("%s: Card %s: DAI-link 0: name = %s\n", + __func__, + u8500_drvdata.name, + u8500_drvdata.dai_link[0].name); + pr_debug("%s: Card %s: DAI-link 0: stream_name = %s\n", + __func__, + u8500_drvdata.name, + u8500_drvdata.dai_link[0].stream_name); + + pr_debug("%s: Card %s: Set platform drvdata.\n", + __func__, + u8500_drvdata.name); + platform_set_drvdata(u8500_platform_dev, &u8500_drvdata); + u8500_drvdata.dev = &u8500_platform_dev->dev; + + pr_debug("%s: Card %s: Add platform device.\n", + __func__, + u8500_drvdata.name); + ret = platform_device_add(u8500_platform_dev); + if (ret) { + pr_err("%s: Error: Failed to add platform device (%s).\n", + __func__, + u8500_drvdata.name); + platform_device_put(u8500_platform_dev); + } + + return ret; +} + +static void __exit u8500_soc_exit(void) +{ + pr_debug("%s: Enter.\n", __func__); + + #ifdef CONFIG_SND_SOC_UX500_AB8500 + pr_debug("%s: Calling exit-function for AB8500 machine driver.\n", + __func__); + ux500_ab8500_soc_machine_drv_cleanup(); + #endif + + pr_debug("%s: Unregister platform device (%s).\n", + __func__, + u8500_drvdata.name); + platform_device_unregister(u8500_platform_dev); +} + +module_init(u8500_soc_init); +module_exit(u8500_soc_exit); + +MODULE_LICENSE("GPLv2"); diff --git a/sound/soc/ux500/ux500_ab3550.c b/sound/soc/ux500/ux500_ab3550.c new file mode 100644 index 00000000000..7e144c0e4d2 --- /dev/null +++ b/sound/soc/ux500/ux500_ab3550.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ola Lilja ola.o.lilja@stericsson.com, + * Roger Nilsson roger.xr.nilsson@stericsson.com + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#include <sound/soc.h> +#include "../codecs/ab3550.h" + +static int ux500_ab3550_startup(struct snd_pcm_substream *substream) +{ + pr_debug("%s: Enter.\n", __func__); + + return 0; +} + +static void ux500_ab3550_shutdown(struct snd_pcm_substream *substream) +{ + pr_debug("%s: Enter.\n", __func__); +} + +static int ux500_ab3550_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret = 0; + + int channels = params_channels(params); + + pr_debug("%s: Enter.\n", __func__); + pr_debug("%s: substream->pcm->name = %s.\n", __func__, substream->pcm->name); + pr_debug("%s: substream->pcm->id = %s.\n", __func__, substream->pcm->id); + pr_debug("%s: substream->name = %s.\n", __func__, substream->name); + pr_debug("%s: substream->number = %d.\n", __func__, substream->number); + pr_debug("%s: channels = %d.\n", __func__, channels); + pr_debug("%s: DAI-index (Codec): %d\n", __func__, codec_dai->id); + pr_debug("%s: DAI-index (Platform): %d\n", __func__, cpu_dai->id); + + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) { + pr_debug("%s: snd_soc_dai_set_fmt failed with %d.\n", + __func__, + ret); + return ret; + } + + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) { + pr_debug("%s: snd_soc_dai_set_fmt failed with %d.\n", + __func__, + ret); + return ret; + } + + return ret; +} + +struct snd_soc_ops ux500_ab3550_ops[] = { + { + .startup = ux500_ab3550_startup, + .shutdown = ux500_ab3550_shutdown, + .hw_params = ux500_ab3550_hw_params, + } +}; diff --git a/sound/soc/ux500/ux500_ab3550.h b/sound/soc/ux500/ux500_ab3550.h new file mode 100644 index 00000000000..53ea3902d36 --- /dev/null +++ b/sound/soc/ux500/ux500_ab3550.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ola Lilja <ola.o.lilja@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#ifndef UX500_AB3550_H +#define UX500_AB3550_H + +extern struct snd_soc_ops ux500_ab3550_ops[]; + +#endif diff --git a/sound/soc/ux500/ux500_ab5500.c b/sound/soc/ux500/ux500_ab5500.c new file mode 100644 index 00000000000..551ec05fcb5 --- /dev/null +++ b/sound/soc/ux500/ux500_ab5500.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Author: Ola Lilja ola.o.lilja@stericsson.com, + * Roger Nilsson roger.xr.nilsson@stericsson.com + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#include <sound/soc.h> +#include "../codecs/ab5500.h" +int ux500_ab5500_startup(struct snd_pcm_substream *substream) +{ + return 0; +} + +void ux500_ab5500_shutdown(struct snd_pcm_substream *substream) +{ + printk(KERN_DEBUG "%s: Enter.\n", __func__); +} + +int ux500_ab5500_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret = 0; + + int channels = params_channels(params); + + printk(KERN_DEBUG "%s: Enter.\n", __func__); + printk(KERN_DEBUG "%s: substream->pcm->name = %s.\n", __func__, substream->pcm->name); + printk(KERN_DEBUG "%s: substream->pcm->id = %s.\n", __func__, substream->pcm->id); + printk(KERN_DEBUG "%s: substream->name = %s.\n", __func__, substream->name); + printk(KERN_DEBUG "%s: substream->number = %d.\n", __func__, substream->number); + printk(KERN_DEBUG "%s: channels = %d.\n", __func__, channels); + printk(KERN_DEBUG "%s: DAI-index (Codec): %d\n", __func__, codec_dai->id); + printk(KERN_DEBUG "%s: DAI-index (Platform): %d\n", __func__, cpu_dai->id); + + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + return ret; +} diff --git a/sound/soc/ux500/ux500_ab5500.h b/sound/soc/ux500/ux500_ab5500.h new file mode 100644 index 00000000000..ea69f1a048c --- /dev/null +++ b/sound/soc/ux500/ux500_ab5500.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Author: Xie Xiaolei (xie.xiaolei@stericsson.com) + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#ifndef UX500_AB5500_H +#define UX500_AB5500_H + +int ux500_ab5500_startup(struct snd_pcm_substream *substream); + +void ux500_ab5500_shutdown(struct snd_pcm_substream *substream); + +int ux500_ab5500_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); + +#endif diff --git a/sound/soc/ux500/ux500_ab8500.c b/sound/soc/ux500/ux500_ab8500.c new file mode 100644 index 00000000000..be647daeeed --- /dev/null +++ b/sound/soc/ux500/ux500_ab8500.c @@ -0,0 +1,561 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Mikko J. Lehto <mikko.lehto@symbio.com>, + * Mikko Sarmanne <mikko.sarmanne@symbio.com>, + * Jarmo K. Kuronen <jarmo.kuronen@symbio.com>. + * Ola Lilja <ola.o.lilja@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/device.h> +#include <linux/io.h> +#include <sound/soc.h> +#include <linux/regulator/consumer.h> +#include <sound/pcm.h> +#include <sound/jack.h> +#include <sound/pcm_params.h> +#include <sound/soc-dapm.h> +#include <mach/hardware.h> +#include "ux500_pcm.h" +#include "ux500_msp_dai.h" +#include "../codecs/ab8500_audio.h" + +#define TX_SLOT_MONO 0x0008 +#define TX_SLOT_STEREO 0x000a +#define RX_SLOT_MONO 0x0001 +#define RX_SLOT_STEREO 0x0003 +#define TX_SLOT_8CH 0x00FF +#define RX_SLOT_8CH 0x00FF + +#define DEF_TX_SLOTS TX_SLOT_STEREO +#define DEF_RX_SLOTS RX_SLOT_MONO + +#define DRIVERMODE_NORMAL 0 +#define DRIVERMODE_CODEC_ONLY 1 + +static struct snd_soc_jack jack; + +/* Power-control */ +static DEFINE_MUTEX(power_lock); +static int ab8500_power_count; + +/* Clocks */ +/* audioclk -> intclk -> sysclk/ulpclk */ +static int master_clock_sel; +static struct clk *clk_ptr_audioclk; +static struct clk *clk_ptr_intclk; +static struct clk *clk_ptr_sysclk; +static struct clk *clk_ptr_ulpclk; + +/* Regulators */ +static enum regulator_idx { + REGULATOR_AUDIO, + REGULATOR_DMIC, + REGULATOR_AMIC1, + REGULATOR_AMIC2 +}; +static struct regulator_bulk_data reg_info[4] = { + { .supply = "v-audio" }, + { .supply = "v-dmic" }, + { .supply = "v-amic1" }, + { .supply = "v-amic2" } +}; +static bool reg_enabled[4] = { + false, + false, + false, + false +}; + +/* Slot configuration */ +static unsigned int tx_slots = DEF_TX_SLOTS; +static unsigned int rx_slots = DEF_RX_SLOTS; + +/* Machine-driver ALSA-controls */ + +static int mclk_input_control_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item) { + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, "ULPCLK"); + } else { + strcpy(uinfo->value.enumerated.name, "SYSCLK"); + } + return 0; +} + +static int mclk_input_control_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.enumerated.item[0] = master_clock_sel; + return 0; +} + +static int mclk_input_control_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned int val; + + val = (ucontrol->value.enumerated.item[0] != 0); + if (master_clock_sel == val) + return 0; + + master_clock_sel = val; + + return 1; +} + +static const struct snd_kcontrol_new mclk_input_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Clock Select", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = mclk_input_control_info, + .get = mclk_input_control_get, + .put = mclk_input_control_put, + .private_value = 1 /* ULPCLK */ +}; + +/* Regulators */ + +static int enable_regulator(enum regulator_idx idx) +{ + int ret; + + if (reg_enabled[idx]) + return 0; + + ret = regulator_enable(reg_info[idx].consumer); + if (ret != 0) { + pr_err("%s: Failure to enable regulator '%s' (ret = %d)\n", + __func__, reg_info[idx].supply, ret); + return ret; + }; + + reg_enabled[idx] = true; + pr_debug("%s: Enabled regulator '%s', status: %d, %d, %d, %d\n", + __func__, + reg_info[idx].supply, + (int)reg_enabled[0], + (int)reg_enabled[1], + (int)reg_enabled[2], + (int)reg_enabled[3]); + return 0; +} + +static void disable_regulator(enum regulator_idx idx) +{ + if (!reg_enabled[idx]) + return; + + regulator_disable(reg_info[idx].consumer); + + reg_enabled[idx] = false; + pr_debug("%s: Disabled regulator '%s', status: %d, %d, %d, %d\n", + __func__, + reg_info[idx].supply, + (int)reg_enabled[0], + (int)reg_enabled[1], + (int)reg_enabled[2], + (int)reg_enabled[3]); +} + +static int create_regulators(void) +{ + int i, status = 0; + + pr_debug("%s: Enter.\n", __func__); + + for (i = 0; i < ARRAY_SIZE(reg_info); ++i) + reg_info[i].consumer = NULL; + + for (i = 0; i < ARRAY_SIZE(reg_info); ++i) { + reg_info[i].consumer = regulator_get(NULL, reg_info[i].supply); + if (IS_ERR(reg_info[i].consumer)) { + status = PTR_ERR(reg_info[i].consumer); + pr_err("%s: ERROR: Failed to get regulator '%s' (ret = %d)!\n", + __func__, reg_info[i].supply, status); + reg_info[i].consumer = NULL; + goto err_get; + } + } + + return 0; + +err_get: + + for (i = 0; i < ARRAY_SIZE(reg_info); ++i) { + if (reg_info[i].consumer) { + regulator_put(reg_info[i].consumer); + reg_info[i].consumer = NULL; + } + } + + return status; +} + +/* Power/clock control */ + +static int ux500_ab8500_power_control_inc(void) +{ + int ret; + + mutex_lock(&power_lock); + + ab8500_power_count++; + pr_debug("%s: ab8500_power_count changed from %d to %d", + __func__, + ab8500_power_count-1, + ab8500_power_count); + + if (ab8500_power_count == 1) { + ret = clk_set_parent(clk_ptr_intclk, + (master_clock_sel == 0) ? clk_ptr_sysclk : clk_ptr_ulpclk); + if (ret) { + pr_err("%s: ERROR: Setting master-clock to %s failed (ret = %d)!", + __func__, + (master_clock_sel == 0) ? "SYSCLK" : "ULPCLK", + ret); + return ret; + } + + pr_debug("%s: Enabling master-clock (%s).", + __func__, + (master_clock_sel == 0) ? "SYSCLK" : "ULPCLK"); + + /* Enable audio-clock */ + ret = clk_enable(clk_ptr_audioclk); + if (ret) { + pr_err("%s: ERROR: clk_enable failed (ret = %d)!", __func__, ret); + ab8500_power_count = 0; + return ret; + } + + /* Power on audio-parts of AB8500 */ + ab8500_audio_power_control(true); + + /* Turn on audio-regulator */ + ret = enable_regulator(REGULATOR_AUDIO); + } + + mutex_unlock(&power_lock); + + return 0; +} + +static void ux500_ab8500_power_control_dec(void) +{ + mutex_lock(&power_lock); + + ab8500_power_count--; + + pr_debug("%s: ab8500_power_count changed from %d to %d", + __func__, + ab8500_power_count+1, + ab8500_power_count); + + if (ab8500_power_count == 0) { + pr_debug("%s: Disabling master-clock (%s).", + __func__, + (master_clock_sel == 0) ? "SYSCLK" : "ULPCLK"); + + /* Disable audio-clock */ + clk_disable(clk_ptr_audioclk); + + /* Power off audio-parts of AB8500 */ + ab8500_audio_power_control(false); + + /* Turn off audio-regulator */ + disable_regulator(REGULATOR_AUDIO); + } + + mutex_unlock(&power_lock); +} + +/* ASoC */ + +int ux500_ab8500_startup(struct snd_pcm_substream *substream) +{ + int ret = 0; + + pr_debug("%s: Enter\n", __func__); + + /* If we start recording we better enable the needed mic-regulators */ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + if (ab8500_audio_dapm_path_active(AB8500_AUDIO_DAPM_PATH_DMIC)) + ret += enable_regulator(REGULATOR_DMIC); + if (ab8500_audio_dapm_path_active(AB8500_AUDIO_DAPM_PATH_AMIC1)) + ret += enable_regulator(REGULATOR_AMIC1); + if (ab8500_audio_dapm_path_active(AB8500_AUDIO_DAPM_PATH_AMIC2)) + ret += enable_regulator(REGULATOR_AMIC2); + if (ret != 0) + return ret; + } + + return ux500_ab8500_power_control_inc(); + + return ret; +} + +void ux500_ab8500_shutdown(struct snd_pcm_substream *substream) +{ + pr_debug("%s: Enter\n", __func__); + + /* Reset slots configuration to default(s) */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + tx_slots = DEF_TX_SLOTS; + else + rx_slots = DEF_RX_SLOTS; + + /* Disable all mic-regulators that were enabled when we stop recording */ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + disable_regulator(REGULATOR_DMIC); + disable_regulator(REGULATOR_AMIC1); + disable_regulator(REGULATOR_AMIC2); + } + + ux500_ab8500_power_control_dec(); +} + +int ux500_ab8500_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + unsigned int fmt, fmt_if1; + int channels, ret = 0, slots, slot_width, driver_mode; + bool streamIsPlayback; + + pr_debug("%s: Enter\n", __func__); + + pr_debug("%s: substream->pcm->name = %s\n" + "substream->pcm->id = %s.\n" + "substream->name = %s.\n" + "substream->number = %d.\n", + __func__, + substream->pcm->name, + substream->pcm->id, + substream->name, + substream->number); + + channels = params_channels(params); + + /* Setup codec depending on driver-mode */ + driver_mode = (channels == 8) ? + DRIVERMODE_CODEC_ONLY : DRIVERMODE_NORMAL; + pr_debug("%s: Driver-mode: %s.\n", + __func__, + (driver_mode == DRIVERMODE_NORMAL) ? "NORMAL" : "CODEC_ONLY"); + if (driver_mode == DRIVERMODE_NORMAL) { + ab8500_audio_set_bit_delay(codec_dai, 0); + ab8500_audio_set_word_length(codec_dai, 16); + fmt = SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_CBM_CFM | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CONT; + } else { + ab8500_audio_set_bit_delay(codec_dai, 1); + ab8500_audio_set_word_length(codec_dai, 20); + fmt = SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_CBM_CFM | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_GATED; + } + + ret = snd_soc_dai_set_fmt(codec_dai, fmt); + if (ret < 0) { + pr_err("%s: ERROR: snd_soc_dai_set_fmt failed for codec_dai (ret = %d)!\n", + __func__, + ret); + return ret; + } + + ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + if (ret < 0) { + pr_err("%s: ERROR: snd_soc_dai_set_fmt for cpu_dai (ret = %d)!\n", + __func__, + ret); + return ret; + } + + /* Setup TDM-slots */ + + streamIsPlayback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + switch (channels) { + case 1: + slots = 16; + slot_width = 16; + tx_slots = (streamIsPlayback) ? TX_SLOT_MONO : 0; + rx_slots = (streamIsPlayback) ? 0 : RX_SLOT_MONO; + break; + case 2: + slots = 16; + slot_width = 16; + tx_slots = (streamIsPlayback) ? TX_SLOT_STEREO : 0; + rx_slots = (streamIsPlayback) ? 0 : RX_SLOT_STEREO; + break; + case 8: + slots = 16; + slot_width = 16; + tx_slots = (streamIsPlayback) ? TX_SLOT_8CH : 0; + rx_slots = (streamIsPlayback) ? 0 : RX_SLOT_8CH; + break; + default: + return -EINVAL; + } + + pr_debug("%s: CPU-DAI TDM: TX=0x%04X RX=0x%04x\n", + __func__, tx_slots, rx_slots); + ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_slots, rx_slots, slots, slot_width); + if (ret) + return ret; + + pr_debug("%s: CODEC-DAI TDM: TX=0x%04X RX=0x%04x\n", + __func__, tx_slots, rx_slots); + ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_slots, rx_slots, slots, slot_width); + if (ret) + return ret; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + pr_debug("%s: Setup IF1 for FM-radio.\n", __func__); + fmt_if1 = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_I2S; + ret = ab8500_audio_setup_if1(codec_dai->codec, fmt_if1, 16, 1); + if (ret) + return ret; + } + + return 0; +} + +struct snd_soc_ops ux500_ab8500_ops[] = { + { + .hw_params = ux500_ab8500_hw_params, + .startup = ux500_ab8500_startup, + .shutdown = ux500_ab8500_shutdown, + } +}; + +int ux500_ab8500_machine_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec; + int ret; + + pr_debug("%s Enter.\n", __func__); + + /* TODO: Add required DAPM routes to control regulators on demand */ + + ret = snd_soc_jack_new(codec, + "AB8500 Hs Status", + SND_JACK_HEADPHONE | + SND_JACK_MICROPHONE | + SND_JACK_HEADSET | + SND_JACK_LINEOUT | + SND_JACK_MECHANICAL | + SND_JACK_VIDEOOUT, + &jack); + if (ret < 0) { + pr_err("%s: ERROR: Failed to create Jack (ret = %d)!\n", __func__, ret); + return ret; + } + + /* Add controls */ + snd_ctl_add(codec->card->snd_card, snd_ctl_new1(&mclk_input_control, codec)); + + /* Get references to clock-nodes */ + clk_ptr_sysclk = NULL; + clk_ptr_ulpclk = NULL; + clk_ptr_intclk = NULL; + clk_ptr_audioclk = NULL; + clk_ptr_sysclk = clk_get(codec->dev, "sysclk"); + if (IS_ERR(clk_ptr_sysclk)) { + pr_err("ERROR: clk_get failed (ret = %d)!", -EFAULT); + return -EFAULT; + } + clk_ptr_ulpclk = clk_get(codec->dev, "ulpclk"); + if (IS_ERR(clk_ptr_sysclk)) { + pr_err("ERROR: clk_get failed (ret = %d)!", -EFAULT); + return -EFAULT; + } + clk_ptr_intclk = clk_get(codec->dev, "intclk"); + if (IS_ERR(clk_ptr_audioclk)) { + pr_err("ERROR: clk_get failed (ret = %d)!", -EFAULT); + return -EFAULT; + } + clk_ptr_audioclk = clk_get(codec->dev, "audioclk"); + if (IS_ERR(clk_ptr_audioclk)) { + pr_err("ERROR: clk_get failed (ret = %d)!", -EFAULT); + return -EFAULT; + } + + /* Set intclk default parent to ulpclk */ + ret = clk_set_parent(clk_ptr_intclk, clk_ptr_ulpclk); + if (ret) { + pr_err("%s: ERROR: Setting intclk parent to ulpclk failed (ret = %d)!", + __func__, + ret); + return -EFAULT; + } + + master_clock_sel = 1; + + ab8500_power_count = 0; + + return 0; +} + +int ux500_ab8500_soc_machine_drv_init(void) +{ + int status = 0; + + pr_debug("%s: Enter.\n", __func__); + + status = create_regulators(); + if (status < 0) { + pr_err("%s: ERROR: Failed to instantiate regulators (ret = %d)!\n", + __func__, status); + return status; + } + + return 0; +} + +void ux500_ab8500_soc_machine_drv_cleanup(void) +{ + pr_debug("%s: Enter.\n", __func__); + + regulator_bulk_free(ARRAY_SIZE(reg_info), reg_info); + + if (clk_ptr_sysclk != NULL) + clk_put(clk_ptr_sysclk); + if (clk_ptr_ulpclk != NULL) + clk_put(clk_ptr_ulpclk); + if (clk_ptr_intclk != NULL) + clk_put(clk_ptr_intclk); + if (clk_ptr_audioclk != NULL) + clk_put(clk_ptr_audioclk); +} + +/* Extended interface */ + +void ux500_ab8500_jack_report(int value) +{ + if (jack.jack) + snd_soc_jack_report(&jack, value, 0xFF); +} +EXPORT_SYMBOL_GPL(ux500_ab8500_jack_report); + diff --git a/sound/soc/ux500/ux500_av8100.c b/sound/soc/ux500/ux500_av8100.c new file mode 100644 index 00000000000..efb6318e1a7 --- /dev/null +++ b/sound/soc/ux500/ux500_av8100.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ola Lilja <ola.o.lilja@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#include <sound/soc.h> +#include "../codecs/av8100_audio.h" +#include "ux500_av8100.h" +#include "ux500_msp_dai.h" + +static const char *stream_str(struct snd_pcm_substream *substream) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return "Playback"; + else + return "Capture"; +} + +static int ux500_av8100_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int channels = params_channels(params); + unsigned int tx_mask, fmt; + enum hdmi_channel_allocation hdmi_ca; + enum hdmi_audio_channel_count hdmi_cc; + struct hdmi_audio_settings as; + int ret; + + pr_debug("%s: Enter (%s).\n", __func__, stream_str(substream)); + pr_debug("%s: substream->pcm->name = %s.\n", __func__, substream->pcm->name); + pr_debug("%s: substream->pcm->id = %s.\n", __func__, substream->pcm->id); + pr_debug("%s: substream->name = %s.\n", __func__, substream->name); + pr_debug("%s: substream->number = %d.\n", __func__, substream->number); + pr_debug("%s: channels = %d.\n", __func__, channels); + pr_debug("%s: DAI-index (Codec): %d\n", __func__, codec_dai->id); + pr_debug("%s: DAI-index (Platform): %d\n", __func__, cpu_dai->id); + + switch (channels) { + case 1: + hdmi_cc = AV8100_CODEC_CC_2CH; + hdmi_ca = AV8100_CODEC_CA_FL_FR; /* Stereo-setup */ + tx_mask = AV8100_CODEC_MASK_MONO; + break; + case 2: + hdmi_cc = AV8100_CODEC_CC_2CH; + hdmi_ca = AV8100_CODEC_CA_FL_FR; /* Stereo */ + tx_mask = AV8100_CODEC_MASK_STEREO; + break; + case 3: + hdmi_cc = AV8100_CODEC_CC_6CH; + hdmi_ca = AV8100_CODEC_CA_FL_FR_LFE_FC_RL_RR; /* 5.1-setup */ + tx_mask = AV8100_CODEC_MASK_2DOT1; + break; + case 4: + hdmi_cc = AV8100_CODEC_CC_6CH; + hdmi_ca = AV8100_CODEC_CA_FL_FR_LFE_FC_RL_RR; /* 5.1-setup */ + tx_mask = AV8100_CODEC_MASK_QUAD; + break; + case 5: + hdmi_cc = AV8100_CODEC_CC_6CH; + hdmi_ca = AV8100_CODEC_CA_FL_FR_LFE_FC_RL_RR; /* 5.1-setup */ + tx_mask = AV8100_CODEC_MASK_5DOT0; + break; + case 6: + hdmi_cc = AV8100_CODEC_CC_6CH; + hdmi_ca = AV8100_CODEC_CA_FL_FR_LFE_FC_RL_RR; /* 5.1 */ + tx_mask = AV8100_CODEC_MASK_5DOT1; + break; + case 7: + hdmi_cc = AV8100_CODEC_CC_8CH; + hdmi_ca = AV8100_CODEC_CA_FL_FR_LFE_FC_RL_RR_RLC_RRC; /* 7.1 */ + tx_mask = AV8100_CODEC_MASK_7DOT0; + break; + case 8: + hdmi_cc = AV8100_CODEC_CC_8CH; + hdmi_ca = AV8100_CODEC_CA_FL_FR_LFE_FC_RL_RR_RLC_RRC; /* 7.1 */ + tx_mask = AV8100_CODEC_MASK_7DOT1; + break; + default: + pr_err("%s: Unsupported number of channels (channels = %d)!\n", + __func__, + channels); + return -EINVAL; + } + + /* Change HDMI audio-settings for codec-DAI. */ + pr_debug("%s: Change HDMI audio-settings for codec-DAI.\n", __func__); + as.audio_coding_type = AV8100_CODEC_CT_IEC60958_PCM; + as.audio_channel_count = hdmi_cc; + as.sampling_frequency = AV8100_CODEC_SF_48KHZ; + as.sample_size = AV8100_CODEC_SS_16BIT; + as.channel_allocation = hdmi_ca; + as.level_shift_value = AV8100_CODEC_LSV_0DB; + as.downmix_inhibit = false; + ret = av8100_audio_change_hdmi_audio_settings(codec_dai, &as); + if (ret < 0) { + pr_err("%s: Unable to change HDMI audio-settings for codec-DAI " + "(av8100_codec_change_hdmi_audio_settings returned %d)!\n", + __func__, + ret); + return ret; + } + + /* Set format for codec-DAI */ + fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM; + pr_debug("%s: Setting format for codec-DAI (fmt = %d).\n", + __func__, + fmt); + ret = snd_soc_dai_set_fmt(codec_dai, fmt); + if (ret < 0) { + pr_err("%s: Unable to set format for codec-DAI " + "(snd_soc_dai_set_tdm_slot returned %d)!\n", + __func__, + ret); + return ret; + } + + /* Set TDM-slot for CPU-DAI */ + pr_debug("%s: Setting TDM-slot for codec-DAI (tx_mask = %d).\n", + __func__, + tx_mask); + ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_mask, 0, 16, 16); + if (ret < 0) { + pr_err("%s: Unable to set TDM-slot for codec-DAI " + "(snd_soc_dai_set_tdm_slot returned %d)!\n", + __func__, + ret); + return ret; + } + + /* Set format for CPU-DAI */ + fmt = SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_CBM_CFM | + SND_SOC_DAIFMT_NB_IF; + pr_debug("%s: Setting DAI-format for Ux500-platform (fmt = %d).\n", + __func__, + fmt); + ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + if (ret < 0) { + pr_err("%s: Unable to set DAI-format for Ux500-platform " + "(snd_soc_dai_set_fmt returned %d).\n", + __func__, + ret); + return ret; + } + + ux500_msp_dai_set_data_delay(cpu_dai, MSP_DELAY_1); + + return ret; +} + +struct snd_soc_ops ux500_av8100_ops[] = { + { + .hw_params = ux500_av8100_hw_params, + } +}; + diff --git a/sound/soc/ux500/ux500_av8100.h b/sound/soc/ux500/ux500_av8100.h new file mode 100644 index 00000000000..b107b2e1be7 --- /dev/null +++ b/sound/soc/ux500/ux500_av8100.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ola Lilja <ola.o.lilja@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#ifndef UX500_AV8100_H +#define UX500_AV8100_H + +extern struct snd_soc_ops ux500_av8100_ops[]; + +#endif diff --git a/sound/soc/ux500/ux500_cg29xx.c b/sound/soc/ux500/ux500_cg29xx.c new file mode 100644 index 00000000000..e83a6869c5a --- /dev/null +++ b/sound/soc/ux500/ux500_cg29xx.c @@ -0,0 +1,110 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ola Lilja <ola.o.lilja@stericsson.com>, + * Roger Nilsson <roger.xr.nilsson@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#include <sound/soc.h> +#include "../codecs/cg29xx.h" +#include "ux500_msp_dai.h" + +#define UX500_CG29XX_MSP_CLOCK_FREQ 18900000 +#define UX500_CG29XX_DAI_SLOT_WIDTH 16 +#define UX500_CG29XX_DAI_SLOTS 2 +#define UX500_CG29XX_DAI_ACTIVE_SLOTS 0x01 + +int ux500_cg29xx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int channels = params_channels(params); + int err; + + pr_debug("%s: Enter.\n", __func__); + pr_debug("%s: substream->pcm->name = %s.\n", __func__, substream->pcm->name); + pr_debug("%s: substream->pcm->id = %s.\n", __func__, substream->pcm->id); + pr_debug("%s: substream->name = %s.\n", __func__, substream->name); + pr_debug("%s: substream->number = %d.\n", __func__, substream->number); + pr_debug("%s: channels = %d.\n", __func__, channels); + pr_debug("%s: DAI-index (Codec): %d\n", __func__, codec_dai->id); + pr_debug("%s: DAI-index (Platform): %d\n", __func__, cpu_dai->id); + + err = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS); + + if (err) { + pr_err("%s: snd_soc_dai_set_fmt(codec) failed with %d.\n", + __func__, + err); + goto out_err; + } + + err = snd_soc_dai_set_tdm_slot(codec_dai, + 1 << CG29XX_DAI_SLOT0_SHIFT, + 1 << CG29XX_DAI_SLOT0_SHIFT, + UX500_CG29XX_DAI_SLOTS, + UX500_CG29XX_DAI_SLOT_WIDTH); + + if (err) { + pr_err("%s: cg29xx_set_tdm_slot(codec_dai) failed with %d.\n", + __func__, + err); + goto out_err; + } + + err = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS | + SND_SOC_DAIFMT_NB_NF); + + if (err) { + pr_err("%s: snd_soc_dai_set_fmt(cpu_dai) failed with %d.\n", + __func__, + err); + goto out_err; + } + + err = snd_soc_dai_set_sysclk(cpu_dai, + UX500_MSP_MASTER_CLOCK, + UX500_CG29XX_MSP_CLOCK_FREQ, + 0); + + if (err) { + pr_err("%s: snd_soc_dai_set_sysclk(cpu_dai) failed with %d.\n", + __func__, + err); + goto out_err; + } + + err = snd_soc_dai_set_tdm_slot(cpu_dai, + UX500_CG29XX_DAI_ACTIVE_SLOTS, + UX500_CG29XX_DAI_ACTIVE_SLOTS, + UX500_CG29XX_DAI_SLOTS, + UX500_CG29XX_DAI_SLOT_WIDTH); + + if (err) { + pr_err("%s: cg29xx_set_tdm_slot(cpu_dai) failed with %d.\n", + __func__, + err); + goto out_err; + } + +out_err: + return err; +} + +struct snd_soc_ops ux500_cg29xx_ops[] = { + { + .hw_params = ux500_cg29xx_hw_params, + } +}; + diff --git a/sound/soc/ux500/ux500_cg29xx.h b/sound/soc/ux500/ux500_cg29xx.h new file mode 100644 index 00000000000..49a8c3e0478 --- /dev/null +++ b/sound/soc/ux500/ux500_cg29xx.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ola Lilja <ola.o.lilja@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#ifndef UX500_CG29XX_H +#define UX500_CG29XX_H + +extern struct snd_soc_ops ux500_cg29xx_ops[]; + +#endif diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c new file mode 100644 index 00000000000..53f3982343b --- /dev/null +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -0,0 +1,1006 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ola Lilja <ola.o.lilja@stericsson.com>, + * Roger Nilsson <roger.xr.nilsson@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#include <linux/slab.h> +#include <asm/dma.h> +#include <linux/bitops.h> +#include <mach/hardware.h> +#include <mach/msp.h> +#include <linux/i2s/i2s.h> +#include <asm/mach-types.h> + +#include <sound/soc.h> +#include <sound/soc-dai.h> +#include "ux500_msp_dai.h" +#include "ux500_pcm.h" + +static struct ux500_platform_drvdata platform_drvdata[UX500_NBR_OF_DAI] = { + { + .i2s = NULL, + .fmt = 0, + .slots = 1, + .tx_mask = 0x01, + .rx_mask = 0x01, + .slot_width = 16, + .playback_active = false, + .capture_active = false, + .configured = 0, + .data_delay = MSP_DELAY_0, + .master_clk = UX500_MSP_U8500_INTERNAL_CLOCK_FREQ, + }, + { + .i2s = NULL, + .fmt = 0, + .slots = 1, + .tx_mask = 0x01, + .rx_mask = 0x01, + .slot_width = 16, + .playback_active = false, + .capture_active = false, + .configured = 0, + .data_delay = MSP_DELAY_0, + .master_clk = UX500_MSP_U8500_INTERNAL_CLOCK_FREQ, + }, + { + .i2s = NULL, + .fmt = 0, + .slots = 1, + .tx_mask = 0x01, + .rx_mask = 0x01, + .slot_width = 16, + .playback_active = false, + .capture_active = false, + .configured = 0, + .data_delay = MSP_DELAY_0, + .master_clk = UX500_MSP_U8500_INTERNAL_CLOCK_FREQ, + }, + { + .i2s = NULL, + .fmt = 0, + .slots = 1, + .tx_mask = 0x01, + .rx_mask = 0x01, + .slot_width = 16, + .playback_active = false, + .capture_active = false, + .configured = 0, + .data_delay = MSP_DELAY_0, + .master_clk = UX500_MSP_U8500_INTERNAL_CLOCK_FREQ, + }, +}; + +bool ux500_msp_dai_i2s_get_underrun_status(int dai_idx) +{ + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai_idx]; + int status = i2s_hw_status(drvdata->i2s->controller); + return (bool)(status & TRANSMIT_UNDERRUN_ERR_INT); +} + +dma_addr_t ux500_msp_dai_i2s_get_pointer(int dai_idx, int stream_id) +{ + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai_idx]; + return i2s_get_pointer(drvdata->i2s->controller, + (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ? + I2S_DIRECTION_TX : + I2S_DIRECTION_RX); +} + +int ux500_msp_dai_i2s_configure_sg(dma_addr_t dma_addr, + int period_cnt, + size_t period_len, + int dai_idx, + int stream_id) +{ + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai_idx]; + struct i2s_message message; + struct i2s_device *i2s_dev; + int ret = 0; + bool playback_req_valid = + (drvdata->playback_active && + stream_id == SNDRV_PCM_STREAM_PLAYBACK); + bool capture_req_valid = + (drvdata->capture_active && + stream_id == SNDRV_PCM_STREAM_CAPTURE); + + pr_debug("%s: Enter (MSP Index: %u, period-cnt: %u, period-len: %u).\n", + __func__, + dai_idx, + period_cnt, + period_len); + + if (!playback_req_valid && !capture_req_valid) { + pr_err("%s: The I2S controller is not available." + "MSP index:%d\n", + __func__, + dai_idx); + return ret; + } + + i2s_dev = drvdata->i2s; + + message.i2s_transfer_mode = I2S_TRANSFER_MODE_CYCLIC_DMA; + message.i2s_direction = (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ? + I2S_DIRECTION_TX : + I2S_DIRECTION_RX; + message.buf_addr = dma_addr; + message.buf_len = period_cnt * period_len; + message.period_len = period_len; + + ret = i2s_transfer(i2s_dev->controller, &message); + if (ret < 0) { + pr_err("%s: Error: i2s_transfer failed. MSP index: %d\n", + __func__, + dai_idx); + } + + return ret; +} + +static const char *stream_str(struct snd_pcm_substream *substream) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return "Playback"; + else + return "Capture"; +} + +static int ux500_msp_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai->id]; + bool mode_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + + pr_debug("%s: MSP %d (%s): Enter.\n", __func__, dai->id, stream_str(substream)); + + if ((mode_playback && drvdata->playback_active) || + (!mode_playback && drvdata->capture_active)) { + pr_err("%s: Error: MSP %d (%s): Stream already active.\n", + __func__, + dai->id, + stream_str(substream)); + return -EBUSY; + } + + if (mode_playback) + drvdata->playback_active = true; + else + drvdata->capture_active = true; + + return 0; +} + +static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai->id]; + bool mode_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + + pr_debug("%s: MSP %d (%s): Enter.\n", __func__, dai->id, stream_str(substream)); + + if (drvdata == NULL) + return; + + if (mode_playback) + drvdata->playback_active = false; + else + drvdata->capture_active = false; + + if (i2s_cleanup(drvdata->i2s->controller, + mode_playback ? DISABLE_TRANSMIT : DISABLE_RECEIVE)) { + pr_err("%s: Error: MSP %d (%s): Unable to close i2s.\n", + __func__, + dai->id, + stream_str(substream)); + } + + if (mode_playback) + drvdata->configured &= ~PLAYBACK_CONFIGURED; + else + drvdata->configured &= ~CAPTURE_CONFIGURED; +} + +static void ux500_msp_dai_setup_multichannel(struct ux500_platform_drvdata *private, + struct msp_config *msp_config) +{ + struct msp_multichannel_config *multi = &msp_config->multichannel_config; + + if (private->slots > 1) { + msp_config->multichannel_configured = 1; + + multi->tx_multichannel_enable = true; + multi->rx_multichannel_enable = true; + multi->rx_comparison_enable_mode = MSP_COMPARISON_DISABLED; + + multi->tx_channel_0_enable = private->tx_mask; + multi->tx_channel_1_enable = 0; + multi->tx_channel_2_enable = 0; + multi->tx_channel_3_enable = 0; + + multi->rx_channel_0_enable = private->rx_mask; + multi->rx_channel_1_enable = 0; + multi->rx_channel_2_enable = 0; + multi->rx_channel_3_enable = 0; + + pr_debug("%s: Multichannel enabled." + "Slots: %d TX: %u RX: %u\n", + __func__, + private->slots, + multi->tx_channel_0_enable, + multi->rx_channel_0_enable); + } +} + +static void ux500_msp_dai_setup_frameper(struct ux500_platform_drvdata *private, + unsigned int rate, + struct msp_protocol_desc *prot_desc) +{ + switch (private->slots) { + default: + case 1: + switch (rate) { + case 8000: + prot_desc->frame_period = + FRAME_PER_SINGLE_SLOT_8_KHZ; + break; + case 16000: + prot_desc->frame_period = + FRAME_PER_SINGLE_SLOT_16_KHZ; + break; + case 44100: + prot_desc->frame_period = + FRAME_PER_SINGLE_SLOT_44_1_KHZ; + break; + case 48000: + default: + prot_desc->frame_period = + FRAME_PER_SINGLE_SLOT_48_KHZ; + break; + } + break; + + case 2: + prot_desc->frame_period = FRAME_PER_2_SLOTS; + break; + + case 8: + prot_desc->frame_period = + FRAME_PER_8_SLOTS; + break; + + case 16: + prot_desc->frame_period = + FRAME_PER_16_SLOTS; + break; + } + + prot_desc->total_clocks_for_one_frame = + prot_desc->frame_period+1; + + pr_debug("%s: Total clocks per frame: %u\n", + __func__, + prot_desc->total_clocks_for_one_frame); +} + +static void ux500_msp_dai_setup_framing_pcm(struct ux500_platform_drvdata *private, + unsigned int rate, + struct msp_protocol_desc *prot_desc) +{ + u32 frame_length = MSP_FRAME_LENGTH_1; + prot_desc->frame_width = 0; + + switch (private->slots) { + default: + case 1: + frame_length = MSP_FRAME_LENGTH_1; + break; + + case 2: + frame_length = MSP_FRAME_LENGTH_2; + break; + + case 8: + frame_length = MSP_FRAME_LENGTH_8; + break; + + case 16: + frame_length = MSP_FRAME_LENGTH_16; + break; + } + + prot_desc->tx_frame_length_1 = frame_length; + prot_desc->rx_frame_length_1 = frame_length; + prot_desc->tx_frame_length_2 = frame_length; + prot_desc->rx_frame_length_2 = frame_length; + + prot_desc->tx_element_length_1 = MSP_ELEM_LENGTH_16; + prot_desc->rx_element_length_1 = MSP_ELEM_LENGTH_16; + prot_desc->tx_element_length_2 = MSP_ELEM_LENGTH_16; + prot_desc->rx_element_length_2 = MSP_ELEM_LENGTH_16; + + ux500_msp_dai_setup_frameper(private, rate, prot_desc); +} + +static void ux500_msp_dai_setup_clocking(unsigned int fmt, + struct msp_config *msp_config) +{ + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + default: + case SND_SOC_DAIFMT_NB_NF: + msp_config->tx_frame_sync_pol = + MSP_FRAME_SYNC_POL(MSP_FRAME_SYNC_POL_ACTIVE_HIGH); + msp_config->rx_frame_sync_pol = + MSP_FRAME_SYNC_POL_ACTIVE_HIGH << RFSPOL_SHIFT; + break; + + case SND_SOC_DAIFMT_NB_IF: + msp_config->tx_frame_sync_pol = + MSP_FRAME_SYNC_POL(MSP_FRAME_SYNC_POL_ACTIVE_LOW); + msp_config->rx_frame_sync_pol = + MSP_FRAME_SYNC_POL_ACTIVE_LOW << RFSPOL_SHIFT; + break; + } + + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) { + pr_debug("%s: Codec is MASTER.\n", + __func__); + + msp_config->rx_frame_sync_sel = 0; + msp_config->tx_frame_sync_sel = 1 << TFSSEL_SHIFT; + msp_config->tx_clock_sel = 0; + msp_config->rx_clock_sel = 0; + msp_config->srg_clock_sel = 0x2 << SCKSEL_SHIFT; + } else { + pr_debug("%s: Codec is SLAVE.\n", + __func__); + + msp_config->tx_clock_sel = TX_CLK_SEL_SRG; + msp_config->tx_frame_sync_sel = TX_SYNC_SRG_PROG; + msp_config->rx_clock_sel = RX_CLK_SEL_SRG; + msp_config->rx_frame_sync_sel = RX_SYNC_SRG; + msp_config->srg_clock_sel = 1 << SCKSEL_SHIFT; + } +} + +static void ux500_msp_dai_compile_prot_desc_pcm(unsigned int fmt, + struct msp_protocol_desc *prot_desc) +{ + prot_desc->rx_phase_mode = MSP_SINGLE_PHASE; + prot_desc->tx_phase_mode = MSP_SINGLE_PHASE; + prot_desc->rx_phase2_start_mode = MSP_PHASE2_START_MODE_IMEDIATE; + prot_desc->tx_phase2_start_mode = MSP_PHASE2_START_MODE_IMEDIATE; + prot_desc->rx_bit_transfer_format = MSP_BTF_MS_BIT_FIRST; + prot_desc->tx_bit_transfer_format = MSP_BTF_MS_BIT_FIRST; + + if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A) { + pr_debug("%s: DSP_A.\n", + __func__); + prot_desc->tx_clock_pol = MSP_FALLING_EDGE; + prot_desc->rx_clock_pol = MSP_FALLING_EDGE; + } else { + pr_debug("%s: DSP_B.\n", + __func__); + prot_desc->tx_clock_pol = MSP_RISING_EDGE; + prot_desc->rx_clock_pol = MSP_RISING_EDGE; + } + + prot_desc->rx_half_word_swap = MSP_HWS_NO_SWAP; + prot_desc->tx_half_word_swap = MSP_HWS_NO_SWAP; + prot_desc->compression_mode = MSP_COMPRESS_MODE_LINEAR; + prot_desc->expansion_mode = MSP_EXPAND_MODE_LINEAR; + prot_desc->spi_clk_mode = MSP_SPI_CLOCK_MODE_NON_SPI; + prot_desc->spi_burst_mode = MSP_SPI_BURST_MODE_DISABLE; + prot_desc->frame_sync_ignore = MSP_FRAME_SYNC_IGNORE; +} + +static void ux500_msp_dai_compile_prot_desc_i2s(struct msp_protocol_desc *prot_desc) +{ + prot_desc->rx_phase_mode = MSP_DUAL_PHASE; + prot_desc->tx_phase_mode = MSP_DUAL_PHASE; + prot_desc->rx_phase2_start_mode = + MSP_PHASE2_START_MODE_FRAME_SYNC; + prot_desc->tx_phase2_start_mode = + MSP_PHASE2_START_MODE_FRAME_SYNC; + prot_desc->rx_bit_transfer_format = MSP_BTF_MS_BIT_FIRST; + prot_desc->tx_bit_transfer_format = MSP_BTF_MS_BIT_FIRST; + + prot_desc->rx_frame_length_1 = MSP_FRAME_LENGTH_1; + prot_desc->rx_frame_length_2 = MSP_FRAME_LENGTH_1; + prot_desc->tx_frame_length_1 = MSP_FRAME_LENGTH_1; + prot_desc->tx_frame_length_2 = MSP_FRAME_LENGTH_1; + prot_desc->rx_element_length_1 = MSP_ELEM_LENGTH_16; + prot_desc->rx_element_length_2 = MSP_ELEM_LENGTH_16; + prot_desc->tx_element_length_1 = MSP_ELEM_LENGTH_16; + prot_desc->tx_element_length_2 = MSP_ELEM_LENGTH_16; + + prot_desc->rx_clock_pol = MSP_RISING_EDGE; + prot_desc->tx_clock_pol = MSP_RISING_EDGE; + + prot_desc->tx_half_word_swap = MSP_HWS_NO_SWAP; + prot_desc->rx_half_word_swap = MSP_HWS_NO_SWAP; + prot_desc->compression_mode = MSP_COMPRESS_MODE_LINEAR; + prot_desc->expansion_mode = MSP_EXPAND_MODE_LINEAR; + prot_desc->spi_clk_mode = MSP_SPI_CLOCK_MODE_NON_SPI; + prot_desc->spi_burst_mode = MSP_SPI_BURST_MODE_DISABLE; + prot_desc->frame_sync_ignore = MSP_FRAME_SYNC_IGNORE; +} + +static void ux500_msp_dai_compile_msp_config(struct snd_pcm_substream *substream, + struct ux500_platform_drvdata *private, + unsigned int rate, + struct msp_config *msp_config) +{ + struct msp_protocol_desc *prot_desc = &msp_config->protocol_desc; + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int fmt = private->fmt; + + memset(msp_config, 0, sizeof(*msp_config)); + + if (machine_is_u5500()) + msp_config->input_clock_freq = UX500_MSP_U5500_INTERNAL_CLOCK_FREQ; + else + msp_config->input_clock_freq = private->master_clk; + + msp_config->tx_fifo_config = TX_FIFO_ENABLE; + msp_config->rx_fifo_config = RX_FIFO_ENABLE; + msp_config->spi_clk_mode = SPI_CLK_MODE_NORMAL; + msp_config->spi_burst_mode = 0; + msp_config->handler = ux500_pcm_dma_eot_handler; + msp_config->tx_callback_data = + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + substream : NULL; + msp_config->rx_callback_data = + substream->stream == SNDRV_PCM_STREAM_CAPTURE ? + substream : NULL; + msp_config->def_elem_len = 1; + msp_config->direction = + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + MSP_TRANSMIT_MODE : MSP_RECEIVE_MODE; + msp_config->data_size = MSP_DATA_BITS_32; + msp_config->work_mode = MSP_DMA_MODE; + msp_config->frame_freq = rate; + + printk(KERN_INFO "%s: input_clock_freq = %u, frame_freq = %u.\n", + __func__, msp_config->input_clock_freq, msp_config->frame_freq); + /* To avoid division by zero in I2S-driver (i2s_setup) */ + prot_desc->total_clocks_for_one_frame = 1; + + prot_desc->rx_data_delay = private->data_delay; + prot_desc->tx_data_delay = private->data_delay; + + pr_debug("%s: rate: %u channels: %d.\n", + __func__, + rate, + runtime->channels); + switch (fmt & + (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { + + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: + pr_debug("%s: SND_SOC_DAIFMT_I2S.\n", + __func__); + + msp_config->default_protocol_desc = 1; + msp_config->protocol = MSP_I2S_PROTOCOL; + break; + + default: + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: + pr_debug("%s: SND_SOC_DAIFMT_I2S.\n", + __func__); + + msp_config->data_size = MSP_DATA_BITS_16; + msp_config->protocol = MSP_I2S_PROTOCOL; + + ux500_msp_dai_compile_prot_desc_i2s(prot_desc); + break; + + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM: + pr_debug("%s: PCM format.\n", + __func__); + msp_config->data_size = MSP_DATA_BITS_16; + msp_config->protocol = MSP_PCM_PROTOCOL; + + ux500_msp_dai_compile_prot_desc_pcm(fmt, prot_desc); + ux500_msp_dai_setup_multichannel(private, msp_config); + ux500_msp_dai_setup_framing_pcm(private, rate, prot_desc); + break; + } + + ux500_msp_dai_setup_clocking(fmt, msp_config); +} + +static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int ret = 0; + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai->id]; + struct snd_pcm_runtime *runtime = substream->runtime; + struct msp_config msp_config; + bool mode_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + + pr_debug("%s: MSP %d (%s): Enter.\n", __func__, dai->id, stream_str(substream)); + + /* If already configured -> not errors reported */ + if (mode_playback) { + if ((drvdata->configured & PLAYBACK_CONFIGURED) && + (drvdata->playback_active)) + goto cleanup; + } else { + if ((drvdata->configured & CAPTURE_CONFIGURED) && + (drvdata->capture_active)) + goto cleanup; + } + + pr_debug("%s: Setup dai (Rate: %u).\n", __func__, runtime->rate); + ux500_msp_dai_compile_msp_config(substream, + drvdata, + runtime->rate, + &msp_config); + + ret = i2s_setup(drvdata->i2s->controller, &msp_config); + if (ret < 0) { + pr_err("%s: Error: i2s_setup failed (ret = %d)!\n", __func__, ret); + goto cleanup; + } + + drvdata->configured |= mode_playback ? + PLAYBACK_CONFIGURED : CAPTURE_CONFIGURED; + +cleanup: + return ret; +} + +static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + unsigned int mask, slots_active; + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai->id]; + + pr_debug("%s: MSP %d (%s): Enter.\n", + __func__, + dai->id, + stream_str(substream)); + + switch (drvdata->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + if (params_channels(params) != 2) { + pr_err("%s: Error: I2S requires channels = 2 " + "(channels = %d)!\n", + __func__, + params_channels(params)); + return -EINVAL; + } + break; + case SND_SOC_DAIFMT_DSP_B: + case SND_SOC_DAIFMT_DSP_A: + + mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + drvdata->tx_mask : + drvdata->rx_mask; + + slots_active = hweight32(mask); + + pr_debug("TDM slots active: %d", slots_active); + + if (params_channels(params) != slots_active) { + pr_err("%s: Error: PCM TDM format requires channels " + "to match active slots " + "(channels = %d, active slots = %d)!\n", + __func__, + params_channels(params), + slots_active); + return -EINVAL; + } + break; + + default: + break; + } + + return 0; +} + +int ux500_msp_dai_set_data_delay(struct snd_soc_dai *dai, int delay) +{ + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai->id]; + + pr_debug("%s: MSP %d: Enter.\n", __func__, dai->id); + + switch (delay) { + case MSP_DELAY_0: + case MSP_DELAY_1: + case MSP_DELAY_2: + case MSP_DELAY_3: + break; + default: + goto unsupported_delay; + } + + drvdata->data_delay = delay; + return 0; + +unsupported_delay: + pr_err("%s: MSP %d: Error: Unsupported DAI delay (%d)!\n", + __func__, + dai->id, + delay); + return -EINVAL; +} + +static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *dai, + unsigned int fmt) +{ + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai->id]; + + pr_debug("%s: MSP %d: Enter.\n", __func__, dai->id); + + switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: + break; + + default: + goto unsupported_format; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + case SND_SOC_DAIFMT_NB_IF: + break; + + default: + goto unsupported_format; + } + + drvdata->fmt = fmt; + return 0; + +unsupported_format: + pr_err("%s: MSP %d: Error: Unsupported DAI format (0x%x)!\n", + __func__, + dai->id, + fmt); + return -EINVAL; +} + +static int ux500_msp_dai_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, + unsigned int rx_mask, + int slots, + int slot_width) +{ + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai->id]; + unsigned int cap; + + if (!(slots == 1 || slots == 2 || slots == 8 || slots == 16)) { + pr_err("%s: Error: Unsupported slots (%d)! " + "Supported values are 1/2/8/16.\n", + __func__, + slots); + return -EINVAL; + } + drvdata->slots = slots; + + if (!(slot_width == 16)) { + pr_err("%s: Error: Unsupported slots_width (%d)!. " + "Supported value is 16.\n", + __func__, + slot_width); + return -EINVAL; + } + drvdata->slot_width = slot_width; + + switch (slots) { + default: + case 1: + cap = 0x01; + break; + case 2: + cap = 0x03; + break; + case 8: + cap = 0xFF; + break; + case 16: + cap = 0xFFFF; + break; + } + + drvdata->tx_mask = tx_mask & cap; + drvdata->rx_mask = rx_mask & cap; + + return 0; +} + +static int ux500_msp_dai_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, + unsigned int freq, + int dir) +{ + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai->id]; + + pr_debug("%s: MSP %d: Enter. Clk id: %d, freq: %u.\n", + __func__, + dai->id, + clk_id, + freq); + + switch (clk_id) { + case UX500_MSP_MASTER_CLOCK: + drvdata->master_clk = freq; + break; + + default: + pr_err("%s: MSP %d: Invalid clkid: %d.\n", + __func__, + dai->id, + clk_id); + } + + return 0; +} + +static int ux500_msp_dai_trigger(struct snd_pcm_substream *substream, + int cmd, + struct snd_soc_dai *dai) +{ + int ret = 0; + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai->id]; + + pr_debug("%s: MSP %d (%s): Enter (chip_select = %d, cmd = %d).\n", + __func__, + dai->id, + stream_str(substream), + (int)drvdata->i2s->chip_select, + cmd); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + ret = 0; + break; + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = 0; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + ret = 0; + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = 0; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = { + { + .name = "ux500-msp.0", + .id = 0, + .suspend = NULL, + .resume = NULL, + .playback = { + .channels_min = UX500_MSP_MIN_CHANNELS, + .channels_max = UX500_MSP_MAX_CHANNELS, + .rates = UX500_I2S_RATES, + .formats = UX500_I2S_FORMATS, + }, + .capture = { + .channels_min = UX500_MSP_MIN_CHANNELS, + .channels_max = UX500_MSP_MAX_CHANNELS, + .rates = UX500_I2S_RATES, + .formats = UX500_I2S_FORMATS, + }, + .ops = (struct snd_soc_dai_ops[]) { + { + .set_sysclk = ux500_msp_dai_set_dai_sysclk, + .set_fmt = ux500_msp_dai_set_dai_fmt, + .set_tdm_slot = ux500_msp_dai_set_tdm_slot, + .startup = ux500_msp_dai_startup, + .shutdown = ux500_msp_dai_shutdown, + .prepare = ux500_msp_dai_prepare, + .trigger = ux500_msp_dai_trigger, + .hw_params = ux500_msp_dai_hw_params, + } + }, + }, + { + .name = "ux500-msp.1", + .id = 1, + .suspend = NULL, + .resume = NULL, + .playback = { + .channels_min = UX500_MSP_MIN_CHANNELS, + .channels_max = UX500_MSP_MAX_CHANNELS, + .rates = UX500_I2S_RATES, + .formats = UX500_I2S_FORMATS, + }, + .capture = { + .channels_min = UX500_MSP_MIN_CHANNELS, + .channels_max = UX500_MSP_MAX_CHANNELS, + .rates = UX500_I2S_RATES, + .formats = UX500_I2S_FORMATS, + }, + .ops = (struct snd_soc_dai_ops[]) { + { + .set_sysclk = ux500_msp_dai_set_dai_sysclk, + .set_fmt = ux500_msp_dai_set_dai_fmt, + .set_tdm_slot = ux500_msp_dai_set_tdm_slot, + .startup = ux500_msp_dai_startup, + .shutdown = ux500_msp_dai_shutdown, + .prepare = ux500_msp_dai_prepare, + .trigger = ux500_msp_dai_trigger, + .hw_params = ux500_msp_dai_hw_params, + } + }, + }, + { + .name = "ux500-msp.2", + .id = 2, + .suspend = NULL, + .resume = NULL, + .playback = { + .channels_min = UX500_MSP_MIN_CHANNELS, + .channels_max = UX500_MSP_MAX_CHANNELS, + .rates = UX500_I2S_RATES, + .formats = UX500_I2S_FORMATS, + }, + .capture = { + .channels_min = UX500_MSP_MIN_CHANNELS, + .channels_max = UX500_MSP_MAX_CHANNELS, + .rates = UX500_I2S_RATES, + .formats = UX500_I2S_FORMATS, + }, + .ops = (struct snd_soc_dai_ops[]) { + { + .set_sysclk = ux500_msp_dai_set_dai_sysclk, + .set_fmt = ux500_msp_dai_set_dai_fmt, + .set_tdm_slot = ux500_msp_dai_set_tdm_slot, + .startup = ux500_msp_dai_startup, + .shutdown = ux500_msp_dai_shutdown, + .prepare = ux500_msp_dai_prepare, + .trigger = ux500_msp_dai_trigger, + .hw_params = ux500_msp_dai_hw_params, + } + }, + }, + { + .name = "ux500-msp.3", + .id = 3, + .suspend = NULL, + .resume = NULL, + .playback = { + .channels_min = UX500_MSP_MIN_CHANNELS, + .channels_max = UX500_MSP_MAX_CHANNELS, + .rates = UX500_I2S_RATES, + .formats = UX500_I2S_FORMATS, + }, + .capture = { + .channels_min = UX500_MSP_MIN_CHANNELS, + .channels_max = UX500_MSP_MAX_CHANNELS, + .rates = UX500_I2S_RATES, + .formats = UX500_I2S_FORMATS, + }, + .ops = (struct snd_soc_dai_ops[]) { + { + .set_sysclk = ux500_msp_dai_set_dai_sysclk, + .set_fmt = ux500_msp_dai_set_dai_fmt, + .set_tdm_slot = ux500_msp_dai_set_tdm_slot, + .startup = ux500_msp_dai_startup, + .shutdown = ux500_msp_dai_shutdown, + .prepare = ux500_msp_dai_prepare, + .trigger = ux500_msp_dai_trigger, + .hw_params = ux500_msp_dai_hw_params, + } + }, + }, +}; +EXPORT_SYMBOL(ux500_msp_dai_drv); + +static int ux500_msp_drv_probe(struct i2s_device *i2s_dev) +{ + int ret = 0; + struct ux500_platform_drvdata *drvdata; + int msp_idx = i2s_dev->chip_select; + + pr_info("%s: Enter (idx: %d, dev-name: %s, drv-name: %s).\n", + __func__, + msp_idx, + dev_name(&i2s_dev->dev), + i2s_dev->dev.driver->name); + + drvdata = &platform_drvdata[msp_idx]; + drvdata->i2s = i2s_dev; + + try_module_get(i2s_dev->controller->dev.parent->driver->owner); + i2s_set_drvdata(i2s_dev, drvdata); + + pr_debug("%s: Register MSP %d.\n", __func__, msp_idx); + ret = snd_soc_register_dai(&i2s_dev->dev, &ux500_msp_dai_drv[msp_idx]); + if (ret < 0) { + pr_err("Error: %s: Failed to register MSP %d.\n", __func__, msp_idx); + return ret; + } + + return ret; +} + +static int ux500_msp_drv_remove(struct i2s_device *i2s_dev) +{ + struct ux500_platform_drvdata *drvdata = i2s_get_drvdata(i2s_dev); + int msp_idx = i2s_dev->chip_select; + + pr_info("%s: Enter (idx: %d, dev-name: %s, drv-name: %s).\n", + __func__, + msp_idx, + dev_name(&i2s_dev->dev), + i2s_dev->dev.driver->name); + + drvdata->i2s = NULL; + i2s_set_drvdata(i2s_dev, NULL); + + pr_debug("%s: Calling module_put.\n", __func__); + module_put(i2s_dev->controller->dev.parent->driver->owner); + + pr_debug("%s: Unregister ux500-pcm SoC platform driver.\n", __func__); + snd_soc_unregister_dais(&i2s_dev->dev, ARRAY_SIZE(ux500_msp_dai_drv)); + + return 0; +} + +static const struct i2s_device_id dev_id_table[] = { + { "i2s_device.0", 0, 0 }, + { "i2s_device.1", 1, 0 }, + { "i2s_device.2", 2, 0 }, + { "i2s_device.3", 3, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2s, dev_id_table); + +static struct i2s_driver i2sdrv_i2s = { + .driver = { + .name = "i2s", + .owner = THIS_MODULE, + }, + .probe = ux500_msp_drv_probe, + .remove = __devexit_p(ux500_msp_drv_remove), + .id_table = dev_id_table, +}; + +static int __init ux500_msp_init(void) +{ + return i2s_register_driver(&i2sdrv_i2s); +} + +static void __exit ux500_msp_exit(void) +{ + i2s_unregister_driver(&i2sdrv_i2s); +} + +module_init(ux500_msp_init); +module_exit(ux500_msp_exit); + +MODULE_LICENSE("GPLv2"); diff --git a/sound/soc/ux500/ux500_msp_dai.h b/sound/soc/ux500/ux500_msp_dai.h new file mode 100644 index 00000000000..64a23506bca --- /dev/null +++ b/sound/soc/ux500/ux500_msp_dai.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ola Lilja <ola.o.lilja@stericsson.com>, + * Roger Nilsson <roger.xr.nilsson@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#ifndef UX500_msp_dai_H +#define UX500_msp_dai_H + +#include <linux/types.h> +#include <linux/spinlock.h> +#include <linux/i2s/i2s.h> +#include <mach/msp.h> + +#define UX500_NBR_OF_DAI 4 + +#define UX500_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) + +#define UX500_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) + +#define FRAME_PER_SINGLE_SLOT_8_KHZ 31 +#define FRAME_PER_SINGLE_SLOT_16_KHZ 124 +#define FRAME_PER_SINGLE_SLOT_44_1_KHZ 63 +#define FRAME_PER_SINGLE_SLOT_48_KHZ 49 +#define FRAME_PER_2_SLOTS 31 +#define FRAME_PER_8_SLOTS 138 +#define FRAME_PER_16_SLOTS 277 + +#define UX500_MSP_U5500_INTERNAL_CLOCK_FREQ 13000000 +#define UX500_MSP_U8500_INTERNAL_CLOCK_FREQ 40000000 + +#define UX500_MSP_MIN_CHANNELS 1 +#define UX500_MSP_MAX_CHANNELS 8 + +#define PLAYBACK_CONFIGURED 1 +#define CAPTURE_CONFIGURED 2 + +enum ux500_msp_clock_id { + UX500_MSP_MASTER_CLOCK, +}; + +struct ux500_platform_drvdata { + struct i2s_device *i2s; + unsigned int fmt; + unsigned int tx_mask; + unsigned int rx_mask; + int slots; + int slot_width; + bool playback_active; + bool capture_active; + u8 configured; + int data_delay; + unsigned int master_clk; +}; + +extern struct snd_soc_dai ux500_msp_dai[UX500_NBR_OF_DAI]; + +bool ux500_msp_dai_i2s_get_underrun_status(int dai_idx); +dma_addr_t ux500_msp_dai_i2s_get_pointer(int dai_idx, int stream_id); +int ux500_msp_dai_i2s_configure_sg(dma_addr_t dma_addr, + int perod_cnt, + size_t period_len, + int dai_idx, + int stream_id); +int ux500_msp_dai_i2s_send_data(void *data, size_t bytes, int dai_idx); +int ux500_msp_dai_i2s_receive_data(void *data, size_t bytes, int dai_idx); + +int ux500_msp_dai_set_data_delay(struct snd_soc_dai *dai, int delay); + +#endif diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c new file mode 100644 index 00000000000..ee953f1b5e5 --- /dev/null +++ b/sound/soc/ux500/ux500_pcm.c @@ -0,0 +1,429 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ola Lilja <ola.o.lilja@stericsson.com>, + * Roger Nilsson <roger.xr.nilsson@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +#include <asm/page.h> + +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/slab.h> + +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "ux500_pcm.h" +#include "ux500_msp_dai.h" + +static struct snd_pcm_hardware ux500_pcm_hw_playback = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_PAUSE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_U16_LE | + SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_U16_BE, + .rates = SNDRV_PCM_RATE_KNOT, + .rate_min = UX500_PLATFORM_MIN_RATE_PLAYBACK, + .rate_max = UX500_PLATFORM_MAX_RATE_PLAYBACK, + .channels_min = UX500_PLATFORM_MIN_CHANNELS, + .channels_max = UX500_PLATFORM_MAX_CHANNELS, + .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX, + .period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN, + .period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX, + .periods_min = UX500_PLATFORM_PERIODS_MIN, + .periods_max = UX500_PLATFORM_PERIODS_MAX, +}; + +static struct snd_pcm_hardware ux500_pcm_hw_capture = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_PAUSE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_U16_LE | + SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_U16_BE, + .rates = SNDRV_PCM_RATE_KNOT, + .rate_min = UX500_PLATFORM_MIN_RATE_CAPTURE, + .rate_max = UX500_PLATFORM_MAX_RATE_CAPTURE, + .channels_min = UX500_PLATFORM_MIN_CHANNELS, + .channels_max = UX500_PLATFORM_MAX_CHANNELS, + .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX, + .period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN, + .period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX, + .periods_min = UX500_PLATFORM_PERIODS_MIN, + .periods_max = UX500_PLATFORM_PERIODS_MAX, +}; + +static const char *stream_str(struct snd_pcm_substream *substream) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return "Playback"; + else + return "Capture"; +} + +static void ux500_pcm_dma_hw_free(struct device *dev, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_dma_buffer *buf = runtime->dma_buffer_p; + + if (runtime->dma_area == NULL) + return; + + if (buf != &substream->dma_buffer) { + dma_free_coherent( + buf->dev.dev, + buf->bytes, + buf->area, + buf->addr); + kfree(runtime->dma_buffer_p); + } + + snd_pcm_set_runtime_buffer(substream, NULL); +} + +void ux500_pcm_dma_eot_handler(void *data) +{ + struct snd_pcm_substream *substream = data; + struct snd_pcm_runtime *runtime; + struct ux500_pcm_private *private; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *dai = rtd->cpu_dai; + + pr_debug("%s: MSP %d (%s): Enter.\n", __func__, dai->id, stream_str(substream)); + + if (substream) { + runtime = substream->runtime; + private = substream->runtime->private_data; + + if (ux500_msp_dai_i2s_get_underrun_status(private->msp_id)) { + private->no_of_underruns++; + pr_debug("%s: Nr of underruns (%d)\n", __func__, + private->no_of_underruns); + } + + /* calc the offset in the circular buffer */ + private->offset += frames_to_bytes(runtime, + runtime->period_size); + private->offset %= frames_to_bytes(runtime, + runtime->period_size) * runtime->periods; + + snd_pcm_period_elapsed(substream); + } +} +EXPORT_SYMBOL(ux500_pcm_dma_eot_handler); + +static int ux500_pcm_open(struct snd_pcm_substream *substream) +{ + int stream_id = substream->pstr->stream; + struct snd_pcm_runtime *runtime = substream->runtime; + struct ux500_pcm_private *private; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *dai = rtd->cpu_dai; + int ret; + + pr_debug("%s: MSP %d (%s): Enter.\n", __func__, dai->id, stream_str(substream)); + + pr_debug("%s: Set runtime hwparams.\n", __func__); + if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_set_runtime_hwparams(substream, &ux500_pcm_hw_playback); + else + snd_soc_set_runtime_hwparams(substream, &ux500_pcm_hw_capture); + + /* ensure that buffer size is a multiple of period size */ + ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) { + pr_err("%s: Error: snd_pcm_hw_constraints failed (%d)\n", + __func__, + ret); + return ret; + } + + pr_debug("%s: Init runtime private data.\n", __func__); + private = kzalloc(sizeof(struct ux500_pcm_private), GFP_KERNEL); + if (private == NULL) + return -ENOMEM; + private->msp_id = dai->id; + runtime->private_data = private; + + pr_debug("%s: Set hw-struct for %s.\n", __func__, stream_str(substream)); + runtime->hw = (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ? + ux500_pcm_hw_playback : ux500_pcm_hw_capture; + + return 0; +} + +static int ux500_pcm_close(struct snd_pcm_substream *substream) +{ + struct ux500_pcm_private *private = substream->runtime->private_data; + + pr_debug("%s: Enter\n", __func__); + + kfree(private); + + return 0; +} + +static int ux500_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_dma_buffer *buf = runtime->dma_buffer_p; + int ret = 0; + int size; + + pr_debug("%s: Enter\n", __func__); + + size = params_buffer_bytes(hw_params); + + if (buf) { + if (buf->bytes >= size) + goto out; + ux500_pcm_dma_hw_free(NULL, substream); + } + + if (substream->dma_buffer.area != NULL && + substream->dma_buffer.bytes >= size) { + buf = &substream->dma_buffer; + } else { + buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL); + if (!buf) + goto nomem; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = NULL; + buf->area = dma_alloc_coherent( + NULL, + size, + &buf->addr, + GFP_KERNEL); + buf->bytes = size; + buf->private_data = NULL; + + if (!buf->area) + goto free; + } + snd_pcm_set_runtime_buffer(substream, buf); + ret = 1; + out: + runtime->dma_bytes = size; + return ret; + + free: + kfree(buf); + nomem: + return -ENOMEM; +} + +static int ux500_pcm_hw_free(struct snd_pcm_substream *substream) +{ + pr_debug("%s: Enter\n", __func__); + + ux500_pcm_dma_hw_free(NULL, substream); + + return 0; +} + +static int ux500_pcm_prepare(struct snd_pcm_substream *substream) +{ + pr_debug("%s: Enter\n", __func__); + return 0; +} + +static int ux500_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + int ret; + struct snd_pcm_runtime *runtime = substream->runtime; + struct ux500_pcm_private *private = runtime->private_data; + int stream_id = substream->pstr->stream; + + pr_debug("%s: Enter\n", __func__); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + pr_debug("%s: START/PAUSE-RELEASE\n", __func__); + if (runtime->status->state == SNDRV_PCM_STATE_XRUN) { + pr_debug("XRUN occurred\n"); + return 0; + } + + private->no_of_underruns = 0; + private->offset = 0; + ret = ux500_msp_dai_i2s_configure_sg(runtime->dma_addr, + runtime->periods, + frames_to_bytes(runtime, runtime->period_size), + private->msp_id, + stream_id); + if (ret) { + pr_err("%s: Failed to configure sg-list!\n", __func__); + return -EINVAL; + } + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + break; + + case SNDRV_PCM_TRIGGER_STOP: + pr_debug("%s: SNDRV_PCM_TRIGGER_STOP\n", __func__); + pr_debug("%s: no_of_underruns = %u\n", + __func__, + private->no_of_underruns); + break; + + default: + pr_err("%s: Invalid command in pcm trigger\n", + __func__); + return -EINVAL; + } + + return 0; +} + +static snd_pcm_uframes_t ux500_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct ux500_pcm_private *private = runtime->private_data; + + pr_debug("%s: dma_offset %d frame %ld\n", __func__, private->offset, + bytes_to_frames(substream->runtime, private->offset)); + + return bytes_to_frames(substream->runtime, private->offset); +} + +static int ux500_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + pr_debug("%s: Enter.\n", __func__); + + return dma_mmap_coherent( + NULL, + vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); +} + +static struct snd_pcm_ops ux500_pcm_ops = { + .open = ux500_pcm_open, + .close = ux500_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = ux500_pcm_hw_params, + .hw_free = ux500_pcm_hw_free, + .prepare = ux500_pcm_prepare, + .trigger = ux500_pcm_trigger, + .pointer = ux500_pcm_pointer, + .mmap = ux500_pcm_mmap +}; + +int ux500_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, + struct snd_pcm *pcm) +{ + pr_debug("%s: pcm = %d\n", __func__, (int)pcm); + + pcm->info_flags = 0; + strcpy(pcm->name, "UX500_PCM"); + + pr_debug("%s: pcm->name = %s.\n", __func__, pcm->name); + + return 0; +} + +static void ux500_pcm_free(struct snd_pcm *pcm) +{ + pr_debug("%s: Enter\n", __func__); +} + +static int ux500_pcm_suspend(struct snd_soc_dai *dai) +{ + pr_debug("%s: Enter\n", __func__); + + return 0; +} + +static int ux500_pcm_resume(struct snd_soc_dai *dai) +{ + pr_debug("%s: Enter\n", __func__); + + return 0; +} + +struct snd_soc_platform_driver ux500_pcm_soc_drv = { + .ops = &ux500_pcm_ops, + .pcm_new = ux500_pcm_new, + .pcm_free = ux500_pcm_free, + .suspend = ux500_pcm_suspend, + .resume = ux500_pcm_resume, +}; +EXPORT_SYMBOL(ux500_pcm_soc_drv); + +static int __devexit ux500_pcm_drv_probe(struct platform_device *pdev) +{ + int ret; + + pr_info("%s: Register ux500-pcm SoC platform driver.\n", __func__); + ret = snd_soc_register_platform(&pdev->dev, &ux500_pcm_soc_drv); + if (ret < 0) { + pr_err("%s: Error: Failed to register " + "ux500-pcm SoC platform driver (%d)!\n", + __func__, + ret); + return ret; + } + + return 0; +} + +static int __devinit ux500_pcm_drv_remove(struct platform_device *pdev) +{ + pr_info("%s: Unregister ux500-pcm SoC platform driver.\n", __func__); + snd_soc_unregister_platform(&pdev->dev); + + return 0; +} + +static struct platform_driver ux500_pcm_driver = { + .driver = { + .name = "ux500-pcm", + .owner = THIS_MODULE, + }, + + .probe = ux500_pcm_drv_probe, + .remove = __devexit_p(ux500_pcm_drv_remove), +}; + +static int __init ux500_pcm_drv_init(void) +{ + pr_debug("%s: Register ux500-pcm platform driver.\n", __func__); + + return platform_driver_register(&ux500_pcm_driver); +} + +static void __exit ux500_pcm_drv_exit(void) +{ + pr_debug("%s: Unregister ux500-pcm platform driver.\n", __func__); + + platform_driver_unregister(&ux500_pcm_driver); +} + +module_init(ux500_pcm_drv_init); +module_exit(ux500_pcm_drv_exit); + +MODULE_LICENSE("GPL"); diff --git a/sound/soc/ux500/ux500_pcm.h b/sound/soc/ux500/ux500_pcm.h new file mode 100644 index 00000000000..50f46615275 --- /dev/null +++ b/sound/soc/ux500/ux500_pcm.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ola Lilja <ola.o.lilja@stericsson.com>, + * Roger Nilsson <roger.xr.nilsson@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ +#ifndef UX500_PCM_H +#define UX500_PCM_H + +#include <mach/msp.h> + +#define UX500_PLATFORM_MIN_RATE_PLAYBACK 8000 +#define UX500_PLATFORM_MAX_RATE_PLAYBACK 48000 +#define UX500_PLATFORM_MIN_RATE_CAPTURE 8000 +#define UX500_PLATFORM_MAX_RATE_CAPTURE 48000 + +#define UX500_PLATFORM_MIN_CHANNELS 1 +#define UX500_PLATFORM_MAX_CHANNELS 8 + +#define UX500_PLATFORM_PERIODS_BYTES_MIN 128 +#define UX500_PLATFORM_PERIODS_BYTES_MAX (64 * PAGE_SIZE) +#define UX500_PLATFORM_PERIODS_MIN 2 +#define UX500_PLATFORM_PERIODS_MAX 48 +#define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE) + +extern struct snd_soc_platform ux500_soc_platform; + +struct ux500_pcm_private { + int msp_id; + int stream_id; + unsigned int no_of_underruns; + unsigned int offset; +}; + +void ux500_pcm_dma_eot_handler(void *data); + +#endif diff --git a/sound/u8500_acodec_ab8500.c b/sound/u8500_acodec_ab8500.c new file mode 100644 index 00000000000..c75da368832 --- /dev/null +++ b/sound/u8500_acodec_ab8500.c @@ -0,0 +1,2523 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Deepak Karda + * for ST-Ericsson. + * + * License terms: + * + * 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. + */ + +/*----------------------------------------------------------------------------- +* Common Includes +*---------------------------------------------------------------------------*/ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/soundcard.h> +#include <linux/sound.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/i2s/i2s.h> +#include <mach/msp.h> +#include <linux/gpio.h> +/*#include <mach/i2c.h>*/ +#include <mach/debug.h> +#include <mach/u8500_acodec_ab8500.h> +#include <mach/ab8500.h> + +#ifdef CONFIG_U8500_AB8500_CUT10 +#include <mach/ab8500_codec_v1_0.h> +#endif +#ifdef CONFIG_U8500_AB8500_ED +#include <mach/ab8500_codec.h> +#endif + +#define ELEMENT_SIZE 0 +#define FRAME_SIZE -1 +#define MSP_NUM 0 + +/* Debugging stuff */ + +#define ACODEC_NAME "DRIVER ACODEC" +#define DRIVER_DEBUG CONFIG_STM_ACODEC_DEBUG /* enables/disables debug msgs */ +#define DRIVER_DEBUG_PFX ACODEC_NAME /* msg header represents this module */ +#define DRIVER_DBG KERN_ERR /* message level */ +#define NMDK_DEBUG CONFIG_STM_ACODEC_DEBUG +extern struct driver_debug_st DBG_ST; + +#if NMDK_DEBUG > 0 +t_ab8500_codec_error dump_acodec_registers(void); +t_ab8500_codec_error dump_msp_registers(void); +#endif + +#ifdef CONFIG_U8500_ACODEC_DMA +static void u8500_digital_lpbk_tx_dma_start(void); +static void u8500_digital_lpbk_rx_dma_start(void); +#endif + +int second_config; +/*---------------------------------------------------------------------------- +* global declarations +*---------------------------------------------------------------------------*/ +t_u8500_codec_system_context g_codec_system_context; + +int u8500_acodec_rates[MAX_NO_OF_RATES] = { 48000 }; + +char *codec_dest_texts[NUMBER_OUTPUT_DEVICE] = { + "CODEC_DEST_HEADSET", "CODEC_DEST_EARPIECE", "CODEC_DEST_HANDSFREE", + "CODEC_DEST_VIBRATOR1", "CODEC_DEST_VIBRATOR2" +}; + +char *codec_in_texts[NUMBER_INPUT_DEVICE] = { + "CODEC_SRC_LINEIN", "CODEC_SRC_MICROPHONE_1A", + "CODEC_SRC_MICROPHONE_1B", + "CODEC_SRC_MICROPHONE_2", "CODEC_SRC_D_MICROPHONE_1", + "CODEC_SRC_D_MICROPHONE_2", + "CODEC_SRC_D_MICROPHONE_3", "CODEC_SRC_D_MICROPHONE_4", + "CODEC_SRC_D_MICROPHONE_5", + "CODEC_SRC_D_MICROPHONE_6", "CODEC_SRC_D_MICROPHONE_12", + "CODEC_SRC_D_MICROPHONE_34", + "CODEC_SRC_D_MICROPHONE_56" +}; + +char *lpbk_state_in_texts[NUMBER_LOOPBACK_STATE] = { "DISABLE", "ENABLE" }; +char *switch_state_in_texts[NUMBER_SWITCH_STATE] = { "DISABLE", "ENABLE" }; +char *power_state_in_texts[NUMBER_POWER_STATE] = { "DISABLE", "ENABLE" }; +char *tdm_mode_state_in_texts[NUMBER_POWER_STATE] = { "DISABLE", "ENABLE" }; +char *direct_rendering_state_in_texts[NUMBER_DIRECT_RENDERING_STATE] = + { "DISABLE", "ENABLE" }; +char *pcm_rendering_state_in_texts[NUMBER_PCM_RENDERING_STATE] = + { "DISABLE", "ENABLE", "PENDING" }; + +EXPORT_SYMBOL(codec_dest_texts); +EXPORT_SYMBOL(codec_in_texts); + +static void ab8500_codec_power_init(void); +static int check_device_id(); +t_ab8500_codec_error perform_src_routing(t_ab8500_codec_src input_device); +t_ab8500_codec_error + u8500_acodec_allocate_all_mono_slots + (t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line1); +t_ab8500_codec_error + u8500_acodec_allocate_all_stereo_slots + (t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line1, + t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line2); + +#if 0 //from Arnaud +/* For Codec in Master mode for recording*/ +struct msp_protocol_desc protocol_desc_tdm_mode = { + MSP_DATA_TRANSFER_WIDTH_HALFWORD, /*rx_data_transfer_width */ + MSP_DATA_TRANSFER_WIDTH_HALFWORD, /*tx_data_transfer_width */ + MSP_SINGLE_PHASE, /*rx_phase_mode */ + MSP_SINGLE_PHASE, /*tx_phase_mode */ + MSP_PHASE2_START_MODE_IMEDIATE, /*rx_phase2_start_mode */ + MSP_PHASE2_START_MODE_IMEDIATE, /*tx_phase2_start_mode */ + MSP_BTF_MS_BIT_FIRST, /*rx_endianess */ + MSP_BTF_MS_BIT_FIRST, /*tx_endianess */ + MSP_FRAME_LENGTH_2, /*rx_frame_length_1 */ + MSP_FRAME_LENGTH_2, /*rx_frame_length_2 */ + MSP_FRAME_LENGTH_2, /*tx_frame_length_1 */ + MSP_FRAME_LENGTH_2, /*tx_frame_length_2 */ + MSP_ELEM_LENGTH_16, /*rx_element_length_1 */ + MSP_ELEM_LENGTH_16, /*rx_element_length_2 */ + MSP_ELEM_LENGTH_16, /*tx_element_length_1 */ + MSP_ELEM_LENGTH_16, /*tx_element_length_2 */ + MSP_DELAY_0, /*rx_data_delay */ + MSP_DELAY_0, /*tx_data_delay */ + MSP_FALLING_EDGE, /*rx_clock_pol */ + MSP_RISING_EDGE, /*tx_clock_pol */ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, /*rx_msp_frame_pol */ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, /*tx_msp_frame_pol */ + MSP_HWS_NO_SWAP, /*rx_half_word_swap */ + MSP_HWS_NO_SWAP, /*tx_half_word_swap */ + MSP_COMPRESS_MODE_LINEAR, /*compression_mode */ + MSP_EXPAND_MODE_LINEAR, /*expansion_mode */ + MSP_SPI_CLOCK_MODE_NON_SPI, /*spi_clk_mode */ + MSP_SPI_BURST_MODE_DISABLE, /*spi_burst_mode */ + 63, /*frame_period */ + 31, /*frame_width */ + 64, /*total_clocks_for_one_frame */ +}; +#endif + +#if 0 //from HCL +/* For Codec in Master mode for recording*/ +struct msp_protocol_desc protocol_desc_tdm_mode = { + MSP_DATA_TRANSFER_WIDTH_WORD, /*rx_data_transfer_width */ + MSP_DATA_TRANSFER_WIDTH_WORD, /*tx_data_transfer_width */ + MSP_DUAL_PHASE, /*rx_phase_mode */ + MSP_DUAL_PHASE, /*tx_phase_mode */ + MSP_PHASE2_START_MODE_FRAME_SYNC, /*rx_phase2_start_mode */ + MSP_PHASE2_START_MODE_FRAME_SYNC, /*tx_phase2_start_mode */ + MSP_BTF_MS_BIT_FIRST, /*rx_endianess */ + MSP_BTF_MS_BIT_FIRST, /*tx_endianess */ + MSP_FRAME_LENGTH_1, /*rx_frame_length_1 */ + MSP_FRAME_LENGTH_1, /*rx_frame_length_2 */ + MSP_FRAME_LENGTH_1, /*tx_frame_length_1 */ + MSP_FRAME_LENGTH_1, /*tx_frame_length_2 */ + MSP_ELEM_LENGTH_16, /*rx_element_length_1 */ + MSP_ELEM_LENGTH_16, /*rx_element_length_2 */ + MSP_ELEM_LENGTH_16, /*tx_element_length_1 */ + MSP_ELEM_LENGTH_16, /*tx_element_length_2 */ + MSP_DELAY_0, /*rx_data_delay */ + MSP_DELAY_0, /*tx_data_delay */ + MSP_RISING_EDGE, /*rx_clock_pol */ + MSP_RISING_EDGE, /*tx_clock_pol */ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, /*rx_msp_frame_pol */ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, /*tx_msp_frame_pol */ + MSP_HWS_NO_SWAP, /*rx_half_word_swap */ + MSP_HWS_NO_SWAP, /*tx_half_word_swap */ + MSP_COMPRESS_MODE_LINEAR, /*compression_mode */ + MSP_EXPAND_MODE_LINEAR, /*expansion_mode */ + MSP_SPI_CLOCK_MODE_NON_SPI, /*spi_clk_mode */ + MSP_SPI_BURST_MODE_DISABLE, /*spi_burst_mode */ + 255, /*frame_period */ + 0, /*frame_width */ + 256, /*total_clocks_for_one_frame */ +}; + +#endif + +#if 0 //from STS +struct msp_protocol_desc protocol_desc_tdm_mode = { + MSP_DATA_TRANSFER_WIDTH_HALFWORD, /*rx_data_transfer_width */ + MSP_DATA_TRANSFER_WIDTH_HALFWORD, /*tx_data_transfer_width */ + MSP_SINGLE_PHASE, /*rx_phase_mode */ + MSP_SINGLE_PHASE, /*tx_phase_mode */ + MSP_PHASE2_START_MODE_IMEDIATE, /*rx_phase2_start_mode */ + MSP_PHASE2_START_MODE_IMEDIATE, /*tx_phase2_start_mode */ + MSP_BTF_MS_BIT_FIRST, /*rx_endianess */ + MSP_BTF_MS_BIT_FIRST, /*tx_endianess */ + MSP_FRAME_LENGTH_2, /*rx_frame_length_1 */ + MSP_FRAME_LENGTH_1, /*rx_frame_length_2 */ + MSP_FRAME_LENGTH_2, /*tx_frame_length_1 */ + MSP_FRAME_LENGTH_1, /*tx_frame_length_2 */ + MSP_ELEM_LENGTH_16, /*rx_element_length_1 */ + MSP_ELEM_LENGTH_16, /*rx_element_length_2 */ + MSP_ELEM_LENGTH_16, /*tx_element_length_1 */ + MSP_ELEM_LENGTH_16, /*tx_element_length_2 */ + MSP_DELAY_0, /*rx_data_delay */ + MSP_DELAY_0, /*tx_data_delay */ + MSP_FALLING_EDGE, /*rx_clock_pol */ + MSP_RISING_EDGE, /*tx_clock_pol */ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, /*rx_msp_frame_pol */ + MSP_FRAME_SYNC_POL_ACTIVE_HIGH, /*tx_msp_frame_pol */ + MSP_HWS_NO_SWAP, /*rx_half_word_swap */ + MSP_HWS_NO_SWAP, /*tx_half_word_swap */ + MSP_COMPRESS_MODE_LINEAR, /*compression_mode */ + MSP_EXPAND_MODE_LINEAR, /*expansion_mode */ + MSP_SPI_CLOCK_MODE_NON_SPI, /*spi_clk_mode */ + MSP_SPI_BURST_MODE_DISABLE, /*spi_burst_mode */ + 25, /*frame_period */ + 32, /*frame_width */ + 32, /*total_clocks_for_one_frame */ +}; +#endif + +#define DIGITAL_LPBK_MAX_BIFFERS 3 + +#ifdef CONFIG_U8500_AB8500_CUT10 +#define NB_OF_CHANNEL_USED 8 +#else +#define NB_OF_CHANNEL_USED 6 +#endif + +#define MONO_SRC 1 +#define STEREO_SRC 2 + +typedef struct { + unsigned char *area; /* virtual pointer */ + dma_addr_t addr; /* physical address */ +} t_dma_buffer; + +typedef struct { + struct completion tx_dma_com; + struct completion rx_dma_com; + volatile int rx_active; + volatile int tx_active; + t_dma_buffer buffer; + int data_size; + int rx_index; + int tx_index; +} t_digital_lpbk_cnxt; + +const int play_flag = 1; +const int capture_flag = 2; + +t_digital_lpbk_cnxt digital_lpbk_cnxt; + +void u8500_set_defaults() +{ + int i; + + for (i = 0; i < NUMBER_INPUT_DEVICE; i++) { + g_codec_system_context.input_config[i].left_volume = 0; + g_codec_system_context.input_config[i].right_volume = 0; + g_codec_system_context.input_config[i].mute_state = DISABLE; + g_codec_system_context.input_config[i].power_state = DISABLE; + } + + for (i = 0; i < NUMBER_OUTPUT_DEVICE; i++) { + g_codec_system_context.output_config[i].left_volume = 0; + g_codec_system_context.output_config[i].right_volume = 0; + g_codec_system_context.output_config[i].mute_state = DISABLE; + g_codec_system_context.output_config[i].power_state = DISABLE; + } + +} //END OF FUNCTION + +struct i2sdrv_data *i2sdrv[MAX_I2S_CLIENTS]; + +t_ab8500_codec_error u8500_acodec_open(int client_id, int stream_id) +{ + struct i2sdrv_data *p_i2sdrv_data = NULL; + struct i2s_device *i2s; + + p_i2sdrv_data = i2sdrv[client_id]; + + if (!p_i2sdrv_data) + return (-1); + + i2s = p_i2sdrv_data->i2s; + + if (stream_id == 0) //PLAYBACK + { + if (p_i2sdrv_data->tx_status) + return -1; + else { + p_i2sdrv_data->tx_status = 1; + } + } else if (stream_id == 1) //CAPTURE + { + if (p_i2sdrv_data->rx_status) + return -1; + else { + p_i2sdrv_data->rx_status = 1; + } + } + + p_i2sdrv_data->flag = 0; + + return 0; +} + +t_ab8500_codec_error u8500_acodec_send_data(int client_id, void *data, + size_t bytes, int dma_flag) +{ + struct i2sdrv_data *p_i2sdrv_data = NULL; + struct i2s_device *i2s_dev = NULL; + int bytes_transmit; + struct i2s_message message; + + p_i2sdrv_data = i2sdrv[client_id]; + + if (!p_i2sdrv_data) + return (-1); + + i2s_dev = p_i2sdrv_data->i2s; + + if (p_i2sdrv_data->flag) { + stm_dbg(DBG_ST.acodec, " I2S controller not available\n"); + return -1; + } + + message.i2s_transfer_mode = I2S_TRANSFER_MODE_SINGLE_DMA; + message.i2s_direction = I2S_DIRECTION_TX; + message.txbytes = bytes; + message.txdata = data; + message.dma_flag = dma_flag; + + bytes_transmit = i2s_transfer(i2s_dev->controller, &message); + + if (bytes_transmit < 0) { + printk("error in transfer\n"); + return -1; + } + return bytes_transmit; + +} + +t_ab8500_codec_error u8500_acodec_loopback_configure(int client_id, void *data, + size_t bytes, int dma_flag) +{ + struct i2sdrv_data *p_i2sdrv_data = NULL; + struct i2s_device *i2s_dev = NULL; + int bytes_receive; + struct i2s_message message; + + p_i2sdrv_data = i2sdrv[client_id]; + + if (!p_i2sdrv_data) + return (-1); + + i2s_dev = p_i2sdrv_data->i2s; + + if (p_i2sdrv_data->flag) { + stm_dbg(DBG_ST.acodec, " I2S controller not available\n"); + return -1; + } + + message.i2s_transfer_mode = I2S_TRANSFER_MODE_INF_LOOPBACK; + message.rxbytes = bytes; + message.rxdata = data; + message.txbytes = bytes; + message.txdata = data; + message.dma_flag = dma_flag; + + bytes_receive = i2s_transfer(i2s_dev->controller, &message); + + if (bytes_receive < 0) { + printk(" not get\n"); + return -1; + } + return bytes_receive; + +} + +t_ab8500_codec_error u8500_acodec_receive_data(int client_id, void *data, + size_t bytes, int dma_flag) +{ + struct i2sdrv_data *p_i2sdrv_data = NULL; + struct i2s_device *i2s_dev = NULL; + int bytes_receive; + struct i2s_message message; + + p_i2sdrv_data = i2sdrv[client_id]; + + if (!p_i2sdrv_data) + return (-1); + + i2s_dev = p_i2sdrv_data->i2s; + + if (p_i2sdrv_data->flag) { + stm_dbg(DBG_ST.acodec, " I2S controller not available\n"); + return -1; + } + + message.i2s_transfer_mode = I2S_TRANSFER_MODE_SINGLE_DMA; + message.i2s_direction = I2S_DIRECTION_RX; + message.rxbytes = bytes; + message.rxdata = data; + message.dma_flag = dma_flag; + + bytes_receive = i2s_transfer(i2s_dev->controller, &message); + + if (bytes_receive < 0) { + printk(" not get\n"); + return -1; + } + return bytes_receive; + +} + +t_ab8500_codec_error u8500_acodec_close(int client_id, t_acodec_disable flag) +{ + struct i2sdrv_data *p_i2sdrv_data = NULL; + struct i2s_device *i2s_dev = NULL; + int status = 0; + + p_i2sdrv_data = i2sdrv[client_id]; + + if (!p_i2sdrv_data) + return (-1); + + i2s_dev = p_i2sdrv_data->i2s; + + if (p_i2sdrv_data->flag) { + stm_dbg(DBG_ST.acodec, " I2S controller not available\n"); + return -1; + } + + if (flag == DISABLE_ALL) { + p_i2sdrv_data->flag = -1; + p_i2sdrv_data->tx_status = 0; + p_i2sdrv_data->rx_status = 0; + } else if (flag == DISABLE_TRANSMIT) { + p_i2sdrv_data->tx_status = 0; + } else if (flag == DISABLE_RECEIVE) { + p_i2sdrv_data->rx_status = 0; + } + status = i2s_cleanup(i2s_dev->controller, flag); + if (status) { + return -1; + } + + return 0; +} + +/** +* u8500_acodec_enable_audio_mode +* +* @direction - direction of data flow (from/to) audiocode +* @mspClockSel - clock for MSP +* @mspInClockFreq - input clock for MSP +* @channels - number of channel, 1 for mono and 2 for stereo +* +* It configures the audiocodec in audio mode. In this case,the I2S +* protocol is used for data exchanges. +*/ + +t_ab8500_codec_error u8500_acodec_enable_audio_mode(struct acodec_configuration + * acodec_config) +{ + struct i2s_device *i2s_dev = NULL; + t_ab8500_codec_error error_status = AB8500_CODEC_OK; + struct msp_config msp_config; + t_ab8500_codec_error codec_error; + t_ab8500_codec_mode codec_in_mode = AB8500_CODEC_MODE_MANUAL_SETTING; + t_ab8500_codec_mode codec_out_mode = AB8500_CODEC_MODE_MANUAL_SETTING; + t_ab8500_codec_direction codec_direction; +/*#ifdef CONFIG_U8500_AB8500_CUT10*/ +#if 1 + t_ab8500_codec_tdm_config tdm_config; +#endif + + memset(&msp_config, 0, sizeof(msp_config)); + + FUNC_ENTER(); + stm_dbg(DBG_ST.acodec, + " Entering in u8500_acodec_enable_audio_mode()\n"); + + if (i2sdrv[I2S_CLIENT_MSP1]->flag) { + stm_dbg(DBG_ST.acodec, " I2S controller not available\n"); + return -1; + } + + i2s_dev = i2sdrv[I2S_CLIENT_MSP1]->i2s; + + if (g_codec_system_context.cur_user == NO_USER) { + stm_error("Audiocodec not yet configured by any user\n"); + return (AB8500_CODEC_ERROR); + } else if (g_codec_system_context.cur_user != acodec_config->user) { + stm_error + (" Trying to acces audiocodec already in use by user %d\n", + g_codec_system_context.cur_user); + return (AB8500_CODEC_ERROR); + } + + switch (acodec_config->direction) { + case AB8500_CODEC_DIRECTION_INOUT: + codec_direction = AB8500_CODEC_DIRECTION_INOUT; + codec_in_mode = AB8500_CODEC_MODE_VOICE; //HIFI + codec_out_mode = AB8500_CODEC_MODE_VOICE; //VOICE + break; + case AB8500_CODEC_DIRECTION_IN: + codec_direction = AB8500_CODEC_DIRECTION_IN; + codec_in_mode = AB8500_CODEC_MODE_VOICE; //HIFI + break; + case AB8500_CODEC_DIRECTION_OUT: + codec_direction = AB8500_CODEC_DIRECTION_OUT; + codec_out_mode = AB8500_CODEC_MODE_VOICE; //HIFI + break; + default: + stm_error("Invalid direction\n"); + return AB8500_CODEC_ERROR; + } + + /* MSP configuration */ + + msp_config.tx_clock_sel = 0; //TX_CLK_SEL_SRG; + msp_config.rx_clock_sel = 0; //RX_CLK_SEL_SRG; + + msp_config.tx_frame_sync_sel = 0; //0x00000400; Frame synchronization signal is provided by an external source. MSPTFS is an input pin + msp_config.rx_frame_sync_sel = 0; //0: Rx Frame synchronization signal is provided by an external source. MSPRFS is an input pin + + msp_config.input_clock_freq = MSP_INPUT_FREQ_48MHZ; + + msp_config.srg_clock_sel = 0; //0x000C0000 + + //msp_config.rx_endianess = MSP_BIG_ENDIAN; + //msp_config.tx_endianess = MSP_BIG_ENDIAN; + + msp_config.rx_frame_sync_pol = RX_FIFO_SYNC_HI; + msp_config.tx_frame_sync_pol = TX_FIFO_SYNC_HI; + + //msp_config.rx_unexpect_frame_sync = MSP_UNEXPECTED_FS_IGNORE; + //msp_config.tx_unexpect_frame_sync = MSP_UNEXPECTED_FS_IGNORE; + + msp_config.rx_fifo_config = RX_FIFO_ENABLE; + msp_config.tx_fifo_config = TX_FIFO_ENABLE; + + msp_config.spi_clk_mode = SPI_CLK_MODE_NORMAL; + msp_config.spi_burst_mode = 0; + + msp_config.handler = acodec_config->handler; + msp_config.tx_callback_data = acodec_config->tx_callback_data; + msp_config.tx_data_enable = 0; + msp_config.rx_callback_data = acodec_config->rx_callback_data; + + msp_config.loopback_enable = 0; + msp_config.multichannel_configured = 0; + + msp_config.def_elem_len = 0; + //msp_config.loopback_enable = g_codec_system_context.msp_loopback; + + stm_dbg(DBG_ST.acodec, " msp_config.loopback_enable = 0x%x \n", + msp_config.loopback_enable); + +#if 0 + msp_config.default_protocol_desc = 1; +#else + msp_config.default_protocol_desc = 0; + msp_config.protocol_desc.rx_phase_mode = MSP_SINGLE_PHASE; + msp_config.protocol_desc.tx_phase_mode = MSP_SINGLE_PHASE; + msp_config.protocol_desc.rx_phase2_start_mode = + MSP_PHASE2_START_MODE_IMEDIATE; + msp_config.protocol_desc.tx_phase2_start_mode = + MSP_PHASE2_START_MODE_IMEDIATE; + msp_config.protocol_desc.rx_bit_transfer_format = MSP_BTF_MS_BIT_FIRST; + msp_config.protocol_desc.tx_bit_transfer_format = MSP_BTF_MS_BIT_FIRST; + msp_config.protocol_desc.rx_frame_length_1 = MSP_FRAME_LENGTH_1; + msp_config.protocol_desc.rx_frame_length_2 = MSP_FRAME_LENGTH_1; + msp_config.protocol_desc.tx_frame_length_1 = MSP_FRAME_LENGTH_1; + msp_config.protocol_desc.tx_frame_length_2 = MSP_FRAME_LENGTH_1; + msp_config.protocol_desc.rx_element_length_1 = MSP_ELEM_LENGTH_32; + msp_config.protocol_desc.rx_element_length_2 = MSP_ELEM_LENGTH_32; + msp_config.protocol_desc.tx_element_length_1 = MSP_ELEM_LENGTH_32; + msp_config.protocol_desc.tx_element_length_2 = MSP_ELEM_LENGTH_32; + msp_config.protocol_desc.rx_data_delay = MSP_DELAY_0; + msp_config.protocol_desc.tx_data_delay = MSP_DELAY_0; + msp_config.protocol_desc.rx_clock_pol = MSP_RISING_EDGE; + msp_config.protocol_desc.tx_clock_pol = MSP_FALLING_EDGE; + msp_config.protocol_desc.rx_frame_sync_pol = + MSP_FRAME_SYNC_POL_ACTIVE_HIGH; + msp_config.protocol_desc.tx_frame_sync_pol = + MSP_FRAME_SYNC_POL_ACTIVE_HIGH; + msp_config.protocol_desc.rx_half_word_swap = MSP_HWS_NO_SWAP; + msp_config.protocol_desc.tx_half_word_swap = MSP_HWS_NO_SWAP; + msp_config.protocol_desc.compression_mode = MSP_COMPRESS_MODE_LINEAR; + msp_config.protocol_desc.expansion_mode = MSP_EXPAND_MODE_LINEAR; + msp_config.protocol_desc.spi_clk_mode = MSP_SPI_CLOCK_MODE_NON_SPI; + msp_config.protocol_desc.spi_burst_mode = MSP_SPI_BURST_MODE_DISABLE; + msp_config.protocol_desc.frame_sync_ignore = MSP_FRAME_SYNC_IGNORE; + msp_config.protocol_desc.frame_period = 63; + msp_config.protocol_desc.frame_width = 31; + msp_config.protocol_desc.total_clocks_for_one_frame = 64; + +#endif + + msp_config.direction = MSP_BOTH_T_R_MODE; + msp_config.protocol = MSP_PCM_PROTOCOL; //MSP_I2S_PROTOCOL + msp_config.frame_size = ELEMENT_SIZE; + // msp_config.frame_freq = freq; $kardad$ + msp_config.frame_freq = CODEC_SAMPLING_FREQ_48KHZ; + + /* enable msp for both tr and rx mode with dma data transfer. THIS IS NOW DONE SEPARATELY from SAA. */ + + if (acodec_config->channels == 1) + msp_config.data_size = MSP_DATA_SIZE_16BIT; + else + msp_config.data_size = MSP_DATA_SIZE_32BIT; + +#ifdef CONFIG_U8500_ACODEC_DMA + msp_config.work_mode = MSP_DMA_MODE; +#elif defined(CONFIG_U8500_ACODEC_POLL) + msp_config.work_mode = MSP_POLLING_MODE; +#else + msp_config.work_mode = MSP_INTERRUPT_MODE; +#endif + + if (DISABLE == acodec_config->direct_rendering_mode) { + msp_config.multichannel_configured = 1; + msp_config.multichannel_config.tx_multichannel_enable = 1; + if (acodec_config->channels == 1) { + msp_config.multichannel_config.tx_channel_0_enable = + 0x0000001; + } else { + msp_config.multichannel_config.tx_channel_0_enable = + 0x0000003; + } + msp_config.multichannel_config.tx_channel_1_enable = 0x0000000; + msp_config.multichannel_config.tx_channel_2_enable = 0x0000000; + msp_config.multichannel_config.tx_channel_3_enable = 0x0000000; + + msp_config.multichannel_config.rx_multichannel_enable = 1; + + if (acodec_config->channels == 1) { + msp_config.multichannel_config.rx_channel_0_enable = + 0x0000001; + } else { + msp_config.multichannel_config.rx_channel_0_enable = + 0x0000003; + } + msp_config.multichannel_config.rx_channel_1_enable = 0x0000000; + msp_config.multichannel_config.rx_channel_2_enable = 0x0000000; + msp_config.multichannel_config.rx_channel_3_enable = 0x0000000; + + if (acodec_config->tdm8_ch_mode == ENABLE) { + msp_config.def_elem_len = 1; + + msp_config.protocol_desc.tx_element_length_1 = + MSP_ELEM_LENGTH_20; + msp_config.protocol_desc.tx_frame_length_1 = + MSP_FRAME_LENGTH_8; + msp_config.protocol_desc.tx_data_delay = MSP_DELAY_1; + + msp_config.protocol_desc.tx_element_length_2 = + MSP_ELEM_LENGTH_8; + msp_config.protocol_desc.tx_frame_length_2 = + MSP_FRAME_LENGTH_1; + + msp_config.protocol_desc.rx_element_length_1 = + MSP_ELEM_LENGTH_20; + msp_config.protocol_desc.rx_frame_length_1 = + MSP_FRAME_LENGTH_8; + msp_config.protocol_desc.rx_data_delay = MSP_DELAY_1; + + msp_config.protocol_desc.rx_element_length_2 = + MSP_ELEM_LENGTH_8; + msp_config.protocol_desc.rx_frame_length_2 = + MSP_FRAME_LENGTH_1; + + msp_config.protocol_desc.frame_sync_ignore = + MSP_FRAME_SYNC_UNIGNORE; + msp_config.protocol_desc.rx_clock_pol = MSP_RISING_EDGE; + + //if(acodec_config->digital_loopback == ENABLE) { + if (1) { + msp_config.multichannel_config. + tx_channel_0_enable = + (1 << NB_OF_CHANNEL_USED) - 1; + msp_config.multichannel_config. + rx_channel_0_enable = + (1 << NB_OF_CHANNEL_USED) - 1; + } else { + msp_config.multichannel_config. + tx_channel_0_enable = 0x3; + msp_config.multichannel_config. + rx_channel_0_enable = 0x3; + } + } + + if (acodec_config->tdm8_ch_mode == ENABLE) { + /* TFSDLY = 2 delay units */ + msp_config.iodelay = 0x20; + } + + error_status = i2s_setup(i2s_dev->controller, &msp_config); + if (error_status < 0) { + stm_error("error in msp enable, error_status is %d\n", + error_status); + return error_status; + } + } else if (ENABLE == acodec_config->direct_rendering_mode) { + writel(0x00, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x04))); //MSP_GCR + } + + if (ACODEC_CONFIG_REQUIRED == acodec_config->acodec_config_need) { + AB8500_CODEC_SelectInterface(AB8500_CODEC_AUDIO_INTERFACE_0); + + codec_error = AB8500_CODEC_PowerUp(); + if (AB8500_CODEC_OK != codec_error) { + stm_error("AB8500_CODEC_PowerUp failed\n"); + return AB8500_CODEC_ERROR; + } + +/*#ifdef CONFIG_U8500_AB8500_CUT10*/ +#if 1 + tdm_config.cr27_if1_bitclk_osr = + AB8500_CODEC_CR27_IF1_BITCLK_OSR_32; + tdm_config.cr27_if0_bitclk_osr = + AB8500_CODEC_CR27_IF0_BITCLK_OSR_32; + tdm_config.cr28_if0wl = AB8500_CODEC_CR28_IF0WL_16BITS; + tdm_config.cr30_if1wl = AB8500_CODEC_CR30_IF1WL_16BITS; + + switch (acodec_config->direction) { + case AB8500_CODEC_DIRECTION_INOUT: + tdm_config.cr28_bitclk0p = + AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE; + tdm_config.cr28_if0del = + AB8500_CODEC_CR28_IF0DEL_DELAYED; + break; + case AB8500_CODEC_DIRECTION_IN: + tdm_config.cr28_bitclk0p = + AB8500_CODEC_CR28_BITCLK0P_RISING_EDGE; + tdm_config.cr28_if0del = + AB8500_CODEC_CR28_IF0DEL_NOT_DELAYED; + break; + case AB8500_CODEC_DIRECTION_OUT: + tdm_config.cr28_bitclk0p = + AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE; + tdm_config.cr28_if0del = + AB8500_CODEC_CR28_IF0DEL_DELAYED; + break; + default: + stm_error("Invalid direction\n"); + return AB8500_CODEC_ERROR; + } + + if (acodec_config->tdm8_ch_mode == ENABLE) { + tdm_config.cr27_if0_bitclk_osr = + AB8500_CODEC_CR27_IF0_BITCLK_OSR_256; + tdm_config.cr28_if0wl = AB8500_CODEC_CR28_IF0WL_20BITS; + tdm_config.cr28_bitclk0p = + AB8500_CODEC_CR28_BITCLK0P_RISING_EDGE; + tdm_config.cr28_if0del = + AB8500_CODEC_CR28_IF0DEL_DELAYED; + codec_in_mode = AB8500_CODEC_MODE_VOICE; + codec_out_mode = AB8500_CODEC_MODE_VOICE; + acodec_config->direction = AB8500_CODEC_DIRECTION_INOUT; + } + + codec_error = + AB8500_CODEC_SetModeAndDirection(acodec_config->direction, + codec_in_mode, + codec_out_mode, + &tdm_config); +#else + codec_error = + AB8500_CODEC_SetModeAndDirection(acodec_config->direction, + codec_in_mode, + codec_out_mode); +#endif + if (AB8500_CODEC_OK != codec_error) { + stm_error("set mode and direction failed\n"); + return AB8500_CODEC_ERROR; + } + + codec_error = + AB8500_CODEC_SetMasterMode(AB8500_CODEC_MASTER_MODE_ENABLE); + + if (AB8500_CODEC_OK != codec_error) { + stm_error("set mode and direction failed\n"); + return AB8500_CODEC_ERROR; + } + + /*codec_error = trg_codec_set_sample_frequency(0); */ + + /*u8500_acodec_set_volume(g_codec_system_context.in_left_volume, + g_codec_system_context.in_right_volume, + g_codec_system_context.out_left_volume, + g_codec_system_context.out_right_volume, + user); */ +#if 0 + if (AB8500_CODEC_DIRECTION_IN == acodec_config->direction + || AB8500_CODEC_DIRECTION_INOUT == + acodec_config->direction) { + + u8500_acodec_allocate_ad_slot + (AB8500_CODEC_SRC_D_MICROPHONE_1, TDM_8_CH_MODE); + u8500_acodec_allocate_ad_slot + (AB8500_CODEC_SRC_D_MICROPHONE_2, TDM_8_CH_MODE); + + /*codec_error = AB8500_CODEC_ADSlotAllocation (AB8500_CODEC_SLOT0, + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT3); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_adslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } + codec_error = AB8500_CODEC_ADSlotAllocation (AB8500_CODEC_SLOT1, + AB8500_CODEC_CR31_TO_CR46_SLOT_IS_TRISTATE); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_adslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } */ + + } + + if (AB8500_CODEC_DIRECTION_OUT == acodec_config->direction + || AB8500_CODEC_DIRECTION_INOUT == + acodec_config->direction) { + u8500_acodec_allocate_da_slot(AB8500_CODEC_DEST_HEADSET, + TDM_8_CH_MODE); + /*codec_error = AB8500_CODEC_DASlotAllocation (AB8500_CODEC_DA_CHANNEL_NUMBER_1, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT08); + if (AB8500_CODEC_OK != codec_error) { + stm_error + ("ab8500_codec_daslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } + codec_error = AB8500_CODEC_DASlotAllocation (AB8500_CODEC_DA_CHANNEL_NUMBER_2, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT09); + if (AB8500_CODEC_OK != codec_error) { + stm_error + ("ab8500_codec_daslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } */ + + } +#endif + + } //END of if acodec_config_need + +/*#if DRIVER_DEBUG > 0 + { + dump_msp_registers(); + dump_acodec_registers(); + } +#endif*/ + + stm_dbg(DBG_ST.acodec, + "leaving in u8500_acodec_enable_audio_mode() \n"); + + FUNC_EXIT(); + return AB8500_CODEC_OK; +} + +/** +* u8500_acodec_set_output_volume - configures the volume level for both speakers +* @in_left_volume - volume for left channel of mic +* @in_right_volume - volume for right channel of mic +* @out_left_volume - volume for left speaker +* @out_right_volume - volume for right speaker +*/ +t_ab8500_codec_error u8500_acodec_set_output_volume(t_ab8500_codec_dest + dest_device, + int left_volume, + int right_volume, + t_acodec_user user) +{ + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + stm_dbg(DBG_ST.acodec, + " Entering in u8500_acodec_set_output_volume()\n"); + + FUNC_ENTER(); + + user = user; //keep compiler happy + + g_codec_system_context.output_config[dest_device].left_volume = + left_volume; + g_codec_system_context.output_config[dest_device].right_volume = + right_volume; + + AB8500_CODEC_SetDestVolume(dest_device, left_volume, right_volume); + + FUNC_EXIT(); + return codec_error; +} + +/*u8500_acodec_get_output_volume*/ + +t_ab8500_codec_error u8500_acodec_get_output_volume(t_ab8500_codec_dest + dest_device, + int *p_left_volume, + int *p_right_volume, + t_acodec_user user) +{ + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + stm_dbg(DBG_ST.acodec, + " Entering in u8500_acodec_set_output_volume()\n"); + + user = user; //keep compiler happy + + *p_left_volume = + g_codec_system_context.output_config[dest_device].left_volume; + *p_right_volume = + g_codec_system_context.output_config[dest_device].right_volume; + + return codec_error; +} + +/** +* u8500_acodec_set_input_volume - configures the volume level for both speakers +* @in_left_volume - volume for left channel of mic +* @in_right_volume - volume for right channel of mic +* @out_left_volume - volume for left speaker +* @out_right_volume - volume for right speaker +*/ +t_ab8500_codec_error u8500_acodec_set_input_volume(t_ab8500_codec_src + src_device, int left_volume, + int right_volume, + t_acodec_user user) +{ + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + stm_dbg(DBG_ST.acodec, + " Entering in u8500_acodec_set_input_volume()\n"); + + user = user; //keep compiler happy + + g_codec_system_context.input_config[src_device].left_volume = + left_volume; + g_codec_system_context.input_config[src_device].right_volume = + right_volume; + + AB8500_CODEC_SetSrcVolume(src_device, left_volume, right_volume); + + return codec_error; +} + +/** +* u8500_acodec_get_input_volume - configures the volume level for both speakers +* @in_left_volume - volume for left channel of mic +* @in_right_volume - volume for right channel of mic +* @out_left_volume - volume for left speaker +* @out_right_volume - volume for right speaker +*/ +t_ab8500_codec_error u8500_acodec_get_input_volume(t_ab8500_codec_src + src_device, + int *p_left_volume, + int *p_right_volume, + t_acodec_user user) +{ + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + stm_dbg(DBG_ST.acodec, + " Entering in u8500_acodec_get_input_volume()\n"); + + user = user; //keep compiler happy + + *p_left_volume = + g_codec_system_context.input_config[src_device].left_volume; + *p_right_volume = + g_codec_system_context.input_config[src_device].right_volume; + + return codec_error; +} + +/** +* u8500_acodec_toggle_playback_mute_control - configures the mute for both speakers +* @in_left_volume - volume for left channel of mic +* @in_right_volume - volume for right channel of mic +* @out_left_volume - volume for left speaker +* @out_right_volume - volume for right speaker +*/ +t_ab8500_codec_error +u8500_acodec_toggle_playback_mute_control(t_ab8500_codec_dest dest_device, + t_u8500_bool_state mute_state, + t_acodec_user user) +{ + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + stm_dbg(DBG_ST.acodec, + " Entering in u8500_acodec_toggle_playback_mute_control \n"); + + user = user; //keep compiler happy + + g_codec_system_context.output_config[dest_device].mute_state = + mute_state; + + if (ENABLE == mute_state) { + AB8500_CODEC_DestPowerControl(dest_device, + AB8500_CODEC_SRC_STATE_ENABLE); + } else { + AB8500_CODEC_DestPowerControl(dest_device, + AB8500_CODEC_SRC_STATE_DISABLE); + } + + return codec_error; +} + +/** +* u8500_acodec_toggle_capture_mute_control - configures the mute for both speakers +* @in_left_volume - volume for left channel of mic +* @in_right_volume - volume for right channel of mic +* @out_left_volume - volume for left speaker +* @out_right_volume - volume for right speaker +*/ +t_ab8500_codec_error u8500_acodec_toggle_capture_mute_control(t_ab8500_codec_src + src_device, + t_u8500_bool_state + mute_state, + t_acodec_user + user) +{ + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + stm_dbg(DBG_ST.acodec, + " Entering in u8500_acodec_toggle_capture_mute_control \n"); + + user = user; //keep compiler happy + + g_codec_system_context.input_config[src_device].mute_state = mute_state; + + if (ENABLE == mute_state) { + AB8500_CODEC_SrcPowerControl(src_device, + AB8500_CODEC_SRC_STATE_ENABLE); + } else { + AB8500_CODEC_SrcPowerControl(src_device, + AB8500_CODEC_SRC_STATE_DISABLE); + } + + return codec_error; +} + +/** +* u8500_acodec_select_input +* @input_device: MIC or linein. +* +* This routine selects the input device mic or linein. +*/ + +t_ab8500_codec_error u8500_acodec_select_input(t_ab8500_codec_src + input_device, + t_acodec_user user, + t_u8500_mode mode) +{ + + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + stm_dbg(DBG_ST.acodec, " Entering u8500_acodec_select_input\n"); + + if (TDM_8_CH_MODE == mode) + u8500_acodec_allocate_ad_slot(input_device, TDM_8_CH_MODE); + else + u8500_acodec_allocate_ad_slot(input_device, CLASSICAL_MODE); + + codec_error = AB8500_CODEC_SelectInput(input_device); + + stm_dbg(DBG_ST.acodec, " leaving u8500_acodec_select_input\n"); + return codec_error; +} + +/** +* u8500_acodec_select_output +* @output_device: output device HP/LSP +* +* This routine selects the output device Headphone or loud speaker +*/ + +t_ab8500_codec_error u8500_acodec_select_output(t_ab8500_codec_dest + output_device, + t_acodec_user user, + t_u8500_mode mode) +{ + + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + FUNC_ENTER(); + stm_dbg(DBG_ST.acodec, " Entering u8500_acodec_select_output()\n"); + + if (TDM_8_CH_MODE == mode) + u8500_acodec_allocate_da_slot(output_device, TDM_8_CH_MODE); + else + u8500_acodec_allocate_da_slot(output_device, CLASSICAL_MODE); + + codec_error = AB8500_CODEC_SelectOutput(output_device); + + stm_dbg(DBG_ST.acodec, " leaving u8500_acodec_select_output()\n"); + FUNC_EXIT(); + return codec_error; +} + +t_ab8500_codec_error u8500_acodec_allocate_ad_slot(t_ab8500_codec_src + input_device, + t_u8500_mode mode) +{ + t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line1, + ad_data_line2; + t_ab8500_codec_slot slot1, slot2; + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + slot1 = AB8500_CODEC_SLOT_UNDEFINED; + slot2 = AB8500_CODEC_SLOT_UNDEFINED; + + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_UNDEFINED; + ad_data_line2 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_UNDEFINED; + + switch (input_device) { + case AB8500_CODEC_SRC_D_MICROPHONE_1: + { + slot1 = AB8500_CODEC_SLOT0; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT1; + } + break; + case AB8500_CODEC_SRC_MICROPHONE_2: + case AB8500_CODEC_SRC_D_MICROPHONE_2: + { + slot1 = AB8500_CODEC_SLOT1; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT2; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_3: + case AB8500_CODEC_SRC_MICROPHONE_1A: + case AB8500_CODEC_SRC_MICROPHONE_1B: + { + slot1 = AB8500_CODEC_SLOT2; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT3; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_4: + { + slot1 = AB8500_CODEC_SLOT3; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT4; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_5: + { + slot1 = AB8500_CODEC_SLOT4; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT5; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_6: + { + slot1 = AB8500_CODEC_SLOT5; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT6; + } + break; + case AB8500_CODEC_SRC_LINEIN: + { + slot1 = AB8500_CODEC_SLOT0; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT1; + + slot2 = AB8500_CODEC_SLOT1; + ad_data_line2 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT2; + } + case AB8500_CODEC_SRC_FM_RX: + { + slot1 = AB8500_CODEC_SLOT6; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT7; + + slot2 = AB8500_CODEC_SLOT7; + ad_data_line2 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT8; + } + break; + case AB8500_CODEC_SRC_ALL: + break; + } + + if ((AB8500_CODEC_SLOT_UNDEFINED != slot1) + && (AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_UNDEFINED != + ad_data_line1)) { + if (CLASSICAL_MODE == mode) { + slot1 = AB8500_CODEC_SLOT0; + } + codec_error = + AB8500_CODEC_ADSlotAllocation(slot1, ad_data_line1); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_adslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } + } + + if ((AB8500_CODEC_SLOT_UNDEFINED != slot2) + && (AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_UNDEFINED != + ad_data_line2)) { + if (CLASSICAL_MODE == mode) { + slot2 = AB8500_CODEC_SLOT1; + } + codec_error = + AB8500_CODEC_ADSlotAllocation(slot2, ad_data_line2); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_adslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } + } + + return AB8500_CODEC_OK; +} + +t_ab8500_codec_error u8500_acodec_unallocate_ad_slot(t_ab8500_codec_src + input_device, + t_u8500_mode mode) +{ + t_ab8500_codec_slot slot1, slot2; + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + slot1 = AB8500_CODEC_SLOT_UNDEFINED; + slot2 = AB8500_CODEC_SLOT_UNDEFINED; + + switch (input_device) { + case AB8500_CODEC_SRC_D_MICROPHONE_1: + { + slot1 = AB8500_CODEC_SLOT0; + } + break; + case AB8500_CODEC_SRC_MICROPHONE_2: + case AB8500_CODEC_SRC_D_MICROPHONE_2: + { + slot1 = AB8500_CODEC_SLOT1; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_3: + case AB8500_CODEC_SRC_MICROPHONE_1A: + case AB8500_CODEC_SRC_MICROPHONE_1B: + { + slot1 = AB8500_CODEC_SLOT2; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_4: + { + slot1 = AB8500_CODEC_SLOT3; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_5: + { + slot1 = AB8500_CODEC_SLOT4; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_6: + { + slot1 = AB8500_CODEC_SLOT5; + } + break; + case AB8500_CODEC_SRC_LINEIN: + { + slot1 = AB8500_CODEC_SLOT0; + slot2 = AB8500_CODEC_SLOT1; + } + break; + case AB8500_CODEC_SRC_ALL: + break; + } + + if (AB8500_CODEC_SLOT_UNDEFINED != slot1) { + if (CLASSICAL_MODE == mode) { + slot1 = AB8500_CODEC_SLOT0; + } + codec_error = + AB8500_CODEC_ADSlotAllocation(slot1, + AB8500_CODEC_CR31_TO_CR46_SLOT_IS_TRISTATE); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_adslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } + } + + if (AB8500_CODEC_SLOT_UNDEFINED != slot2) { + if (CLASSICAL_MODE == mode) { + slot2 = AB8500_CODEC_SLOT1; + } + codec_error = + AB8500_CODEC_ADSlotAllocation(slot2, + AB8500_CODEC_CR31_TO_CR46_SLOT_IS_TRISTATE); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_adslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } + } + + return AB8500_CODEC_OK; +} + +#ifdef CONFIG_U8500_AB8500_CUT10 +t_ab8500_codec_error u8500_acodec_allocate_da_slot(t_ab8500_codec_dest + output_device, + t_u8500_mode mode) +{ + t_ab8500_codec_da_channel_number da_ch_no1, da_ch_no2; + t_ab8500_codec_cr51_to_cr58_sltoda da_slot1, da_slot2; + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED; + da_ch_no2 = AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED; + + da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT_UNDEFINED; + da_slot2 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT_UNDEFINED; + + switch (output_device) { + case AB8500_CODEC_DEST_HEADSET: + { + da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_1; + da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT08; + + da_ch_no2 = AB8500_CODEC_DA_CHANNEL_NUMBER_2; + da_slot2 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT09; + } + break; + case AB8500_CODEC_DEST_EARPIECE: + { + da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_1; + da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT08; + } + break; + case AB8500_CODEC_DEST_HANDSFREE: + { + da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_3; + da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT10; + + da_ch_no2 = AB8500_CODEC_DA_CHANNEL_NUMBER_4; + da_slot2 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT11; + } + break; + case AB8500_CODEC_DEST_VIBRATOR_L: + { + da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_5; + da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT12; + } + break; + case AB8500_CODEC_DEST_VIBRATOR_R: + { + da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_6; + da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT13; + } + break; + + case AB8500_CODEC_DEST_FM_TX: + { + da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_7; + da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT14; + + da_ch_no2 = AB8500_CODEC_DA_CHANNEL_NUMBER_8; + da_slot2 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT15; + } + + case AB8500_CODEC_DEST_ALL: + break; + } + + if ((AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED != da_ch_no1) + && (AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT_UNDEFINED != da_slot1)) { + if (CLASSICAL_MODE == mode) { + da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT08; + } + codec_error = + AB8500_CODEC_DASlotAllocation(da_ch_no1, da_slot1); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_daslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } + } + + if ((AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED != da_ch_no2) + && (AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT_UNDEFINED != da_slot2)) { + if (CLASSICAL_MODE == mode) { + da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT09; + } + codec_error = + AB8500_CODEC_DASlotAllocation(da_ch_no2, da_slot2); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_daslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } + } + + return AB8500_CODEC_OK; +} + +#else +t_ab8500_codec_error u8500_acodec_allocate_da_slot(t_ab8500_codec_dest + output_device, + t_u8500_mode mode) +{ + t_ab8500_codec_da_channel_number da_ch_no1, da_ch_no2; + t_ab8500_codec_cr51_to_cr56_sltoda da_slot1, da_slot2; + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED; + da_ch_no2 = AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED; + + da_slot1 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT_UNDEFINED; + da_slot2 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT_UNDEFINED; + + switch (output_device) { + case AB8500_CODEC_DEST_HEADSET: + { + da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_1; + da_slot1 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT08; + + da_ch_no2 = AB8500_CODEC_DA_CHANNEL_NUMBER_2; + da_slot2 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT09; + } + break; + case AB8500_CODEC_DEST_EARPIECE: + { + da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_1; + da_slot1 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT08; + } + break; + case AB8500_CODEC_DEST_HANDSFREE: + { + da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_3; + da_slot1 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT10; + + da_ch_no2 = AB8500_CODEC_DA_CHANNEL_NUMBER_4; + da_slot2 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT11; + } + break; + case AB8500_CODEC_DEST_VIBRATOR_L: + { + da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_5; + da_slot1 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT12; + } + break; + case AB8500_CODEC_DEST_VIBRATOR_R: + { + da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_6; + da_slot1 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT13; + } + break; + + case AB8500_CODEC_DEST_ALL: + break; + } + + if ((AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED != da_ch_no1) + && (AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT_UNDEFINED != da_slot1)) { + if (CLASSICAL_MODE == mode) { + da_slot1 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT08; + } + codec_error = + AB8500_CODEC_DASlotAllocation(da_ch_no1, da_slot1); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_daslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } + } + + if ((AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED != da_ch_no2) + && (AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT_UNDEFINED != da_slot2)) { + if (CLASSICAL_MODE == mode) { + da_slot1 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT09; + } + codec_error = + AB8500_CODEC_DASlotAllocation(da_ch_no2, da_slot2); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_daslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } + } + + return AB8500_CODEC_OK; +} +#endif + +t_ab8500_codec_error u8500_acodec_unallocate_da_slot(t_ab8500_codec_dest + output_device, + t_u8500_mode mode) +{ + return AB8500_CODEC_OK; +} + +t_ab8500_codec_error u8500_acodec_set_src_power_cntrl(t_ab8500_codec_src + input_device, + t_u8500_bool_state + pwr_state) +{ + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + if (ENABLE == pwr_state) { + u8500_acodec_allocate_ad_slot(input_device, TDM_8_CH_MODE); + codec_error = + AB8500_CODEC_SrcPowerControl(input_device, + AB8500_CODEC_SRC_STATE_ENABLE); + if (AB8500_CODEC_OK != codec_error) { + stm_error("AB8500_CODEC_SrcPowerControl failed\n"); + return AB8500_CODEC_ERROR; + } + g_codec_system_context.input_config[input_device].power_state = + ENABLE; + } else { + u8500_acodec_unallocate_ad_slot(input_device, TDM_8_CH_MODE); + codec_error = + AB8500_CODEC_SrcPowerControl(input_device, + AB8500_CODEC_SRC_STATE_DISABLE); + if (AB8500_CODEC_OK != codec_error) { + stm_error("AB8500_CODEC_SrcPowerControl failed\n"); + return AB8500_CODEC_ERROR; + } + g_codec_system_context.input_config[input_device].power_state = + DISABLE; + } + + return AB8500_CODEC_OK; +} + +t_u8500_bool_state u8500_acodec_get_src_power_state(t_ab8500_codec_src + input_device) +{ + return (g_codec_system_context.input_config[input_device].power_state); +} + +t_ab8500_codec_error u8500_acodec_set_dest_power_cntrl(t_ab8500_codec_dest + output_device, + t_u8500_bool_state + pwr_state) +{ + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + if (ENABLE == pwr_state) { + AB8500_CODEC_SelectInterface(AB8500_CODEC_AUDIO_INTERFACE_0); + + codec_error = AB8500_CODEC_PowerUp(); + if (AB8500_CODEC_OK != codec_error) { + stm_error("AB8500_CODEC_PowerUp failed\n"); + return AB8500_CODEC_ERROR; + } + + u8500_acodec_allocate_da_slot(output_device, TDM_8_CH_MODE); + + codec_error = + AB8500_CODEC_DestPowerControl(output_device, + AB8500_CODEC_DEST_STATE_ENABLE); + if (AB8500_CODEC_OK != codec_error) { + stm_error("AB8500_CODEC_DestPowerControl failed\n"); + return AB8500_CODEC_ERROR; + } + g_codec_system_context.output_config[output_device]. + power_state = ENABLE; + } else { + u8500_acodec_unallocate_da_slot(output_device, TDM_8_CH_MODE); + codec_error = + AB8500_CODEC_DestPowerControl(output_device, + AB8500_CODEC_DEST_STATE_DISABLE); + if (AB8500_CODEC_OK != codec_error) { + stm_error("AB8500_CODEC_DestPowerControl failed\n"); + return AB8500_CODEC_ERROR; + } + g_codec_system_context.output_config[output_device]. + power_state = DISABLE; + } + + return AB8500_CODEC_OK; +} + +t_u8500_bool_state u8500_acodec_get_dest_power_state(t_ab8500_codec_dest + output_device) +{ + return (g_codec_system_context.output_config[output_device]. + power_state); +} + +/** +* u8500_acodec_toggle_analog_lpbk +* @output_device: output device HP/LSP +* +* This routine selects the output device Headphone or loud speaker +*/ +t_ab8500_codec_error u8500_acodec_toggle_analog_lpbk(t_u8500_bool_state + lpbk_state, + t_acodec_user user) +{ + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + stm_dbg(DBG_ST.acodec, + " Entering inu8500_acodec_toggle_analog_lpbk() \n"); + + user = user; //keep compiler happy + + if (ENABLE == lpbk_state) { + /* Reset CODEC */ + codec_error = AB8500_CODEC_Reset(); + + AB8500_CODEC_SelectInterface(AB8500_CODEC_AUDIO_INTERFACE_0); + + codec_error = AB8500_CODEC_PowerUp(); + if (AB8500_CODEC_OK != codec_error) { + stm_error("AB8500_CODEC_PowerUp failed\n"); + return AB8500_CODEC_ERROR; + } + + codec_error = AB8500_CODEC_SelectInput(AB8500_CODEC_SRC_LINEIN); + + codec_error = + AB8500_CODEC_SrcPowerControl(AB8500_CODEC_SRC_LINEIN, + AB8500_CODEC_SRC_STATE_ENABLE); + + //codec_error = AB8500_CODEC_SetSrcVolume(AB8500_CODEC_SRC_LINEIN,VOL_MAX,VOL_MAX); + + codec_error = + AB8500_CODEC_SelectOutput(AB8500_CODEC_DEST_HEADSET); + + codec_error = + AB8500_CODEC_DestPowerControl(AB8500_CODEC_DEST_HEADSET, + AB8500_CODEC_DEST_STATE_ENABLE); + + //codec_error = AB8500_CODEC_SetDestVolume(AB8500_CODEC_DEST_HEADSET,0,0); + + codec_error = AB8500_CODEC_SetAnalogLoopback(VOL_MAX, VOL_MAX); + + ab8500_write(AB8500_AUDIO, 0xd05, 0x30); + ab8500_write(AB8500_AUDIO, 0xd07, 0xf3); + ab8500_write(AB8500_AUDIO, 0xd16, 0xdd); + ab8500_write(AB8500_AUDIO, 0xd17, 0x55); + ab8500_write(AB8500_AUDIO, 0xd3f, 0xc0); + + } else { + codec_error = AB8500_CODEC_RemoveAnalogLoopback(); + } + +#if DRIVER_DEBUG > 0 + { + dump_acodec_registers(); + } +#endif + + return codec_error; +} + +#ifdef CONFIG_U8500_ACODEC_POLL + +static int digital_lpbk_msp_rx_tx_thread(void *data) +{ + t_digital_lpbk_cnxt *p_cnxt = (t_digital_lpbk_cnxt *) data; + unsigned int sample[8], count = 32; + + daemonize("digital_lpbk_msp_rx_tx_thread"); + allow_signal(SIGKILL); + + printk("\n Rx-Tx : digital_lpbk_msp_rx_tx_thread started \n"); + + while ((!signal_pending(current)) && (p_cnxt->rx_active)) { + +// ret_val = u8500_msp_receive_data(alsa_msp_adev,p_cnxt->buffer[p_cnxt->rx_index],p_cnxt->data_size); + + //u8500_msp_transceive_data(alsa_msp_adev,p_cnxt->buffer[0], p_cnxt->data_size,p_cnxt->buffer[1], p_cnxt->data_size); + + //u8500_msp_transceive_data(alsa_msp_adev,p_cnxt->buffer[1], p_cnxt->data_size,p_cnxt->buffer[0], p_cnxt->data_size); + +#if DRIVER_DEBUG > 1 + stm_dbg(DBG_ST.alsa, " Receiving \n"); +#endif + u8500_acodec_receive_data(I2S_CLIENT_MSP1, (void *)sample, + count, 0); + +#if DRIVER_DEBUG > 1 + stm_dbg(DBG_ST.alsa, " Transmitting \n"); +#endif + u8500_acodec_send_data(I2S_CLIENT_MSP1, (void *)sample, count, + 0); + + } + printk("\n Rx-Tx : digital_lpbk_msp_rx_tx_thread ended \n"); + return 0; +} + +#endif + +#ifdef CONFIG_U8500_ACODEC_DMA + +static void u8500_digital_lpbk_dma_start() +{ + u8500_acodec_loopback_configure(I2S_CLIENT_MSP1, + (void *)digital_lpbk_cnxt.buffer.addr, + digital_lpbk_cnxt.data_size, 1); + + stm_dbg(DBG_ST.alsa, " Rx DMA Transfer started\n"); + stm_dbg(DBG_ST.alsa, " Rx : add = %x size=%d\n", + (int)(digital_lpbk_cnxt.buffer.addr), + digital_lpbk_cnxt.data_size); + +} +#endif + +/** +* u8500_acodec_toggle_digital_lpbk +* @output_device: output device HP/LSP +* +* This routine selects the output device Headphone or loud speaker +*/ + +t_ab8500_codec_error u8500_acodec_toggle_digital_lpbk(t_u8500_bool_state + lpbk_state, + t_ab8500_codec_dest + dest_device, + t_ab8500_codec_src + src_device, + t_acodec_user user, + t_u8500_bool_state + tdm8_ch_mode) +{ + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + struct acodec_configuration acodec_config; + int status = 0; + + stm_dbg(DBG_ST.acodec, + " Entering u8500_acodec_toggle_digital_lpbk() \n"); + + user = user; //keep compiler happy + + if (ENABLE == lpbk_state) { + //data_size = 1024*100; + + //data[0] = (unsigned char *)kmalloc(data_size, GFP_KERNEL); + + codec_error = AB8500_CODEC_Reset(); + + //AB8500_CODEC_SelectInterface(AB8500_CODEC_AUDIO_INTERFACE_0); + + //codec_error = AB8500_CODEC_PowerUp(); + if (AB8500_CODEC_OK != codec_error) { + stm_error("AB8500_CODEC_PowerUp failed\n"); + return AB8500_CODEC_ERROR; + } + + status = u8500_acodec_open(I2S_CLIENT_MSP1, 0); + if (status) { + printk("failed in getting acodec playback open\n"); + return -1; + } + status = u8500_acodec_open(I2S_CLIENT_MSP1, 1); + if (status) { + printk("failed in getting acdoec capture open\n"); + return -1; + } + + u8500_acodec_setuser(USER_ALSA); + + if (ENABLE == tdm8_ch_mode) { + printk("\n 20 bit 8 ch Digital Loopback"); + printk("\n DMIC1 -> HS-L"); + printk("\n DMIC2 -> HS-R"); + printk("\n DMIC3 -> IHF-L"); + printk("\n DMIC5 -> Vibra-L\n"); + printk("\n DMIC6 -> Vibra-R\n"); + printk("\n FM -> FM Tx\n"); + } else { + printk("\n 16 bit 2 ch Digital Loopback"); + printk("\n DMIC1 -> HS-L"); + printk("\n DMIC2 -> HS-R"); + } + + stm_dbg(DBG_ST.alsa, "enabling audiocodec audio mode\n"); + acodec_config.direction = AB8500_CODEC_DIRECTION_INOUT; + acodec_config.input_frequency = T_CODEC_SAMPLING_FREQ_48KHZ; + acodec_config.output_frequency = T_CODEC_SAMPLING_FREQ_48KHZ; + acodec_config.mspClockSel = CODEC_MSP_APB_CLOCK; + acodec_config.mspInClockFreq = CODEC_MSP_INPUT_FREQ_48MHZ; + acodec_config.channels = 2; + acodec_config.user = 2; + acodec_config.acodec_config_need = ACODEC_CONFIG_REQUIRED; + acodec_config.direct_rendering_mode = DISABLE; + acodec_config.tdm8_ch_mode = tdm8_ch_mode; + acodec_config.digital_loopback = ENABLE; +#ifdef CONFIG_U8500_ACODEC_POLL + acodec_config.handler = NULL; + acodec_config.tx_callback_data = NULL; + acodec_config.rx_callback_data = NULL; +#endif + u8500_acodec_enable_audio_mode(&acodec_config); + + /*turn on src devices */ + + perform_src_routing(src_device); + +/* u8500_acodec_set_src_power_cntrl(src_device,ENABLE); + u8500_acodec_set_input_volume(src_device,50,50,USER_ALSA); + + u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_D_MICROPHONE_2,ENABLE); + u8500_acodec_set_input_volume(AB8500_CODEC_SRC_D_MICROPHONE_2,50,50,USER_ALSA); + + u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_D_MICROPHONE_3,ENABLE); + u8500_acodec_set_input_volume(AB8500_CODEC_SRC_D_MICROPHONE_3,50,50,USER_ALSA); + + u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_D_MICROPHONE_4,ENABLE); + u8500_acodec_set_input_volume(AB8500_CODEC_SRC_D_MICROPHONE_4,50,50,USER_ALSA); + + u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_D_MICROPHONE_5,ENABLE); + u8500_acodec_set_input_volume(AB8500_CODEC_SRC_D_MICROPHONE_5,50,50,USER_ALSA); + + u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_D_MICROPHONE_6,ENABLE); + u8500_acodec_set_input_volume(AB8500_CODEC_SRC_D_MICROPHONE_6,50,50,USER_ALSA); + + u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_D_MICROPHONE_6,ENABLE); + u8500_acodec_set_input_volume(AB8500_CODEC_SRC_D_MICROPHONE_6,50,50,USER_ALSA); + + u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_FM_RX,ENABLE); */ + + /*turn on dest devices */ + + //u8500_acodec_set_dest_power_cntrl(dest_device,ENABLE); + u8500_acodec_allocate_da_slot(dest_device, TDM_8_CH_MODE); + codec_error = AB8500_CODEC_SelectOutput(dest_device); + u8500_acodec_set_output_volume(dest_device, 100, 100, + USER_ALSA); + + /*u8500_acodec_set_dest_power_cntrl(AB8500_CODEC_DEST_HEADSET,ENABLE); + u8500_acodec_set_output_volume(AB8500_CODEC_DEST_HEADSET,100,100,USER_ALSA); */ + + /*u8500_acodec_set_dest_power_cntrl(AB8500_CODEC_DEST_HANDSFREE,ENABLE); + u8500_acodec_set_output_volume(AB8500_CODEC_DEST_HANDSFREE,100,100,USER_ALSA); */ + +#ifdef CONFIG_U8500_AB8500_CUT10 + codec_error = + AB8500_CODEC_DASlotAllocation + (AB8500_CODEC_DA_CHANNEL_NUMBER_5, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT12); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_daslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } + + codec_error = + AB8500_CODEC_DASlotAllocation + (AB8500_CODEC_DA_CHANNEL_NUMBER_6, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT13); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_daslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } + + codec_error = + AB8500_CODEC_DASlotAllocation + (AB8500_CODEC_DA_CHANNEL_NUMBER_7, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT14); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_daslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } + + codec_error = + AB8500_CODEC_DASlotAllocation + (AB8500_CODEC_DA_CHANNEL_NUMBER_8, + AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT15); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_daslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } +#else + codec_error = + AB8500_CODEC_DASlotAllocation + (AB8500_CODEC_DA_CHANNEL_NUMBER_5, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT12); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_daslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } + + codec_error = + AB8500_CODEC_DASlotAllocation + (AB8500_CODEC_DA_CHANNEL_NUMBER_6, + AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT13); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_daslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } +#endif + + digital_lpbk_cnxt.data_size = 2048; + + digital_lpbk_cnxt.rx_active = 1; + digital_lpbk_cnxt.tx_active = 1; + + digital_lpbk_cnxt.rx_index = 0; + digital_lpbk_cnxt.tx_index = 2; + + digital_lpbk_cnxt.buffer.area = + dma_alloc_coherent(NULL, digital_lpbk_cnxt.data_size, + &digital_lpbk_cnxt.buffer.addr, + GFP_KERNEL); + if (NULL == digital_lpbk_cnxt.buffer.area) { + printk("\n dma_alloc_coherent failed \n"); + } +#if DRIVER_DEBUG > 0 + { + dump_msp_registers(); + dump_acodec_registers(); + } +#endif + +#ifdef CONFIG_U8500_ACODEC_POLL + { + pid_t pid_rx_tx; + pid_rx_tx = + kernel_thread(digital_lpbk_msp_rx_tx_thread, + &digital_lpbk_cnxt, + CLONE_FS | CLONE_SIGHAND); + } +#elif defined(CONFIG_U8500_ACODEC_DMA) + { + u8500_digital_lpbk_dma_start(); + } +#endif + } else //lpbk is disable + { + + digital_lpbk_cnxt.rx_active = 0; + digital_lpbk_cnxt.tx_active = 0; + + dma_free_coherent(NULL, digital_lpbk_cnxt.data_size, + digital_lpbk_cnxt.buffer.area, + digital_lpbk_cnxt.buffer.addr); + + u8500_acodec_set_src_power_cntrl + (AB8500_CODEC_SRC_D_MICROPHONE_1, DISABLE); + u8500_acodec_set_src_power_cntrl + (AB8500_CODEC_SRC_D_MICROPHONE_2, DISABLE); + u8500_acodec_set_src_power_cntrl + (AB8500_CODEC_SRC_D_MICROPHONE_3, DISABLE); + u8500_acodec_set_src_power_cntrl + (AB8500_CODEC_SRC_D_MICROPHONE_4, DISABLE); + + u8500_acodec_set_dest_power_cntrl(AB8500_CODEC_DEST_HEADSET, + DISABLE); + u8500_acodec_set_dest_power_cntrl(AB8500_CODEC_DEST_HANDSFREE, + DISABLE); + + u8500_acodec_unsetuser(USER_ALSA); + u8500_acodec_close(I2S_CLIENT_MSP1, ACODEC_DISABLE_ALL); + } + return codec_error; +} + +t_ab8500_codec_error perform_src_routing(t_ab8500_codec_src input_device) +{ + int src_type = 0; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line1; + t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line2; + t_ab8500_codec_src input_device1; + t_ab8500_codec_src input_device2; + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + switch (input_device) { + case AB8500_CODEC_SRC_D_MICROPHONE_1: + { + src_type = MONO_SRC; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT1; + } + break; + case AB8500_CODEC_SRC_MICROPHONE_2: + case AB8500_CODEC_SRC_D_MICROPHONE_2: + { + src_type = MONO_SRC; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT2; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_3: + case AB8500_CODEC_SRC_MICROPHONE_1A: + case AB8500_CODEC_SRC_MICROPHONE_1B: + { + src_type = MONO_SRC; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT3; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_4: + { + src_type = MONO_SRC; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT4; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_5: + { + src_type = MONO_SRC; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT5; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_6: + { + src_type = MONO_SRC; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT6; + } + break; + case AB8500_CODEC_SRC_LINEIN: + { + src_type = STEREO_SRC; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT1; + ad_data_line2 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT2; + input_device1 = AB8500_CODEC_SRC_LINEIN; + input_device2 = AB8500_CODEC_SRC_LINEIN; + } + break; +#ifdef CONFIG_U8500_AB8500_CUT10 + case AB8500_CODEC_SRC_D_MICROPHONE_12: + { + src_type = STEREO_SRC; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT1; + ad_data_line2 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT2; + input_device1 = AB8500_CODEC_SRC_D_MICROPHONE_1; + input_device2 = AB8500_CODEC_SRC_D_MICROPHONE_2; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_34: + { + src_type = STEREO_SRC; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT3; + ad_data_line2 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT4; + input_device1 = AB8500_CODEC_SRC_D_MICROPHONE_3; + input_device2 = AB8500_CODEC_SRC_D_MICROPHONE_4; + } + break; + case AB8500_CODEC_SRC_D_MICROPHONE_56: + { + src_type = STEREO_SRC; + ad_data_line1 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT5; + ad_data_line2 = + AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT6; + input_device1 = AB8500_CODEC_SRC_D_MICROPHONE_5; + input_device2 = AB8500_CODEC_SRC_D_MICROPHONE_6; + } + break; +#endif /* #ifdef CONFIG_U8500_AB8500_CUT10 */ + } + if (STEREO_SRC == src_type) { + u8500_acodec_allocate_all_stereo_slots(ad_data_line1, + ad_data_line2); + codec_error = + AB8500_CODEC_SrcPowerControl(input_device1, + AB8500_CODEC_SRC_STATE_ENABLE); + if (AB8500_CODEC_OK != codec_error) { + stm_error("AB8500_CODEC_SrcPowerControl failed\n"); + return AB8500_CODEC_ERROR; + } + g_codec_system_context.input_config[input_device1].power_state = + ENABLE; + + u8500_acodec_set_input_volume(input_device1, 50, 50, USER_ALSA); + + codec_error = + AB8500_CODEC_SrcPowerControl(input_device2, + AB8500_CODEC_SRC_STATE_ENABLE); + if (AB8500_CODEC_OK != codec_error) { + stm_error("AB8500_CODEC_SrcPowerControl failed\n"); + return AB8500_CODEC_ERROR; + } + g_codec_system_context.input_config[input_device2].power_state = + ENABLE; + + u8500_acodec_set_input_volume(input_device2, 50, 50, USER_ALSA); + } else { + u8500_acodec_allocate_all_mono_slots(ad_data_line1); + codec_error = + AB8500_CODEC_SrcPowerControl(input_device, + AB8500_CODEC_SRC_STATE_ENABLE); + if (AB8500_CODEC_OK != codec_error) { + stm_error("AB8500_CODEC_SrcPowerControl failed\n"); + return AB8500_CODEC_ERROR; + } + g_codec_system_context.input_config[input_device].power_state = + ENABLE; + + u8500_acodec_set_input_volume(input_device, 50, 50, USER_ALSA); + } + return AB8500_CODEC_OK; +} + +t_ab8500_codec_error + u8500_acodec_allocate_all_mono_slots + (t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line1) { + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + int i; + + for (i = AB8500_CODEC_SLOT0; i <= AB8500_CODEC_SLOT7; i++) { + codec_error = AB8500_CODEC_ADSlotAllocation(i, ad_data_line1); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_adslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } + } + return AB8500_CODEC_OK; +} + +t_ab8500_codec_error + u8500_acodec_allocate_all_stereo_slots + (t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line1, + t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line2) { + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + int i; + + for (i = AB8500_CODEC_SLOT0; i <= AB8500_CODEC_SLOT7; i += 2) { + codec_error = AB8500_CODEC_ADSlotAllocation(i, ad_data_line1); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_adslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } + codec_error = + AB8500_CODEC_ADSlotAllocation(i + 1, ad_data_line2); + if (AB8500_CODEC_OK != codec_error) { + stm_error("ab8500_codec_adslot_allocation failed\n"); + return AB8500_CODEC_ERROR; + } + } + return AB8500_CODEC_OK; +} + +#ifdef CONFIG_U8500_AB8500_CUT10 +t_ab8500_codec_error +u8500_acodec_set_burst_mode_fifo(t_u8500_pmc_rendering_state fifo_state) +{ + +} +#else +t_ab8500_codec_error +u8500_acodec_set_burst_mode_fifo(t_u8500_pmc_rendering_state fifo_state) +{ + t_ab8500_codec_error ab8500_codec_error; + t_ab8500_codec_burst_fifo_config burst_fifo_config; + + if (RENDERING_ENABLE == fifo_state) { + burst_fifo_config.cr104_bfifoint = 0x1; + burst_fifo_config.cr105_bfifotx = 0xC0; + burst_fifo_config.cr106_bfifofsext = + AB8500_CODEC_CR106_BFIFOFSEXT_6SLOT_EXTRA_CLK; + burst_fifo_config.cr106_bfifomsk = + AB8500_CODEC_CR106_BFIFOMSK_AD_DATA0_UNMASKED; + burst_fifo_config.cr106_bfifomstr = + AB8500_CODEC_CR106_BFIFOMSTR_MASTER_MODE; + burst_fifo_config.cr106_bfifostrt = + AB8500_CODEC_CR106_BFIFOSTRT_RUNNING; + burst_fifo_config.cr107_bfifosampnr = 0x100; + burst_fifo_config.cr108_bfifowakeup = 0x1; + + ab8500_codec_error = + AB8500_CODEC_ConfigureBurstFifo(&burst_fifo_config); + if (AB8500_CODEC_OK != ab8500_codec_error) { + return ab8500_codec_error; + } + + ab8500_codec_error = AB8500_CODEC_EnableBurstFifo(); + if (AB8500_CODEC_OK != ab8500_codec_error) { + return ab8500_codec_error; + } + + printk("\n Burst mode activated\n"); + } else if (RENDERING_DISABLE == fifo_state) { + ab8500_codec_error = AB8500_CODEC_DisableBurstFifo(); + if (AB8500_CODEC_OK != ab8500_codec_error) { + return ab8500_codec_error; + } + printk("\n Burst mode deactivated\n"); + } + return AB8500_CODEC_OK; +} +#endif +/** +* u8500_acodec_set_user +* +* Set the current user for acodec. +*/ + +t_ab8500_codec_error u8500_acodec_setuser(t_acodec_user user) +{ + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + FUNC_ENTER(); + + if ((g_codec_system_context.cur_user == NO_USER) + || (g_codec_system_context.cur_user == user)) + g_codec_system_context.cur_user = user; + else { + stm_error + (" Trying to acces audiocodec already in use by user %d\n", + g_codec_system_context.cur_user); + return AB8500_CODEC_ERROR; + } + FUNC_EXIT(); + return (codec_error); +} + +/** +* u8500_acodec_unset_user +* +* Unset the current user for acodec. +*/ + +t_ab8500_codec_error u8500_acodec_unsetuser(t_acodec_user user) +{ + t_ab8500_codec_error codec_error = AB8500_CODEC_OK; + + if (g_codec_system_context.cur_user != user) { + stm_error + (" Trying to free audiocodec already in use by other user %d\n", + g_codec_system_context.cur_user); + return AB8500_CODEC_ERROR; + } else + g_codec_system_context.cur_user = NO_USER; + + return (codec_error); +} + +#if DRIVER_DEBUG > 0 +t_ab8500_codec_error dump_acodec_registers() +{ + u8 i; + + for (i = 0; i <= 0x6D; i++) + stm_dbg(DBG_ST.acodec, "block=0x0D, adr=%x = %x\n", i, + ab8500_read(AB8500_AUDIO, i)); + + /*for (i = 0; i < 0x5e; i++) + stm_dbg(DBG_ST.acodec,"\n block 1,reg =%d val %x", i, ab8500_read(AB8500_AUDIO, i)); + */ + return 0; +} + +t_ab8500_codec_error dump_msp_registers() +{ + int i; + + stm_dbg(DBG_ST.acodec, "\nMSP_1 base add = 0x%x\n", + (unsigned int)U8500_MSP1_BASE); + + for (i = 0; i < 0x40; i += 4) + stm_dbg(DBG_ST.acodec, "msp[0x%x]=0x%x\n", i, + readl((char *)(IO_ADDRESS(U8500_MSP1_BASE) + i))); + + return 0; +} + +EXPORT_SYMBOL(dump_msp_registers); +EXPORT_SYMBOL(dump_acodec_registers); +#endif + +/** +* u8500_acodec_powerdown +* +* This function power off the audio codec. +*/ +void u8500_acodec_powerdown() +{ + AB8500_CODEC_PowerDown(); +} + +/** +* u8500_acodec_init +* +* This is the init function for STW5098 audiocodec driver. +*/ + +static int i2sdrv_probe(struct i2s_device *i2s) +{ + + /* Allocate driver data */ + try_module_get(i2s->controller->dev.parent->driver->owner); + + /* Allocate memory to i2sdrv structure */ + i2sdrv[i2s->chip_select] = + kzalloc(sizeof(*i2sdrv[i2s->chip_select]), GFP_KERNEL); + if (!i2sdrv[i2s->chip_select]) + return -ENOMEM; + + /* Initialize the driver data */ + i2sdrv[i2s->chip_select]->i2s = i2s; + i2sdrv[i2s->chip_select]->flag = -1; + i2sdrv[i2s->chip_select]->tx_status = 0; + i2sdrv[i2s->chip_select]->rx_status = 0; + spin_lock_init(&i2sdrv[i2s->chip_select]->i2s_lock); + + i2s_set_drvdata(i2s, (void *)i2sdrv[i2s->chip_select]); + return 0; +} + +static int i2sdrv_remove(struct i2s_device *i2s) +{ + struct i2sdrv_data *i2sdrv = i2s_get_drvdata(i2s); + + spin_lock_irq(&i2sdrv->i2s_lock); + i2sdrv->i2s = NULL; + i2s_set_drvdata(i2s, NULL); + spin_unlock_irq(&i2sdrv->i2s_lock); + + stm_dbg(DBG_ST.acodec, "Entering AUDIOTRG_CODEC_DeIni\n"); + stm_dbg(DBG_ST.acodec, "leaving AUDIOTRG_CODEC_DeIni\n"); + module_put(i2s->controller->dev.parent->driver->owner); + printk("Remove of I2S gets called\n"); + return 0; +} +static const struct i2s_device_id acodec_id_table[] = { + {"i2s_device.2", 0, 0}, + {"i2s_device.1", 0, 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2s, acodec_id_table); + +static struct i2s_driver i2sdrv_i2s = { + .driver = { + .name = "u8500_acodec", + .owner = THIS_MODULE, + }, + .probe = i2sdrv_probe, + .remove = __devexit_p(i2sdrv_remove), + .id_table = acodec_id_table, + +}; + +static void ab8500_codec_power_init(void) +{ + __u8 data, old_data; + + old_data = + ab8500_read(AB8500_SYS_CTRL2_BLOCK, (AB8500_CTRL3_REG & 0xFF)); + + data = 0xFE & old_data; + ab8500_write(AB8500_SYS_CTRL2_BLOCK, (AB8500_CTRL3_REG & 0xFF), data); //0x0200 + + data = 0x02 | old_data; + ab8500_write(AB8500_SYS_CTRL2_BLOCK, (AB8500_CTRL3_REG & 0xFF), data); //0x0200 + + old_data = + ab8500_read(AB8500_SYS_CTRL2_BLOCK, + (AB8500_SYSULPCLK_CTRL1_REG & 0xFF)); +#ifdef CONFIG_U8500_AB8500_CUT10 + data = 0x18 | old_data; +#else + data = 0x10 | old_data; +#endif + ab8500_write(AB8500_SYS_CTRL2_BLOCK, (AB8500_SYSULPCLK_CTRL1_REG & 0xFF), data); //0x020B + + old_data = + ab8500_read(AB8500_REGU_CTRL1, (AB8500_REGU_MISC1_REG & 0xFF)); + data = 0x04 | old_data; + ab8500_write(AB8500_REGU_CTRL1, (AB8500_REGU_MISC1_REG & 0xFF), data); //0x380 + + old_data = + ab8500_read(AB8500_REGU_CTRL1, + (AB8500_REGU_VAUDIO_SUPPLY_REG & 0xFF)); + data = 0x5E | old_data; + ab8500_write(AB8500_REGU_CTRL1, (AB8500_REGU_VAUDIO_SUPPLY_REG & 0xFF), data); //0x0383 + +#ifdef CONFIG_U8500_AB8500_CUT10 + old_data = ab8500_read(AB8500_MISC, (AB8500_GPIO_DIR4_REG & 0xFF)); + data = 0x54 | old_data; + ab8500_write(AB8500_MISC, (AB8500_GPIO_DIR4_REG & 0xFF), data); //0x1013 +#endif +} + +/** +* u8500_acodec_deinit +* +* exit function for STW5098 audiocodec driver. +*/ +static int check_device_id() +{ + __u8 data; + + data = ab8500_read(AB8500_MISC, (0x80 & 0xFF)); + if (((data & 0xF0) == 0x10) || ((data & 0xF0) == 0x11)) { + /* V1 version */ +#ifndef CONFIG_U8500_AB8500_CUT10 + printk("ERROR: AB8500 hardware detected is CUT1x\n"); + return -ENODEV; +#endif + } else { +#ifndef CONFIG_U8500_AB8500_ED + /* ED version */ + printk("ERROR: AB8500 hardware detected is EarlyDrop\n"); + return -ENODEV; +#endif + } + return 0; +} + +static int __init u8500_acodec_init(void) +{ + int status, ret_val; + t_ab8500_codec_error error; + + ret_val = check_device_id(); + if (0 != ret_val) + return ret_val; + + status = i2s_register_driver(&i2sdrv_i2s); + if (status < 0) { + printk("Unable to register i2s driver\n"); + return status; + } + + /*Initialize Audiocodec */ + + ab8500_codec_power_init(); + + AB8500_CODEC_Init(TRG_CODEC_ADDRESS_ON_SPI_BUS); + + /* Reset CODEC */ + error = AB8500_CODEC_Reset(); + if (AB8500_CODEC_OK != error) { + stm_error("Error in AB8500_CODEC_Reset\n"); + return -1; + } + + stm_dbg(DBG_ST.acodec, " leaving u8500_acodec_init() \n"); + return 0; +} + +static void __exit u8500_acodec_deinit(void) +{ + stm_dbg(DBG_ST.acodec, "Entering AUDIOTRG_CODEC_DeIni\n"); + stm_dbg(DBG_ST.acodec, "leaving AUDIOTRG_CODEC_DeIni\n"); + i2s_unregister_driver(&i2sdrv_i2s); +} + +module_init(u8500_acodec_init); +module_exit(u8500_acodec_deinit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AB8500 stw5098 audiocodec driver"); + +/* exported function by audiocodec to be used by SAA driver and ALSA driver */ + +EXPORT_SYMBOL(u8500_acodec_open); +EXPORT_SYMBOL(u8500_acodec_close); +EXPORT_SYMBOL(u8500_acodec_send_data); +EXPORT_SYMBOL(u8500_acodec_receive_data); +EXPORT_SYMBOL(u8500_acodec_rates); +EXPORT_SYMBOL(u8500_acodec_powerdown); +EXPORT_SYMBOL(u8500_acodec_setuser); +EXPORT_SYMBOL(u8500_acodec_unsetuser); +EXPORT_SYMBOL(u8500_acodec_enable_audio_mode); +//EXPORT_SYMBOL(u8500_acodec_enable_voice_mode); +EXPORT_SYMBOL(u8500_acodec_get_output_volume); +EXPORT_SYMBOL(u8500_acodec_get_input_volume); +EXPORT_SYMBOL(u8500_acodec_set_output_volume); +EXPORT_SYMBOL(u8500_acodec_set_input_volume); +EXPORT_SYMBOL(u8500_acodec_select_input); +EXPORT_SYMBOL(u8500_acodec_select_output); + +t_ab8500_codec_error AB8500_CODEC_Write(IN t_uint8 register_offset, + IN t_uint8 count, IN t_uint8 * ptr_data) +{ + int i; + u32 address; + + for (i = 0; i < count; i++) { + address = (AB8500_AUDIO << 8) | (register_offset + i); + ab8500_write(AB8500_AUDIO, address, ptr_data[i]); + } + return AB8500_CODEC_OK; +} + +t_ab8500_codec_error AB8500_CODEC_Read(IN t_uint8 register_offset, + IN t_uint8 count, + IN t_uint8 * dummy_data, + IN t_uint8 * ptr_data) +{ + int i; + u32 address; + + dummy_data = dummy_data; /*keep compiler happy */ + + for (i = 0; i < count; i++) { + address = (AB8500_AUDIO << 8) | (register_offset + i); + ptr_data[i] = ab8500_read(AB8500_AUDIO, address); + } + + return AB8500_CODEC_OK; +} + +EXPORT_SYMBOL(u8500_acodec_set_src_power_cntrl); +EXPORT_SYMBOL(u8500_acodec_set_burst_mode_fifo); +EXPORT_SYMBOL(u8500_acodec_get_dest_power_state); +EXPORT_SYMBOL(lpbk_state_in_texts); +EXPORT_SYMBOL(u8500_acodec_toggle_playback_mute_control); +EXPORT_SYMBOL(u8500_acodec_set_dest_power_cntrl); +EXPORT_SYMBOL(power_state_in_texts); +EXPORT_SYMBOL(u8500_acodec_toggle_capture_mute_control); +EXPORT_SYMBOL(u8500_acodec_toggle_analog_lpbk); +EXPORT_SYMBOL(u8500_acodec_toggle_digital_lpbk); +EXPORT_SYMBOL(tdm_mode_state_in_texts); +EXPORT_SYMBOL(switch_state_in_texts); +EXPORT_SYMBOL(pcm_rendering_state_in_texts); +EXPORT_SYMBOL(direct_rendering_state_in_texts); +EXPORT_SYMBOL(u8500_acodec_get_src_power_state); +EXPORT_SYMBOL(i2sdrv); +EXPORT_SYMBOL(second_config); |