"LA.UM.9.15.r1-07300-KAMORTA.QSSI13.0" * tag 'LA.UM.9.15.r1-07300-KAMORTA.QSSI13.0' of https://git.codelinaro.org/clo/la/platform/vendor/opensource/audio-kernel: ASoC: msm-pcm-q6-v2: Add dsp buf check ASoC: rouleur-mbhc: Enhance impedance calculation logic ASoC: rouleur-mbhc: Fix pop noise heard when headset insertion asoc: wsa881x: Fix to set the correct volume level soc: swr-mstr-ctrl: remove FIFO_Flush for overflow asoc: Add routing control for qrb5165 BT HFP usecase soc: swr-mstr: Store and compare dev_addr along with dev_num Asoc: fix integer overflow for long duration offload playback asoc: Correct the range of dev_token for usb headset. asoc: pcm-noirq: set substream state to disconnect when ssr happens soc: pinctrl-lpi-legacy : Add nullptr check asoc: msm-pcm-routing: Assign default topology when app_type is zero asoc: notify dp driver after disp codec probe asoc: codecs: fix race condition of core vote and reg access ASoC: wcd937x: Add check for ULP irrespective of the Class asoc: codecs: Add nullptr check ASoC: wcd937x: Update QCRG sequence for wcd937x asoc: changes to fix KW errors. asoc: changes to fix KW errors. ASoC: pcm-routing: Add WSA VI sense macro to support capture ASoC: wcd937x: Update EAR PA CnP FSM sequence soc: swr-mstr: update component and interrupt enable sequence ASoC: wcd937x: Update EAR PA CnP FSM sequence soc: add check condition before enabling irq ASoC: wcd937x: Add change for LDOL VOUT accuracy calibration ASoC: dsp: Synchronise adm commands ASoC: wcd937x: Add change to micbias reg for new tanggu fab id ASoC: wcd937x: Update register value for new fab id for tanggu dsp:q6afe: Resolve crash in q6afe_get_avcs_modules ASoC: wcd937x: Change resistor divider output for hph if fab id is enabled dsp: adm: add to check output/input channel value asoc: Parse wcd-datalane-mismatch property to update rx frame config for khaje asoc: wcd-cpe: Set the dma_mask for cpe_device asoc: Parse wcd-datalane-mismatch property to update rx frame config for khaje ASoC: msm8952: Defer until pcm voice probe done q6afe: Fix out of bound access of clkinfo_per_port asoc: Register CDC_DMA interface only if enabled config: sdm450: Disable CDC_DMA interfaces asoc: codecs: add null check before access asoc: fix KW issue of using uninitialized variable audio-kernel: enable wsa883x compilation on qrb5165 ASoC: Enable wsa881x-temp-sensor for bengal ASoC: msm8952: avoid static route between cpu and codec dai asoc: codecs: Fix LPASS register access during bootup ASoC: wcd: Add check to stop invalid memory access afe: release codec port when afe starts failed ASoC: Changes to enable codec clk for wcd9335 Asoc: check for invalid voice session id SoC: codecs: Fix slim_tx port configuration for wcd9335 ASoC: Get the component handle for cpe and tasha ASoC: wcd937x: Change vbg fine voltage to 0.5V for wcd937x second source audio-kernel: enable wsa883x compilation on sxr2130 dsp: fix out of bound access for cal_data size dsp: update size check for set/get VI param function config: sdm450: Disable TDM and AUXPCM interfaces asoc: msm_sdw: Revert adsp ready check for read/write ASoC: SDM660: Avoid static route between cpu and codec dai asoc: bolero: Update PCM_RATE based delay for amic ASoC: SDM660: Avoid static route between cpu and codec dai ASoC: Fix for SSR issue on msm8953 ASoC: error check for backend index and MCLK src Asoc: sdm450: Add capture support for Multimedia10 FE asoc: add proxy ports for call screening in machine driver asoc: msm: Fix compilation error when enable TDM and disable MI2S Makefile: Correct TARGET_SUPPORT entry for qrb5165 dsp: update size check for get VI param function asoc: codecs: add child devices after completing initialization asoc: bolero: Add core_vote before gfmux access dsp: Disable q6_pdr build for msm8937 and msm8953 asoc: Fixed wsa881x codec machine driver callback asoc: codec: enable the cpe on tasha Use proper TARGET_SUPPORT entry for sxr2130 asoc: wsa881x: Fix to set the correct volume level ASoC: ep92: Add external mclk support ASoC: msm: Add WCD interrupt config for SDA660 dsp: Unload the BT modules when APR handle is NULL asoc: Update copy_to_user to requested buffer size ASoC: Audio bringup changes for msm8937_32go. asoc: Add check to handle negative value passed for num_app_cfg_type ASoC: QCS405: Additional TDM samplerates and channels asoc: qcs405: Add support for TDM interface asoc: Add support for QUAT and SEN TDM interface asoc: qcs405: Update clk src string from dts dsp: Add support to update and store clk src values dsp: afe topology deregister ASoC: qcs405: Add external mclk support ASoC: Add external mclk mixer support dsp: Fix improper mutex unlock in afe close ASoC: wsa883x: Handle PA_ERR interrupt on WSA speaker ASoC: Add support to send voice UI port id to afe Revert "dsp: avtimer: Add adsp ready check before accessing avtimer registers" asoc: wsa881x: Fix crash while capturing swr_slv codec dump dsp: add change to enable preemption at cal_utils_dealloc_cal asoc: msm_sdw: Handle locking for mclk enable flag asoc: codecs: sdm660_cdc: Fix LPASS register access during PDR ASoC: lagoon: add support for CPS speaker protection dsp: add change to enable preemption at cal_utils_dealloc_cal ASoC: tx-macro: Allow regcache sync during clock enablement ASoC: wsa883x: add function to get swr device number dsp: add change to handle use-after-free in cal_utils_is_cal_stale soc: swr-mstr: Check if fifo available before bulk write asoc: bolero: control wakeup of swr_tx during clock setup soc: swr-mstr: Resolve swr overflow, underflow errors for wsa soc: swr-mstr: Update soundwire state to SSR during UP dsp: add change to fix use-after-free issue asoc: msm-pcm-q6-v2: Update memset for period size asoc: va-macro: Allow swr switch at powerup/shutdown ASoC: SDM660: Avoid static route between cpu and codec dai soc: Synchronize RESET event and lpi ops in legacy driver ASoC: codec: Enable wcd-spi driver compilation asoc: wcd-spi: Set the dma_mask for spi_device ASoC: audio-ext-clk: Add pmi clk support for tasha asoc: add null check for pcm pointer of snd_pcm_volume dsp: add afe function to send cps configuration asoc: Add 32bit support in meta i2s asoc: va-macro: Update widget order for VA_MCLK and VA_SWR_PWR dsp: Add param header size based on the instance id support dsp: q6core: Check q6core avs state to be modules ready ASoC: dsp: Synchronise adm and rtac commands asoc: codecs: Add support to dump rouleur swr slave regs asoc: sdm660: Correct the dev_id for hdmi backend. Revert "ASoC: codecs: handle device disconnect during SSR/PDR" ASoC: wsa883x: Update register sequence to reduce CnP asoc: sdm660: add proxy ports for call screening in machine driver soc: swr-mstr: Fix headset detect issue due to master.num_dev not updated soc: swr-mstr: Fix random headset detection issue on scuba dsp: Feedback path cfg to support 3rd party spkr protection algorithms. ASOC: SPV4 set correct number of speakers. ASoC: wsa883x: enable vbat adc filter config: kona: Disable MI2S, TDM and AUXPCM interfaces dsp: fix compilation issue in q6lsm_callback function asoc: Register widgets and intercons only when supported soc: swr-mstr: Fix random headset detection issue on scuba ASoC: codecs: handle device disconnect during SSR asoc: dsp: Fix possible invalid memory access due to race condition ASoC: rouleur-mbhc: Fix impedance detection issue on rouleur dsp: Add support for GET_PARAMS Conflicts: techpack/audio/asoc/kona.c techpack/audio/asoc/msm-pcm-routing-v2.c techpack/audio/dsp/q6core.c techpack/audio/dsp/q6lsm.c techpack/audio/include/dsp/audio_cal_utils.h techpack/audio/soc/swr-mstr-ctrl.c techpack/audio/soc/swr-mstr-ctrl.h Change-Id: Id77d1c17f36618427f929d7830200733a0e8b460
1988 lines
56 KiB
C
1988 lines
56 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (c) 2015-2018, 2020-2021, The Linux Foundation. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/of_gpio.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/module.h>
|
|
#include <sound/soc.h>
|
|
#include <sound/pcm.h>
|
|
#include <sound/pcm_params.h>
|
|
#include <dsp/q6core.h>
|
|
#include <dsp/audio_notifier.h>
|
|
#include "msm-pcm-routing-v2.h"
|
|
#include <asoc/sdm660-common.h>
|
|
#include <asoc/sdm660-external.h>
|
|
#include "codecs/wcd9335.h"
|
|
#include "codecs/wcd934x/wcd934x.h"
|
|
#include "codecs/wcd934x/wcd934x-mbhc.h"
|
|
#include <soc/qcom/socinfo.h>
|
|
|
|
#define SDM660_SPK_ON 1
|
|
#define SDM660_SPK_OFF 0
|
|
|
|
#define WCD9XXX_MBHC_DEF_BUTTONS 8
|
|
#define WCD9XXX_MBHC_DEF_RLOADS 5
|
|
#define CODEC_EXT_CLK_RATE 9600000
|
|
#define ADSP_STATE_READY_TIMEOUT_MS 3000
|
|
|
|
#define TLMM_CENTER_MPM_WAKEUP_INT_EN_0 0x03596000
|
|
#define LPI_GPIO_22_WAKEUP_VAL 0x00000002
|
|
|
|
#define TLMM_LPI_DIR_CONN_INTR1_CFG_APPS 0x0359D004
|
|
#define LPI_GPIO_22_INTR1_CFG_VAL 0x01
|
|
#define LPI_GPIO_22_INTR1_CFG_MASK 0x03
|
|
|
|
#define TLMM_LPI_GPIO_INTR_CFG1 0x0359B004
|
|
#define LPI_GPIO_INTR_CFG1_VAL 0x00000113
|
|
|
|
#define TLMM_LPI_GPIO22_CFG 0x15078040
|
|
#define LPI_GPIO22_CFG_VAL 0x0000009
|
|
|
|
#define TLMM_LPI_GPIO22_INOUT 0x179D1318
|
|
#define LPI_GPIO22_INOUT_VAL 0x0020000
|
|
|
|
|
|
#define WSA8810_NAME_1 "wsa881x.20170211"
|
|
#define WSA8810_NAME_2 "wsa881x.20170212"
|
|
#define SDM660_SOC_MSM_ID 0x13D
|
|
#define SDM660_SOC_SDA_ID 0x144
|
|
|
|
static int msm_ext_spk_control = 1;
|
|
static struct wcd_mbhc_config *wcd_mbhc_cfg_ptr;
|
|
|
|
struct msm_asoc_wcd93xx_codec {
|
|
void* (*get_afe_config_fn)(struct snd_soc_component *component,
|
|
enum afe_config_type config_type);
|
|
void (*mbhc_hs_detect_exit)(struct snd_soc_component *component);
|
|
};
|
|
|
|
static struct msm_asoc_wcd93xx_codec msm_codec_fn;
|
|
static struct platform_device *spdev;
|
|
|
|
static bool is_initial_boot;
|
|
|
|
static void *def_ext_mbhc_cal(void);
|
|
|
|
enum {
|
|
SLIM_RX_0 = 0,
|
|
SLIM_RX_1,
|
|
SLIM_RX_2,
|
|
SLIM_RX_3,
|
|
SLIM_RX_4,
|
|
SLIM_RX_5,
|
|
SLIM_RX_6,
|
|
SLIM_RX_7,
|
|
SLIM_RX_MAX,
|
|
};
|
|
|
|
enum {
|
|
SLIM_TX_0 = 0,
|
|
SLIM_TX_1,
|
|
SLIM_TX_2,
|
|
SLIM_TX_3,
|
|
SLIM_TX_4,
|
|
SLIM_TX_5,
|
|
SLIM_TX_6,
|
|
SLIM_TX_7,
|
|
SLIM_TX_8,
|
|
SLIM_TX_MAX,
|
|
};
|
|
|
|
/* Default configuration of slimbus channels */
|
|
static struct dev_config slim_rx_cfg[] = {
|
|
[SLIM_RX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
[SLIM_RX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
[SLIM_RX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
[SLIM_RX_3] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
[SLIM_RX_4] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
[SLIM_RX_5] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
[SLIM_RX_6] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
[SLIM_RX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
};
|
|
|
|
static struct dev_config slim_tx_cfg[] = {
|
|
[SLIM_TX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
[SLIM_TX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
[SLIM_TX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
[SLIM_TX_3] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
[SLIM_TX_4] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
[SLIM_TX_5] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
[SLIM_TX_6] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
[SLIM_TX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
[SLIM_TX_8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
|
|
};
|
|
|
|
static int msm_vi_feed_tx_ch = 2;
|
|
static const char *const slim_rx_ch_text[] = {"One", "Two"};
|
|
static const char *const slim_tx_ch_text[] = {"One", "Two", "Three", "Four",
|
|
"Five", "Six", "Seven",
|
|
"Eight"};
|
|
static const char *const vi_feed_ch_text[] = {"One", "Two"};
|
|
static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
|
|
"S32_LE"};
|
|
static char const *slim_sample_rate_text[] = {"KHZ_8", "KHZ_16",
|
|
"KHZ_32", "KHZ_44P1", "KHZ_48",
|
|
"KHZ_88P2", "KHZ_96", "KHZ_176P4",
|
|
"KHZ_192", "KHZ_352P8", "KHZ_384"};
|
|
static const char *const spk_function_text[] = {"Off", "On"};
|
|
static char const *bt_sample_rate_text[] = {"KHZ_8", "KHZ_16",
|
|
"KHZ_44P1", "KHZ_48",
|
|
"KHZ_88P2", "KHZ_96"};
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(spk_func_en, spk_function_text);
|
|
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text);
|
|
static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_chs, slim_rx_ch_text);
|
|
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_chs, slim_tx_ch_text);
|
|
static SOC_ENUM_SINGLE_EXT_DECL(slim_1_tx_chs, slim_tx_ch_text);
|
|
static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_chs, slim_rx_ch_text);
|
|
static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_chs, slim_rx_ch_text);
|
|
static SOC_ENUM_SINGLE_EXT_DECL(vi_feed_tx_chs, vi_feed_ch_text);
|
|
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_format, bit_format_text);
|
|
static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_format, bit_format_text);
|
|
static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_format, bit_format_text);
|
|
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_format, bit_format_text);
|
|
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_sample_rate, slim_sample_rate_text);
|
|
static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_sample_rate, slim_sample_rate_text);
|
|
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_sample_rate, slim_sample_rate_text);
|
|
static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_sample_rate, slim_sample_rate_text);
|
|
static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_sample_rate, slim_sample_rate_text);
|
|
static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text);
|
|
|
|
static int slim_get_sample_rate_val(int sample_rate)
|
|
{
|
|
int sample_rate_val = 0;
|
|
|
|
switch (sample_rate) {
|
|
case SAMPLING_RATE_8KHZ:
|
|
sample_rate_val = 0;
|
|
break;
|
|
case SAMPLING_RATE_16KHZ:
|
|
sample_rate_val = 1;
|
|
break;
|
|
case SAMPLING_RATE_32KHZ:
|
|
sample_rate_val = 2;
|
|
break;
|
|
case SAMPLING_RATE_44P1KHZ:
|
|
sample_rate_val = 3;
|
|
break;
|
|
case SAMPLING_RATE_48KHZ:
|
|
sample_rate_val = 4;
|
|
break;
|
|
case SAMPLING_RATE_88P2KHZ:
|
|
sample_rate_val = 5;
|
|
break;
|
|
case SAMPLING_RATE_96KHZ:
|
|
sample_rate_val = 6;
|
|
break;
|
|
case SAMPLING_RATE_176P4KHZ:
|
|
sample_rate_val = 7;
|
|
break;
|
|
case SAMPLING_RATE_192KHZ:
|
|
sample_rate_val = 8;
|
|
break;
|
|
case SAMPLING_RATE_352P8KHZ:
|
|
sample_rate_val = 9;
|
|
break;
|
|
case SAMPLING_RATE_384KHZ:
|
|
sample_rate_val = 10;
|
|
break;
|
|
default:
|
|
sample_rate_val = 4;
|
|
break;
|
|
}
|
|
return sample_rate_val;
|
|
}
|
|
|
|
static int slim_get_sample_rate(int value)
|
|
{
|
|
int sample_rate = 0;
|
|
|
|
switch (value) {
|
|
case 0:
|
|
sample_rate = SAMPLING_RATE_8KHZ;
|
|
break;
|
|
case 1:
|
|
sample_rate = SAMPLING_RATE_16KHZ;
|
|
break;
|
|
case 2:
|
|
sample_rate = SAMPLING_RATE_32KHZ;
|
|
break;
|
|
case 3:
|
|
sample_rate = SAMPLING_RATE_44P1KHZ;
|
|
break;
|
|
case 4:
|
|
sample_rate = SAMPLING_RATE_48KHZ;
|
|
break;
|
|
case 5:
|
|
sample_rate = SAMPLING_RATE_88P2KHZ;
|
|
break;
|
|
case 6:
|
|
sample_rate = SAMPLING_RATE_96KHZ;
|
|
break;
|
|
case 7:
|
|
sample_rate = SAMPLING_RATE_176P4KHZ;
|
|
break;
|
|
case 8:
|
|
sample_rate = SAMPLING_RATE_192KHZ;
|
|
break;
|
|
case 9:
|
|
sample_rate = SAMPLING_RATE_352P8KHZ;
|
|
break;
|
|
case 10:
|
|
sample_rate = SAMPLING_RATE_384KHZ;
|
|
break;
|
|
default:
|
|
sample_rate = SAMPLING_RATE_48KHZ;
|
|
break;
|
|
}
|
|
return sample_rate;
|
|
}
|
|
|
|
static int slim_get_bit_format_val(int bit_format)
|
|
{
|
|
int val = 0;
|
|
|
|
switch (bit_format) {
|
|
case SNDRV_PCM_FORMAT_S32_LE:
|
|
val = 3;
|
|
break;
|
|
case SNDRV_PCM_FORMAT_S24_3LE:
|
|
val = 2;
|
|
break;
|
|
case SNDRV_PCM_FORMAT_S24_LE:
|
|
val = 1;
|
|
break;
|
|
case SNDRV_PCM_FORMAT_S16_LE:
|
|
default:
|
|
val = 0;
|
|
break;
|
|
}
|
|
return val;
|
|
}
|
|
|
|
static int slim_get_bit_format(int val)
|
|
{
|
|
int bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
|
|
|
|
switch (val) {
|
|
case 0:
|
|
bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
|
|
break;
|
|
case 1:
|
|
bit_fmt = SNDRV_PCM_FORMAT_S24_LE;
|
|
break;
|
|
case 2:
|
|
bit_fmt = SNDRV_PCM_FORMAT_S24_3LE;
|
|
break;
|
|
case 3:
|
|
bit_fmt = SNDRV_PCM_FORMAT_S32_LE;
|
|
break;
|
|
default:
|
|
bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
|
|
break;
|
|
}
|
|
return bit_fmt;
|
|
}
|
|
|
|
static int slim_get_port_idx(struct snd_kcontrol *kcontrol)
|
|
{
|
|
int port_id = 0;
|
|
|
|
if (strnstr(kcontrol->id.name, "SLIM_0_RX", sizeof("SLIM_0_RX")))
|
|
port_id = SLIM_RX_0;
|
|
else if (strnstr(kcontrol->id.name, "SLIM_2_RX", sizeof("SLIM_2_RX")))
|
|
port_id = SLIM_RX_2;
|
|
else if (strnstr(kcontrol->id.name, "SLIM_5_RX", sizeof("SLIM_5_RX")))
|
|
port_id = SLIM_RX_5;
|
|
else if (strnstr(kcontrol->id.name, "SLIM_6_RX", sizeof("SLIM_6_RX")))
|
|
port_id = SLIM_RX_6;
|
|
else if (strnstr(kcontrol->id.name, "SLIM_0_TX", sizeof("SLIM_0_TX")))
|
|
port_id = SLIM_TX_0;
|
|
else if (strnstr(kcontrol->id.name, "SLIM_1_TX", sizeof("SLIM_1_TX")))
|
|
port_id = SLIM_TX_1;
|
|
else {
|
|
pr_err("%s: unsupported channel: %s",
|
|
__func__, kcontrol->id.name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return port_id;
|
|
}
|
|
|
|
static int msm_bt_sample_rate_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
/*
|
|
* Slimbus_7_Rx/Tx sample rate values should always be in sync (same)
|
|
* when used for BT_SCO use case. Return either Rx or Tx sample rate
|
|
* value.
|
|
*/
|
|
switch (slim_rx_cfg[SLIM_RX_7].sample_rate) {
|
|
case SAMPLING_RATE_96KHZ:
|
|
ucontrol->value.integer.value[0] = 5;
|
|
break;
|
|
case SAMPLING_RATE_88P2KHZ:
|
|
ucontrol->value.integer.value[0] = 4;
|
|
break;
|
|
case SAMPLING_RATE_48KHZ:
|
|
ucontrol->value.integer.value[0] = 3;
|
|
break;
|
|
case SAMPLING_RATE_44P1KHZ:
|
|
ucontrol->value.integer.value[0] = 2;
|
|
break;
|
|
case SAMPLING_RATE_16KHZ:
|
|
ucontrol->value.integer.value[0] = 1;
|
|
break;
|
|
case SAMPLING_RATE_8KHZ:
|
|
default:
|
|
ucontrol->value.integer.value[0] = 0;
|
|
break;
|
|
}
|
|
pr_debug("%s: sample rate = %d", __func__,
|
|
slim_rx_cfg[SLIM_RX_7].sample_rate);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int msm_bt_sample_rate_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
switch (ucontrol->value.integer.value[0]) {
|
|
case 1:
|
|
slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_16KHZ;
|
|
slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_16KHZ;
|
|
break;
|
|
case 2:
|
|
slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_44P1KHZ;
|
|
slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_44P1KHZ;
|
|
break;
|
|
case 3:
|
|
slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_48KHZ;
|
|
slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_48KHZ;
|
|
break;
|
|
case 4:
|
|
slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_88P2KHZ;
|
|
slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_88P2KHZ;
|
|
break;
|
|
case 5:
|
|
slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_96KHZ;
|
|
slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_96KHZ;
|
|
break;
|
|
case 0:
|
|
default:
|
|
slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_8KHZ;
|
|
slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_8KHZ;
|
|
break;
|
|
}
|
|
pr_debug("%s: sample rates: slim7_rx = %d, slim7_tx = %d, value = %d\n",
|
|
__func__,
|
|
slim_rx_cfg[SLIM_RX_7].sample_rate,
|
|
slim_tx_cfg[SLIM_TX_7].sample_rate,
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int slim_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
int ch_num = slim_get_port_idx(kcontrol);
|
|
|
|
if (ch_num < 0)
|
|
return ch_num;
|
|
|
|
ucontrol->value.enumerated.item[0] =
|
|
slim_get_sample_rate_val(slim_rx_cfg[ch_num].sample_rate);
|
|
|
|
pr_debug("%s: slim[%d]_rx_sample_rate = %d, item = %d\n", __func__,
|
|
ch_num, slim_rx_cfg[ch_num].sample_rate,
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int slim_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
int ch_num = slim_get_port_idx(kcontrol);
|
|
|
|
if (ch_num < 0)
|
|
return ch_num;
|
|
|
|
slim_rx_cfg[ch_num].sample_rate =
|
|
slim_get_sample_rate(ucontrol->value.enumerated.item[0]);
|
|
|
|
pr_debug("%s: slim[%d]_rx_sample_rate = %d, item = %d\n", __func__,
|
|
ch_num, slim_rx_cfg[ch_num].sample_rate,
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int slim_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
int ch_num = slim_get_port_idx(kcontrol);
|
|
|
|
if (ch_num < 0)
|
|
return ch_num;
|
|
|
|
ucontrol->value.enumerated.item[0] =
|
|
slim_get_sample_rate_val(slim_tx_cfg[ch_num].sample_rate);
|
|
|
|
pr_debug("%s: slim[%d]_tx_sample_rate = %d, item = %d\n", __func__,
|
|
ch_num, slim_tx_cfg[ch_num].sample_rate,
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int slim_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
int sample_rate = 0;
|
|
int ch_num = slim_get_port_idx(kcontrol);
|
|
|
|
if (ch_num < 0)
|
|
return ch_num;
|
|
|
|
sample_rate = slim_get_sample_rate(ucontrol->value.enumerated.item[0]);
|
|
if (sample_rate == SAMPLING_RATE_44P1KHZ) {
|
|
pr_err("%s: Unsupported sample rate %d: for Tx path\n",
|
|
__func__, sample_rate);
|
|
return -EINVAL;
|
|
}
|
|
slim_tx_cfg[ch_num].sample_rate = sample_rate;
|
|
|
|
pr_debug("%s: slim[%d]_tx_sample_rate = %d, value = %d\n", __func__,
|
|
ch_num, slim_tx_cfg[ch_num].sample_rate,
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int slim_rx_bit_format_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
int ch_num = slim_get_port_idx(kcontrol);
|
|
|
|
if (ch_num < 0)
|
|
return ch_num;
|
|
|
|
ucontrol->value.enumerated.item[0] =
|
|
slim_get_bit_format_val(slim_rx_cfg[ch_num].bit_format);
|
|
|
|
pr_debug("%s: slim[%d]_rx_bit_format = %d, ucontrol value = %d\n",
|
|
__func__, ch_num, slim_rx_cfg[ch_num].bit_format,
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int slim_rx_bit_format_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
int ch_num = slim_get_port_idx(kcontrol);
|
|
|
|
if (ch_num < 0)
|
|
return ch_num;
|
|
|
|
slim_rx_cfg[ch_num].bit_format =
|
|
slim_get_bit_format(ucontrol->value.enumerated.item[0]);
|
|
|
|
pr_debug("%s: slim[%d]_rx_bit_format = %d, ucontrol value = %d\n",
|
|
__func__, ch_num, slim_rx_cfg[ch_num].bit_format,
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int slim_tx_bit_format_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
int ch_num = slim_get_port_idx(kcontrol);
|
|
|
|
if (ch_num < 0)
|
|
return ch_num;
|
|
|
|
ucontrol->value.enumerated.item[0] =
|
|
slim_get_bit_format_val(slim_tx_cfg[ch_num].bit_format);
|
|
|
|
pr_debug("%s: slim[%d]_tx_bit_format = %d, ucontrol value = %d\n",
|
|
__func__, ch_num, slim_tx_cfg[ch_num].bit_format,
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int slim_tx_bit_format_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
int ch_num = slim_get_port_idx(kcontrol);
|
|
|
|
if (ch_num < 0)
|
|
return ch_num;
|
|
|
|
slim_tx_cfg[ch_num].bit_format =
|
|
slim_get_bit_format(ucontrol->value.enumerated.item[0]);
|
|
|
|
pr_debug("%s: slim[%d]_tx_bit_format = %d, ucontrol value = %d\n",
|
|
__func__, ch_num, slim_tx_cfg[ch_num].bit_format,
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int msm_slim_rx_ch_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
int ch_num = slim_get_port_idx(kcontrol);
|
|
|
|
if (ch_num < 0)
|
|
return ch_num;
|
|
|
|
pr_debug("%s: msm_slim_[%d]_rx_ch = %d\n", __func__,
|
|
ch_num, slim_rx_cfg[ch_num].channels);
|
|
ucontrol->value.enumerated.item[0] = slim_rx_cfg[ch_num].channels - 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int msm_slim_rx_ch_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
int ch_num = slim_get_port_idx(kcontrol);
|
|
|
|
if (ch_num < 0)
|
|
return ch_num;
|
|
|
|
slim_rx_cfg[ch_num].channels = ucontrol->value.enumerated.item[0] + 1;
|
|
pr_debug("%s: msm_slim_[%d]_rx_ch = %d\n", __func__,
|
|
ch_num, slim_rx_cfg[ch_num].channels);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int msm_slim_tx_ch_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
int ch_num = slim_get_port_idx(kcontrol);
|
|
|
|
if (ch_num < 0)
|
|
return ch_num;
|
|
|
|
pr_debug("%s: msm_slim_[%d]_tx_ch = %d\n", __func__,
|
|
ch_num, slim_tx_cfg[ch_num].channels);
|
|
ucontrol->value.enumerated.item[0] = slim_tx_cfg[ch_num].channels - 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int msm_slim_tx_ch_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
int ch_num = slim_get_port_idx(kcontrol);
|
|
|
|
if (ch_num < 0)
|
|
return ch_num;
|
|
|
|
slim_tx_cfg[ch_num].channels = ucontrol->value.enumerated.item[0] + 1;
|
|
pr_debug("%s: msm_slim_[%d]_tx_ch = %d\n", __func__,
|
|
ch_num, slim_tx_cfg[ch_num].channels);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int msm_vi_feed_tx_ch_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
ucontrol->value.integer.value[0] = msm_vi_feed_tx_ch - 1;
|
|
pr_debug("%s: msm_vi_feed_tx_ch = %ld\n", __func__,
|
|
ucontrol->value.integer.value[0]);
|
|
return 0;
|
|
}
|
|
|
|
static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
msm_vi_feed_tx_ch = ucontrol->value.integer.value[0] + 1;
|
|
|
|
pr_debug("%s: msm_vi_feed_tx_ch = %d\n", __func__, msm_vi_feed_tx_ch);
|
|
return 1;
|
|
}
|
|
|
|
static void *def_ext_mbhc_cal(void)
|
|
{
|
|
void *wcd_mbhc_cal;
|
|
struct wcd_mbhc_btn_detect_cfg *btn_cfg;
|
|
u16 *btn_high;
|
|
|
|
wcd_mbhc_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS,
|
|
WCD9XXX_MBHC_DEF_RLOADS), GFP_KERNEL);
|
|
if (!wcd_mbhc_cal)
|
|
return NULL;
|
|
|
|
#define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(wcd_mbhc_cal)->X) = (Y))
|
|
S(v_hs_max, 1600);
|
|
#undef S
|
|
#define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(wcd_mbhc_cal)->X) = (Y))
|
|
S(num_btn, WCD_MBHC_DEF_BUTTONS);
|
|
#undef S
|
|
|
|
btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(wcd_mbhc_cal);
|
|
btn_high = ((void *)&btn_cfg->_v_btn_low) +
|
|
(sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn);
|
|
|
|
btn_high[0] = 75;
|
|
btn_high[1] = 150;
|
|
btn_high[2] = 237;
|
|
btn_high[3] = 500;
|
|
btn_high[4] = 500;
|
|
btn_high[5] = 500;
|
|
btn_high[6] = 500;
|
|
btn_high[7] = 500;
|
|
|
|
return wcd_mbhc_cal;
|
|
}
|
|
|
|
static inline int param_is_mask(int p)
|
|
{
|
|
return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
|
|
(p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
|
|
}
|
|
|
|
static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
|
|
{
|
|
return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
|
|
}
|
|
|
|
|
|
static void msm_ext_control(struct snd_soc_component *codec)
|
|
{
|
|
struct snd_soc_dapm_context *dapm =
|
|
snd_soc_component_get_dapm(codec);
|
|
|
|
pr_debug("%s: msm_ext_spk_control = %d", __func__, msm_ext_spk_control);
|
|
if (msm_ext_spk_control == SDM660_SPK_ON) {
|
|
snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
|
|
snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
|
|
} else {
|
|
snd_soc_dapm_disable_pin(dapm, "Lineout_1 amp");
|
|
snd_soc_dapm_disable_pin(dapm, "Lineout_3 amp");
|
|
}
|
|
snd_soc_dapm_sync(dapm);
|
|
}
|
|
|
|
static int msm_ext_get_spk(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
pr_debug("%s: msm_ext_spk_control = %d\n",
|
|
__func__, msm_ext_spk_control);
|
|
ucontrol->value.integer.value[0] = msm_ext_spk_control;
|
|
return 0;
|
|
}
|
|
|
|
static int msm_ext_set_spk(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *component =
|
|
snd_soc_kcontrol_component(kcontrol);
|
|
|
|
pr_debug("%s()\n", __func__);
|
|
if (msm_ext_spk_control == ucontrol->value.integer.value[0])
|
|
return 0;
|
|
|
|
msm_ext_spk_control = ucontrol->value.integer.value[0];
|
|
msm_ext_control(component);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int msm_ext_enable_codec_mclk(struct snd_soc_component *component, int enable,
|
|
bool dapm)
|
|
{
|
|
int ret;
|
|
|
|
pr_debug("%s: enable = %d\n", __func__, enable);
|
|
|
|
if (!strcmp(dev_name(component->dev), "tasha_codec"))
|
|
ret = tasha_cdc_mclk_enable(component, enable, dapm);
|
|
else if (!strcmp(dev_name(component->dev), "tavil_codec"))
|
|
ret = tavil_cdc_mclk_enable(component, enable);
|
|
else {
|
|
dev_err(component->dev, "%s: unknown codec to enable ext clk\n",
|
|
__func__);
|
|
ret = -EINVAL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static const struct snd_kcontrol_new msm_snd_controls[] = {
|
|
SOC_ENUM_EXT("Speaker Function", spk_func_en, msm_ext_get_spk,
|
|
msm_ext_set_spk),
|
|
SOC_ENUM_EXT("SLIM_0_RX Channels", slim_0_rx_chs,
|
|
msm_slim_rx_ch_get, msm_slim_rx_ch_put),
|
|
SOC_ENUM_EXT("SLIM_2_RX Channels", slim_2_rx_chs,
|
|
msm_slim_rx_ch_get, msm_slim_rx_ch_put),
|
|
SOC_ENUM_EXT("SLIM_0_TX Channels", slim_0_tx_chs,
|
|
msm_slim_tx_ch_get, msm_slim_tx_ch_put),
|
|
SOC_ENUM_EXT("SLIM_1_TX Channels", slim_1_tx_chs,
|
|
msm_slim_tx_ch_get, msm_slim_tx_ch_put),
|
|
SOC_ENUM_EXT("SLIM_5_RX Channels", slim_5_rx_chs,
|
|
msm_slim_rx_ch_get, msm_slim_rx_ch_put),
|
|
SOC_ENUM_EXT("SLIM_6_RX Channels", slim_6_rx_chs,
|
|
msm_slim_rx_ch_get, msm_slim_rx_ch_put),
|
|
SOC_ENUM_EXT("VI_FEED_TX Channels", vi_feed_tx_chs,
|
|
msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put),
|
|
SOC_ENUM_EXT("SLIM_0_RX Format", slim_0_rx_format,
|
|
slim_rx_bit_format_get, slim_rx_bit_format_put),
|
|
SOC_ENUM_EXT("SLIM_5_RX Format", slim_5_rx_format,
|
|
slim_rx_bit_format_get, slim_rx_bit_format_put),
|
|
SOC_ENUM_EXT("SLIM_6_RX Format", slim_6_rx_format,
|
|
slim_rx_bit_format_get, slim_rx_bit_format_put),
|
|
SOC_ENUM_EXT("SLIM_0_TX Format", slim_0_tx_format,
|
|
slim_tx_bit_format_get, slim_tx_bit_format_put),
|
|
SOC_ENUM_EXT("SLIM_0_RX SampleRate", slim_0_rx_sample_rate,
|
|
slim_rx_sample_rate_get, slim_rx_sample_rate_put),
|
|
SOC_ENUM_EXT("SLIM_2_RX SampleRate", slim_2_rx_sample_rate,
|
|
slim_rx_sample_rate_get, slim_rx_sample_rate_put),
|
|
SOC_ENUM_EXT("SLIM_0_TX SampleRate", slim_0_tx_sample_rate,
|
|
slim_tx_sample_rate_get, slim_tx_sample_rate_put),
|
|
SOC_ENUM_EXT("SLIM_5_RX SampleRate", slim_5_rx_sample_rate,
|
|
slim_rx_sample_rate_get, slim_rx_sample_rate_put),
|
|
SOC_ENUM_EXT("SLIM_6_RX SampleRate", slim_6_rx_sample_rate,
|
|
slim_rx_sample_rate_get, slim_rx_sample_rate_put),
|
|
SOC_ENUM_EXT("BT SampleRate", bt_sample_rate,
|
|
msm_bt_sample_rate_get,
|
|
msm_bt_sample_rate_put),
|
|
};
|
|
|
|
static int msm_slim_get_ch_from_beid(int32_t id)
|
|
{
|
|
int ch_id = 0;
|
|
|
|
switch (id) {
|
|
case MSM_BACKEND_DAI_SLIMBUS_0_RX:
|
|
ch_id = SLIM_RX_0;
|
|
break;
|
|
case MSM_BACKEND_DAI_SLIMBUS_1_RX:
|
|
ch_id = SLIM_RX_1;
|
|
break;
|
|
case MSM_BACKEND_DAI_SLIMBUS_2_RX:
|
|
ch_id = SLIM_RX_2;
|
|
break;
|
|
case MSM_BACKEND_DAI_SLIMBUS_3_RX:
|
|
ch_id = SLIM_RX_3;
|
|
break;
|
|
case MSM_BACKEND_DAI_SLIMBUS_4_RX:
|
|
ch_id = SLIM_RX_4;
|
|
break;
|
|
case MSM_BACKEND_DAI_SLIMBUS_6_RX:
|
|
ch_id = SLIM_RX_6;
|
|
break;
|
|
case MSM_BACKEND_DAI_SLIMBUS_0_TX:
|
|
ch_id = SLIM_TX_0;
|
|
break;
|
|
case MSM_BACKEND_DAI_SLIMBUS_3_TX:
|
|
ch_id = SLIM_TX_3;
|
|
break;
|
|
default:
|
|
ch_id = SLIM_RX_0;
|
|
break;
|
|
}
|
|
|
|
return ch_id;
|
|
}
|
|
|
|
static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned int bit)
|
|
{
|
|
if (bit >= SNDRV_MASK_MAX)
|
|
return;
|
|
if (param_is_mask(n)) {
|
|
struct snd_mask *m = param_to_mask(p, n);
|
|
|
|
m->bits[0] = 0;
|
|
m->bits[1] = 0;
|
|
m->bits[bit >> 5] |= (1 << (bit & 31));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* msm_ext_be_hw_params_fixup - updates settings of ALSA BE hw params.
|
|
*
|
|
* @rtd: runtime dailink instance
|
|
* @params: HW params of associated backend dailink.
|
|
*
|
|
* Returns 0 on success or rc on failure.
|
|
*/
|
|
int msm_ext_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
|
|
struct snd_pcm_hw_params *params)
|
|
{
|
|
struct snd_soc_dai_link *dai_link = rtd->dai_link;
|
|
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
|
struct snd_interval *rate = hw_param_interval(params,
|
|
SNDRV_PCM_HW_PARAM_RATE);
|
|
struct snd_interval *channels = hw_param_interval(params,
|
|
SNDRV_PCM_HW_PARAM_CHANNELS);
|
|
int rc = 0;
|
|
int idx;
|
|
void *config = NULL;
|
|
struct snd_soc_component *component = NULL;
|
|
|
|
pr_debug("%s: format = %d, rate = %d\n",
|
|
__func__, params_format(params), params_rate(params));
|
|
|
|
switch (dai_link->id) {
|
|
case MSM_BACKEND_DAI_SLIMBUS_0_RX:
|
|
case MSM_BACKEND_DAI_SLIMBUS_1_RX:
|
|
case MSM_BACKEND_DAI_SLIMBUS_2_RX:
|
|
case MSM_BACKEND_DAI_SLIMBUS_3_RX:
|
|
case MSM_BACKEND_DAI_SLIMBUS_4_RX:
|
|
case MSM_BACKEND_DAI_SLIMBUS_6_RX:
|
|
idx = msm_slim_get_ch_from_beid(dai_link->id);
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
slim_rx_cfg[idx].bit_format);
|
|
rate->min = rate->max = slim_rx_cfg[idx].sample_rate;
|
|
channels->min = channels->max = slim_rx_cfg[idx].channels;
|
|
break;
|
|
|
|
case MSM_BACKEND_DAI_SLIMBUS_0_TX:
|
|
case MSM_BACKEND_DAI_SLIMBUS_3_TX:
|
|
idx = msm_slim_get_ch_from_beid(dai_link->id);
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
slim_tx_cfg[idx].bit_format);
|
|
rate->min = rate->max = slim_tx_cfg[idx].sample_rate;
|
|
channels->min = channels->max = slim_tx_cfg[idx].channels;
|
|
break;
|
|
|
|
case MSM_BACKEND_DAI_SLIMBUS_1_TX:
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
slim_tx_cfg[1].bit_format);
|
|
rate->min = rate->max = slim_tx_cfg[1].sample_rate;
|
|
channels->min = channels->max = slim_tx_cfg[1].channels;
|
|
break;
|
|
|
|
case MSM_BACKEND_DAI_SLIMBUS_4_TX:
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
SNDRV_PCM_FORMAT_S32_LE);
|
|
rate->min = rate->max = SAMPLING_RATE_8KHZ;
|
|
channels->min = channels->max = msm_vi_feed_tx_ch;
|
|
break;
|
|
|
|
case MSM_BACKEND_DAI_SLIMBUS_5_RX:
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
slim_rx_cfg[5].bit_format);
|
|
rate->min = rate->max = slim_rx_cfg[5].sample_rate;
|
|
channels->min = channels->max = slim_rx_cfg[5].channels;
|
|
break;
|
|
|
|
case MSM_BACKEND_DAI_SLIMBUS_5_TX:
|
|
if (!strcmp(dev_name(codec_dai->dev), "tavil_codec"))
|
|
component = snd_soc_rtdcom_lookup(rtd, "tavil_codec");
|
|
else if (!strcmp(dev_name(codec_dai->dev), "tasha_codec"))
|
|
component = snd_soc_rtdcom_lookup(rtd, "tasha_codec");
|
|
rate->min = rate->max = SAMPLING_RATE_16KHZ;
|
|
channels->min = channels->max = 1;
|
|
|
|
config = msm_codec_fn.get_afe_config_fn(component,
|
|
AFE_SLIMBUS_SLAVE_PORT_CONFIG);
|
|
if (config) {
|
|
rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG,
|
|
config, SLIMBUS_5_TX);
|
|
if (rc)
|
|
pr_err("%s: Failed to set slimbus slave port config %d\n",
|
|
__func__, rc);
|
|
}
|
|
break;
|
|
|
|
case MSM_BACKEND_DAI_SLIMBUS_7_RX:
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
slim_rx_cfg[SLIM_RX_7].bit_format);
|
|
rate->min = rate->max = slim_rx_cfg[SLIM_RX_7].sample_rate;
|
|
channels->min = channels->max =
|
|
slim_rx_cfg[SLIM_RX_7].channels;
|
|
break;
|
|
|
|
case MSM_BACKEND_DAI_SLIMBUS_7_TX:
|
|
rate->min = rate->max = slim_tx_cfg[SLIM_TX_7].sample_rate;
|
|
channels->min = channels->max =
|
|
slim_tx_cfg[SLIM_TX_7].channels;
|
|
break;
|
|
|
|
case MSM_BACKEND_DAI_SLIMBUS_8_TX:
|
|
rate->min = rate->max = slim_tx_cfg[SLIM_TX_8].sample_rate;
|
|
channels->min = channels->max =
|
|
slim_tx_cfg[SLIM_TX_8].channels;
|
|
break;
|
|
|
|
default:
|
|
rate->min = rate->max = SAMPLING_RATE_48KHZ;
|
|
break;
|
|
}
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL(msm_ext_be_hw_params_fixup);
|
|
|
|
/**
|
|
* msm_snd_hw_params - hw params ops of backend dailink.
|
|
*
|
|
* @substream: PCM stream of associated backend dailink.
|
|
* @params: HW params of associated backend dailink.
|
|
*
|
|
* Returns 0 on success or ret on failure.
|
|
*/
|
|
int msm_snd_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;
|
|
struct snd_soc_dai_link *dai_link = rtd->dai_link;
|
|
|
|
int ret = 0;
|
|
u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
|
|
u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
|
|
u32 user_set_tx_ch = 0;
|
|
u32 rx_ch_count;
|
|
|
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
ret = snd_soc_dai_get_channel_map(codec_dai,
|
|
&tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed to get codec chan map, err:%d\n",
|
|
__func__, ret);
|
|
goto err_ch_map;
|
|
}
|
|
if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_5_RX) {
|
|
pr_debug("%s: rx_5_ch=%d\n", __func__,
|
|
slim_rx_cfg[5].channels);
|
|
rx_ch_count = slim_rx_cfg[5].channels;
|
|
} else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_2_RX) {
|
|
pr_debug("%s: rx_2_ch=%d\n", __func__,
|
|
slim_rx_cfg[2].channels);
|
|
rx_ch_count = slim_rx_cfg[2].channels;
|
|
} else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_6_RX) {
|
|
pr_debug("%s: rx_6_ch=%d\n", __func__,
|
|
slim_rx_cfg[6].channels);
|
|
rx_ch_count = slim_rx_cfg[6].channels;
|
|
} else {
|
|
pr_debug("%s: rx_0_ch=%d\n", __func__,
|
|
slim_rx_cfg[0].channels);
|
|
rx_ch_count = slim_rx_cfg[0].channels;
|
|
}
|
|
ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
|
|
rx_ch_count, rx_ch);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed to set cpu chan map, err:%d\n",
|
|
__func__, ret);
|
|
goto err_ch_map;
|
|
}
|
|
} else {
|
|
pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
|
|
codec_dai->name, codec_dai->id, user_set_tx_ch);
|
|
ret = snd_soc_dai_get_channel_map(codec_dai,
|
|
&tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed to get codec chan map\n, err:%d\n",
|
|
__func__, ret);
|
|
goto err_ch_map;
|
|
}
|
|
/* For <codec>_tx1 case */
|
|
if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_0_TX)
|
|
user_set_tx_ch = slim_tx_cfg[0].channels;
|
|
/* For <codec>_tx3 case */
|
|
else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_1_TX)
|
|
user_set_tx_ch = slim_tx_cfg[1].channels;
|
|
else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_4_TX)
|
|
user_set_tx_ch = msm_vi_feed_tx_ch;
|
|
else
|
|
user_set_tx_ch = tx_ch_cnt;
|
|
|
|
pr_debug("%s: msm_slim_0_tx_ch(%d) user_set_tx_ch(%d) tx_ch_cnt(%d), id (%d)\n",
|
|
__func__, slim_tx_cfg[0].channels, user_set_tx_ch,
|
|
tx_ch_cnt, dai_link->id);
|
|
|
|
ret = snd_soc_dai_set_channel_map(cpu_dai,
|
|
user_set_tx_ch, tx_ch, 0, 0);
|
|
if (ret < 0)
|
|
pr_err("%s: failed to set cpu chan map, err:%d\n",
|
|
__func__, ret);
|
|
}
|
|
|
|
err_ch_map:
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(msm_snd_hw_params);
|
|
|
|
/**
|
|
* msm_ext_slimbus_2_hw_params - hw params ops of slimbus_2 BE.
|
|
*
|
|
* @substream: PCM stream of associated backend dailink.
|
|
* @params: HW params of associated backend dailink.
|
|
*
|
|
* Returns 0 on success or ret on failure.
|
|
*/
|
|
int msm_ext_slimbus_2_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;
|
|
unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
|
|
unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
|
|
unsigned int num_tx_ch = 0;
|
|
unsigned int num_rx_ch = 0;
|
|
|
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
num_rx_ch = params_channels(params);
|
|
pr_debug("%s: %s rx_dai_id = %d num_ch = %d\n", __func__,
|
|
codec_dai->name, codec_dai->id, num_rx_ch);
|
|
ret = snd_soc_dai_get_channel_map(codec_dai,
|
|
&tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed to get codec chan map, err:%d\n",
|
|
__func__, ret);
|
|
goto end;
|
|
}
|
|
ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
|
|
num_rx_ch, rx_ch);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed to set cpu chan map, err:%d\n",
|
|
__func__, ret);
|
|
goto end;
|
|
}
|
|
} else {
|
|
num_tx_ch = params_channels(params);
|
|
pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__,
|
|
codec_dai->name, codec_dai->id, num_tx_ch);
|
|
ret = snd_soc_dai_get_channel_map(codec_dai,
|
|
&tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed to get codec chan map, err:%d\n",
|
|
__func__, ret);
|
|
goto end;
|
|
}
|
|
ret = snd_soc_dai_set_channel_map(cpu_dai,
|
|
num_tx_ch, tx_ch, 0, 0);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed to set cpu chan map, err:%d\n",
|
|
__func__, ret);
|
|
goto end;
|
|
}
|
|
}
|
|
end:
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(msm_ext_slimbus_2_hw_params);
|
|
|
|
/**
|
|
* msm_snd_cpe_hw_params - hw params ops of CPE backend.
|
|
*
|
|
* @substream: PCM stream of associated backend dailink.
|
|
* @params: HW params of associated backend dailink.
|
|
*
|
|
* Returns 0 on success or ret on failure.
|
|
*/
|
|
int msm_snd_cpe_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;
|
|
struct snd_soc_dai_link *dai_link = rtd->dai_link;
|
|
int ret = 0;
|
|
u32 tx_ch[SLIM_MAX_TX_PORTS];
|
|
u32 tx_ch_cnt = 0;
|
|
|
|
if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) {
|
|
pr_err("%s: Invalid stream type %d\n",
|
|
__func__, substream->stream);
|
|
ret = -EINVAL;
|
|
goto end;
|
|
}
|
|
|
|
pr_debug("%s: %s_tx_dai_id_%d\n", __func__,
|
|
codec_dai->name, codec_dai->id);
|
|
ret = snd_soc_dai_get_channel_map(codec_dai,
|
|
&tx_ch_cnt, tx_ch, NULL, NULL);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed to get codec chan map\n, err:%d\n",
|
|
__func__, ret);
|
|
goto end;
|
|
}
|
|
|
|
pr_debug("%s: tx_ch_cnt(%d) id %d\n",
|
|
__func__, tx_ch_cnt, dai_link->id);
|
|
|
|
ret = snd_soc_dai_set_channel_map(cpu_dai,
|
|
tx_ch_cnt, tx_ch, 0, 0);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed to set cpu chan map, err:%d\n",
|
|
__func__, ret);
|
|
goto end;
|
|
}
|
|
end:
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(msm_snd_cpe_hw_params);
|
|
|
|
static int msm_afe_set_config(struct snd_soc_component *component)
|
|
{
|
|
int rc;
|
|
void *config_data;
|
|
|
|
pr_debug("%s: enter\n", __func__);
|
|
|
|
if (!msm_codec_fn.get_afe_config_fn) {
|
|
dev_err(component->dev, "%s: codec get afe config not init'ed\n",
|
|
__func__);
|
|
return -EINVAL;
|
|
}
|
|
config_data = msm_codec_fn.get_afe_config_fn(component,
|
|
AFE_CDC_REGISTERS_CONFIG);
|
|
if (config_data) {
|
|
rc = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
|
|
if (rc) {
|
|
pr_err("%s: Failed to set codec registers config %d\n",
|
|
__func__, rc);
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
config_data = msm_codec_fn.get_afe_config_fn(component,
|
|
AFE_CDC_REGISTER_PAGE_CONFIG);
|
|
if (config_data) {
|
|
rc = afe_set_config(AFE_CDC_REGISTER_PAGE_CONFIG, config_data,
|
|
0);
|
|
if (rc)
|
|
pr_err("%s: Failed to set cdc register page config\n",
|
|
__func__);
|
|
}
|
|
|
|
config_data = msm_codec_fn.get_afe_config_fn(component,
|
|
AFE_SLIMBUS_SLAVE_CONFIG);
|
|
if (config_data) {
|
|
rc = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
|
|
if (rc) {
|
|
pr_err("%s: Failed to set slimbus slave config %d\n",
|
|
__func__, rc);
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
config_data = msm_codec_fn.get_afe_config_fn(component,
|
|
AFE_AANC_VERSION);
|
|
if (config_data) {
|
|
rc = afe_set_config(AFE_AANC_VERSION, config_data, 0);
|
|
if (rc) {
|
|
pr_err("%s: Failed to set AANC version %d\n",
|
|
__func__, rc);
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
config_data = msm_codec_fn.get_afe_config_fn(component,
|
|
AFE_CDC_CLIP_REGISTERS_CONFIG);
|
|
if (config_data) {
|
|
rc = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
|
|
config_data, 0);
|
|
if (rc) {
|
|
pr_err("%s: Failed to set clip registers %d\n",
|
|
__func__, rc);
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
config_data = msm_codec_fn.get_afe_config_fn(component,
|
|
AFE_CLIP_BANK_SEL);
|
|
if (config_data) {
|
|
rc = afe_set_config(AFE_CLIP_BANK_SEL,
|
|
config_data, 0);
|
|
if (rc) {
|
|
pr_err("%s: Failed to set AFE bank selection %d\n",
|
|
__func__, rc);
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
config_data = msm_codec_fn.get_afe_config_fn(component,
|
|
AFE_CDC_REGISTER_PAGE_CONFIG);
|
|
if (config_data) {
|
|
rc = afe_set_config(AFE_CDC_REGISTER_PAGE_CONFIG, config_data,
|
|
0);
|
|
if (rc)
|
|
pr_err("%s: Failed to set cdc register page config\n",
|
|
__func__);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void msm_afe_clear_config(void)
|
|
{
|
|
afe_clear_config(AFE_CDC_REGISTERS_CONFIG);
|
|
afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
|
|
}
|
|
|
|
static void msm_snd_interrupt_config(struct msm_asoc_mach_data *pdata)
|
|
{
|
|
int val;
|
|
|
|
val = ioread32(pdata->msm_snd_intr_lpi.mpm_wakeup);
|
|
val |= LPI_GPIO_22_WAKEUP_VAL;
|
|
iowrite32(val, pdata->msm_snd_intr_lpi.mpm_wakeup);
|
|
|
|
val = ioread32(pdata->msm_snd_intr_lpi.intr1_cfg_apps);
|
|
val &= ~(LPI_GPIO_22_INTR1_CFG_MASK);
|
|
val |= LPI_GPIO_22_INTR1_CFG_VAL;
|
|
iowrite32(val, pdata->msm_snd_intr_lpi.intr1_cfg_apps);
|
|
|
|
iowrite32(LPI_GPIO_INTR_CFG1_VAL,
|
|
pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg);
|
|
iowrite32(LPI_GPIO22_CFG_VAL,
|
|
pdata->msm_snd_intr_lpi.lpi_gpio_cfg);
|
|
|
|
val = ioread32(pdata->msm_snd_intr_lpi.lpi_gpio_inout);
|
|
val |= LPI_GPIO22_INOUT_VAL;
|
|
iowrite32(val, pdata->msm_snd_intr_lpi.lpi_gpio_inout);
|
|
}
|
|
|
|
static int msm_adsp_power_up_config(struct snd_soc_component *component,
|
|
struct snd_card *card)
|
|
{
|
|
int ret = 0;
|
|
unsigned long timeout;
|
|
int adsp_ready = 0;
|
|
bool snd_card_online = 0;
|
|
struct snd_soc_card *soc_card = component->card;
|
|
struct msm_asoc_mach_data *pdata;
|
|
|
|
pdata = snd_soc_card_get_drvdata(soc_card);
|
|
timeout = jiffies +
|
|
msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
|
|
|
|
do {
|
|
if (!snd_card_online) {
|
|
snd_card_online = snd_card_is_online_state(card);
|
|
pr_debug("%s: Sound card is %s\n", __func__,
|
|
snd_card_online ? "Online" : "Offline");
|
|
}
|
|
if (!adsp_ready) {
|
|
adsp_ready = q6core_is_adsp_ready();
|
|
pr_debug("%s: ADSP Audio is %s\n", __func__,
|
|
adsp_ready ? "ready" : "not ready");
|
|
}
|
|
if (snd_card_online && adsp_ready)
|
|
break;
|
|
|
|
/*
|
|
* Sound card/ADSP will be coming up after subsystem restart and
|
|
* it might not be fully up when the control reaches
|
|
* here. So, wait for 50msec before checking ADSP state
|
|
*/
|
|
msleep(50);
|
|
} while (time_after(timeout, jiffies));
|
|
|
|
if (!snd_card_online || !adsp_ready) {
|
|
pr_err("%s: Timeout. Sound card is %s, ADSP Audio is %s\n",
|
|
__func__,
|
|
snd_card_online ? "Online" : "Offline",
|
|
adsp_ready ? "ready" : "not ready");
|
|
ret = -ETIMEDOUT;
|
|
goto err_fail;
|
|
}
|
|
|
|
if (socinfo_get_id() == SDM660_SOC_MSM_ID ||
|
|
socinfo_get_id() == SDM660_SOC_SDA_ID) {
|
|
msm_snd_interrupt_config(pdata);
|
|
}
|
|
ret = msm_afe_set_config(component);
|
|
if (ret)
|
|
pr_err("%s: Failed to set AFE config. err %d\n",
|
|
__func__, ret);
|
|
|
|
return 0;
|
|
|
|
err_fail:
|
|
return ret;
|
|
}
|
|
|
|
static int sdm660_notifier_service_cb(struct notifier_block *this,
|
|
unsigned long opcode, void *ptr)
|
|
{
|
|
int ret;
|
|
struct snd_soc_card *card = NULL;
|
|
struct snd_soc_dai *codec_dai;
|
|
const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX;
|
|
struct snd_soc_pcm_runtime *rtd;
|
|
struct snd_soc_component *component;
|
|
|
|
pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode);
|
|
|
|
switch (opcode) {
|
|
case AUDIO_NOTIFIER_SERVICE_DOWN:
|
|
/*
|
|
* Use flag to ignore initial boot notifications
|
|
* On initial boot msm_adsp_power_up_config is
|
|
* called on init. There is no need to clear
|
|
* and set the config again on initial boot.
|
|
*/
|
|
if (is_initial_boot)
|
|
break;
|
|
msm_afe_clear_config();
|
|
break;
|
|
case AUDIO_NOTIFIER_SERVICE_UP:
|
|
if (is_initial_boot) {
|
|
is_initial_boot = false;
|
|
break;
|
|
}
|
|
if (!spdev)
|
|
return -EINVAL;
|
|
|
|
card = platform_get_drvdata(spdev);
|
|
rtd = snd_soc_get_pcm_runtime(card, be_dl_name);
|
|
if (!rtd) {
|
|
dev_err(card->dev,
|
|
"%s: snd_soc_get_pcm_runtime for %s failed!\n",
|
|
__func__, be_dl_name);
|
|
ret = -EINVAL;
|
|
goto done;
|
|
}
|
|
codec_dai = rtd->codec_dai;
|
|
if (!strcmp(dev_name(codec_dai->dev), "tavil_codec"))
|
|
component = snd_soc_rtdcom_lookup(rtd, "tavil_codec");
|
|
else if (!strcmp(dev_name(codec_dai->dev), "tasha_codec"))
|
|
component = snd_soc_rtdcom_lookup(rtd, "tasha_codec");
|
|
ret = msm_adsp_power_up_config(component, card->snd_card);
|
|
if (ret < 0) {
|
|
dev_err(card->dev,
|
|
"%s: msm_adsp_power_up_config failed ret = %d!\n",
|
|
__func__, ret);
|
|
goto done;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
done:
|
|
return NOTIFY_OK;
|
|
}
|
|
|
|
static struct notifier_block service_nb = {
|
|
.notifier_call = sdm660_notifier_service_cb,
|
|
.priority = -INT_MAX,
|
|
};
|
|
|
|
static int msm_config_hph_en0_gpio(struct snd_soc_component *component,
|
|
bool high)
|
|
{
|
|
struct snd_soc_card *card = component->card;
|
|
struct msm_asoc_mach_data *pdata;
|
|
int val;
|
|
|
|
if (!card)
|
|
return 0;
|
|
|
|
pdata = snd_soc_card_get_drvdata(card);
|
|
if (!pdata || !gpio_is_valid(pdata->hph_en0_gpio))
|
|
return 0;
|
|
|
|
val = gpio_get_value_cansleep(pdata->hph_en0_gpio);
|
|
if ((!!val) == high)
|
|
return 0;
|
|
|
|
gpio_direction_output(pdata->hph_en0_gpio, (int)high);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int msm_snd_enable_codec_ext_tx_clk(struct snd_soc_component *component,
|
|
int enable, bool dapm)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (!strcmp(dev_name(component->dev), "tasha_codec"))
|
|
ret = tasha_cdc_mclk_tx_enable(component, enable, dapm);
|
|
else {
|
|
dev_err(component->dev, "%s: unknown codec to enable ext clk\n",
|
|
__func__);
|
|
ret = -EINVAL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int msm_ext_mclk_tx_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol, int event)
|
|
{
|
|
struct snd_soc_component *component =
|
|
snd_soc_dapm_to_component(w->dapm);
|
|
|
|
pr_debug("%s: event = %d\n", __func__, event);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
return msm_snd_enable_codec_ext_tx_clk(component, 1, true);
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
return msm_snd_enable_codec_ext_tx_clk(component, 0, true);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int msm_ext_mclk_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol, int event)
|
|
{
|
|
struct snd_soc_component *component =
|
|
snd_soc_dapm_to_component(w->dapm);
|
|
|
|
pr_debug("%s: event = %d\n", __func__, event);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
return msm_ext_enable_codec_mclk(component, 1, true);
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
return msm_ext_enable_codec_mclk(component, 0, true);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int msm_ext_prepare_hifi(struct msm_asoc_mach_data *pdata)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (gpio_is_valid(pdata->hph_en1_gpio)) {
|
|
pr_debug("%s: hph_en1_gpio request %d\n", __func__,
|
|
pdata->hph_en1_gpio);
|
|
ret = gpio_request(pdata->hph_en1_gpio, "hph_en1_gpio");
|
|
if (ret) {
|
|
pr_err("%s: hph_en1_gpio request failed, ret:%d\n",
|
|
__func__, ret);
|
|
goto err;
|
|
}
|
|
}
|
|
if (gpio_is_valid(pdata->hph_en0_gpio)) {
|
|
pr_debug("%s: hph_en0_gpio request %d\n", __func__,
|
|
pdata->hph_en0_gpio);
|
|
ret = gpio_request(pdata->hph_en0_gpio, "hph_en0_gpio");
|
|
if (ret)
|
|
pr_err("%s: hph_en0_gpio request failed, ret:%d\n",
|
|
__func__, ret);
|
|
}
|
|
|
|
err:
|
|
return ret;
|
|
}
|
|
|
|
static const struct snd_soc_dapm_widget msm_dapm_widgets[] = {
|
|
|
|
SND_SOC_DAPM_SUPPLY_S("MCLK", -1, SND_SOC_NOPM, 0, 0,
|
|
msm_ext_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
|
|
|
SND_SOC_DAPM_SUPPLY_S("MCLK TX", -1, SND_SOC_NOPM, 0, 0,
|
|
msm_ext_mclk_tx_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
|
|
|
SND_SOC_DAPM_SPK("Lineout_1 amp", NULL),
|
|
SND_SOC_DAPM_SPK("Lineout_3 amp", NULL),
|
|
SND_SOC_DAPM_SPK("Lineout_2 amp", NULL),
|
|
SND_SOC_DAPM_SPK("Lineout_4 amp", NULL),
|
|
SND_SOC_DAPM_MIC("Handset Mic", NULL),
|
|
SND_SOC_DAPM_MIC("Headset Mic", NULL),
|
|
SND_SOC_DAPM_MIC("Secondary Mic", NULL),
|
|
SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
|
|
SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
|
|
SND_SOC_DAPM_MIC("Analog Mic4", NULL),
|
|
SND_SOC_DAPM_MIC("Analog Mic6", NULL),
|
|
SND_SOC_DAPM_MIC("Analog Mic7", NULL),
|
|
SND_SOC_DAPM_MIC("Analog Mic8", NULL),
|
|
|
|
SND_SOC_DAPM_MIC("Digital Mic0", NULL),
|
|
SND_SOC_DAPM_MIC("Digital Mic1", NULL),
|
|
SND_SOC_DAPM_MIC("Digital Mic2", NULL),
|
|
SND_SOC_DAPM_MIC("Digital Mic3", NULL),
|
|
SND_SOC_DAPM_MIC("Digital Mic4", NULL),
|
|
SND_SOC_DAPM_MIC("Digital Mic5", NULL),
|
|
SND_SOC_DAPM_MIC("Digital Mic6", NULL),
|
|
};
|
|
|
|
static struct snd_soc_dapm_route wcd_audio_paths_tasha[] = {
|
|
{"MIC BIAS1", NULL, "MCLK TX"},
|
|
{"MIC BIAS2", NULL, "MCLK TX"},
|
|
{"MIC BIAS3", NULL, "MCLK TX"},
|
|
{"MIC BIAS4", NULL, "MCLK TX"},
|
|
};
|
|
|
|
static struct snd_soc_dapm_route wcd_audio_paths[] = {
|
|
{"MIC BIAS1", NULL, "MCLK"},
|
|
{"MIC BIAS2", NULL, "MCLK"},
|
|
{"MIC BIAS3", NULL, "MCLK"},
|
|
{"MIC BIAS4", NULL, "MCLK"},
|
|
};
|
|
|
|
int msm_snd_card_tasha_late_probe(struct snd_soc_card *card)
|
|
{
|
|
const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX;
|
|
struct snd_soc_pcm_runtime *rtd;
|
|
int ret = 0;
|
|
void *mbhc_calibration;
|
|
struct snd_soc_component *component = NULL;
|
|
|
|
rtd = snd_soc_get_pcm_runtime(card, be_dl_name);
|
|
if (!rtd) {
|
|
dev_err(card->dev,
|
|
"%s: snd_soc_get_pcm_runtime for %s failed!\n",
|
|
__func__, be_dl_name);
|
|
ret = -EINVAL;
|
|
goto err_pcm_runtime;
|
|
}
|
|
|
|
component = snd_soc_rtdcom_lookup(rtd, "tasha_codec");
|
|
if (!component) {
|
|
dev_err(card->dev, "%s: component is NULL\n", __func__);
|
|
ret = -EINVAL;
|
|
goto err_pcm_runtime;
|
|
}
|
|
|
|
mbhc_calibration = def_ext_mbhc_cal();
|
|
if (!mbhc_calibration) {
|
|
ret = -ENOMEM;
|
|
goto err_mbhc_cal;
|
|
}
|
|
wcd_mbhc_cfg_ptr->calibration = mbhc_calibration;
|
|
ret = tasha_mbhc_hs_detect(component, wcd_mbhc_cfg_ptr);
|
|
if (ret) {
|
|
dev_err(card->dev, "%s: mbhc hs detect failed, err:%d\n",
|
|
__func__, ret);
|
|
goto err_hs_detect;
|
|
}
|
|
return 0;
|
|
|
|
err_hs_detect:
|
|
kfree(mbhc_calibration);
|
|
err_mbhc_cal:
|
|
err_pcm_runtime:
|
|
return ret;
|
|
}
|
|
|
|
int msm_snd_card_tavil_late_probe(struct snd_soc_card *card)
|
|
{
|
|
const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX;
|
|
struct snd_soc_pcm_runtime *rtd;
|
|
int ret = 0;
|
|
void *mbhc_calibration;
|
|
struct snd_soc_component *component = NULL;
|
|
|
|
rtd = snd_soc_get_pcm_runtime(card, be_dl_name);
|
|
if (!rtd) {
|
|
dev_err(card->dev,
|
|
"%s: snd_soc_get_pcm_runtime for %s failed!\n",
|
|
__func__, be_dl_name);
|
|
ret = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
component = snd_soc_rtdcom_lookup(rtd, "tavil_codec");
|
|
if (!component) {
|
|
dev_err(card->dev, "%s: component is NULL\n", __func__);
|
|
ret = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
mbhc_calibration = def_ext_mbhc_cal();
|
|
if (!mbhc_calibration) {
|
|
ret = -ENOMEM;
|
|
goto err;
|
|
}
|
|
wcd_mbhc_cfg_ptr->calibration = mbhc_calibration;
|
|
ret = tavil_mbhc_hs_detect(component, wcd_mbhc_cfg_ptr);
|
|
if (ret) {
|
|
dev_err(card->dev, "%s: mbhc hs detect failed, err:%d\n",
|
|
__func__, ret);
|
|
goto err_free_mbhc_cal;
|
|
}
|
|
return 0;
|
|
|
|
err_free_mbhc_cal:
|
|
kfree(mbhc_calibration);
|
|
err:
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* msm_audrx_init - Audio init function of sound card instantiate.
|
|
*
|
|
* @rtd: runtime dailink instance
|
|
*
|
|
* Returns 0 on success or ret on failure.
|
|
*/
|
|
int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
|
|
{
|
|
int ret;
|
|
void *config_data;
|
|
struct snd_soc_component *component;
|
|
struct snd_soc_dapm_context *dapm;
|
|
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
|
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
|
struct snd_soc_component *aux_comp;
|
|
struct snd_card *card = rtd->card->snd_card;
|
|
struct snd_info_entry *entry;
|
|
struct msm_asoc_mach_data *pdata =
|
|
snd_soc_card_get_drvdata(rtd->card);
|
|
|
|
/* Codec SLIMBUS configuration
|
|
* RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
|
|
* TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
|
|
* TX14, TX15, TX16
|
|
*/
|
|
unsigned int rx_ch[TASHA_RX_MAX] = {144, 145, 146, 147, 148, 149, 150,
|
|
151, 152, 153, 154, 155, 156};
|
|
unsigned int tx_ch[TASHA_TX_MAX] = {128, 129, 130, 131, 132, 133,
|
|
134, 135, 136, 137, 138, 139,
|
|
140, 141, 142, 143};
|
|
|
|
/* Tavil Codec SLIMBUS configuration
|
|
* RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8
|
|
* TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
|
|
* TX14, TX15, TX16
|
|
*/
|
|
unsigned int rx_ch_tavil[WCD934X_RX_MAX] = {144, 145, 146, 147, 148,
|
|
149, 150, 151};
|
|
unsigned int tx_ch_tavil[WCD934X_TX_MAX] = {128, 129, 130, 131, 132,
|
|
133, 134, 135, 136, 137, 138,
|
|
139, 140, 141, 142, 143};
|
|
|
|
pr_debug("%s: dev_name%s\n", __func__, dev_name(cpu_dai->dev));
|
|
|
|
rtd->pmdown_time = 0;
|
|
if (!strcmp(dev_name(codec_dai->dev), "tavil_codec"))
|
|
component = snd_soc_rtdcom_lookup(rtd, "tavil_codec");
|
|
else if (!strcmp(dev_name(codec_dai->dev), "tasha_codec"))
|
|
component = snd_soc_rtdcom_lookup(rtd, "tasha_codec");
|
|
if (!component) {
|
|
pr_err("%s: component is NULL\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
dapm = snd_soc_component_get_dapm(component);
|
|
|
|
ret = snd_soc_add_component_controls(component, msm_snd_controls,
|
|
ARRAY_SIZE(msm_snd_controls));
|
|
if (ret < 0) {
|
|
pr_err("%s: add_codec_controls failed: %d\n",
|
|
__func__, ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = snd_soc_add_component_controls(component, msm_common_snd_controls,
|
|
msm_common_snd_controls_size());
|
|
if (ret < 0) {
|
|
pr_err("%s: add_common_snd_controls failed: %d\n",
|
|
__func__, ret);
|
|
return ret;
|
|
}
|
|
|
|
snd_soc_dapm_new_controls(dapm, msm_dapm_widgets,
|
|
ARRAY_SIZE(msm_dapm_widgets));
|
|
|
|
if (!strcmp(dev_name(codec_dai->dev), "tasha_codec"))
|
|
snd_soc_dapm_add_routes(dapm, wcd_audio_paths_tasha,
|
|
ARRAY_SIZE(wcd_audio_paths_tasha));
|
|
else
|
|
snd_soc_dapm_add_routes(dapm, wcd_audio_paths,
|
|
ARRAY_SIZE(wcd_audio_paths));
|
|
|
|
snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
|
|
snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
|
|
snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
|
|
snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
|
|
|
|
snd_soc_dapm_ignore_suspend(dapm, "MADINPUT");
|
|
snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_INPUT");
|
|
snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
|
|
snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
|
|
snd_soc_dapm_ignore_suspend(dapm, "Secondary Mic");
|
|
snd_soc_dapm_ignore_suspend(dapm, "Lineout_1 amp");
|
|
snd_soc_dapm_ignore_suspend(dapm, "Lineout_3 amp");
|
|
snd_soc_dapm_ignore_suspend(dapm, "Lineout_2 amp");
|
|
snd_soc_dapm_ignore_suspend(dapm, "Lineout_4 amp");
|
|
snd_soc_dapm_ignore_suspend(dapm, "ANCRight Headset Mic");
|
|
snd_soc_dapm_ignore_suspend(dapm, "ANCLeft Headset Mic");
|
|
snd_soc_dapm_ignore_suspend(dapm, "Digital Mic0");
|
|
snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1");
|
|
snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2");
|
|
snd_soc_dapm_ignore_suspend(dapm, "Digital Mic3");
|
|
snd_soc_dapm_ignore_suspend(dapm, "Digital Mic4");
|
|
snd_soc_dapm_ignore_suspend(dapm, "Digital Mic5");
|
|
snd_soc_dapm_ignore_suspend(dapm, "Analog Mic4");
|
|
snd_soc_dapm_ignore_suspend(dapm, "Analog Mic6");
|
|
snd_soc_dapm_ignore_suspend(dapm, "Analog Mic7");
|
|
snd_soc_dapm_ignore_suspend(dapm, "Analog Mic8");
|
|
|
|
snd_soc_dapm_ignore_suspend(dapm, "EAR");
|
|
snd_soc_dapm_ignore_suspend(dapm, "LINEOUT1");
|
|
snd_soc_dapm_ignore_suspend(dapm, "LINEOUT2");
|
|
snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
|
|
snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
|
|
snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
|
|
snd_soc_dapm_ignore_suspend(dapm, "AMIC4");
|
|
snd_soc_dapm_ignore_suspend(dapm, "AMIC5");
|
|
snd_soc_dapm_ignore_suspend(dapm, "DMIC0");
|
|
snd_soc_dapm_ignore_suspend(dapm, "DMIC1");
|
|
snd_soc_dapm_ignore_suspend(dapm, "DMIC2");
|
|
snd_soc_dapm_ignore_suspend(dapm, "DMIC3");
|
|
snd_soc_dapm_ignore_suspend(dapm, "DMIC4");
|
|
snd_soc_dapm_ignore_suspend(dapm, "DMIC5");
|
|
snd_soc_dapm_ignore_suspend(dapm, "ANC EAR");
|
|
snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT");
|
|
snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT");
|
|
snd_soc_dapm_ignore_suspend(dapm, "HPHL");
|
|
snd_soc_dapm_ignore_suspend(dapm, "HPHR");
|
|
snd_soc_dapm_ignore_suspend(dapm, "AIF4 VI");
|
|
snd_soc_dapm_ignore_suspend(dapm, "VIINPUT");
|
|
|
|
if (!strcmp(dev_name(codec_dai->dev), "tasha_codec")) {
|
|
snd_soc_dapm_ignore_suspend(dapm, "LINEOUT3");
|
|
snd_soc_dapm_ignore_suspend(dapm, "LINEOUT4");
|
|
snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL");
|
|
snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR");
|
|
snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1");
|
|
snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2");
|
|
} else {
|
|
snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_OUT1");
|
|
snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_OUT2");
|
|
}
|
|
|
|
snd_soc_dapm_sync(dapm);
|
|
|
|
if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) {
|
|
snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch_tavil),
|
|
tx_ch_tavil, ARRAY_SIZE(rx_ch_tavil),
|
|
rx_ch_tavil);
|
|
} else {
|
|
snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
|
|
tx_ch, ARRAY_SIZE(rx_ch),
|
|
rx_ch);
|
|
}
|
|
|
|
if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) {
|
|
msm_codec_fn.get_afe_config_fn = tavil_get_afe_config;
|
|
} else {
|
|
msm_codec_fn.get_afe_config_fn = tasha_get_afe_config;
|
|
msm_codec_fn.mbhc_hs_detect_exit = tasha_mbhc_hs_detect_exit;
|
|
}
|
|
|
|
ret = msm_adsp_power_up_config(component, rtd->card->snd_card);
|
|
if (ret) {
|
|
pr_err("%s: Failed to set AFE config %d\n", __func__, ret);
|
|
goto err_afe_cfg;
|
|
}
|
|
|
|
config_data = msm_codec_fn.get_afe_config_fn(component,
|
|
AFE_AANC_VERSION);
|
|
if (config_data) {
|
|
ret = afe_set_config(AFE_AANC_VERSION, config_data, 0);
|
|
if (ret) {
|
|
pr_err("%s: Failed to set aanc version %d\n",
|
|
__func__, ret);
|
|
goto err_afe_cfg;
|
|
}
|
|
}
|
|
|
|
if (!strcmp(dev_name(codec_dai->dev), "tasha_codec")) {
|
|
config_data = msm_codec_fn.get_afe_config_fn(component,
|
|
AFE_CDC_CLIP_REGISTERS_CONFIG);
|
|
if (config_data) {
|
|
ret = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
|
|
config_data, 0);
|
|
if (ret) {
|
|
pr_err("%s: Failed to set clip registers %d\n",
|
|
__func__, ret);
|
|
goto err_afe_cfg;
|
|
}
|
|
}
|
|
config_data = msm_codec_fn.get_afe_config_fn(component,
|
|
AFE_CLIP_BANK_SEL);
|
|
if (config_data) {
|
|
ret = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0);
|
|
if (ret) {
|
|
pr_err("%s: Failed to set AFE bank selection %d\n",
|
|
__func__, ret);
|
|
goto err_afe_cfg;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Send speaker configuration only for WSA8810.
|
|
* Defalut configuration is for WSA8815.
|
|
*/
|
|
pr_debug("%s: Number of aux devices: %d\n",
|
|
__func__, rtd->card->num_aux_devs);
|
|
|
|
if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) {
|
|
if (rtd->card->num_aux_devs &&
|
|
!list_empty(&rtd->card->aux_comp_list)) {
|
|
aux_comp = list_first_entry(&rtd->card->aux_comp_list,
|
|
struct snd_soc_component, card_aux_list);
|
|
if (!strcmp(aux_comp->name, WSA8810_NAME_1) ||
|
|
!strcmp(aux_comp->name, WSA8810_NAME_2)) {
|
|
tavil_set_spkr_mode(component, SPKR_MODE_1);
|
|
tavil_set_spkr_gain_offset(component,
|
|
RX_GAIN_OFFSET_M1P5_DB);
|
|
}
|
|
}
|
|
card = rtd->card->snd_card;
|
|
entry = snd_info_create_subdir(card->module, "codecs",
|
|
card->proc_root);
|
|
if (!entry) {
|
|
pr_debug("%s: Cannot create codecs module entry\n",
|
|
__func__);
|
|
goto done;
|
|
}
|
|
pdata->codec_root = entry;
|
|
tavil_codec_info_create_codec_entry(pdata->codec_root,
|
|
component);
|
|
} else {
|
|
if (rtd->card->num_aux_devs &&
|
|
!list_empty(&rtd->card->aux_comp_list)) {
|
|
aux_comp = list_first_entry(&rtd->card->aux_comp_list,
|
|
struct snd_soc_component, card_aux_list);
|
|
if (!strcmp(aux_comp->name, WSA8810_NAME_1) ||
|
|
!strcmp(aux_comp->name, WSA8810_NAME_2)) {
|
|
tasha_set_spkr_mode(component, SPKR_MODE_1);
|
|
tasha_set_spkr_gain_offset(component,
|
|
RX_GAIN_OFFSET_M1P5_DB);
|
|
}
|
|
}
|
|
card = rtd->card->snd_card;
|
|
entry = snd_info_create_subdir(card->module, "codecs",
|
|
card->proc_root);
|
|
if (!entry) {
|
|
pr_debug("%s: Cannot create codecs module entry\n",
|
|
__func__);
|
|
goto done;
|
|
}
|
|
pdata->codec_root = entry;
|
|
tasha_codec_info_create_codec_entry(pdata->codec_root,
|
|
component);
|
|
tasha_mbhc_zdet_gpio_ctrl(msm_config_hph_en0_gpio,
|
|
component);
|
|
}
|
|
done:
|
|
msm_set_codec_reg_done(true);
|
|
return 0;
|
|
|
|
err_afe_cfg:
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(msm_audrx_init);
|
|
|
|
/**
|
|
* msm_ext_register_audio_notifier - register SSR notifier.
|
|
*/
|
|
void msm_ext_register_audio_notifier(struct platform_device *pdev)
|
|
{
|
|
int ret;
|
|
|
|
is_initial_boot = true;
|
|
spdev = pdev;
|
|
ret = audio_notifier_register("sdm660", AUDIO_NOTIFIER_ADSP_DOMAIN,
|
|
&service_nb);
|
|
if (ret < 0)
|
|
pr_err("%s: Audio notifier register failed ret = %d\n",
|
|
__func__, ret);
|
|
}
|
|
EXPORT_SYMBOL(msm_ext_register_audio_notifier);
|
|
|
|
/**
|
|
* msm_ext_cdc_init - external codec machine specific init.
|
|
*
|
|
* @pdev: platform device handle
|
|
* @pdata: private data of machine driver
|
|
* @card: sound card pointer reference
|
|
* @mbhc_cfg: MBHC config reference
|
|
*
|
|
* Returns 0 on success or ret on failure.
|
|
*/
|
|
int msm_ext_cdc_init(struct platform_device *pdev,
|
|
struct msm_asoc_mach_data *pdata,
|
|
struct snd_soc_card **card,
|
|
struct wcd_mbhc_config *wcd_mbhc_cfg_ptr1)
|
|
{
|
|
int ret = 0;
|
|
|
|
wcd_mbhc_cfg_ptr = wcd_mbhc_cfg_ptr1;
|
|
pdev->id = 0;
|
|
wcd_mbhc_cfg_ptr->moisture_en = true;
|
|
wcd_mbhc_cfg_ptr->mbhc_micbias = MIC_BIAS_2;
|
|
wcd_mbhc_cfg_ptr->anc_micbias = MIC_BIAS_2;
|
|
wcd_mbhc_cfg_ptr->enable_anc_mic_detect = false;
|
|
|
|
*card = populate_snd_card_dailinks(&pdev->dev, pdata->snd_card_val);
|
|
if (!(*card)) {
|
|
dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__);
|
|
ret = -EPROBE_DEFER;
|
|
goto err;
|
|
}
|
|
platform_set_drvdata(pdev, *card);
|
|
snd_soc_card_set_drvdata(*card, pdata);
|
|
pdata->hph_en1_gpio = of_get_named_gpio(pdev->dev.of_node,
|
|
"qcom,hph-en1-gpio", 0);
|
|
if (!gpio_is_valid(pdata->hph_en1_gpio))
|
|
pdata->hph_en1_gpio_p = of_parse_phandle(pdev->dev.of_node,
|
|
"qcom,hph-en1-gpio", 0);
|
|
if (!gpio_is_valid(pdata->hph_en1_gpio) && (!pdata->hph_en1_gpio_p)) {
|
|
dev_dbg(&pdev->dev, "property %s not detected in node %s",
|
|
"qcom,hph-en1-gpio", pdev->dev.of_node->full_name);
|
|
}
|
|
|
|
pdata->hph_en0_gpio = of_get_named_gpio(pdev->dev.of_node,
|
|
"qcom,hph-en0-gpio", 0);
|
|
if (!gpio_is_valid(pdata->hph_en0_gpio))
|
|
pdata->hph_en0_gpio_p = of_parse_phandle(pdev->dev.of_node,
|
|
"qcom,hph-en0-gpio", 0);
|
|
if (!gpio_is_valid(pdata->hph_en0_gpio) && (!pdata->hph_en0_gpio_p)) {
|
|
dev_dbg(&pdev->dev, "property %s not detected in node %s",
|
|
"qcom,hph-en0-gpio", pdev->dev.of_node->full_name);
|
|
}
|
|
|
|
ret = msm_ext_prepare_hifi(pdata);
|
|
if (ret) {
|
|
dev_dbg(&pdev->dev, "msm_ext_prepare_hifi failed (%d)\n",
|
|
ret);
|
|
ret = 0;
|
|
}
|
|
pdata->msm_snd_intr_lpi.mpm_wakeup =
|
|
ioremap(TLMM_CENTER_MPM_WAKEUP_INT_EN_0, 4);
|
|
pdata->msm_snd_intr_lpi.intr1_cfg_apps =
|
|
ioremap(TLMM_LPI_DIR_CONN_INTR1_CFG_APPS, 4);
|
|
pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg =
|
|
ioremap(TLMM_LPI_GPIO_INTR_CFG1, 4);
|
|
pdata->msm_snd_intr_lpi.lpi_gpio_cfg =
|
|
ioremap(TLMM_LPI_GPIO22_CFG, 4);
|
|
pdata->msm_snd_intr_lpi.lpi_gpio_inout =
|
|
ioremap(TLMM_LPI_GPIO22_INOUT, 4);
|
|
err:
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(msm_ext_cdc_init);
|
|
|
|
/**
|
|
* msm_ext_cdc_deinit - external codec machine specific deinit.
|
|
*/
|
|
void msm_ext_cdc_deinit(struct msm_asoc_mach_data *pdata)
|
|
{
|
|
if (pdata->msm_snd_intr_lpi.mpm_wakeup)
|
|
iounmap(pdata->msm_snd_intr_lpi.mpm_wakeup);
|
|
if (pdata->msm_snd_intr_lpi.intr1_cfg_apps)
|
|
iounmap(pdata->msm_snd_intr_lpi.intr1_cfg_apps);
|
|
if (pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg)
|
|
iounmap(pdata->msm_snd_intr_lpi.lpi_gpio_intr_cfg);
|
|
if (pdata->msm_snd_intr_lpi.lpi_gpio_cfg)
|
|
iounmap(pdata->msm_snd_intr_lpi.lpi_gpio_cfg);
|
|
if (pdata->msm_snd_intr_lpi.lpi_gpio_inout)
|
|
iounmap(pdata->msm_snd_intr_lpi.lpi_gpio_inout);
|
|
}
|
|
EXPORT_SYMBOL(msm_ext_cdc_deinit);
|