2017-07-20 09:01:55 -04:00
|
|
|
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
|
|
* only 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/input.h>
|
|
|
|
#include <linux/of_gpio.h>
|
2017-07-25 06:59:27 -04:00
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <linux/of_device.h>
|
2017-07-20 09:01:55 -04:00
|
|
|
#include <sound/pcm_params.h>
|
2017-08-01 12:32:15 -04:00
|
|
|
#include <dsp/q6afe-v2.h>
|
2017-10-17 22:52:07 -04:00
|
|
|
#include <dsp/audio_notifier.h>
|
2017-08-01 12:32:15 -04:00
|
|
|
#include "msm-pcm-routing-v2.h"
|
2017-07-20 09:01:55 -04:00
|
|
|
#include "sdm660-common.h"
|
|
|
|
#include "sdm660-internal.h"
|
|
|
|
#include "sdm660-external.h"
|
2017-08-01 12:32:15 -04:00
|
|
|
#include "codecs/msm-cdc-pinctrl.h"
|
|
|
|
#include "codecs/sdm660_cdc/msm-analog-cdc.h"
|
|
|
|
#include "codecs/wsa881x.h"
|
2017-07-20 09:01:55 -04:00
|
|
|
|
|
|
|
#define DRV_NAME "sdm660-asoc-snd"
|
|
|
|
|
|
|
|
#define MSM_INT_DIGITAL_CODEC "msm-dig-codec"
|
|
|
|
#define PMIC_INT_ANALOG_CODEC "analog-codec"
|
|
|
|
|
|
|
|
#define DEV_NAME_STR_LEN 32
|
|
|
|
#define DEFAULT_MCLK_RATE 9600000
|
|
|
|
|
|
|
|
struct dev_config {
|
|
|
|
u32 sample_rate;
|
|
|
|
u32 bit_format;
|
|
|
|
u32 channels;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
DP_RX_IDX,
|
|
|
|
EXT_DISP_RX_IDX_MAX,
|
|
|
|
};
|
|
|
|
|
2017-08-17 08:51:59 -04:00
|
|
|
bool codec_reg_done;
|
|
|
|
|
2017-07-20 09:01:55 -04:00
|
|
|
/* TDM default config */
|
|
|
|
static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
|
|
|
|
{ /* PRI TDM */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
|
|
|
|
},
|
|
|
|
{ /* SEC TDM */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
|
|
|
|
},
|
|
|
|
{ /* TERT TDM */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
|
|
|
|
},
|
|
|
|
{ /* QUAT TDM */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
|
2017-09-10 13:27:39 -04:00
|
|
|
},
|
|
|
|
{ /* QUIN TDM */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
|
2017-07-20 09:01:55 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* TDM default config */
|
|
|
|
static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
|
|
|
|
{ /* PRI TDM */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
|
|
|
|
},
|
|
|
|
{ /* SEC TDM */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
|
|
|
|
},
|
|
|
|
{ /* TERT TDM */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
|
|
|
|
},
|
|
|
|
{ /* QUAT TDM */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
|
2017-09-10 13:27:39 -04:00
|
|
|
},
|
|
|
|
{ /* QUIN TDM */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
|
|
|
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
|
2017-07-20 09:01:55 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Default configuration of external display BE */
|
|
|
|
static struct dev_config ext_disp_rx_cfg[] = {
|
|
|
|
[DP_RX_IDX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
|
|
|
|
};
|
|
|
|
static struct dev_config usb_rx_cfg = {
|
|
|
|
.sample_rate = SAMPLING_RATE_48KHZ,
|
|
|
|
.bit_format = SNDRV_PCM_FORMAT_S16_LE,
|
|
|
|
.channels = 2,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct dev_config usb_tx_cfg = {
|
|
|
|
.sample_rate = SAMPLING_RATE_48KHZ,
|
|
|
|
.bit_format = SNDRV_PCM_FORMAT_S16_LE,
|
|
|
|
.channels = 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
PRIM_AUX_PCM = 0,
|
|
|
|
SEC_AUX_PCM,
|
|
|
|
TERT_AUX_PCM,
|
|
|
|
QUAT_AUX_PCM,
|
2017-09-10 13:27:39 -04:00
|
|
|
QUIN_AUX_PCM,
|
2017-07-20 09:01:55 -04:00
|
|
|
AUX_PCM_MAX,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
PCM_I2S_SEL_PRIM = 0,
|
|
|
|
PCM_I2S_SEL_SEC,
|
|
|
|
PCM_I2S_SEL_TERT,
|
|
|
|
PCM_I2S_SEL_QUAT,
|
2017-09-10 13:27:39 -04:00
|
|
|
PCM_I2S_SEL_QUIN,
|
2017-07-20 09:01:55 -04:00
|
|
|
PCM_I2S_SEL_MAX,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct mi2s_conf {
|
|
|
|
struct mutex lock;
|
|
|
|
u32 ref_cnt;
|
|
|
|
u32 msm_is_mi2s_master;
|
|
|
|
u32 msm_is_ext_mclk;
|
|
|
|
};
|
|
|
|
|
|
|
|
static u32 mi2s_ebit_clk[MI2S_MAX] = {
|
|
|
|
Q6AFE_LPASS_CLK_ID_PRI_MI2S_EBIT,
|
|
|
|
Q6AFE_LPASS_CLK_ID_SEC_MI2S_EBIT,
|
|
|
|
Q6AFE_LPASS_CLK_ID_TER_MI2S_EBIT,
|
2017-10-02 01:05:21 -04:00
|
|
|
Q6AFE_LPASS_CLK_ID_QUAD_MI2S_EBIT,
|
|
|
|
Q6AFE_LPASS_CLK_ID_QUI_MI2S_EBIT
|
2017-07-20 09:01:55 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct msm_wsa881x_dev_info {
|
|
|
|
struct device_node *of_node;
|
|
|
|
u32 index;
|
|
|
|
};
|
|
|
|
static struct snd_soc_aux_dev *msm_aux_dev;
|
|
|
|
static struct snd_soc_codec_conf *msm_codec_conf;
|
|
|
|
|
2017-07-25 06:59:27 -04:00
|
|
|
static bool msm_swap_gnd_mic(struct snd_soc_codec *codec, bool active);
|
2017-07-20 09:01:55 -04:00
|
|
|
|
|
|
|
static struct wcd_mbhc_config mbhc_cfg = {
|
|
|
|
.read_fw_bin = false,
|
|
|
|
.calibration = NULL,
|
|
|
|
.detect_extn_cable = true,
|
|
|
|
.mono_stero_detection = false,
|
|
|
|
.swap_gnd_mic = NULL,
|
|
|
|
.hs_ext_micbias = true,
|
|
|
|
.key_code[0] = KEY_MEDIA,
|
|
|
|
.key_code[1] = KEY_VOICECOMMAND,
|
|
|
|
.key_code[2] = KEY_VOLUMEUP,
|
|
|
|
.key_code[3] = KEY_VOLUMEDOWN,
|
|
|
|
.key_code[4] = 0,
|
|
|
|
.key_code[5] = 0,
|
|
|
|
.key_code[6] = 0,
|
|
|
|
.key_code[7] = 0,
|
|
|
|
.linein_th = 5000,
|
|
|
|
.moisture_en = false,
|
|
|
|
.mbhc_micbias = 0,
|
|
|
|
.anc_micbias = 0,
|
|
|
|
.enable_anc_mic_detect = false,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct dev_config proxy_rx_cfg = {
|
|
|
|
.sample_rate = SAMPLING_RATE_48KHZ,
|
|
|
|
.bit_format = SNDRV_PCM_FORMAT_S16_LE,
|
|
|
|
.channels = 2,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Default configuration of MI2S channels */
|
|
|
|
static struct dev_config mi2s_rx_cfg[] = {
|
|
|
|
[PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
|
|
|
|
[SEC_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
|
|
|
|
[TERT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
|
|
|
|
[QUAT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
|
2017-09-10 13:27:39 -04:00
|
|
|
[QUIN_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
|
2017-07-20 09:01:55 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct dev_config mi2s_tx_cfg[] = {
|
|
|
|
[PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
|
|
[SEC_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
|
|
[TERT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
|
|
[QUAT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
2017-09-10 13:27:39 -04:00
|
|
|
[QUIN_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
2017-07-20 09:01:55 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct dev_config aux_pcm_rx_cfg[] = {
|
|
|
|
[PRIM_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
|
|
[SEC_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
|
|
[TERT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
|
|
[QUAT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
2017-09-10 13:27:39 -04:00
|
|
|
[QUIN_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
2017-07-20 09:01:55 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct dev_config aux_pcm_tx_cfg[] = {
|
|
|
|
[PRIM_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
|
|
[SEC_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
|
|
[TERT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
|
|
|
[QUAT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
2017-09-10 13:27:39 -04:00
|
|
|
[QUIN_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
2017-07-20 09:01:55 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
static char const *ch_text[] = {"Two", "Three", "Four", "Five",
|
|
|
|
"Six", "Seven", "Eight"};
|
|
|
|
static const char *const auxpcm_rate_text[] = {"KHZ_8", "KHZ_16"};
|
|
|
|
static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_16",
|
|
|
|
"KHZ_32", "KHZ_44P1", "KHZ_48",
|
|
|
|
"KHZ_96", "KHZ_192"};
|
|
|
|
static const char *const mi2s_ch_text[] = {"One", "Two", "Three", "Four",
|
|
|
|
"Five", "Six", "Seven",
|
|
|
|
"Eight"};
|
|
|
|
static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
|
|
|
|
"S32_LE"};
|
|
|
|
static char const *mi2s_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
|
|
|
|
"S32_LE"};
|
|
|
|
static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four",
|
|
|
|
"Five", "Six", "Seven", "Eight"};
|
|
|
|
static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"};
|
|
|
|
static char const *tdm_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32",
|
|
|
|
"KHZ_44P1", "KHZ_48", "KHZ_96",
|
|
|
|
"KHZ_192", "KHZ_352P8", "KHZ_384"};
|
|
|
|
static const char *const usb_ch_text[] = {"One", "Two", "Three", "Four",
|
|
|
|
"Five", "Six", "Seven",
|
|
|
|
"Eight"};
|
|
|
|
static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025",
|
|
|
|
"KHZ_16", "KHZ_22P05",
|
|
|
|
"KHZ_32", "KHZ_44P1", "KHZ_48",
|
|
|
|
"KHZ_96", "KHZ_192", "KHZ_384"};
|
|
|
|
static char const *ext_disp_bit_format_text[] = {"S16_LE", "S24_LE"};
|
|
|
|
static char const *ext_disp_sample_rate_text[] = {"KHZ_48", "KHZ_96",
|
|
|
|
"KHZ_192"};
|
|
|
|
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_chs, ch_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_rx_sample_rate, auxpcm_rate_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_rx_sample_rate, auxpcm_rate_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_rx_sample_rate, auxpcm_rate_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(quat_aux_pcm_rx_sample_rate, auxpcm_rate_text);
|
2017-09-10 13:27:39 -04:00
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(quin_aux_pcm_rx_sample_rate, auxpcm_rate_text);
|
2017-07-20 09:01:55 -04:00
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_tx_sample_rate, auxpcm_rate_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_tx_sample_rate, auxpcm_rate_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_tx_sample_rate, auxpcm_rate_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(quat_aux_pcm_tx_sample_rate, auxpcm_rate_text);
|
2017-09-10 13:27:39 -04:00
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(quin_aux_pcm_tx_sample_rate, auxpcm_rate_text);
|
2017-07-20 09:01:55 -04:00
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_sample_rate, mi2s_rate_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_sample_rate, mi2s_rate_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_sample_rate, mi2s_rate_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_sample_rate, mi2s_rate_text);
|
2017-09-10 13:27:39 -04:00
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(quin_mi2s_rx_sample_rate, mi2s_rate_text);
|
2017-07-20 09:01:55 -04:00
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_sample_rate, mi2s_rate_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_sample_rate, mi2s_rate_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_sample_rate, mi2s_rate_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_sample_rate, mi2s_rate_text);
|
2017-09-10 13:27:39 -04:00
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(quin_mi2s_tx_sample_rate, mi2s_rate_text);
|
2017-07-20 09:01:55 -04:00
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_format, mi2s_format_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_format, mi2s_format_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_format, mi2s_format_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_format, mi2s_format_text);
|
2017-09-10 13:27:39 -04:00
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(quin_mi2s_rx_format, mi2s_format_text);
|
2017-07-20 09:01:55 -04:00
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_format, mi2s_format_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_format, mi2s_format_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_format, mi2s_format_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_format, mi2s_format_text);
|
2017-09-10 13:27:39 -04:00
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(quin_mi2s_tx_format, mi2s_format_text);
|
2017-07-20 09:01:55 -04:00
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_chs, mi2s_ch_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_chs, mi2s_ch_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_chs, mi2s_ch_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_chs, mi2s_ch_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_chs, mi2s_ch_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_chs, mi2s_ch_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_chs, mi2s_ch_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_chs, mi2s_ch_text);
|
2017-09-10 13:27:39 -04:00
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(quin_mi2s_rx_chs, mi2s_ch_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(quin_mi2s_tx_chs, mi2s_ch_text);
|
2017-07-20 09:01:55 -04:00
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_format, ext_disp_bit_format_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_sample_rate,
|
|
|
|
ext_disp_sample_rate_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_chs, tdm_ch_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_format, tdm_bit_format_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_sample_rate, tdm_sample_rate_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_chs, tdm_ch_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_format, tdm_bit_format_text);
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_sample_rate, tdm_sample_rate_text);
|
|
|
|
|
|
|
|
static struct afe_clk_set mi2s_clk[MI2S_MAX] = {
|
|
|
|
{
|
|
|
|
AFE_API_VERSION_I2S_CONFIG,
|
|
|
|
Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
|
|
|
|
Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
|
|
|
|
Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
|
|
|
|
Q6AFE_LPASS_CLK_ROOT_DEFAULT,
|
|
|
|
0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
AFE_API_VERSION_I2S_CONFIG,
|
|
|
|
Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
|
|
|
|
Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
|
|
|
|
Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
|
|
|
|
Q6AFE_LPASS_CLK_ROOT_DEFAULT,
|
|
|
|
0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
AFE_API_VERSION_I2S_CONFIG,
|
|
|
|
Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
|
|
|
|
Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
|
|
|
|
Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
|
|
|
|
Q6AFE_LPASS_CLK_ROOT_DEFAULT,
|
|
|
|
0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
AFE_API_VERSION_I2S_CONFIG,
|
|
|
|
Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT,
|
|
|
|
Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
|
|
|
|
Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
|
|
|
|
Q6AFE_LPASS_CLK_ROOT_DEFAULT,
|
|
|
|
0,
|
2017-10-02 01:05:21 -04:00
|
|
|
},
|
|
|
|
{
|
|
|
|
AFE_API_VERSION_I2S_CONFIG,
|
|
|
|
Q6AFE_LPASS_CLK_ID_QUI_MI2S_IBIT,
|
|
|
|
Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
|
|
|
|
Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
|
|
|
|
Q6AFE_LPASS_CLK_ROOT_DEFAULT,
|
|
|
|
0,
|
2017-07-20 09:01:55 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct afe_clk_set mi2s_mclk[MI2S_MAX] = {
|
|
|
|
{
|
|
|
|
AFE_API_VERSION_I2S_CONFIG,
|
|
|
|
Q6AFE_LPASS_CLK_ID_MCLK_3,
|
|
|
|
Q6AFE_LPASS_OSR_CLK_9_P600_MHZ,
|
|
|
|
Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
|
|
|
|
Q6AFE_LPASS_CLK_ROOT_DEFAULT,
|
|
|
|
0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
AFE_API_VERSION_I2S_CONFIG,
|
2017-10-02 01:05:21 -04:00
|
|
|
Q6AFE_LPASS_CLK_ID_MCLK_2,
|
2017-07-20 09:01:55 -04:00
|
|
|
Q6AFE_LPASS_OSR_CLK_9_P600_MHZ,
|
|
|
|
Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
|
|
|
|
Q6AFE_LPASS_CLK_ROOT_DEFAULT,
|
|
|
|
0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
AFE_API_VERSION_I2S_CONFIG,
|
|
|
|
Q6AFE_LPASS_CLK_ID_MCLK_1,
|
|
|
|
Q6AFE_LPASS_OSR_CLK_9_P600_MHZ,
|
|
|
|
Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
|
|
|
|
Q6AFE_LPASS_CLK_ROOT_DEFAULT,
|
|
|
|
0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
AFE_API_VERSION_I2S_CONFIG,
|
2017-10-02 01:05:21 -04:00
|
|
|
Q6AFE_LPASS_CLK_ID_MCLK_1,
|
|
|
|
Q6AFE_LPASS_OSR_CLK_9_P600_MHZ,
|
|
|
|
Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
|
|
|
|
Q6AFE_LPASS_CLK_ROOT_DEFAULT,
|
|
|
|
0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
AFE_API_VERSION_I2S_CONFIG,
|
|
|
|
Q6AFE_LPASS_CLK_ID_QUI_MI2S_OSR,
|
2017-07-20 09:01:55 -04:00
|
|
|
Q6AFE_LPASS_OSR_CLK_9_P600_MHZ,
|
|
|
|
Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
|
|
|
|
Q6AFE_LPASS_CLK_ROOT_DEFAULT,
|
|
|
|
0,
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct mi2s_conf mi2s_intf_conf[MI2S_MAX];
|
|
|
|
|
|
|
|
static int proxy_rx_ch_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
pr_debug("%s: proxy_rx channels = %d\n",
|
|
|
|
__func__, proxy_rx_cfg.channels);
|
|
|
|
ucontrol->value.integer.value[0] = proxy_rx_cfg.channels - 2;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int proxy_rx_ch_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
proxy_rx_cfg.channels = ucontrol->value.integer.value[0] + 2;
|
|
|
|
pr_debug("%s: proxy_rx channels = %d\n",
|
|
|
|
__func__, proxy_rx_cfg.channels);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tdm_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_96KHZ;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
sample_rate = SAMPLING_RATE_192KHZ;
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
sample_rate = SAMPLING_RATE_352P8KHZ;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
sample_rate = SAMPLING_RATE_384KHZ;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
sample_rate = SAMPLING_RATE_48KHZ;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return sample_rate;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tdm_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_96KHZ:
|
|
|
|
sample_rate_val = 5;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_192KHZ:
|
|
|
|
sample_rate_val = 6;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_352P8KHZ:
|
|
|
|
sample_rate_val = 7;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_384KHZ:
|
|
|
|
sample_rate_val = 8;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
sample_rate_val = 4;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return sample_rate_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tdm_get_port_idx(struct snd_kcontrol *kcontrol,
|
|
|
|
struct tdm_port *port)
|
|
|
|
{
|
|
|
|
if (port) {
|
|
|
|
if (strnstr(kcontrol->id.name, "PRI",
|
|
|
|
sizeof(kcontrol->id.name))) {
|
|
|
|
port->mode = TDM_PRI;
|
|
|
|
} else if (strnstr(kcontrol->id.name, "SEC",
|
|
|
|
sizeof(kcontrol->id.name))) {
|
|
|
|
port->mode = TDM_SEC;
|
|
|
|
} else if (strnstr(kcontrol->id.name, "TERT",
|
|
|
|
sizeof(kcontrol->id.name))) {
|
|
|
|
port->mode = TDM_TERT;
|
|
|
|
} else if (strnstr(kcontrol->id.name, "QUAT",
|
|
|
|
sizeof(kcontrol->id.name))) {
|
|
|
|
port->mode = TDM_QUAT;
|
2017-09-10 13:27:39 -04:00
|
|
|
} else if (strnstr(kcontrol->id.name, "QUIN",
|
|
|
|
sizeof(kcontrol->id.name))) {
|
|
|
|
port->mode = TDM_QUIN;
|
2017-07-20 09:01:55 -04:00
|
|
|
} else {
|
|
|
|
pr_err("%s: unsupported mode in: %s",
|
|
|
|
__func__, kcontrol->id.name);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strnstr(kcontrol->id.name, "RX_0",
|
|
|
|
sizeof(kcontrol->id.name)) ||
|
|
|
|
strnstr(kcontrol->id.name, "TX_0",
|
|
|
|
sizeof(kcontrol->id.name))) {
|
|
|
|
port->channel = TDM_0;
|
|
|
|
} else if (strnstr(kcontrol->id.name, "RX_1",
|
|
|
|
sizeof(kcontrol->id.name)) ||
|
|
|
|
strnstr(kcontrol->id.name, "TX_1",
|
|
|
|
sizeof(kcontrol->id.name))) {
|
|
|
|
port->channel = TDM_1;
|
|
|
|
} else if (strnstr(kcontrol->id.name, "RX_2",
|
|
|
|
sizeof(kcontrol->id.name)) ||
|
|
|
|
strnstr(kcontrol->id.name, "TX_2",
|
|
|
|
sizeof(kcontrol->id.name))) {
|
|
|
|
port->channel = TDM_2;
|
|
|
|
} else if (strnstr(kcontrol->id.name, "RX_3",
|
|
|
|
sizeof(kcontrol->id.name)) ||
|
|
|
|
strnstr(kcontrol->id.name, "TX_3",
|
|
|
|
sizeof(kcontrol->id.name))) {
|
|
|
|
port->channel = TDM_3;
|
|
|
|
} else if (strnstr(kcontrol->id.name, "RX_4",
|
|
|
|
sizeof(kcontrol->id.name)) ||
|
|
|
|
strnstr(kcontrol->id.name, "TX_4",
|
|
|
|
sizeof(kcontrol->id.name))) {
|
|
|
|
port->channel = TDM_4;
|
|
|
|
} else if (strnstr(kcontrol->id.name, "RX_5",
|
|
|
|
sizeof(kcontrol->id.name)) ||
|
|
|
|
strnstr(kcontrol->id.name, "TX_5",
|
|
|
|
sizeof(kcontrol->id.name))) {
|
|
|
|
port->channel = TDM_5;
|
|
|
|
} else if (strnstr(kcontrol->id.name, "RX_6",
|
|
|
|
sizeof(kcontrol->id.name)) ||
|
|
|
|
strnstr(kcontrol->id.name, "TX_6",
|
|
|
|
sizeof(kcontrol->id.name))) {
|
|
|
|
port->channel = TDM_6;
|
|
|
|
} else if (strnstr(kcontrol->id.name, "RX_7",
|
|
|
|
sizeof(kcontrol->id.name)) ||
|
|
|
|
strnstr(kcontrol->id.name, "TX_7",
|
|
|
|
sizeof(kcontrol->id.name))) {
|
|
|
|
port->channel = TDM_7;
|
|
|
|
} else {
|
|
|
|
pr_err("%s: unsupported channel in: %s",
|
|
|
|
__func__, kcontrol->id.name);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
return -EINVAL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tdm_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct tdm_port port;
|
|
|
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: unsupported control: %s",
|
|
|
|
__func__, kcontrol->id.name);
|
|
|
|
} else {
|
|
|
|
ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val(
|
|
|
|
tdm_rx_cfg[port.mode][port.channel].sample_rate);
|
|
|
|
|
|
|
|
pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__,
|
|
|
|
tdm_rx_cfg[port.mode][port.channel].sample_rate,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tdm_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct tdm_port port;
|
|
|
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: unsupported control: %s",
|
|
|
|
__func__, kcontrol->id.name);
|
|
|
|
} else {
|
|
|
|
tdm_rx_cfg[port.mode][port.channel].sample_rate =
|
|
|
|
tdm_get_sample_rate(ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__,
|
|
|
|
tdm_rx_cfg[port.mode][port.channel].sample_rate,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tdm_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct tdm_port port;
|
|
|
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: unsupported control: %s",
|
|
|
|
__func__, kcontrol->id.name);
|
|
|
|
} else {
|
|
|
|
ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val(
|
|
|
|
tdm_tx_cfg[port.mode][port.channel].sample_rate);
|
|
|
|
|
|
|
|
pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__,
|
|
|
|
tdm_tx_cfg[port.mode][port.channel].sample_rate,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tdm_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct tdm_port port;
|
|
|
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: unsupported control: %s",
|
|
|
|
__func__, kcontrol->id.name);
|
|
|
|
} else {
|
|
|
|
tdm_tx_cfg[port.mode][port.channel].sample_rate =
|
|
|
|
tdm_get_sample_rate(ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__,
|
|
|
|
tdm_tx_cfg[port.mode][port.channel].sample_rate,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tdm_get_format(int value)
|
|
|
|
{
|
|
|
|
int format = 0;
|
|
|
|
|
|
|
|
switch (value) {
|
|
|
|
case 0:
|
|
|
|
format = SNDRV_PCM_FORMAT_S16_LE;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
format = SNDRV_PCM_FORMAT_S24_LE;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
format = SNDRV_PCM_FORMAT_S32_LE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
format = SNDRV_PCM_FORMAT_S16_LE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tdm_get_format_val(int format)
|
|
|
|
{
|
|
|
|
int value = 0;
|
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
case SNDRV_PCM_FORMAT_S16_LE:
|
|
|
|
value = 0;
|
|
|
|
break;
|
|
|
|
case SNDRV_PCM_FORMAT_S24_LE:
|
|
|
|
value = 1;
|
|
|
|
break;
|
|
|
|
case SNDRV_PCM_FORMAT_S32_LE:
|
|
|
|
value = 2;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
value = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mi2s_get_format(int value)
|
|
|
|
{
|
|
|
|
int format = 0;
|
|
|
|
|
|
|
|
switch (value) {
|
|
|
|
case 0:
|
|
|
|
format = SNDRV_PCM_FORMAT_S16_LE;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
format = SNDRV_PCM_FORMAT_S24_LE;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
format = SNDRV_PCM_FORMAT_S24_3LE;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
format = SNDRV_PCM_FORMAT_S32_LE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
format = SNDRV_PCM_FORMAT_S16_LE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mi2s_get_format_value(int format)
|
|
|
|
{
|
|
|
|
int value = 0;
|
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
case SNDRV_PCM_FORMAT_S16_LE:
|
|
|
|
value = 0;
|
|
|
|
break;
|
|
|
|
case SNDRV_PCM_FORMAT_S24_LE:
|
|
|
|
value = 1;
|
|
|
|
break;
|
|
|
|
case SNDRV_PCM_FORMAT_S24_3LE:
|
|
|
|
value = 2;
|
|
|
|
break;
|
|
|
|
case SNDRV_PCM_FORMAT_S32_LE:
|
|
|
|
value = 3;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
value = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tdm_rx_format_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct tdm_port port;
|
|
|
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: unsupported control: %s",
|
|
|
|
__func__, kcontrol->id.name);
|
|
|
|
} else {
|
|
|
|
ucontrol->value.enumerated.item[0] = tdm_get_format_val(
|
|
|
|
tdm_rx_cfg[port.mode][port.channel].bit_format);
|
|
|
|
|
|
|
|
pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__,
|
|
|
|
tdm_rx_cfg[port.mode][port.channel].bit_format,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tdm_rx_format_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct tdm_port port;
|
|
|
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: unsupported control: %s",
|
|
|
|
__func__, kcontrol->id.name);
|
|
|
|
} else {
|
|
|
|
tdm_rx_cfg[port.mode][port.channel].bit_format =
|
|
|
|
tdm_get_format(ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__,
|
|
|
|
tdm_rx_cfg[port.mode][port.channel].bit_format,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tdm_tx_format_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct tdm_port port;
|
|
|
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: unsupported control: %s",
|
|
|
|
__func__, kcontrol->id.name);
|
|
|
|
} else {
|
|
|
|
ucontrol->value.enumerated.item[0] = tdm_get_format_val(
|
|
|
|
tdm_tx_cfg[port.mode][port.channel].bit_format);
|
|
|
|
|
|
|
|
pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__,
|
|
|
|
tdm_tx_cfg[port.mode][port.channel].bit_format,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tdm_tx_format_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct tdm_port port;
|
|
|
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: unsupported control: %s",
|
|
|
|
__func__, kcontrol->id.name);
|
|
|
|
} else {
|
|
|
|
tdm_tx_cfg[port.mode][port.channel].bit_format =
|
|
|
|
tdm_get_format(ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__,
|
|
|
|
tdm_tx_cfg[port.mode][port.channel].bit_format,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tdm_rx_ch_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct tdm_port port;
|
|
|
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: unsupported control: %s",
|
|
|
|
__func__, kcontrol->id.name);
|
|
|
|
} else {
|
|
|
|
|
|
|
|
ucontrol->value.enumerated.item[0] =
|
|
|
|
tdm_rx_cfg[port.mode][port.channel].channels - 1;
|
|
|
|
|
|
|
|
pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__,
|
|
|
|
tdm_rx_cfg[port.mode][port.channel].channels - 1,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tdm_rx_ch_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct tdm_port port;
|
|
|
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: unsupported control: %s",
|
|
|
|
__func__, kcontrol->id.name);
|
|
|
|
} else {
|
|
|
|
tdm_rx_cfg[port.mode][port.channel].channels =
|
|
|
|
ucontrol->value.enumerated.item[0] + 1;
|
|
|
|
|
|
|
|
pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__,
|
|
|
|
tdm_rx_cfg[port.mode][port.channel].channels,
|
|
|
|
ucontrol->value.enumerated.item[0] + 1);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tdm_tx_ch_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct tdm_port port;
|
|
|
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: unsupported control: %s",
|
|
|
|
__func__, kcontrol->id.name);
|
|
|
|
} else {
|
|
|
|
ucontrol->value.enumerated.item[0] =
|
|
|
|
tdm_tx_cfg[port.mode][port.channel].channels - 1;
|
|
|
|
|
|
|
|
pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__,
|
|
|
|
tdm_tx_cfg[port.mode][port.channel].channels - 1,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tdm_tx_ch_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct tdm_port port;
|
|
|
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%s: unsupported control: %s",
|
|
|
|
__func__, kcontrol->id.name);
|
|
|
|
} else {
|
|
|
|
tdm_tx_cfg[port.mode][port.channel].channels =
|
|
|
|
ucontrol->value.enumerated.item[0] + 1;
|
|
|
|
|
|
|
|
pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__,
|
|
|
|
tdm_tx_cfg[port.mode][port.channel].channels,
|
|
|
|
ucontrol->value.enumerated.item[0] + 1);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int aux_pcm_get_sample_rate(int value)
|
|
|
|
{
|
|
|
|
int sample_rate;
|
|
|
|
|
|
|
|
switch (value) {
|
|
|
|
case 1:
|
|
|
|
sample_rate = SAMPLING_RATE_16KHZ;
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
default:
|
|
|
|
sample_rate = SAMPLING_RATE_8KHZ;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return sample_rate;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int aux_pcm_get_sample_rate_val(int sample_rate)
|
|
|
|
{
|
|
|
|
int sample_rate_val;
|
|
|
|
|
|
|
|
switch (sample_rate) {
|
|
|
|
case SAMPLING_RATE_16KHZ:
|
|
|
|
sample_rate_val = 1;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_8KHZ:
|
|
|
|
default:
|
|
|
|
sample_rate_val = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return sample_rate_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol)
|
|
|
|
{
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
if (strnstr(kcontrol->id.name, "PRIM_AUX_PCM",
|
|
|
|
sizeof("PRIM_AUX_PCM")))
|
|
|
|
idx = PRIM_AUX_PCM;
|
|
|
|
else if (strnstr(kcontrol->id.name, "SEC_AUX_PCM",
|
|
|
|
sizeof("SEC_AUX_PCM")))
|
|
|
|
idx = SEC_AUX_PCM;
|
|
|
|
else if (strnstr(kcontrol->id.name, "TERT_AUX_PCM",
|
|
|
|
sizeof("TERT_AUX_PCM")))
|
|
|
|
idx = TERT_AUX_PCM;
|
|
|
|
else if (strnstr(kcontrol->id.name, "QUAT_AUX_PCM",
|
|
|
|
sizeof("QUAT_AUX_PCM")))
|
|
|
|
idx = QUAT_AUX_PCM;
|
2017-09-10 13:27:39 -04:00
|
|
|
else if (strnstr(kcontrol->id.name, "QUIN_AUX_PCM",
|
|
|
|
sizeof("QUIN_AUX_PCM")))
|
|
|
|
idx = QUIN_AUX_PCM;
|
2017-07-20 09:01:55 -04:00
|
|
|
else {
|
|
|
|
pr_err("%s: unsupported port: %s",
|
|
|
|
__func__, kcontrol->id.name);
|
|
|
|
idx = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int aux_pcm_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = aux_pcm_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
aux_pcm_rx_cfg[idx].sample_rate =
|
|
|
|
aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
|
|
|
|
idx, aux_pcm_rx_cfg[idx].sample_rate,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int aux_pcm_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = aux_pcm_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
ucontrol->value.enumerated.item[0] =
|
|
|
|
aux_pcm_get_sample_rate_val(aux_pcm_rx_cfg[idx].sample_rate);
|
|
|
|
|
|
|
|
pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
|
|
|
|
idx, aux_pcm_rx_cfg[idx].sample_rate,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int aux_pcm_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = aux_pcm_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
aux_pcm_tx_cfg[idx].sample_rate =
|
|
|
|
aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
|
|
|
|
idx, aux_pcm_tx_cfg[idx].sample_rate,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int aux_pcm_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = aux_pcm_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
ucontrol->value.enumerated.item[0] =
|
|
|
|
aux_pcm_get_sample_rate_val(aux_pcm_tx_cfg[idx].sample_rate);
|
|
|
|
|
|
|
|
pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
|
|
|
|
idx, aux_pcm_tx_cfg[idx].sample_rate,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mi2s_get_port_idx(struct snd_kcontrol *kcontrol)
|
|
|
|
{
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
if (strnstr(kcontrol->id.name, "PRIM_MI2S_RX",
|
|
|
|
sizeof("PRIM_MI2S_RX")))
|
|
|
|
idx = PRIM_MI2S;
|
|
|
|
else if (strnstr(kcontrol->id.name, "SEC_MI2S_RX",
|
|
|
|
sizeof("SEC_MI2S_RX")))
|
|
|
|
idx = SEC_MI2S;
|
|
|
|
else if (strnstr(kcontrol->id.name, "TERT_MI2S_RX",
|
|
|
|
sizeof("TERT_MI2S_RX")))
|
|
|
|
idx = TERT_MI2S;
|
|
|
|
else if (strnstr(kcontrol->id.name, "QUAT_MI2S_RX",
|
|
|
|
sizeof("QUAT_MI2S_RX")))
|
|
|
|
idx = QUAT_MI2S;
|
2017-09-10 13:27:39 -04:00
|
|
|
else if (strnstr(kcontrol->id.name, "QUIN_MI2S_RX",
|
|
|
|
sizeof("QUIN_MI2S_RX")))
|
|
|
|
idx = QUIN_MI2S;
|
2017-07-20 09:01:55 -04:00
|
|
|
else if (strnstr(kcontrol->id.name, "PRIM_MI2S_TX",
|
|
|
|
sizeof("PRIM_MI2S_TX")))
|
|
|
|
idx = PRIM_MI2S;
|
|
|
|
else if (strnstr(kcontrol->id.name, "SEC_MI2S_TX",
|
|
|
|
sizeof("SEC_MI2S_TX")))
|
|
|
|
idx = SEC_MI2S;
|
|
|
|
else if (strnstr(kcontrol->id.name, "TERT_MI2S_TX",
|
|
|
|
sizeof("TERT_MI2S_TX")))
|
|
|
|
idx = TERT_MI2S;
|
|
|
|
else if (strnstr(kcontrol->id.name, "QUAT_MI2S_TX",
|
|
|
|
sizeof("QUAT_MI2S_TX")))
|
|
|
|
idx = QUAT_MI2S;
|
2017-09-10 13:27:39 -04:00
|
|
|
else if (strnstr(kcontrol->id.name, "QUIN_MI2S_TX",
|
|
|
|
sizeof("QUIN_MI2S_TX")))
|
|
|
|
idx = QUIN_MI2S;
|
2017-07-20 09:01:55 -04:00
|
|
|
else {
|
|
|
|
pr_err("%s: unsupported channel: %s",
|
|
|
|
__func__, kcontrol->id.name);
|
|
|
|
idx = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mi2s_get_sample_rate_val(int sample_rate)
|
|
|
|
{
|
|
|
|
int sample_rate_val;
|
|
|
|
|
|
|
|
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_96KHZ:
|
|
|
|
sample_rate_val = 5;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_192KHZ:
|
|
|
|
sample_rate_val = 6;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
sample_rate_val = 4;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return sample_rate_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mi2s_get_sample_rate(int value)
|
|
|
|
{
|
|
|
|
int sample_rate;
|
|
|
|
|
|
|
|
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_96KHZ;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
sample_rate = SAMPLING_RATE_192KHZ;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
sample_rate = SAMPLING_RATE_48KHZ;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return sample_rate;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mi2s_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = mi2s_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
mi2s_rx_cfg[idx].sample_rate =
|
|
|
|
mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
|
|
|
|
idx, mi2s_rx_cfg[idx].sample_rate,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mi2s_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = mi2s_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
ucontrol->value.enumerated.item[0] =
|
|
|
|
mi2s_get_sample_rate_val(mi2s_rx_cfg[idx].sample_rate);
|
|
|
|
|
|
|
|
pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
|
|
|
|
idx, mi2s_rx_cfg[idx].sample_rate,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mi2s_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = mi2s_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
mi2s_tx_cfg[idx].sample_rate =
|
|
|
|
mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
|
|
|
|
idx, mi2s_tx_cfg[idx].sample_rate,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mi2s_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = mi2s_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
ucontrol->value.enumerated.item[0] =
|
|
|
|
mi2s_get_sample_rate_val(mi2s_tx_cfg[idx].sample_rate);
|
|
|
|
|
|
|
|
pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
|
|
|
|
idx, mi2s_tx_cfg[idx].sample_rate,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mi2s_tx_format_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = mi2s_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
mi2s_tx_cfg[idx].bit_format =
|
|
|
|
mi2s_get_format(ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
pr_debug("%s: idx[%d] _tx_format = %d, item = %d\n", __func__,
|
|
|
|
idx, mi2s_tx_cfg[idx].bit_format,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mi2s_tx_format_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = mi2s_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
ucontrol->value.enumerated.item[0] =
|
|
|
|
mi2s_get_format_value(mi2s_tx_cfg[idx].bit_format);
|
|
|
|
|
|
|
|
pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__,
|
|
|
|
idx, mi2s_tx_cfg[idx].bit_format,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mi2s_rx_format_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = mi2s_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
mi2s_rx_cfg[idx].bit_format =
|
|
|
|
mi2s_get_format(ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
pr_debug("%s: idx[%d] _rx_format = %d, item = %d\n", __func__,
|
|
|
|
idx, mi2s_rx_cfg[idx].bit_format,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mi2s_rx_format_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = mi2s_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
ucontrol->value.enumerated.item[0] =
|
|
|
|
mi2s_get_format_value(mi2s_rx_cfg[idx].bit_format);
|
|
|
|
|
|
|
|
pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
|
|
|
|
idx, mi2s_rx_cfg[idx].bit_format,
|
|
|
|
ucontrol->value.enumerated.item[0]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int msm_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = mi2s_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
pr_debug("%s: msm_mi2s_[%d]_rx_ch = %d\n", __func__,
|
|
|
|
idx, mi2s_rx_cfg[idx].channels);
|
|
|
|
ucontrol->value.enumerated.item[0] = mi2s_rx_cfg[idx].channels - 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int msm_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = mi2s_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
mi2s_rx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1;
|
|
|
|
pr_debug("%s: msm_mi2s_[%d]_rx_ch = %d\n", __func__,
|
|
|
|
idx, mi2s_rx_cfg[idx].channels);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int msm_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = mi2s_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
pr_debug("%s: msm_mi2s_[%d]_tx_ch = %d\n", __func__,
|
|
|
|
idx, mi2s_tx_cfg[idx].channels);
|
|
|
|
ucontrol->value.enumerated.item[0] = mi2s_tx_cfg[idx].channels - 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int msm_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = mi2s_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
mi2s_tx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1;
|
|
|
|
pr_debug("%s: msm_mi2s_[%d]_tx_ch = %d\n", __func__,
|
|
|
|
idx, mi2s_tx_cfg[idx].channels);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int usb_audio_rx_ch_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
pr_debug("%s: usb_audio_rx_ch = %d\n", __func__,
|
|
|
|
usb_rx_cfg.channels);
|
|
|
|
ucontrol->value.integer.value[0] = usb_rx_cfg.channels - 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int usb_audio_rx_ch_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
usb_rx_cfg.channels = ucontrol->value.integer.value[0] + 1;
|
|
|
|
|
|
|
|
pr_debug("%s: usb_audio_rx_ch = %d\n", __func__, usb_rx_cfg.channels);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int usb_audio_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int sample_rate_val;
|
|
|
|
|
|
|
|
switch (usb_rx_cfg.sample_rate) {
|
|
|
|
case SAMPLING_RATE_384KHZ:
|
|
|
|
sample_rate_val = 9;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_192KHZ:
|
|
|
|
sample_rate_val = 8;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_96KHZ:
|
|
|
|
sample_rate_val = 7;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_48KHZ:
|
|
|
|
sample_rate_val = 6;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_44P1KHZ:
|
|
|
|
sample_rate_val = 5;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_32KHZ:
|
|
|
|
sample_rate_val = 4;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_22P05KHZ:
|
|
|
|
sample_rate_val = 3;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_16KHZ:
|
|
|
|
sample_rate_val = 2;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_11P025KHZ:
|
|
|
|
sample_rate_val = 1;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_8KHZ:
|
|
|
|
default:
|
|
|
|
sample_rate_val = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ucontrol->value.integer.value[0] = sample_rate_val;
|
|
|
|
pr_debug("%s: usb_audio_rx_sample_rate = %d\n", __func__,
|
|
|
|
usb_rx_cfg.sample_rate);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int usb_audio_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
switch (ucontrol->value.integer.value[0]) {
|
|
|
|
case 9:
|
|
|
|
usb_rx_cfg.sample_rate = SAMPLING_RATE_384KHZ;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
usb_rx_cfg.sample_rate = SAMPLING_RATE_192KHZ;
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
usb_rx_cfg.sample_rate = SAMPLING_RATE_96KHZ;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
usb_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
usb_rx_cfg.sample_rate = SAMPLING_RATE_44P1KHZ;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
usb_rx_cfg.sample_rate = SAMPLING_RATE_32KHZ;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
usb_rx_cfg.sample_rate = SAMPLING_RATE_22P05KHZ;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
usb_rx_cfg.sample_rate = SAMPLING_RATE_16KHZ;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
usb_rx_cfg.sample_rate = SAMPLING_RATE_11P025KHZ;
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
usb_rx_cfg.sample_rate = SAMPLING_RATE_8KHZ;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usb_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_debug("%s: control value = %ld, usb_audio_rx_sample_rate = %d\n",
|
|
|
|
__func__, ucontrol->value.integer.value[0],
|
|
|
|
usb_rx_cfg.sample_rate);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int usb_audio_rx_format_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
switch (usb_rx_cfg.bit_format) {
|
|
|
|
case SNDRV_PCM_FORMAT_S32_LE:
|
|
|
|
ucontrol->value.integer.value[0] = 3;
|
|
|
|
break;
|
|
|
|
case SNDRV_PCM_FORMAT_S24_3LE:
|
|
|
|
ucontrol->value.integer.value[0] = 2;
|
|
|
|
break;
|
|
|
|
case SNDRV_PCM_FORMAT_S24_LE:
|
|
|
|
ucontrol->value.integer.value[0] = 1;
|
|
|
|
break;
|
|
|
|
case SNDRV_PCM_FORMAT_S16_LE:
|
|
|
|
default:
|
|
|
|
ucontrol->value.integer.value[0] = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_debug("%s: usb_audio_rx_format = %d, ucontrol value = %ld\n",
|
|
|
|
__func__, usb_rx_cfg.bit_format,
|
|
|
|
ucontrol->value.integer.value[0]);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int usb_audio_rx_format_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
switch (ucontrol->value.integer.value[0]) {
|
|
|
|
case 3:
|
|
|
|
usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE;
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
default:
|
|
|
|
usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pr_debug("%s: usb_audio_rx_format = %d, ucontrol value = %ld\n",
|
|
|
|
__func__, usb_rx_cfg.bit_format,
|
|
|
|
ucontrol->value.integer.value[0]);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int usb_audio_tx_ch_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
pr_debug("%s: usb_audio_tx_ch = %d\n", __func__,
|
|
|
|
usb_tx_cfg.channels);
|
|
|
|
ucontrol->value.integer.value[0] = usb_tx_cfg.channels - 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int usb_audio_tx_ch_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
usb_tx_cfg.channels = ucontrol->value.integer.value[0] + 1;
|
|
|
|
|
|
|
|
pr_debug("%s: usb_audio_tx_ch = %d\n", __func__, usb_tx_cfg.channels);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int usb_audio_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int sample_rate_val;
|
|
|
|
|
|
|
|
switch (usb_tx_cfg.sample_rate) {
|
|
|
|
case SAMPLING_RATE_384KHZ:
|
|
|
|
sample_rate_val = 9;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_192KHZ:
|
|
|
|
sample_rate_val = 8;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_96KHZ:
|
|
|
|
sample_rate_val = 7;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_48KHZ:
|
|
|
|
sample_rate_val = 6;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_44P1KHZ:
|
|
|
|
sample_rate_val = 5;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_32KHZ:
|
|
|
|
sample_rate_val = 4;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_22P05KHZ:
|
|
|
|
sample_rate_val = 3;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_16KHZ:
|
|
|
|
sample_rate_val = 2;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_11P025KHZ:
|
|
|
|
sample_rate_val = 1;
|
|
|
|
break;
|
|
|
|
case SAMPLING_RATE_8KHZ:
|
|
|
|
sample_rate_val = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
sample_rate_val = 6;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ucontrol->value.integer.value[0] = sample_rate_val;
|
|
|
|
pr_debug("%s: usb_audio_tx_sample_rate = %d\n", __func__,
|
|
|
|
usb_tx_cfg.sample_rate);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int usb_audio_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
switch (ucontrol->value.integer.value[0]) {
|
|
|
|
case 9:
|
|
|
|
usb_tx_cfg.sample_rate = SAMPLING_RATE_384KHZ;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
usb_tx_cfg.sample_rate = SAMPLING_RATE_192KHZ;
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
usb_tx_cfg.sample_rate = SAMPLING_RATE_96KHZ;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
usb_tx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
usb_tx_cfg.sample_rate = SAMPLING_RATE_44P1KHZ;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
usb_tx_cfg.sample_rate = SAMPLING_RATE_32KHZ;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
usb_tx_cfg.sample_rate = SAMPLING_RATE_22P05KHZ;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
usb_tx_cfg.sample_rate = SAMPLING_RATE_16KHZ;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
usb_tx_cfg.sample_rate = SAMPLING_RATE_11P025KHZ;
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
usb_tx_cfg.sample_rate = SAMPLING_RATE_8KHZ;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usb_tx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_debug("%s: control value = %ld, usb_audio_tx_sample_rate = %d\n",
|
|
|
|
__func__, ucontrol->value.integer.value[0],
|
|
|
|
usb_tx_cfg.sample_rate);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int usb_audio_tx_format_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
switch (usb_tx_cfg.bit_format) {
|
|
|
|
case SNDRV_PCM_FORMAT_S32_LE:
|
|
|
|
ucontrol->value.integer.value[0] = 3;
|
|
|
|
break;
|
|
|
|
case SNDRV_PCM_FORMAT_S24_3LE:
|
|
|
|
ucontrol->value.integer.value[0] = 2;
|
|
|
|
break;
|
|
|
|
case SNDRV_PCM_FORMAT_S24_LE:
|
|
|
|
ucontrol->value.integer.value[0] = 1;
|
|
|
|
break;
|
|
|
|
case SNDRV_PCM_FORMAT_S16_LE:
|
|
|
|
default:
|
|
|
|
ucontrol->value.integer.value[0] = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_debug("%s: usb_audio_tx_format = %d, ucontrol value = %ld\n",
|
|
|
|
__func__, usb_tx_cfg.bit_format,
|
|
|
|
ucontrol->value.integer.value[0]);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
switch (ucontrol->value.integer.value[0]) {
|
|
|
|
case 3:
|
|
|
|
usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE;
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
default:
|
|
|
|
usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pr_debug("%s: usb_audio_tx_format = %d, ucontrol value = %ld\n",
|
|
|
|
__func__, usb_tx_cfg.bit_format,
|
|
|
|
ucontrol->value.integer.value[0]);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ext_disp_get_port_idx(struct snd_kcontrol *kcontrol)
|
|
|
|
{
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
if (strnstr(kcontrol->id.name, "Display Port RX",
|
|
|
|
sizeof("Display Port RX")))
|
|
|
|
idx = DP_RX_IDX;
|
|
|
|
else {
|
|
|
|
pr_err("%s: unsupported BE: %s",
|
|
|
|
__func__, kcontrol->id.name);
|
|
|
|
idx = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ext_disp_rx_format_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = ext_disp_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
switch (ext_disp_rx_cfg[idx].bit_format) {
|
|
|
|
case SNDRV_PCM_FORMAT_S24_LE:
|
|
|
|
ucontrol->value.integer.value[0] = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SNDRV_PCM_FORMAT_S16_LE:
|
|
|
|
default:
|
|
|
|
ucontrol->value.integer.value[0] = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_debug("%s: ext_disp_rx[%d].format = %d, ucontrol value = %ld\n",
|
|
|
|
__func__, idx, ext_disp_rx_cfg[idx].bit_format,
|
|
|
|
ucontrol->value.integer.value[0]);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ext_disp_rx_format_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = ext_disp_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
switch (ucontrol->value.integer.value[0]) {
|
|
|
|
case 1:
|
|
|
|
ext_disp_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S24_LE;
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
default:
|
|
|
|
ext_disp_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S16_LE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pr_debug("%s: ext_disp_rx[%d].format = %d, ucontrol value = %ld\n",
|
|
|
|
__func__, idx, ext_disp_rx_cfg[idx].bit_format,
|
|
|
|
ucontrol->value.integer.value[0]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ext_disp_rx_ch_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = ext_disp_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
ucontrol->value.integer.value[0] =
|
|
|
|
ext_disp_rx_cfg[idx].channels - 2;
|
|
|
|
|
|
|
|
pr_debug("%s: ext_disp_rx[%d].ch = %d\n", __func__,
|
|
|
|
idx, ext_disp_rx_cfg[idx].channels);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ext_disp_rx_ch_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = ext_disp_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
ext_disp_rx_cfg[idx].channels =
|
|
|
|
ucontrol->value.integer.value[0] + 2;
|
|
|
|
|
|
|
|
pr_debug("%s: ext_disp_rx[%d].ch = %d\n", __func__,
|
|
|
|
idx, ext_disp_rx_cfg[idx].channels);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ext_disp_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int sample_rate_val;
|
|
|
|
int idx = ext_disp_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
switch (ext_disp_rx_cfg[idx].sample_rate) {
|
|
|
|
case SAMPLING_RATE_192KHZ:
|
|
|
|
sample_rate_val = 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SAMPLING_RATE_96KHZ:
|
|
|
|
sample_rate_val = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SAMPLING_RATE_48KHZ:
|
|
|
|
default:
|
|
|
|
sample_rate_val = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ucontrol->value.integer.value[0] = sample_rate_val;
|
|
|
|
pr_debug("%s: ext_disp_rx[%d].sample_rate = %d\n", __func__,
|
|
|
|
idx, ext_disp_rx_cfg[idx].sample_rate);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ext_disp_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
int idx = ext_disp_get_port_idx(kcontrol);
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
switch (ucontrol->value.integer.value[0]) {
|
|
|
|
case 2:
|
|
|
|
ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_192KHZ;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_96KHZ;
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
default:
|
|
|
|
ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_48KHZ;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_debug("%s: control value = %ld, ext_disp_rx[%d].sample_rate = %d\n",
|
|
|
|
__func__, ucontrol->value.integer.value[0], idx,
|
|
|
|
ext_disp_rx_cfg[idx].sample_rate);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct snd_kcontrol_new msm_common_snd_controls[] = {
|
|
|
|
SOC_ENUM_EXT("PROXY_RX Channels", proxy_rx_chs,
|
|
|
|
proxy_rx_ch_get, proxy_rx_ch_put),
|
|
|
|
SOC_ENUM_EXT("PRIM_AUX_PCM_RX SampleRate", prim_aux_pcm_rx_sample_rate,
|
|
|
|
aux_pcm_rx_sample_rate_get,
|
|
|
|
aux_pcm_rx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("SEC_AUX_PCM_RX SampleRate", sec_aux_pcm_rx_sample_rate,
|
|
|
|
aux_pcm_rx_sample_rate_get,
|
|
|
|
aux_pcm_rx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("TERT_AUX_PCM_RX SampleRate", tert_aux_pcm_rx_sample_rate,
|
|
|
|
aux_pcm_rx_sample_rate_get,
|
|
|
|
aux_pcm_rx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("QUAT_AUX_PCM_RX SampleRate", quat_aux_pcm_rx_sample_rate,
|
|
|
|
aux_pcm_rx_sample_rate_get,
|
|
|
|
aux_pcm_rx_sample_rate_put),
|
2017-09-10 13:27:39 -04:00
|
|
|
SOC_ENUM_EXT("QUIN_AUX_PCM_RX SampleRate", quin_aux_pcm_rx_sample_rate,
|
|
|
|
aux_pcm_rx_sample_rate_get,
|
|
|
|
aux_pcm_rx_sample_rate_put),
|
2017-07-20 09:01:55 -04:00
|
|
|
SOC_ENUM_EXT("PRIM_AUX_PCM_TX SampleRate", prim_aux_pcm_tx_sample_rate,
|
|
|
|
aux_pcm_tx_sample_rate_get,
|
|
|
|
aux_pcm_tx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("SEC_AUX_PCM_TX SampleRate", sec_aux_pcm_tx_sample_rate,
|
|
|
|
aux_pcm_tx_sample_rate_get,
|
|
|
|
aux_pcm_tx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("TERT_AUX_PCM_TX SampleRate", tert_aux_pcm_tx_sample_rate,
|
|
|
|
aux_pcm_tx_sample_rate_get,
|
|
|
|
aux_pcm_tx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("QUAT_AUX_PCM_TX SampleRate", quat_aux_pcm_tx_sample_rate,
|
|
|
|
aux_pcm_tx_sample_rate_get,
|
|
|
|
aux_pcm_tx_sample_rate_put),
|
2017-09-10 13:27:39 -04:00
|
|
|
SOC_ENUM_EXT("QUIN_AUX_PCM_TX SampleRate", quin_aux_pcm_tx_sample_rate,
|
|
|
|
aux_pcm_tx_sample_rate_get,
|
|
|
|
aux_pcm_tx_sample_rate_put),
|
2017-07-20 09:01:55 -04:00
|
|
|
SOC_ENUM_EXT("PRIM_MI2S_RX SampleRate", prim_mi2s_rx_sample_rate,
|
|
|
|
mi2s_rx_sample_rate_get,
|
|
|
|
mi2s_rx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("SEC_MI2S_RX SampleRate", sec_mi2s_rx_sample_rate,
|
|
|
|
mi2s_rx_sample_rate_get,
|
|
|
|
mi2s_rx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("TERT_MI2S_RX SampleRate", tert_mi2s_rx_sample_rate,
|
|
|
|
mi2s_rx_sample_rate_get,
|
|
|
|
mi2s_rx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("QUAT_MI2S_RX SampleRate", quat_mi2s_rx_sample_rate,
|
|
|
|
mi2s_rx_sample_rate_get,
|
|
|
|
mi2s_rx_sample_rate_put),
|
2017-09-10 13:27:39 -04:00
|
|
|
SOC_ENUM_EXT("QUIN_MI2S_RX SampleRate", quin_mi2s_rx_sample_rate,
|
|
|
|
mi2s_rx_sample_rate_get,
|
|
|
|
mi2s_rx_sample_rate_put),
|
2017-07-20 09:01:55 -04:00
|
|
|
SOC_ENUM_EXT("PRIM_MI2S_TX SampleRate", prim_mi2s_tx_sample_rate,
|
|
|
|
mi2s_tx_sample_rate_get,
|
|
|
|
mi2s_tx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("SEC_MI2S_TX SampleRate", sec_mi2s_tx_sample_rate,
|
|
|
|
mi2s_tx_sample_rate_get,
|
|
|
|
mi2s_tx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("TERT_MI2S_TX SampleRate", tert_mi2s_tx_sample_rate,
|
|
|
|
mi2s_tx_sample_rate_get,
|
|
|
|
mi2s_tx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("QUAT_MI2S_TX SampleRate", quat_mi2s_tx_sample_rate,
|
|
|
|
mi2s_tx_sample_rate_get,
|
|
|
|
mi2s_tx_sample_rate_put),
|
2017-09-10 13:27:39 -04:00
|
|
|
SOC_ENUM_EXT("QUIN_MI2S_TX SampleRate", quin_mi2s_tx_sample_rate,
|
|
|
|
mi2s_tx_sample_rate_get,
|
|
|
|
mi2s_tx_sample_rate_put),
|
2017-07-20 09:01:55 -04:00
|
|
|
SOC_ENUM_EXT("PRIM_MI2S_RX Format", prim_mi2s_rx_format,
|
|
|
|
mi2s_rx_format_get,
|
|
|
|
mi2s_rx_format_put),
|
|
|
|
SOC_ENUM_EXT("SEC_MI2S_RX Format", sec_mi2s_rx_format,
|
|
|
|
mi2s_rx_format_get,
|
|
|
|
mi2s_rx_format_put),
|
|
|
|
SOC_ENUM_EXT("TERT_MI2S_RX Format", tert_mi2s_rx_format,
|
|
|
|
mi2s_rx_format_get,
|
|
|
|
mi2s_rx_format_put),
|
|
|
|
SOC_ENUM_EXT("QUAT_MI2S_RX Format", quat_mi2s_rx_format,
|
|
|
|
mi2s_rx_format_get,
|
|
|
|
mi2s_rx_format_put),
|
2017-09-10 13:27:39 -04:00
|
|
|
SOC_ENUM_EXT("QUIN_MI2S_RX Format", quin_mi2s_rx_format,
|
|
|
|
mi2s_rx_format_get,
|
|
|
|
mi2s_rx_format_put),
|
2017-07-20 09:01:55 -04:00
|
|
|
SOC_ENUM_EXT("PRIM_MI2S_TX Format", prim_mi2s_tx_format,
|
|
|
|
mi2s_tx_format_get,
|
|
|
|
mi2s_tx_format_put),
|
|
|
|
SOC_ENUM_EXT("SEC_MI2S_TX Format", sec_mi2s_tx_format,
|
|
|
|
mi2s_tx_format_get,
|
|
|
|
mi2s_tx_format_put),
|
|
|
|
SOC_ENUM_EXT("TERT_MI2S_TX Format", tert_mi2s_tx_format,
|
|
|
|
mi2s_tx_format_get,
|
|
|
|
mi2s_tx_format_put),
|
|
|
|
SOC_ENUM_EXT("QUAT_MI2S_TX Format", quat_mi2s_tx_format,
|
|
|
|
mi2s_tx_format_get,
|
|
|
|
mi2s_tx_format_put),
|
2017-09-10 13:27:39 -04:00
|
|
|
SOC_ENUM_EXT("QUIN_MI2S_TX Format", quin_mi2s_tx_format,
|
|
|
|
mi2s_tx_format_get,
|
|
|
|
mi2s_tx_format_put),
|
2017-07-20 09:01:55 -04:00
|
|
|
SOC_ENUM_EXT("PRIM_MI2S_RX Channels", prim_mi2s_rx_chs,
|
|
|
|
msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
|
|
|
|
SOC_ENUM_EXT("PRIM_MI2S_TX Channels", prim_mi2s_tx_chs,
|
|
|
|
msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
|
|
|
|
SOC_ENUM_EXT("SEC_MI2S_RX Channels", sec_mi2s_rx_chs,
|
|
|
|
msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
|
|
|
|
SOC_ENUM_EXT("SEC_MI2S_TX Channels", sec_mi2s_tx_chs,
|
|
|
|
msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
|
|
|
|
SOC_ENUM_EXT("TERT_MI2S_RX Channels", tert_mi2s_rx_chs,
|
|
|
|
msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
|
|
|
|
SOC_ENUM_EXT("TERT_MI2S_TX Channels", tert_mi2s_tx_chs,
|
|
|
|
msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
|
|
|
|
SOC_ENUM_EXT("QUAT_MI2S_RX Channels", quat_mi2s_rx_chs,
|
|
|
|
msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
|
|
|
|
SOC_ENUM_EXT("QUAT_MI2S_TX Channels", quat_mi2s_tx_chs,
|
|
|
|
msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
|
2017-09-10 13:27:39 -04:00
|
|
|
SOC_ENUM_EXT("QUIN_MI2S_RX Channels", quin_mi2s_rx_chs,
|
|
|
|
msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
|
|
|
|
SOC_ENUM_EXT("QUIN_MI2S_TX Channels", quin_mi2s_tx_chs,
|
|
|
|
msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
|
2017-07-20 09:01:55 -04:00
|
|
|
SOC_ENUM_EXT("USB_AUDIO_RX Channels", usb_rx_chs,
|
|
|
|
usb_audio_rx_ch_get, usb_audio_rx_ch_put),
|
|
|
|
SOC_ENUM_EXT("USB_AUDIO_TX Channels", usb_tx_chs,
|
|
|
|
usb_audio_tx_ch_get, usb_audio_tx_ch_put),
|
|
|
|
SOC_ENUM_EXT("Display Port RX Channels", ext_disp_rx_chs,
|
|
|
|
ext_disp_rx_ch_get, ext_disp_rx_ch_put),
|
|
|
|
SOC_ENUM_EXT("USB_AUDIO_RX Format", usb_rx_format,
|
|
|
|
usb_audio_rx_format_get, usb_audio_rx_format_put),
|
|
|
|
SOC_ENUM_EXT("USB_AUDIO_TX Format", usb_tx_format,
|
|
|
|
usb_audio_tx_format_get, usb_audio_tx_format_put),
|
|
|
|
SOC_ENUM_EXT("Display Port RX Bit Format", ext_disp_rx_format,
|
|
|
|
ext_disp_rx_format_get, ext_disp_rx_format_put),
|
|
|
|
SOC_ENUM_EXT("USB_AUDIO_RX SampleRate", usb_rx_sample_rate,
|
|
|
|
usb_audio_rx_sample_rate_get,
|
|
|
|
usb_audio_rx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("USB_AUDIO_TX SampleRate", usb_tx_sample_rate,
|
|
|
|
usb_audio_tx_sample_rate_get,
|
|
|
|
usb_audio_tx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("Display Port RX SampleRate", ext_disp_rx_sample_rate,
|
|
|
|
ext_disp_rx_sample_rate_get,
|
|
|
|
ext_disp_rx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("PRI_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
|
|
|
|
tdm_rx_sample_rate_get,
|
|
|
|
tdm_rx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("PRI_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
|
|
|
|
tdm_tx_sample_rate_get,
|
|
|
|
tdm_tx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("PRI_TDM_RX_0 Format", tdm_rx_format,
|
|
|
|
tdm_rx_format_get,
|
|
|
|
tdm_rx_format_put),
|
|
|
|
SOC_ENUM_EXT("PRI_TDM_TX_0 Format", tdm_tx_format,
|
|
|
|
tdm_tx_format_get,
|
|
|
|
tdm_tx_format_put),
|
|
|
|
SOC_ENUM_EXT("PRI_TDM_RX_0 Channels", tdm_rx_chs,
|
|
|
|
tdm_rx_ch_get,
|
|
|
|
tdm_rx_ch_put),
|
|
|
|
SOC_ENUM_EXT("PRI_TDM_TX_0 Channels", tdm_tx_chs,
|
|
|
|
tdm_tx_ch_get,
|
|
|
|
tdm_tx_ch_put),
|
|
|
|
SOC_ENUM_EXT("SEC_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
|
|
|
|
tdm_rx_sample_rate_get,
|
|
|
|
tdm_rx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("SEC_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
|
|
|
|
tdm_tx_sample_rate_get,
|
|
|
|
tdm_tx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("SEC_TDM_RX_0 Format", tdm_rx_format,
|
|
|
|
tdm_rx_format_get,
|
|
|
|
tdm_rx_format_put),
|
|
|
|
SOC_ENUM_EXT("SEC_TDM_TX_0 Format", tdm_tx_format,
|
|
|
|
tdm_tx_format_get,
|
|
|
|
tdm_tx_format_put),
|
|
|
|
SOC_ENUM_EXT("SEC_TDM_RX_0 Channels", tdm_rx_chs,
|
|
|
|
tdm_rx_ch_get,
|
|
|
|
tdm_rx_ch_put),
|
|
|
|
SOC_ENUM_EXT("SEC_TDM_TX_0 Channels", tdm_tx_chs,
|
|
|
|
tdm_tx_ch_get,
|
|
|
|
tdm_tx_ch_put),
|
|
|
|
SOC_ENUM_EXT("TERT_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
|
|
|
|
tdm_rx_sample_rate_get,
|
|
|
|
tdm_rx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("TERT_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
|
|
|
|
tdm_tx_sample_rate_get,
|
|
|
|
tdm_tx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("TERT_TDM_RX_0 Format", tdm_rx_format,
|
|
|
|
tdm_rx_format_get,
|
|
|
|
tdm_rx_format_put),
|
|
|
|
SOC_ENUM_EXT("TERT_TDM_TX_0 Format", tdm_tx_format,
|
|
|
|
tdm_tx_format_get,
|
|
|
|
tdm_tx_format_put),
|
|
|
|
SOC_ENUM_EXT("TERT_TDM_RX_0 Channels", tdm_rx_chs,
|
|
|
|
tdm_rx_ch_get,
|
|
|
|
tdm_rx_ch_put),
|
|
|
|
SOC_ENUM_EXT("TERT_TDM_TX_0 Channels", tdm_tx_chs,
|
|
|
|
tdm_tx_ch_get,
|
|
|
|
tdm_tx_ch_put),
|
|
|
|
SOC_ENUM_EXT("QUAT_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
|
|
|
|
tdm_rx_sample_rate_get,
|
|
|
|
tdm_rx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("QUAT_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
|
|
|
|
tdm_tx_sample_rate_get,
|
|
|
|
tdm_tx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("QUAT_TDM_RX_0 Format", tdm_rx_format,
|
|
|
|
tdm_rx_format_get,
|
|
|
|
tdm_rx_format_put),
|
|
|
|
SOC_ENUM_EXT("QUAT_TDM_TX_0 Format", tdm_tx_format,
|
|
|
|
tdm_tx_format_get,
|
|
|
|
tdm_tx_format_put),
|
|
|
|
SOC_ENUM_EXT("QUAT_TDM_RX_0 Channels", tdm_rx_chs,
|
|
|
|
tdm_rx_ch_get,
|
|
|
|
tdm_rx_ch_put),
|
|
|
|
SOC_ENUM_EXT("QUAT_TDM_TX_0 Channels", tdm_tx_chs,
|
|
|
|
tdm_tx_ch_get,
|
|
|
|
tdm_tx_ch_put),
|
2017-09-10 13:27:39 -04:00
|
|
|
SOC_ENUM_EXT("QUIN_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
|
|
|
|
tdm_rx_sample_rate_get,
|
|
|
|
tdm_rx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("QUIN_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
|
|
|
|
tdm_tx_sample_rate_get,
|
|
|
|
tdm_tx_sample_rate_put),
|
|
|
|
SOC_ENUM_EXT("QUIN_TDM_RX_0 Format", tdm_rx_format,
|
|
|
|
tdm_rx_format_get,
|
|
|
|
tdm_rx_format_put),
|
|
|
|
SOC_ENUM_EXT("QUIN_TDM_TX_0 Format", tdm_tx_format,
|
|
|
|
tdm_tx_format_get,
|
|
|
|
tdm_tx_format_put),
|
|
|
|
SOC_ENUM_EXT("QUIN_TDM_RX_0 Channels", tdm_rx_chs,
|
|
|
|
tdm_rx_ch_get,
|
|
|
|
tdm_rx_ch_put),
|
|
|
|
SOC_ENUM_EXT("QUIN_TDM_TX_0 Channels", tdm_tx_chs,
|
|
|
|
tdm_tx_ch_get,
|
|
|
|
tdm_tx_ch_put),
|
2017-07-20 09:01:55 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* msm_common_snd_controls_size - to return controls size
|
|
|
|
*
|
|
|
|
* Return: returns size of common controls array
|
|
|
|
*/
|
|
|
|
int msm_common_snd_controls_size(void)
|
|
|
|
{
|
|
|
|
return ARRAY_SIZE(msm_common_snd_controls);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(msm_common_snd_controls_size);
|
|
|
|
|
2017-08-17 08:51:59 -04:00
|
|
|
void msm_set_codec_reg_done(bool done)
|
|
|
|
{
|
|
|
|
codec_reg_done = done;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(msm_set_codec_reg_done);
|
|
|
|
|
2017-07-20 09:01:55 -04:00
|
|
|
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 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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-25 06:59:27 -04:00
|
|
|
static int msm_ext_disp_get_idx_from_beid(int32_t id)
|
2017-07-20 09:01:55 -04:00
|
|
|
{
|
|
|
|
int idx;
|
|
|
|
|
2017-07-25 06:59:27 -04:00
|
|
|
switch (id) {
|
2017-07-20 09:01:55 -04:00
|
|
|
case MSM_BACKEND_DAI_DISPLAY_PORT_RX:
|
|
|
|
idx = DP_RX_IDX;
|
|
|
|
break;
|
|
|
|
default:
|
2017-07-25 06:59:27 -04:00
|
|
|
pr_err("%s: Incorrect ext_disp id %d\n", __func__, id);
|
2017-07-20 09:01:55 -04:00
|
|
|
idx = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* msm_common_be_hw_params_fixup - updates settings of ALSA BE hw params.
|
|
|
|
*
|
|
|
|
* @rtd: runtime dailink instance
|
|
|
|
* @params: HW params of associated backend dailink.
|
|
|
|
*
|
|
|
|
* Returns 0.
|
|
|
|
*/
|
|
|
|
int msm_common_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_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;
|
|
|
|
|
|
|
|
pr_debug("%s: format = %d, rate = %d\n",
|
|
|
|
__func__, params_format(params), params_rate(params));
|
|
|
|
|
2017-07-25 06:59:27 -04:00
|
|
|
switch (dai_link->id) {
|
2017-07-20 09:01:55 -04:00
|
|
|
case MSM_BACKEND_DAI_USB_RX:
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
usb_rx_cfg.bit_format);
|
|
|
|
rate->min = rate->max = usb_rx_cfg.sample_rate;
|
|
|
|
channels->min = channels->max = usb_rx_cfg.channels;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_USB_TX:
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
usb_tx_cfg.bit_format);
|
|
|
|
rate->min = rate->max = usb_tx_cfg.sample_rate;
|
|
|
|
channels->min = channels->max = usb_tx_cfg.channels;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_DISPLAY_PORT_RX:
|
2017-07-25 06:59:27 -04:00
|
|
|
idx = msm_ext_disp_get_idx_from_beid(dai_link->id);
|
|
|
|
if (idx < 0) {
|
2017-07-20 09:01:55 -04:00
|
|
|
pr_err("%s: Incorrect ext disp idx %d\n",
|
|
|
|
__func__, idx);
|
|
|
|
rc = idx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
ext_disp_rx_cfg[idx].bit_format);
|
|
|
|
rate->min = rate->max = ext_disp_rx_cfg[idx].sample_rate;
|
|
|
|
channels->min = channels->max = ext_disp_rx_cfg[idx].channels;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_AFE_PCM_RX:
|
|
|
|
channels->min = channels->max = proxy_rx_cfg.channels;
|
|
|
|
rate->min = rate->max = SAMPLING_RATE_48KHZ;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_PRI_TDM_RX_0:
|
|
|
|
channels->min = channels->max =
|
|
|
|
tdm_rx_cfg[TDM_PRI][TDM_0].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
tdm_rx_cfg[TDM_PRI][TDM_0].bit_format);
|
|
|
|
rate->min = rate->max = tdm_rx_cfg[TDM_PRI][TDM_0].sample_rate;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_PRI_TDM_TX_0:
|
|
|
|
channels->min = channels->max =
|
|
|
|
tdm_tx_cfg[TDM_PRI][TDM_0].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
tdm_tx_cfg[TDM_PRI][TDM_0].bit_format);
|
|
|
|
rate->min = rate->max = tdm_tx_cfg[TDM_PRI][TDM_0].sample_rate;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_SEC_TDM_RX_0:
|
|
|
|
channels->min = channels->max =
|
|
|
|
tdm_rx_cfg[TDM_SEC][TDM_0].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
tdm_rx_cfg[TDM_SEC][TDM_0].bit_format);
|
|
|
|
rate->min = rate->max = tdm_rx_cfg[TDM_SEC][TDM_0].sample_rate;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_SEC_TDM_TX_0:
|
|
|
|
channels->min = channels->max =
|
|
|
|
tdm_tx_cfg[TDM_SEC][TDM_0].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
tdm_tx_cfg[TDM_SEC][TDM_0].bit_format);
|
|
|
|
rate->min = rate->max = tdm_tx_cfg[TDM_SEC][TDM_0].sample_rate;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_TERT_TDM_RX_0:
|
|
|
|
channels->min = channels->max =
|
|
|
|
tdm_rx_cfg[TDM_TERT][TDM_0].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
tdm_rx_cfg[TDM_TERT][TDM_0].bit_format);
|
|
|
|
rate->min = rate->max = tdm_rx_cfg[TDM_TERT][TDM_0].sample_rate;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_TERT_TDM_TX_0:
|
|
|
|
channels->min = channels->max =
|
|
|
|
tdm_tx_cfg[TDM_TERT][TDM_0].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
tdm_tx_cfg[TDM_TERT][TDM_0].bit_format);
|
|
|
|
rate->min = rate->max = tdm_tx_cfg[TDM_TERT][TDM_0].sample_rate;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_QUAT_TDM_RX_0:
|
|
|
|
channels->min = channels->max =
|
|
|
|
tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
tdm_rx_cfg[TDM_QUAT][TDM_0].bit_format);
|
|
|
|
rate->min = rate->max = tdm_rx_cfg[TDM_QUAT][TDM_0].sample_rate;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_QUAT_TDM_TX_0:
|
|
|
|
channels->min = channels->max =
|
|
|
|
tdm_tx_cfg[TDM_QUAT][TDM_0].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
tdm_tx_cfg[TDM_QUAT][TDM_0].bit_format);
|
|
|
|
rate->min = rate->max = tdm_tx_cfg[TDM_QUAT][TDM_0].sample_rate;
|
|
|
|
break;
|
|
|
|
|
2017-09-10 13:27:39 -04:00
|
|
|
case MSM_BACKEND_DAI_QUIN_TDM_RX_0:
|
|
|
|
channels->min = channels->max =
|
|
|
|
tdm_rx_cfg[TDM_QUIN][TDM_0].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
tdm_rx_cfg[TDM_QUIN][TDM_0].bit_format);
|
|
|
|
rate->min = rate->max = tdm_rx_cfg[TDM_QUIN][TDM_0].sample_rate;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_QUIN_TDM_TX_0:
|
|
|
|
channels->min = channels->max =
|
|
|
|
tdm_tx_cfg[TDM_QUIN][TDM_0].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
tdm_tx_cfg[TDM_QUIN][TDM_0].bit_format);
|
|
|
|
rate->min = rate->max = tdm_tx_cfg[TDM_QUIN][TDM_0].sample_rate;
|
|
|
|
break;
|
|
|
|
|
2017-07-20 09:01:55 -04:00
|
|
|
case MSM_BACKEND_DAI_AUXPCM_RX:
|
|
|
|
rate->min = rate->max =
|
|
|
|
aux_pcm_rx_cfg[PRIM_AUX_PCM].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
aux_pcm_rx_cfg[PRIM_AUX_PCM].channels;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_AUXPCM_TX:
|
|
|
|
rate->min = rate->max =
|
|
|
|
aux_pcm_tx_cfg[PRIM_AUX_PCM].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
aux_pcm_tx_cfg[PRIM_AUX_PCM].channels;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_SEC_AUXPCM_RX:
|
|
|
|
rate->min = rate->max =
|
|
|
|
aux_pcm_rx_cfg[SEC_AUX_PCM].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
aux_pcm_rx_cfg[SEC_AUX_PCM].channels;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_SEC_AUXPCM_TX:
|
|
|
|
rate->min = rate->max =
|
|
|
|
aux_pcm_tx_cfg[SEC_AUX_PCM].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
aux_pcm_tx_cfg[SEC_AUX_PCM].channels;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_TERT_AUXPCM_RX:
|
|
|
|
rate->min = rate->max =
|
|
|
|
aux_pcm_rx_cfg[TERT_AUX_PCM].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
aux_pcm_rx_cfg[TERT_AUX_PCM].channels;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_TERT_AUXPCM_TX:
|
|
|
|
rate->min = rate->max =
|
|
|
|
aux_pcm_tx_cfg[TERT_AUX_PCM].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
aux_pcm_tx_cfg[TERT_AUX_PCM].channels;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_QUAT_AUXPCM_RX:
|
|
|
|
rate->min = rate->max =
|
|
|
|
aux_pcm_rx_cfg[QUAT_AUX_PCM].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
aux_pcm_rx_cfg[QUAT_AUX_PCM].channels;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_QUAT_AUXPCM_TX:
|
|
|
|
rate->min = rate->max =
|
|
|
|
aux_pcm_tx_cfg[QUAT_AUX_PCM].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
aux_pcm_tx_cfg[QUAT_AUX_PCM].channels;
|
|
|
|
break;
|
|
|
|
|
2017-09-10 13:27:39 -04:00
|
|
|
case MSM_BACKEND_DAI_QUIN_AUXPCM_RX:
|
|
|
|
rate->min = rate->max =
|
|
|
|
aux_pcm_rx_cfg[QUIN_AUX_PCM].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
aux_pcm_rx_cfg[QUIN_AUX_PCM].channels;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_QUIN_AUXPCM_TX:
|
|
|
|
rate->min = rate->max =
|
|
|
|
aux_pcm_tx_cfg[QUIN_AUX_PCM].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
aux_pcm_tx_cfg[QUIN_AUX_PCM].channels;
|
|
|
|
break;
|
|
|
|
|
2017-07-20 09:01:55 -04:00
|
|
|
case MSM_BACKEND_DAI_PRI_MI2S_RX:
|
|
|
|
rate->min = rate->max = mi2s_rx_cfg[PRIM_MI2S].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
mi2s_rx_cfg[PRIM_MI2S].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
mi2s_rx_cfg[PRIM_MI2S].bit_format);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_PRI_MI2S_TX:
|
|
|
|
rate->min = rate->max = mi2s_tx_cfg[PRIM_MI2S].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
mi2s_tx_cfg[PRIM_MI2S].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
mi2s_tx_cfg[PRIM_MI2S].bit_format);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_SECONDARY_MI2S_RX:
|
|
|
|
rate->min = rate->max = mi2s_rx_cfg[SEC_MI2S].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
mi2s_rx_cfg[SEC_MI2S].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
mi2s_rx_cfg[SEC_MI2S].bit_format);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_SECONDARY_MI2S_TX:
|
|
|
|
rate->min = rate->max = mi2s_tx_cfg[SEC_MI2S].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
mi2s_tx_cfg[SEC_MI2S].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
mi2s_tx_cfg[SEC_MI2S].bit_format);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_TERTIARY_MI2S_RX:
|
|
|
|
rate->min = rate->max = mi2s_rx_cfg[TERT_MI2S].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
mi2s_rx_cfg[TERT_MI2S].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
mi2s_rx_cfg[TERT_MI2S].bit_format);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_TERTIARY_MI2S_TX:
|
|
|
|
rate->min = rate->max = mi2s_tx_cfg[TERT_MI2S].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
mi2s_tx_cfg[TERT_MI2S].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
mi2s_tx_cfg[TERT_MI2S].bit_format);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX:
|
|
|
|
rate->min = rate->max = mi2s_rx_cfg[QUAT_MI2S].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
mi2s_rx_cfg[QUAT_MI2S].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
mi2s_rx_cfg[QUAT_MI2S].bit_format);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX:
|
|
|
|
rate->min = rate->max = mi2s_tx_cfg[QUAT_MI2S].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
mi2s_tx_cfg[QUAT_MI2S].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
mi2s_tx_cfg[QUAT_MI2S].bit_format);
|
|
|
|
break;
|
|
|
|
|
2017-09-10 13:27:39 -04:00
|
|
|
case MSM_BACKEND_DAI_QUINARY_MI2S_RX:
|
|
|
|
rate->min = rate->max = mi2s_rx_cfg[QUIN_MI2S].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
mi2s_rx_cfg[QUIN_MI2S].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
mi2s_rx_cfg[QUIN_MI2S].bit_format);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSM_BACKEND_DAI_QUINARY_MI2S_TX:
|
|
|
|
rate->min = rate->max = mi2s_tx_cfg[QUIN_MI2S].sample_rate;
|
|
|
|
channels->min = channels->max =
|
|
|
|
mi2s_tx_cfg[QUIN_MI2S].channels;
|
|
|
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
mi2s_tx_cfg[QUIN_MI2S].bit_format);
|
|
|
|
break;
|
|
|
|
|
2017-07-20 09:01:55 -04:00
|
|
|
default:
|
|
|
|
rate->min = rate->max = SAMPLING_RATE_48KHZ;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(msm_common_be_hw_params_fixup);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* msm_aux_pcm_snd_startup - startup ops of auxpcm.
|
|
|
|
*
|
|
|
|
* @substream: PCM stream pointer of associated backend dailink
|
|
|
|
*
|
|
|
|
* Returns 0 on success or -EINVAL on error.
|
|
|
|
*/
|
|
|
|
int msm_aux_pcm_snd_startup(struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
|
|
|
|
|
|
dev_dbg(rtd->card->dev,
|
|
|
|
"%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
|
|
|
|
__func__, substream->name, substream->stream,
|
|
|
|
rtd->cpu_dai->name, rtd->cpu_dai->id);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(msm_aux_pcm_snd_startup);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* msm_aux_pcm_snd_shutdown - shutdown ops of auxpcm.
|
|
|
|
*
|
|
|
|
* @substream: PCM stream pointer of associated backend dailink
|
|
|
|
*/
|
|
|
|
void msm_aux_pcm_snd_shutdown(struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
|
|
|
|
|
|
dev_dbg(rtd->card->dev,
|
|
|
|
"%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
|
|
|
|
__func__,
|
|
|
|
substream->name, substream->stream,
|
|
|
|
rtd->cpu_dai->name, rtd->cpu_dai->id);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(msm_aux_pcm_snd_shutdown);
|
|
|
|
|
2017-07-25 06:59:27 -04:00
|
|
|
static int msm_get_port_id(int id)
|
2017-07-20 09:01:55 -04:00
|
|
|
{
|
|
|
|
int afe_port_id;
|
|
|
|
|
2017-07-25 06:59:27 -04:00
|
|
|
switch (id) {
|
2017-07-20 09:01:55 -04:00
|
|
|
case MSM_BACKEND_DAI_PRI_MI2S_RX:
|
|
|
|
afe_port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
|
|
|
|
break;
|
|
|
|
case MSM_BACKEND_DAI_PRI_MI2S_TX:
|
|
|
|
afe_port_id = AFE_PORT_ID_PRIMARY_MI2S_TX;
|
|
|
|
break;
|
|
|
|
case MSM_BACKEND_DAI_SECONDARY_MI2S_RX:
|
|
|
|
afe_port_id = AFE_PORT_ID_SECONDARY_MI2S_RX;
|
|
|
|
break;
|
|
|
|
case MSM_BACKEND_DAI_SECONDARY_MI2S_TX:
|
|
|
|
afe_port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
|
|
|
|
break;
|
|
|
|
case MSM_BACKEND_DAI_TERTIARY_MI2S_RX:
|
|
|
|
afe_port_id = AFE_PORT_ID_TERTIARY_MI2S_RX;
|
|
|
|
break;
|
|
|
|
case MSM_BACKEND_DAI_TERTIARY_MI2S_TX:
|
|
|
|
afe_port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
|
|
|
|
break;
|
|
|
|
case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX:
|
|
|
|
afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX;
|
|
|
|
break;
|
|
|
|
case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX:
|
|
|
|
afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
|
|
|
|
break;
|
2017-09-10 13:27:39 -04:00
|
|
|
case MSM_BACKEND_DAI_QUINARY_MI2S_RX:
|
|
|
|
afe_port_id = AFE_PORT_ID_QUINARY_MI2S_RX;
|
|
|
|
break;
|
|
|
|
case MSM_BACKEND_DAI_QUINARY_MI2S_TX:
|
|
|
|
afe_port_id = AFE_PORT_ID_QUINARY_MI2S_TX;
|
|
|
|
break;
|
2017-07-20 09:01:55 -04:00
|
|
|
default:
|
2017-07-25 06:59:27 -04:00
|
|
|
pr_err("%s: Invalid id: %d\n", __func__, id);
|
2017-07-20 09:01:55 -04:00
|
|
|
afe_port_id = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return afe_port_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
static u32 get_mi2s_bits_per_sample(u32 bit_format)
|
|
|
|
{
|
|
|
|
u32 bit_per_sample;
|
|
|
|
|
|
|
|
switch (bit_format) {
|
|
|
|
case SNDRV_PCM_FORMAT_S32_LE:
|
|
|
|
case SNDRV_PCM_FORMAT_S24_3LE:
|
|
|
|
case SNDRV_PCM_FORMAT_S24_LE:
|
|
|
|
bit_per_sample = 32;
|
|
|
|
break;
|
|
|
|
case SNDRV_PCM_FORMAT_S16_LE:
|
|
|
|
default:
|
|
|
|
bit_per_sample = 16;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bit_per_sample;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void update_mi2s_clk_val(int dai_id, int stream)
|
|
|
|
{
|
|
|
|
u32 bit_per_sample;
|
|
|
|
|
|
|
|
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
|
|
bit_per_sample =
|
|
|
|
get_mi2s_bits_per_sample(mi2s_rx_cfg[dai_id].bit_format);
|
|
|
|
mi2s_clk[dai_id].clk_freq_in_hz =
|
|
|
|
mi2s_rx_cfg[dai_id].sample_rate * 2 * bit_per_sample;
|
|
|
|
} else {
|
|
|
|
bit_per_sample =
|
|
|
|
get_mi2s_bits_per_sample(mi2s_tx_cfg[dai_id].bit_format);
|
|
|
|
mi2s_clk[dai_id].clk_freq_in_hz =
|
|
|
|
mi2s_tx_cfg[dai_id].sample_rate * 2 * bit_per_sample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int msm_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
|
|
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
|
|
|
int port_id = 0;
|
|
|
|
int index = cpu_dai->id;
|
|
|
|
|
2017-07-25 06:59:27 -04:00
|
|
|
port_id = msm_get_port_id(rtd->dai_link->id);
|
2017-07-20 09:01:55 -04:00
|
|
|
if (port_id < 0) {
|
|
|
|
dev_err(rtd->card->dev, "%s: Invalid port_id\n", __func__);
|
|
|
|
ret = port_id;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (enable) {
|
|
|
|
update_mi2s_clk_val(index, substream->stream);
|
|
|
|
dev_dbg(rtd->card->dev, "%s: clock rate %ul\n", __func__,
|
|
|
|
mi2s_clk[index].clk_freq_in_hz);
|
|
|
|
}
|
|
|
|
|
|
|
|
mi2s_clk[index].enable = enable;
|
|
|
|
ret = afe_set_lpass_clock_v2(port_id,
|
|
|
|
&mi2s_clk[index]);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(rtd->card->dev,
|
|
|
|
"%s: afe lpass clock failed for port 0x%x , err:%d\n",
|
|
|
|
__func__, port_id, ret);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* msm_mi2s_snd_startup - startup ops of mi2s.
|
|
|
|
*
|
|
|
|
* @substream: PCM stream pointer of associated backend dailink
|
|
|
|
*
|
|
|
|
* Returns 0 on success or -EINVAL on error.
|
|
|
|
*/
|
|
|
|
int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
|
|
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
2017-07-25 06:59:27 -04:00
|
|
|
int port_id = msm_get_port_id(rtd->dai_link->id);
|
2017-07-20 09:01:55 -04:00
|
|
|
int index = cpu_dai->id;
|
|
|
|
unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
|
2017-10-04 04:17:10 -04:00
|
|
|
struct msm_asoc_mach_data *pdata =
|
|
|
|
snd_soc_card_get_drvdata(rtd->card);
|
2017-07-20 09:01:55 -04:00
|
|
|
|
|
|
|
dev_dbg(rtd->card->dev,
|
|
|
|
"%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
|
|
|
|
__func__, substream->name, substream->stream,
|
|
|
|
cpu_dai->name, cpu_dai->id);
|
|
|
|
|
2017-09-10 13:27:39 -04:00
|
|
|
if (index < PRIM_MI2S || index >= MI2S_MAX) {
|
2017-07-20 09:01:55 -04:00
|
|
|
ret = -EINVAL;
|
|
|
|
dev_err(rtd->card->dev,
|
|
|
|
"%s: CPU DAI id (%d) out of range\n",
|
|
|
|
__func__, cpu_dai->id);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Muxtex protection in case the same MI2S
|
|
|
|
* interface using for both TX and RX so
|
|
|
|
* that the same clock won't be enable twice.
|
|
|
|
*/
|
|
|
|
mutex_lock(&mi2s_intf_conf[index].lock);
|
|
|
|
if (++mi2s_intf_conf[index].ref_cnt == 1) {
|
|
|
|
/* Check if msm needs to provide the clock to the interface */
|
|
|
|
if (!mi2s_intf_conf[index].msm_is_mi2s_master) {
|
|
|
|
mi2s_clk[index].clk_id = mi2s_ebit_clk[index];
|
|
|
|
fmt = SND_SOC_DAIFMT_CBM_CFM;
|
|
|
|
}
|
|
|
|
ret = msm_mi2s_set_sclk(substream, true);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(rtd->card->dev,
|
|
|
|
"%s: afe lpass clock failed to enable MI2S clock, err:%d\n",
|
|
|
|
__func__, ret);
|
|
|
|
goto clean_up;
|
|
|
|
}
|
|
|
|
ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(rtd->card->dev,
|
|
|
|
"%s: set fmt cpu dai failed for MI2S (%d), err:%d\n",
|
|
|
|
__func__, index, ret);
|
|
|
|
goto clk_off;
|
|
|
|
}
|
|
|
|
if (mi2s_intf_conf[index].msm_is_ext_mclk) {
|
|
|
|
mi2s_mclk[index].enable = 1;
|
|
|
|
pr_debug("%s: Enabling mclk, clk_freq_in_hz = %u\n",
|
|
|
|
__func__, mi2s_mclk[index].clk_freq_in_hz);
|
|
|
|
ret = afe_set_lpass_clock_v2(port_id,
|
|
|
|
&mi2s_mclk[index]);
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_err("%s: afe lpass mclk failed, err:%d\n",
|
|
|
|
__func__, ret);
|
|
|
|
goto clk_off;
|
|
|
|
}
|
|
|
|
}
|
2017-10-04 04:17:10 -04:00
|
|
|
if (pdata->mi2s_gpio_p[index])
|
|
|
|
msm_cdc_pinctrl_select_active_state(
|
|
|
|
pdata->mi2s_gpio_p[index]);
|
2017-07-20 09:01:55 -04:00
|
|
|
}
|
|
|
|
mutex_unlock(&mi2s_intf_conf[index].lock);
|
|
|
|
return 0;
|
|
|
|
clk_off:
|
|
|
|
if (ret < 0)
|
|
|
|
msm_mi2s_set_sclk(substream, false);
|
|
|
|
clean_up:
|
|
|
|
if (ret < 0)
|
|
|
|
mi2s_intf_conf[index].ref_cnt--;
|
|
|
|
mutex_unlock(&mi2s_intf_conf[index].lock);
|
|
|
|
done:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(msm_mi2s_snd_startup);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* msm_mi2s_snd_shutdown - shutdown ops of mi2s.
|
|
|
|
*
|
|
|
|
* @substream: PCM stream pointer of associated backend dailink
|
|
|
|
*/
|
|
|
|
void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
2017-07-25 06:59:27 -04:00
|
|
|
int port_id = msm_get_port_id(rtd->dai_link->id);
|
2017-07-20 09:01:55 -04:00
|
|
|
int index = rtd->cpu_dai->id;
|
2017-10-04 04:17:10 -04:00
|
|
|
struct msm_asoc_mach_data *pdata =
|
|
|
|
snd_soc_card_get_drvdata(rtd->card);
|
2017-07-20 09:01:55 -04:00
|
|
|
|
|
|
|
pr_debug("%s(): substream = %s stream = %d\n", __func__,
|
|
|
|
substream->name, substream->stream);
|
2017-09-10 13:27:39 -04:00
|
|
|
if (index < PRIM_MI2S || index >= MI2S_MAX) {
|
2017-07-20 09:01:55 -04:00
|
|
|
pr_err("%s:invalid MI2S DAI(%d)\n", __func__, index);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_lock(&mi2s_intf_conf[index].lock);
|
|
|
|
if (--mi2s_intf_conf[index].ref_cnt == 0) {
|
2017-10-04 04:17:10 -04:00
|
|
|
if (pdata->mi2s_gpio_p[index])
|
|
|
|
msm_cdc_pinctrl_select_sleep_state(
|
|
|
|
pdata->mi2s_gpio_p[index]);
|
|
|
|
|
2017-07-20 09:01:55 -04:00
|
|
|
ret = msm_mi2s_set_sclk(substream, false);
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_err("%s:clock disable failed for MI2S (%d); ret=%d\n",
|
|
|
|
__func__, index, ret);
|
|
|
|
mi2s_intf_conf[index].ref_cnt++;
|
|
|
|
}
|
|
|
|
if (mi2s_intf_conf[index].msm_is_ext_mclk) {
|
|
|
|
mi2s_mclk[index].enable = 0;
|
|
|
|
pr_debug("%s: Disabling mclk, clk_freq_in_hz = %u\n",
|
|
|
|
__func__, mi2s_mclk[index].clk_freq_in_hz);
|
|
|
|
ret = afe_set_lpass_clock_v2(port_id,
|
|
|
|
&mi2s_mclk[index]);
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_err("%s: mclk disable failed for MCLK (%d); ret=%d\n",
|
|
|
|
__func__, index, ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mutex_unlock(&mi2s_intf_conf[index].lock);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(msm_mi2s_snd_shutdown);
|
|
|
|
|
|
|
|
/* Validate whether US EU switch is present or not */
|
|
|
|
static int msm_prepare_us_euro(struct snd_soc_card *card)
|
|
|
|
{
|
|
|
|
struct msm_asoc_mach_data *pdata =
|
|
|
|
snd_soc_card_get_drvdata(card);
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (pdata->us_euro_gpio >= 0) {
|
|
|
|
dev_dbg(card->dev, "%s: us_euro gpio request %d", __func__,
|
|
|
|
pdata->us_euro_gpio);
|
|
|
|
ret = gpio_request(pdata->us_euro_gpio, "TASHA_CODEC_US_EURO");
|
|
|
|
if (ret) {
|
|
|
|
dev_err(card->dev,
|
|
|
|
"%s: Failed to request codec US/EURO gpio %d error %d\n",
|
|
|
|
__func__, pdata->us_euro_gpio, ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-07-25 06:59:27 -04:00
|
|
|
static bool msm_swap_gnd_mic(struct snd_soc_codec *codec, bool active)
|
2017-07-20 09:01:55 -04:00
|
|
|
{
|
|
|
|
struct snd_soc_card *card = codec->component.card;
|
|
|
|
struct msm_asoc_mach_data *pdata =
|
|
|
|
snd_soc_card_get_drvdata(card);
|
|
|
|
int value = 0;
|
|
|
|
|
|
|
|
if (pdata->us_euro_gpio_p) {
|
|
|
|
value = msm_cdc_pinctrl_get_state(pdata->us_euro_gpio_p);
|
|
|
|
if (value)
|
|
|
|
msm_cdc_pinctrl_select_sleep_state(
|
|
|
|
pdata->us_euro_gpio_p);
|
|
|
|
else
|
|
|
|
msm_cdc_pinctrl_select_active_state(
|
|
|
|
pdata->us_euro_gpio_p);
|
|
|
|
} else if (pdata->us_euro_gpio >= 0) {
|
|
|
|
value = gpio_get_value_cansleep(pdata->us_euro_gpio);
|
|
|
|
gpio_set_value_cansleep(pdata->us_euro_gpio, !value);
|
|
|
|
}
|
|
|
|
pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int msm_populate_dai_link_component_of_node(
|
|
|
|
struct msm_asoc_mach_data *pdata,
|
|
|
|
struct snd_soc_card *card)
|
|
|
|
{
|
|
|
|
int i, index, ret = 0;
|
|
|
|
struct device *cdev = card->dev;
|
|
|
|
struct snd_soc_dai_link *dai_link = card->dai_link;
|
|
|
|
struct device_node *phandle;
|
|
|
|
|
|
|
|
if (!cdev) {
|
|
|
|
pr_err("%s: Sound card device memory NULL\n", __func__);
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < card->num_links; i++) {
|
|
|
|
if (dai_link[i].platform_of_node && dai_link[i].cpu_of_node)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* populate platform_of_node for snd card dai links */
|
|
|
|
if (dai_link[i].platform_name &&
|
|
|
|
!dai_link[i].platform_of_node) {
|
|
|
|
index = of_property_match_string(cdev->of_node,
|
|
|
|
"asoc-platform-names",
|
|
|
|
dai_link[i].platform_name);
|
|
|
|
if (index < 0) {
|
|
|
|
pr_err("%s: No match found for platform name: %s\n",
|
|
|
|
__func__, dai_link[i].platform_name);
|
|
|
|
ret = index;
|
|
|
|
goto cpu_dai;
|
|
|
|
}
|
|
|
|
phandle = of_parse_phandle(cdev->of_node,
|
|
|
|
"asoc-platform",
|
|
|
|
index);
|
|
|
|
if (!phandle) {
|
|
|
|
pr_err("%s: retrieving phandle for platform %s, index %d failed\n",
|
|
|
|
__func__, dai_link[i].platform_name,
|
|
|
|
index);
|
|
|
|
ret = -ENODEV;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
dai_link[i].platform_of_node = phandle;
|
|
|
|
dai_link[i].platform_name = NULL;
|
|
|
|
}
|
|
|
|
cpu_dai:
|
|
|
|
/* populate cpu_of_node for snd card dai links */
|
|
|
|
if (dai_link[i].cpu_dai_name && !dai_link[i].cpu_of_node) {
|
|
|
|
index = of_property_match_string(cdev->of_node,
|
|
|
|
"asoc-cpu-names",
|
|
|
|
dai_link[i].cpu_dai_name);
|
|
|
|
if (index < 0)
|
|
|
|
goto codec_dai;
|
|
|
|
phandle = of_parse_phandle(cdev->of_node, "asoc-cpu",
|
|
|
|
index);
|
|
|
|
if (!phandle) {
|
|
|
|
pr_err("%s: retrieving phandle for cpu dai %s failed\n",
|
|
|
|
__func__, dai_link[i].cpu_dai_name);
|
|
|
|
ret = -ENODEV;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
dai_link[i].cpu_of_node = phandle;
|
|
|
|
dai_link[i].cpu_dai_name = NULL;
|
|
|
|
}
|
|
|
|
codec_dai:
|
|
|
|
/* populate codec_of_node for snd card dai links */
|
|
|
|
if (dai_link[i].codec_name && !dai_link[i].codec_of_node) {
|
|
|
|
index = of_property_match_string(cdev->of_node,
|
|
|
|
"asoc-codec-names",
|
|
|
|
dai_link[i].codec_name);
|
|
|
|
if (index < 0)
|
|
|
|
continue;
|
|
|
|
phandle = of_parse_phandle(cdev->of_node, "asoc-codec",
|
|
|
|
index);
|
|
|
|
if (!phandle) {
|
|
|
|
pr_err("%s: retrieving phandle for codec dai %s failed\n",
|
|
|
|
__func__, dai_link[i].codec_name);
|
|
|
|
ret = -ENODEV;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
dai_link[i].codec_of_node = phandle;
|
|
|
|
dai_link[i].codec_name = NULL;
|
|
|
|
}
|
|
|
|
if (pdata->snd_card_val == INT_SND_CARD) {
|
2017-07-25 06:59:27 -04:00
|
|
|
if ((dai_link[i].id ==
|
2017-07-20 09:01:55 -04:00
|
|
|
MSM_BACKEND_DAI_INT0_MI2S_RX) ||
|
2017-07-25 06:59:27 -04:00
|
|
|
(dai_link[i].id ==
|
2017-07-20 09:01:55 -04:00
|
|
|
MSM_BACKEND_DAI_INT1_MI2S_RX) ||
|
2017-07-25 06:59:27 -04:00
|
|
|
(dai_link[i].id ==
|
2017-07-20 09:01:55 -04:00
|
|
|
MSM_BACKEND_DAI_INT2_MI2S_TX) ||
|
2017-07-25 06:59:27 -04:00
|
|
|
(dai_link[i].id ==
|
2017-07-20 09:01:55 -04:00
|
|
|
MSM_BACKEND_DAI_INT3_MI2S_TX)) {
|
|
|
|
index = of_property_match_string(cdev->of_node,
|
|
|
|
"asoc-codec-names",
|
|
|
|
MSM_INT_DIGITAL_CODEC);
|
|
|
|
phandle = of_parse_phandle(cdev->of_node,
|
|
|
|
"asoc-codec",
|
|
|
|
index);
|
|
|
|
dai_link[i].codecs[DIG_CDC].of_node = phandle;
|
|
|
|
index = of_property_match_string(cdev->of_node,
|
|
|
|
"asoc-codec-names",
|
|
|
|
PMIC_INT_ANALOG_CODEC);
|
|
|
|
phandle = of_parse_phandle(cdev->of_node,
|
|
|
|
"asoc-codec",
|
|
|
|
index);
|
|
|
|
dai_link[i].codecs[ANA_CDC].of_node = phandle;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int msm_wsa881x_init(struct snd_soc_component *component)
|
|
|
|
{
|
|
|
|
u8 spkleft_ports[WSA881X_MAX_SWR_PORTS] = {100, 101, 102, 106};
|
|
|
|
u8 spkright_ports[WSA881X_MAX_SWR_PORTS] = {103, 104, 105, 107};
|
|
|
|
unsigned int ch_rate[WSA881X_MAX_SWR_PORTS] = {2400, 600, 300, 1200};
|
|
|
|
unsigned int ch_mask[WSA881X_MAX_SWR_PORTS] = {0x1, 0xF, 0x3, 0x3};
|
|
|
|
struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
|
|
|
|
struct msm_asoc_mach_data *pdata;
|
|
|
|
struct snd_soc_dapm_context *dapm =
|
|
|
|
snd_soc_codec_get_dapm(codec);
|
|
|
|
|
|
|
|
if (!codec) {
|
|
|
|
pr_err("%s codec is NULL\n", __func__);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(component->name_prefix, "SpkrLeft")) {
|
|
|
|
dev_dbg(codec->dev, "%s: setting left ch map to codec %s\n",
|
|
|
|
__func__, codec->component.name);
|
|
|
|
wsa881x_set_channel_map(codec, &spkleft_ports[0],
|
|
|
|
WSA881X_MAX_SWR_PORTS, &ch_mask[0],
|
|
|
|
&ch_rate[0]);
|
|
|
|
if (dapm->component) {
|
|
|
|
snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft IN");
|
|
|
|
snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft SPKR");
|
|
|
|
}
|
|
|
|
} else if (!strcmp(component->name_prefix, "SpkrRight")) {
|
|
|
|
dev_dbg(codec->dev, "%s: setting right ch map to codec %s\n",
|
|
|
|
__func__, codec->component.name);
|
|
|
|
wsa881x_set_channel_map(codec, &spkright_ports[0],
|
|
|
|
WSA881X_MAX_SWR_PORTS, &ch_mask[0],
|
|
|
|
&ch_rate[0]);
|
|
|
|
if (dapm->component) {
|
|
|
|
snd_soc_dapm_ignore_suspend(dapm, "SpkrRight IN");
|
|
|
|
snd_soc_dapm_ignore_suspend(dapm, "SpkrRight SPKR");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dev_err(codec->dev, "%s: wrong codec name %s\n", __func__,
|
|
|
|
codec->component.name);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pdata = snd_soc_card_get_drvdata(component->card);
|
|
|
|
if (pdata && pdata->codec_root)
|
|
|
|
wsa881x_codec_info_create_codec_entry(pdata->codec_root,
|
|
|
|
codec);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int msm_init_wsa_dev(struct platform_device *pdev,
|
|
|
|
struct snd_soc_card *card)
|
|
|
|
{
|
|
|
|
struct device_node *wsa_of_node;
|
|
|
|
u32 wsa_max_devs;
|
|
|
|
u32 wsa_dev_cnt;
|
|
|
|
char *dev_name_str = NULL;
|
|
|
|
struct msm_wsa881x_dev_info *wsa881x_dev_info;
|
|
|
|
const char *wsa_auxdev_name_prefix[1];
|
|
|
|
int found = 0;
|
|
|
|
int i;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* Get maximum WSA device count for this platform */
|
|
|
|
ret = of_property_read_u32(pdev->dev.of_node,
|
|
|
|
"qcom,wsa-max-devs", &wsa_max_devs);
|
|
|
|
if (ret) {
|
|
|
|
dev_dbg(&pdev->dev,
|
|
|
|
"%s: wsa-max-devs property missing in DT %s, ret = %d\n",
|
|
|
|
__func__, pdev->dev.of_node->full_name, ret);
|
|
|
|
goto err_dt;
|
|
|
|
}
|
|
|
|
if (wsa_max_devs == 0) {
|
|
|
|
dev_warn(&pdev->dev,
|
|
|
|
"%s: Max WSA devices is 0 for this target?\n",
|
|
|
|
__func__);
|
|
|
|
goto err_dt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get count of WSA device phandles for this platform */
|
|
|
|
wsa_dev_cnt = of_count_phandle_with_args(pdev->dev.of_node,
|
|
|
|
"qcom,wsa-devs", NULL);
|
|
|
|
if (wsa_dev_cnt == -ENOENT) {
|
|
|
|
dev_warn(&pdev->dev, "%s: No wsa device defined in DT.\n",
|
|
|
|
__func__);
|
|
|
|
goto err_dt;
|
|
|
|
} else if (wsa_dev_cnt <= 0) {
|
|
|
|
dev_err(&pdev->dev,
|
|
|
|
"%s: Error reading wsa device from DT. wsa_dev_cnt = %d\n",
|
|
|
|
__func__, wsa_dev_cnt);
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_dt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Expect total phandles count to be NOT less than maximum possible
|
|
|
|
* WSA count. However, if it is less, then assign same value to
|
|
|
|
* max count as well.
|
|
|
|
*/
|
|
|
|
if (wsa_dev_cnt < wsa_max_devs) {
|
|
|
|
dev_dbg(&pdev->dev,
|
|
|
|
"%s: wsa_max_devs = %d cannot exceed wsa_dev_cnt = %d\n",
|
|
|
|
__func__, wsa_max_devs, wsa_dev_cnt);
|
|
|
|
wsa_max_devs = wsa_dev_cnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure prefix string passed for each WSA device */
|
|
|
|
ret = of_property_count_strings(pdev->dev.of_node,
|
|
|
|
"qcom,wsa-aux-dev-prefix");
|
|
|
|
if (ret != wsa_dev_cnt) {
|
|
|
|
dev_err(&pdev->dev,
|
|
|
|
"%s: expecting %d wsa prefix. Defined only %d in DT\n",
|
|
|
|
__func__, wsa_dev_cnt, ret);
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_dt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Alloc mem to store phandle and index info of WSA device, if already
|
|
|
|
* registered with ALSA core
|
|
|
|
*/
|
|
|
|
wsa881x_dev_info = devm_kcalloc(&pdev->dev, wsa_max_devs,
|
|
|
|
sizeof(struct msm_wsa881x_dev_info),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!wsa881x_dev_info) {
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto err_mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* search and check whether all WSA devices are already
|
|
|
|
* registered with ALSA core or not. If found a node, store
|
|
|
|
* the node and the index in a local array of struct for later
|
|
|
|
* use.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < wsa_dev_cnt; i++) {
|
|
|
|
wsa_of_node = of_parse_phandle(pdev->dev.of_node,
|
|
|
|
"qcom,wsa-devs", i);
|
|
|
|
if (unlikely(!wsa_of_node)) {
|
|
|
|
/* we should not be here */
|
|
|
|
dev_err(&pdev->dev,
|
|
|
|
"%s: wsa dev node is not present\n",
|
|
|
|
__func__);
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_dev_node;
|
|
|
|
}
|
|
|
|
if (soc_find_component(wsa_of_node, NULL)) {
|
|
|
|
/* WSA device registered with ALSA core */
|
|
|
|
wsa881x_dev_info[found].of_node = wsa_of_node;
|
|
|
|
wsa881x_dev_info[found].index = i;
|
|
|
|
found++;
|
|
|
|
if (found == wsa_max_devs)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found < wsa_max_devs) {
|
|
|
|
dev_dbg(&pdev->dev,
|
|
|
|
"%s: failed to find %d components. Found only %d\n",
|
|
|
|
__func__, wsa_max_devs, found);
|
|
|
|
return -EPROBE_DEFER;
|
|
|
|
}
|
|
|
|
dev_info(&pdev->dev,
|
|
|
|
"%s: found %d wsa881x devices registered with ALSA core\n",
|
|
|
|
__func__, found);
|
|
|
|
|
|
|
|
card->num_aux_devs = wsa_max_devs;
|
|
|
|
card->num_configs = wsa_max_devs;
|
|
|
|
|
|
|
|
/* Alloc array of AUX devs struct */
|
|
|
|
msm_aux_dev = devm_kcalloc(&pdev->dev, card->num_aux_devs,
|
|
|
|
sizeof(struct snd_soc_aux_dev),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!msm_aux_dev) {
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto err_auxdev_mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Alloc array of codec conf struct */
|
|
|
|
msm_codec_conf = devm_kcalloc(&pdev->dev, card->num_aux_devs,
|
|
|
|
sizeof(struct snd_soc_codec_conf),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!msm_codec_conf) {
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto err_codec_conf;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < card->num_aux_devs; i++) {
|
|
|
|
dev_name_str = devm_kzalloc(&pdev->dev, DEV_NAME_STR_LEN,
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!dev_name_str) {
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto err_dev_str;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = of_property_read_string_index(pdev->dev.of_node,
|
|
|
|
"qcom,wsa-aux-dev-prefix",
|
|
|
|
wsa881x_dev_info[i].index,
|
|
|
|
wsa_auxdev_name_prefix);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(&pdev->dev,
|
|
|
|
"%s: failed to read wsa aux dev prefix, ret = %d\n",
|
|
|
|
__func__, ret);
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_dt_prop;
|
|
|
|
}
|
|
|
|
|
|
|
|
snprintf(dev_name_str, strlen("wsa881x.%d"), "wsa881x.%d", i);
|
|
|
|
msm_aux_dev[i].name = dev_name_str;
|
|
|
|
msm_aux_dev[i].codec_name = NULL;
|
|
|
|
msm_aux_dev[i].codec_of_node =
|
|
|
|
wsa881x_dev_info[i].of_node;
|
|
|
|
msm_aux_dev[i].init = msm_wsa881x_init;
|
|
|
|
msm_codec_conf[i].dev_name = NULL;
|
|
|
|
msm_codec_conf[i].name_prefix = wsa_auxdev_name_prefix[0];
|
|
|
|
msm_codec_conf[i].of_node = wsa881x_dev_info[i].of_node;
|
|
|
|
}
|
|
|
|
card->codec_conf = msm_codec_conf;
|
|
|
|
card->aux_dev = msm_aux_dev;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_dt_prop:
|
|
|
|
devm_kfree(&pdev->dev, dev_name_str);
|
|
|
|
err_dev_str:
|
|
|
|
devm_kfree(&pdev->dev, msm_codec_conf);
|
|
|
|
err_codec_conf:
|
|
|
|
devm_kfree(&pdev->dev, msm_aux_dev);
|
|
|
|
err_auxdev_mem:
|
|
|
|
err_dev_node:
|
|
|
|
devm_kfree(&pdev->dev, wsa881x_dev_info);
|
|
|
|
err_mem:
|
|
|
|
err_dt:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2s_auxpcm_init(struct platform_device *pdev)
|
|
|
|
{
|
|
|
|
int count;
|
|
|
|
u32 mi2s_master_slave[MI2S_MAX];
|
|
|
|
u32 mi2s_ext_mclk[MI2S_MAX];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
for (count = 0; count < MI2S_MAX; count++) {
|
|
|
|
mutex_init(&mi2s_intf_conf[count].lock);
|
|
|
|
mi2s_intf_conf[count].ref_cnt = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = of_property_read_u32_array(pdev->dev.of_node,
|
|
|
|
"qcom,msm-mi2s-master",
|
|
|
|
mi2s_master_slave, MI2S_MAX);
|
|
|
|
if (ret) {
|
|
|
|
dev_dbg(&pdev->dev, "%s: no qcom,msm-mi2s-master in DT node\n",
|
|
|
|
__func__);
|
|
|
|
} else {
|
|
|
|
for (count = 0; count < MI2S_MAX; count++) {
|
|
|
|
mi2s_intf_conf[count].msm_is_mi2s_master =
|
|
|
|
mi2s_master_slave[count];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = of_property_read_u32_array(pdev->dev.of_node,
|
|
|
|
"qcom,msm-mi2s-ext-mclk",
|
|
|
|
mi2s_ext_mclk, MI2S_MAX);
|
|
|
|
if (ret) {
|
|
|
|
dev_dbg(&pdev->dev, "%s: no qcom,msm-mi2s-ext-mclk in DT node\n",
|
|
|
|
__func__);
|
|
|
|
} else {
|
|
|
|
for (count = 0; count < MI2S_MAX; count++)
|
|
|
|
mi2s_intf_conf[count].msm_is_ext_mclk =
|
|
|
|
mi2s_ext_mclk[count];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct of_device_id sdm660_asoc_machine_of_match[] = {
|
|
|
|
{ .compatible = "qcom,sdm660-asoc-snd",
|
|
|
|
.data = "internal_codec"},
|
|
|
|
{ .compatible = "qcom,sdm660-asoc-snd-tasha",
|
|
|
|
.data = "tasha_codec"},
|
|
|
|
{ .compatible = "qcom,sdm660-asoc-snd-tavil",
|
|
|
|
.data = "tavil_codec"},
|
2017-08-17 08:51:59 -04:00
|
|
|
{ .compatible = "qcom,sdm670-asoc-snd",
|
|
|
|
.data = "internal_codec"},
|
|
|
|
{ .compatible = "qcom,sdm670-asoc-snd-tasha",
|
|
|
|
.data = "tasha_codec"},
|
|
|
|
{ .compatible = "qcom,sdm670-asoc-snd-tavil",
|
|
|
|
.data = "tavil_codec"},
|
2017-07-20 09:01:55 -04:00
|
|
|
{},
|
|
|
|
};
|
|
|
|
|
|
|
|
static int msm_asoc_machine_probe(struct platform_device *pdev)
|
|
|
|
{
|
|
|
|
struct snd_soc_card *card = NULL;
|
|
|
|
struct msm_asoc_mach_data *pdata = NULL;
|
|
|
|
const char *mclk = "qcom,msm-mclk-freq";
|
|
|
|
int ret = -EINVAL, id;
|
|
|
|
const struct of_device_id *match;
|
|
|
|
|
|
|
|
pdata = devm_kzalloc(&pdev->dev,
|
|
|
|
sizeof(struct msm_asoc_mach_data),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!pdata)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2017-08-17 08:51:59 -04:00
|
|
|
msm_set_codec_reg_done(false);
|
2017-07-20 09:01:55 -04:00
|
|
|
match = of_match_node(sdm660_asoc_machine_of_match,
|
|
|
|
pdev->dev.of_node);
|
|
|
|
if (!match)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
ret = of_property_read_u32(pdev->dev.of_node, mclk, &id);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(&pdev->dev,
|
|
|
|
"%s: missing %s in dt node\n", __func__, mclk);
|
|
|
|
id = DEFAULT_MCLK_RATE;
|
|
|
|
}
|
|
|
|
pdata->mclk_freq = id;
|
|
|
|
|
|
|
|
if (!strcmp(match->data, "tasha_codec") ||
|
|
|
|
!strcmp(match->data, "tavil_codec")) {
|
|
|
|
if (!strcmp(match->data, "tasha_codec"))
|
|
|
|
pdata->snd_card_val = EXT_SND_CARD_TASHA;
|
|
|
|
else
|
|
|
|
pdata->snd_card_val = EXT_SND_CARD_TAVIL;
|
|
|
|
ret = msm_ext_cdc_init(pdev, pdata, &card, &mbhc_cfg);
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
} else if (!strcmp(match->data, "internal_codec")) {
|
|
|
|
pdata->snd_card_val = INT_SND_CARD;
|
|
|
|
ret = msm_int_cdc_init(pdev, pdata, &card, &mbhc_cfg);
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
} else {
|
|
|
|
dev_err(&pdev->dev,
|
|
|
|
"%s: Not a matching DT sound node\n", __func__);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (!card)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (pdata->snd_card_val == INT_SND_CARD) {
|
|
|
|
/*reading the gpio configurations from dtsi file*/
|
|
|
|
pdata->pdm_gpio_p = of_parse_phandle(pdev->dev.of_node,
|
|
|
|
"qcom,cdc-pdm-gpios", 0);
|
|
|
|
pdata->comp_gpio_p = of_parse_phandle(pdev->dev.of_node,
|
|
|
|
"qcom,cdc-comp-gpios", 0);
|
|
|
|
pdata->dmic_gpio_p = of_parse_phandle(pdev->dev.of_node,
|
|
|
|
"qcom,cdc-dmic-gpios", 0);
|
|
|
|
pdata->ext_spk_gpio_p = of_parse_phandle(pdev->dev.of_node,
|
|
|
|
"qcom,cdc-ext-spk-gpios", 0);
|
|
|
|
}
|
|
|
|
|
2017-10-04 04:17:10 -04:00
|
|
|
pdata->mi2s_gpio_p[PRIM_MI2S] = of_parse_phandle(pdev->dev.of_node,
|
|
|
|
"qcom,pri-mi2s-gpios", 0);
|
|
|
|
pdata->mi2s_gpio_p[SEC_MI2S] = of_parse_phandle(pdev->dev.of_node,
|
|
|
|
"qcom,sec-mi2s-gpios", 0);
|
|
|
|
pdata->mi2s_gpio_p[TERT_MI2S] = of_parse_phandle(pdev->dev.of_node,
|
|
|
|
"qcom,tert-mi2s-gpios", 0);
|
|
|
|
pdata->mi2s_gpio_p[QUAT_MI2S] = of_parse_phandle(pdev->dev.of_node,
|
|
|
|
"qcom,quat-mi2s-gpios", 0);
|
|
|
|
pdata->mi2s_gpio_p[QUIN_MI2S] = of_parse_phandle(pdev->dev.of_node,
|
|
|
|
"qcom,quin-mi2s-gpios", 0);
|
2017-07-20 09:01:55 -04:00
|
|
|
/*
|
|
|
|
* Parse US-Euro gpio info from DT. Report no error if us-euro
|
|
|
|
* entry is not found in DT file as some targets do not support
|
|
|
|
* US-Euro detection
|
|
|
|
*/
|
|
|
|
pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
|
|
|
|
"qcom,us-euro-gpios", 0);
|
|
|
|
if (!gpio_is_valid(pdata->us_euro_gpio))
|
|
|
|
pdata->us_euro_gpio_p = of_parse_phandle(pdev->dev.of_node,
|
|
|
|
"qcom,us-euro-gpios", 0);
|
|
|
|
if (!gpio_is_valid(pdata->us_euro_gpio) && (!pdata->us_euro_gpio_p)) {
|
|
|
|
dev_dbg(&pdev->dev, "property %s not detected in node %s",
|
|
|
|
"qcom,us-euro-gpios", pdev->dev.of_node->full_name);
|
|
|
|
} else {
|
|
|
|
dev_dbg(&pdev->dev, "%s detected",
|
|
|
|
"qcom,us-euro-gpios");
|
|
|
|
mbhc_cfg.swap_gnd_mic = msm_swap_gnd_mic;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = msm_prepare_us_euro(card);
|
|
|
|
if (ret)
|
|
|
|
dev_dbg(&pdev->dev, "msm_prepare_us_euro failed (%d)\n",
|
|
|
|
ret);
|
|
|
|
|
|
|
|
i2s_auxpcm_init(pdev);
|
|
|
|
|
|
|
|
ret = snd_soc_of_parse_audio_routing(card, "qcom,audio-routing");
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
ret = msm_populate_dai_link_component_of_node(pdata, card);
|
|
|
|
if (ret) {
|
|
|
|
ret = -EPROBE_DEFER;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!of_property_read_bool(pdev->dev.of_node, "qcom,wsa-disable")) {
|
|
|
|
ret = msm_init_wsa_dev(pdev, card);
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = devm_snd_soc_register_card(&pdev->dev, card);
|
|
|
|
if (ret == -EPROBE_DEFER) {
|
|
|
|
if (codec_reg_done) {
|
|
|
|
/*
|
|
|
|
* return failure as EINVAL since other codec
|
|
|
|
* registered sound card successfully.
|
|
|
|
* This avoids any further probe calls.
|
|
|
|
*/
|
|
|
|
ret = -EINVAL;
|
|
|
|
}
|
|
|
|
goto err;
|
|
|
|
} else if (ret) {
|
|
|
|
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
|
|
|
|
ret);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (pdata->snd_card_val != INT_SND_CARD)
|
|
|
|
msm_ext_register_audio_notifier(pdev);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
err:
|
|
|
|
if (pdata->us_euro_gpio > 0) {
|
|
|
|
dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n",
|
|
|
|
__func__, pdata->us_euro_gpio);
|
|
|
|
pdata->us_euro_gpio = 0;
|
|
|
|
}
|
|
|
|
if (pdata->hph_en1_gpio > 0) {
|
|
|
|
dev_dbg(&pdev->dev, "%s free hph_en1_gpio %d\n",
|
|
|
|
__func__, pdata->hph_en1_gpio);
|
|
|
|
gpio_free(pdata->hph_en1_gpio);
|
|
|
|
pdata->hph_en1_gpio = 0;
|
|
|
|
}
|
|
|
|
if (pdata->hph_en0_gpio > 0) {
|
|
|
|
dev_dbg(&pdev->dev, "%s free hph_en0_gpio %d\n",
|
|
|
|
__func__, pdata->hph_en0_gpio);
|
|
|
|
gpio_free(pdata->hph_en0_gpio);
|
|
|
|
pdata->hph_en0_gpio = 0;
|
|
|
|
}
|
|
|
|
devm_kfree(&pdev->dev, pdata);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int msm_asoc_machine_remove(struct platform_device *pdev)
|
|
|
|
{
|
|
|
|
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
|
|
|
struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
|
|
|
|
|
|
|
|
if (pdata->snd_card_val == INT_SND_CARD)
|
|
|
|
mutex_destroy(&pdata->cdc_int_mclk0_mutex);
|
|
|
|
|
|
|
|
gpio_free(pdata->us_euro_gpio);
|
|
|
|
gpio_free(pdata->hph_en1_gpio);
|
|
|
|
gpio_free(pdata->hph_en0_gpio);
|
2017-10-17 22:52:07 -04:00
|
|
|
|
|
|
|
if (pdata->snd_card_val != INT_SND_CARD)
|
|
|
|
audio_notifier_deregister("sdm660");
|
|
|
|
|
2017-07-20 09:01:55 -04:00
|
|
|
snd_soc_unregister_card(card);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct platform_driver sdm660_asoc_machine_driver = {
|
|
|
|
.driver = {
|
|
|
|
.name = DRV_NAME,
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.pm = &snd_soc_pm_ops,
|
|
|
|
.of_match_table = sdm660_asoc_machine_of_match,
|
|
|
|
},
|
|
|
|
.probe = msm_asoc_machine_probe,
|
|
|
|
.remove = msm_asoc_machine_remove,
|
|
|
|
};
|
|
|
|
module_platform_driver(sdm660_asoc_machine_driver);
|
|
|
|
|
|
|
|
MODULE_DESCRIPTION("ALSA SoC msm");
|
|
|
|
MODULE_LICENSE("GPL v2");
|
|
|
|
MODULE_ALIAS("platform:" DRV_NAME);
|
|
|
|
MODULE_DEVICE_TABLE(of, sdm660_asoc_machine_of_match);
|