ASoC: msm: 8916 machine driver

Changes for 8916 machine driver with
basic DAI links and snd_soc controls.

Change-Id: I1caf87243984c12305901cca6d6addc770267839
Signed-off-by: Laxminath Kasam <lkasam@codeaurora.org>
This commit is contained in:
Laxminath Kasam 2013-08-30 15:20:39 +05:30 committed by Michael Bohan
parent 9aa19f67fe
commit a0c1f4bf5c
6 changed files with 814 additions and 3 deletions

View file

@ -131,6 +131,10 @@ config ARCH_MSM8916
select CPU_FREQ
select PM_DEVFREQ
select MSM_DEVFREQ_CPUBW
select MSM_RPM_SMD
select MSM_QDSP6_APRV3
select MSM_QDSP6V2_CODECS
select MSM_AUDIO_QDSP6V2 if SND_SOC
config ARCH_FSM9900
bool "FSM9900"

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2014, 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
@ -19,7 +19,7 @@
#if defined(CONFIG_ARCH_MSM8974) \
|| defined(CONFIG_ARCH_MSM8226) || defined(CONFIG_ARCH_MSM8610) \
|| defined(CONFIG_ARCH_APQ8084) || defined(CONFIG_ARCH_MPQ8092) \
|| defined(CONFIG_ARCH_MDM9630)
|| defined(CONFIG_ARCH_MDM9630) || defined(CONFIG_ARCH_MSM8916)
#include <sound/apr_audio-v2.h>
#include <sound/q6asm-v2.h>

View file

@ -34,7 +34,7 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include <mach/subsystem_notif.h>
#include <soc/qcom/subsystem_notif.h>
#include "msm8x16-wcd.h"
#include "msm8916-wcd-irq.h"
#include "msm8x16_wcd_registers.h"

View file

@ -213,6 +213,17 @@ config SND_SOC_MSMSAMARIUM
select DOLBY_DAP
help
To add support for SoC audio on MSMSAMARIUM.
config SND_SOC_MSM8X16
tristate "SoC Machine driver for MSM8X16 boards"
depends on ARCH_MSM8916
select SND_SOC_QDSP6V2
select SND_SOC_MSM_STUB
select SND_SOC_MSM_HOSTLESS_PCM
select SND_SOC_MSM8X16_WCD
select SND_DYNAMIC_MINORS
help
To add support for SoC audio on MSM8X16.
This will enable sound soc drivers which
interfaces with DSP, also it will enable
the machine drivers and the corresponding

View file

@ -82,3 +82,7 @@ obj-$(CONFIG_SND_SOC_MSMSAMARIUM) += snd-soc-msmsamarium.o
#for mdm9630 sound card driver
snd-soc-mdm9630-objs := mdm9630.o
obj-$(CONFIG_SND_SOC_MDM9630) += snd-soc-mdm9630.o
# for MSM 8x16 sound card driver
snd-soc-msm8x16-objs := msm8x16.o
obj-$(CONFIG_SND_SOC_MSM8X16) += snd-soc-msm8x16.o

792
sound/soc/msm/msm8x16.c Normal file
View file

