mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-22 09:22:37 +00:00
Merge remote-tracking branch 'asoc/topic/intel' into asoc-next
This commit is contained in:
commit
51fa6a8f15
@ -161,6 +161,8 @@
|
||||
*
|
||||
* %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
|
||||
|
@ -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);
|
||||
|
@ -41,15 +41,6 @@
|
||||
|
||||
#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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 },
|
||||
{
|
||||
.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
|
||||
},
|
||||
|
||||
{"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 = "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
|
||||
{},
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
300
sound/soc/intel/boards/bytcht_es8316.c
Normal file
300
sound/soc/intel/boards/bytcht_es8316.c
Normal file
@ -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");
|
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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),
|
||||
|
@ -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>
|
||||
@ -31,8 +33,11 @@
|
||||
#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);
|
||||
|
687
sound/soc/intel/boards/kbl_rt5663_max98927.c
Normal file
687
sound/soc/intel/boards/kbl_rt5663_max98927.c
Normal file
@ -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");
|
640
sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
Normal file
640
sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
Normal file
@ -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");
|
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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",
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
268
sound/soc/intel/skylake/skl-debug.c
Normal file
268
sound/soc/intel/skylake/skl-debug.c
Normal file
@ -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);
|
||||
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -36,6 +36,19 @@
|
||||
#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,
|
||||
};
|
||||
|
||||
|
@ -39,6 +39,11 @@
|
||||
#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);
|
||||
|
@ -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 {
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user