]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'asoc/topic/intel' into asoc-next
authorMark Brown <broonie@kernel.org>
Mon, 3 Jul 2017 15:15:04 +0000 (16:15 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 3 Jul 2017 15:15:04 +0000 (16:15 +0100)
38 files changed:
include/uapi/sound/snd_sst_tokens.h
sound/soc/codecs/rt5670.c
sound/soc/codecs/rt5677.c
sound/soc/intel/Kconfig
sound/soc/intel/atom/sst-mfld-platform-pcm.c
sound/soc/intel/atom/sst/sst.c
sound/soc/intel/atom/sst/sst.h
sound/soc/intel/atom/sst/sst_acpi.c
sound/soc/intel/boards/Makefile
sound/soc/intel/boards/bdw-rt5677.c
sound/soc/intel/boards/bxt_da7219_max98357a.c
sound/soc/intel/boards/bxt_rt298.c
sound/soc/intel/boards/byt-max98090.c
sound/soc/intel/boards/bytcht_es8316.c [new file with mode: 0644]
sound/soc/intel/boards/bytcht_nocodec.c
sound/soc/intel/boards/bytcr_rt5651.c
sound/soc/intel/boards/cht_bsw_max98090_ti.c
sound/soc/intel/boards/cht_bsw_rt5672.c
sound/soc/intel/boards/kbl_rt5663_max98927.c [new file with mode: 0644]
sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c [new file with mode: 0644]
sound/soc/intel/boards/skl_nau88l25_max98357a.c
sound/soc/intel/boards/skl_nau88l25_ssm4567.c
sound/soc/intel/boards/skl_rt286.c
sound/soc/intel/common/sst-acpi.h
sound/soc/intel/common/sst-dsp-priv.h
sound/soc/intel/common/sst-match-acpi.c
sound/soc/intel/skylake/Makefile
sound/soc/intel/skylake/bxt-sst.c
sound/soc/intel/skylake/skl-debug.c [new file with mode: 0644]
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl-sst.c
sound/soc/intel/skylake/skl-topology.c
sound/soc/intel/skylake/skl-topology.h
sound/soc/intel/skylake/skl-tplg-interface.h
sound/soc/intel/skylake/skl.c
sound/soc/intel/skylake/skl.h
sound/soc/soc-core.c

index 93392bedcc5870d64514ae84ab00095de4b9971f..dedb2056160d03a76ca2b1238652ad3afa64926e 100644 (file)
  *
  * %SKL_TKL_U32_D0I3_CAPS:     Specifies the D0i3 capability for module
  *
+ * %SKL_TKN_U32_DMA_BUF_SIZE:  DMA buffer size in millisec
+ *
  * module_id and loadable flags dont have tokens as these values will be
  * read from the DSP FW manifest
  */
@@ -213,8 +215,10 @@ enum SKL_TKNS {
        SKL_TKN_U32_LIB_COUNT,
        SKL_TKN_STR_LIB_NAME,
        SKL_TKN_U32_PMODE,
-       SKL_TKL_U32_D0I3_CAPS,
-       SKL_TKN_MAX = SKL_TKL_U32_D0I3_CAPS,
+       SKL_TKL_U32_D0I3_CAPS, /* Typo added at v4.10 */
+       SKL_TKN_U32_D0I3_CAPS = SKL_TKL_U32_D0I3_CAPS,
+       SKL_TKN_U32_DMA_BUF_SIZE,
+       SKL_TKN_MAX = SKL_TKN_U32_DMA_BUF_SIZE,
 };
 
 #endif
index d95d2e693dc6c9cf380f2d6ab2341df7f4d66b89..a5f15a104c47a7558405380f8603490e7bd9b921 100644 (file)
@@ -2848,6 +2848,10 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = {
                        DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Tablet B"),
                },
        },
+       {}
+};
+
+static const struct dmi_system_id dmi_platform_intel_bytcht_jdmode2[] = {
        {
                .ident = "Lenovo Thinkpad Tablet 10",
                .matches = {
@@ -2882,6 +2886,11 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
                rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
                rt5670->pdata.dev_gpio = true;
                rt5670->pdata.jd_mode = 1;
+       } else if (dmi_check_system(dmi_platform_intel_bytcht_jdmode2)) {
+               rt5670->pdata.dmic_en = true;
+               rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
+               rt5670->pdata.dev_gpio = true;
+               rt5670->pdata.jd_mode = 2;
        }
 
        rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap);
index 65ac4518ad06096e1ca8d04c539fc19ddf1b8f15..36e530a36c8241d5005c8e8f5f933f2a405c3434 100644 (file)
 
 #define RT5677_PR_BASE (RT5677_PR_RANGE_BASE + (0 * RT5677_PR_SPACING))
 
-/* GPIO indexes defined by ACPI */
-enum {
-       RT5677_GPIO_PLUG_DET            = 0,
-       RT5677_GPIO_MIC_PRESENT_L       = 1,
-       RT5677_GPIO_HOTWORD_DET_L       = 2,
-       RT5677_GPIO_DSP_INT             = 3,
-       RT5677_GPIO_HP_AMP_SHDN_L       = 4,
-};
-
 static const struct regmap_range_cfg rt5677_ranges[] = {
        {
                .name = "PR",
@@ -5030,7 +5021,6 @@ static const struct regmap_config rt5677_regmap = {
 static const struct i2c_device_id rt5677_i2c_id[] = {
        { "rt5677", RT5677 },
        { "rt5676", RT5676 },
-       { "RT5677CE:00", RT5677 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id);
@@ -5041,28 +5031,19 @@ static const struct of_device_id rt5677_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, rt5677_of_match);
 
-static const struct acpi_gpio_params plug_det_gpio = { RT5677_GPIO_PLUG_DET, 0, false };
-static const struct acpi_gpio_params mic_present_gpio = { RT5677_GPIO_MIC_PRESENT_L, 0, false };
-static const struct acpi_gpio_params headphone_enable_gpio = { RT5677_GPIO_HP_AMP_SHDN_L, 0, false };
-
-static const struct acpi_gpio_mapping bdw_rt5677_gpios[] = {
-       { "plug-det-gpios", &plug_det_gpio, 1 },
-       { "mic-present-gpios", &mic_present_gpio, 1 },
-       { "headphone-enable-gpios", &headphone_enable_gpio, 1 },
-       { NULL },
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt5677_acpi_match[] = {
+       { "RT5677CE", RT5677 },
+       { }
 };
+MODULE_DEVICE_TABLE(acpi, rt5677_acpi_match);
+#endif
 
 static void rt5677_read_acpi_properties(struct rt5677_priv *rt5677,
                struct device *dev)
 {
-       int ret;
        u32 val;
 
-       ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev),
-                       bdw_rt5677_gpios);
-       if (ret)
-               dev_warn(dev, "Failed to add driver gpios\n");
-
        if (!device_property_read_u32(dev, "DCLK", &val))
                rt5677->pdata.dmic2_clk_pin = val;
 
@@ -5301,6 +5282,7 @@ static struct i2c_driver rt5677_i2c_driver = {
        .driver = {
                .name = "rt5677",
                .of_match_table = rt5677_of_match,
+               .acpi_match_table = ACPI_PTR(rt5677_acpi_match),
        },
        .probe = rt5677_i2c_probe,
        .remove   = rt5677_i2c_remove,
index 67968ef3bbda48528c4bac723252b0cab2684cbb..b301bfff1c09ca06a10692c47352366aa096493b 100644 (file)
@@ -214,6 +214,18 @@ config SND_SOC_INTEL_BYT_CHT_DA7213_MACH
          platforms with DA7212/7213 audio codec.
          If unsure select "N".
 
+config SND_SOC_INTEL_BYT_CHT_ES8316_MACH
+       tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with ES8316 codec"
+       depends on X86_INTEL_LPSS && I2C && ACPI
+       select SND_SOC_ES8316
+       select SND_SST_ATOM_HIFI2_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 &
+         Cherrytrail platforms with ES8316 audio codec.
+         If unsure select "N".
+
 config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH
        tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)"
        depends on X86_INTEL_LPSS && I2C && ACPI
@@ -226,6 +238,36 @@ config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH
          connector
          If unsure select "N".
 
+config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
+       tristate "ASoC Audio driver for KBL with RT5663 and MAX98927 in I2S Mode"
+       depends on X86_INTEL_LPSS && I2C
+       select SND_SOC_INTEL_SST
+       select SND_SOC_INTEL_SKYLAKE
+       select SND_SOC_RT5663
+       select SND_SOC_MAX98927
+       select SND_SOC_DMIC
+       select SND_SOC_HDAC_HDMI
+       help
+         This adds support for ASoC Onboard Codec I2S machine driver. This will
+         create an alsa sound card for RT5663 + MAX98927.
+         Say Y if you have such a device.
+         If unsure select "N".
+
+config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
+        tristate "ASoC Audio driver for KBL with RT5663, RT5514 and MAX98927 in I2S Mode"
+        depends on X86_INTEL_LPSS && I2C
+        select SND_SOC_INTEL_SST
+        select SND_SOC_INTEL_SKYLAKE
+        select SND_SOC_RT5663
+        select SND_SOC_RT5514
+        select SND_SOC_MAX98927
+        select SND_SOC_HDAC_HDMI
+        help
+          This adds support for ASoC Onboard Codec I2S machine driver. This will
+          create an alsa sound card for RT5663 + RT5514 + MAX98927.
+          Say Y if you have such a device.
+          If unsure select "N".
+
 config SND_SOC_INTEL_SKYLAKE
        tristate
        select SND_HDA_EXT_CORE
index 21cac1c8dd4cb295cf9013386ea6f4549e14d1bf..b082b31023d59e648034c8d5ffc718c202a72e60 100644 (file)
@@ -690,7 +690,7 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
                        snd_dma_continuous_data(GFP_DMA),
                        SST_MIN_BUFFER, SST_MAX_BUFFER);
                if (retval) {
-                       dev_err(rtd->dev, "dma buffer allocationf fail\n");
+                       dev_err(rtd->dev, "dma buffer allocation failure\n");
                        return retval;
                }
        }
index f9ba71315e335021b34aa18b4030a29b861bcac1..8afdff457579fe9062089fcb6d364cd2185f45ee 100644 (file)
@@ -258,7 +258,7 @@ static ssize_t firmware_version_show(struct device *dev,
 
 }
 
-DEVICE_ATTR_RO(firmware_version);
+static DEVICE_ATTR_RO(firmware_version);
 
 static const struct attribute *sst_fw_version_attrs[] = {
        &dev_attr_firmware_version.attr,
@@ -382,37 +382,6 @@ void sst_context_cleanup(struct intel_sst_drv *ctx)
 }
 EXPORT_SYMBOL_GPL(sst_context_cleanup);
 
-static inline void sst_save_shim64(struct intel_sst_drv *ctx,
-                           void __iomem *shim,
-                           struct sst_shim_regs64 *shim_regs)
-{
-       unsigned long irq_flags;
-
-       spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags);
-
-       shim_regs->imrx = sst_shim_read64(shim, SST_IMRX);
-       shim_regs->csr = sst_shim_read64(shim, SST_CSR);
-
-
-       spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags);
-}
-
-static inline void sst_restore_shim64(struct intel_sst_drv *ctx,
-                                     void __iomem *shim,
-                                     struct sst_shim_regs64 *shim_regs)
-{
-       unsigned long irq_flags;
-
-       /*
-        * we only need to restore IMRX for this case, rest will be
-        * initialize by FW or driver when firmware is loaded
-        */
-       spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags);
-       sst_shim_write64(shim, SST_IMRX, shim_regs->imrx);
-       sst_shim_write64(shim, SST_CSR, shim_regs->csr);
-       spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags);
-}
-
 void sst_configure_runtime_pm(struct intel_sst_drv *ctx)
 {
        pm_runtime_set_autosuspend_delay(ctx->dev, SST_SUSPEND_DELAY);
@@ -432,8 +401,6 @@ void sst_configure_runtime_pm(struct intel_sst_drv *ctx)
                pm_runtime_set_active(ctx->dev);
        else
                pm_runtime_put_noidle(ctx->dev);
-
-       sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64);
 }
 EXPORT_SYMBOL_GPL(sst_configure_runtime_pm);
 
@@ -457,8 +424,6 @@ static int intel_sst_runtime_suspend(struct device *dev)
        flush_workqueue(ctx->post_msg_wq);
 
        ctx->ops->reset(ctx);
-       /* save the shim registers because PMC doesn't save state */
-       sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64);
 
        return ret;
 }
@@ -499,23 +464,23 @@ static int intel_sst_suspend(struct device *dev)
        fw_save = kzalloc(sizeof(*fw_save), GFP_KERNEL);
        if (!fw_save)
                return -ENOMEM;
-       fw_save->iram = kzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL);
+       fw_save->iram = kvzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL);
        if (!fw_save->iram) {
                ret = -ENOMEM;
                goto iram;
        }
-       fw_save->dram = kzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL);
+       fw_save->dram = kvzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL);
        if (!fw_save->dram) {
                ret = -ENOMEM;
                goto dram;
        }
-       fw_save->sram = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL);
+       fw_save->sram = kvzalloc(SST_MAILBOX_SIZE, GFP_KERNEL);
        if (!fw_save->sram) {
                ret = -ENOMEM;
                goto sram;
        }
 
