From: Rebecca Schultz Zavin Date: Fri, 3 Sep 2010 08:27:24 +0000 (-0700) Subject: Revert "[ARM] tegra: stingray: cpcap-audio: integrate Motorola's driver" X-Git-Tag: firefly_0821_release~9834^2~598 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=8b05fe70e11ad6a27dac425c971419703cd1fbd4;p=firefly-linux-kernel-4.4.55.git Revert "[ARM] tegra: stingray: cpcap-audio: integrate Motorola's driver" This reverts commit f01ee18d3d1f7e03216b652a04ba82161fd069aa. --- diff --git a/arch/arm/mach-tegra/board-stingray.c b/arch/arm/mach-tegra/board-stingray.c index e3df31d80653..8c501fef2773 100644 --- a/arch/arm/mach-tegra/board-stingray.c +++ b/arch/arm/mach-tegra/board-stingray.c @@ -229,38 +229,88 @@ static struct platform_device cpcap_otg = { .num_resources = ARRAY_SIZE(cpcap_otg_resources), }; -static struct cpcap_audio_state stingray_cpcap_audio_state = { - NULL, - CPCAP_AUDIO_MODE_NORMAL, - CPCAP_AUDIO_CODEC_OFF, - CPCAP_AUDIO_CODEC_RATE_8000_HZ, - CPCAP_AUDIO_CODEC_MUTE, - CPCAP_AUDIO_STDAC_OFF, - CPCAP_AUDIO_STDAC_RATE_44100_HZ, - CPCAP_AUDIO_STDAC_MUTE, - CPCAP_AUDIO_ANALOG_SOURCE_OFF, - CPCAP_AUDIO_OUT_NONE, - CPCAP_AUDIO_OUT_NONE, - CPCAP_AUDIO_OUT_LINEOUT, - CPCAP_AUDIO_OUT_LINEOUT, - CPCAP_AUDIO_OUT_NONE, - CPCAP_AUDIO_OUT_NONE, - CPCAP_AUDIO_BALANCE_NEUTRAL, - CPCAP_AUDIO_BALANCE_NEUTRAL, - CPCAP_AUDIO_BALANCE_NEUTRAL, - 7, /*default output gain */ - CPCAP_AUDIO_IN_NONE, - 31, /*default input_gain */ - CPCAP_AUDIO_RAT_NONE +#define CPCAP_REG(r, v, m) { .reg = (r), .val = (v), .mask = (m) } +#define CPCAP_REG_SLAVE(r, v, m, s) { .reg = (r), .val = (v), \ + .mask = (m), .slave_or = (s) } + +static const struct cpcap_audio_config_table speaker_config_table[] = { + CPCAP_REG(CPCAP_REG_VAUDIOC, 0x0007, 0x77), /* 512 */ + CPCAP_REG(CPCAP_REG_CC, 0x8E93, 0xFEDF), /* 513 */ + CPCAP_REG(CPCAP_REG_CDI, 0x1E42, 0xBFFF), /* 514 */ + CPCAP_REG(CPCAP_REG_SDAC, 0x0079, 0xFFF), /* 515 */ + CPCAP_REG_SLAVE(CPCAP_REG_SDACDI, 0x003E, 0x3FFF, 1), /* 516 */ + CPCAP_REG(CPCAP_REG_RXOA, 0x0218, 0x07FF), /* 519 */ + CPCAP_REG(CPCAP_REG_RXVC, 0x0028, 0x003C), /* 520 */ + CPCAP_REG(CPCAP_REG_RXCOA, 0x0618, 0x07FF), /* 521 */ + CPCAP_REG(CPCAP_REG_RXSDOA, 0x1818, 0x1FFF), /* 522 */ +}; + +static const struct cpcap_audio_config_table headset_config_table[] = { + CPCAP_REG(CPCAP_REG_VAUDIOC, 0x0007, 0x0077), /* 512 */ + CPCAP_REG(CPCAP_REG_CC, 0x8000, 0xFEDF), /* 513 */ + CPCAP_REG(CPCAP_REG_CDI, 0x8607, 0xBFFF), /* 514 */ + CPCAP_REG(CPCAP_REG_SDAC, 0x0079, 0xFFF), /* 515 */ + CPCAP_REG_SLAVE(CPCAP_REG_SDACDI, 0x003E, 0x3FFF, 1), /* 516 */ + CPCAP_REG(CPCAP_REG_RXOA, 0x0262, 0x07FF), /* 519 */ + CPCAP_REG(CPCAP_REG_RXVC, 0x0030, 0x003C), /* 520 */ + CPCAP_REG(CPCAP_REG_RXCOA, 0x0000, 0x07FF), /* 521 */ + CPCAP_REG(CPCAP_REG_RXSDOA, 0x1862, 0x1FFF), /* 522 */ +}; + +static const struct cpcap_audio_config_table mic1_config_table[] = { + CPCAP_REG(CPCAP_REG_VAUDIOC, 0x0035, 0x77), /* 512 */ + CPCAP_REG(CPCAP_REG_CC, 0x8F11, 0xFE11), /* 513 */ + CPCAP_REG(CPCAP_REG_CDI, 0x9E42, 0xBFFF), /* 514 */ + CPCAP_REG_SLAVE(CPCAP_REG_SDACDI, 0x003E, 0x3FFF, 1), /* 516 */ + CPCAP_REG(CPCAP_REG_TXI, 0x1CC6, 0xFFFF), /* 517 */ +}; + +static const struct cpcap_audio_config_table mic2_config_table[] = { + CPCAP_REG(CPCAP_REG_VAUDIOC, 0x0007, 0x77), + CPCAP_REG(CPCAP_REG_CC, 0x8FB3, 0xFEDF), + CPCAP_REG(CPCAP_REG_CDI, 0x1E40, 0xBFFF), + CPCAP_REG_SLAVE(CPCAP_REG_SDACDI, 0x007E, 0x3FFF, 1), + CPCAP_REG(CPCAP_REG_TXI, 0x0CC6, 0xFFFF), +}; + +#undef CPCAP_REG +#undef CPCAP_REG_SLAVE + +static struct cpcap_audio_path speaker = { + .name = "speaker", + .gpio = TEGRA_GPIO_PR3, + .table = speaker_config_table, + .table_len = ARRAY_SIZE(speaker_config_table) +}; + +static const struct cpcap_audio_path headset = { + .name = "headset", + .gpio = TEGRA_GPIO_PS7, + .table = headset_config_table, + .table_len = ARRAY_SIZE(headset_config_table) +}; + +static const struct cpcap_audio_path mic1 = { + .name = "mic1", + .gpio = -1, + .table = mic1_config_table, + .table_len = ARRAY_SIZE(mic1_config_table), +}; + +static const struct cpcap_audio_path mic2 = { + .name = "mic2", + .gpio = -1, + .table = mic2_config_table, + .table_len = ARRAY_SIZE(mic2_config_table), }; /* CPCAP is i2s master; tegra_audio_pdata.master == false */ static struct cpcap_audio_platform_data cpcap_audio_pdata = { .master = true, - .regulator = "vaudio", - .state = &stingray_cpcap_audio_state, - .speaker_gpio = TEGRA_GPIO_PR3, - .headset_gpio = TEGRA_GPIO_PS7, + .speaker = &speaker, + .headset = &headset, + .mic1 = &mic1, + .mic2 = &mic2, }; static struct platform_device cpcap_audio_device = { diff --git a/arch/arm/mach-tegra/include/mach/cpcap_audio.h b/arch/arm/mach-tegra/include/mach/cpcap_audio.h index 85f740be57b7..1f6804dbaba7 100644 --- a/arch/arm/mach-tegra/include/mach/cpcap_audio.h +++ b/arch/arm/mach-tegra/include/mach/cpcap_audio.h @@ -2,7 +2,6 @@ * arch/arm/mach-tegra/include/mach/cpcap_audio.h * * Copyright (C) 2010 Google, Inc. - * Copyright (C) 2007 - 2010 Motorola, Inc. * * Author: * Iliyan Malchev @@ -24,216 +23,27 @@ #include #include #include -#include -#include -enum { - CPCAP_AUDIO_MODE_NORMAL, /* mode of normal audio operation */ - CPCAP_AUDIO_MODE_DAI, /* CPCAP_AUDIO is configured for DAI testing */ - CPCAP_AUDIO_MODE_DAI_DOWNLINK = CPCAP_AUDIO_MODE_DAI, - CPCAP_AUDIO_MODE_DAI_UPLINK, - CPCAP_AUDIO_MODE_TTY /* CPCAP_AUDIO is configured for TTY */ +struct cpcap_audio_config_table { + int reg; + int val; + int mask; + int slave_or; }; -enum { - CPCAP_AUDIO_CODEC_OFF, /* codec is powered down */ - CPCAP_AUDIO_CODEC_CLOCK_ONLY, /* codec powered down, clocks running */ - CPCAP_AUDIO_CODEC_ON, /* codec is completely operational */ - CPCAP_AUDIO_CODEC_LOOPBACK /* xcap in (analog->digital->analog) mode */ -}; - -enum { - CPCAP_AUDIO_CODEC_RATE_8000_HZ, - /* codec is running at 8Khz sample rate */ - CPCAP_AUDIO_CODEC_RATE_11025_HZ, - /* codec is running at 11.025Khz sample rate */ - CPCAP_AUDIO_CODEC_RATE_12000_HZ, - /* codec is running at 12Khz sample rate */ - CPCAP_AUDIO_CODEC_RATE_16000_HZ, - /* codec is running at 16Khz sample rate */ - CPCAP_AUDIO_CODEC_RATE_22050_HZ, - /* codec is running at 22.05Khz sample rate */ - CPCAP_AUDIO_CODEC_RATE_24000_HZ, - /* codec is running at 24Khz sample rate */ - CPCAP_AUDIO_CODEC_RATE_32000_HZ, - /* codec is running at 32Khz sample rate */ - CPCAP_AUDIO_CODEC_RATE_44100_HZ, - /* codec is running at 44.1Khz sample rate */ - CPCAP_AUDIO_CODEC_RATE_48000_HZ, - /* codec is running at 48Khz sample rate */ -}; - -enum { - CPCAP_AUDIO_CODEC_UNMUTE, /* codec is unmuted */ - CPCAP_AUDIO_CODEC_MUTE, /* codec is muted */ - CPCAP_AUDIO_CODEC_BYPASS_LOOP - /* codec is bypassed - * (analog-only loopback mode) */ -}; - -enum { - CPCAP_AUDIO_STDAC_OFF, - /* stereo dac is powered down */ - CPCAP_AUDIO_STDAC_CLOCK_ONLY, - /* stereo dac is powered down, but clocks are activated */ - CPCAP_AUDIO_STDAC_ON - /* stereo dac is completely operational */ -}; - -enum { - /* THESE MUST CORRESPOND TO XCPCAP_AUDIO SETTINGS */ - CPCAP_AUDIO_STDAC_RATE_8000_HZ, - /* stereo dac set for 8Khz sample rate */ - CPCAP_AUDIO_STDAC_RATE_11025_HZ, - /* stereo dac set for 11.025Khz sample rate */ - CPCAP_AUDIO_STDAC_RATE_12000_HZ, - /* stereo dac set for 12Khz sample rate */ - CPCAP_AUDIO_STDAC_RATE_16000_HZ, - /* stereo dac set for 16Khz sample rate */ - CPCAP_AUDIO_STDAC_RATE_22050_HZ, - /* stereo dac set for 22.05Khz sample rate */ - CPCAP_AUDIO_STDAC_RATE_24000_HZ, - /* stereo dac set for 24Khz sample rate */ - CPCAP_AUDIO_STDAC_RATE_32000_HZ, - /* stereo dac set for 32Khz sample rate */ - CPCAP_AUDIO_STDAC_RATE_44100_HZ, - /* stereo dac set for 44.1Khz sample rate */ - CPCAP_AUDIO_STDAC_RATE_48000_HZ - /* stereo dac set for 48Khz sample rate */ -}; - -enum { - CPCAP_AUDIO_STDAC_UNMUTE, /* stereo dac is unmuted */ - CPCAP_AUDIO_STDAC_MUTE /* stereo dac is muted */ -}; - -enum { - CPCAP_AUDIO_ANALOG_SOURCE_OFF, - /* Analog PGA input is disabled */ - CPCAP_AUDIO_ANALOG_SOURCE_R, - /* Right analog PGA input is enabled */ - CPCAP_AUDIO_ANALOG_SOURCE_L, - /* Left analog PGA input is enabled */ - CPCAP_AUDIO_ANALOG_SOURCE_STEREO - /* Both analog PGA inputs are enabled */ -}; - -enum { - CPCAP_AUDIO_OUT_NONE, - /* No audio output selected */ - CPCAP_AUDIO_OUT_HANDSET, - /* handset (earpiece) speaker */ - CPCAP_AUDIO_OUT_LOUDSPEAKER, - /* loudspeaker (speakerphone) */ - CPCAP_AUDIO_OUT_LINEAR_VIBRATOR, - /* linear vibrator, if equipped */ - CPCAP_AUDIO_OUT_MONO_HEADSET, - /* mono (R channel) x.5mm headset */ - CPCAP_AUDIO_OUT_STEREO_HEADSET, - /* stereo x.5mm headset */ - CPCAP_AUDIO_OUT_EXT_BUS_MONO, - /* accessory bus mono output(EMU) */ - CPCAP_AUDIO_OUT_EMU_MONO, - CPCAP_AUDIO_OUT_EXT_BUS_STEREO, - /* accessory bus stereo output (EMU only) */ - CPCAP_AUDIO_OUT_EMU_STEREO, - CPCAP_AUDIO_OUT_LINEOUT, - CPCAP_AUDIO_OUT_BT_MONO, - CPCAP_AUDIO_OUT_NUM_OF_PATHS - /* Max number of audio output paths */ -}; - -enum { - CPCAP_AUDIO_IN_NONE, - /* No audio input selected */ - CPCAP_AUDIO_IN_HANDSET, - /* handset (internal) microphone */ - CPCAP_AUDIO_IN_AUX_INTERNAL, - /* Auxiliary (second) internal mic */ - CPCAP_AUDIO_IN_DUAL_INTERNAL, - /* both internal microphones are connected */ - CPCAP_AUDIO_IN_HEADSET, - /* Audio <- x.5mm headset microphone */ - CPCAP_AUDIO_IN_EXT_BUS, - /* Audio <- accessory bus analog input (EMU) */ - CPCAP_AUDIO_IN_EMU = CPCAP_AUDIO_IN_EXT_BUS, - CPCAP_AUDIO_IN_HEADSET_BIAS_ONLY, - /* 3.5mm headset control when no mic is selected */ - CPCAP_AUDIO_IN_DUAL_EXTERNAL, - /* Recording from external source */ - CPCAP_AUDIO_IN_BT_MONO, - CPCAP_AUDIO_IN_NUM_OF_PATHS - /* Max number of audio input paths */ -}; - -enum { - /* Defines the audio path type */ - CPCAP_AUDIO_AUDIO_IN_PATH, - /* Audio input path refers to CPCAP_AUDIO_MIC_TYPE */ - CPCAP_AUDIO_AUDIO_OUT_PATH - /* Audio output path refers to CPCAP_AUDIO_SPEAKER_TYPE */ -}; - -enum { - CPCAP_AUDIO_BALANCE_NEUTRAL,/* audio routed normally */ - CPCAP_AUDIO_BALANCE_R_ONLY, /* audio routed to left channel only */ - CPCAP_AUDIO_BALANCE_L_ONLY /* audio routed to right channel only */ -}; - -enum { - CPCAP_AUDIO_RAT_NONE, /* Not in a call mode */ - CPCAP_AUDIO_RAT_2G, /* In 2G call mode */ - CPCAP_AUDIO_RAT_3G, /* In 3G call mode */ - CPCAP_AUDIO_RAT_CDMA /* In CDMA call mode */ -}; - -/* Clock multipliers for A2LA register */ -enum { - CPCAP_AUDIO_A2_CLOCK_MASK = CPCAP_BIT_A2_CLK2 | CPCAP_BIT_A2_CLK1 | - CPCAP_BIT_A2_CLK0, - CPCAP_AUDIO_A2_CLOCK_15_36 = CPCAP_BIT_A2_CLK0, - CPCAP_AUDIO_A2_CLOCK_16_80 = CPCAP_BIT_A2_CLK1, - CPCAP_AUDIO_A2_CLOCK_19_20 = CPCAP_BIT_A2_CLK1 | CPCAP_BIT_A2_CLK0, - CPCAP_AUDIO_A2_CLOCK_26_00 = CPCAP_BIT_A2_CLK2, - CPCAP_AUDIO_A2_CLOCK_33_60 = CPCAP_BIT_A2_CLK2 | CPCAP_BIT_A2_CLK0, - CPCAP_AUDIO_A2_CLOCK_38_40 = CPCAP_BIT_A2_CLK2 | CPCAP_BIT_A2_CLK1 -}; - -struct cpcap_audio_state { - struct cpcap_device *cpcap; - int mode; - int codec_mode; - int codec_rate; - int codec_mute; - int stdac_mode; - int stdac_rate; - int stdac_mute; - int analog_source; - int codec_primary_speaker; - int codec_secondary_speaker; - int stdac_primary_speaker; - int stdac_secondary_speaker; - int ext_primary_speaker; - int ext_secondary_speaker; - int codec_primary_balance; - int stdac_primary_balance; - int ext_primary_balance; - unsigned int output_gain; - int microphone; - unsigned int input_gain; - int rat_type; +struct cpcap_audio_path { + const char *name; + int gpio; + const struct cpcap_audio_config_table *table; + int table_len; }; struct cpcap_audio_platform_data { bool master; - const char *regulator; - struct cpcap_audio_state *state; - int speaker_gpio; - int headset_gpio; + const struct cpcap_audio_path *speaker; + const struct cpcap_audio_path *headset; + const struct cpcap_audio_path *mic1; + const struct cpcap_audio_path *mic2; }; -int cpcap_audio_init(struct cpcap_audio_state *state, const char *regulator); -void cpcap_audio_register_dump(struct cpcap_audio_state *state); -void cpcap_audio_set_audio_state(struct cpcap_audio_state *state); - #endif/*__ARCH_ARM_MACH_TEGRA_CPCAP_AUDIO_H_*/ diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index a28fc814aea6..ece21b1a98a2 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -85,7 +85,6 @@ cpcap-objs := cpcap-core.o \ cpcap-adc.o \ cpcap-uc.o \ cpcap-3mm5.o \ - tegra-cpcap-audio.o \ - cpcap-audio-core.o + cpcap-audio.o obj-$(CONFIG_MFD_CPCAP) += cpcap.o diff --git a/drivers/mfd/cpcap-audio-core.c b/drivers/mfd/cpcap-audio-core.c deleted file mode 100644 index 8c725a00fe79..000000000000 --- a/drivers/mfd/cpcap-audio-core.c +++ /dev/null @@ -1,1126 +0,0 @@ -/* - * Copyright (C) 2007 - 2009 Motorola, Inc. - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307, USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define SLEEP_ACTIVATE_POWER_DELAY_MS 2 -#define CLOCK_TREE_RESET_DELAY_MS 1 - -#define CPCAP_AUDIO_SPI_READBACK 1 - -#define E(args...) pr_err("cpcap-audio: " args) - -static struct cpcap_audio_state current_state = { - .cpcap = NULL, - .mode = CPCAP_AUDIO_MODE_NORMAL, - - .codec_mode = CPCAP_AUDIO_CODEC_OFF, - .codec_rate = CPCAP_AUDIO_CODEC_RATE_8000_HZ, - .codec_mute = CPCAP_AUDIO_CODEC_MUTE, - - .stdac_mode = CPCAP_AUDIO_STDAC_OFF, - .stdac_rate = CPCAP_AUDIO_STDAC_RATE_8000_HZ, - .stdac_mute = CPCAP_AUDIO_STDAC_MUTE, - - .analog_source = CPCAP_AUDIO_ANALOG_SOURCE_OFF, - - .codec_primary_speaker = CPCAP_AUDIO_OUT_NONE, - .codec_secondary_speaker = CPCAP_AUDIO_OUT_NONE, - - .stdac_primary_speaker = CPCAP_AUDIO_OUT_NONE, - .stdac_secondary_speaker = CPCAP_AUDIO_OUT_NONE, - - .ext_primary_speaker = CPCAP_AUDIO_OUT_NONE, - .ext_secondary_speaker = CPCAP_AUDIO_OUT_NONE, - - .codec_primary_balance = CPCAP_AUDIO_BALANCE_NEUTRAL, - .stdac_primary_balance = CPCAP_AUDIO_BALANCE_NEUTRAL, - .ext_primary_balance = CPCAP_AUDIO_BALANCE_NEUTRAL, - - .output_gain = 0, - .microphone = CPCAP_AUDIO_IN_NONE, - .input_gain = 0, - .rat_type = CPCAP_AUDIO_RAT_NONE -}; - -/* Define regulator to turn on the audio portion of cpcap */ -struct regulator *audio_reg; - -static inline bool is_mic_stereo(int microphone) -{ - return microphone == CPCAP_AUDIO_IN_DUAL_INTERNAL || - microphone == CPCAP_AUDIO_IN_DUAL_EXTERNAL; -} - -static inline bool is_codec_changed(struct cpcap_audio_state *state, - struct cpcap_audio_state *prev) -{ - return state->codec_mode != prev->codec_mode || - state->codec_rate != prev->codec_rate || - state->rat_type != prev->rat_type || - state->microphone != prev->microphone; -} - -static inline bool is_stdac_changed(struct cpcap_audio_state *state, - struct cpcap_audio_state *prev) -{ - return state->stdac_mode != prev->stdac_mode || - state->rat_type != prev->rat_type || - state->stdac_rate != prev->stdac_rate; -} - -static inline bool is_output_bt_only(struct cpcap_audio_state *state) -{ - if (state->codec_primary_speaker == CPCAP_AUDIO_OUT_BT_MONO && - state->codec_secondary_speaker == CPCAP_AUDIO_OUT_NONE) - return true; - - if (state->stdac_primary_speaker == CPCAP_AUDIO_OUT_BT_MONO && - state->stdac_secondary_speaker == CPCAP_AUDIO_OUT_NONE) - return true; - - if (state->ext_primary_speaker == CPCAP_AUDIO_OUT_BT_MONO && - state->ext_secondary_speaker == CPCAP_AUDIO_OUT_NONE) - return true; - - return false; -} - -static inline bool is_output_headset(struct cpcap_audio_state *state) -{ - if (state->codec_primary_speaker == CPCAP_AUDIO_OUT_STEREO_HEADSET || - state->codec_primary_speaker == - CPCAP_AUDIO_OUT_MONO_HEADSET || - state->codec_secondary_speaker == - CPCAP_AUDIO_OUT_STEREO_HEADSET || - state->codec_secondary_speaker == - CPCAP_AUDIO_OUT_MONO_HEADSET) - return true; - - if (state->stdac_primary_speaker == CPCAP_AUDIO_OUT_STEREO_HEADSET || - state->stdac_primary_speaker == - CPCAP_AUDIO_OUT_MONO_HEADSET || - state->stdac_secondary_speaker == - CPCAP_AUDIO_OUT_STEREO_HEADSET || - state->stdac_secondary_speaker == - CPCAP_AUDIO_OUT_MONO_HEADSET) - return true; - - if (state->ext_primary_speaker == CPCAP_AUDIO_OUT_STEREO_HEADSET || - state->ext_primary_speaker == - CPCAP_AUDIO_OUT_MONO_HEADSET || - state->ext_secondary_speaker == - CPCAP_AUDIO_OUT_STEREO_HEADSET || - state->ext_secondary_speaker == - CPCAP_AUDIO_OUT_MONO_HEADSET) - return true; - - return false; -} - -static inline bool is_speaker_turning_off(struct cpcap_audio_state *state, - struct cpcap_audio_state *prev) -{ - return (prev->codec_primary_speaker != CPCAP_AUDIO_OUT_NONE && - state->codec_primary_speaker == - CPCAP_AUDIO_OUT_NONE) || - (prev->codec_secondary_speaker != CPCAP_AUDIO_OUT_NONE && - state->codec_secondary_speaker == - CPCAP_AUDIO_OUT_NONE) || - (prev->stdac_primary_speaker != CPCAP_AUDIO_OUT_NONE && - state->stdac_primary_speaker == - CPCAP_AUDIO_OUT_NONE) || - (prev->stdac_secondary_speaker != CPCAP_AUDIO_OUT_NONE && - state->stdac_secondary_speaker == - CPCAP_AUDIO_OUT_NONE) || - (prev->ext_primary_speaker != CPCAP_AUDIO_OUT_NONE && - state->ext_primary_speaker == - CPCAP_AUDIO_OUT_NONE) || - (prev->ext_secondary_speaker != CPCAP_AUDIO_OUT_NONE && - state->ext_secondary_speaker == - CPCAP_AUDIO_OUT_NONE); -} - -static inline bool is_output_changed(struct cpcap_audio_state *state, - struct cpcap_audio_state *prev) -{ - if (state->codec_primary_speaker != prev->codec_primary_speaker || - state->codec_primary_balance != - prev->codec_primary_balance || - state->codec_secondary_speaker != - prev->codec_secondary_speaker) - return true; - - if (state->stdac_primary_speaker != prev->stdac_primary_speaker || - state->stdac_primary_balance != - prev->stdac_primary_balance || - state->stdac_secondary_speaker != - prev->stdac_secondary_speaker) - return true; - - if (state->ext_primary_speaker != prev->ext_primary_speaker || - state->ext_primary_balance != - prev->ext_primary_balance || - state->ext_secondary_speaker != - prev->ext_secondary_speaker) - return true; - - return false; -} - -/* this is only true for audio registers, but those are the only ones we use */ -#define CPCAP_REG_FOR_POWERIC_REG(a) ((a) + (0x200 - CPCAP_REG_VAUDIOC)) - -static void logged_cpcap_write(struct cpcap_device *cpcap, unsigned int reg, - unsigned short int value, unsigned short int mask) -{ - if (mask != 0) { - int ret_val = 0; - pr_debug("%s: audio: reg %u, value 0x%x,mask 0x%x\n", __func__, - CPCAP_REG_FOR_POWERIC_REG(reg), value, mask); - ret_val = cpcap_regacc_write(cpcap, reg, value, mask); - if (ret_val != 0) - E("%s: w %04x m %04x -> r %u failed: %d\n", __func__, - value, mask, reg, ret_val); -#if CPCAP_AUDIO_SPI_READBACK - ret_val = cpcap_regacc_read(cpcap, reg, &value); - if (ret_val == 0) - pr_debug("%s: audio verify: reg %u: value 0x%x\n", - __func__, - CPCAP_REG_FOR_POWERIC_REG(reg), value); - else - E("%s: audio verify: reg %u FAILED\n", __func__, - CPCAP_REG_FOR_POWERIC_REG(reg)); -#endif - } -} - -static unsigned short int cpcap_audio_get_codec_output_amp_switches( - int speaker, int balance) -{ - unsigned short int value = CPCAP_BIT_PGA_CDC_EN; - - pr_debug("%s() called with speaker = %d\n", __func__, - speaker); - - switch (speaker) { - case CPCAP_AUDIO_OUT_HANDSET: - value |= CPCAP_BIT_A1_EAR_CDC_SW; - break; - - case CPCAP_AUDIO_OUT_LOUDSPEAKER: - value |= CPCAP_BIT_A2_LDSP_L_CDC_SW; - break; - - case CPCAP_AUDIO_OUT_MONO_HEADSET: - case CPCAP_AUDIO_OUT_STEREO_HEADSET: - if (balance != CPCAP_AUDIO_BALANCE_L_ONLY) - value |= CPCAP_BIT_ARIGHT_HS_CDC_SW; - if (balance != CPCAP_AUDIO_BALANCE_R_ONLY) - value |= CPCAP_BIT_ALEFT_HS_CDC_SW; - break; - - case CPCAP_AUDIO_OUT_LINEOUT: - value |= CPCAP_BIT_A4_LINEOUT_R_CDC_SW | - CPCAP_BIT_A4_LINEOUT_L_CDC_SW; - break; - - case CPCAP_AUDIO_OUT_BT_MONO: - default: - value = 0; - break; - } - - pr_debug("Exiting %s() with return value = %d\n", __func__, - value); - return value; -} - -static unsigned short int cpcap_audio_get_stdac_output_amp_switches( - int speaker, int balance) -{ - unsigned short int value = CPCAP_BIT_PGA_DAC_EN; - - pr_debug("%s() called with speaker = %d\n", __func__, - speaker); - - switch (speaker) { - case CPCAP_AUDIO_OUT_HANDSET: - value |= CPCAP_BIT_A1_EAR_DAC_SW; - break; - - case CPCAP_AUDIO_OUT_MONO_HEADSET: - case CPCAP_AUDIO_OUT_STEREO_HEADSET: - if (balance != CPCAP_AUDIO_BALANCE_R_ONLY) - value |= CPCAP_BIT_ALEFT_HS_DAC_SW; - if (balance != CPCAP_AUDIO_BALANCE_L_ONLY) - value |= CPCAP_BIT_ARIGHT_HS_DAC_SW; - break; - - case CPCAP_AUDIO_OUT_LOUDSPEAKER: - value |= CPCAP_BIT_A2_LDSP_L_DAC_SW | CPCAP_BIT_MONO_DAC0 | - CPCAP_BIT_MONO_DAC1; - break; - - case CPCAP_AUDIO_OUT_LINEOUT: - value |= CPCAP_BIT_A4_LINEOUT_R_DAC_SW | - CPCAP_BIT_A4_LINEOUT_L_DAC_SW; - break; - - case CPCAP_AUDIO_OUT_BT_MONO: - default: - value = 0; - break; - } - - pr_debug("Exiting %s() with return value = %d\n", __func__, - value); - return value; -} - -static unsigned short int cpcap_audio_get_ext_output_amp_switches( - int speaker, int balance) -{ - unsigned short int value = 0; - pr_debug("%s() called with speaker %d\n", __func__, - speaker); - switch (speaker) { - case CPCAP_AUDIO_OUT_HANDSET: - value = CPCAP_BIT_A1_EAR_EXT_SW | CPCAP_BIT_PGA_EXT_R_EN; - break; - - case CPCAP_AUDIO_OUT_MONO_HEADSET: - case CPCAP_AUDIO_OUT_STEREO_HEADSET: - if (balance != CPCAP_AUDIO_BALANCE_L_ONLY) - value = CPCAP_BIT_ARIGHT_HS_EXT_SW | - CPCAP_BIT_PGA_EXT_R_EN; - if (balance != CPCAP_AUDIO_BALANCE_R_ONLY) - value |= CPCAP_BIT_ALEFT_HS_EXT_SW | - CPCAP_BIT_PGA_EXT_L_EN; - break; - - case CPCAP_AUDIO_OUT_LOUDSPEAKER: - value = CPCAP_BIT_A2_LDSP_L_EXT_SW | CPCAP_BIT_PGA_EXT_L_EN; - break; - - case CPCAP_AUDIO_OUT_LINEOUT: - value = CPCAP_BIT_A4_LINEOUT_R_EXT_SW | - CPCAP_BIT_A4_LINEOUT_L_EXT_SW | - CPCAP_BIT_PGA_EXT_L_EN | CPCAP_BIT_PGA_EXT_R_EN; - break; - - case CPCAP_AUDIO_OUT_BT_MONO: - default: - value = 0; - break; - } - - pr_debug("Exiting %s() with return value = %d\n", __func__, - value); - return value; -} - -static void cpcap_audio_set_output_amp_switches(struct cpcap_audio_state *state) -{ - static unsigned int codec_prev_settings; - static unsigned int stdac_prev_settings; - static unsigned int ext_prev_settings; - - struct cpcap_regacc reg_changes; - unsigned short int value1 = 0, value2 = 0; - - /* First set codec output amp switches */ - value1 = cpcap_audio_get_codec_output_amp_switches(state-> - codec_primary_speaker, state->codec_primary_balance); - value2 = cpcap_audio_get_codec_output_amp_switches(state-> - codec_secondary_speaker, state->codec_primary_balance); - - reg_changes.mask = value1 | value2 | codec_prev_settings; - reg_changes.value = value1 | value2; - codec_prev_settings = reg_changes.value; - - logged_cpcap_write(state->cpcap, CPCAP_REG_RXCOA, reg_changes.value, - reg_changes.mask); - - /* Second Stdac switches */ - value1 = cpcap_audio_get_stdac_output_amp_switches(state-> - stdac_primary_speaker, state->stdac_primary_balance); - value2 = cpcap_audio_get_stdac_output_amp_switches(state-> - stdac_secondary_speaker, state->stdac_primary_balance); - - reg_changes.mask = value1 | value2 | stdac_prev_settings; - reg_changes.value = value1 | value2; - - if ((state->stdac_primary_speaker == CPCAP_AUDIO_OUT_STEREO_HEADSET && - state->stdac_secondary_speaker == CPCAP_AUDIO_OUT_LOUDSPEAKER) - || (state->stdac_primary_speaker == CPCAP_AUDIO_OUT_LOUDSPEAKER - && state->stdac_secondary_speaker == - CPCAP_AUDIO_OUT_STEREO_HEADSET)) - reg_changes.value &= ~(CPCAP_BIT_MONO_DAC0 | - CPCAP_BIT_MONO_DAC1); - - stdac_prev_settings = reg_changes.value; - - logged_cpcap_write(state->cpcap, CPCAP_REG_RXSDOA, reg_changes.value, - reg_changes.mask); - - /* Last External source switches */ - value1 = - cpcap_audio_get_ext_output_amp_switches(state-> - ext_primary_speaker, - state->ext_primary_balance); - value2 = - cpcap_audio_get_ext_output_amp_switches(state-> - ext_secondary_speaker, - state->ext_primary_balance); - - reg_changes.mask = value1 | value2 | ext_prev_settings; - reg_changes.value = value1 | value2; - ext_prev_settings = reg_changes.value; - - logged_cpcap_write(state->cpcap, CPCAP_REG_RXEPOA, - reg_changes.value, reg_changes.mask); -} - -static bool cpcap_audio_set_bits_for_speaker(int speaker, int balance, - unsigned short int *message) -{ - pr_debug("%s() called with speaker = %d\n", __func__, - speaker); - - /* Get the data required to enable each possible path */ - switch (speaker) { - case CPCAP_AUDIO_OUT_HANDSET: - (*message) |= CPCAP_BIT_A1_EAR_EN; - break; - - case CPCAP_AUDIO_OUT_MONO_HEADSET: - case CPCAP_AUDIO_OUT_STEREO_HEADSET: - if (balance != CPCAP_AUDIO_BALANCE_R_ONLY) - (*message) |= CPCAP_BIT_HS_L_EN; - if (balance != CPCAP_AUDIO_BALANCE_L_ONLY) - (*message) |= CPCAP_BIT_HS_R_EN; - break; - - case CPCAP_AUDIO_OUT_LOUDSPEAKER: - (*message) |= CPCAP_BIT_A2_LDSP_L_EN; - break; - - case CPCAP_AUDIO_OUT_LINEOUT: - (*message) |= CPCAP_BIT_A4_LINEOUT_R_EN | - CPCAP_BIT_A4_LINEOUT_L_EN; - break; - - case CPCAP_AUDIO_OUT_BT_MONO: - default: - (*message) |= 0; - break; - } - - return false; /* There is no external loudspeaker on this product */ -} - -static void cpcap_audio_configure_aud_mute(struct cpcap_audio_state *state, - struct cpcap_audio_state *prev) -{ - struct cpcap_regacc reg_changes = { 0 }; - unsigned short int value1 = 0, value2 = 0; - - if (state->codec_mute != prev->codec_mute) { - value1 = cpcap_audio_get_codec_output_amp_switches( - prev->codec_primary_speaker, - prev->codec_primary_balance); - - value2 = cpcap_audio_get_codec_output_amp_switches( - prev->codec_secondary_speaker, - prev->codec_primary_balance); - - reg_changes.mask = value1 | value2 | CPCAP_BIT_CDC_SW; - - if (state->codec_mute == CPCAP_AUDIO_CODEC_UNMUTE) - reg_changes.value = reg_changes.mask; - - logged_cpcap_write(state->cpcap, CPCAP_REG_RXCOA, - reg_changes.value, reg_changes.mask); - } - - if (state->stdac_mute != prev->stdac_mute) { - value1 = cpcap_audio_get_stdac_output_amp_switches( - prev->stdac_primary_speaker, - prev->stdac_primary_balance); - - value2 = cpcap_audio_get_stdac_output_amp_switches( - prev->stdac_secondary_speaker, - prev->stdac_primary_balance); - - reg_changes.mask = value1 | value2 | CPCAP_BIT_ST_DAC_SW; - - if (state->stdac_mute == CPCAP_AUDIO_STDAC_UNMUTE) - reg_changes.value = reg_changes.mask; - - logged_cpcap_write(state->cpcap, CPCAP_REG_RXSDOA, - reg_changes.value, reg_changes.mask); - } -} - -static void cpcap_audio_configure_codec(struct cpcap_audio_state *state, - struct cpcap_audio_state *prev) -{ - unsigned int temp_codec_rate = state->codec_rate; - struct cpcap_regacc cdai_changes = { 0 }; - struct cpcap_regacc codec_changes = { 0 }; - int codec_freq_config = 0; - - const unsigned int CODEC_FREQ_MASK = CPCAP_BIT_CDC_CLK0 - | CPCAP_BIT_CDC_CLK1 | CPCAP_BIT_CDC_CLK2; - const unsigned int CODEC_RESET_FREQ_MASK = CODEC_FREQ_MASK - | CPCAP_BIT_CDC_CLOCK_TREE_RESET; - - static unsigned int prev_codec_data = 0x0, prev_cdai_data = 0x0; - - if (!is_codec_changed(state, prev)) - return; - - if (state->rat_type == CPCAP_AUDIO_RAT_CDMA) - codec_freq_config = (CPCAP_BIT_CDC_CLK0 - | CPCAP_BIT_CDC_CLK1) ; /* 19.2Mhz */ - else - codec_freq_config = CPCAP_BIT_CDC_CLK2 ; /* 26Mhz */ - - /* If a codec is already in use, reset codec to initial state */ - if (prev->codec_mode != CPCAP_AUDIO_CODEC_OFF) { - codec_changes.mask = prev_codec_data - | CPCAP_BIT_DF_RESET - | CPCAP_BIT_CDC_CLOCK_TREE_RESET; - - logged_cpcap_write(state->cpcap, CPCAP_REG_CC, - codec_changes.value, codec_changes.mask); - - prev_codec_data = 0; - prev->codec_mode = CPCAP_AUDIO_CODEC_OFF; - } - - temp_codec_rate &= 0x0000000F; - temp_codec_rate = temp_codec_rate << 9; - - switch (state->codec_mode) { - case CPCAP_AUDIO_CODEC_LOOPBACK: - case CPCAP_AUDIO_CODEC_ON: - if (state->codec_primary_speaker != - CPCAP_AUDIO_OUT_NONE) { - codec_changes.value |= CPCAP_BIT_CDC_EN_RX; - } - - /* Turning on the input HPF */ - if (state->microphone != CPCAP_AUDIO_IN_NONE) - codec_changes.value |= CPCAP_BIT_AUDIHPF_0 | - CPCAP_BIT_AUDIHPF_1; - -#if 1 - if (state->microphone != CPCAP_AUDIO_IN_NONE) { - codec_changes.value |= CPCAP_BIT_MIC1_CDC_EN; - codec_changes.value |= CPCAP_BIT_MIC2_CDC_EN; - } -#else - if (state->microphone != CPCAP_AUDIO_IN_AUX_INTERNAL && - state->microphone != CPCAP_AUDIO_IN_NONE) - codec_changes.value |= CPCAP_BIT_MIC1_CDC_EN | - CPCAP_BIT_MIC2_CDC_EN; - - if (state->microphone == CPCAP_AUDIO_IN_AUX_INTERNAL || - is_mic_stereo(state->microphone)) - codec_changes.value |= CPCAP_BIT_MIC2_CDC_EN; -#endif - - /* falling through intentionally */ - case CPCAP_AUDIO_CODEC_CLOCK_ONLY: - codec_changes.value |= - (codec_freq_config | temp_codec_rate | - CPCAP_BIT_DF_RESET); - cdai_changes.value |= CPCAP_BIT_CDC_CLK_EN; - break; - - case CPCAP_AUDIO_CODEC_OFF: - cdai_changes.value |= CPCAP_BIT_SMB_CDC; - break; - - default: - break; - } - - /* Multimedia uses CLK_IN0, incall uses CLK_IN1 */ - if (state->rat_type != CPCAP_AUDIO_RAT_NONE) - cdai_changes.value |= CPCAP_BIT_CLK_IN_SEL; - - cdai_changes.value |= CPCAP_BIT_CDC_PLL_SEL | CPCAP_BIT_CLK_INV; - cdai_changes.value |= CPCAP_BIT_DIG_AUD_IN; - - /* Setting I2S mode */ - cdai_changes.value |= CPCAP_BIT_CDC_DIG_AUD_FS0 | - CPCAP_BIT_CDC_DIG_AUD_FS1 | - CPCAP_BIT_MIC2_TIMESLOT0; - - /* OK, now start paranoid codec sequence */ - /* FIRST, make sure the frequency config is right... */ - logged_cpcap_write(state->cpcap, CPCAP_REG_CC, - codec_freq_config, CODEC_FREQ_MASK); - - /* Next, write the CDAI if it's changed */ - if (prev_cdai_data != cdai_changes.value) { - cdai_changes.mask = cdai_changes.value - | prev_cdai_data; - prev_cdai_data = cdai_changes.value; - - logged_cpcap_write(state->cpcap, CPCAP_REG_CDI, - cdai_changes.value, cdai_changes.mask); - - /* Clock tree change -- reset and wait */ - codec_freq_config |= CPCAP_BIT_CDC_CLOCK_TREE_RESET; - - logged_cpcap_write(state->cpcap, CPCAP_REG_CC, - codec_freq_config, CODEC_RESET_FREQ_MASK); - - /* Wait for clock tree reset to complete */ - mdelay(CLOCK_TREE_RESET_DELAY_MS); - } - - /* Clear old settings */ - codec_changes.mask = codec_changes.value | prev_codec_data; - prev_codec_data = codec_changes.value; - - logged_cpcap_write(state->cpcap, CPCAP_REG_CC, - codec_changes.value, codec_changes.mask); -} - -static void cpcap_audio_configure_stdac(struct cpcap_audio_state *state, - struct cpcap_audio_state *prev) -{ - const unsigned int SDAC_FREQ_MASK = CPCAP_BIT_ST_DAC_CLK0 - | CPCAP_BIT_ST_DAC_CLK1 | CPCAP_BIT_ST_DAC_CLK2; - const unsigned int SDAC_RESET_FREQ_MASK = SDAC_FREQ_MASK - | CPCAP_BIT_ST_CLOCK_TREE_RESET; - static unsigned int prev_stdac_data, prev_sdai_data; - - if (is_stdac_changed(state, prev)) { - unsigned int temp_stdac_rate = state->stdac_rate; - struct cpcap_regacc sdai_changes = { 0 }; - struct cpcap_regacc stdac_changes = { 0 }; - - int stdac_freq_config = 0; - if (state->rat_type == CPCAP_AUDIO_RAT_CDMA) - stdac_freq_config = (CPCAP_BIT_ST_DAC_CLK0 - | CPCAP_BIT_ST_DAC_CLK1) ; /*19.2Mhz*/ - else - stdac_freq_config = CPCAP_BIT_ST_DAC_CLK2 ; /* 26Mhz */ - - /* We need to turn off stdac before changing its settings */ - if (prev->stdac_mode != CPCAP_AUDIO_STDAC_OFF) { - stdac_changes.mask = prev_stdac_data | - CPCAP_BIT_DF_RESET_ST_DAC | - CPCAP_BIT_ST_CLOCK_TREE_RESET; - - logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, - stdac_changes.value, stdac_changes.mask); - - prev_stdac_data = 0; - prev->stdac_mode = CPCAP_AUDIO_STDAC_OFF; - } - - temp_stdac_rate &= 0x0000000F; - temp_stdac_rate = temp_stdac_rate << 4; - - switch (state->stdac_mode) { - case CPCAP_AUDIO_STDAC_ON: - stdac_changes.value |= CPCAP_BIT_ST_DAC_EN; - /* falling through intentionally */ - case CPCAP_AUDIO_STDAC_CLOCK_ONLY: - stdac_changes.value |= temp_stdac_rate | - CPCAP_BIT_DF_RESET_ST_DAC | stdac_freq_config; - sdai_changes.value |= CPCAP_BIT_ST_CLK_EN; - break; - - case CPCAP_AUDIO_STDAC_OFF: - default: - break; - } - - if (state->rat_type != CPCAP_AUDIO_RAT_NONE) - sdai_changes.value |= CPCAP_BIT_ST_DAC_CLK_IN_SEL; - /* begin everest change */ - /* - sdai_changes.value |= CPCAP_BIT_ST_DIG_AUD_FS0 | - CPCAP_BIT_DIG_AUD_IN_ST_DAC | CPCAP_BIT_ST_L_TIMESLOT0; - */ - /* I2S Mode, ignore timeslots, invert bit clock */ - sdai_changes.value |= CPCAP_BIT_ST_DIG_AUD_FS0 | - CPCAP_BIT_DIG_AUD_IN_ST_DAC | - CPCAP_BIT_ST_DIG_AUD_FS1 | CPCAP_BIT_ST_CLK_INV; - /* end everest change */ - - logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, - stdac_freq_config, SDAC_FREQ_MASK); - - /* Next, write the SDACDI if it's changed */ - if (prev_sdai_data != sdai_changes.value) { - sdai_changes.mask = sdai_changes.value - | prev_sdai_data; - prev_sdai_data = sdai_changes.value; - - logged_cpcap_write(state->cpcap, CPCAP_REG_SDACDI, - sdai_changes.value, sdai_changes.mask); - - /* Clock tree change -- reset and wait */ - stdac_freq_config |= CPCAP_BIT_ST_CLOCK_TREE_RESET; - - logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, - stdac_freq_config, SDAC_RESET_FREQ_MASK); - - /* Wait for clock tree reset to complete */ - mdelay(CLOCK_TREE_RESET_DELAY_MS); - } - - /* Clear old settings */ - stdac_changes.mask = stdac_changes.value | prev_stdac_data; - prev_stdac_data = stdac_changes.value; - - logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, - stdac_changes.value, stdac_changes.mask); - } -} - -static void cpcap_audio_configure_analog_source( - struct cpcap_audio_state *state, - struct cpcap_audio_state *prev) -{ - if (state->analog_source != prev->analog_source) { - struct cpcap_regacc ext_changes = { 0 }; - static unsigned int prev_ext_data; - switch (state->analog_source) { - case CPCAP_AUDIO_ANALOG_SOURCE_STEREO: - ext_changes.value |= CPCAP_BIT_MONO_EXT0 | - CPCAP_BIT_PGA_IN_R_SW | CPCAP_BIT_PGA_IN_L_SW; - break; - case CPCAP_AUDIO_ANALOG_SOURCE_L: - ext_changes.value |= CPCAP_BIT_MONO_EXT1 | - CPCAP_BIT_PGA_IN_L_SW; - break; - case CPCAP_AUDIO_ANALOG_SOURCE_R: - ext_changes.value |= CPCAP_BIT_MONO_EXT1 | - CPCAP_BIT_PGA_IN_R_SW; - break; - default: - break; - } - - ext_changes.mask = ext_changes.value | prev_ext_data; - - prev_ext_data = ext_changes.value; - - logged_cpcap_write(state->cpcap, CPCAP_REG_RXEPOA, - ext_changes.value, ext_changes.mask); - } -} - -static void cpcap_audio_configure_input_gains( - struct cpcap_audio_state *state, - struct cpcap_audio_state *prev) -{ - if (state->input_gain != prev->input_gain) { - struct cpcap_regacc reg_changes = { 0 }; - unsigned int temp_input_gain = state->input_gain & 0x0000001F; - - reg_changes.value |= ((temp_input_gain << 5) | temp_input_gain); - - reg_changes.mask = 0x3FF; - - logged_cpcap_write(state->cpcap, CPCAP_REG_TXMP, - reg_changes.value, reg_changes.mask); - } -} - -static void cpcap_audio_configure_output_gains( - struct cpcap_audio_state *state, - struct cpcap_audio_state *prev) -{ - if (state->output_gain != prev->output_gain) { - struct cpcap_regacc reg_changes = { 0 }; - unsigned int temp_output_gain = state->output_gain & 0x0000000F; - - reg_changes.value |= - ((temp_output_gain << 2) | (temp_output_gain << 8) | - (temp_output_gain << 12)); - - reg_changes.mask = 0xFF3C; - - logged_cpcap_write(state->cpcap, CPCAP_REG_RXVC, - reg_changes.value, reg_changes.mask); - } -} - -static void cpcap_audio_configure_output( - struct cpcap_audio_state *state, - struct cpcap_audio_state *prev) -{ - static unsigned int prev_aud_out_data; - - bool activate_ext_loudspeaker = false; - struct cpcap_regacc reg_changes = { 0 }; - - if (!is_output_changed(prev, state) && - !is_codec_changed(prev, state) && - !is_stdac_changed(prev, state)) - return; - - cpcap_audio_set_output_amp_switches(state); - - activate_ext_loudspeaker = cpcap_audio_set_bits_for_speaker( - state->codec_primary_speaker, - state->codec_primary_balance, - &(reg_changes.value)); - - activate_ext_loudspeaker = activate_ext_loudspeaker || - cpcap_audio_set_bits_for_speaker( - state->codec_secondary_speaker, - CPCAP_AUDIO_BALANCE_NEUTRAL, - &(reg_changes.value)); - - activate_ext_loudspeaker = activate_ext_loudspeaker || - cpcap_audio_set_bits_for_speaker( - state->stdac_primary_speaker, - state->stdac_primary_balance, - &(reg_changes.value)); - - activate_ext_loudspeaker = activate_ext_loudspeaker || - cpcap_audio_set_bits_for_speaker( - state->stdac_secondary_speaker, - CPCAP_AUDIO_BALANCE_NEUTRAL, - &(reg_changes.value)); - - activate_ext_loudspeaker = activate_ext_loudspeaker || - cpcap_audio_set_bits_for_speaker( - state->ext_primary_speaker, - state->ext_primary_balance, - &(reg_changes.value)); - - activate_ext_loudspeaker = activate_ext_loudspeaker || - cpcap_audio_set_bits_for_speaker( - state->ext_secondary_speaker, - CPCAP_AUDIO_BALANCE_NEUTRAL, - &(reg_changes.value)); - - reg_changes.mask = reg_changes.value | prev_aud_out_data; - - prev_aud_out_data = reg_changes.value; - - /* Sleep for 300ms if we are getting into a call to allow the switch to - * settle. If we don't do this, it causes a loud pop at the beginning - * of the call. - */ - if (state->rat_type == CPCAP_AUDIO_RAT_CDMA && - state->ext_primary_speaker != CPCAP_AUDIO_OUT_NONE && - prev->ext_primary_speaker == CPCAP_AUDIO_OUT_NONE) - msleep(300); - - logged_cpcap_write(state->cpcap, CPCAP_REG_RXOA, - reg_changes.value, reg_changes.mask); -} - -static inline bool codec_loopback_changed(struct cpcap_audio_state *new, - struct cpcap_audio_state *old) -{ - return (new->codec_mode != old->codec_mode) && - (new->codec_mode == CPCAP_AUDIO_CODEC_LOOPBACK || - old->codec_mode == CPCAP_AUDIO_CODEC_LOOPBACK); -} - -static void cpcap_audio_configure_input(struct cpcap_audio_state *state, - struct cpcap_audio_state *prev) -{ - static unsigned int prev_input_data = 0x0; - struct cpcap_regacc reg_changes = { 0 }; - - if (state->microphone == prev->microphone && - !codec_loopback_changed(state, prev)) - return; - - if (state->codec_mode == CPCAP_AUDIO_CODEC_LOOPBACK) - reg_changes.value |= CPCAP_BIT_DLM; - - if (prev->microphone == CPCAP_AUDIO_IN_HEADSET) - logged_cpcap_write(state->cpcap, CPCAP_REG_GPIO4, - 0, CPCAP_BIT_GPIO4DRV); - - switch (state->microphone) { - case CPCAP_AUDIO_IN_HANDSET: - pr_debug("%s: handset\n", __func__); - reg_changes.value |= CPCAP_BIT_MB_ON1R - | CPCAP_BIT_MIC1_MUX | CPCAP_BIT_MIC1_PGA_EN; - break; - - case CPCAP_AUDIO_IN_HEADSET: - pr_debug("%s: headset\n", __func__); - reg_changes.value |= CPCAP_BIT_HS_MIC_MUX - | CPCAP_BIT_MIC1_PGA_EN; - if (state->rat_type == CPCAP_AUDIO_RAT_CDMA) - logged_cpcap_write(state->cpcap, CPCAP_REG_GPIO4, - CPCAP_BIT_GPIO4DRV, CPCAP_BIT_GPIO4DRV); - break; - - case CPCAP_AUDIO_IN_EXT_BUS: - reg_changes.value |= CPCAP_BIT_EMU_MIC_MUX - | CPCAP_BIT_MIC1_PGA_EN; - break; - - case CPCAP_AUDIO_IN_AUX_INTERNAL: - reg_changes.value |= CPCAP_BIT_MB_ON1L - | CPCAP_BIT_MIC2_MUX | CPCAP_BIT_MIC2_PGA_EN; - break; - - case CPCAP_AUDIO_IN_DUAL_INTERNAL: - reg_changes.value |= CPCAP_BIT_MB_ON1R - | CPCAP_BIT_MIC1_MUX | CPCAP_BIT_MIC1_PGA_EN - | CPCAP_BIT_MB_ON1L | CPCAP_BIT_MIC2_MUX - | CPCAP_BIT_MIC2_PGA_EN; - break; - - case CPCAP_AUDIO_IN_DUAL_EXTERNAL: - reg_changes.value |= CPCAP_BIT_RX_R_ENCODE - | CPCAP_BIT_RX_L_ENCODE; - break; - - case CPCAP_AUDIO_IN_BT_MONO: - default: - reg_changes.value = 0; - break; - } - - reg_changes.mask = reg_changes.value | prev_input_data; - prev_input_data = reg_changes.value; - - logged_cpcap_write(state->cpcap, CPCAP_REG_TXI, - reg_changes.value, reg_changes.mask); -} - -static void cpcap_audio_configure_power(int power) -{ - static int previous_power = -1; - - pr_debug("%s() called with power= %d\n", __func__, power); - - if (power == previous_power) - return; - - if (IS_ERR_OR_NULL(audio_reg)) { - E("audio_reg not valid for regulator setup\n"); - return; - } - - if (power) { - pr_info("%s: regulator -> enable\n", __func__); - regulator_enable(audio_reg); - regulator_set_mode(audio_reg, REGULATOR_MODE_NORMAL); - mdelay(SLEEP_ACTIVATE_POWER_DELAY_MS); - } else { - pr_info("%s: regulator -> standby\n", __func__); - regulator_set_mode(audio_reg, REGULATOR_MODE_STANDBY); - regulator_disable(audio_reg); - } - - previous_power = power; -} - -void cpcap_audio_register_dump(struct cpcap_audio_state *state) -{ - unsigned short reg_val = 0; - - cpcap_regacc_read(state->cpcap, CPCAP_REG_VAUDIOC, ®_val); - printk(KERN_INFO "0x200[512] = %x\n", reg_val); - cpcap_regacc_read(state->cpcap, CPCAP_REG_CC, ®_val); - printk(KERN_INFO "0x201[513] = %x\n", reg_val); - cpcap_regacc_read(state->cpcap, CPCAP_REG_CDI, ®_val); - printk(KERN_INFO "0x202[514] = %x\n", reg_val); - cpcap_regacc_read(state->cpcap, CPCAP_REG_SDAC, ®_val); - printk(KERN_INFO "0x203[515] = %x\n", reg_val); - cpcap_regacc_read(state->cpcap, CPCAP_REG_SDACDI, ®_val); - printk(KERN_INFO "0x204[516] = %x\n", reg_val); - cpcap_regacc_read(state->cpcap, CPCAP_REG_TXI, ®_val); - printk(KERN_INFO "0x205[517] = %x\n", reg_val); - cpcap_regacc_read(state->cpcap, CPCAP_REG_TXMP, ®_val); - printk(KERN_INFO "0x206[518] = %x\n", reg_val); - cpcap_regacc_read(state->cpcap, CPCAP_REG_RXOA, ®_val); - printk(KERN_INFO "0x207[519] = %x\n", reg_val); - cpcap_regacc_read(state->cpcap, CPCAP_REG_RXVC, ®_val); - printk(KERN_INFO "0x208[520] = %x\n", reg_val); - cpcap_regacc_read(state->cpcap, CPCAP_REG_RXCOA, ®_val); - printk(KERN_INFO "0x209[521] = %x\n", reg_val); - cpcap_regacc_read(state->cpcap, CPCAP_REG_RXSDOA, ®_val); - printk(KERN_INFO "0x20A[522] = %x\n", reg_val); - cpcap_regacc_read(state->cpcap, CPCAP_REG_RXEPOA, ®_val); - printk(KERN_INFO "0x20B[523] = %x\n", reg_val); - cpcap_regacc_read(state->cpcap, CPCAP_REG_RXLL, ®_val); - printk(KERN_INFO "0x20C[524] = %x\n", reg_val); - cpcap_regacc_read(state->cpcap, CPCAP_REG_A2LA, ®_val); - printk(KERN_INFO "0x20D[525] = %x\n", reg_val); -} - -static inline bool should_power_on(struct cpcap_audio_state *state) -{ - if (state->codec_mode != CPCAP_AUDIO_CODEC_OFF && - state->codec_mode != CPCAP_AUDIO_CODEC_CLOCK_ONLY) - return true; - - if (state->stdac_mode != CPCAP_AUDIO_STDAC_OFF) - return true; - - if (state->codec_primary_speaker != CPCAP_AUDIO_OUT_NONE && - state->codec_primary_speaker != - CPCAP_AUDIO_OUT_BT_MONO) - return true; - - if (state->stdac_primary_speaker != CPCAP_AUDIO_OUT_NONE) - return true; - - if (state->ext_primary_speaker != CPCAP_AUDIO_OUT_NONE) - return true; - - if (state->microphone != CPCAP_AUDIO_IN_NONE && - state->microphone != CPCAP_AUDIO_IN_BT_MONO) - return true; - - return false; -} - -void cpcap_audio_set_audio_state(struct cpcap_audio_state *state) -{ - bool power_on; - struct cpcap_audio_state *prev = ¤t_state; - - if (state->codec_mute == CPCAP_AUDIO_CODEC_BYPASS_LOOP) - state->codec_mode = CPCAP_AUDIO_CODEC_ON; - - if (state->codec_mode == CPCAP_AUDIO_CODEC_OFF || - state->codec_mode == CPCAP_AUDIO_CODEC_CLOCK_ONLY || - state->rat_type == CPCAP_AUDIO_RAT_CDMA) - state->codec_mute = CPCAP_AUDIO_CODEC_MUTE; - else - state->codec_mute = CPCAP_AUDIO_CODEC_UNMUTE; - - if (state->stdac_mode != CPCAP_AUDIO_STDAC_ON) - state->stdac_mute = CPCAP_AUDIO_STDAC_MUTE; - else - state->stdac_mute = CPCAP_AUDIO_STDAC_UNMUTE; - - if (state->stdac_mode == CPCAP_AUDIO_STDAC_CLOCK_ONLY) - state->stdac_mode = CPCAP_AUDIO_STDAC_ON; - - power_on = should_power_on(state); - - if (power_on) - cpcap_audio_configure_power(1); - - if (is_speaker_turning_off(state, prev)) - cpcap_audio_configure_output(state, prev); - - if (is_codec_changed(state, prev) || is_stdac_changed(state, prev)) { - int codec_mute = state->codec_mute; - int stdac_mute = state->stdac_mute; - - state->codec_mute = CPCAP_AUDIO_CODEC_MUTE; - state->stdac_mute = CPCAP_AUDIO_STDAC_MUTE; - - cpcap_audio_configure_aud_mute(state, prev); - - prev->codec_mute = state->codec_mute; - prev->stdac_mute = state->stdac_mute; - - state->codec_mute = codec_mute; - state->stdac_mute = stdac_mute; - - cpcap_audio_configure_codec(state, prev); - cpcap_audio_configure_stdac(state, prev); - } - - cpcap_audio_configure_analog_source(state, prev); - - cpcap_audio_configure_input(state, prev); - - cpcap_audio_configure_input_gains(state, prev); - - cpcap_audio_configure_output(state, prev); - - cpcap_audio_configure_output_gains(state, prev); - - cpcap_audio_configure_aud_mute(state, prev); - - if (!power_on) - cpcap_audio_configure_power(0); - - current_state = *state; -} - -int cpcap_audio_init(struct cpcap_audio_state *state, const char *regulator) -{ - logged_cpcap_write(state->cpcap, CPCAP_REG_CC, 0, 0xFFFF); - logged_cpcap_write(state->cpcap, CPCAP_REG_CDI, 0, 0xBFFF); - logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, 0, 0xFFF); - logged_cpcap_write(state->cpcap, CPCAP_REG_SDACDI, 0, 0x3FFF); - logged_cpcap_write(state->cpcap, CPCAP_REG_TXI, 0, 0xFDF); - logged_cpcap_write(state->cpcap, CPCAP_REG_TXMP, 0, 0xFFF); - logged_cpcap_write(state->cpcap, CPCAP_REG_RXOA, 0, 0x1FF); - /* logged_cpcap_write(state->cpcap, CPCAP_REG_RXVC, 0, 0xFFF); */ - logged_cpcap_write(state->cpcap, CPCAP_REG_RXCOA, 0, 0x7FF); - logged_cpcap_write(state->cpcap, CPCAP_REG_RXSDOA, 0, 0x1FFF); - logged_cpcap_write(state->cpcap, CPCAP_REG_RXEPOA, 0, 0x7FFF); - - /* Use free running clock for amplifiers */ - logged_cpcap_write(state->cpcap, CPCAP_REG_A2LA, - CPCAP_BIT_A2_FREE_RUN, - CPCAP_BIT_A2_FREE_RUN); - - logged_cpcap_write(state->cpcap, CPCAP_REG_GPIO4, - CPCAP_BIT_GPIO4DIR, CPCAP_BIT_GPIO4DIR); - - audio_reg = regulator_get(NULL, regulator); - - if (IS_ERR(audio_reg)) { - E("could not get regulator for audio\n"); - return PTR_ERR(audio_reg); - } - - return 0; -} - -int cpcap_set_volume(struct cpcap_device *cpcap, unsigned volume) -{ - volume &= 0xF; - volume = volume << 12 | volume << 8; - return cpcap_regacc_write(cpcap, CPCAP_REG_RXVC, volume, 0xFF00); -} diff --git a/drivers/mfd/cpcap-audio.c b/drivers/mfd/cpcap-audio.c new file mode 100644 index 000000000000..d335083899bf --- /dev/null +++ b/drivers/mfd/cpcap-audio.c @@ -0,0 +1,351 @@ +/* drivers/mfd/cpcap-audio.c + * + * Copyright (C) 2010 Google, Inc. + * + * Author: + * Iliyan Malchev + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static struct cpcap_device *cpcap; +static struct cpcap_audio_platform_data *pdata; +static unsigned current_output = CPCAP_AUDIO_OUT_SPEAKER; +static unsigned current_input = -1U; /* none */ +static unsigned current_volume = CPCAP_AUDIO_OUT_VOL_MAX; +static unsigned current_in_volume = CPCAP_AUDIO_IN_VOL_MAX; + +static int cpcap_audio_set(const struct cpcap_audio_path *path, bool on) +{ + int len, rc; + const struct cpcap_audio_config_table *entry; + + pr_info("%s: %s %s\n", __func__, path->name, on ? "on" : "off"); + + if (!path) { + pr_info("%s: no path\n", __func__); + return -ENOSYS; + } + + if (path->gpio >= 0) { + pr_info("%s: %s: enable gpio %d\n", __func__, + path->name, path->gpio); + rc = gpio_direction_output(path->gpio, on); + if (rc) + pr_err("%s: could not set gpio %d to %d\n", __func__, + path->gpio, on); + } + + if (!on) + return 0; + if (!path->table) { + pr_info("%s: no config table for path %s\n", __func__, + path->name); + return -ENOSYS; + } + + entry = path->table; + len = path->table_len; + while (len--) { + u16 val = entry->val | (pdata->master ? 0 : entry->slave_or); + int rc = cpcap_regacc_write(cpcap, + entry->reg, + val, + entry->mask); + if (rc) { + pr_err("%s: cpcap_regacc_write %d %x/%x %x failed: %d\n", + __func__, + entry->reg, + entry->val, + entry->slave_or, + entry->mask, rc); + rc = -EIO; + } + entry++; + } + + return 0; +} + +static int cpcap_set_volume(struct cpcap_device *cpcap, unsigned volume) +{ + pr_info("%s\n", __func__); + volume &= 0xF; + volume = volume << 12 | volume << 8; + return cpcap_regacc_write(cpcap, CPCAP_REG_RXVC, volume, 0xFF00); +} + + +static int cpcap_set_mic_volume(struct cpcap_device *cpcap, unsigned volume) +{ + pr_info("%s\n", __func__); + volume &= 0x1F; + /* set the same volume for mic1 and mic2 */ + volume = volume << 5 | volume; + return cpcap_regacc_write(cpcap, CPCAP_REG_TXMP, volume, 0x3FF); +} + +static int cpcap_audio_ctl_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int cpcap_audio_ctl_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static DEFINE_MUTEX(cpcap_lock); + +static long cpcap_audio_ctl_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int rc = 0; + struct cpcap_audio_output out; + + mutex_lock(&cpcap_lock); + + switch (cmd) { + case CPCAP_AUDIO_OUT_SET_OUTPUT: + if (copy_from_user(&out, (const void __user *)arg, + sizeof(out))) { + rc = -EFAULT; + goto done; + } + if (out.id > CPCAP_AUDIO_OUT_MAX) { + pr_err("%s: invalid audio-output selector %d\n", + __func__, out.id); + rc = -EINVAL; + goto done; + } + switch (out.id) { + case CPCAP_AUDIO_OUT_SPEAKER: + pr_info("%s: setting output path to %s\n", __func__, + pdata->speaker->name); + cpcap_audio_set(pdata->headset, 0); + cpcap_audio_set(pdata->speaker, out.on); + break; + case CPCAP_AUDIO_OUT_HEADSET: + pr_info("%s: setting output path to %s\n", __func__, + pdata->headset->name); + cpcap_audio_set(pdata->speaker, 0); + cpcap_audio_set(pdata->headset, out.on); + break; + } + current_output = out.id; + break; + case CPCAP_AUDIO_OUT_GET_OUTPUT: + if (copy_to_user((void __user *)arg, ¤t_output, + sizeof(unsigned int))) + rc = -EFAULT; + break; + case CPCAP_AUDIO_IN_SET_INPUT: + if (arg > CPCAP_AUDIO_IN_MAX && arg != -1UL) { + pr_err("%s: invalid audio input selector %ld\n", + __func__, arg); + rc = -EINVAL; + goto done; + } + switch (arg) { + case -1UL: + pr_info("%s: turning off input path\n", __func__); + cpcap_audio_set(pdata->mic1, 0); + cpcap_audio_set(pdata->mic2, 0); + break; + case CPCAP_AUDIO_IN_MIC1: + pr_info("%s: setting input path to %s\n", __func__, + pdata->mic1->name); + cpcap_audio_set(pdata->mic2, 0); + cpcap_audio_set(pdata->mic1, 1); + break; + case CPCAP_AUDIO_IN_MIC2: + pr_info("%s: setting input path to %s\n", __func__, + pdata->mic2->name); + cpcap_audio_set(pdata->mic1, 0); + cpcap_audio_set(pdata->mic2, 1); + break; + } + current_input = arg; + break; + case CPCAP_AUDIO_IN_GET_INPUT: + if (copy_to_user((void __user *)arg, ¤t_input, + sizeof(unsigned int))) + rc = -EFAULT; + break; + case CPCAP_AUDIO_OUT_SET_VOLUME: + if (arg > CPCAP_AUDIO_OUT_VOL_MAX) { + pr_err("%s: invalid audio volume %ld\n", + __func__, arg); + rc = -EINVAL; + goto done; + } + rc = cpcap_set_volume(cpcap, (unsigned)arg); + if (rc < 0) { + pr_err("%s: could not set audio volume to %ld: %d\n", + __func__, arg, rc); + goto done; + } + current_volume = arg; + break; + case CPCAP_AUDIO_IN_SET_VOLUME: + if (arg > CPCAP_AUDIO_IN_VOL_MAX) { + pr_err("%s: invalid audio-input volume %ld\n", + __func__, arg); + rc = -EINVAL; + goto done; + } + rc = cpcap_set_mic_volume(cpcap, (unsigned)arg); + if (rc < 0) { + pr_err("%s: could not set audio-input"\ + " volume to %ld: %d\n", __func__, arg, rc); + goto done; + } + current_in_volume = arg; + break; + case CPCAP_AUDIO_OUT_GET_VOLUME: + if (copy_to_user((void __user *)arg, ¤t_volume, + sizeof(unsigned int))) { + rc = -EFAULT; + goto done; + } + break; + case CPCAP_AUDIO_IN_GET_VOLUME: + if (copy_to_user((void __user *)arg, ¤t_in_volume, + sizeof(unsigned int))) { + rc = -EFAULT; + goto done; + } + break; + } + +done: + mutex_unlock(&cpcap_lock); + return rc; +} + +static const struct file_operations cpcap_audio_ctl_fops = { + .open = cpcap_audio_ctl_open, + .release = cpcap_audio_ctl_release, + .unlocked_ioctl = cpcap_audio_ctl_ioctl, +}; + +static struct miscdevice cpcap_audio_ctl = { + .name = "audio_ctl", + .minor = MISC_DYNAMIC_MINOR, + .fops = &cpcap_audio_ctl_fops, +}; + +static int cpcap_audio_probe(struct platform_device *pdev) +{ + int rc; + struct regulator *audio_reg; + + pr_info("%s\n", __func__); + + cpcap = platform_get_drvdata(pdev); + BUG_ON(!cpcap); + + pdata = pdev->dev.platform_data; + BUG_ON(!pdata); + + audio_reg = regulator_get(NULL, "vaudio"); + if (IS_ERR(audio_reg)) { + rc = PTR_ERR(audio_reg); + pr_err("%s: could not get vaudio regulator: %d\n", __func__, + rc); + return rc; + } + + rc = regulator_enable(audio_reg); + if (rc) { + pr_err("%s: failed to enable vaudio regulator: %d\n", __func__, + rc); + goto fail; + } + + if (pdata->speaker->gpio >= 0) { + tegra_gpio_enable(pdata->speaker->gpio); + rc = gpio_request(pdata->speaker->gpio, pdata->speaker->name); + if (rc) { + pr_err("%s: could not get speaker GPIO %d: %d\n", + __func__, pdata->speaker->gpio, rc); + goto fail1; + } + } + + if (pdata->headset->gpio >= 0) { + tegra_gpio_enable(pdata->headset->gpio); + rc = gpio_request(pdata->headset->gpio, pdata->headset->name); + if (rc) { + pr_err("%s: could not get headset GPIO %d: %d\n", + __func__, pdata->headset->gpio, rc); + goto fail2; + } + } + + cpcap_audio_set(pdata->speaker, 1); + cpcap_set_volume(cpcap, current_volume); + cpcap_set_mic_volume(cpcap, current_in_volume); + + rc = misc_register(&cpcap_audio_ctl); + if (rc < 0) { + pr_err("%s: failed to register misc device: %d\n", __func__, + rc); + goto fail3; + } + + return rc; + +fail3: + if (pdata->headset->gpio >= 0) + gpio_free(pdata->headset->gpio); +fail2: + if (pdata->speaker->gpio >= 0) + gpio_free(pdata->speaker->gpio); +fail1: + regulator_disable(audio_reg); +fail: + regulator_put(audio_reg); + return rc; +} + +static struct platform_driver cpcap_audio_driver = { + .probe = cpcap_audio_probe, + .driver = { + .name = "cpcap_audio", + .owner = THIS_MODULE, + }, +}; + +static int __init cpcap_audio_init(void) +{ + return cpcap_driver_register(&cpcap_audio_driver); +} + +module_init(cpcap_audio_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/tegra-cpcap-audio.c b/drivers/mfd/tegra-cpcap-audio.c deleted file mode 100644 index 5a78d1483575..000000000000 --- a/drivers/mfd/tegra-cpcap-audio.c +++ /dev/null @@ -1,356 +0,0 @@ -/* drivers/mfd/cpcap-audio.c - * - * Copyright (C) 2010 Google, Inc. - * - * Author: - * Iliyan Malchev - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static struct cpcap_device *cpcap; -static struct cpcap_audio_platform_data *pdata; -static unsigned current_output = CPCAP_AUDIO_OUT_SPEAKER; -static unsigned current_input = -1U; /* none */ -static unsigned current_volume = CPCAP_AUDIO_OUT_VOL_MAX; -static unsigned current_in_volume = CPCAP_AUDIO_IN_VOL_MAX; - -static int cpcap_set_volume(struct cpcap_device *cpcap, unsigned volume) -{ - pr_info("%s\n", __func__); - volume &= 0xF; - volume = volume << 12 | volume << 8; - return cpcap_regacc_write(cpcap, CPCAP_REG_RXVC, volume, 0xFF00); -} - - -static int cpcap_set_mic_volume(struct cpcap_device *cpcap, unsigned volume) -{ - pr_info("%s\n", __func__); - volume &= 0x1F; - /* set the same volume for mic1 and mic2 */ - volume = volume << 5 | volume; - return cpcap_regacc_write(cpcap, CPCAP_REG_TXMP, volume, 0x3FF); -} - -static int cpcap_audio_ctl_open(struct inode *inode, struct file *file) -{ - return 0; -} - -static int cpcap_audio_ctl_release(struct inode *inode, struct file *file) -{ - return 0; -} - -static DEFINE_MUTEX(cpcap_lock); - -static long cpcap_audio_ctl_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - int rc = 0; - struct cpcap_audio_stream in, out; - - mutex_lock(&cpcap_lock); - - switch (cmd) { - case CPCAP_AUDIO_OUT_SET_OUTPUT: - if (copy_from_user(&out, (const void __user *)arg, - sizeof(out))) { - rc = -EFAULT; - goto done; - } - if (out.id > CPCAP_AUDIO_OUT_MAX) { - pr_err("%s: invalid audio-output selector %d\n", - __func__, out.id); - rc = -EINVAL; - goto done; - } - switch (out.id) { - case CPCAP_AUDIO_OUT_SPEAKER: - pr_info("%s: setting output path to speaker\n", - __func__); - pdata->state->stdac_primary_speaker = - CPCAP_AUDIO_OUT_NONE; - cpcap_audio_set_audio_state(pdata->state); - if (!out.on) { - if (pdata->speaker_gpio >= 0) - gpio_direction_output( - pdata->speaker_gpio, 0); - break; - } - - pr_info("%s: enable speaker\n", __func__); - - pdata->state->stdac_primary_speaker = - CPCAP_AUDIO_OUT_LOUDSPEAKER; - gpio_direction_output(pdata->headset_gpio, 0); - gpio_direction_output(pdata->speaker_gpio, 1); - break; - case CPCAP_AUDIO_OUT_HEADSET: - pr_info("%s: setting output path to headset\n", - __func__); - pdata->state->stdac_primary_speaker = - CPCAP_AUDIO_OUT_NONE; - cpcap_audio_set_audio_state(pdata->state); - if (!out.on) { - if (pdata->headset_gpio >= 0) - gpio_direction_output( - pdata->headset_gpio, 0); - break; - } - pdata->state->stdac_primary_speaker = - CPCAP_AUDIO_OUT_STEREO_HEADSET; - cpcap_audio_set_audio_state(pdata->state); - gpio_direction_output(pdata->speaker_gpio, 0); - gpio_direction_output(pdata->headset_gpio, 1); - break; - case CPCAP_AUDIO_OUT_HEADSET_AND_SPEAKER: - pr_info("%s: setting output path to " - "headset + speaker\n", __func__); - pdata->state->stdac_primary_speaker = - CPCAP_AUDIO_OUT_NONE; - cpcap_audio_set_audio_state(pdata->state); - if (!out.on) { - if (pdata->headset_gpio >= 0) - gpio_direction_output( - pdata->headset_gpio, 0); - gpio_direction_output( - pdata->speaker_gpio, 0); - break; - } - pdata->state->stdac_primary_speaker = - CPCAP_AUDIO_OUT_STEREO_HEADSET; - cpcap_audio_set_audio_state(pdata->state); - gpio_direction_output(pdata->speaker_gpio, 1); - gpio_direction_output(pdata->headset_gpio, 1); - break; - } - current_output = out.id; - break; - case CPCAP_AUDIO_OUT_GET_OUTPUT: - if (copy_to_user((void __user *)arg, ¤t_output, - sizeof(unsigned int))) - rc = -EFAULT; - break; - case CPCAP_AUDIO_IN_SET_INPUT: - if (copy_from_user(&in, (const void __user *)arg, - sizeof(in))) { - rc = -EFAULT; - goto done; - } - - if (in.id > CPCAP_AUDIO_IN_MAX) { - pr_err("%s: invalid audio input selector %d\n", - __func__, in.id); - rc = -EINVAL; - goto done; - } - - pr_info("%s: muting current input before switch\n", __func__); - - pdata->state->microphone = CPCAP_AUDIO_IN_NONE; - pdata->state->codec_mute = CPCAP_AUDIO_CODEC_MUTE; - pdata->state->stdac_mute = CPCAP_AUDIO_STDAC_MUTE; - pdata->state->codec_mode = CPCAP_AUDIO_CODEC_OFF; - pdata->state->stdac_mode = CPCAP_AUDIO_STDAC_OFF; - cpcap_audio_set_audio_state(pdata->state); - - if (!in.on) - break; - - pdata->state->codec_mute = CPCAP_AUDIO_CODEC_UNMUTE; - pdata->state->stdac_mute = CPCAP_AUDIO_STDAC_UNMUTE; - pdata->state->codec_mode = CPCAP_AUDIO_CODEC_ON; - pdata->state->stdac_mode = CPCAP_AUDIO_STDAC_ON; - - switch (in.id) { - case CPCAP_AUDIO_IN_MIC1: - pr_info("%s: setting input path to on-board mic\n", - __func__); - pdata->state->microphone = CPCAP_AUDIO_IN_HANDSET; - cpcap_audio_set_audio_state(pdata->state); - cpcap_audio_register_dump(pdata->state); - break; - case CPCAP_AUDIO_IN_MIC2: - pr_info("%s: setting input path to headset mic\n", - __func__); - pdata->state->microphone = CPCAP_AUDIO_IN_HEADSET; - cpcap_audio_set_audio_state(pdata->state); - cpcap_audio_register_dump(pdata->state); - break; - } - current_input = arg; - break; - case CPCAP_AUDIO_IN_GET_INPUT: - if (copy_to_user((void __user *)arg, ¤t_input, - sizeof(unsigned int))) - rc = -EFAULT; - break; - case CPCAP_AUDIO_OUT_SET_VOLUME: - if (arg > CPCAP_AUDIO_OUT_VOL_MAX) { - pr_err("%s: invalid audio volume %ld\n", - __func__, arg); - rc = -EINVAL; - goto done; - } - rc = cpcap_set_volume(cpcap, (unsigned)arg); - if (rc < 0) { - pr_err("%s: could not set audio volume to %ld: %d\n", - __func__, arg, rc); - goto done; - } - current_volume = arg; - break; - case CPCAP_AUDIO_IN_SET_VOLUME: - if (arg > CPCAP_AUDIO_IN_VOL_MAX) { - pr_err("%s: invalid audio-input volume %ld\n", - __func__, arg); - rc = -EINVAL; - goto done; - } - rc = cpcap_set_mic_volume(cpcap, (unsigned)arg); - if (rc < 0) { - pr_err("%s: could not set audio-input"\ - " volume to %ld: %d\n", __func__, arg, rc); - goto done; - } - current_in_volume = arg; - break; - case CPCAP_AUDIO_OUT_GET_VOLUME: - if (copy_to_user((void __user *)arg, ¤t_volume, - sizeof(unsigned int))) { - rc = -EFAULT; - goto done; - } - break; - case CPCAP_AUDIO_IN_GET_VOLUME: - if (copy_to_user((void __user *)arg, ¤t_in_volume, - sizeof(unsigned int))) { - rc = -EFAULT; - goto done; - } - break; - } - -done: - mutex_unlock(&cpcap_lock); - return rc; -} - -static const struct file_operations cpcap_audio_ctl_fops = { - .open = cpcap_audio_ctl_open, - .release = cpcap_audio_ctl_release, - .unlocked_ioctl = cpcap_audio_ctl_ioctl, -}; - -static struct miscdevice cpcap_audio_ctl = { - .name = "audio_ctl", - .minor = MISC_DYNAMIC_MINOR, - .fops = &cpcap_audio_ctl_fops, -}; - -static int cpcap_audio_probe(struct platform_device *pdev) -{ - int rc; - - pr_info("%s\n", __func__); - - cpcap = platform_get_drvdata(pdev); - BUG_ON(!cpcap); - - pdata = pdev->dev.platform_data; - BUG_ON(!pdata); - - if (pdata->speaker_gpio >= 0) { - tegra_gpio_enable(pdata->speaker_gpio); - rc = gpio_request(pdata->speaker_gpio, "speaker"); - if (rc) { - pr_err("%s: could not get speaker GPIO %d: %d\n", - __func__, pdata->speaker_gpio, rc); - goto fail1; - } - } - - if (pdata->headset_gpio >= 0) { - tegra_gpio_enable(pdata->headset_gpio); - rc = gpio_request(pdata->headset_gpio, "headset"); - if (rc) { - pr_err("%s: could not get headset GPIO %d: %d\n", - __func__, pdata->headset_gpio, rc); - goto fail2; - } - } - - pdata->state->cpcap = cpcap; - if (cpcap_audio_init(pdata->state, pdata->regulator)) - goto fail3; - cpcap_audio_register_dump(pdata->state); - - pdata->state->stdac_mode = CPCAP_AUDIO_STDAC_ON; - cpcap_audio_set_audio_state(pdata->state); - cpcap_audio_register_dump(pdata->state); - - rc = misc_register(&cpcap_audio_ctl); - if (rc < 0) { - pr_err("%s: failed to register misc device: %d\n", __func__, - rc); - goto fail3; - } - - return rc; - -fail3: - if (pdata->headset_gpio >= 0) - gpio_free(pdata->headset_gpio); -fail2: - if (pdata->headset_gpio >= 0) - tegra_gpio_disable(pdata->headset_gpio); - if (pdata->speaker_gpio >= 0) - gpio_free(pdata->speaker_gpio); -fail1: - if (pdata->speaker_gpio >= 0) - tegra_gpio_disable(pdata->speaker_gpio); - return rc; -} - -static struct platform_driver cpcap_audio_driver = { - .probe = cpcap_audio_probe, - .driver = { - .name = "cpcap_audio", - .owner = THIS_MODULE, - }, -}; - -static int __init tegra_cpcap_audio_init(void) -{ - return cpcap_driver_register(&cpcap_audio_driver); -} - -module_init(tegra_cpcap_audio_init); -MODULE_LICENSE("GPL"); diff --git a/include/linux/cpcap_audio.h b/include/linux/cpcap_audio.h index 3d3766e03858..50097231b276 100644 --- a/include/linux/cpcap_audio.h +++ b/include/linux/cpcap_audio.h @@ -23,18 +23,17 @@ #define CPCAP_AUDIO_MAGIC 'c' -#define CPCAP_AUDIO_OUT_SPEAKER 0 -#define CPCAP_AUDIO_OUT_HEADSET 1 -#define CPCAP_AUDIO_OUT_HEADSET_AND_SPEAKER 2 -#define CPCAP_AUDIO_OUT_MAX 2 - -struct cpcap_audio_stream { - unsigned id; /* e.g., CPCAP_AUDIO_OUT_SPEAKER or CPCAP_AUDIO_IN_MIC1 */ - int on; /* enable/disable for output, unmute/mute for input */ +#define CPCAP_AUDIO_OUT_SPEAKER 0 +#define CPCAP_AUDIO_OUT_HEADSET 1 +#define CPCAP_AUDIO_OUT_MAX 1 + +struct cpcap_audio_output { + int id; /* e.g., CPCAP_AUDIO_OUT_SPEAKER */ + int on; }; #define CPCAP_AUDIO_OUT_SET_OUTPUT _IOW(CPCAP_AUDIO_MAGIC, 0, \ - const struct cpcap_audio_stream *) + struct cpcap_audio_output *) #define CPCAP_AUDIO_OUT_VOL_MIN 0 #define CPCAP_AUDIO_OUT_VOL_MAX 15 @@ -50,11 +49,9 @@ struct cpcap_audio_stream { #define CPCAP_AUDIO_IN_MIC2 1 #define CPCAP_AUDIO_IN_MAX 1 -#define CPCAP_AUDIO_IN_SET_INPUT _IOW(CPCAP_AUDIO_MAGIC, 4, \ - const struct cpcap_audio_stream *) +#define CPCAP_AUDIO_IN_SET_INPUT _IOW(CPCAP_AUDIO_MAGIC, 4, unsigned int) -#define CPCAP_AUDIO_IN_GET_INPUT _IOR(CPCAP_AUDIO_MAGIC, 5, \ - struct cpcap_audio_stream *) +#define CPCAP_AUDIO_IN_GET_INPUT _IOR(CPCAP_AUDIO_MAGIC, 5, unsigned int *) #define CPCAP_AUDIO_IN_VOL_MIN 0 #define CPCAP_AUDIO_IN_VOL_MAX 31