Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions sound/soc/intel/boards/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -318,16 +318,20 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH

endif ## SND_SOC_INTEL_SKYLAKE

if SND_SOC_INTEL_SKL || SND_SOC_SOF_CANNONLAKE
if SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_CANNONLAKE

config SND_SOC_INTEL_CNL_RT274_MACH
tristate "ASoC Audio driver for CNL with RT274 in I2S Mode"
select SND_SOC_RT274
tristate "Cannonlake with RT274 I2S mode"
depends on MFD_INTEL_LPSS && I2C && ACPI
select SND_SOC_RT274
select SND_SOC_DMIC
select SND_SOC_HDAC_HDMI
help
This adds support for ASoC machine driver for CNL and codec RT274. This
will create an alsa sound card. Say Y if you have such a device If
unsure select "N".
This adds support for ASoC machine driver for Cannonlake platform
with RT274 I2S audio codec.
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".

endif ## SND_SOC_INTEL_SKL || SND_SOC_SOF_CANNONLAKE
endif ## SND_SOC_INTEL_SKYLAKE

endif ## SND_SOC_INTEL_MACH
198 changes: 152 additions & 46 deletions sound/soc/intel/boards/cnl_rt274.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,20 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/async.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/acpi.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include <sound/pcm_params.h>
#include <linux/input.h>

#include "../../codecs/rt274.h"

#define CNL_FREQ_OUT 24000000
Expand All @@ -41,19 +52,32 @@ static int cnl_rt274_clock_control(struct snd_soc_dapm_widget *w,
if (!codec_dai)
return -EINVAL;

ret = snd_soc_dai_set_sysclk(codec_dai, RT274_SCLK_S_PLL1,
CNL_FREQ_OUT,
SND_SOC_CLOCK_IN);
if (ret) {
dev_err(codec_dai->dev,
"failed to enable PLL1: %d\n", ret);
/* Codec needs clock for Jack detection and button press */
ret = snd_soc_dai_set_sysclk(codec_dai, RT274_SCLK_S_PLL2,
CNL_FREQ_OUT, SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(codec_dai->dev, "set codec sysclk failed: %d\n", ret);
return ret;
}

snd_soc_dai_set_bclk_ratio(codec_dai, ratio);
if (SND_SOC_DAPM_EVENT_ON(event)) {
snd_soc_dai_set_bclk_ratio(codec_dai, ratio);

ret = snd_soc_dai_set_pll(codec_dai, 0, RT274_PLL2_S_BCLK,
CNL_BE_FIXUP_RATE * ratio,
CNL_FREQ_OUT);
if (ret) {
dev_err(codec_dai->dev,
"failed to enable PLL2: %d\n", ret);
return ret;
}
}

return ret;
}

static struct snd_soc_jack cnl_headset;

/* Headset jack detection DAPM pins */
static struct snd_soc_jack_pin cnl_headset_pins[] = {
{
Expand All @@ -80,13 +104,17 @@ static const struct snd_soc_dapm_widget cnl_rt274_widgets[] = {
SND_SOC_DAPM_POST_PMD),
};

static const struct snd_soc_pcm_stream dai_params_codec = {
.formats = SNDRV_PCM_FMTBIT_S24_LE,
.rate_min = 48000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
};
#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL)
static int cnl_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
channels->min = channels->max = 2;

return 0;
}
#endif

static const struct snd_soc_dapm_route cnl_map[] = {
{"Headphone Jack", NULL, "HPO Pin"},
Expand All @@ -95,6 +123,17 @@ static const struct snd_soc_dapm_route cnl_map[] = {
{"DMIC01 Rx", NULL, "Capture"},
{"dmic01_hifi", NULL, "DMIC01 Rx"},

/* ssp2 path */
{"Dummy Playback", NULL, "ssp2 Tx"},
{"ssp2 Tx", NULL, "ssp2_out"},

{"ssp2 Rx", NULL, "Dummy Capture"},
{"ssp2_in", NULL, "ssp2 Rx"},

/* ssp1 path */
{"Dummy Playback", NULL, "ssp1 Tx"},
{"ssp1 Tx", NULL, "ssp1_out"},

{"AIF1 Playback", NULL, "ssp0 Tx"},
{"ssp0 Tx", NULL, "codec1_out"},
{"ssp0 Tx", NULL, "codec0_out"},
Expand All @@ -106,14 +145,12 @@ static const struct snd_soc_dapm_route cnl_map[] = {
{"MIC", NULL, "Platform Clock"},
};

static struct snd_soc_jack cnl_headset;

static int cnl_rt274_init(struct snd_soc_pcm_runtime *runtime)
{
int ret;
struct snd_soc_component *component = runtime->codec_dai->component;
struct snd_soc_card *card = runtime->card;
struct snd_soc_dai *codec_dai = runtime->codec_dai;
struct snd_soc_component *component = codec_dai->component;

ret = snd_soc_card_jack_new(runtime->card, "Headset",
SND_JACK_HEADSET, &cnl_headset,
Expand Down Expand Up @@ -151,34 +188,99 @@ static int cnl_be_fixup(struct snd_soc_pcm_runtime *rtd,
channels->max = 2;
snd_mask_none(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT));
snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
SNDRV_PCM_FORMAT_S24_LE);
(unsigned int __force)SNDRV_PCM_FORMAT_S24_LE);

return 0;
}

#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL)
static int cnl_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
channels->min = 2;
channels->max = 2;

return 0;
}
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL_FPGA)
static const char pname[] = "0000:02:18.0";
static const char cname[] = "rt274.0-001c";
#else
#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL)
static const char pname[] = "sof-audio";
#else
static const char pname[] = "0000:00:1f.3";
#endif