-       fw_save->ddr = kzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL);
+       fw_save->ddr = kvzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL);
        if (!fw_save->ddr) {
                ret = -ENOMEM;
                goto ddr;
@@ -530,11 +495,11 @@ static int intel_sst_suspend(struct device *dev)
        ctx->ops->reset(ctx);
        return 0;
 ddr:
-       kfree(fw_save->sram);
+       kvfree(fw_save->sram);
 sram:
-       kfree(fw_save->dram);
+       kvfree(fw_save->dram);
 dram:
-       kfree(fw_save->iram);
+       kvfree(fw_save->iram);
 iram:
        kfree(fw_save);
        return ret;
@@ -562,10 +527,10 @@ static int intel_sst_resume(struct device *dev)
        memcpy32_toio(ctx->mailbox, fw_save->sram, SST_MAILBOX_SIZE);
        memcpy32_toio(ctx->ddr, fw_save->ddr, ctx->ddr_end - ctx->ddr_base);
 
-       kfree(fw_save->sram);
-       kfree(fw_save->dram);
-       kfree(fw_save->iram);
-       kfree(fw_save->ddr);
+       kvfree(fw_save->sram);
+       kvfree(fw_save->dram);
+       kvfree(fw_save->iram);
+       kvfree(fw_save->ddr);
        kfree(fw_save);
 
        block = sst_create_block(ctx, 0, FW_DWNL_ID);
index 5c9a51cc77aa41e8efe123afc517a42867f16baf..e02e2b4cc08f0e657be5096fce99aa3d003db96d 100644 (file)
@@ -317,31 +317,11 @@ struct sst_ipc_reg {
        int ipcd;
 };
 
-struct sst_shim_regs64 {
-       u64 csr;
-       u64 pisr;
-       u64 pimr;
-       u64 isrx;
-       u64 isrd;
-       u64 imrx;
-       u64 imrd;
-       u64 ipcx;
-       u64 ipcd;
-       u64 isrsc;
-       u64 isrlpesc;
-       u64 imrsc;
-       u64 imrlpesc;
-       u64 ipcsc;
-       u64 ipclpesc;
-       u64 clkctl;
-       u64 csr2;
-};
-
 struct sst_fw_save {
-       void *iram;
-       void *dram;
-       void *sram;
-       void *ddr;
+       void *iram;     /* allocated via kvmalloc() */
+       void *dram;     /* allocated via kvmalloc() */
+       void *sram;     /* allocated via kvmalloc() */
+       void *ddr;      /* allocated via kvmalloc() */
 };
 
 /**
@@ -356,7 +336,6 @@ struct sst_fw_save {
  * @dram : SST DRAM pointer
  * @pdata : SST info passed as a part of pci platform data
  * @shim_phy_add : SST shim phy addr
- * @shim_regs64: Struct to save shim registers
  * @ipc_dispatch_list : ipc messages dispatched
  * @rx_list : to copy the process_reply/process_msg from DSP
  * @ipc_post_msg_wq : wq to post IPC messages context
@@ -398,7 +377,6 @@ struct intel_sst_drv {
        unsigned int            ddr_end;
        unsigned int            ddr_base;
        unsigned int            mailbox_recv_offset;
-       struct sst_shim_regs64  *shim_regs64;
        struct list_head        block_list;
        struct list_head        ipc_dispatch_list;
        struct sst_platform_info *pdata;
index dd250b8b26f24c2d09012f9a7a434ae661b5bf49..0e928d54305dad366586c6d2ec56829e5bb75ed2 100644 (file)
@@ -303,8 +303,6 @@ static int sst_acpi_probe(struct platform_device *pdev)
                dev_err(dev, "No matching machine driver found\n");
                return -ENODEV;
        }
-       if (mach->machine_quirk)
-               mach = mach->machine_quirk(mach);
 
        pdata = mach->pdata;
 
@@ -360,23 +358,9 @@ static int sst_acpi_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
-       /* need to save shim registers in BYT */
-       ctx->shim_regs64 = devm_kzalloc(ctx->dev, sizeof(*ctx->shim_regs64),
-                                       GFP_KERNEL);
-       if (!ctx->shim_regs64) {
-               ret = -ENOMEM;
-               goto do_sst_cleanup;
-       }
-
        sst_configure_runtime_pm(ctx);
        platform_set_drvdata(pdev, ctx);
        return ret;
-
-do_sst_cleanup:
-       sst_context_cleanup(ctx);
-       platform_set_drvdata(pdev, NULL);
-       dev_err(ctx->dev, "failed with %d\n", ret);
-       return ret;
 }
 
 /**
@@ -453,12 +437,20 @@ static const struct dmi_system_id cht_table[] = {
 
 
 static struct sst_acpi_mach cht_surface_mach = {
-       "10EC5640", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
-                                                               &chv_platform_data };
+       .id = "10EC5640",
+       .drv_name = "cht-bsw-rt5645",
+       .fw_filename = "intel/fw_sst_22a8.bin",
+       .board = "cht-bsw",
+       .pdata = &chv_platform_data,
+};
 
 static struct sst_acpi_mach byt_thinkpad_10 = {
-       "10EC5640", "cht-bsw-rt5672", "intel/fw_sst_0f28.bin", "cht-bsw", NULL,
-                                                               &byt_rvp_platform_data };
+       .id = "10EC5640",
+       .drv_name = "cht-bsw-rt5672",
+       .fw_filename = "intel/fw_sst_0f28.bin",
+       .board = "cht-bsw",
+       .pdata = &byt_rvp_platform_data,
+};
 
 static struct sst_acpi_mach *cht_quirk(void *arg)
 {
@@ -486,68 +478,182 @@ static struct sst_acpi_mach *byt_quirk(void *arg)
 
 
 static struct sst_acpi_mach sst_acpi_bytcr[] = {
-       {"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", byt_quirk,
-                                               &byt_rvp_platform_data },
-       {"10EC5642", "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,
-                                               &byt_rvp_platform_data },
-       {"DLGS7212", "bytcht_da7213", "intel/fw_sst_0f28.bin", "bytcht_da7213", NULL,
-                                               &byt_rvp_platform_data },
-       {"DLGS7213", "bytcht_da7213", "intel/fw_sst_0f28.bin", "bytcht_da7213", NULL,
-                                               &byt_rvp_platform_data },
+       {
+               .id = "10EC5640",
+               .drv_name = "bytcr_rt5640",
+               .fw_filename = "intel/fw_sst_0f28.bin",
+               .board = "bytcr_rt5640",
+               .machine_quirk = byt_quirk,
+               .pdata = &byt_rvp_platform_data,
+       },
+       {
+               .id = "10EC5642",
+               .drv_name = "bytcr_rt5640",
+               .fw_filename = "intel/fw_sst_0f28.bin",
+               .board = "bytcr_rt5640",
+               .pdata = &byt_rvp_platform_data
+       },
+       {
+               .id = "INTCCFFD",
+               .drv_name = "bytcr_rt5640",
+               .fw_filename = "intel/fw_sst_0f28.bin",
+               .board = "bytcr_rt5640",
+               .pdata = &byt_rvp_platform_data
+       },
+       {
+               .id = "10EC5651",
+               .drv_name = "bytcr_rt5651",
+               .fw_filename = "intel/fw_sst_0f28.bin",
+               .board = "bytcr_rt5651",
+               .pdata = &byt_rvp_platform_data
+       },
+       {
+               .id = "DLGS7212",
+               .drv_name = "bytcht_da7213",
+               .fw_filename = "intel/fw_sst_0f28.bin",
+               .board = "bytcht_da7213",
+               .pdata = &byt_rvp_platform_data
+       },
+       {
+               .id = "DLGS7213",
+               .drv_name = "bytcht_da7213",
+               .fw_filename = "intel/fw_sst_0f28.bin",
+               .board = "bytcht_da7213",
+               .pdata = &byt_rvp_platform_data
+       },
        /* some Baytrail platforms rely on RT5645, use CHT machine driver */
-       {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL,
-                                               &byt_rvp_platform_data },
-       {"10EC5648", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL,
-                                               &byt_rvp_platform_data },
+       {
+               .id = "10EC5645",
+               .drv_name = "cht-bsw-rt5645",
+               .fw_filename = "intel/fw_sst_0f28.bin",
+               .board = "cht-bsw",
+               .pdata = &byt_rvp_platform_data
+       },
+       {
+               .id = "10EC5648",
+               .drv_name = "cht-bsw-rt5645",
+               .fw_filename = "intel/fw_sst_0f28.bin",
+               .board = "cht-bsw",
+               .pdata = &byt_rvp_platform_data
+       },
 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH)
        /*
         * This is always last in the table so that it is selected only when
         * enabled explicitly and there is no codec-related information in SSDT
         */
-       {"80860F28", "bytcht_nocodec", "intel/fw_sst_0f28.bin", "bytcht_nocodec", NULL,
-                                               &byt_rvp_platform_data },
+       {
+               .id = "80860F28",
+               .drv_name = "bytcht_nocodec",
+               .fw_filename = "intel/fw_sst_0f28.bin",
+               .board = "bytcht_nocodec",
+               .pdata = &byt_rvp_platform_data
+       },
 #endif
        {},
 };
 
 /* Cherryview-based platforms: CherryTrail and Braswell */
 static struct sst_acpi_mach sst_acpi_chv[] = {
-       {"10EC5670", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
-                                               &chv_platform_data },
-       {"10EC5672", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
-                                               &chv_platform_data },
-       {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
-                                               &chv_platform_data },
-       {"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
-                                               &chv_platform_data },
-       {"10EC3270", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
-                                               &chv_platform_data },
-
-       {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
-                                               &chv_platform_data },
-       {"DLGS7212", "bytcht_da7213", "intel/fw_sst_22a8.bin", "bytcht_da7213", NULL,
-                                               &chv_platform_data },
-       {"DLGS7213", "bytcht_da7213", "intel/fw_sst_22a8.bin", "bytcht_da7213", NULL,
-                                               &chv_platform_data },
+       {
+               .id = "10EC5670",
+               .drv_name = "cht-bsw-rt5672",
+               .fw_filename = "intel/fw_sst_22a8.bin",
+               .board = "cht-bsw",
+               .pdata = &chv_platform_data
+       },
+       {
+               .id = "10EC5672",
+               .drv_name = "cht-bsw-rt5672",
+               .fw_filename = "intel/fw_sst_22a8.bin",
+               .board = "cht-bsw",
+               .pdata = &chv_platform_data
+       },
+       {
+               .id = "10EC5645",
+               .drv_name = "cht-bsw-rt5645",
+               .fw_filename = "intel/fw_sst_22a8.bin",
+               .board = "cht-bsw",
+               .pdata = &chv_platform_data
+       },
+       {
+               .id = "10EC5650",
+               .drv_name = "cht-bsw-rt5645",
+               .fw_filename = "intel/fw_sst_22a8.bin",
+               .board = "cht-bsw",
+               .pdata = &chv_platform_data
+       },
+       {
+               .id = "10EC3270",
+               .drv_name = "cht-bsw-rt5645",
+               .fw_filename = "intel/fw_sst_22a8.bin",
+               .board = "cht-bsw",
+               .pdata = &chv_platform_data
+       },
+
+       {
+               .id = "193C9890",
+               .drv_name = "cht-bsw-max98090",
+               .fw_filename = "intel/fw_sst_22a8.bin",
+               .board = "cht-bsw",
+               .pdata = &chv_platform_data
+       },
+       {
+               .id = "DLGS7212",
+               .drv_name = "bytcht_da7213",
+               .fw_filename = "intel/fw_sst_22a8.bin",
+               .board = "bytcht_da7213",
+               .pdata = &chv_platform_data
+       },
+       {
+               .id = "DLGS7213",
+               .drv_name = "bytcht_da7213",
+               .fw_filename = "intel/fw_sst_22a8.bin",
+               .board = "bytcht_da7213",
+               .pdata = &chv_platform_data
+       },
+       {
+               .id = "ESSX8316",
+               .drv_name = "bytcht_es8316",
+               .fw_filename = "intel/fw_sst_22a8.bin",
+               .board = "bytcht_es8316",
+               .pdata = &chv_platform_data
+       },
        /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */
-       {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk,
-                                               &chv_platform_data },
-       {"10EC3276", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", NULL,
-                                               &chv_platform_data },
+       {
+               .id = "10EC5640",
+               .drv_name = "bytcr_rt5640",
+               .fw_filename = "intel/fw_sst_22a8.bin",
+               .board = "bytcr_rt5640",
+               .machine_quirk = cht_quirk,
+               .pdata = &chv_platform_data
+       },
+       {
+               .id = "10EC3276",
+               .drv_name = "bytcr_rt5640",
+               .fw_filename = "intel/fw_sst_22a8.bin",
+               .board = "bytcr_rt5640",
+               .pdata = &chv_platform_data
+       },
        /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */
-       {"10EC5651", "bytcr_rt5651", "intel/fw_sst_22a8.bin", "bytcr_rt5651", NULL,
-                                               &chv_platform_data },
+       {
+               .id = "10EC5651",
+               .drv_name = "bytcr_rt5651",
+               .fw_filename = "intel/fw_sst_22a8.bin",
+               .board = "bytcr_rt5651",
+               .pdata = &chv_platform_data
+       },
 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH)
        /*
         * This is always last in the table so that it is selected only when
         * enabled explicitly and there is no codec-related information in SSDT
         */
-       {"808622A8", "bytcht_nocodec", "intel/fw_sst_22a8.bin", "bytcht_nocodec", NULL,
-                                               &chv_platform_data },
+       {
+               .id = "808622A8",
+               .drv_name = "bytcht_nocodec",
+               .fw_filename = "intel/fw_sst_22a8.bin",
+               .board = "bytcht_nocodec",
+               .pdata = &chv_platform_data
+       },
 #endif
        {},
 };
index 56896e09445df13f099956fd41852173ca6817cd..a5c5bc5732a2fc62c559fcf194827fce75da2bff 100644 (file)
@@ -11,7 +11,10 @@ snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
 snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o
 snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o
 snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o
+snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o
 snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o
+snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o
+snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o
 snd-soc-skl_rt286-objs := skl_rt286.o
 snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
 snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o
@@ -29,7 +32,10 @@ obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o
 obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o
+obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o
 obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o
+obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o
+obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o
 obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o
 obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o
 obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o
index 14d9693c1641b460159f9b13ba0f0e8298825e69..058b8ccedf02ed658305474531d5b2b32c3d0631 100644 (file)
@@ -16,6 +16,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/acpi.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/gpio/consumer.h>
@@ -120,6 +121,26 @@ static struct snd_soc_jack_gpio mic_jack_gpio = {
        .invert                 = 1,
 };
 