@ -0,0 +1,792 @@
/* Copyright (c) 2014, 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/clk.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/qpnp/clkdiv.h>
#include <linux/io.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
#include <sound/jack.h>
#include <sound/q6afe-v2.h>
#include <asm/mach-types.h>
#include <soc/qcom/socinfo.h>
#include <qdsp6v2/msm-pcm-routing-v2.h>
#include "../codecs/msm8x16-wcd.h"
#define DRV_NAME "msm8x16-asoc-wcd"
#define BTSCO_RATE_8KHZ 8000
#define BTSCO_RATE_16KHZ 16000
#define MAX_SND_CARDS 1
static int msm_btsco_rate = BTSCO_RATE_8KHZ;
static int msm_btsco_ch = 1;
static int msm_proxy_rx_ch = 2;
static int msm8x16_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
bool dapm);
static struct afe_clk_cfg mi2s_rx_clk = {
AFE_API_VERSION_I2S_CONFIG,
Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
Q6AFE_LPASS_OSR_CLK_12_P288_MHZ,
Q6AFE_LPASS_CLK_SRC_INTERNAL,
Q6AFE_LPASS_CLK_ROOT_DEFAULT,
Q6AFE_LPASS_MODE_BOTH_VALID,
0,
};
static struct afe_clk_cfg mi2s_tx_clk = {
AFE_API_VERSION_I2S_CONFIG,
Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
Q6AFE_LPASS_OSR_CLK_12_P288_MHZ,
Q6AFE_LPASS_CLK_SRC_INTERNAL,
Q6AFE_LPASS_CLK_ROOT_DEFAULT,
Q6AFE_LPASS_MODE_BOTH_VALID,
0,
};
static struct afe_digital_clk_cfg digital_cdc_clk = {
AFE_API_VERSION_I2S_CONFIG,
9600000,
5, /* Digital Codec root */
0,
};
static atomic_t mclk_rsc_ref;
static struct mutex cdc_mclk_mutex;
static int msm8x16_mclk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
static const struct snd_soc_dapm_widget msm8x16_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
msm8x16_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MIC("Handset Mic", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Secondary Mic", NULL),
};
static int msm_config_mclk(u16 port_id, struct afe_digital_clk_cfg *cfg)
{
iowrite32(0x1, ioremap(MSM8X16_TOMBAK_LPASS_DIGCODEC_CBCR, 4));
/* Set the update bit to make the settings go through */
iowrite32(0x1, ioremap(MSM8X16_TOMBAK_LPASS_DIGCODEC_CMD_RCGR, 4));
return 0;
}
static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
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);
pr_debug("%s()\n", __func__);
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
return 0;
}
static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
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);
rate->min = rate->max = msm_btsco_rate;
channels->min = channels->max = msm_btsco_ch;
return 0;
}
static int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
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);
pr_debug("%s: msm_proxy_rx_ch =%d\n", __func__, msm_proxy_rx_ch);
if (channels->max < 2)
channels->min = channels->max = 2;
channels->min = channels->max = msm_proxy_rx_ch;
rate->min = rate->max = 48000;
return 0;
}
static int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct snd_interval *rate = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_RATE);
rate->min = rate->max = 48000;
return 0;
}
static int msm_mi2s_snd_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
return 0;
}
static int mi2s_clk_ctl(struct snd_pcm_substream *substream, bool enable)
{
int ret = 0;
if (enable) {
digital_cdc_clk.clk_val = 9600000;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
&mi2s_rx_clk);
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
ret = afe_set_lpass_clock(AFE_PORT_ID_TERTIARY_MI2S_TX,
&mi2s_tx_clk);
} else
pr_err("%s:Not valid substream.\n", __func__);
if (ret < 0)
pr_err("%s:afe_set_lpass_clock failed\n", __func__);
} else {
digital_cdc_clk.clk_val = 0;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
&mi2s_rx_clk);
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
ret = afe_set_lpass_clock(AFE_PORT_ID_TERTIARY_MI2S_TX,
&mi2s_tx_clk);
} else
pr_err("%s:Not valid substream.\n", __func__);
if (ret < 0)
pr_err("%s:afe_set_lpass_clock failed\n", __func__);
}
return ret;
}
static int msm8x16_enable_codec_ext_clk(struct snd_soc_codec *codec,
int enable, bool dapm)
{
int ret = 0;
mutex_lock(&cdc_mclk_mutex);
pr_debug("%s: enable = %d codec name %s enable %d mclk ref counter %d\n",
__func__, enable, codec->name, enable,
atomic_read(&mclk_rsc_ref));
if (enable) {
if (atomic_inc_return(&mclk_rsc_ref) == 1) {
digital_cdc_clk.clk_val = 9600000;
msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX,
&digital_cdc_clk);
msm8x16_wcd_mclk_enable(codec, 1, dapm);
}
} else {
if (atomic_dec_return(&mclk_rsc_ref) == 0) {
digital_cdc_clk.clk_val = 0;
msm8x16_wcd_mclk_enable(codec, 0, dapm);
msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX,
&digital_cdc_clk);
}
}
mutex_unlock(&cdc_mclk_mutex);
return ret;
}
static int msm8x16_mclk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
pr_debug("%s: event = %d\n", __func__, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
return msm8x16_enable_codec_ext_clk(w->codec, 1, true);
case SND_SOC_DAPM_POST_PMD:
return msm8x16_enable_codec_ext_clk(w->codec, 0, true);
default:
return -EINVAL;
}
}
static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
{
int ret;
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
ret = mi2s_clk_ctl(substream, false);
if (ret < 0)
pr_err("%s:clock disable failed\n", __func__);
}
static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret = 0;
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
ret = mi2s_clk_ctl(substream, true);
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0)
pr_err("set fmt cpu dai failed\n");
return ret;
}
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret = 0;
pr_debug("%s(),dev_name%s\n", __func__, dev_name(cpu_dai->dev));
snd_soc_dapm_new_controls(dapm, msm8x16_dapm_widgets,
ARRAY_SIZE(msm8x16_dapm_widgets));
snd_soc_dapm_sync(dapm);
return ret;
}
static struct snd_soc_ops msm8x16_mi2s_be_ops = {
.startup = msm_mi2s_snd_startup,
.hw_params = msm_mi2s_snd_hw_params,
.shutdown = msm_mi2s_snd_shutdown,
};
/* Digital audio interface glue - connects codec <---> CPU */
static struct snd_soc_dai_link msm8x16_dai[] = {
/* FrontEnd DAI Links */
{/* hw:x,0 */
.name = "MSM8X16 Media1",
.stream_name = "MultiMedia1",
.cpu_dai_name = "MultiMedia1",
.platform_name = "msm-pcm-dsp.0",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.ignore_suspend = 1,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
},
{/* hw:x,1 */
.name = "MSM8X16 Media2",
.stream_name = "MultiMedia2",
.cpu_dai_name = "MultiMedia2",
.platform_name = "msm-pcm-dsp.0",
.dynamic = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.ignore_suspend = 1,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
},
{/* hw:x,2 */
.name = "Circuit-Switch Voice",
.stream_name = "CS-Voice",
.cpu_dai_name = "CS-VOICE",
.platform_name = "msm-pcm-voice",
.dynamic = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_CS_VOICE,
},
{/* hw:x,3 */
.name = "MSM VoIP",
.stream_name = "VoIP",
.cpu_dai_name = "VoIP",
.platform_name = "msm-voip-dsp",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.ignore_suspend = 1,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_VOIP,
},
{/* hw:x,4 */
.name = "MSM8X16 LPA",
.stream_name = "LPA",
.cpu_dai_name = "MultiMedia3",
.platform_name = "msm-pcm-lpa",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.ignore_suspend = 1,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
},
/* Hostless PCM purpose */
{/* hw:x,5 */
.name = "Secondary MI2S RX Hostless",
.stream_name = "Secondary MI2S_RX Hostless Playback",
.cpu_dai_name = "SEC_MI2S_RX_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.ignore_pmdown_time = 1,
/* This dainlink has MI2S support */
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
{/* hw:x,6 */
.name = "INT_FM Hostless",
.stream_name = "INT_FM Hostless",
.cpu_dai_name = "INT_FM_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
{/* hw:x,7 */
.name = "MSM AFE-PCM RX",
.stream_name = "AFE-PROXY RX",
.cpu_dai_name = "msm-dai-q6-dev.241",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-rx",
.platform_name = "msm-pcm-afe",
.ignore_suspend = 1,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
},
{/* hw:x,8 */
.name = "MSM AFE-PCM TX",
.stream_name = "AFE-PROXY TX",
.cpu_dai_name = "msm-dai-q6-dev.240",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-tx",
.platform_name = "msm-pcm-afe",
.ignore_suspend = 1,
},
{/* hw:x,9 */
.name = "MSM8X16 Compr",
.stream_name = "COMPR",
.cpu_dai_name = "MultiMedia4",
.platform_name = "msm-compr-dsp",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.ignore_suspend = 1,
.ignore_pmdown_time = 1,
/* this dainlink has playback support */
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
},
{/* hw:x,10 */
.name = "AUXPCM Hostless",
.stream_name = "AUXPCM Hostless",
.cpu_dai_name = "AUXPCM_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
{/* hw:x,11 */
.name = "Primary MI2S TX Hostless",
.stream_name = "Primary MI2S_TX Hostless Capture",
.cpu_dai_name = "PRI_MI2S_TX_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.ignore_pmdown_time = 1,
/* This dainlink has MI2S support */
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
{/* hw:x,12 */
.name = "MSM8x16 LowLatency",
.stream_name = "MultiMedia5",
.cpu_dai_name = "MultiMedia5",
.platform_name = "msm-pcm-dsp.1",
.dynamic = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.ignore_suspend = 1,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
},
{/* hw:x,13 */
.name = "Voice2",
.stream_name = "Voice2",
.cpu_dai_name = "Voice2",
.platform_name = "msm-pcm-voice",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
{/* hw:x,14 */
.name = "MSM8x16 Media9",
.stream_name = "MultiMedia9",
.cpu_dai_name = "MultiMedia9",
.platform_name = "msm-pcm-dsp.0",
.dynamic = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.ignore_suspend = 1,
/* This dailink has playback support */
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
},
/* Backend I2S DAI Links */
{
.name = LPASS_BE_PRI_MI2S_RX,
.stream_name = "Primary MI2S Playback",
.cpu_dai_name = "msm-dai-q6-mi2s.0",
.platform_name = "msm-pcm-routing",
.codec_name = MSM8X16_CODEC_NAME,
.codec_dai_name = "msm8x16_wcd_i2s_rx1",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_PRI_MI2S_RX,
.init = &msm_audrx_init,
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ops = &msm8x16_mi2s_be_ops,
.ignore_suspend = 1,
},
{
.name = LPASS_BE_SEC_MI2S_RX,
.stream_name = "Secondary MI2S Playback",
.cpu_dai_name = "msm-dai-q6-mi2s.1",
.platform_name = "msm-pcm-routing",
.codec_name = MSM8X16_CODEC_NAME,
.codec_dai_name = "msm8x16_wcd_i2s_rx1",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
.init = &msm_audrx_init,
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ops = &msm8x16_mi2s_be_ops,
.ignore_suspend = 1,
},
{
.name = LPASS_BE_TERT_MI2S_TX,
.stream_name = "Tertiary MI2S Capture",
.cpu_dai_name = "msm-dai-q6-mi2s.2",
.platform_name = "msm-pcm-routing",
.codec_name = MSM8X16_CODEC_NAME,
.codec_dai_name = "msm8x16_wcd_i2s_tx1",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ops = &msm8x16_mi2s_be_ops,
.ignore_suspend = 1,
},
{
.name = LPASS_BE_INT_BT_SCO_RX,
.stream_name = "Internal BT-SCO Playback",
.cpu_dai_name = "msm-dai-q6-dev.12288",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-rx",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
.ignore_suspend = 1,
},
{
.name = LPASS_BE_INT_BT_SCO_TX,
.stream_name = "Internal BT-SCO Capture",
.cpu_dai_name = "msm-dai-q6-dev.12289",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-tx",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
.ignore_suspend = 1,
},
{
.name = LPASS_BE_INT_FM_RX,
.stream_name = "Internal FM Playback",
.cpu_dai_name = "msm-dai-q6-dev.12292",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-rx",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_INT_FM_RX,
.be_hw_params_fixup = msm_be_hw_params_fixup,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
.ignore_suspend = 1,
},
{
.name = LPASS_BE_INT_FM_TX,
.stream_name = "Internal FM Capture",
.cpu_dai_name = "msm-dai-q6-dev.12293",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-tx",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_INT_FM_TX,
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ignore_suspend = 1,
},
{
.name = LPASS_BE_AFE_PCM_RX,
.stream_name = "AFE Playback",
.cpu_dai_name = "msm-dai-q6-dev.224",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-rx",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
.be_hw_params_fixup = msm_proxy_rx_be_hw_params_fixup,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
.ignore_suspend = 1,
},
{
.name = LPASS_BE_AFE_PCM_TX,
.stream_name = "AFE Capture",
.cpu_dai_name = "msm-dai-q6-dev.225",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-tx",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
.be_hw_params_fixup = msm_proxy_tx_be_hw_params_fixup,
.ignore_suspend = 1,
},
/* Incall Record Uplink BACK END DAI Link */
{
.name = LPASS_BE_INCALL_RECORD_TX,
.stream_name = "Voice Uplink Capture",
.cpu_dai_name = "msm-dai-q6-dev.32772",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-tx",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ignore_suspend = 1,
},
/* Incall Record Downlink BACK END DAI Link */
{
.name = LPASS_BE_INCALL_RECORD_RX,
.stream_name = "Voice Downlink Capture",
.cpu_dai_name = "msm-dai-q6-dev.32771",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-tx",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ignore_suspend = 1,
},
/* Incall Music BACK END DAI Link */
{
.name = LPASS_BE_VOICE_PLAYBACK_TX,
.stream_name = "Voice Farend Playback",
.cpu_dai_name = "msm-dai-q6-dev.32773",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-rx",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ignore_suspend = 1,
},
/* Incall Music 2 BACK END DAI Link */
{
.name = LPASS_BE_VOICE2_PLAYBACK_TX,
.stream_name = "Voice2 Farend Playback",
.cpu_dai_name = "msm-dai-q6-dev.32770",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-rx",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ignore_suspend = 1,
},
};
static struct snd_soc_card bear_cards[MAX_SND_CARDS] = {
/* snd_soc_card_msm8x16 */
{
.name = "msm8x16-snd-card",
.dai_link = msm8x16_dai,
.num_links = ARRAY_SIZE(msm8x16_dai),
},
};
static int msm8x16_asoc_machine_probe(struct platform_device *pdev)
{
struct snd_soc_card *card;
const char *card_dev_id = "qcom,msm-snd-card-id";
int ret, id;
ret = of_property_read_u32(pdev->dev.of_node, card_dev_id, &id);
if (ret) {
dev_err(&pdev->dev,
"%s: missing %s in dt node\n", __func__, card_dev_id);
return ret;
}
pdev->id = id;
dev_set_name(&pdev->dev, "%s.%d", "msm-snd-card", id);
dev_dbg(&pdev->dev, "%s: dev name %s, id:%d\n", __func__,
dev_name(&pdev->dev), pdev->id);
dev_dbg(&pdev->dev, "%s-card:%d\n", __func__, pdev->id);
if (!pdev->dev.of_node) {
dev_err(&pdev->dev, "No platform supplied from device tree\n");
return -EINVAL;
}
if (pdev->id >= MAX_SND_CARDS) {
dev_err(&pdev->dev, "Sound Card parsed is wrong\n");
return -EINVAL;
}
card = &bear_cards[pdev->id];
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
ret = snd_soc_of_parse_card_name(card, "qcom,model");
if (ret)
goto err;
ret = snd_soc_of_parse_audio_routing(card,
"qcom,audio-routing");
if (ret)
goto err;
ret = snd_soc_register_card(card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
ret);
goto err;
}
mutex_init(&cdc_mclk_mutex);
atomic_set(&mclk_rsc_ref, 0);
return 0;
err:
return ret;
}
static int msm8x16_asoc_machine_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
mutex_destroy(&cdc_mclk_mutex);
return 0;
}
static const struct of_device_id msm8x16_asoc_machine_of_match[] = {
{ .compatible = "qcom,msm8x16-audio-codec", },
{},
};
static struct platform_driver msm8x16_asoc_machine_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = msm8x16_asoc_machine_of_match,
},
.probe = msm8x16_asoc_machine_probe,
.remove = msm8x16_asoc_machine_remove,
};
module_platform_driver(msm8x16_asoc_machine_driver);
MODULE_DESCRIPTION("ALSA SoC msm");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRV_NAME);
MODULE_DEVICE_TABLE(of, msm8x16_asoc_machine_of_match);