static const char cname[] = "i2c-INT34C2:00";
#endif

static struct snd_soc_dai_link cnl_rt274_dailink[] = {
static struct snd_soc_dai_link cnl_rt274_msic_dailink[] = {
#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL)
/* Trace Buffer DAI links */
{
.name = "CNL Trace Buffer0",
.stream_name = "Core 0 Trace Buffer",
.cpu_dai_name = "TraceBuffer0 Pin",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = pname,
.capture_only = true,
.ignore_suspend = 1,
},
{
.name = "CNL Trace Buffer1",
.stream_name = "Core 1 Trace Buffer",
.cpu_dai_name = "TraceBuffer1 Pin",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = pname,
.capture_only = true,
.ignore_suspend = 1,
},
{
.name = "CNL Trace Buffer2",
.stream_name = "Core 2 Trace Buffer",
.cpu_dai_name = "TraceBuffer2 Pin",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = pname,
.capture_only = true,
.ignore_suspend = 1,
},
{
.name = "CNL Trace Buffer3",
.stream_name = "Core 3 Trace Buffer",
.cpu_dai_name = "TraceBuffer3 Pin",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = pname,
.capture_only = true,
.ignore_suspend = 1,
},
/* Probe DAI-links */
{
.name = "CNL Compress Probe playback",
.stream_name = "Probe Playback",
.cpu_dai_name = "Compress Probe0 Pin",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = pname,
.init = NULL,
.ignore_suspend = 1,
.nonatomic = 1,
},
{
.name = "CNL Compress Probe capture",
.stream_name = "Probe Capture",
.cpu_dai_name = "Compress Probe1 Pin",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = pname,
.init = NULL,
.ignore_suspend = 1,
.nonatomic = 1,
},
#endif
/* back ends */
{
.name = "SSP0-Codec",
.id = 1,
.cpu_dai_name = "SSP0 Pin",
.codec_name = cname,
.codec_dai_name = "rt274-aif1",
.be_hw_params_fixup = cnl_be_fixup,
.ignore_pmdown_time = 1,
.ignore_suspend = 1,
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_DSP_A |
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS,
Expand All @@ -189,6 +291,7 @@ static struct snd_soc_dai_link cnl_rt274_dailink[] = {
#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL)
{
.name = "dmic01",
.id = 2,
.cpu_dai_name = "DMIC01 Pin",
.codec_name = "dmic-codec",
.codec_dai_name = "dmic-hifi",
Expand All @@ -200,42 +303,45 @@ static struct snd_soc_dai_link cnl_rt274_dailink[] = {
#endif
};

static int
cnl_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link)
{
link->platform_name = pname;
link->nonatomic = 1;

return 0;
}

/* SoC card */
static struct snd_soc_card snd_soc_card_cnl = {
.name = "cnl-audio",
.dai_link = cnl_rt274_dailink,
.num_links = ARRAY_SIZE(cnl_rt274_dailink),
.dai_link = cnl_rt274_msic_dailink,
.num_links = ARRAY_SIZE(cnl_rt274_msic_dailink),
.dapm_widgets = cnl_rt274_widgets,
.num_dapm_widgets = ARRAY_SIZE(cnl_rt274_widgets),
.dapm_routes = cnl_map,
.num_dapm_routes = ARRAY_SIZE(cnl_map),
.controls = cnl_controls,
.num_controls = ARRAY_SIZE(cnl_controls),
.add_dai_link = cnl_add_dai_link,
.fully_routed = true,
};

static int cnl_rt274_probe(struct platform_device *pdev)
static int snd_cnl_rt274_mc_probe(struct platform_device *pdev)
{
snd_soc_card_cnl.dev = &pdev->dev;

return devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cnl);
}

static const struct platform_device_id cnl_board_ids[] = {
{ .name = "cnl_rt274" },
{ }
};

static struct platform_driver cnl_rt274_driver = {
static struct platform_driver snd_cnl_rt274_driver = {
.driver = {
.name = "cnl_rt274",
.pm = &snd_soc_pm_ops,
},
.probe = cnl_rt274_probe,
.id_table = cnl_board_ids,
.probe = snd_cnl_rt274_mc_probe,
};

module_platform_driver(cnl_rt274_driver);
module_platform_driver(snd_cnl_rt274_driver);

MODULE_AUTHOR("Guneshwor Singh <guneshwor.o.singh@intel.com>");
MODULE_LICENSE("GPL v2");
Expand Down