+/* GPIO indexes defined by ACPI */
+enum {
+       RT5677_GPIO_PLUG_DET            = 0,
+       RT5677_GPIO_MIC_PRESENT_L       = 1,
+       RT5677_GPIO_HOTWORD_DET_L       = 2,
+       RT5677_GPIO_DSP_INT             = 3,
+       RT5677_GPIO_HP_AMP_SHDN_L       = 4,
+};
+
+static const struct acpi_gpio_params plug_det_gpio = { RT5677_GPIO_PLUG_DET, 0, false };
+static const struct acpi_gpio_params mic_present_gpio = { RT5677_GPIO_MIC_PRESENT_L, 0, false };
+static const struct acpi_gpio_params headphone_enable_gpio = { RT5677_GPIO_HP_AMP_SHDN_L, 0, false };
+
+static const struct acpi_gpio_mapping bdw_rt5677_gpios[] = {
+       { "plug-det-gpios", &plug_det_gpio, 1 },
+       { "mic-present-gpios", &mic_present_gpio, 1 },
+       { "headphone-enable-gpios", &headphone_enable_gpio, 1 },
+       { NULL },
+};
+
 static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
                        struct snd_pcm_hw_params *params)
 {
@@ -184,6 +205,11 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd)
                        snd_soc_card_get_drvdata(rtd->card);
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       int ret;
+
+       ret = devm_acpi_dev_add_driver_gpios(codec->dev, bdw_rt5677_gpios);
+       if (ret)
+               dev_warn(codec->dev, "Failed to add driver gpios\n");
 
        /* Enable codec ASRC function for Stereo DAC/Stereo1 ADC/DMIC/I2S1.
         * The ASRC clock source is clk_i2s1_asrc.
index 1866e31b6c29e9912d13d173856eb34456fba06b..ce35ec7884d1e59873e184d3dd8f5bf0711806a6 100644 (file)
@@ -242,31 +242,31 @@ static int broxton_da7219_fe_init(struct snd_soc_pcm_runtime *rtd)
        return 0;
 }
 
-static unsigned int rates[] = {
+static const unsigned int rates[] = {
        48000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_rates = {
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
        .count = ARRAY_SIZE(rates),
        .list  = rates,
        .mask = 0,
 };
 
-static unsigned int channels[] = {
+static const unsigned int channels[] = {
        DUAL_CHANNEL,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_channels = {
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
        .count = ARRAY_SIZE(channels),
        .list = channels,
        .mask = 0,
 };
 
-static unsigned int channels_quad[] = {
+static const unsigned int channels_quad[] = {
        QUAD_CHANNEL,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_channels_quad = {
+static const struct snd_pcm_hw_constraint_list constraints_channels_quad = {
        .count = ARRAY_SIZE(channels_quad),
        .list = channels_quad,
        .mask = 0,
index 1a68d043c803331afeb4c8acabacb3844816e02e..0c3a3cbcb884c080c24275551f5ee6d2e329ad98 100644 (file)
@@ -207,11 +207,11 @@ static const struct snd_soc_ops broxton_rt298_ops = {
        .hw_params = broxton_rt298_hw_params,
 };
 
-static unsigned int rates[] = {
+static const unsigned int rates[] = {
        48000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_rates = {
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
        .count = ARRAY_SIZE(rates),
        .list  = rates,
        .mask = 0,
@@ -222,19 +222,16 @@ static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
 {
        struct snd_interval *channels = hw_param_interval(params,
                                                SNDRV_PCM_HW_PARAM_CHANNELS);
-       if (params_channels(params) == 2)
-               channels->min = channels->max = 2;
-       else
-               channels->min = channels->max = 4;
+       channels->min = channels->max = 4;
 
        return 0;
 }
 
-static unsigned int channels_dmic[] = {
-       2, 4,
+static const unsigned int channels_dmic[] = {
+       1, 2, 3, 4,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
+static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
        .count = ARRAY_SIZE(channels_dmic),
        .list = channels_dmic,
        .mask = 0,
@@ -256,11 +253,11 @@ static const struct snd_soc_ops broxton_dmic_ops = {
        .startup = broxton_dmic_startup,
 };
 
-static unsigned int channels[] = {
+static const unsigned int channels[] = {
        2,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_channels = {
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
        .count = ARRAY_SIZE(channels),
        .list = channels,
        .mask = 0,
index d9f81b8d915dfc268ac53e366d060fd86e5edea8..047be7fa0ce9f86a1462063b18184a8d984e1404 100644 (file)
@@ -67,20 +67,27 @@ static struct snd_soc_jack_pin hs_jack_pins[] = {
 
 static struct snd_soc_jack_gpio hs_jack_gpios[] = {
        {
-               .name           = "hp-gpio",
-               .idx            = 0,
+               .name           = "hp",
                .report         = SND_JACK_HEADPHONE | SND_JACK_LINEOUT,
                .debounce_time  = 200,
        },
        {
-               .name           = "mic-gpio",
-               .idx            = 1,
+               .name           = "mic",
                .invert         = 1,
                .report         = SND_JACK_MICROPHONE,
                .debounce_time  = 200,
        },
 };
 
+static const struct acpi_gpio_params hp_gpios = { 0, 0, false };
+static const struct acpi_gpio_params mic_gpios = { 1, 0, false };
+
+static const struct acpi_gpio_mapping acpi_byt_max98090_gpios[] = {
+       { "hp-gpios", &hp_gpios, 1 },
+       { "mic-gpios", &mic_gpios, 1 },
+       {},
+};
+
 static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime)
 {
        int ret;
@@ -140,8 +147,9 @@ static struct snd_soc_card byt_max98090_card = {
 
 static int byt_max98090_probe(struct platform_device *pdev)
 {
-       int ret_val = 0;
+       struct device *dev = &pdev->dev;
        struct byt_max98090_private *priv;
+       int ret_val;
 
        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
        if (!priv) {
@@ -149,6 +157,10 @@ static int byt_max98090_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       ret_val = devm_acpi_dev_add_driver_gpios(dev->parent, acpi_byt_max98090_gpios);
+       if (ret_val)
+               dev_dbg(dev, "Unable to add GPIO mapping table\n");
+
        byt_max98090_card.dev = &pdev->dev;
        snd_soc_card_set_drvdata(&byt_max98090_card, priv);
        ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_max98090_card);
@@ -158,7 +170,7 @@ static int byt_max98090_probe(struct platform_device *pdev)
                return ret_val;
        }
 
-       return ret_val;
+       return 0;
 }
 
 static int byt_max98090_remove(struct platform_device *pdev)
diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c
new file mode 100644 (file)
index 0000000..5263546
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ *  bytcht_es8316.c - ASoc Machine driver for Intel Baytrail/Cherrytrail
+ *                    platforms with Everest ES8316 SoC
+ *
+ *  Copyright (C) 2017 Endless Mobile, Inc.
+ *  Authors: David Yang <yangxiaohua@everest-semi.com>,
+ *           Daniel Drake <drake@endlessm.com>
+ *
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  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/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <asm/platform_sst_audio.h>
+#include <linux/clk.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../atom/sst-atom-controls.h"
+#include "../common/sst-acpi.h"
+#include "../common/sst-dsp.h"
+
+struct byt_cht_es8316_private {
+       struct clk *mclk;
+};
+
+#define CODEC_DAI1     "ES8316 HiFi"
+
+static inline struct snd_soc_dai *get_codec_dai(struct snd_soc_card *card)
+{
+       struct snd_soc_pcm_runtime *rtd;
+
+       list_for_each_entry(rtd, &card->rtd_list, list) {
+               if (!strncmp(rtd->codec_dai->name, CODEC_DAI1,
+                            strlen(CODEC_DAI1)))
+                       return rtd->codec_dai;
+       }
+       return NULL;
+}
+
+static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+
+       /*
+        * The codec supports two analog microphone inputs. I have only
+        * tested MIC1. A DMIC route could also potentially be added
+        * if such functionality is found on another platform.
+        */
+       SND_SOC_DAPM_MIC("Microphone 1", NULL),
+       SND_SOC_DAPM_MIC("Microphone 2", NULL),
+};
+
+static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = {
+       {"MIC1", NULL, "Microphone 1"},
+       {"MIC2", NULL, "Microphone 2"},
+
+       {"Headphone", NULL, "HPOL"},
+       {"Headphone", NULL, "HPOR"},
+
+       {"Playback", NULL, "ssp2 Tx"},
+       {"ssp2 Tx", NULL, "codec_out0"},
+       {"ssp2 Tx", NULL, "codec_out1"},
+       {"codec_in0", NULL, "ssp2 Rx" },
+       {"codec_in1", NULL, "ssp2 Rx" },
+       {"ssp2 Rx", NULL, "Capture"},
+};
+
+static const struct snd_kcontrol_new byt_cht_es8316_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Microphone 1"),
+       SOC_DAPM_PIN_SWITCH("Microphone 2"),
+};
+
+static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime)
+{
+       struct snd_soc_card *card = runtime->card;
+       struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card);
+       int ret;
+
+       card->dapm.idle_bias_off = true;
+
+       /*
+        * The firmware might enable the clock at boot (this information
+        * may or may not be reflected in the enable clock register).
+        * To change the rate we must disable the clock first to cover these
+        * cases. Due to common clock framework restrictions that do not allow
+        * to disable a clock that has not been enabled, we need to enable
+        * the clock first.
+        */
+       ret = clk_prepare_enable(priv->mclk);
+       if (!ret)
+               clk_disable_unprepare(priv->mclk);
+
+       ret = clk_set_rate(priv->mclk, 19200000);
+       if (ret)
+               dev_err(card->dev, "unable to set MCLK rate\n");
+
+       ret = clk_prepare_enable(priv->mclk);
+       if (ret)
+               dev_err(card->dev, "unable to enable MCLK\n");
+
+       ret = snd_soc_dai_set_sysclk(runtime->codec_dai, 0, 19200000,
+                                    SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               dev_err(card->dev, "can't set codec clock %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_pcm_stream byt_cht_es8316_dai_params = {
+       .formats = SNDRV_PCM_FMTBIT_S24_LE,
+       .rate_min = 48000,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 2,
+};
+
+static int byt_cht_es8316_codec_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);
+       int ret;
+
+       /* The DSP will covert the FE rate to 48k, stereo */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       /* set SSP2 to 24-bit */
+       params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+
+       /*
+        * Default mode for SSP configuration is TDM 4 slot, override config
+        * with explicit setting to I2S 2ch 24-bit. The word length is set with
+        * dai_set_tdm_slot() since there is no other API exposed
+        */
+       ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
+                               SND_SOC_DAIFMT_I2S     |
+                               SND_SOC_DAIFMT_NB_NF   |
+                               SND_SOC_DAIFMT_CBS_CFS
+               );
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24);
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int byt_cht_es8316_aif1_startup(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_hw_constraint_single(substream->runtime,
+                       SNDRV_PCM_HW_PARAM_RATE, 48000);
+}
+
+static const struct snd_soc_ops byt_cht_es8316_aif1_ops = {
+       .startup = byt_cht_es8316_aif1_startup,
+};
+
+static struct snd_soc_dai_link byt_cht_es8316_dais[] = {
+       [MERR_DPCM_AUDIO] = {
+               .name = "Audio Port",
+               .stream_name = "Audio",
+               .cpu_dai_name = "media-cpu-dai",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+               .platform_name = "sst-mfld-platform",
+               .nonatomic = true,
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ops = &byt_cht_es8316_aif1_ops,
+       },
+
+       [MERR_DPCM_DEEP_BUFFER] = {
+               .name = "Deep-Buffer Audio Port",
+               .stream_name = "Deep-Buffer Audio",
+               .cpu_dai_name = "deepbuffer-cpu-dai",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+               .platform_name = "sst-mfld-platform",
+               .nonatomic = true,
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .ops = &byt_cht_es8316_aif1_ops,
+       },
+
+       [MERR_DPCM_COMPR] = {
+               .name = "Compressed Port",
+               .stream_name = "Compress",
+               .cpu_dai_name = "compress-cpu-dai",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+               .platform_name = "sst-mfld-platform",
+       },
+
+               /* back ends */
+       {
+               /* Only SSP2 has been tested here, so BYT-CR platforms that
+                * require SSP0 will not work.
+                */
+               .name = "SSP2-Codec",
+               .id = 1,
+               .cpu_dai_name = "ssp2-port",
+               .platform_name = "sst-mfld-platform",
+               .no_pcm = 1,
+               .codec_dai_name = "ES8316 HiFi",
+               .codec_name = "i2c-ESSX8316:00",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                                               | SND_SOC_DAIFMT_CBS_CFS,
+               .be_hw_params_fixup = byt_cht_es8316_codec_fixup,
+               .nonatomic = true,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .init = byt_cht_es8316_init,
+       },
+};
+
+
+/* SoC card */
+static struct snd_soc_card byt_cht_es8316_card = {
+       .name = "bytcht-es8316",
+       .owner = THIS_MODULE,
+       .dai_link = byt_cht_es8316_dais,
+       .num_links = ARRAY_SIZE(byt_cht_es8316_dais),
+       .dapm_widgets = byt_cht_es8316_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(byt_cht_es8316_widgets),
+       .dapm_routes = byt_cht_es8316_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(byt_cht_es8316_audio_map),
+       .controls = byt_cht_es8316_controls,
+       .num_controls = ARRAY_SIZE(byt_cht_es8316_controls),
+       .fully_routed = true,
+};
+
+static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct byt_cht_es8316_private *priv;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
+       if (!priv)
+               return -ENOMEM;
+
+       /* register the soc card */
+       byt_cht_es8316_card.dev = &pdev->dev;
+       snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv);
+
+       priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
+       if (IS_ERR(priv->mclk)) {
+               ret = PTR_ERR(priv->mclk);
+               dev_err(&pdev->dev,
+                       "Failed to get MCLK from pmc_plt_clk_3: %d\n",
+                       ret);
+               return ret;
+       }
+
+       ret = devm_snd_soc_register_card(&pdev->dev, &byt_cht_es8316_card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret);
+               return ret;
+       }
+       platform_set_drvdata(pdev, &byt_cht_es8316_card);
+       return ret;
+}
+
+static struct platform_driver snd_byt_cht_es8316_mc_driver = {
+       .driver = {
+               .name = "bytcht_es8316",
+       },
+       .probe = snd_byt_cht_es8316_mc_probe,
+};
+
+module_platform_driver(snd_byt_cht_es8316_mc_driver);
+MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail Machine driver");
+MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bytcht_es8316");
index 89853eeaaf9dd4f20bdcd61acc10e43c3eb29839..1dd9441806fa31d02c7d3808a35d2d3e8fd304f1 100644 (file)
@@ -85,11 +85,11 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd,
        return 0;
 }
 
-static unsigned int rates_48000[] = {
+static const unsigned int rates_48000[] = {
        48000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_48000 = {
+static const struct snd_pcm_hw_constraint_list constraints_48000 = {
        .count = ARRAY_SIZE(rates_48000),
        .list  = rates_48000,
 };
index 8164bec63bf15b874da49a4406ae9f6124cd776c..4a3516b38c2c9727f7138054cee367ab5ede1205 100644 (file)
@@ -203,11 +203,11 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd,
        return 0;
 }
 
-static unsigned int rates_48000[] = {
+static const unsigned int rates_48000[] = {
        48000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_48000 = {
+static const struct snd_pcm_hw_constraint_list constraints_48000 = {
        .count = ARRAY_SIZE(rates_48000),
        .list  = rates_48000,
 };
index 742bc0d4e681646c969e4c9563decbb291843517..20755ecc7f9ea7e17d1fcdd5096f577929bb1957 100644 (file)
@@ -39,18 +39,6 @@ struct cht_mc_private {
        bool ts3a227e_present;
 };
 
-static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
-{
-       struct snd_soc_pcm_runtime *rtd;
-
-       list_for_each_entry(rtd, &card->rtd_list, list) {
-               if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
-                            strlen(CHT_CODEC_DAI)))
-                       return rtd->codec_dai;
-       }
-       return NULL;
-}
-
 static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
        SND_SOC_DAPM_HP("Headphone", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
index e4d46d4360d7e88cfdac008e9804bb7fdb310e6f..bc2a52de06a39729ac6aae83c38e08e822575445 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/clk.h>
+#include <asm/cpu_device_id.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #define CHT_PLAT_CLK_3_HZ      19200000
 #define CHT_CODEC_DAI  "rt5670-aif1"
 
-static struct snd_soc_jack cht_bsw_headset;
-static char cht_bsw_codec_name[16];
+struct cht_mc_private {
+       struct snd_soc_jack headset;
+       char codec_name[16];
+       struct clk *mclk;
+};
 
 /* Headset jack detection DAPM pins */
 static struct snd_soc_jack_pin cht_bsw_headset_pins[] = {
@@ -64,6 +69,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
        struct snd_soc_dapm_context *dapm = w->dapm;
        struct snd_soc_card *card = dapm->card;
        struct snd_soc_dai *codec_dai;
+       struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
        int ret;
 
        codec_dai = cht_get_codec_dai(card);
@@ -73,6 +79,15 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
        }
 
        if (SND_SOC_DAPM_EVENT_ON(event)) {
+               if (ctx->mclk) {
+                       ret = clk_prepare_enable(ctx->mclk);
+                       if (ret < 0) {
+                               dev_err(card->dev,
+                                       "could not configure MCLK state");
+                               return ret;
+                       }
+               }
+
                /* set codec PLL source to the 19.2MHz platform clock (MCLK) */
                ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK,
                                CHT_PLAT_CLK_3_HZ, 48000 * 512);
@@ -96,6 +111,9 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
                 */
                snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK,
                                       48000 * 512, SND_SOC_CLOCK_IN);
+
+               if (ctx->mclk)
+                       clk_disable_unprepare(ctx->mclk);
        }
        return 0;
 }
@@ -171,6 +189,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
        int ret;
        struct snd_soc_dai *codec_dai = runtime->codec_dai;
        struct snd_soc_codec *codec = codec_dai->codec;
+       struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
 
        /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
        ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
@@ -194,13 +213,37 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
                                RT5670_CLK_SEL_I2S1_ASRC);
 
         ret = snd_soc_card_jack_new(runtime->card, "Headset",
-                SND_JACK_HEADSET | SND_JACK_BTN_0 |
-                SND_JACK_BTN_1 | SND_JACK_BTN_2, &cht_bsw_headset,
-                cht_bsw_headset_pins, ARRAY_SIZE(cht_bsw_headset_pins));
+                                   SND_JACK_HEADSET | SND_JACK_BTN_0 |
+                                   SND_JACK_BTN_1 | SND_JACK_BTN_2,
+                                   &ctx->headset,
+                                   cht_bsw_headset_pins,
+                                   ARRAY_SIZE(cht_bsw_headset_pins));
         if (ret)
                 return ret;
 
-       rt5670_set_jack_detect(codec, &cht_bsw_headset);
+       rt5670_set_jack_detect(codec, &ctx->headset);
+       if (ctx->mclk) {
+               /*
+                * The firmware might enable the clock at
+                * boot (this information may or may not
+                * be reflected in the enable clock register).
+                * To change the rate we must disable the clock
+                * first to cover these cases. Due to common
+                * clock framework restrictions that do not allow
+                * to disable a clock that has not been enabled,
+                * we need to enable the clock first.
+                */
+               ret = clk_prepare_enable(ctx->mclk);
+               if (!ret)
+                       clk_disable_unprepare(ctx->mclk);
+
+               ret = clk_set_rate(ctx->mclk, CHT_PLAT_CLK_3_HZ);
+
+               if (ret) {
+                       dev_err(runtime->dev, "unable to set MCLK rate\n");
+                       return ret;
+               }
+       }
        return 0;
 }
 
@@ -341,34 +384,62 @@ static struct snd_soc_card snd_soc_card_cht = {
        .resume_post = cht_resume_post,
 };
 
