rt5660 and rt5640 are similar codecs so reuse the bytcr_rt5640 driver. RT5660 codec is used on Dell Edge IoT Gateways with ACPI ID 10EC3277. These devices sport only Line-In and Line-Out jacks.
Signed-off-by: Shrirang Bagul shrirang.bagul@canonical.com --- sound/soc/intel/Kconfig | 11 +-- sound/soc/intel/atom/sst/sst_acpi.c | 2 + sound/soc/intel/boards/bytcr_rt5640.c | 156 ++++++++++++++++++++++++++++++---- 3 files changed, 147 insertions(+), 22 deletions(-)
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index fd5d1e0..0b43b6a 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -147,17 +147,18 @@ config SND_SOC_INTEL_BROADWELL_MACH If unsure select "N".
config SND_SOC_INTEL_BYTCR_RT5640_MACH - tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec" + tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640/5660 codec" depends on X86 && I2C && ACPI select SND_SOC_RT5640 + select SND_SOC_RT5660 select SND_SST_MFLD_PLATFORM select SND_SST_IPC_ACPI select SND_SOC_INTEL_SST_MATCH if ACPI help - This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR - platforms with RT5640 audio codec. - Say Y if you have such a device. - If unsure select "N". + This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR + platforms with RT5640, RT5460 audio codec. + Say Y if you have such a device. + If unsure select "N".
config SND_SOC_INTEL_BYTCR_RT5651_MACH tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec" diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index f4d92bb..d401457f 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -441,6 +441,8 @@ static struct sst_acpi_mach sst_acpi_bytcr[] = { &byt_rvp_platform_data }, {"10EC5642", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, &byt_rvp_platform_data }, + {"10EC3277", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, + &byt_rvp_platform_data }, {"INTCCFFD", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, &byt_rvp_platform_data }, {"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL, diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index f6fd397..e8c9a01 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -32,11 +32,17 @@ #include <sound/soc.h> #include <sound/jack.h> #include "../../codecs/rt5640.h" +#include "../../codecs/rt5660.h" #include "../atom/sst-atom-controls.h" #include "../common/sst-acpi.h" #include "../common/sst-dsp.h"
enum { + CODEC_TYPE_RT5640, + CODEC_TYPE_RT5660, +}; + +enum { BYT_RT5640_DMIC1_MAP, BYT_RT5640_DMIC2_MAP, BYT_RT5640_IN1_MAP, @@ -60,8 +66,16 @@ enum { PLL1_MCLK, };
+struct byt_acpi_card { + char *codec_id; + int codec_type; + struct snd_soc_card *soc_card; +}; + struct byt_rt5640_private { + struct byt_acpi_card *acpi_card; struct clk *mclk; + char codec_name[16]; int *clks; };
@@ -72,6 +86,13 @@ static int byt_rt5640_clks[] = { RT5640_PLL1_S_MCLK };
+static int byt_rt5660_clks[] = { + RT5660_SCLK_S_PLL1, + RT5660_SCLK_S_RCCLK, + RT5660_PLL1_S_BCLK, + RT5660_PLL1_S_MCLK +}; + static unsigned long byt_rt5640_quirk = BYT_RT5640_MCLK_EN;
static void log_quirks(struct device *dev) @@ -105,6 +126,7 @@ static void log_quirks(struct device *dev)
#define BYT_CODEC_DAI1 "rt5640-aif1" #define BYT_CODEC_DAI2 "rt5640-aif2" +#define BYT_CODEC_DAI3 "rt5660-aif1"
static inline struct snd_soc_dai *byt_get_codec_dai(struct snd_soc_card *card) { @@ -117,6 +139,9 @@ static inline struct snd_soc_dai *byt_get_codec_dai(struct snd_soc_card *card) if (!strncmp(rtd->codec_dai->name, BYT_CODEC_DAI2, strlen(BYT_CODEC_DAI2))) return rtd->codec_dai; + if (!strncmp(rtd->codec_dai->name, BYT_CODEC_DAI3, + strlen(BYT_CODEC_DAI3))) + return rtd->codec_dai;
} return NULL; @@ -269,6 +294,29 @@ static const struct snd_kcontrol_new byt_rt5640_controls[] = { SOC_DAPM_PIN_SWITCH("Speaker"), };
+static const struct snd_soc_dapm_widget byt_rt5660_widgets[] = { + SND_SOC_DAPM_MIC("Line In", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route byt_rt5660_audio_map[] = { + {"IN1P", NULL, "Line In"}, + {"IN2P", NULL, "Line In"}, + {"Line Out", NULL, "LOUTR"}, + {"Line Out", NULL, "LOUTL"}, + + {"Line In", NULL, "Platform Clock"}, + {"Line Out", NULL, "Platform Clock"}, +}; + +static const struct snd_kcontrol_new byt_rt5660_controls[] = { + SOC_DAPM_PIN_SWITCH("Line In"), + SOC_DAPM_PIN_SWITCH("Line Out"), +}; + static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -422,11 +470,8 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) struct snd_soc_codec *codec = runtime->codec; struct snd_soc_card *card = runtime->card; const struct snd_soc_dapm_route *custom_map; - struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); int num_routes;
- card->dapm.idle_bias_off = true; - rt5640_sel_asrc_clk_src(codec, RT5640_DA_STEREO_FILTER | RT5640_DA_MONO_L_FILTER | @@ -511,6 +556,39 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
+ return ret; +} + +static int byt_rt5660_init(struct snd_soc_pcm_runtime *runtime) +{ + int ret; + struct snd_soc_card *card = runtime->card; + + ret = snd_soc_dapm_add_routes(&card->dapm, + byt_rt5640_ssp2_aif1_map, + ARRAY_SIZE(byt_rt5640_ssp2_aif1_map)); + if (ret) + return ret; + + snd_soc_dapm_enable_pin(&card->dapm, "Line In"); + snd_soc_dapm_enable_pin(&card->dapm, "Line Out"); + + return ret; +} + +static int byt_rt56x0_init(struct snd_soc_pcm_runtime *runtime) +{ + int ret; + struct snd_soc_card *card = runtime->card; + struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); + + card->dapm.idle_bias_off = true; + + if (priv->acpi_card->codec_type == CODEC_TYPE_RT5640) + ret = byt_rt5640_init(runtime); + else + ret = byt_rt5660_init(runtime); + if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk) { /* * The firmware might enable the clock at @@ -679,7 +757,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .ignore_suspend = 1, .dpcm_playback = 1, .dpcm_capture = 1, - .init = byt_rt5640_init, + .init = byt_rt56x0_init, .ops = &byt_rt5640_be_ssp2_ops, }, }; @@ -697,6 +775,25 @@ static struct snd_soc_card byt_rt5640_card = { .fully_routed = true, };
+static struct snd_soc_card byt_rt5660_card = { + .name = "bytcr-rt5660", + .owner = THIS_MODULE, + .dai_link = byt_rt5640_dais, + .num_links = ARRAY_SIZE(byt_rt5640_dais), + .controls = byt_rt5660_controls, + .num_controls = ARRAY_SIZE(byt_rt5660_controls), + .dapm_widgets = byt_rt5660_widgets, + .num_dapm_widgets = ARRAY_SIZE(byt_rt5660_widgets), + .dapm_routes = byt_rt5660_audio_map, + .num_dapm_routes = ARRAY_SIZE(byt_rt5660_audio_map), + .fully_routed = true, +}; + +static struct byt_acpi_card snd_soc_cards[] = { + {"10EC5640", CODEC_TYPE_RT5640, &byt_rt5640_card}, + {"10EC3277", CODEC_TYPE_RT5660, &byt_rt5660_card}, +}; + static char byt_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */ static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ @@ -721,41 +818,51 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { int ret_val = 0; - struct sst_acpi_mach *mach; - const char *i2c_name = NULL; int i; - int dai_index; struct byt_rt5640_private *priv; + struct snd_soc_card *card = snd_soc_cards[0].soc_card; + struct sst_acpi_mach *mach; + const char *i2c_name = NULL; + int dai_index = 0; bool is_bytcr = false;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); if (!priv) return -ENOMEM;
+ for (i = 0; i < ARRAY_SIZE(snd_soc_cards); i++) { + if (acpi_dev_found(snd_soc_cards[i].codec_id)) { + dev_dbg(&pdev->dev, + "found codec %s\n", snd_soc_cards[i].codec_id); + card = snd_soc_cards[i].soc_card; + priv->acpi_card = &snd_soc_cards[i]; + break; + } + } + /* register the soc card */ priv->clks = byt_rt5640_clks; - byt_rt5640_card.dev = &pdev->dev; - mach = byt_rt5640_card.dev->platform_data; - snd_soc_card_set_drvdata(&byt_rt5640_card, priv); + card->dev = &pdev->dev; + mach = card->dev->platform_data; + sprintf(priv->codec_name, "i2c-%s:00", priv->acpi_card->codec_id);
/* fix index of codec dai */ - dai_index = MERR_DPCM_COMPR + 1; - for (i = 0; i < ARRAY_SIZE(byt_rt5640_dais); i++) { + for (i = 0; i < ARRAY_SIZE(byt_rt5640_dais); i++) if (!strcmp(byt_rt5640_dais[i].codec_name, "i2c-10EC5640:00")) { + card->dai_link[i].codec_name = priv->codec_name; dai_index = i; - break; } - }
/* fixup codec name based on HID */ i2c_name = sst_acpi_find_name_from_hid(mach->id); if (i2c_name != NULL) { snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name), "%s%s", "i2c-", i2c_name); - byt_rt5640_dais[dai_index].codec_name = byt_rt5640_codec_name; }
+ snd_soc_card_set_drvdata(card, priv); + /* * swap SSP0 if bytcr is detected * (will be overridden if DMI quirk is detected) @@ -821,6 +928,21 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) BYT_RT5640_DMIC_EN); }
+ if (priv->acpi_card->codec_type == CODEC_TYPE_RT5660) { + priv->clks = byt_rt5660_clks; + + /* fixup codec aif name for rt5660 */ + snprintf(byt_rt5640_codec_aif_name, + sizeof(byt_rt5640_codec_aif_name), + "%s", "rt5660-aif1"); + + byt_rt5640_dais[dai_index].codec_dai_name = + byt_rt5640_codec_aif_name; + + /* setup codec quirks for rt5660 */ + byt_rt5640_quirk = BYT_RT5640_MCLK_EN; + } + /* check quirks before creating card */ dmi_check_system(byt_rt5640_quirk_table); log_quirks(&pdev->dev); @@ -869,14 +991,14 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) } }
- ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); + ret_val = devm_snd_soc_register_card(&pdev->dev, card);
if (ret_val) { dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", ret_val); return ret_val; } - platform_set_drvdata(pdev, &byt_rt5640_card); + platform_set_drvdata(pdev, card); return ret_val; }