+static bool is_valleyview(void)
+{
+       static const struct x86_cpu_id cpu_ids[] = {
+               { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */
+               {}
+       };
+
+       if (!x86_match_cpu(cpu_ids))
+               return false;
+       return true;
+}
+
 #define RT5672_I2C_DEFAULT     "i2c-10EC5670:00"
 
 static int snd_cht_mc_probe(struct platform_device *pdev)
 {
        int ret_val = 0;
+       struct cht_mc_private *drv;
        struct sst_acpi_mach *mach = pdev->dev.platform_data;
        const char *i2c_name;
        int i;
 
-       strcpy(cht_bsw_codec_name, RT5672_I2C_DEFAULT);
+       drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
+       if (!drv)
+               return -ENOMEM;
+
+       strcpy(drv->codec_name, RT5672_I2C_DEFAULT);
 
        /* fixup codec name based on HID */
        if (mach) {
                i2c_name = sst_acpi_find_name_from_hid(mach->id);
                if (i2c_name) {
-                       snprintf(cht_bsw_codec_name, sizeof(cht_bsw_codec_name),
+                       snprintf(drv->codec_name, sizeof(drv->codec_name),
                                 "i2c-%s", i2c_name);
                        for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) {
                                if (!strcmp(cht_dailink[i].codec_name,
                                            RT5672_I2C_DEFAULT)) {
                                        cht_dailink[i].codec_name =
-                                               cht_bsw_codec_name;
+                                               drv->codec_name;
                                        break;
                                }
                        }
                }
        }
 
+       if (is_valleyview()) {
+               drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
+               if (IS_ERR(drv->mclk)) {
+                       dev_err(&pdev->dev,
+                               "Failed to get MCLK from pmc_plt_clk_3: %ld\n",
+                               PTR_ERR(drv->mclk));
+                       return PTR_ERR(drv->mclk);
+               }
+       }
+       snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
+
        /* register the soc card */
        snd_soc_card_cht.dev = &pdev->dev;
        ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c
new file mode 100644 (file)
index 0000000..f9ba977
--- /dev/null
@@ -0,0 +1,687 @@
+/*
+ * Intel Kabylake I2S Machine Driver with MAXIM98927
+ * and RT5663 Codecs
+ *
+ * Copyright (C) 2017, Intel Corporation. All rights reserved.
+ *
+ * Modified from:
+ *   Intel Skylake I2S Machine driver
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 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/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../../codecs/rt5663.h"
+#include "../../codecs/hdac_hdmi.h"
+#include "../skylake/skl.h"
+
+#define KBL_REALTEK_CODEC_DAI "rt5663-aif"
+#define KBL_MAXIM_CODEC_DAI "max98927-aif1"
+#define DMIC_CH(p) p->list[p->count-1]
+#define MAXIM_DEV0_NAME "i2c-MX98927:00"
+#define MAXIM_DEV1_NAME "i2c-MX98927:01"
+
+static struct snd_soc_card kabylake_audio_card;
+static const struct snd_pcm_hw_constraint_list *dmic_constraints;
+static struct snd_soc_jack skylake_hdmi[3];
+
+struct kbl_hdmi_pcm {
+       struct list_head head;
+       struct snd_soc_dai *codec_dai;
+       int device;
+};
+
+struct kbl_rt5663_private {
+       struct snd_soc_jack kabylake_headset;
+       struct list_head hdmi_pcm_list;
+};
+
+enum {
+       KBL_DPCM_AUDIO_PB = 0,
+       KBL_DPCM_AUDIO_CP,
+       KBL_DPCM_AUDIO_REF_CP,
+       KBL_DPCM_AUDIO_DMIC_CP,
+       KBL_DPCM_AUDIO_HDMI1_PB,
+       KBL_DPCM_AUDIO_HDMI2_PB,
+       KBL_DPCM_AUDIO_HDMI3_PB,
+};
+
+static const struct snd_kcontrol_new kabylake_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Left Spk"),
+       SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
+static const struct snd_soc_dapm_widget kabylake_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_SPK("Left Spk", NULL),
+       SND_SOC_DAPM_SPK("Right Spk", NULL),
+       SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+       SND_SOC_DAPM_SPK("DP", NULL),
+       SND_SOC_DAPM_SPK("HDMI", NULL),
+
+};
+
+static const struct snd_soc_dapm_route kabylake_map[] = {
+       /* HP jack connectors - unknown if we have jack detection */
+       { "Headphone Jack", NULL, "HPOL" },
+       { "Headphone Jack", NULL, "HPOR" },
+
+       /* speaker */
+       { "Left Spk", NULL, "Left BE_OUT" },
+       { "Right Spk", NULL, "Right BE_OUT" },
+
+       /* other jacks */
+       { "IN1P", NULL, "Headset Mic" },
+       { "IN1N", NULL, "Headset Mic" },
+       { "DMic", NULL, "SoC DMIC" },
+
+       { "HDMI", NULL, "hif5 Output" },
+       { "DP", NULL, "hif6 Output" },
+
+       /* CODEC BE connections */
+       { "Left HiFi Playback", NULL, "ssp0 Tx" },
+       { "Right HiFi Playback", NULL, "ssp0 Tx" },
+       { "ssp0 Tx", NULL, "codec0_out" },
+
+       { "AIF Playback", NULL, "ssp1 Tx" },
+       { "ssp1 Tx", NULL, "codec1_out" },
+
+       { "codec0_in", NULL, "ssp1 Rx" },
+       { "ssp1 Rx", NULL, "AIF Capture" },
+
+       /* DMIC */
+       { "dmic01_hifi", NULL, "DMIC01 Rx" },
+       { "DMIC01 Rx", NULL, "DMIC AIF" },
+
+       { "hifi3", NULL, "iDisp3 Tx"},
+       { "iDisp3 Tx", NULL, "iDisp3_out"},
+       { "hifi2", NULL, "iDisp2 Tx"},
+       { "iDisp2 Tx", NULL, "iDisp2_out"},
+       { "hifi1", NULL, "iDisp1 Tx"},
+       { "iDisp1 Tx", NULL, "iDisp1_out"},
+};
+
+static struct snd_soc_codec_conf max98927_codec_conf[] = {
+       {
+               .dev_name = MAXIM_DEV0_NAME,
+               .name_prefix = "Right",
+       },
+       {
+               .dev_name = MAXIM_DEV1_NAME,
+               .name_prefix = "Left",
+       },
+};
+
+static struct snd_soc_dai_link_component max98927_codec_components[] = {
+       { /* Left */
+               .name = MAXIM_DEV0_NAME,
+               .dai_name = KBL_MAXIM_CODEC_DAI,
+       },
+       { /* Right */
+               .name = MAXIM_DEV1_NAME,
+               .dai_name = KBL_MAXIM_CODEC_DAI,
+       },
+};
+
+static int kabylake_rt5663_fe_init(struct snd_soc_pcm_runtime *rtd)
+{
+       int ret;
+       struct snd_soc_dapm_context *dapm;
+       struct snd_soc_component *component = rtd->cpu_dai->component;
+
+       dapm = snd_soc_component_get_dapm(component);
+       ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
+       if (ret) {
+               dev_err(rtd->dev, "Ref Cap ignore suspend failed %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+       int ret;
+       struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_codec *codec = rtd->codec;
+
+       /*
+        * Headset buttons map to the google Reference headset.
+        * These can be configured by userspace.
+        */
+       ret = snd_soc_card_jack_new(&kabylake_audio_card, "Headset Jack",
+                       SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                       SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset,
+                       NULL, 0);
+       if (ret) {
+               dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
+               return ret;
+       }
+
+       rt5663_set_jack_detect(codec, &ctx->kabylake_headset);
+       ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
+       if (ret) {
+               dev_err(rtd->dev, "SoC DMIC ignore suspend failed %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_dai *dai = rtd->codec_dai;
+       struct kbl_hdmi_pcm *pcm;
+
+       pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
+       if (!pcm)
+               return -ENOMEM;
+
+       pcm->device = KBL_DPCM_AUDIO_HDMI1_PB;
+       pcm->codec_dai = dai;
+
+       list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+
+       return 0;
+}
+
+static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_dai *dai = rtd->codec_dai;
+       struct kbl_hdmi_pcm *pcm;
+
+       pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
+       if (!pcm)
+               return -ENOMEM;
+
+       pcm->device = KBL_DPCM_AUDIO_HDMI2_PB;
+       pcm->codec_dai = dai;
+
+       list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+
+       return 0;
+}
+
+static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_dai *dai = rtd->codec_dai;
+       struct kbl_hdmi_pcm *pcm;
+
+       pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
+       if (!pcm)
+               return -ENOMEM;
+
+       pcm->device = KBL_DPCM_AUDIO_HDMI3_PB;
+       pcm->codec_dai = dai;
+
+       list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+
+       return 0;
+}
+
+static unsigned int rates[] = {
+       48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list  = rates,
+       .mask = 0,
+};
+
+static unsigned int channels[] = {
+       2,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_channels = {
+       .count = ARRAY_SIZE(channels),
+       .list = channels,
+       .mask = 0,
+};
+
+static int kbl_fe_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       /*
+        * On this platform for PCM device we support,
+        * 48Khz
+        * stereo
+        * 16 bit audio
+        */
+
+       runtime->hw.channels_max = 2;
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                          &constraints_channels);
+
+       runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+       snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
+       snd_pcm_hw_constraint_list(runtime, 0,
+                               SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+
+       return 0;
+}
+
+static const struct snd_soc_ops kabylake_rt5663_fe_ops = {
+       .startup = kbl_fe_startup,
+};
+
+static int kabylake_ssp_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);
+       struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+       /* The ADSP will convert the FE rate to 48k, stereo */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+       /* set SSP1 to 24 bit */
+       snd_mask_none(fmt);
+       snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+       return 0;
+}
+
+static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai,
+                       RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
+       /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */
+       rt5663_sel_asrc_clk_src(codec_dai->codec, RT5663_DA_STEREO_FILTER, 1);
+
+       if (ret < 0)
+               dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+       return ret;
+}
+
+static struct snd_soc_ops kabylake_rt5663_ops = {
+       .hw_params = kabylake_rt5663_hw_params,
+};
+
+static int kabylake_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);
+
+       if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2)
+               channels->min = channels->max = 2;
+       else
+               channels->min = channels->max = 4;
+
+       return 0;
+}
+
+static unsigned int channels_dmic[] = {
+       2, 4,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
+       .count = ARRAY_SIZE(channels_dmic),
+       .list = channels_dmic,
+       .mask = 0,
+};
+
+static const unsigned int dmic_2ch[] = {
+       2,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = {
+       .count = ARRAY_SIZE(dmic_2ch),
+       .list = dmic_2ch,
+       .mask = 0,
+};
+
+static int kabylake_dmic_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       runtime->hw.channels_max = DMIC_CH(dmic_constraints);
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                       dmic_constraints);
+
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+}
+
+static struct snd_soc_ops kabylake_dmic_ops = {
+       .startup = kabylake_dmic_startup,
+};
+
+static unsigned int rates_16000[] = {
+       16000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_16000 = {
+       .count = ARRAY_SIZE(rates_16000),
+       .list  = rates_16000,
+};
+
+static const unsigned int ch_mono[] = {
+       1,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_refcap = {
+       .count = ARRAY_SIZE(ch_mono),
+       .list  = ch_mono,
+};
+
+static int kabylake_refcap_startup(struct snd_pcm_substream *substream)
+{
+       substream->runtime->hw.channels_max = 1;
+       snd_pcm_hw_constraint_list(substream->runtime, 0,
+                                       SNDRV_PCM_HW_PARAM_CHANNELS,
+                                       &constraints_refcap);
+
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                               SNDRV_PCM_HW_PARAM_RATE,
+                               &constraints_16000);
+}
+
+static struct snd_soc_ops skylaye_refcap_ops = {
+       .startup = kabylake_refcap_startup,
+};
+
+/* kabylake digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link kabylake_dais[] = {
+       /* Front End DAI links */
+       [KBL_DPCM_AUDIO_PB] = {
+               .name = "Kbl Audio Port",
+               .stream_name = "Audio",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "0000:00:1f.3",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .nonatomic = 1,
+               .init = kabylake_rt5663_fe_init,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               .ops = &kabylake_rt5663_fe_ops,
+       },
+       [KBL_DPCM_AUDIO_CP] = {
+               .name = "Kbl Audio Capture Port",
+               .stream_name = "Audio Record",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "0000:00:1f.3",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .nonatomic = 1,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_capture = 1,
+               .ops = &kabylake_rt5663_fe_ops,
+       },
+       [KBL_DPCM_AUDIO_REF_CP] = {
+               .name = "Kbl Audio Reference cap",
+               .stream_name = "Wake on Voice",
+               .cpu_dai_name = "Reference Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .init = NULL,
+               .dpcm_capture = 1,
+               .nonatomic = 1,
+               .dynamic = 1,
+               .ops = &skylaye_refcap_ops,
+       },
+       [KBL_DPCM_AUDIO_DMIC_CP] = {
+               .name = "Kbl Audio DMIC cap",
+               .stream_name = "dmiccap",
+               .cpu_dai_name = "DMIC Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .init = NULL,
+               .dpcm_capture = 1,
+               .nonatomic = 1,
+               .dynamic = 1,
+               .ops = &kabylake_dmic_ops,
+       },
+       [KBL_DPCM_AUDIO_HDMI1_PB] = {
+               .name = "Kbl HDMI Port1",
+               .stream_name = "Hdmi1",
+               .cpu_dai_name = "HDMI1 Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .init = NULL,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+       [KBL_DPCM_AUDIO_HDMI2_PB] = {
+               .name = "Kbl HDMI Port2",
+               .stream_name = "Hdmi2",
+               .cpu_dai_name = "HDMI2 Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .init = NULL,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+       [KBL_DPCM_AUDIO_HDMI3_PB] = {
+               .name = "Kbl HDMI Port3",
+               .stream_name = "Hdmi3",
+               .cpu_dai_name = "HDMI3 Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               .init = NULL,
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+
+       /* Back End DAI links */
+       {
+               /* SSP0 - Codec */
+               .name = "SSP0-Codec",
+               .id = 0,
+               .cpu_dai_name = "SSP0 Pin",
+               .platform_name = "0000:00:1f.3",
+               .no_pcm = 1,
+               .codecs = max98927_codec_components,
+               .num_codecs = ARRAY_SIZE(max98927_codec_components),
+               .dai_fmt = SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = kabylake_ssp_fixup,
+               .dpcm_playback = 1,
+       },
+       {
+               /* SSP1 - Codec */
+               .name = "SSP1-Codec",
+               .id = 1,
+               .cpu_dai_name = "SSP1 Pin",
+               .platform_name = "0000:00:1f.3",
+               .no_pcm = 1,
+               .codec_name = "i2c-10EC5663:00",
+               .codec_dai_name = KBL_REALTEK_CODEC_DAI,
+               .init = kabylake_rt5663_codec_init,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = kabylake_ssp_fixup,
+               .ops = &kabylake_rt5663_ops,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+       },
+       {
+               .name = "dmic01",
+               .id = 2,
+               .cpu_dai_name = "DMIC01 Pin",
+               .codec_name = "dmic-codec",
+               .codec_dai_name = "dmic-hifi",
+               .platform_name = "0000:00:1f.3",
+               .be_hw_params_fixup = kabylake_dmic_fixup,
+               .ignore_suspend = 1,
+               .dpcm_capture = 1,
+               .no_pcm = 1,
+       },
+       {
+               .name = "iDisp1",
+               .id = 3,
+               .cpu_dai_name = "iDisp1 Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi1",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .init = kabylake_hdmi1_init,
+               .no_pcm = 1,
+       },
+       {
+               .name = "iDisp2",
+               .id = 4,
+               .cpu_dai_name = "iDisp2 Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi2",
+               .platform_name = "0000:00:1f.3",
+               .init = kabylake_hdmi2_init,
+               .dpcm_playback = 1,
+               .no_pcm = 1,
+       },
+       {
+               .name = "iDisp3",
+               .id = 5,
+               .cpu_dai_name = "iDisp3 Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi3",
+               .platform_name = "0000:00:1f.3",
+               .init = kabylake_hdmi3_init,
+               .dpcm_playback = 1,
+               .no_pcm = 1,
+       },
+};
+
+#define NAME_SIZE      32
+static int kabylake_card_late_probe(struct snd_soc_card *card)
+{
+       struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(card);
+       struct kbl_hdmi_pcm *pcm;
+       int err, i = 0;
+       char jack_name[NAME_SIZE];
+
+       list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+               snprintf(jack_name, sizeof(jack_name),
+                       "HDMI/DP, pcm=%d Jack", pcm->device);
+               err = snd_soc_card_jack_new(card, jack_name,
+                                       SND_JACK_AVOUT, &skylake_hdmi[i],
+                                       NULL, 0);
+
+               if (err)
+                       return err;
+
+               err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
+                                               &skylake_hdmi[i]);
+               if (err < 0)
+                       return err;
+
+               i++;
+       }
+
+       return 0;
+}
+
+/* kabylake audio machine driver for SPT + RT5663 */
+static struct snd_soc_card kabylake_audio_card = {
+       .name = "kblrt5663max",
+       .owner = THIS_MODULE,
+       .dai_link = kabylake_dais,
+       .num_links = ARRAY_SIZE(kabylake_dais),
+       .controls = kabylake_controls,
+       .num_controls = ARRAY_SIZE(kabylake_controls),
+       .dapm_widgets = kabylake_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets),
+       .dapm_routes = kabylake_map,
+       .num_dapm_routes = ARRAY_SIZE(kabylake_map),
+       .codec_conf = max98927_codec_conf,
+       .num_configs = ARRAY_SIZE(max98927_codec_conf),
+       .fully_routed = true,
+       .late_probe = kabylake_card_late_probe,
+};
+
+static int kabylake_audio_probe(struct platform_device *pdev)
+{
+       struct kbl_rt5663_private *ctx;
+       struct skl_machine_pdata *pdata;
+
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+       if (!ctx)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+
+       kabylake_audio_card.dev = &pdev->dev;
+       snd_soc_card_set_drvdata(&kabylake_audio_card, ctx);
+
+       pdata = dev_get_drvdata(&pdev->dev);
+       if (pdata)
+               dmic_constraints = pdata->dmic_num == 2 ?
+                       &constraints_dmic_2ch : &constraints_dmic_channels;
+
+       return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card);
+}
+
+static const struct platform_device_id kbl_board_ids[] = {
+       { .name = "kbl_rt5663_m98927" },
+       { }
+};
+
+static struct platform_driver kabylake_audio = {
+       .probe = kabylake_audio_probe,
+       .driver = {
+               .name = "kbl_rt5663_m98927",
+               .pm = &snd_soc_pm_ops,
+       },
+       .id_table = kbl_board_ids,
+};
+
+module_platform_driver(kabylake_audio)
+
+/* Module information */
+MODULE_DESCRIPTION("Audio Machine driver-RT5663 & MAX98927 in I2S mode");
+MODULE_AUTHOR("Naveen M <naveen.m@intel.com>");
+MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:kbl_rt5663_m98927");
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
new file mode 100644 (file)
index 0000000..3fe4a08
--- /dev/null
@@ -0,0 +1,640 @@
+/*
+ * Intel Kabylake I2S Machine Driver with MAXIM98927
+ * RT5514 and RT5663 Codecs
+ *
+ * Copyright (C) 2017, Intel Corporation. All rights reserved.
+ *
+ * Modified from:
+ *   Intel Kabylake I2S Machine driver supporting MAXIM98927 and
+ *   RT5663 codecs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 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/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../../codecs/rt5514.h"
+#include "../../codecs/rt5663.h"
+#include "../../codecs/hdac_hdmi.h"
+#include "../skylake/skl.h"
+
+#define KBL_REALTEK_CODEC_DAI "rt5663-aif"
+#define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1"
+#define KBL_MAXIM_CODEC_DAI "max98927-aif1"
+#define MAXIM_DEV0_NAME "i2c-MX98927:00"
+#define MAXIM_DEV1_NAME "i2c-MX98927:01"
+#define RT5514_DEV_NAME "i2c-10EC5514:00"
+#define RT5663_DEV_NAME "i2c-10EC5663:00"
+#define RT5514_AIF1_BCLK_FREQ (48000 * 8 * 16)
+#define RT5514_AIF1_SYSCLK_FREQ 12288000
+#define NAME_SIZE 32
+
+#define DMIC_CH(p) p->list[p->count-1]
+
+
+static struct snd_soc_card kabylake_audio_card;
+static const struct snd_pcm_hw_constraint_list *dmic_constraints;
+
+struct kbl_hdmi_pcm {
+       struct list_head head;
+       struct snd_soc_dai *codec_dai;
+       int device;
+};
+
+struct kbl_codec_private {
+       struct snd_soc_jack kabylake_headset;
+       struct list_head hdmi_pcm_list;
+       struct snd_soc_jack kabylake_hdmi[2];
+};
+
+enum {
+       KBL_DPCM_AUDIO_PB = 0,
+       KBL_DPCM_AUDIO_CP,
+       KBL_DPCM_AUDIO_DMIC_CP,
+       KBL_DPCM_AUDIO_HDMI1_PB,
+       KBL_DPCM_AUDIO_HDMI2_PB,
+};
+
+static const struct snd_kcontrol_new kabylake_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Left Spk"),
+       SOC_DAPM_PIN_SWITCH("Right Spk"),
+       SOC_DAPM_PIN_SWITCH("DMIC"),
+};
+
+static const struct snd_soc_dapm_widget kabylake_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_SPK("Left Spk", NULL),
+       SND_SOC_DAPM_SPK("Right Spk", NULL),
+       SND_SOC_DAPM_MIC("DMIC", NULL),
+       SND_SOC_DAPM_SPK("DP", NULL),
+       SND_SOC_DAPM_SPK("HDMI", NULL),
+
+};
+
+static const struct snd_soc_dapm_route kabylake_map[] = {
+       /* Headphones */
+       { "Headphone Jack", NULL, "HPOL" },
+       { "Headphone Jack", NULL, "HPOR" },
+
+       /* speaker */
+       { "Left Spk", NULL, "Left BE_OUT" },
+       { "Right Spk", NULL, "Right BE_OUT" },
+
+       /* other jacks */
+       { "IN1P", NULL, "Headset Mic" },
+       { "IN1N", NULL, "Headset Mic" },
+
+       { "HDMI", NULL, "hif5 Output" },
+       { "DP", NULL, "hif6 Output" },
+
+       /* CODEC BE connections */
+       { "Left HiFi Playback", NULL, "ssp0 Tx" },
+       { "Right HiFi Playback", NULL, "ssp0 Tx" },
+       { "ssp0 Tx", NULL, "codec0_out" },
+
+       { "AIF Playback", NULL, "ssp1 Tx" },
+       { "ssp1 Tx", NULL, "codec1_out" },
+
+       { "codec0_in", NULL, "ssp1 Rx" },
+       { "ssp1 Rx", NULL, "AIF Capture" },
+
+       { "codec1_in", NULL, "ssp0 Rx" },
+       { "ssp0 Rx", NULL, "AIF1 Capture" },
+
+       /* DMIC */
+       { "DMIC1L", NULL, "DMIC" },
+       { "DMIC1R", NULL, "DMIC" },
+       { "DMIC2L", NULL, "DMIC" },
+       { "DMIC2R", NULL, "DMIC" },
+
+       { "hifi2", NULL, "iDisp2 Tx" },
+       { "iDisp2 Tx", NULL, "iDisp2_out" },
+       { "hifi1", NULL, "iDisp1 Tx" },
+       { "iDisp1 Tx", NULL, "iDisp1_out" },
+};
+
+static struct snd_soc_codec_conf max98927_codec_conf[] = {
+       {
+               .dev_name = MAXIM_DEV0_NAME,
+               .name_prefix = "Right",
+       },
+       {
+               .dev_name = MAXIM_DEV1_NAME,
+               .name_prefix = "Left",
+       },
+};
+
+static struct snd_soc_dai_link_component ssp0_codec_components[] = {
+       { /* Left */
+               .name = MAXIM_DEV0_NAME,
+               .dai_name = KBL_MAXIM_CODEC_DAI,
+       },
+       { /* Right */
+               .name = MAXIM_DEV1_NAME,
+               .dai_name = KBL_MAXIM_CODEC_DAI,
+       },
+       { /*dmic */
+               .name = RT5514_DEV_NAME,
+               .dai_name = KBL_REALTEK_DMIC_CODEC_DAI,
+       },
+};
+
+static int kabylake_rt5663_fe_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dapm_context *dapm;
+       struct snd_soc_component *component = rtd->cpu_dai->component;
+       int ret;
+
+       dapm = snd_soc_component_get_dapm(component);
+       ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
+       if (ret)
+               dev_err(rtd->dev, "Ref Cap -Ignore suspend failed = %d\n", ret);
+
+       return ret;
+}
+
+static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+       int ret;
+       struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_codec *codec = rtd->codec;
+
+       /*
+        * Headset buttons map to the google Reference headset.
+        * These can be configured by userspace.
+        */
+       ret = snd_soc_card_jack_new(&kabylake_audio_card, "Headset Jack",
+                       SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                       SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset,
+                       NULL, 0);
+       if (ret) {
+               dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
+               return ret;
+       }
+
+       rt5663_set_jack_detect(codec, &ctx->kabylake_headset);
+
+       ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "DMIC");
+       if (ret)
+               dev_err(rtd->dev, "DMIC - Ignore suspend failed = %d\n", ret);
+
+       return ret;
+}
+
+static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device)
+{
+       struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_dai *dai = rtd->codec_dai;
+       struct kbl_hdmi_pcm *pcm;
+
+       pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
+       if (!pcm)
+               return -ENOMEM;
+
+       pcm->device = device;
+       pcm->codec_dai = dai;
+
+       list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+
+       return 0;
+}
+
+static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
+{
+       return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB);
+}
+
+static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
+{
+       return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB);
+}
+
+static const unsigned int rates[] = {
+       48000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list  = rates,
+       .mask = 0,
+};
+
+static const unsigned int channels[] = {
+       2,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
+       .count = ARRAY_SIZE(channels),
+       .list = channels,
+       .mask = 0,
+};
+
+static int kbl_fe_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       /*
+        * On this platform for PCM device we support,
+        * 48Khz
+        * stereo
+        * 16 bit audio
+        */
+
+       runtime->hw.channels_max = 2;
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                          &constraints_channels);
+
+       runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+       snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
+       snd_pcm_hw_constraint_list(runtime, 0,
+                               SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+
+       return 0;
+}
+
+static const struct snd_soc_ops kabylake_rt5663_fe_ops = {
+       .startup = kbl_fe_startup,
+};
+
+static int kabylake_ssp_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);
+       struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+       struct snd_soc_dpcm *dpcm = container_of(
+                       params, struct snd_soc_dpcm, hw_params);
+       struct snd_soc_dai_link *fe_dai_link = dpcm->fe->dai_link;
+       struct snd_soc_dai_link *be_dai_link = dpcm->be->dai_link;
+
+       /*
+        * The ADSP will convert the FE rate to 48k, stereo, 24 bit
+        */
+       if (!strcmp(fe_dai_link->name, "Kbl Audio Port") ||
+           !strcmp(fe_dai_link->name, "Kbl Audio Capture Port")) {
+               rate->min = rate->max = 48000;
+               channels->min = channels->max = 2;
+               snd_mask_none(fmt);
+               snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+       } else if (!strcmp(fe_dai_link->name, "Kbl Audio DMIC cap")) {
+               if (params_channels(params) == 2 ||
+                               DMIC_CH(dmic_constraints) == 2)
+                       channels->min = channels->max = 2;
+               else
+                       channels->min = channels->max = 4;
+       }
+       /*
+        * The speaker on the SSP0 supports S16_LE and not S24_LE.
+        * thus changing the mask here
+        */
+       if (!strcmp(be_dai_link->name, "SSP0-Codec"))
+               snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE);
+
+       return 0;
+}
+
+static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */
+       rt5663_sel_asrc_clk_src(codec_dai->codec, RT5663_DA_STEREO_FILTER, 1);
+
+       ret = snd_soc_dai_set_sysclk(codec_dai,
+                       RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+       return ret;
+}
+
+static struct snd_soc_ops kabylake_rt5663_ops = {
+       .hw_params = kabylake_rt5663_hw_params,
+};
+
+static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       int ret = 0, j;
+
+       for (j = 0; j < rtd->num_codecs; j++) {
+               struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
+
+               if (!strcmp(codec_dai->component->name, RT5514_DEV_NAME)) {
+                       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0, 8, 16);
+                       if (ret < 0) {
+                               dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
+                               return ret;
+                       }
+
+                       ret = snd_soc_dai_set_pll(codec_dai, 0,
+                               RT5514_PLL1_S_BCLK, RT5514_AIF1_BCLK_FREQ,
+                                               RT5514_AIF1_SYSCLK_FREQ);
+                       if (ret < 0) {
+                               dev_err(rtd->dev, "set bclk err: %d\n", ret);
+                               return ret;
+                       }
+
+                       ret = snd_soc_dai_set_sysclk(codec_dai,
+                               RT5514_SCLK_S_PLL1, RT5514_AIF1_SYSCLK_FREQ,
+                                                       SND_SOC_CLOCK_IN);
+                       if (ret < 0) {
+                               dev_err(rtd->dev, "set sclk err: %d\n", ret);
+                               return ret;
+                       }
+               }
+               if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME) ||
+                       !strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) {
+                       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF0, 3, 8, 16);
+                       if (ret < 0) {
+                               dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
+                               return ret;
+                       }
+               }
+       }
+       return ret;
+}
+
+static struct snd_soc_ops kabylake_ssp0_ops = {
+       .hw_params = kabylake_ssp0_hw_params,
+};
+
+static const unsigned int channels_dmic[] = {
+       4,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
+       .count = ARRAY_SIZE(channels_dmic),
+       .list = channels_dmic,
+       .mask = 0,
+};
+
+static const unsigned int dmic_2ch[] = {
+       4,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = {
+       .count = ARRAY_SIZE(dmic_2ch),
+       .list = dmic_2ch,
+       .mask = 0,
+};
+
+static int kabylake_dmic_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       runtime->hw.channels_max = DMIC_CH(dmic_constraints);
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                       dmic_constraints);
+
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+}
+
+static struct snd_soc_ops kabylake_dmic_ops = {
+       .startup = kabylake_dmic_startup,
+};
+
+/* kabylake digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link kabylake_dais[] = {
+       /* Front End DAI links */
+       [KBL_DPCM_AUDIO_PB] = {
+               .name = "Kbl Audio Port",
+               .stream_name = "Audio",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "0000:00:1f.3",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .nonatomic = 1,
+               .init = kabylake_rt5663_fe_init,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               .ops = &kabylake_rt5663_fe_ops,
+       },
+       [KBL_DPCM_AUDIO_CP] = {
+               .name = "Kbl Audio Capture Port",
+               .stream_name = "Audio Record",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "0000:00:1f.3",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .nonatomic = 1,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_capture = 1,
+               .ops = &kabylake_rt5663_fe_ops,
+       },
+       [KBL_DPCM_AUDIO_DMIC_CP] = {
+               .name = "Kbl Audio DMIC cap",
+               .stream_name = "dmiccap",
+               .cpu_dai_name = "DMIC Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .init = NULL,
+               .dpcm_capture = 1,
+               .nonatomic = 1,
+               .dynamic = 1,
+               .ops = &kabylake_dmic_ops,
+       },
+       [KBL_DPCM_AUDIO_HDMI1_PB] = {
+               .name = "Kbl HDMI Port1",
+               .stream_name = "Hdmi1",
+               .cpu_dai_name = "HDMI1 Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .init = NULL,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+       [KBL_DPCM_AUDIO_HDMI2_PB] = {
+               .name = "Kbl HDMI Port2",
+               .stream_name = "Hdmi2",
+               .cpu_dai_name = "HDMI2 Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .init = NULL,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+       /* Back End DAI links */
+       /* single Back end dai for both max speakers and dmic */
+       {
+               /* SSP0 - Codec */
+               .name = "SSP0-Codec",
+               .id = 0,
+               .cpu_dai_name = "SSP0 Pin",
+               .platform_name = "0000:00:1f.3",
+               .no_pcm = 1,
+               .codecs = ssp0_codec_components,
+               .num_codecs = ARRAY_SIZE(ssp0_codec_components),
+               .dai_fmt = SND_SOC_DAIFMT_DSP_B |
+                       SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = kabylake_ssp_fixup,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ops = &kabylake_ssp0_ops,
+       },
+       {
+               .name = "SSP1-Codec",
+               .id = 1,
+               .cpu_dai_name = "SSP1 Pin",
+               .platform_name = "0000:00:1f.3",
+               .no_pcm = 1,
+               .codec_name = RT5663_DEV_NAME,
+               .codec_dai_name = KBL_REALTEK_CODEC_DAI,
+               .init = kabylake_rt5663_codec_init,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = kabylake_ssp_fixup,
+               .ops = &kabylake_rt5663_ops,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+       },
+       {
+               .name = "iDisp1",
+               .id = 3,
+               .cpu_dai_name = "iDisp1 Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi1",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .init = kabylake_hdmi1_init,
+               .no_pcm = 1,
+       },
+       {
+               .name = "iDisp2",
+               .id = 4,
+               .cpu_dai_name = "iDisp2 Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi2",
+               .platform_name = "0000:00:1f.3",
+               .init = kabylake_hdmi2_init,
+               .dpcm_playback = 1,
+               .no_pcm = 1,
+       },
+};
+
+static int kabylake_card_late_probe(struct snd_soc_card *card)
+{
+       struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card);
+       struct kbl_hdmi_pcm *pcm;
+       int err, i = 0;
+       char jack_name[NAME_SIZE];
+
+       list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+               err = snd_soc_card_jack_new(card, jack_name,
+                               SND_JACK_AVOUT, &ctx->kabylake_hdmi[i],
+                               NULL, 0);
+
+               if (err)
+                       return err;
+               err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
+                                               &ctx->kabylake_hdmi[i]);
+               if (err < 0)
+                       return err;
+               i++;
+       }
+
+       return 0;
+}
+
+/*
+ * kabylake audio machine driver for  MAX98927 + RT5514 + RT5663
+ */
+static struct snd_soc_card kabylake_audio_card = {
+       .name = "kbl_r5514_5663_max",
+       .owner = THIS_MODULE,
+       .dai_link = kabylake_dais,
+       .num_links = ARRAY_SIZE(kabylake_dais),
+       .controls = kabylake_controls,
+       .num_controls = ARRAY_SIZE(kabylake_controls),
+       .dapm_widgets = kabylake_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets),
+       .dapm_routes = kabylake_map,
+       .num_dapm_routes = ARRAY_SIZE(kabylake_map),
+       .codec_conf = max98927_codec_conf,
+       .num_configs = ARRAY_SIZE(max98927_codec_conf),
+       .fully_routed = true,
+       .late_probe = kabylake_card_late_probe,
+};
+
+static int kabylake_audio_probe(struct platform_device *pdev)
+{
+       struct kbl_codec_private *ctx;
+       struct skl_machine_pdata *pdata;
+
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+       if (!ctx)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+
+       kabylake_audio_card.dev = &pdev->dev;
+       snd_soc_card_set_drvdata(&kabylake_audio_card, ctx);
+
+       pdata = dev_get_drvdata(&pdev->dev);
+       if (pdata)
+               dmic_constraints = pdata->dmic_num == 2 ?
+                       &constraints_dmic_2ch : &constraints_dmic_channels;
+
+       return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card);
+}
+
+static const struct platform_device_id kbl_board_ids[] = {
+       { .name = "kbl_r5514_5663_max" },
+       { }
+};
+
+static struct platform_driver kabylake_audio = {
+       .probe = kabylake_audio_probe,
+       .driver = {
+               .name = "kbl_r5514_5663_max",
+               .pm = &snd_soc_pm_ops,
+       },
+       .id_table = kbl_board_ids,
+};
+
+module_platform_driver(kabylake_audio)
+
+/* Module information */
+MODULE_DESCRIPTION("Audio Machine driver-RT5663 RT5514 & MAX98927");
+MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:kbl_r5514_5663_max");
index 3b12bc1fa518e66409764b22b261d0c532af0b9b..5ed0aa27b467d0e4807a6fefecfb216334d49daf 100644 (file)
@@ -266,21 +266,21 @@ static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
        return 0;
 }
 
-static unsigned int rates[] = {
+static const unsigned int rates[] = {
        48000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_rates = {
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
        .count = ARRAY_SIZE(rates),
        .list  = rates,
        .mask = 0,
 };
 
-static unsigned int channels[] = {
+static const unsigned int channels[] = {
        2,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_channels = {
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
        .count = ARRAY_SIZE(channels),
        .list = channels,
        .mask = 0,
@@ -348,11 +348,11 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
        return 0;
 }
 
-static unsigned int channels_dmic[] = {
+static const unsigned int channels_dmic[] = {
        2, 4,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
+static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
        .count = ARRAY_SIZE(channels_dmic),
        .list = channels_dmic,
        .mask = 0,
@@ -384,11 +384,11 @@ static const struct snd_soc_ops skylake_dmic_ops = {
        .startup = skylake_dmic_startup,
 };
 
-static unsigned int rates_16000[] = {
+static const unsigned int rates_16000[] = {
        16000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_16000 = {
+static const struct snd_pcm_hw_constraint_list constraints_16000 = {
        .count = ARRAY_SIZE(rates_16000),
        .list  = rates_16000,
 };
index eb7751b0599bbcb1ea343b7c284f5b28ce238aae..01b8b140bb0874af87fa3ef98a4213bf7f6c74a5 100644 (file)
@@ -297,21 +297,21 @@ static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
        return 0;
 }
 
-static unsigned int rates[] = {
+static const unsigned int rates[] = {
        48000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_rates = {
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
        .count = ARRAY_SIZE(rates),
        .list  = rates,
        .mask = 0,
 };
 
-static unsigned int channels[] = {
+static const unsigned int channels[] = {
        2,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_channels = {
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
        .count = ARRAY_SIZE(channels),
        .list = channels,
        .mask = 0,
@@ -397,11 +397,11 @@ static const struct snd_soc_ops skylake_nau8825_ops = {
        .hw_params = skylake_nau8825_hw_params,
 };
 
-static unsigned int channels_dmic[] = {
+static const unsigned int channels_dmic[] = {
        2, 4,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
+static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
        .count = ARRAY_SIZE(channels_dmic),
        .list = channels_dmic,
        .mask = 0,
@@ -433,11 +433,11 @@ static const struct snd_soc_ops skylake_dmic_ops = {
        .startup = skylake_dmic_startup,
 };
 
-static unsigned int rates_16000[] = {
+static const unsigned int rates_16000[] = {
        16000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_16000 = {
+static const struct snd_pcm_hw_constraint_list constraints_16000 = {
        .count = ARRAY_SIZE(rates_16000),
        .list  = rates_16000,
 };
index f5ab7b8d51d1ceedb1e2e09033d5a68e97aad435..2bc4cfca594e1b295a283f284bd26f6ad0fc6c5c 100644 (file)
@@ -43,6 +43,7 @@ struct skl_rt286_private {
 
 enum {
        SKL_DPCM_AUDIO_PB = 0,
+       SKL_DPCM_AUDIO_DB_PB,
        SKL_DPCM_AUDIO_CP,
        SKL_DPCM_AUDIO_REF_CP,
        SKL_DPCM_AUDIO_DMIC_CP,
@@ -165,21 +166,21 @@ static int skylake_hdmi_init(struct snd_soc_pcm_runtime *rtd)
        return 0;
 }
 
-static unsigned int rates[] = {
+static const unsigned int rates[] = {
        48000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_rates = {
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
        .count = ARRAY_SIZE(rates),
        .list  = rates,
        .mask = 0,
 };
 
-static unsigned int channels[] = {
+static const unsigned int channels[] = {
        2,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_channels = {
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
        .count = ARRAY_SIZE(channels),
        .list = channels,
        .mask = 0,
@@ -264,11 +265,11 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
        return 0;
 }
 
-static unsigned int channels_dmic[] = {
+static const unsigned int channels_dmic[] = {
        2, 4,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
+static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
        .count = ARRAY_SIZE(channels_dmic),
        .list = channels_dmic,
        .mask = 0,
@@ -310,6 +311,23 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
                .dpcm_playback = 1,
                .ops = &skylake_rt286_fe_ops,
        },
+       [SKL_DPCM_AUDIO_DB_PB] = {
+               .name = "Skl Deepbuffer Port",
+               .stream_name = "Deep Buffer Audio",
+               .cpu_dai_name = "Deepbuffer Pin",
+               .platform_name = "0000:00:1f.3",
+               .nonatomic = 1,
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST,
+                       SND_SOC_DPCM_TRIGGER_POST
+               },
+               .dpcm_playback = 1,
+               .ops = &skylake_rt286_fe_ops,
+
+       },
        [SKL_DPCM_AUDIO_CP] = {
                .name = "Skl Audio Capture Port",
                .stream_name = "Audio Record",
index 214e000667ae0a2725f951e0956a39dbc37d8f10..afe9b87b8bd558065153da3a5c7ac4e7a7b536e7 100644 (file)
@@ -43,6 +43,9 @@ static inline bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
 /* acpi match */
 struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines);
 
+/* acpi check hid */
+bool sst_acpi_check_hid(const u8 hid[ACPI_ID_LEN]);
+
 /* Descriptor for SST ASoC machine driver */
 struct sst_acpi_mach {
        /* ACPI ID for the matching machine driver. Audio codec for instance */
@@ -55,5 +58,25 @@ struct sst_acpi_mach {
        /* board name */
        const char *board;
        struct sst_acpi_mach * (*machine_quirk)(void *arg);
+       const void *quirk_data;
        void *pdata;
 };
+
+#define SST_ACPI_MAX_CODECS 3
+
+/**
+ * struct sst_codecs: Structure to hold secondary codec information apart from
+ * the matched one, this data will be passed to the quirk function to match
+ * with the ACPI detected devices
+ *
+ * @num_codecs: number of secondary codecs used in the platform
+ * @codecs: holds the codec IDs
+ *
+ */
+struct sst_codecs {
+       int num_codecs;
+       u8 codecs[SST_ACPI_MAX_CODECS][ACPI_ID_LEN];
+};
+
+/* check all codecs */
+struct sst_acpi_mach *sst_acpi_codec_list(void *arg);
index d13c84364c3c0fd6e79ff3b38b4fe885eb0e2e92..8734040d64d379f5ad4849f529e61b31aceb6670 100644 (file)
@@ -77,6 +77,10 @@ struct sst_addr {
        u32 dram_offset;
        u32 dsp_iram_offset;
        u32 dsp_dram_offset;
+       u32 sram0_base;
+       u32 sram1_base;
+       u32 w0_stat_sz;
+       u32 w0_up_sz;
        void __iomem *lpe;
        void __iomem *shim;
        void __iomem *pci_cfg;
index 1070f3ad23e50e1e495824ca13f8d7176ca0b05e..56d26f36a3cba16f25217b465cfe4704c674e3c9 100644 (file)
@@ -63,16 +63,33 @@ static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
        return AE_OK;
 }
 
+bool sst_acpi_check_hid(const u8 hid[ACPI_ID_LEN])
+{
+       acpi_status status;
+       bool found = false;
+
+       status = acpi_get_devices(hid, sst_acpi_mach_match, &found, NULL);
+
+       if (ACPI_FAILURE(status))
+               return false;
+
+       return found;
+}
+EXPORT_SYMBOL_GPL(sst_acpi_check_hid);
+
 struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines)
 {
        struct sst_acpi_mach *mach;
-       bool found = false;
 
-       for (mach = machines; mach->id[0]; mach++)
-               if (ACPI_SUCCESS(acpi_get_devices(mach->id,
-                                                 sst_acpi_mach_match,
-                                                 &found, NULL)) && found)
-                       return mach;
+       for (mach = machines; mach->id[0]; mach++) {
+               if (sst_acpi_check_hid(mach->id) == true) {
+                       if (mach->machine_quirk == NULL)
+                               return mach;
+
+                       if (mach->machine_quirk(mach) != NULL)
+                               return mach;
+               }
+       }
        return NULL;
 }
 EXPORT_SYMBOL_GPL(sst_acpi_find_machine);
@@ -134,5 +151,23 @@ bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
 }
 EXPORT_SYMBOL_GPL(sst_acpi_find_package_from_hid);
 
+struct sst_acpi_mach *sst_acpi_codec_list(void *arg)
+{
+       struct sst_acpi_mach *mach = arg;
+       struct sst_codecs *codec_list = (struct sst_codecs *) mach->quirk_data;
+       int i;
+
+       if (mach->quirk_data == NULL)
+               return mach;
+
+       for (i = 0; i < codec_list->num_codecs; i++) {
+               if (sst_acpi_check_hid(codec_list->codecs[i]) != true)
+                       return NULL;
+       }
+
+       return mach;
+}
+EXPORT_SYMBOL_GPL(sst_acpi_codec_list);
+
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Intel Common ACPI Match module");
index 60fbc9bbe47330c720fd286e1c57606d34b0312d..e7d77722d56010dee2f3ea16f3642f4d63a56d1f 100644 (file)
@@ -1,6 +1,10 @@
 snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o skl-messages.o \
 skl-topology.o
 
+ifdef CONFIG_DEBUG_FS
+  snd-soc-skl-objs += skl-debug.o
+endif
+
 obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
 
 # Skylake IPC Support
index f5e7dbb1ba39e073fc1ee7212bb558962a85c987..cf11b84888b9044c94495beba67c539e35f8a816 100644 (file)
@@ -573,6 +573,10 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
        sst->fw_ops = bxt_fw_ops;
        sst->addr.lpe = mmio_base;
        sst->addr.shim = mmio_base;
+       sst->addr.sram0_base = BXT_ADSP_SRAM0_BASE;
+       sst->addr.sram1_base = BXT_ADSP_SRAM1_BASE;
+       sst->addr.w0_stat_sz = SKL_ADSP_W0_STAT_SZ;
+       sst->addr.w0_up_sz = SKL_ADSP_W0_UP_SZ;
 
        sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
                        SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c
new file mode 100644 (file)
index 0000000..75497b1
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ *  skl-debug.c - Debugfs for skl driver
+ *
+ *  Copyright (C) 2016-17 Intel Corp
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  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/pci.h>
+#include <linux/debugfs.h>
+#include "skl.h"
+#include "skl-sst-dsp.h"
+#include "skl-sst-ipc.h"
+#include "skl-tplg-interface.h"
+#include "skl-topology.h"
+#include "../common/sst-dsp-priv.h"
+
+#define MOD_BUF                PAGE_SIZE
+#define FW_REG_BUF     PAGE_SIZE
+#define FW_REG_SIZE    0x60
+
+struct skl_debug {
+       struct skl *skl;
+       struct device *dev;
+
+       struct dentry *fs;
+       struct dentry *modules;
+       u8 fw_read_buff[FW_REG_BUF];
+};
+
+static ssize_t skl_print_pins(struct skl_module_pin *m_pin, char *buf,
+                               int max_pin, ssize_t size, bool direction)
+{
+       int i;
+       ssize_t ret = 0;
+
+       for (i = 0; i < max_pin; i++)
+               ret += snprintf(buf + size, MOD_BUF - size,
+                               "%s %d\n\tModule %d\n\tInstance %d\n\t"
+                               "In-used %s\n\tType %s\n"
+                               "\tState %d\n\tIndex %d\n",
+                               direction ? "Input Pin:" : "Output Pin:",
+                               i, m_pin[i].id.module_id,
+                               m_pin[i].id.instance_id,
+                               m_pin[i].in_use ? "Used" : "Unused",
+                               m_pin[i].is_dynamic ? "Dynamic" : "Static",
+                               m_pin[i].pin_state, i);
+       return ret;
+}
+
+static ssize_t skl_print_fmt(struct skl_module_fmt *fmt, char *buf,
+                                       ssize_t size, bool direction)
+{
+       return snprintf(buf + size, MOD_BUF - size,
+                       "%s\n\tCh %d\n\tFreq %d\n\tBit depth %d\n\t"
+                       "Valid bit depth %d\n\tCh config %#x\n\tInterleaving %d\n\t"
+                       "Sample Type %d\n\tCh Map %#x\n",
+                       direction ? "Input Format:" : "Output Format:",
+                       fmt->channels, fmt->s_freq, fmt->bit_depth,
+                       fmt->valid_bit_depth, fmt->ch_cfg,
+                       fmt->interleaving_style, fmt->sample_type,
+                       fmt->ch_map);
+}
+
+static ssize_t module_read(struct file *file, char __user *user_buf,
+                          size_t count, loff_t *ppos)
+{
+       struct skl_module_cfg *mconfig = file->private_data;
+       char *buf;
+       ssize_t ret;
+
+       buf = kzalloc(MOD_BUF, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = snprintf(buf, MOD_BUF, "Module:\n\tUUID %pUL\n\tModule id %d\n"
+                       "\tInstance id %d\n\tPvt_id %d\n", mconfig->guid,
+                       mconfig->id.module_id, mconfig->id.instance_id,
+                       mconfig->id.pvt_id);
+
+       ret += snprintf(buf + ret, MOD_BUF - ret,
+                       "Resources:\n\tMCPS %#x\n\tIBS %#x\n\tOBS %#x\t\n",
+                       mconfig->mcps, mconfig->ibs, mconfig->obs);
+
+       ret += snprintf(buf + ret, MOD_BUF - ret,
+                       "Module data:\n\tCore %d\n\tIn queue %d\n\t"
+                       "Out queue %d\n\tType %s\n",
+                       mconfig->core_id, mconfig->max_in_queue,
+                       mconfig->max_out_queue,
+                       mconfig->is_loadable ? "loadable" : "inbuilt");
+
+       ret += skl_print_fmt(mconfig->in_fmt, buf, ret, true);
+       ret += skl_print_fmt(mconfig->out_fmt, buf, ret, false);
+
+       ret += snprintf(buf + ret, MOD_BUF - ret,
+                       "Fixup:\n\tParams %#x\n\tConverter %#x\n",
+                       mconfig->params_fixup, mconfig->converter);
+
+       ret += snprintf(buf + ret, MOD_BUF - ret,
+                       "Module Gateway:\n\tType %#x\n\tVbus %#x\n\tHW conn %#x\n\tSlot %#x\n",
+                       mconfig->dev_type, mconfig->vbus_id,
+                       mconfig->hw_conn_type, mconfig->time_slot);
+
+       ret += snprintf(buf + ret, MOD_BUF - ret,
+                       "Pipeline:\n\tID %d\n\tPriority %d\n\tConn Type %d\n\t"
+                       "Pages %#x\n", mconfig->pipe->ppl_id,
+                       mconfig->pipe->pipe_priority, mconfig->pipe->conn_type,
+                       mconfig->pipe->memory_pages);
+
+       ret += snprintf(buf + ret, MOD_BUF - ret,
+                       "\tParams:\n\t\tHost DMA %d\n\t\tLink DMA %d\n",
+                       mconfig->pipe->p_params->host_dma_id,
+                       mconfig->pipe->p_params->link_dma_id);
+
+       ret += snprintf(buf + ret, MOD_BUF - ret,
+                       "\tPCM params:\n\t\tCh %d\n\t\tFreq %d\n\t\tFormat %d\n",
+                       mconfig->pipe->p_params->ch,
+                       mconfig->pipe->p_params->s_freq,
+                       mconfig->pipe->p_params->s_fmt);
+
+       ret += snprintf(buf + ret, MOD_BUF - ret,
+                       "\tLink %#x\n\tStream %#x\n",
+                       mconfig->pipe->p_params->linktype,
+                       mconfig->pipe->p_params->stream);
+
+       ret += snprintf(buf + ret, MOD_BUF - ret,
+                       "\tState %d\n\tPassthru %s\n",
+                       mconfig->pipe->state,
+                       mconfig->pipe->passthru ? "true" : "false");
+
+       ret += skl_print_pins(mconfig->m_in_pin, buf,
+                       mconfig->max_in_queue, ret, true);
+       ret += skl_print_pins(mconfig->m_out_pin, buf,
+                       mconfig->max_out_queue, ret, false);
+
+       ret += snprintf(buf + ret, MOD_BUF - ret,
+                       "Other:\n\tDomain %d\n\tHomogenous Input %s\n\t"
+                       "Homogenous Output %s\n\tIn Queue Mask %d\n\t"
+                       "Out Queue Mask %d\n\tDMA ID %d\n\tMem Pages %d\n\t"
+                       "Module Type %d\n\tModule State %d\n",
+                       mconfig->domain,
+                       mconfig->homogenous_inputs ? "true" : "false",
+                       mconfig->homogenous_outputs ? "true" : "false",
+                       mconfig->in_queue_mask, mconfig->out_queue_mask,
+                       mconfig->dma_id, mconfig->mem_pages, mconfig->m_state,
+                       mconfig->m_type);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+       kfree(buf);
+       return ret;
+}
+
+static const struct file_operations mcfg_fops = {
+       .open = simple_open,
+       .read = module_read,
+       .llseek = default_llseek,
+};
+
+
+void skl_debug_init_module(struct skl_debug *d,
+                       struct snd_soc_dapm_widget *w,
+                       struct skl_module_cfg *mconfig)
+{
+       if (!debugfs_create_file(w->name, 0444,
+                               d->modules, mconfig,
+                               &mcfg_fops))
+               dev_err(d->dev, "%s: module debugfs init failed\n", w->name);
+}
+
+static ssize_t fw_softreg_read(struct file *file, char __user *user_buf,
+                              size_t count, loff_t *ppos)
+{
+       struct skl_debug *d = file->private_data;
+       struct sst_dsp *sst = d->skl->skl_sst->dsp;
+       size_t w0_stat_sz = sst->addr.w0_stat_sz;
+       void __iomem *in_base = sst->mailbox.in_base;
+       void __iomem *fw_reg_addr;
+       unsigned int offset;
+       char *tmp;
+       ssize_t ret = 0;
+
+       tmp = kzalloc(FW_REG_BUF, GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       fw_reg_addr = in_base - w0_stat_sz;
+       memset(d->fw_read_buff, 0, FW_REG_BUF);
+
+       if (w0_stat_sz > 0)
+               __iowrite32_copy(d->fw_read_buff, fw_reg_addr, w0_stat_sz >> 2);
+
+       for (offset = 0; offset < FW_REG_SIZE; offset += 16) {
+               ret += snprintf(tmp + ret, FW_REG_BUF - ret, "%#.4x: ", offset);
+               hex_dump_to_buffer(d->fw_read_buff + offset, 16, 16, 4,
+                                  tmp + ret, FW_REG_BUF - ret, 0);
+               ret += strlen(tmp + ret);
+
+               /* print newline for each offset */
+               if (FW_REG_BUF - ret > 0)
+                       tmp[ret++] = '\n';
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, tmp, ret);
+       kfree(tmp);
+
+       return ret;
+}
+
+static const struct file_operations soft_regs_ctrl_fops = {
+       .open = simple_open,
+       .read = fw_softreg_read,
+       .llseek = default_llseek,
+};
+
+struct skl_debug *skl_debugfs_init(struct skl *skl)
+{
+       struct skl_debug *d;
+
+       d = devm_kzalloc(&skl->pci->dev, sizeof(*d), GFP_KERNEL);
+       if (!d)
+               return NULL;
+
+       /* create the debugfs dir with platform component's debugfs as parent */
+       d->fs = debugfs_create_dir("dsp",
+                                  skl->platform->component.debugfs_root);
+       if (IS_ERR(d->fs) || !d->fs) {
+               dev_err(&skl->pci->dev, "debugfs root creation failed\n");
+               return NULL;
+       }
+
+       d->skl = skl;
+       d->dev = &skl->pci->dev;
+
+       /* now create the module dir */
+       d->modules = debugfs_create_dir("modules", d->fs);
+       if (IS_ERR(d->modules) || !d->modules) {
+               dev_err(&skl->pci->dev, "modules debugfs create failed\n");
+               goto err;
+       }
+
+       if (!debugfs_create_file("fw_soft_regs_rd", 0444, d->fs, d,
+                                &soft_regs_ctrl_fops)) {
+               dev_err(d->dev, "fw soft regs control debugfs init failed\n");
+               goto err;
+       }
+
+       return d;
+
+err:
+       debugfs_remove_recursive(d->fs);
+       return NULL;
+}
+
+void skl_debugfs_exit(struct skl_debug *d)
+{
+       debugfs_remove_recursive(d->fs);
+
+       kfree(d);
+
+}
index ab1adc0c9cc3296e1f6d28d270916f36f8b41dd8..eca85827dbd2af68f1bece9718650023dd91fbd4 100644 (file)
@@ -507,6 +507,8 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
                        struct skl_module_cfg *mconfig,
                        struct skl_cpr_cfg *cpr_mconfig)
 {
+       u32 dma_io_buf;
+
        cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(ctx, mconfig);
 
        if (cpr_mconfig->gtw_cfg.node_id == SKL_NON_GATEWAY_CPR_NODE_ID) {
@@ -514,10 +516,29 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
                return;
        }
 
-       if (SKL_CONN_SOURCE == mconfig->hw_conn_type)
-               cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->obs;
-       else
-               cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->ibs;
+       switch (mconfig->hw_conn_type) {
+       case SKL_CONN_SOURCE:
+               if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
+                       dma_io_buf =  mconfig->ibs;
+               else
+                       dma_io_buf =  mconfig->obs;
+               break;
+
+       case SKL_CONN_SINK:
+               if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
+                       dma_io_buf =  mconfig->obs;
+               else
+                       dma_io_buf =  mconfig->ibs;
+               break;
+
+       default:
+               dev_warn(ctx->dev, "wrong connection type: %d\n",
+                               mconfig->hw_conn_type);
+               return;
+       }
+
+       cpr_mconfig->gtw_cfg.dma_buffer_size =
+                               mconfig->dma_buffer_size * dma_io_buf;
 
        cpr_mconfig->cpr_feature_mask = 0;
        cpr_mconfig->gtw_cfg.config_length  = 0;
@@ -707,6 +728,7 @@ static u16 skl_get_module_param_size(struct skl_sst *ctx,
                return param_size;
 
        case SKL_MODULE_TYPE_BASE_OUTFMT:
+       case SKL_MODULE_TYPE_MIC_SELECT:
        case SKL_MODULE_TYPE_KPB:
                return sizeof(struct skl_base_outfmt_cfg);
 
@@ -761,6 +783,7 @@ static int skl_set_module_format(struct skl_sst *ctx,
                break;
 
        case SKL_MODULE_TYPE_BASE_OUTFMT:
+       case SKL_MODULE_TYPE_MIC_SELECT:
        case SKL_MODULE_TYPE_KPB:
                skl_set_base_outfmt_format(ctx, module_config, *param_data);
                break;
index e91bbcffc856514d0c8eaa7af4719b0a4d684b10..0ebea34a4988833e4033ae0ce280fc87b3598ad7 100644 (file)
@@ -1249,12 +1249,16 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
 
        pm_runtime_get_sync(platform->dev);
        if ((ebus_to_hbus(ebus))->ppcap) {
+               skl->platform = platform;
+
+               /* init debugfs */
+               skl->debugfs = skl_debugfs_init(skl);
+
                ret = skl_tplg_init(platform, ebus);
                if (ret < 0) {
                        dev_err(platform->dev, "Failed to init topology!\n");
                        return ret;
                }
-               skl->platform = platform;
 
                /* load the firmwares, since all is set */
                ops = skl_get_dsp_ops(skl->pci->device);
index 155e456b7a3ac1e3aa6fba6a9d5ed7a931dff3f8..aba9ea11ac749d7aa285218cc0530fbbd1b34615 100644 (file)
@@ -553,6 +553,11 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
        sst = skl->dsp;
        sst->addr.lpe = mmio_base;
        sst->addr.shim = mmio_base;
+       sst->addr.sram0_base = SKL_ADSP_SRAM0_BASE;
+       sst->addr.sram1_base = SKL_ADSP_SRAM1_BASE;
+       sst->addr.w0_stat_sz = SKL_ADSP_W0_STAT_SZ;
+       sst->addr.w0_up_sz = SKL_ADSP_W0_UP_SZ;
+
        sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
                        SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
 
index 64a0f8ed33e135eb5c0af683624afa3ebdb616b9..68c3f121efc3b22a4caff235303be07ba9914721 100644 (file)
 #define SKL_IN_DIR_BIT_MASK            BIT(0)
 #define SKL_PIN_COUNT_MASK             GENMASK(7, 4)
 
+static const int mic_mono_list[] = {
+0, 1, 2, 3,
+};
+static const int mic_stereo_list[][SKL_CH_STEREO] = {
+{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3},
+};
+static const int mic_trio_list[][SKL_CH_TRIO] = {
+{0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3},
+};
+static const int mic_quatro_list[][SKL_CH_QUATRO] = {
+{0, 1, 2, 3},
+};
+
 void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps)
 {
        struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3;
@@ -1314,6 +1327,111 @@ static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+static int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
+       struct skl_module_cfg *mconfig = w->priv;
+       struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+       u32 ch_type = *((u32 *)ec->dobj.private);
+
+       if (mconfig->dmic_ch_type == ch_type)
+               ucontrol->value.enumerated.item[0] =
+                                       mconfig->dmic_ch_combo_index;
+       else
+               ucontrol->value.enumerated.item[0] = 0;
+
+       return 0;
+}
+
+static int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig,
+       struct skl_mic_sel_config *mic_cfg, struct device *dev)
+{
+       struct skl_specific_cfg *sp_cfg = &mconfig->formats_config;
+
+       sp_cfg->caps_size = sizeof(struct skl_mic_sel_config);
+       sp_cfg->set_params = SKL_PARAM_SET;
+       sp_cfg->param_id = 0x00;
+       if (!sp_cfg->caps) {
+               sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL);
+               if (!sp_cfg->caps)
+                       return -ENOMEM;
+       }
+
+       mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH;
+       mic_cfg->flags = 0;
+       memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size);
+
+       return 0;
+}
+
+static int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
+       struct skl_module_cfg *mconfig = w->priv;
+       struct skl_mic_sel_config mic_cfg = {0};
+       struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+       u32 ch_type = *((u32 *)ec->dobj.private);
+       const int *list;
+       u8 in_ch, out_ch, index;
+
+       mconfig->dmic_ch_type = ch_type;
+       mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0];
+
+       /* enum control index 0 is INVALID, so no channels to be set */
+       if (mconfig->dmic_ch_combo_index == 0)
+               return 0;
+
+       /* No valid channel selection map for index 0, so offset by 1 */
+       index = mconfig->dmic_ch_combo_index - 1;
+
+       switch (ch_type) {
+       case SKL_CH_MONO:
+               if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list))
+                       return -EINVAL;
+
+               list = &mic_mono_list[index];
+               break;
+
+       case SKL_CH_STEREO:
+               if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list))
+                       return -EINVAL;
+
+               list = mic_stereo_list[index];
+               break;
+
+       case SKL_CH_TRIO:
+               if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list))
+                       return -EINVAL;
+
+               list = mic_trio_list[index];
+               break;
+
+       case SKL_CH_QUATRO:
+               if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list))
+                       return -EINVAL;
+
+               list = mic_quatro_list[index];
+               break;
+
+       default:
+               dev_err(w->dapm->dev,
+                               "Invalid channel %d for mic_select module\n",
+                               ch_type);
+               return -EINVAL;
+
+       }
+
+       /* channel type enum map to number of chanels for that type */
+       for (out_ch = 0; out_ch < ch_type; out_ch++) {
+               in_ch = list[out_ch];
+               mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN;
+       }
+
+       return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev);
+}
+
 /*
  * Fill the dma id for host and link. In case of passthrough
  * pipeline, this will both host and link in the same
@@ -1666,6 +1784,14 @@ static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
                                        skl_tplg_tlv_control_set},
 };
 
+static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
+       {
+               .id = SKL_CONTROL_TYPE_MIC_SELECT,
+               .get = skl_tplg_mic_control_get,
+               .put = skl_tplg_mic_control_set,
+       },
+};
+
 static int skl_tplg_fill_pipe_tkn(struct device *dev,
                        struct skl_pipe *pipe, u32 tkn,
                        u32 tkn_val)
@@ -1995,7 +2121,7 @@ static int skl_tplg_get_token(struct device *dev,
                mconfig->converter = tkn_elem->value;
                break;
 
-       case SKL_TKL_U32_D0I3_CAPS:
+       case SKL_TKN_U32_D0I3_CAPS:
                mconfig->d0i3_caps = tkn_elem->value;
                break;
 
@@ -2070,12 +2196,26 @@ static int skl_tplg_get_token(struct device *dev,
 
                break;
 
+       case SKL_TKN_U32_CAPS_SET_PARAMS:
+               mconfig->formats_config.set_params =
+                               tkn_elem->value;
+               break;
+
+       case SKL_TKN_U32_CAPS_PARAMS_ID:
+               mconfig->formats_config.param_id =
+                               tkn_elem->value;
+               break;
+
        case SKL_TKN_U32_PROC_DOMAIN:
                mconfig->domain =
                        tkn_elem->value;
 
                break;
 
+       case SKL_TKN_U32_DMA_BUF_SIZE:
+               mconfig->dma_buffer_size = tkn_elem->value;
+               break;
+
        case SKL_TKN_U8_IN_PIN_TYPE:
        case SKL_TKN_U8_OUT_PIN_TYPE:
        case SKL_TKN_U8_CONN_TYPE:
@@ -2147,7 +2287,7 @@ static int skl_tplg_get_tokens(struct device *dev,
                tuple_size += tkn_count * sizeof(*tkn_elem);
        }
 
-       return 0;
+       return off;
 }
 
 /*
@@ -2198,10 +2338,11 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
        num_blocks = ret;
 
        off += array->size;
-       array = (struct snd_soc_tplg_vendor_array *)(tplg_w->priv.data + off);
-
        /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
        while (num_blocks > 0) {
+               array = (struct snd_soc_tplg_vendor_array *)
+                               (tplg_w->priv.data + off);
+
                ret = skl_tplg_get_desc_blocks(dev, array);
 
                if (ret < 0)
@@ -2237,7 +2378,9 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
                                memcpy(mconfig->formats_config.caps, data,
                                        mconfig->formats_config.caps_size);
                        --num_blocks;
+                       ret = mconfig->formats_config.caps_size;
                }
+               off += ret;
        }
 
        return 0;
@@ -2329,6 +2472,9 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
        ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig);
        if (ret < 0)
                return ret;
+
+       skl_debug_init_module(skl->debugfs, w, mconfig);
+
 bind_event:
        if (tplg_w->event_type == 0) {
                dev_dbg(bus->dev, "ASoC: No event handler required\n");
@@ -2377,14 +2523,34 @@ static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
        return 0;
 }
 
+static int skl_init_enum_data(struct device *dev, struct soc_enum *se,
+                               struct snd_soc_tplg_enum_control *ec)
+{
+
+       void *data;
+
+       if (ec->priv.size) {
+               data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL);
+               if (!data)
+                       return -ENOMEM;
+               memcpy(data, ec->priv.data, ec->priv.size);
+               se->dobj.private = data;
+       }
+
+       return 0;
+
+}
+
 static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
                                struct snd_kcontrol_new *kctl,
                                struct snd_soc_tplg_ctl_hdr *hdr)
 {
        struct soc_bytes_ext *sb;
        struct snd_soc_tplg_bytes_control *tplg_bc;
+       struct snd_soc_tplg_enum_control *tplg_ec;
        struct hdac_ext_bus *ebus  = snd_soc_component_get_drvdata(cmpnt);
        struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct soc_enum *se;
 
        switch (hdr->ops.info) {
        case SND_SOC_TPLG_CTL_BYTES:
@@ -2398,6 +2564,17 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
                }
                break;
 
+       case SND_SOC_TPLG_CTL_ENUM:
+               tplg_ec = container_of(hdr,
+                               struct snd_soc_tplg_enum_control, hdr);
+               if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READWRITE) {
+                       se = (struct soc_enum *)kctl->private_value;
+                       if (tplg_ec->priv.size)
+                               return skl_init_enum_data(bus->dev, se,
+                                               tplg_ec);
+               }
+               break;
+
        default:
                dev_warn(bus->dev, "Control load not supported %d:%d:%d\n",
                        hdr->ops.get, hdr->ops.put, hdr->ops.info);
@@ -2626,6 +2803,8 @@ static struct snd_soc_tplg_ops skl_tplg_ops  = {
        .control_load = skl_tplg_control_load,
        .bytes_ext_ops = skl_tlv_ops,
        .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
+       .io_ops = skl_tplg_kcontrol_ops,
+       .io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops),
        .manifest = skl_manifest_load,
 };
 
index cc64d6bdb4f6c4859621619daa3a9077a96a8dc7..c25e8868b84e670cb765f815d2b69f409c245c22 100644 (file)
 #define MODULE_MAX_IN_PINS     8
 #define MODULE_MAX_OUT_PINS    8
 
+#define SKL_MIC_CH_SUPPORT     4
+#define SKL_MIC_MAX_CH_SUPPORT 8
+#define SKL_DEFAULT_MIC_SEL_GAIN       0x3FF
+#define SKL_MIC_SEL_SWITCH     0x3
+
 enum skl_channel_index {
        SKL_CHANNEL_LEFT = 0,
        SKL_CHANNEL_RIGHT = 1,
@@ -309,11 +314,14 @@ struct skl_module_cfg {
        u8 dev_type;
        u8 dma_id;
        u8 time_slot;
+       u8 dmic_ch_combo_index;
+       u32 dmic_ch_type;
        u32 params_fixup;
        u32 converter;
        u32 vbus_id;
        u32 mem_pages;
        enum d0i3_capability d0i3_caps;
+       u32 dma_buffer_size; /* in milli seconds */
        struct skl_module_pin *m_in_pin;
        struct skl_module_pin *m_out_pin;
        enum skl_module_type m_type;
@@ -342,6 +350,19 @@ struct skl_module_deferred_bind {
        struct list_head node;
 };
 
+struct skl_mic_sel_config {
+       u16 mic_switch;
+       u16 flags;
+       u16 blob[SKL_MIC_MAX_CH_SUPPORT][SKL_MIC_MAX_CH_SUPPORT];
+} __packed;
+
+enum skl_channel {
+       SKL_CH_MONO = 1,
+       SKL_CH_STEREO = 2,
+       SKL_CH_TRIO = 3,
+       SKL_CH_QUATRO = 4,
+};
+
 static inline struct skl *get_skl_ctx(struct device *dev)
 {
        struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
index 7a2febf99019be78f3f9c47c9c69edebafbefc20..f8d1749a2e0c89df8b1a95fd8b6729623ba8b8a1 100644 (file)
@@ -24,6 +24,7 @@
  * SST types start at higher to avoid any overlapping in future
  */
 #define SKL_CONTROL_TYPE_BYTE_TLV      0x100
+#define SKL_CONTROL_TYPE_MIC_SELECT    0x102
 
 #define HDA_SST_CFG_MAX        900 /* size of copier cfg*/
 #define MAX_IN_QUEUE 8
@@ -82,6 +83,7 @@ enum skl_module_type {
        SKL_MODULE_TYPE_ALGO,
        SKL_MODULE_TYPE_BASE_OUTFMT,
        SKL_MODULE_TYPE_KPB,
+       SKL_MODULE_TYPE_MIC_SELECT,
 };
 
 enum skl_core_affinity {
index 4c9b5781282bb149e8d749b32f2a1bd5c2987338..410ce83f4a49c711e4d76af19cc395cd206e3cb9 100644 (file)
@@ -866,6 +866,8 @@ static void skl_remove(struct pci_dev *pci)
        /* codec removal, invoke bus_device_remove */
        snd_hdac_ext_bus_device_remove(ebus);
 
+       skl_debugfs_exit(skl->debugfs);
+       skl->debugfs = NULL;
        skl_platform_unregister(&pci->dev);
        skl_free_dsp(skl);
        skl_machine_device_unregister(skl);
@@ -876,29 +878,120 @@ static void skl_remove(struct pci_dev *pci)
        dev_set_drvdata(&pci->dev, NULL);
 }
 
+static struct sst_codecs skl_codecs = {
+       .num_codecs = 1,
+       .codecs = {"NAU88L25"}
+};
+
+static struct sst_codecs kbl_codecs = {
+       .num_codecs = 1,
+       .codecs = {"NAU88L25"}
+};
+
+static struct sst_codecs bxt_codecs = {
+       .num_codecs = 1,
+       .codecs = {"MX98357A"}
+};
+
+static struct sst_codecs kbl_poppy_codecs = {
+       .num_codecs = 1,
+       .codecs = {"10EC5663"}
+};
+
+static struct sst_codecs kbl_5663_5514_codecs = {
+       .num_codecs = 2,
+       .codecs = {"10EC5663", "10EC5514"}
+};
+
+
 static struct sst_acpi_mach sst_skl_devdata[] = {
-       { "INT343A", "skl_alc286s_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL },
-       { "INT343B", "skl_n88l25_s4567", "intel/dsp_fw_release.bin",
-                               NULL, NULL, &skl_dmic_data },
-       { "MX98357A", "skl_n88l25_m98357a", "intel/dsp_fw_release.bin",
-                               NULL, NULL, &skl_dmic_data },
+       {
+               .id = "INT343A",
+               .drv_name = "skl_alc286s_i2s",
+               .fw_filename = "intel/dsp_fw_release.bin",
+       },
+       {
+               .id = "INT343B",
+               .drv_name = "skl_n88l25_s4567",
+               .fw_filename = "intel/dsp_fw_release.bin",
+               .machine_quirk = sst_acpi_codec_list,
+               .quirk_data = &skl_codecs,
+               .pdata = &skl_dmic_data
+       },
+       {
+               .id = "MX98357A",
+               .drv_name = "skl_n88l25_m98357a",
+               .fw_filename = "intel/dsp_fw_release.bin",
+               .machine_quirk = sst_acpi_codec_list,
+               .quirk_data = &skl_codecs,
+               .pdata = &skl_dmic_data
+       },
        {}
 };
 
 static struct sst_acpi_mach sst_bxtp_devdata[] = {
-       { "INT343A", "bxt_alc298s_i2s", "intel/dsp_fw_bxtn.bin", NULL, NULL, NULL },
-       { "DLGS7219", "bxt_da7219_max98357a_i2s", "intel/dsp_fw_bxtn.bin", NULL, NULL, NULL },
+       {
+               .id = "INT343A",
+               .drv_name = "bxt_alc298s_i2s",
+               .fw_filename = "intel/dsp_fw_bxtn.bin",
+       },
+       {
+               .id = "DLGS7219",
+               .drv_name = "bxt_da7219_max98357a_i2s",
+               .fw_filename = "intel/dsp_fw_bxtn.bin",
+               .machine_quirk = sst_acpi_codec_list,
+               .quirk_data = &bxt_codecs,
+       },
 };
 
 static struct sst_acpi_mach sst_kbl_devdata[] = {
-       { "INT343A", "kbl_alc286s_i2s", "intel/dsp_fw_kbl.bin", NULL, NULL, NULL },
-       { "INT343B", "kbl_n88l25_s4567", "intel/dsp_fw_kbl.bin", NULL, NULL, &skl_dmic_data },
-       { "MX98357A", "kbl_n88l25_m98357a", "intel/dsp_fw_kbl.bin", NULL, NULL, &skl_dmic_data },
+       {
+               .id = "INT343A",
+               .drv_name = "kbl_alc286s_i2s",
+               .fw_filename = "intel/dsp_fw_kbl.bin",
+       },
+       {
+               .id = "INT343B",
+               .drv_name = "kbl_n88l25_s4567",
+               .fw_filename = "intel/dsp_fw_kbl.bin",
+               .machine_quirk = sst_acpi_codec_list,
+               .quirk_data = &kbl_codecs,
+               .pdata = &skl_dmic_data
+       },
+       {
+               .id = "MX98357A",
+               .drv_name = "kbl_n88l25_m98357a",
+               .fw_filename = "intel/dsp_fw_kbl.bin",
+               .machine_quirk = sst_acpi_codec_list,
+               .quirk_data = &kbl_codecs,
+               .pdata = &skl_dmic_data
+       },
+       {
+               .id = "MX98927",
+               .drv_name = "kbl_r5514_5663_max",
+               .fw_filename = "intel/dsp_fw_kbl.bin",
+               .machine_quirk = sst_acpi_codec_list,
+               .quirk_data = &kbl_5663_5514_codecs,
+               .pdata = &skl_dmic_data
+       },
+       {
+               .id = "MX98927",
+               .drv_name = "kbl_rt5663_m98927",
+               .fw_filename = "intel/dsp_fw_kbl.bin",
+               .machine_quirk = sst_acpi_codec_list,
+               .quirk_data = &kbl_poppy_codecs,
+               .pdata = &skl_dmic_data
+       },
+
        {}
 };
 
 static struct sst_acpi_mach sst_glk_devdata[] = {
-       { "INT343A", "glk_alc298s_i2s", "intel/dsp_fw_glk.bin", NULL, NULL, NULL },
+       {
+               .id = "INT343A",
+               .drv_name = "glk_alc298s_i2s",
+               .fw_filename = "intel/dsp_fw_glk.bin",
+       },
 };
 
 /* PCI IDs */
index 2a630fcb7f088c1d548f06de31933ca662eafca2..14e7778d7f80c1f335b21a26c5d4496ad2c09783 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <sound/hda_register.h>
 #include <sound/hdaudio_ext.h>
+#include <sound/soc.h>
 #include "skl-nhlt.h"
 
 #define SKL_SUSPEND_DELAY 2000
@@ -42,6 +43,8 @@ struct skl_dsp_resource {
        u32 mem;
 };
 
+struct skl_debug;
+
 struct skl {
        struct hdac_ext_bus ebus;
        struct pci_dev *pci;
@@ -66,6 +69,8 @@ struct skl {
        int supend_active;
 
        struct work_struct probe_work;
+
+       struct skl_debug *debugfs;
 };
 
 #define skl_to_ebus(s) (&(s)->ebus)
@@ -116,4 +121,25 @@ void skl_update_d0i3c(struct device *dev, bool enable);
 int skl_nhlt_create_sysfs(struct skl *skl);
 void skl_nhlt_remove_sysfs(struct skl *skl);
 
+struct skl_module_cfg;
+
+#ifdef CONFIG_DEBUG_FS
+struct skl_debug *skl_debugfs_init(struct skl *skl);
+void skl_debugfs_exit(struct skl_debug *d);
+void skl_debug_init_module(struct skl_debug *d,
+                       struct snd_soc_dapm_widget *w,
+                       struct skl_module_cfg *mconfig);
+#else
+static inline struct skl_debug *skl_debugfs_init(struct skl *skl)
+{
+       return NULL;
+}
+static inline void skl_debugfs_exit(struct skl_debug *d)
+{}
+static inline void skl_debug_init_module(struct skl_debug *d,
+                                        struct snd_soc_dapm_widget *w,
+                                        struct skl_module_cfg *mconfig)
+{}
+#endif
+
 #endif /* __SOUND_SOC_SKL_H */
index 754e3ef8d7ae1b8b188c3e52986f2c306fb7b763..180bfbfe833da3c53a32a1845392d2af554e3929 100644 (file)
@@ -68,6 +68,20 @@ static int pmdown_time = 5000;
 module_param(pmdown_time, int, 0);
 MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)");
 
+/* If a DMI filed contain strings in this blacklist (e.g.
+ * "Type2 - Board Manufacturer" or  "Type1 - TBD by OEM"), it will be taken
+ * as invalid and dropped when setting the card long name from DMI info.
+ */
+static const char * const dmi_blacklist[] = {
+       "To be filled by OEM",
+       "TBD by OEM",
+       "Default String",
+       "Board Manufacturer",
+       "Board Vendor Name",
+       "Board Product Name",
+       NULL,   /* terminator */
+};
+
 /* returns the minimum number of bytes needed to represent
  * a particular given value */
 static int min_bytes_needed(unsigned long val)
@@ -1933,6 +1947,22 @@ static void cleanup_dmi_name(char *name)
        name[j] = '\0';
 }
 
+/* Check if a DMI field is valid, i.e. not containing any string
+ * in the black list.
+ */
+static int is_dmi_valid(const char *field)
+{
+       int i = 0;
+
+       while (dmi_blacklist[i]) {
+               if (strstr(field, dmi_blacklist[i]))
+                       return 0;
+               i++;
+       }
+
+       return 1;
+}
+
 /**
  * snd_soc_set_dmi_name() - Register DMI names to card
  * @card: The card to register DMI names
@@ -1975,17 +2005,18 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
 
        /* make up dmi long name as: vendor.product.version.board */
        vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
-       if (!vendor) {
+       if (!vendor || !is_dmi_valid(vendor)) {
                dev_warn(card->dev, "ASoC: no DMI vendor name!\n");
                return 0;
        }
 
+
        snprintf(card->dmi_longname, sizeof(card->snd_card->longname),
                         "%s", vendor);
        cleanup_dmi_name(card->dmi_longname);
 
        product = dmi_get_system_info(DMI_PRODUCT_NAME);
-       if (product) {
+       if (product && is_dmi_valid(product)) {
                len = strlen(card->dmi_longname);
                snprintf(card->dmi_longname + len,
                         longname_buf_size - len,
@@ -1999,7 +2030,7 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
                 * name in the product version field
                 */
                product_version = dmi_get_system_info(DMI_PRODUCT_VERSION);
-               if (product_version) {
+               if (product_version && is_dmi_valid(product_version)) {
                        len = strlen(card->dmi_longname);
                        snprintf(card->dmi_longname + len,
                                 longname_buf_size - len,
@@ -2012,7 +2043,7 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
        }
 
        board = dmi_get_system_info(DMI_BOARD_NAME);
-       if (board) {
+       if (board && is_dmi_valid(board)) {
                len = strlen(card->dmi_longname);
                snprintf(card->dmi_longname + len,
                         longname_buf_size - len,