mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-24 01:41:39 +00:00
Merge remote-tracking branch 'asoc/topic/intel' into asoc-next
This commit is contained in:
commit
16b5711485
37 changed files with 1947 additions and 847 deletions
|
@ -497,6 +497,8 @@ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream);
|
|||
int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
|
||||
unsigned int dai_fmt);
|
||||
|
||||
int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour);
|
||||
|
||||
/* Utility functions to get clock rates from various things */
|
||||
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
|
||||
int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
|
||||
|
@ -1093,6 +1095,8 @@ struct snd_soc_card {
|
|||
const char *name;
|
||||
const char *long_name;
|
||||
const char *driver_name;
|
||||
char dmi_longname[80];
|
||||
|
||||
struct device *dev;
|
||||
struct snd_card *snd_card;
|
||||
struct module *owner;
|
||||
|
|
|
@ -128,14 +128,17 @@ void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *ebus,
|
|||
{
|
||||
struct hdac_stream *hstream = &stream->hstream;
|
||||
struct hdac_bus *bus = &ebus->bus;
|
||||
u32 val;
|
||||
int mask = AZX_PPCTL_PROCEN(hstream->index);
|
||||
|
||||
spin_lock_irq(&bus->reg_lock);
|
||||
if (decouple)
|
||||
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0,
|
||||
AZX_PPCTL_PROCEN(hstream->index));
|
||||
else
|
||||
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
|
||||
AZX_PPCTL_PROCEN(hstream->index), 0);
|
||||
val = readw(bus->ppcap + AZX_REG_PP_PPCTL) & mask;
|
||||
|
||||
if (decouple && !val)
|
||||
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, mask, mask);
|
||||
else if (!decouple && val)
|
||||
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, mask, 0);
|
||||
|
||||
stream->decoupled = decouple;
|
||||
spin_unlock_irq(&bus->reg_lock);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,9 @@
|
|||
#ifndef __HDAC_HDMI_H__
|
||||
#define __HDAC_HDMI_H__
|
||||
|
||||
int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm);
|
||||
int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm,
|
||||
struct snd_soc_jack *jack);
|
||||
|
||||
int hdac_hdmi_jack_port_init(struct snd_soc_codec *codec,
|
||||
struct snd_soc_dapm_context *dapm);
|
||||
#endif /* __HDAC_HDMI_H__ */
|
||||
|
|
|
@ -1163,6 +1163,13 @@ static const struct dmi_system_id force_combo_jack_table[] = {
|
|||
DMI_MATCH(DMI_PRODUCT_NAME, "Broxton P")
|
||||
}
|
||||
},
|
||||
{
|
||||
.ident = "Intel Gemini Lake",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Geminilake")
|
||||
}
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
@ -2313,6 +2313,7 @@ MODULE_DEVICE_TABLE(of, rt5640_of_match);
|
|||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id rt5640_acpi_match[] = {
|
||||
{ "INT33CA", 0 },
|
||||
{ "10EC3276", 0 },
|
||||
{ "10EC5640", 0 },
|
||||
{ "10EC5642", 0 },
|
||||
{ "INTCCFFD", 0 },
|
||||
|
|
|
@ -3545,8 +3545,10 @@ MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
|
|||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id rt5645_acpi_match[] = {
|
||||
{ "10EC5645", 0 },
|
||||
{ "10EC5648", 0 },
|
||||
{ "10EC5650", 0 },
|
||||
{ "10EC5640", 0 },
|
||||
{ "10EC3270", 0 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
|
||||
|
|
|
@ -2814,6 +2814,7 @@ MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id);
|
|||
static const struct acpi_device_id rt5670_acpi_match[] = {
|
||||
{ "10EC5670", 0},
|
||||
{ "10EC5672", 0},
|
||||
{ "10EC5640", 0}, /* quirk */
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);
|
||||
|
|
|
@ -2,7 +2,7 @@ config SND_MFLD_MACHINE
|
|||
tristate "SOC Machine Audio driver for Intel Medfield MID platform"
|
||||
depends on INTEL_SCU_IPC
|
||||
select SND_SOC_SN95031
|
||||
select SND_SST_MFLD_PLATFORM
|
||||
select SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_PCI
|
||||
help
|
||||
This adds support for ASoC machine driver for Intel(R) MID Medfield platform
|
||||
|
@ -10,7 +10,7 @@ config SND_MFLD_MACHINE
|
|||
Say Y if you have such a device.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SST_MFLD_PLATFORM
|
||||
config SND_SST_ATOM_HIFI2_PLATFORM
|
||||
tristate
|
||||
select SND_SOC_COMPRESS
|
||||
|
||||
|
@ -31,13 +31,10 @@ config SND_SOC_INTEL_SST
|
|||
tristate
|
||||
select SND_SOC_INTEL_SST_ACPI if ACPI
|
||||
select SND_SOC_INTEL_SST_MATCH if ACPI
|
||||
depends on (X86 || COMPILE_TEST)
|
||||
|
||||
# firmware stuff depends DW_DMAC_CORE; since there is no depends-on from
|
||||
# the reverse selection, each machine driver needs to select
|
||||
# SND_SOC_INTEL_SST_FIRMWARE carefully depending on DW_DMAC_CORE
|
||||
config SND_SOC_INTEL_SST_FIRMWARE
|
||||
tristate
|
||||
select DW_DMAC_CORE
|
||||
|
||||
config SND_SOC_INTEL_SST_ACPI
|
||||
tristate
|
||||
|
@ -47,16 +44,18 @@ config SND_SOC_INTEL_SST_MATCH
|
|||
|
||||
config SND_SOC_INTEL_HASWELL
|
||||
tristate
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SST_FIRMWARE
|
||||
|
||||
config SND_SOC_INTEL_BAYTRAIL
|
||||
tristate
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SST_FIRMWARE
|
||||
|
||||
config SND_SOC_INTEL_HASWELL_MACH
|
||||
tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
|
||||
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
|
||||
depends on DW_DMAC_CORE
|
||||
select SND_SOC_INTEL_SST
|
||||
depends on DMADEVICES
|
||||
select SND_SOC_INTEL_HASWELL
|
||||
select SND_SOC_RT5640
|
||||
help
|
||||
|
@ -68,7 +67,6 @@ config SND_SOC_INTEL_HASWELL_MACH
|
|||
config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
|
||||
tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode"
|
||||
depends on X86 && ACPI && I2C
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SKYLAKE
|
||||
select SND_SOC_DA7219
|
||||
select SND_SOC_MAX98357A
|
||||
|
@ -84,7 +82,6 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
|
|||
config SND_SOC_INTEL_BXT_RT298_MACH
|
||||
tristate "ASoC Audio driver for Broxton with RT298 I2S mode"
|
||||
depends on X86 && ACPI && I2C
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SKYLAKE
|
||||
select SND_SOC_RT298
|
||||
select SND_SOC_DMIC
|
||||
|
@ -99,9 +96,8 @@ config SND_SOC_INTEL_BXT_RT298_MACH
|
|||
config SND_SOC_INTEL_BYT_RT5640_MACH
|
||||
tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
|
||||
depends on X86_INTEL_LPSS && I2C
|
||||
depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n)
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SST_FIRMWARE
|
||||
depends on DMADEVICES
|
||||
depends on SND_SST_IPC_ACPI = n
|
||||
select SND_SOC_INTEL_BAYTRAIL
|
||||
select SND_SOC_RT5640
|
||||
help
|
||||
|
@ -112,9 +108,8 @@ config SND_SOC_INTEL_BYT_RT5640_MACH
|
|||
config SND_SOC_INTEL_BYT_MAX98090_MACH
|
||||
tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
|
||||
depends on X86_INTEL_LPSS && I2C
|
||||
depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n)
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SST_FIRMWARE
|
||||
depends on DMADEVICES
|
||||
depends on SND_SST_IPC_ACPI = n
|
||||
select SND_SOC_INTEL_BAYTRAIL
|
||||
select SND_SOC_MAX98090
|
||||
help
|
||||
|
@ -123,9 +118,8 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH
|
|||
|
||||
config SND_SOC_INTEL_BDW_RT5677_MACH
|
||||
tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec"
|
||||
depends on X86_INTEL_LPSS && GPIOLIB && I2C && DW_DMAC
|
||||
depends on DW_DMAC_CORE=y
|
||||
select SND_SOC_INTEL_SST
|
||||
depends on X86_INTEL_LPSS && GPIOLIB && I2C
|
||||
depends on DMADEVICES
|
||||
select SND_SOC_INTEL_HASWELL
|
||||
select SND_SOC_RT5677
|
||||
help
|
||||
|
@ -134,10 +128,8 @@ config SND_SOC_INTEL_BDW_RT5677_MACH
|
|||
|
||||
config SND_SOC_INTEL_BROADWELL_MACH
|
||||
tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
|
||||
depends on X86_INTEL_LPSS && I2C && DW_DMAC && \
|
||||
I2C_DESIGNWARE_PLATFORM
|
||||
depends on DW_DMAC_CORE
|
||||
select SND_SOC_INTEL_SST
|
||||
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
|
||||
depends on DMADEVICES
|
||||
select SND_SOC_INTEL_HASWELL
|
||||
select SND_SOC_RT286
|
||||
help
|
||||
|
@ -150,7 +142,7 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH
|
|||
tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec"
|
||||
depends on X86 && I2C && ACPI
|
||||
select SND_SOC_RT5640
|
||||
select SND_SST_MFLD_PLATFORM
|
||||
select SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
select SND_SOC_INTEL_SST_MATCH if ACPI
|
||||
help
|
||||
|
@ -163,7 +155,7 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH
|
|||
tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec"
|
||||
depends on X86 && I2C && ACPI
|
||||
select SND_SOC_RT5651
|
||||
select SND_SST_MFLD_PLATFORM
|
||||
select SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
select SND_SOC_INTEL_SST_MATCH if ACPI
|
||||
help
|
||||
|
@ -176,7 +168,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
|
|||
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec"
|
||||
depends on X86_INTEL_LPSS && I2C && ACPI
|
||||
select SND_SOC_RT5670
|
||||
select SND_SST_MFLD_PLATFORM
|
||||
select SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
select SND_SOC_INTEL_SST_MATCH if ACPI
|
||||
help
|
||||
|
@ -189,7 +181,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
|
|||
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec"
|
||||
depends on X86_INTEL_LPSS && I2C && ACPI
|
||||
select SND_SOC_RT5645
|
||||
select SND_SST_MFLD_PLATFORM
|
||||
select SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
select SND_SOC_INTEL_SST_MATCH if ACPI
|
||||
help
|
||||
|
@ -202,7 +194,7 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
|
|||
depends on X86_INTEL_LPSS && I2C && ACPI
|
||||
select SND_SOC_MAX98090
|
||||
select SND_SOC_TS3A227E
|
||||
select SND_SST_MFLD_PLATFORM
|
||||
select SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
select SND_SOC_INTEL_SST_MATCH if ACPI
|
||||
help
|
||||
|
@ -220,7 +212,6 @@ config SND_SOC_INTEL_SKYLAKE
|
|||
config SND_SOC_INTEL_SKL_RT286_MACH
|
||||
tristate "ASoC Audio driver for SKL with RT286 I2S mode"
|
||||
depends on X86 && ACPI && I2C
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SKYLAKE
|
||||
select SND_SOC_RT286
|
||||
select SND_SOC_DMIC
|
||||
|
@ -234,7 +225,6 @@ config SND_SOC_INTEL_SKL_RT286_MACH
|
|||
config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
|
||||
tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode"
|
||||
depends on X86_INTEL_LPSS && I2C
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SKYLAKE
|
||||
select SND_SOC_NAU8825
|
||||
select SND_SOC_SSM4567
|
||||
|
@ -249,7 +239,6 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
|
|||
config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
|
||||
tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode"
|
||||
depends on X86_INTEL_LPSS && I2C
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SKYLAKE
|
||||
select SND_SOC_NAU8825
|
||||
select SND_SOC_MAX98357A
|
||||
|
|
|
@ -4,7 +4,7 @@ obj-$(CONFIG_SND_SOC_INTEL_SST) += common/
|
|||
# Platform Support
|
||||
obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/
|
||||
obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += atom/
|
||||
obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += atom/
|
||||
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += skylake/
|
||||
|
||||
# Machine support
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \
|
||||
sst-mfld-platform-compress.o sst-atom-controls.o
|
||||
snd-soc-sst-atom-hifi2-platform-objs := sst-mfld-platform-pcm.o \
|
||||
sst-mfld-platform-compress.o \
|
||||
sst-atom-controls.o
|
||||
|
||||
obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o
|
||||
obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += snd-soc-sst-atom-hifi2-platform.o
|
||||
|
||||
# DSP driver
|
||||
obj-$(CONFIG_SND_SST_IPC) += sst/
|
||||
|
|
|
@ -1085,8 +1085,8 @@ static const struct snd_soc_dapm_widget sst_dapm_widgets[] = {
|
|||
SST_PATH_INPUT("sprot_loop_in", SST_TASK_SBA, SST_SWM_IN_SPROT_LOOP, NULL),
|
||||
SST_PATH_INPUT("media_loop1_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP1, NULL),
|
||||
SST_PATH_INPUT("media_loop2_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP2, NULL),
|
||||
SST_PATH_MEDIA_LOOP_OUTPUT("sprot_loop_out", SST_TASK_SBA, SST_SWM_OUT_SPROT_LOOP, SST_FMT_MONO, sst_set_media_loop),
|
||||
SST_PATH_MEDIA_LOOP_OUTPUT("media_loop1_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP1, SST_FMT_MONO, sst_set_media_loop),
|
||||
SST_PATH_MEDIA_LOOP_OUTPUT("sprot_loop_out", SST_TASK_SBA, SST_SWM_OUT_SPROT_LOOP, SST_FMT_STEREO, sst_set_media_loop),
|
||||
SST_PATH_MEDIA_LOOP_OUTPUT("media_loop1_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP1, SST_FMT_STEREO, sst_set_media_loop),
|
||||
SST_PATH_MEDIA_LOOP_OUTPUT("media_loop2_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP2, SST_FMT_STEREO, sst_set_media_loop),
|
||||
|
||||
/* Media Mixers */
|
||||
|
|
|
@ -357,14 +357,14 @@ static void sst_media_close(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sst_runtime_stream *stream;
|
||||
int ret_val = 0, str_id;
|
||||
int str_id;
|
||||
|
||||
stream = substream->runtime->private_data;
|
||||
power_down_sst(stream);
|
||||
|
||||
str_id = stream->stream_info.str_id;
|
||||
if (str_id)
|
||||
ret_val = stream->ops->close(sst->dev, str_id);
|
||||
stream->ops->close(sst->dev, str_id);
|
||||
module_put(sst->dev->driver->owner);
|
||||
kfree(stream);
|
||||
}
|
||||
|
@ -839,4 +839,5 @@ MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
|
|||
MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
|
||||
MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:sst-atom-hifi2-platform");
|
||||
MODULE_ALIAS("platform:sst-mfld-platform");
|
||||
|
|
|
@ -400,6 +400,7 @@ static int sst_acpi_remove(struct platform_device *pdev)
|
|||
static unsigned long cht_machine_id;
|
||||
|
||||
#define CHT_SURFACE_MACH 1
|
||||
#define BYT_THINKPAD_10 2
|
||||
|
||||
static int cht_surface_quirk_cb(const struct dmi_system_id *id)
|
||||
{
|
||||
|
@ -407,6 +408,23 @@ static int cht_surface_quirk_cb(const struct dmi_system_id *id)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id)
|
||||
{
|
||||
cht_machine_id = BYT_THINKPAD_10;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static const struct dmi_system_id byt_table[] = {
|
||||
{
|
||||
.callback = byt_thinkpad10_quirk_cb,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "20C3001VHH"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct dmi_system_id cht_table[] = {
|
||||
{
|
||||
|
@ -424,6 +442,10 @@ static struct sst_acpi_mach cht_surface_mach = {
|
|||
"10EC5640", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
|
||||
&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 };
|
||||
|
||||
static struct sst_acpi_mach *cht_quirk(void *arg)
|
||||
{
|
||||
struct sst_acpi_mach *mach = arg;
|
||||
|
@ -436,8 +458,21 @@ static struct sst_acpi_mach *cht_quirk(void *arg)
|
|||
return mach;
|
||||
}
|
||||
|
||||
static struct sst_acpi_mach *byt_quirk(void *arg)
|
||||
{
|
||||
struct sst_acpi_mach *mach = arg;
|
||||
|
||||
dmi_check_system(byt_table);
|
||||
|
||||
if (cht_machine_id == BYT_THINKPAD_10)
|
||||
return &byt_thinkpad_10;
|
||||
else
|
||||
return mach;
|
||||
}
|
||||
|
||||
|
||||
static struct sst_acpi_mach sst_acpi_bytcr[] = {
|
||||
{"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL,
|
||||
{"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 },
|
||||
|
@ -445,6 +480,12 @@ static struct sst_acpi_mach sst_acpi_bytcr[] = {
|
|||
&byt_rvp_platform_data },
|
||||
{"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL,
|
||||
&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 },
|
||||
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -458,12 +499,19 @@ static struct sst_acpi_mach sst_acpi_chv[] = {
|
|||
&chv_platform_data },
|
||||
{"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
|
||||
&chv_platform_data },
|
||||
{"10EC3270", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
|
||||
&chv_platform_data },
|
||||
|
||||
{"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
|
||||
&chv_platform_data },
|
||||
/* 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 },
|
||||
/* 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 },
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
|
@ -260,10 +260,8 @@ static void process_fw_async_msg(struct intel_sst_drv *sst_drv_ctx,
|
|||
u32 data_size, i;
|
||||
void *data_offset;
|
||||
struct stream_info *stream;
|
||||
union ipc_header_high msg_high;
|
||||
u32 msg_low, pipe_id;
|
||||
|
||||
msg_high = msg->mrfld_header.p.header_high;
|
||||
msg_low = msg->mrfld_header.p.header_low_payload;
|
||||
msg_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->cmd_id;
|
||||
data_offset = (msg->mailbox_data + sizeof(struct ipc_dsp_hdr));
|
||||
|
|
|
@ -394,7 +394,6 @@ int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
|
|||
{
|
||||
int retval = 0;
|
||||
struct stream_info *str_info;
|
||||
struct intel_sst_ops *ops;
|
||||
|
||||
dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id);
|
||||
|
||||
|
@ -407,7 +406,6 @@ int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
|
|||
str_info = get_stream_info(sst_drv_ctx, str_id);
|
||||
if (!str_info)
|
||||
return -EINVAL;
|
||||
ops = sst_drv_ctx->ops;
|
||||
|
||||
mutex_lock(&str_info->lock);
|
||||
if (str_info->status != STREAM_UN_INIT) {
|
||||
|
|
|
@ -270,6 +270,8 @@ static int broadwell_audio_probe(struct platform_device *pdev)
|
|||
{
|
||||
broadwell_rt286.dev = &pdev->dev;
|
||||
|
||||
snd_soc_set_dmi_name(&broadwell_rt286, NULL);
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,17 @@
|
|||
#define QUAD_CHANNEL 4
|
||||
|
||||
static struct snd_soc_jack broxton_headset;
|
||||
static struct snd_soc_jack broxton_hdmi[3];
|
||||
|
||||
struct bxt_hdmi_pcm {
|
||||
struct list_head head;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
int device;
|
||||
};
|
||||
|
||||
struct bxt_card_private {
|
||||
struct list_head hdmi_pcm_list;
|
||||
};
|
||||
|
||||
enum {
|
||||
BXT_DPCM_AUDIO_PB = 0,
|
||||
|
@ -84,9 +95,9 @@ static const struct snd_soc_dapm_route broxton_map[] = {
|
|||
{"codec0_in", NULL, "ssp1 Rx"},
|
||||
{"ssp1 Rx", NULL, "Capture"},
|
||||
|
||||
{"HDMI1", NULL, "hif5 Output"},
|
||||
{"HDMI2", NULL, "hif6 Output"},
|
||||
{"HDMI3", NULL, "hif7 Output"},
|
||||
{"HDMI1", NULL, "hif5-0 Output"},
|
||||
{"HDMI2", NULL, "hif6-0 Output"},
|
||||
{"HDMI2", NULL, "hif7-0 Output"},
|
||||
|
||||
{"hifi3", NULL, "iDisp3 Tx"},
|
||||
{"iDisp3 Tx", NULL, "iDisp3_out"},
|
||||
|
@ -147,9 +158,20 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
|
|||
|
||||
static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct bxt_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct snd_soc_dai *dai = rtd->codec_dai;
|
||||
struct bxt_hdmi_pcm *pcm;
|
||||
|
||||
return hdac_hdmi_jack_init(dai, BXT_DPCM_AUDIO_HDMI1_PB + dai->id);
|
||||
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
|
||||
if (!pcm)
|
||||
return -ENOMEM;
|
||||
|
||||
pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id;
|
||||
pcm->codec_dai = dai;
|
||||
|
||||
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int broxton_da7219_fe_init(struct snd_soc_pcm_runtime *rtd)
|
||||
|
@ -357,7 +379,6 @@ static struct snd_soc_dai_link broxton_dais[] = {
|
|||
.platform_name = "0000:00:0e.0",
|
||||
.init = NULL,
|
||||
.dpcm_capture = 1,
|
||||
.ignore_suspend = 1,
|
||||
.nonatomic = 1,
|
||||
.dynamic = 1,
|
||||
.ops = &broxton_refcap_ops,
|
||||
|
@ -497,6 +518,40 @@ static struct snd_soc_dai_link broxton_dais[] = {
|
|||
},
|
||||
};
|
||||
|
||||
#define NAME_SIZE 32
|
||||
static int bxt_card_late_probe(struct snd_soc_card *card)
|
||||
{
|
||||
struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
struct bxt_hdmi_pcm *pcm;
|
||||
struct snd_soc_codec *codec = NULL;
|
||||
int err, i = 0;
|
||||
char jack_name[NAME_SIZE];
|
||||
|
||||
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
|
||||
codec = pcm->codec_dai->codec;
|
||||
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, &broxton_hdmi[i],
|
||||
NULL, 0);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
|
||||
&broxton_hdmi[i]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!codec)
|
||||
return -EINVAL;
|
||||
|
||||
return hdac_hdmi_jack_port_init(codec, &card->dapm);
|
||||
}
|
||||
|
||||
/* broxton audio machine driver for SPT + da7219 */
|
||||
static struct snd_soc_card broxton_audio_card = {
|
||||
.name = "bxtda7219max",
|
||||
|
@ -510,11 +565,22 @@ static struct snd_soc_card broxton_audio_card = {
|
|||
.dapm_routes = broxton_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(broxton_map),
|
||||
.fully_routed = true,
|
||||
.late_probe = bxt_card_late_probe,
|
||||
};
|
||||
|
||||
static int broxton_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bxt_card_private *ctx;
|
||||
|
||||
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
|
||||
|
||||
broxton_audio_card.dev = &pdev->dev;
|
||||
snd_soc_card_set_drvdata(&broxton_audio_card, ctx);
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,8 +26,19 @@
|
|||
#include "../../codecs/hdac_hdmi.h"
|
||||
#include "../../codecs/rt298.h"
|
||||
|
||||
static struct snd_soc_jack broxton_headset;
|
||||
/* Headset jack detection DAPM pins */
|
||||
static struct snd_soc_jack broxton_headset;
|
||||
static struct snd_soc_jack broxton_hdmi[3];
|
||||
|
||||
struct bxt_hdmi_pcm {
|
||||
struct list_head head;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
int device;
|
||||
};
|
||||
|
||||
struct bxt_rt286_private {
|
||||
struct list_head hdmi_pcm_list;
|
||||
};
|
||||
|
||||
enum {
|
||||
BXT_DPCM_AUDIO_PB = 0,
|
||||
|
@ -82,9 +93,9 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = {
|
|||
{"DMIC1 Pin", NULL, "DMIC2"},
|
||||
{"DMic", NULL, "SoC DMIC"},
|
||||
|
||||
{"HDMI1", NULL, "hif5 Output"},
|
||||
{"HDMI2", NULL, "hif6 Output"},
|
||||
{"HDMI3", NULL, "hif7 Output"},
|
||||
{"HDMI1", NULL, "hif5-0 Output"},
|
||||
{"HDMI2", NULL, "hif6-0 Output"},
|
||||
{"HDMI2", NULL, "hif7-0 Output"},
|
||||
|
||||
/* CODEC BE connections */
|
||||
{ "AIF1 Playback", NULL, "ssp5 Tx"},
|
||||
|
@ -139,9 +150,20 @@ static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd)
|
|||
|
||||
static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct snd_soc_dai *dai = rtd->codec_dai;
|
||||
struct bxt_hdmi_pcm *pcm;
|
||||
|
||||
return hdac_hdmi_jack_init(dai, BXT_DPCM_AUDIO_HDMI1_PB + dai->id);
|
||||
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
|
||||
if (!pcm)
|
||||
return -ENOMEM;
|
||||
|
||||
pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id;
|
||||
pcm->codec_dai = dai;
|
||||
|
||||
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
|
@ -432,6 +454,41 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
|
|||
},
|
||||
};
|
||||
|
||||
#define NAME_SIZE 32
|
||||
static int bxt_card_late_probe(struct snd_soc_card *card)
|
||||
{
|
||||
struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
struct bxt_hdmi_pcm *pcm;
|
||||
struct snd_soc_codec *codec = NULL;
|
||||
int err, i = 0;
|
||||
char jack_name[NAME_SIZE];
|
||||
|
||||
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
|
||||
codec = pcm->codec_dai->codec;
|
||||
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, &broxton_hdmi[i],
|
||||
NULL, 0);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
|
||||
&broxton_hdmi[i]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!codec)
|
||||
return -EINVAL;
|
||||
|
||||
return hdac_hdmi_jack_port_init(codec, &card->dapm);
|
||||
}
|
||||
|
||||
|
||||
/* broxton audio machine driver for SPT + RT298S */
|
||||
static struct snd_soc_card broxton_rt298 = {
|
||||
.name = "broxton-rt298",
|
||||
|
@ -445,11 +502,22 @@ static struct snd_soc_card broxton_rt298 = {
|
|||
.dapm_routes = broxton_rt298_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(broxton_rt298_map),
|
||||
.fully_routed = true,
|
||||
.late_probe = bxt_card_late_probe,
|
||||
|
||||
};
|
||||
|
||||
static int broxton_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bxt_rt286_private *ctx;
|
||||
|
||||
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
|
||||
|
||||
broxton_rt298.dev = &pdev->dev;
|
||||
snd_soc_card_set_drvdata(&broxton_rt298, ctx);
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &broxton_rt298);
|
||||
}
|
||||
|
|
|
@ -386,6 +386,16 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
|
|||
BYT_RT5640_MCLK_EN |
|
||||
BYT_RT5640_SSP0_AIF1),
|
||||
|
||||
},
|
||||
{
|
||||
.callback = byt_rt5640_quirk_cb,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
|
||||
},
|
||||
.driver_data = (unsigned long *)(BYT_RT5640_IN3_MAP |
|
||||
BYT_RT5640_MCLK_EN |
|
||||
BYT_RT5640_SSP0_AIF1),
|
||||
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -23,7 +23,11 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/cpu_device_id.h>
|
||||
#include <asm/platform_sst_audio.h>
|
||||
#include <linux/clk.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
|
@ -33,7 +37,8 @@
|
|||
#include "../common/sst-acpi.h"
|
||||
|
||||
#define CHT_PLAT_CLK_3_HZ 19200000
|
||||
#define CHT_CODEC_DAI "rt5645-aif1"
|
||||
#define CHT_CODEC_DAI1 "rt5645-aif1"
|
||||
#define CHT_CODEC_DAI2 "rt5645-aif2"
|
||||
|
||||
struct cht_acpi_card {
|
||||
char *codec_id;
|
||||
|
@ -45,15 +50,36 @@ struct cht_mc_private {
|
|||
struct snd_soc_jack jack;
|
||||
struct cht_acpi_card *acpi_card;
|
||||
char codec_name[16];
|
||||
struct clk *mclk;
|
||||
};
|
||||
|
||||
#define CHT_RT5645_MAP(quirk) ((quirk) & 0xff)
|
||||
#define CHT_RT5645_SSP2_AIF2 BIT(16) /* default is using AIF1 */
|
||||
#define CHT_RT5645_SSP0_AIF1 BIT(17)
|
||||
#define CHT_RT5645_SSP0_AIF2 BIT(18)
|
||||
|
||||
static unsigned long cht_rt5645_quirk = 0;
|
||||
|
||||
static void log_quirks(struct device *dev)
|
||||
{
|
||||
if (cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2)
|
||||
dev_info(dev, "quirk SSP2_AIF2 enabled");
|
||||
if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1)
|
||||
dev_info(dev, "quirk SSP0_AIF1 enabled");
|
||||
if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)
|
||||
dev_info(dev, "quirk SSP0_AIF2 enabled");
|
||||
}
|
||||
|
||||
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)))
|
||||
if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI1,
|
||||
strlen(CHT_CODEC_DAI1)))
|
||||
return rtd->codec_dai;
|
||||
if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI2,
|
||||
strlen(CHT_CODEC_DAI2)))
|
||||
return rtd->codec_dai;
|
||||
}
|
||||
return NULL;
|
||||
|
@ -65,6 +91,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,19 +100,30 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (!SND_SOC_DAPM_EVENT_OFF(event))
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Set codec sysclk source to its internal clock because codec PLL will
|
||||
* be off when idle and MCLK will also be off when codec is
|
||||
* runtime suspended. Codec needs clock for jack detection and button
|
||||
* press. MCLK is turned off with clock framework or ACPI.
|
||||
*/
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK,
|
||||
48000 * 512, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
dev_err(card->dev, "can't set codec sysclk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set codec sysclk source to its internal clock because codec PLL will
|
||||
* be off when idle and MCLK will also be off by ACPI when codec is
|
||||
* runtime suspended. Codec needs clock for jack detection and button
|
||||
* press.
|
||||
*/
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK,
|
||||
0, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
dev_err(card->dev, "can't set codec sysclk: %d\n", ret);
|
||||
return ret;
|
||||
if (ctx->mclk)
|
||||
clk_disable_unprepare(ctx->mclk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -97,7 +135,7 @@ static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
|
|||
SND_SOC_DAPM_MIC("Int Mic", NULL),
|
||||
SND_SOC_DAPM_SPK("Ext Spk", NULL),
|
||||
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
|
||||
platform_clock_control, SND_SOC_DAPM_POST_PMD),
|
||||
platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = {
|
||||
|
@ -109,12 +147,6 @@ static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = {
|
|||
{"Headphone", NULL, "HPOR"},
|
||||
{"Ext Spk", NULL, "SPOL"},
|
||||
{"Ext Spk", NULL, "SPOR"},
|
||||
{"AIF1 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, "AIF1 Capture"},
|
||||
{"Headphone", NULL, "Platform Clock"},
|
||||
{"Headset Mic", NULL, "Platform Clock"},
|
||||
{"Int Mic", NULL, "Platform Clock"},
|
||||
|
@ -130,16 +162,42 @@ static const struct snd_soc_dapm_route cht_rt5650_audio_map[] = {
|
|||
{"Headphone", NULL, "HPOR"},
|
||||
{"Ext Spk", NULL, "SPOL"},
|
||||
{"Ext Spk", NULL, "SPOR"},
|
||||
{"Headphone", NULL, "Platform Clock"},
|
||||
{"Headset Mic", NULL, "Platform Clock"},
|
||||
{"Int Mic", NULL, "Platform Clock"},
|
||||
{"Ext Spk", NULL, "Platform Clock"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cht_rt5645_ssp2_aif1_map[] = {
|
||||
{"AIF1 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, "AIF1 Capture"},
|
||||
{"Headphone", NULL, "Platform Clock"},
|
||||
{"Headset Mic", NULL, "Platform Clock"},
|
||||
{"Int Mic", NULL, "Platform Clock"},
|
||||
{"Ext Spk", NULL, "Platform Clock"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cht_rt5645_ssp2_aif2_map[] = {
|
||||
{"AIF2 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, "AIF2 Capture"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cht_rt5645_ssp0_aif1_map[] = {
|
||||
{"AIF1 Playback", NULL, "ssp0 Tx"},
|
||||
{"ssp0 Tx", NULL, "modem_out"},
|
||||
{"modem_in", NULL, "ssp0 Rx" },
|
||||
{"ssp0 Rx", NULL, "AIF1 Capture"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cht_rt5645_ssp0_aif2_map[] = {
|
||||
{"AIF2 Playback", NULL, "ssp0 Tx"},
|
||||
{"ssp0 Tx", NULL, "modem_out"},
|
||||
{"modem_in", NULL, "ssp0 Rx" },
|
||||
{"ssp0 Rx", NULL, "AIF2 Capture"},
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new cht_mc_controls[] = {
|
||||
|
@ -185,29 +243,66 @@ static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* uncomment when we have a real quirk
|
||||
static int cht_rt5645_quirk_cb(const struct dmi_system_id *id)
|
||||
{
|
||||
cht_rt5645_quirk = (unsigned long)id->driver_data;
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
static const struct dmi_system_id cht_rt5645_quirk_table[] = {
|
||||
{
|
||||
},
|
||||
};
|
||||
|
||||
static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
|
||||
{
|
||||
int ret;
|
||||
int jack_type;
|
||||
struct snd_soc_codec *codec = runtime->codec;
|
||||
struct snd_soc_dai *codec_dai = runtime->codec_dai;
|
||||
struct snd_soc_card *card = runtime->card;
|
||||
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
|
||||
|
||||
/* Select clk_i2s1_asrc as ASRC clock source */
|
||||
rt5645_sel_asrc_clk_src(codec,
|
||||
RT5645_DA_STEREO_FILTER |
|
||||
RT5645_DA_MONO_L_FILTER |
|
||||
RT5645_DA_MONO_R_FILTER |
|
||||
RT5645_AD_STEREO_FILTER,
|
||||
RT5645_CLK_SEL_I2S1_ASRC);
|
||||
|
||||
/* 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);
|
||||
if (ret < 0) {
|
||||
dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret);
|
||||
return ret;
|
||||
if ((cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) ||
|
||||
(cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) {
|
||||
/* Select clk_i2s2_asrc as ASRC clock source */
|
||||
rt5645_sel_asrc_clk_src(codec,
|
||||
RT5645_DA_STEREO_FILTER |
|
||||
RT5645_DA_MONO_L_FILTER |
|
||||
RT5645_DA_MONO_R_FILTER |
|
||||
RT5645_AD_STEREO_FILTER,
|
||||
RT5645_CLK_SEL_I2S2_ASRC);
|
||||
} else {
|
||||
/* Select clk_i2s1_asrc as ASRC clock source */
|
||||
rt5645_sel_asrc_clk_src(codec,
|
||||
RT5645_DA_STEREO_FILTER |
|
||||
RT5645_DA_MONO_L_FILTER |
|
||||
RT5645_DA_MONO_R_FILTER |
|
||||
RT5645_AD_STEREO_FILTER,
|
||||
RT5645_CLK_SEL_I2S1_ASRC);
|
||||
}
|
||||
|
||||
if (cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) {
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm,
|
||||
cht_rt5645_ssp2_aif2_map,
|
||||
ARRAY_SIZE(cht_rt5645_ssp2_aif2_map));
|
||||
} else if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) {
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm,
|
||||
cht_rt5645_ssp0_aif1_map,
|
||||
ARRAY_SIZE(cht_rt5645_ssp0_aif1_map));
|
||||
} else if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2) {
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm,
|
||||
cht_rt5645_ssp0_aif2_map,
|
||||
ARRAY_SIZE(cht_rt5645_ssp0_aif2_map));
|
||||
} else {
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm,
|
||||
cht_rt5645_ssp2_aif1_map,
|
||||
ARRAY_SIZE(cht_rt5645_ssp2_aif1_map));
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ctx->acpi_card->codec_type == CODEC_TYPE_RT5650)
|
||||
jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
|
||||
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
|
||||
|
@ -225,12 +320,33 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
|
|||
|
||||
rt5645_set_jack_detect(codec, &ctx->jack, &ctx->jack, &ctx->jack);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
int ret;
|
||||
struct snd_interval *rate = hw_param_interval(params,
|
||||
SNDRV_PCM_HW_PARAM_RATE);
|
||||
struct snd_interval *channels = hw_param_interval(params,
|
||||
|
@ -240,8 +356,67 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
|
|||
rate->min = rate->max = 48000;
|
||||
channels->min = channels->max = 2;
|
||||
|
||||
/* set SSP2 to 24-bit */
|
||||
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
|
||||
if ((cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) ||
|
||||
(cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) {
|
||||
|
||||
/* set SSP0 to 16-bit */
|
||||
params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
|
||||
|
||||
/*
|
||||
* Default mode for SSP configuration is TDM 4 slot, override config
|
||||
* with explicit setting to I2S 2ch 16-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_fmt(rtd->codec_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, 16);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* set SSP2 to 24-bit */
|
||||
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
|
||||
|
||||
/*
|
||||
* Default mode for SSP configuration is TDM 4 slot
|
||||
*/
|
||||
ret = snd_soc_dai_set_fmt(rtd->codec_dai,
|
||||
SND_SOC_DAIFMT_DSP_B |
|
||||
SND_SOC_DAIFMT_IB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set format to TDM %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
|
||||
ret = snd_soc_dai_set_tdm_slot(rtd->codec_dai, 0xF, 0xF, 4, 24);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set codec TDM slot %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -303,8 +478,6 @@ static struct snd_soc_dai_link cht_dailink[] = {
|
|||
.no_pcm = 1,
|
||||
.codec_dai_name = "rt5645-aif1",
|
||||
.codec_name = "i2c-10EC5645:00",
|
||||
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
|
||||
| SND_SOC_DAIFMT_CBS_CFS,
|
||||
.init = cht_codec_init,
|
||||
.be_hw_params_fixup = cht_codec_fixup,
|
||||
.nonatomic = true,
|
||||
|
@ -344,10 +517,31 @@ static struct snd_soc_card snd_soc_card_chtrt5650 = {
|
|||
static struct cht_acpi_card snd_soc_cards[] = {
|
||||
{"10EC5640", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
|
||||
{"10EC5645", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
|
||||
{"10EC5648", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
|
||||
{"10EC3270", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
|
||||
{"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650},
|
||||
};
|
||||
|
||||
static char cht_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
|
||||
static char cht_rt5645_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
|
||||
static char cht_rt5645_codec_aif_name[12]; /* = "rt5645-aif[1|2]" */
|
||||
static char cht_rt5645_cpu_dai_name[10]; /* = "ssp[0|2]-port" */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */
|
||||
u64 aif_value; /* 1: AIF1, 2: AIF2 */
|
||||
u64 mclock_value; /* usually 25MHz (0x17d7940), ignored */
|
||||
};
|
||||
|
||||
static int snd_cht_mc_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
@ -358,22 +552,33 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
|||
struct sst_acpi_mach *mach;
|
||||
const char *i2c_name = NULL;
|
||||
int dai_index = 0;
|
||||
bool found = false;
|
||||
bool is_bytcr = false;
|
||||
|
||||
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
|
||||
if (!drv)
|
||||
return -ENOMEM;
|
||||
|
||||
mach = (&pdev->dev)->platform_data;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(snd_soc_cards); i++) {
|
||||
if (acpi_dev_found(snd_soc_cards[i].codec_id)) {
|
||||
if (acpi_dev_found(snd_soc_cards[i].codec_id) &&
|
||||
(!strncmp(snd_soc_cards[i].codec_id, mach->id, 8))) {
|
||||
dev_dbg(&pdev->dev,
|
||||
"found codec %s\n", snd_soc_cards[i].codec_id);
|
||||
card = snd_soc_cards[i].soc_card;
|
||||
drv->acpi_card = &snd_soc_cards[i];
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
dev_err(&pdev->dev, "No matching HID found in supported list\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
mach = card->dev->platform_data;
|
||||
sprintf(drv->codec_name, "i2c-%s:00", drv->acpi_card->codec_id);
|
||||
|
||||
/* set correct codec name */
|
||||
|
@ -386,9 +591,105 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
|||
/* fixup codec name based on HID */
|
||||
i2c_name = sst_acpi_find_name_from_hid(mach->id);
|
||||
if (i2c_name != NULL) {
|
||||
snprintf(cht_rt5640_codec_name, sizeof(cht_rt5640_codec_name),
|
||||
snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name),
|
||||
"%s%s", "i2c-", i2c_name);
|
||||
cht_dailink[dai_index].codec_name = cht_rt5640_codec_name;
|
||||
cht_dailink[dai_index].codec_name = cht_rt5645_codec_name;
|
||||
}
|
||||
|
||||
/*
|
||||
* swap SSP0 if bytcr is detected
|
||||
* (will be overridden if DMI quirk is detected)
|
||||
*/
|
||||
if (is_valleyview()) {
|
||||
struct sst_platform_info *p_info = mach->pdata;
|
||||
const struct sst_res_info *res_info = p_info->res_info;
|
||||
|
||||
if (res_info->acpi_ipc_irq_index == 0)
|
||||
is_bytcr = true;
|
||||
}
|
||||
|
||||
if (is_bytcr) {
|
||||
/*
|
||||
* Baytrail CR platforms may have CHAN package in BIOS, try
|
||||
* to find relevant routing quirk based as done on Windows
|
||||
* platforms. We have to read the information directly from the
|
||||
* BIOS, at this stage the card is not created and the links
|
||||
* with the codec driver/pdata are non-existent
|
||||
*/
|
||||
|
||||
struct acpi_chan_package chan_package;
|
||||
|
||||
/* format specified: 2 64-bit integers */
|
||||
struct acpi_buffer format = {sizeof("NN"), "NN"};
|
||||
struct acpi_buffer state = {0, NULL};
|
||||
struct sst_acpi_package_context pkg_ctx;
|
||||
bool pkg_found = false;
|
||||
|
||||
state.length = sizeof(chan_package);
|
||||
state.pointer = &chan_package;
|
||||
|
||||
pkg_ctx.name = "CHAN";
|
||||
pkg_ctx.length = 2;
|
||||
pkg_ctx.format = &format;
|
||||
pkg_ctx.state = &state;
|
||||
pkg_ctx.data_valid = false;
|
||||
|
||||
pkg_found = sst_acpi_find_package_from_hid(mach->id, &pkg_ctx);
|
||||
if (pkg_found) {
|
||||
if (chan_package.aif_value == 1) {
|
||||
dev_info(&pdev->dev, "BIOS Routing: AIF1 connected\n");
|
||||
cht_rt5645_quirk |= CHT_RT5645_SSP0_AIF1;
|
||||
} else if (chan_package.aif_value == 2) {
|
||||
dev_info(&pdev->dev, "BIOS Routing: AIF2 connected\n");
|
||||
cht_rt5645_quirk |= CHT_RT5645_SSP0_AIF2;
|
||||
} else {
|
||||
dev_info(&pdev->dev, "BIOS Routing isn't valid, ignored\n");
|
||||
pkg_found = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pkg_found) {
|
||||
/* no BIOS indications, assume SSP0-AIF2 connection */
|
||||
cht_rt5645_quirk |= CHT_RT5645_SSP0_AIF2;
|
||||
}
|
||||
}
|
||||
|
||||
/* check quirks before creating card */
|
||||
dmi_check_system(cht_rt5645_quirk_table);
|
||||
log_quirks(&pdev->dev);
|
||||
|
||||
if ((cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) ||
|
||||
(cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) {
|
||||
|
||||
/* fixup codec aif name */
|
||||
snprintf(cht_rt5645_codec_aif_name,
|
||||
sizeof(cht_rt5645_codec_aif_name),
|
||||
"%s", "rt5645-aif2");
|
||||
|
||||
cht_dailink[dai_index].codec_dai_name =
|
||||
cht_rt5645_codec_aif_name;
|
||||
}
|
||||
|
||||
if ((cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) ||
|
||||
(cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) {
|
||||
|
||||
/* fixup cpu dai name name */
|
||||
snprintf(cht_rt5645_cpu_dai_name,
|
||||
sizeof(cht_rt5645_cpu_dai_name),
|
||||
"%s", "ssp0-port");
|
||||
|
||||
cht_dailink[dai_index].cpu_dai_name =
|
||||
cht_rt5645_cpu_dai_name;
|
||||
}
|
||||
|
||||
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(card, drv);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
static struct snd_soc_jack skylake_headset;
|
||||
static struct snd_soc_card skylake_audio_card;
|
||||
static const struct snd_pcm_hw_constraint_list *dmic_constraints;
|
||||
static struct snd_soc_jack skylake_hdmi[3];
|
||||
|
||||
struct skl_hdmi_pcm {
|
||||
struct list_head head;
|
||||
|
@ -111,8 +112,8 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
|
|||
SND_SOC_DAPM_MIC("Headset Mic", NULL),
|
||||
SND_SOC_DAPM_SPK("Spk", NULL),
|
||||
SND_SOC_DAPM_MIC("SoC DMIC", NULL),
|
||||
SND_SOC_DAPM_SPK("DP", NULL),
|
||||
SND_SOC_DAPM_SPK("HDMI", NULL),
|
||||
SND_SOC_DAPM_SPK("DP1", NULL),
|
||||
SND_SOC_DAPM_SPK("DP2", NULL),
|
||||
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
|
||||
platform_clock_control, SND_SOC_DAPM_PRE_PMU |
|
||||
SND_SOC_DAPM_POST_PMD),
|
||||
|
@ -130,9 +131,6 @@ static const struct snd_soc_dapm_route skylake_map[] = {
|
|||
{ "MIC", NULL, "Headset Mic" },
|
||||
{ "DMic", NULL, "SoC DMIC" },
|
||||
|
||||
{"HDMI", NULL, "hif5 Output"},
|
||||
{"DP", NULL, "hif6 Output"},
|
||||
|
||||
/* CODEC BE connections */
|
||||
{ "HiFi Playback", NULL, "ssp0 Tx" },
|
||||
{ "ssp0 Tx", NULL, "codec0_out" },
|
||||
|
@ -603,19 +601,39 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
|||
},
|
||||
};
|
||||
|
||||
#define NAME_SIZE 32
|
||||
static int skylake_card_late_probe(struct snd_soc_card *card)
|
||||
{
|
||||
struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
struct skl_hdmi_pcm *pcm;
|
||||
int err;
|
||||
struct snd_soc_codec *codec = NULL;
|
||||
int err, i = 0;
|
||||
char jack_name[NAME_SIZE];
|
||||
|
||||
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
|
||||
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device);
|
||||
codec = pcm->codec_dai->codec;
|
||||
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;
|
||||
if (!codec)
|
||||
return -EINVAL;
|
||||
|
||||
return hdac_hdmi_jack_port_init(codec, &card->dapm);
|
||||
}
|
||||
|
||||
/* skylake audio machine driver for SPT + NAU88L25 */
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
static struct snd_soc_jack skylake_headset;
|
||||
static struct snd_soc_card skylake_audio_card;
|
||||
static const struct snd_pcm_hw_constraint_list *dmic_constraints;
|
||||
static struct snd_soc_jack skylake_hdmi[3];
|
||||
|
||||
struct skl_hdmi_pcm {
|
||||
struct list_head head;
|
||||
|
@ -115,8 +116,8 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
|
|||
SND_SOC_DAPM_SPK("Left Speaker", NULL),
|
||||
SND_SOC_DAPM_SPK("Right Speaker", NULL),
|
||||
SND_SOC_DAPM_MIC("SoC DMIC", NULL),
|
||||
SND_SOC_DAPM_SPK("DP", NULL),
|
||||
SND_SOC_DAPM_SPK("HDMI", NULL),
|
||||
SND_SOC_DAPM_SPK("DP1", NULL),
|
||||
SND_SOC_DAPM_SPK("DP2", NULL),
|
||||
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
|
||||
platform_clock_control, SND_SOC_DAPM_PRE_PMU |
|
||||
SND_SOC_DAPM_POST_PMD),
|
||||
|
@ -135,8 +136,6 @@ static const struct snd_soc_dapm_route skylake_map[] = {
|
|||
{"MIC", NULL, "Headset Mic"},
|
||||
{"DMic", NULL, "SoC DMIC"},
|
||||
|
||||
{"HDMI", NULL, "hif5 Output"},
|
||||
{"DP", NULL, "hif6 Output"},
|
||||
/* CODEC BE connections */
|
||||
{ "Left Playback", NULL, "ssp0 Tx"},
|
||||
{ "Right Playback", NULL, "ssp0 Tx"},
|
||||
|
@ -653,19 +652,39 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
|||
},
|
||||
};
|
||||
|
||||
#define NAME_SIZE 32
|
||||
static int skylake_card_late_probe(struct snd_soc_card *card)
|
||||
{
|
||||
struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
struct skl_hdmi_pcm *pcm;
|
||||
int err;
|
||||
struct snd_soc_codec *codec = NULL;
|
||||
int err, i = 0;
|
||||
char jack_name[NAME_SIZE];
|
||||
|
||||
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
|
||||
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device);
|
||||
codec = pcm->codec_dai->codec;
|
||||
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;
|
||||
if (!codec)
|
||||
return -EINVAL;
|
||||
|
||||
return hdac_hdmi_jack_port_init(codec, &card->dapm);
|
||||
}
|
||||
|
||||
/* skylake audio machine driver for SPT + NAU88L25 */
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "../../codecs/hdac_hdmi.h"
|
||||
|
||||
static struct snd_soc_jack skylake_headset;
|
||||
static struct snd_soc_jack skylake_hdmi[3];
|
||||
|
||||
struct skl_hdmi_pcm {
|
||||
struct list_head head;
|
||||
|
@ -94,10 +95,6 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = {
|
|||
{"DMIC1 Pin", NULL, "DMIC2"},
|
||||
{"DMic", NULL, "SoC DMIC"},
|
||||
|
||||
{"HDMI1", NULL, "hif5 Output"},
|
||||
{"HDMI2", NULL, "hif6 Output"},
|
||||
{"HDMI3", NULL, "hif7 Output"},
|
||||
|
||||
/* CODEC BE connections */
|
||||
{ "AIF1 Playback", NULL, "ssp0 Tx"},
|
||||
{ "ssp0 Tx", NULL, "codec0_out"},
|
||||
|
@ -458,19 +455,38 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
|
|||
},
|
||||
};
|
||||
|
||||
#define NAME_SIZE 32
|
||||
static int skylake_card_late_probe(struct snd_soc_card *card)
|
||||
{
|
||||
struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
struct skl_hdmi_pcm *pcm;
|
||||
int err;
|
||||
struct snd_soc_codec *codec = NULL;
|
||||
int err, i = 0;
|
||||
char jack_name[NAME_SIZE];
|
||||
|
||||
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
|
||||
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device);
|
||||
codec = pcm->codec_dai->codec;
|
||||
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;
|
||||
if (!codec)
|
||||
return -EINVAL;
|
||||
|
||||
return hdac_hdmi_jack_port_init(codec, &card->dapm);
|
||||
}
|
||||
|
||||
/* skylake audio machine driver for SPT + RT286S */
|
||||
|
|
|
@ -252,44 +252,44 @@ void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset,
|
|||
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced);
|
||||
|
||||
int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
|
||||
u32 target, u32 timeout, char *operation)
|
||||
u32 target, u32 time, char *operation)
|
||||
{
|
||||
int time, ret;
|
||||
u32 reg;
|
||||
bool done = false;
|
||||
unsigned long timeout;
|
||||
int k = 0, s = 500;
|
||||
|
||||
/*
|
||||
* we will poll for couple of ms using mdelay, if not successful
|
||||
* then go to longer sleep using usleep_range
|
||||
* split the loop into sleeps of varying resolution. more accurately,
|
||||
* the range of wakeups are:
|
||||
* Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms.
|
||||
* Phase 2:( 5ms to 10ms) : min sleep 0.5ms; max sleep 10ms
|
||||
* (usleep_range (500, 1000) and usleep_range(5000, 10000) are
|
||||
* both possible in this phase depending on whether k > 10 or not).
|
||||
* Phase 3: (beyond 10 ms) min sleep 5ms; max sleep 10ms.
|
||||
*/
|
||||
|
||||
/* check if set state successful */
|
||||
for (time = 0; time < 5; time++) {
|
||||
if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
mdelay(1);
|
||||
}
|
||||
timeout = jiffies + msecs_to_jiffies(time);
|
||||
while (((sst_dsp_shim_read_unlocked(ctx, offset) & mask) != target)
|
||||
&& time_before(jiffies, timeout)) {
|
||||
k++;
|
||||
if (k > 10)
|
||||
s = 5000;
|
||||
|
||||
if (done == false) {
|
||||
/* sleeping in 10ms steps so adjust timeout value */
|
||||
timeout /= 10;
|
||||
|
||||
for (time = 0; time < timeout; time++) {
|
||||
if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target)
|
||||
break;
|
||||
|
||||
usleep_range(5000, 10000);
|
||||
}
|
||||
usleep_range(s, 2*s);
|
||||
}
|
||||
|
||||
reg = sst_dsp_shim_read_unlocked(ctx, offset);
|
||||
dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s %s\n", reg, operation,
|
||||
(time < timeout) ? "successful" : "timedout");
|
||||
ret = time < timeout ? 0 : -ETIME;
|
||||
|
||||
return ret;
|
||||
if ((reg & mask) == target) {
|
||||
dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n",
|
||||
reg, operation);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s timedout\n",
|
||||
reg, operation);
|
||||
return -ETIME;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_register_poll);
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include "../common/sst-dsp.h"
|
||||
#include "../common/sst-dsp-priv.h"
|
||||
#include "skl-sst-ipc.h"
|
||||
#include "skl-tplg-interface.h"
|
||||
|
||||
#define BXT_BASEFW_TIMEOUT 3000
|
||||
#define BXT_INIT_TIMEOUT 500
|
||||
|
@ -52,7 +51,7 @@ static unsigned int bxt_get_errorcode(struct sst_dsp *ctx)
|
|||
}
|
||||
|
||||
static int
|
||||
bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo)
|
||||
bxt_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count)
|
||||
{
|
||||
struct snd_dma_buffer dmab;
|
||||
struct skl_sst *skl = ctx->thread_context;
|
||||
|
@ -61,11 +60,11 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo)
|
|||
int ret = 0, i, dma_id, stream_tag;
|
||||
|
||||
/* library indices start from 1 to N. 0 represents base FW */
|
||||
for (i = 1; i < minfo->lib_count; i++) {
|
||||
ret = request_firmware(&fw, minfo->lib[i].name, ctx->dev);
|
||||
for (i = 1; i < lib_count; i++) {
|
||||
ret = request_firmware(&fw, linfo[i].name, ctx->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Request lib %s failed:%d\n",
|
||||
minfo->lib[i].name, ret);
|
||||
linfo[i].name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -96,7 +95,7 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo)
|
|||
ret = skl_sst_ipc_load_library(&skl->ipc, dma_id, i);
|
||||
if (ret < 0)
|
||||
dev_err(ctx->dev, "IPC Load Lib for %s fail: %d\n",
|
||||
minfo->lib[i].name, ret);
|
||||
linfo[i].name, ret);
|
||||
|
||||
ctx->dsp_ops.trigger(ctx->dev, false, stream_tag);
|
||||
ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag);
|
||||
|
@ -119,8 +118,7 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo)
|
|||
static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
|
||||
const void *fwdata, u32 fwsize)
|
||||
{
|
||||
int stream_tag, ret, i;
|
||||
u32 reg;
|
||||
int stream_tag, ret;
|
||||
|
||||
stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab);
|
||||
if (stream_tag <= 0) {
|
||||
|
@ -153,23 +151,13 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
|
|||
}
|
||||
|
||||
/* Step 4: Wait for DONE Bit */
|
||||
for (i = BXT_INIT_TIMEOUT; i > 0; --i) {
|
||||
reg = sst_dsp_shim_read(ctx, SKL_ADSP_REG_HIPCIE);
|
||||
|
||||
if (reg & SKL_ADSP_REG_HIPCIE_DONE) {
|
||||
sst_dsp_shim_update_bits_forced(ctx,
|
||||
SKL_ADSP_REG_HIPCIE,
|
||||
ret = sst_dsp_register_poll(ctx, SKL_ADSP_REG_HIPCIE,
|
||||
SKL_ADSP_REG_HIPCIE_DONE,
|
||||
SKL_ADSP_REG_HIPCIE_DONE);
|
||||
break;
|
||||
}
|
||||
mdelay(1);
|
||||
}
|
||||
if (!i) {
|
||||
dev_info(ctx->dev, "Waiting for HIPCIE done, reg: 0x%x\n", reg);
|
||||
sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCIE,
|
||||
SKL_ADSP_REG_HIPCIE_DONE,
|
||||
SKL_ADSP_REG_HIPCIE_DONE);
|
||||
SKL_ADSP_REG_HIPCIE_DONE,
|
||||
BXT_INIT_TIMEOUT, "HIPCIE Done");
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Timout for Purge Request%d\n", ret);
|
||||
goto base_fw_load_failed;
|
||||
}
|
||||
|
||||
/* Step 5: power down core1 */
|
||||
|
@ -184,19 +172,10 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
|
|||
skl_ipc_op_int_enable(ctx);
|
||||
|
||||
/* Step 7: Wait for ROM init */
|
||||
for (i = BXT_INIT_TIMEOUT; i > 0; --i) {
|
||||
if (SKL_FW_INIT ==
|
||||
(sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS) &
|
||||
SKL_FW_STS_MASK)) {
|
||||
|
||||
dev_info(ctx->dev, "ROM loaded, continue FW loading\n");
|
||||
break;
|
||||
}
|
||||
mdelay(1);
|
||||
}
|
||||
if (!i) {
|
||||
dev_err(ctx->dev, "Timeout for ROM init, HIPCIE: 0x%x\n", reg);
|
||||
ret = -EIO;
|
||||
ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK,
|
||||
SKL_FW_INIT, BXT_INIT_TIMEOUT, "ROM Load");
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Timeout for ROM init, ret:%d\n", ret);
|
||||
goto base_fw_load_failed;
|
||||
}
|
||||
|
||||
|
@ -432,7 +411,6 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
|
|||
int ret;
|
||||
struct skl_ipc_dxstate_info dx;
|
||||
unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
|
||||
struct skl_dfw_manifest *minfo = &skl->manifest;
|
||||
|
||||
if (skl->fw_loaded == false) {
|
||||
skl->boot_complete = false;
|
||||
|
@ -442,8 +420,9 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (minfo->lib_count > 1) {
|
||||
ret = bxt_load_library(ctx, minfo);
|
||||
if (skl->lib_count > 1) {
|
||||
ret = bxt_load_library(ctx, skl->lib_info,
|
||||
skl->lib_count);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "reload libs failed: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -640,8 +619,9 @@ int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx)
|
|||
|
||||
skl_dsp_init_core_state(sst);
|
||||
|
||||
if (ctx->manifest.lib_count > 1) {
|
||||
ret = sst->fw_ops.load_library(sst, &ctx->manifest);
|
||||
if (ctx->lib_count > 1) {
|
||||
ret = sst->fw_ops.load_library(sst, ctx->lib_info,
|
||||
ctx->lib_count);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Load Library failed : %x\n", ret);
|
||||
return ret;
|
||||
|
|
|
@ -220,6 +220,13 @@ static const struct skl_dsp_ops dsp_ops[] = {
|
|||
.init_fw = bxt_sst_init_fw,
|
||||
.cleanup = bxt_sst_dsp_cleanup
|
||||
},
|
||||
{
|
||||
.id = 0x3198,
|
||||
.loader_ops = bxt_get_loader_ops,
|
||||
.init = bxt_sst_dsp_init,
|
||||
.init_fw = bxt_sst_init_fw,
|
||||
.cleanup = bxt_sst_dsp_cleanup
|
||||
},
|
||||
};
|
||||
|
||||
const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id)
|
||||
|
|
|
@ -102,14 +102,16 @@ static void dump_config(struct device *dev, u32 instance_id, u8 linktype,
|
|||
}
|
||||
|
||||
static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt,
|
||||
u32 instance_id, u8 link_type, u8 dirn)
|
||||
u32 instance_id, u8 link_type, u8 dirn, u8 dev_type)
|
||||
{
|
||||
dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d\n",
|
||||
epnt->virtual_bus_id, epnt->linktype, epnt->direction);
|
||||
dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d dev_type = %d\n",
|
||||
epnt->virtual_bus_id, epnt->linktype,
|
||||
epnt->direction, epnt->device_type);
|
||||
|
||||
if ((epnt->virtual_bus_id == instance_id) &&
|
||||
(epnt->linktype == link_type) &&
|
||||
(epnt->direction == dirn))
|
||||
(epnt->direction == dirn) &&
|
||||
(epnt->device_type == dev_type))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
@ -117,7 +119,8 @@ static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt,
|
|||
|
||||
struct nhlt_specific_cfg
|
||||
*skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type,
|
||||
u8 s_fmt, u8 num_ch, u32 s_rate, u8 dirn)
|
||||
u8 s_fmt, u8 num_ch, u32 s_rate,
|
||||
u8 dirn, u8 dev_type)
|
||||
{
|
||||
struct nhlt_fmt *fmt;
|
||||
struct nhlt_endpoint *epnt;
|
||||
|
@ -135,7 +138,8 @@ struct nhlt_specific_cfg
|
|||
dev_dbg(dev, "endpoint count =%d\n", nhlt->endpoint_count);
|
||||
|
||||
for (j = 0; j < nhlt->endpoint_count; j++) {
|
||||
if (skl_check_ep_match(dev, epnt, instance, link_type, dirn)) {
|
||||
if (skl_check_ep_match(dev, epnt, instance, link_type,
|
||||
dirn, dev_type)) {
|
||||
fmt = (struct nhlt_fmt *)(epnt->config.caps +
|
||||
epnt->config.size);
|
||||
sp_config = skl_get_specific_cfg(dev, fmt, num_ch,
|
||||
|
@ -189,9 +193,9 @@ int skl_get_dmic_geo(struct skl *skl)
|
|||
return dmic_geo;
|
||||
}
|
||||
|
||||
static void skl_nhlt_trim_space(struct skl *skl)
|
||||
static void skl_nhlt_trim_space(char *trim)
|
||||
{
|
||||
char *s = skl->tplg_name;
|
||||
char *s = trim;
|
||||
int cnt;
|
||||
int i;
|
||||
|
||||
|
@ -218,7 +222,43 @@ int skl_nhlt_update_topology_bin(struct skl *skl)
|
|||
skl->pci_id, nhlt->header.oem_id, nhlt->header.oem_table_id,
|
||||
nhlt->header.oem_revision, "-tplg.bin");
|
||||
|
||||
skl_nhlt_trim_space(skl);
|
||||
skl_nhlt_trim_space(skl->tplg_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t skl_nhlt_platform_id_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pci_dev *pci = to_pci_dev(dev);
|
||||
struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
|
||||
struct skl *skl = ebus_to_skl(ebus);
|
||||
struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
|
||||
char platform_id[32];
|
||||
|
||||
sprintf(platform_id, "%x-%.6s-%.8s-%d", skl->pci_id,
|
||||
nhlt->header.oem_id, nhlt->header.oem_table_id,
|
||||
nhlt->header.oem_revision);
|
||||
|
||||
skl_nhlt_trim_space(platform_id);
|
||||
return sprintf(buf, "%s\n", platform_id);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(platform_id, 0444, skl_nhlt_platform_id_show, NULL);
|
||||
|
||||
int skl_nhlt_create_sysfs(struct skl *skl)
|
||||
{
|
||||
struct device *dev = &skl->pci->dev;
|
||||
|
||||
if (sysfs_create_file(&dev->kobj, &dev_attr_platform_id.attr))
|
||||
dev_warn(dev, "Error creating sysfs entry\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void skl_nhlt_remove_sysfs(struct skl *skl)
|
||||
{
|
||||
struct device *dev = &skl->pci->dev;
|
||||
|
||||
sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr);
|
||||
}
|
||||
|
|
|
@ -137,6 +137,80 @@ static void skl_set_suspend_active(struct snd_pcm_substream *substream,
|
|||
skl->supend_active--;
|
||||
}
|
||||
|
||||
int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
|
||||
{
|
||||
struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
unsigned int format_val;
|
||||
struct hdac_stream *hstream;
|
||||
struct hdac_ext_stream *stream;
|
||||
int err;
|
||||
|
||||
hstream = snd_hdac_get_stream(bus, params->stream,
|
||||
params->host_dma_id + 1);
|
||||
if (!hstream)
|
||||
return -EINVAL;
|
||||
|
||||
stream = stream_to_hdac_ext_stream(hstream);
|
||||
snd_hdac_ext_stream_decouple(ebus, stream, true);
|
||||
|
||||
format_val = snd_hdac_calc_stream_format(params->s_freq,
|
||||
params->ch, params->format, 32, 0);
|
||||
|
||||
dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
|
||||
format_val, params->s_freq, params->ch, params->format);
|
||||
|
||||
snd_hdac_stream_reset(hdac_stream(stream));
|
||||
err = snd_hdac_stream_set_params(hdac_stream(stream), format_val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = snd_hdac_stream_setup(hdac_stream(stream));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
hdac_stream(stream)->prepared = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params)
|
||||
{
|
||||
struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
unsigned int format_val;
|
||||
struct hdac_stream *hstream;
|
||||
struct hdac_ext_stream *stream;
|
||||
struct hdac_ext_link *link;
|
||||
|
||||
hstream = snd_hdac_get_stream(bus, params->stream,
|
||||
params->link_dma_id + 1);
|
||||
if (!hstream)
|
||||
return -EINVAL;
|
||||
|
||||
stream = stream_to_hdac_ext_stream(hstream);
|
||||
snd_hdac_ext_stream_decouple(ebus, stream, true);
|
||||
format_val = snd_hdac_calc_stream_format(params->s_freq,
|
||||
params->ch, params->format, 24, 0);
|
||||
|
||||
dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
|
||||
format_val, params->s_freq, params->ch, params->format);
|
||||
|
||||
snd_hdac_ext_link_stream_reset(stream);
|
||||
|
||||
snd_hdac_ext_link_stream_setup(stream, format_val);
|
||||
|
||||
list_for_each_entry(link, &ebus->hlink_list, list) {
|
||||
if (link->index == params->link_index)
|
||||
snd_hdac_ext_link_set_stream_id(link,
|
||||
hstream->stream_tag);
|
||||
}
|
||||
|
||||
stream->link_prepared = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skl_pcm_open(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
|
@ -188,32 +262,6 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int skl_get_format(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
struct skl_dma_params *dma_params;
|
||||
struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
|
||||
int format_val = 0;
|
||||
|
||||
if ((ebus_to_hbus(ebus))->ppcap) {
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
||||
format_val = snd_hdac_calc_stream_format(runtime->rate,
|
||||
runtime->channels,
|
||||
runtime->format,
|
||||
32, 0);
|
||||
} else {
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
|
||||
dma_params = snd_soc_dai_get_dma_data(codec_dai, substream);
|
||||
if (dma_params)
|
||||
format_val = dma_params->format;
|
||||
}
|
||||
|
||||
return format_val;
|
||||
}
|
||||
|
||||
static int skl_be_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
|
@ -234,37 +282,19 @@ static int skl_be_prepare(struct snd_pcm_substream *substream,
|
|||
static int skl_pcm_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
|
||||
struct skl *skl = get_skl_ctx(dai->dev);
|
||||
unsigned int format_val;
|
||||
int err;
|
||||
struct skl_module_cfg *mconfig;
|
||||
|
||||
dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
|
||||
|
||||
mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
|
||||
|
||||
format_val = skl_get_format(substream, dai);
|
||||
dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n",
|
||||
hdac_stream(stream)->stream_tag, format_val);
|
||||
snd_hdac_stream_reset(hdac_stream(stream));
|
||||
|
||||
/* In case of XRUN recovery, reset the FW pipe to clean state */
|
||||
if (mconfig && (substream->runtime->status->state ==
|
||||
SNDRV_PCM_STATE_XRUN))
|
||||
skl_reset_pipe(skl->skl_sst, mconfig->pipe);
|
||||
|
||||
err = snd_hdac_stream_set_params(hdac_stream(stream), format_val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = snd_hdac_stream_setup(hdac_stream(stream));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
hdac_stream(stream)->prepared = 1;
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
|
@ -295,6 +325,7 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
p_params.s_freq = params_rate(params);
|
||||
p_params.host_dma_id = dma_id;
|
||||
p_params.stream = substream->stream;
|
||||
p_params.format = params_format(params);
|
||||
|
||||
m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream);
|
||||
if (m_cfg)
|
||||
|
@ -438,7 +469,6 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
if (!w->ignore_suspend) {
|
||||
skl_pcm_prepare(substream, dai);
|
||||
/*
|
||||
* enable DMA Resume enable bit for the stream, set the
|
||||
* dpib & lpib position to resume before starting the
|
||||
|
@ -447,7 +477,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
snd_hdac_ext_stream_drsm_enable(ebus, true,
|
||||
hdac_stream(stream)->index);
|
||||
snd_hdac_ext_stream_set_dpibr(ebus, stream,
|
||||
stream->dpib);
|
||||
stream->lpib);
|
||||
snd_hdac_ext_stream_set_lpib(stream, stream->lpib);
|
||||
}
|
||||
|
||||
|
@ -459,7 +489,6 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
* pipeline is started but there is a delay in starting the
|
||||
* DMA channel on the host.
|
||||
*/
|
||||
snd_hdac_ext_stream_decouple(ebus, stream, true);
|
||||
ret = skl_decoupled_trigger(substream, cmd);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -506,9 +535,10 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
|
|||
struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
|
||||
struct hdac_ext_stream *link_dev;
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
struct hdac_ext_dma_params *dma_params;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct skl_pipe_params p_params = {0};
|
||||
struct hdac_ext_link *link;
|
||||
int stream_tag;
|
||||
|
||||
link_dev = snd_hdac_ext_stream_assign(ebus, substream,
|
||||
HDAC_EXT_STREAM_TYPE_LINK);
|
||||
|
@ -517,16 +547,22 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
|
|||
|
||||
snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
|
||||
|
||||
link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name);
|
||||
if (!link)
|
||||
return -EINVAL;
|
||||
|
||||
stream_tag = hdac_stream(link_dev)->stream_tag;
|
||||
|
||||
/* set the stream tag in the codec dai dma params */
|
||||
dma_params = snd_soc_dai_get_dma_data(codec_dai, substream);
|
||||
if (dma_params)
|
||||
dma_params->stream_tag = hdac_stream(link_dev)->stream_tag;
|
||||
snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0);
|
||||
|
||||
p_params.s_fmt = snd_pcm_format_width(params_format(params));
|
||||
p_params.ch = params_channels(params);
|
||||
p_params.s_freq = params_rate(params);
|
||||
p_params.stream = substream->stream;
|
||||
p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1;
|
||||
p_params.link_dma_id = stream_tag - 1;
|
||||
p_params.link_index = link->index;
|
||||
p_params.format = params_format(params);
|
||||
|
||||
return skl_tplg_be_update_params(dai, &p_params);
|
||||
}
|
||||
|
@ -534,41 +570,15 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
|
|||
static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
|
||||
struct hdac_ext_stream *link_dev =
|
||||
snd_soc_dai_get_dma_data(dai, substream);
|
||||
unsigned int format_val = 0;
|
||||
struct skl_dma_params *dma_params;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct hdac_ext_link *link;
|
||||
struct skl *skl = get_skl_ctx(dai->dev);
|
||||
struct skl_module_cfg *mconfig = NULL;
|
||||
|
||||
dma_params = (struct skl_dma_params *)
|
||||
snd_soc_dai_get_dma_data(codec_dai, substream);
|
||||
if (dma_params)
|
||||
format_val = dma_params->format;
|
||||
dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d codec_dai_name=%s\n",
|
||||
hdac_stream(link_dev)->stream_tag, format_val, codec_dai->name);
|
||||
|
||||
link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name);
|
||||
if (!link)
|
||||
return -EINVAL;
|
||||
|
||||
snd_hdac_ext_link_stream_reset(link_dev);
|
||||
|
||||
/* In case of XRUN recovery, reset the FW pipe to clean state */
|
||||
mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream);
|
||||
if (mconfig && (substream->runtime->status->state ==
|
||||
SNDRV_PCM_STATE_XRUN))
|
||||
if (mconfig && !mconfig->pipe->passthru &&
|
||||
(substream->runtime->status->state == SNDRV_PCM_STATE_XRUN))
|
||||
skl_reset_pipe(skl->skl_sst, mconfig->pipe);
|
||||
|
||||
snd_hdac_ext_link_stream_setup(link_dev, format_val);
|
||||
|
||||
snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag);
|
||||
link_dev->link_prepared = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -583,10 +593,8 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
|
|||
dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
skl_link_pcm_prepare(substream, dai);
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
snd_hdac_ext_stream_decouple(ebus, stream, true);
|
||||
snd_hdac_ext_link_stream_start(link_dev);
|
||||
break;
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <sound/memalloc.h>
|
||||
#include "skl-sst-cldma.h"
|
||||
#include "skl-tplg-interface.h"
|
||||
#include "skl-topology.h"
|
||||
|
||||
struct sst_dsp;
|
||||
|
@ -145,7 +144,7 @@ struct skl_dsp_fw_ops {
|
|||
int (*load_fw)(struct sst_dsp *ctx);
|
||||
/* FW module parser/loader */
|
||||
int (*load_library)(struct sst_dsp *ctx,
|
||||
struct skl_dfw_manifest *minfo);
|
||||
struct skl_lib_info *linfo, int count);
|
||||
int (*parse_fw)(struct sst_dsp *ctx);
|
||||
int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id);
|
||||
int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id);
|
||||
|
@ -236,5 +235,4 @@ int skl_get_pvt_instance_id_map(struct skl_sst *ctx,
|
|||
void skl_freeup_uuid_list(struct skl_sst *ctx);
|
||||
|
||||
int skl_dsp_strip_extended_manifest(struct firmware *fw);
|
||||
|
||||
#endif /*__SKL_SST_DSP_H__*/
|
||||
|
|
|
@ -97,8 +97,9 @@ struct skl_sst {
|
|||
/* multi-core */
|
||||
struct skl_dsp_cores cores;
|
||||
|
||||
/* tplg manifest */
|
||||
struct skl_dfw_manifest manifest;
|
||||
/* library info */
|
||||
struct skl_lib_info lib_info[SKL_MAX_LIB];
|
||||
int lib_count;
|
||||
|
||||
/* Callback to update D0i3C register */
|
||||
void (*update_d0i3c)(struct device *dev, bool enable);
|
||||
|
|
|
@ -330,6 +330,31 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
|
|||
multiplier;
|
||||
}
|
||||
|
||||
static u8 skl_tplg_be_dev_type(int dev_type)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (dev_type) {
|
||||
case SKL_DEVICE_BT:
|
||||
ret = NHLT_DEVICE_BT;
|
||||
break;
|
||||
|
||||
case SKL_DEVICE_DMIC:
|
||||
ret = NHLT_DEVICE_DMIC;
|
||||
break;
|
||||
|
||||
case SKL_DEVICE_I2S:
|
||||
ret = NHLT_DEVICE_I2S;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = NHLT_DEVICE_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
|
||||
struct skl_sst *ctx)
|
||||
{
|
||||
|
@ -338,6 +363,7 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
|
|||
u32 ch, s_freq, s_fmt;
|
||||
struct nhlt_specific_cfg *cfg;
|
||||
struct skl *skl = get_skl_ctx(ctx->dev);
|
||||
u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
|
||||
|
||||
/* check if we already have blob */
|
||||
if (m_cfg->formats_config.caps_size > 0)
|
||||
|
@ -374,7 +400,7 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
|
|||
|
||||
/* update the blob based on virtual bus_id and default params */
|
||||
cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type,
|
||||
s_fmt, ch, s_freq, dir);
|
||||
s_fmt, ch, s_freq, dir, dev_type);
|
||||
if (cfg) {
|
||||
m_cfg->formats_config.caps_size = cfg->size;
|
||||
m_cfg->formats_config.caps = (u32 *) &cfg->caps;
|
||||
|
@ -496,6 +522,20 @@ static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int skl_tplg_module_prepare(struct skl_sst *ctx, struct skl_pipe *pipe,
|
||||
struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg)
|
||||
{
|
||||
switch (mcfg->dev_type) {
|
||||
case SKL_DEVICE_HDAHOST:
|
||||
return skl_pcm_host_dma_prepare(ctx->dev, pipe->p_params);
|
||||
|
||||
case SKL_DEVICE_HDALINK:
|
||||
return skl_pcm_link_dma_prepare(ctx->dev, pipe->p_params);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inside a pipe instance, we can have various modules. These modules need
|
||||
* to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
|
||||
|
@ -535,6 +575,11 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
|
|||
mconfig->m_state = SKL_MODULE_LOADED;
|
||||
}
|
||||
|
||||
/* prepare the DMA if the module is gateway cpr */
|
||||
ret = skl_tplg_module_prepare(ctx, pipe, w, mconfig);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* update blob if blob is null for be with default value */
|
||||
skl_tplg_update_be_blob(w, ctx);
|
||||
|
||||
|
@ -974,7 +1019,6 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
|
|||
struct skl_module_cfg *src_module = NULL, *dst_module;
|
||||
struct skl_sst *ctx = skl->skl_sst;
|
||||
struct skl_pipe *s_pipe = mconfig->pipe;
|
||||
int ret = 0;
|
||||
|
||||
if (s_pipe->state == SKL_PIPE_INVALID)
|
||||
return -EINVAL;
|
||||
|
@ -996,7 +1040,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
|
|||
src_module = dst_module;
|
||||
}
|
||||
|
||||
ret = skl_delete_pipe(ctx, mconfig->pipe);
|
||||
skl_delete_pipe(ctx, mconfig->pipe);
|
||||
|
||||
return skl_tplg_unload_pipe_modules(ctx, s_pipe);
|
||||
}
|
||||
|
@ -1207,6 +1251,7 @@ static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
|
|||
switch (mcfg->dev_type) {
|
||||
case SKL_DEVICE_HDALINK:
|
||||
pipe->p_params->link_dma_id = params->link_dma_id;
|
||||
pipe->p_params->link_index = params->link_index;
|
||||
break;
|
||||
|
||||
case SKL_DEVICE_HDAHOST:
|
||||
|
@ -1220,6 +1265,7 @@ static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
|
|||
pipe->p_params->ch = params->ch;
|
||||
pipe->p_params->s_freq = params->s_freq;
|
||||
pipe->p_params->stream = params->stream;
|
||||
pipe->p_params->format = params->format;
|
||||
|
||||
} else {
|
||||
memcpy(pipe->p_params, params, sizeof(*params));
|
||||
|
@ -1428,6 +1474,7 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
|
|||
struct nhlt_specific_cfg *cfg;
|
||||
struct skl *skl = get_skl_ctx(dai->dev);
|
||||
int link_type = skl_tplg_be_link_type(mconfig->dev_type);
|
||||
u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type);
|
||||
|
||||
skl_tplg_fill_dma_id(mconfig, params);
|
||||
|
||||
|
@ -1437,7 +1484,8 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
|
|||
/* update the blob based on virtual bus_id*/
|
||||
cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
|
||||
params->s_fmt, params->ch,
|
||||
params->s_freq, params->stream);
|
||||
params->s_freq, params->stream,
|
||||
dev_type);
|
||||
if (cfg) {
|
||||
mconfig->formats_config.caps_size = cfg->size;
|
||||
mconfig->formats_config.caps = (u32 *) &cfg->caps;
|
||||
|
@ -2280,20 +2328,21 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
|
|||
|
||||
static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
|
||||
struct snd_soc_tplg_vendor_string_elem *str_elem,
|
||||
struct skl_dfw_manifest *minfo)
|
||||
struct skl *skl)
|
||||
{
|
||||
int tkn_count = 0;
|
||||
static int ref_count;
|
||||
|
||||
switch (str_elem->token) {
|
||||
case SKL_TKN_STR_LIB_NAME:
|
||||
if (ref_count > minfo->lib_count - 1) {
|
||||
if (ref_count > skl->skl_sst->lib_count - 1) {
|
||||
ref_count = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
strncpy(minfo->lib[ref_count].name, str_elem->string,
|
||||
ARRAY_SIZE(minfo->lib[ref_count].name));
|
||||
strncpy(skl->skl_sst->lib_info[ref_count].name,
|
||||
str_elem->string,
|
||||
ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name));
|
||||
ref_count++;
|
||||
tkn_count++;
|
||||
break;
|
||||
|
@ -2308,14 +2357,14 @@ static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
|
|||
|
||||
static int skl_tplg_get_str_tkn(struct device *dev,
|
||||
struct snd_soc_tplg_vendor_array *array,
|
||||
struct skl_dfw_manifest *minfo)
|
||||
struct skl *skl)
|
||||
{
|
||||
int tkn_count = 0, ret;
|
||||
struct snd_soc_tplg_vendor_string_elem *str_elem;
|
||||
|
||||
str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value;
|
||||
while (tkn_count < array->num_elems) {
|
||||
ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, minfo);
|
||||
ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl);
|
||||
str_elem++;
|
||||
|
||||
if (ret < 0)
|
||||
|
@ -2329,13 +2378,13 @@ static int skl_tplg_get_str_tkn(struct device *dev,
|
|||
|
||||
static int skl_tplg_get_int_tkn(struct device *dev,
|
||||
struct snd_soc_tplg_vendor_value_elem *tkn_elem,
|
||||
struct skl_dfw_manifest *minfo)
|
||||
struct skl *skl)
|
||||
{
|
||||
int tkn_count = 0;
|
||||
|
||||
switch (tkn_elem->token) {
|
||||
case SKL_TKN_U32_LIB_COUNT:
|
||||
minfo->lib_count = tkn_elem->value;
|
||||
skl->skl_sst->lib_count = tkn_elem->value;
|
||||
tkn_count++;
|
||||
break;
|
||||
|
||||
|
@ -2352,7 +2401,7 @@ static int skl_tplg_get_int_tkn(struct device *dev,
|
|||
* type.
|
||||
*/
|
||||
static int skl_tplg_get_manifest_tkn(struct device *dev,
|
||||
char *pvt_data, struct skl_dfw_manifest *minfo,
|
||||
char *pvt_data, struct skl *skl,
|
||||
int block_size)
|
||||
{
|
||||
int tkn_count = 0, ret;
|
||||
|
@ -2368,7 +2417,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
|
|||
off += array->size;
|
||||
switch (array->type) {
|
||||
case SND_SOC_TPLG_TUPLE_TYPE_STRING:
|
||||
ret = skl_tplg_get_str_tkn(dev, array, minfo);
|
||||
ret = skl_tplg_get_str_tkn(dev, array, skl);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -2390,7 +2439,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
|
|||
|
||||
while (tkn_count <= array->num_elems - 1) {
|
||||
ret = skl_tplg_get_int_tkn(dev,
|
||||
tkn_elem, minfo);
|
||||
tkn_elem, skl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -2411,7 +2460,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
|
|||
* preceded by descriptors for type and size of data block.
|
||||
*/
|
||||
static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
|
||||
struct device *dev, struct skl_dfw_manifest *minfo)
|
||||
struct device *dev, struct skl *skl)
|
||||
{
|
||||
struct snd_soc_tplg_vendor_array *array;
|
||||
int num_blocks, block_size = 0, block_type, off = 0;
|
||||
|
@ -2454,7 +2503,7 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
|
|||
data = (manifest->priv.data + off);
|
||||
|
||||
if (block_type == SKL_TYPE_TUPLE) {
|
||||
ret = skl_tplg_get_manifest_tkn(dev, data, minfo,
|
||||
ret = skl_tplg_get_manifest_tkn(dev, data, skl,
|
||||
block_size);
|
||||
|
||||
if (ret < 0)
|
||||
|
@ -2472,27 +2521,23 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
|
|||
static int skl_manifest_load(struct snd_soc_component *cmpnt,
|
||||
struct snd_soc_tplg_manifest *manifest)
|
||||
{
|
||||
struct skl_dfw_manifest *minfo;
|
||||
struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
struct skl *skl = ebus_to_skl(ebus);
|
||||
int ret = 0;
|
||||
|
||||
/* proceed only if we have private data defined */
|
||||
if (manifest->priv.size == 0)
|
||||
return 0;
|
||||
|
||||
minfo = &skl->skl_sst->manifest;
|
||||
skl_tplg_get_manifest_data(manifest, bus->dev, skl);
|
||||
|
||||
skl_tplg_get_manifest_data(manifest, bus->dev, minfo);
|
||||
|
||||
if (minfo->lib_count > HDA_MAX_LIB) {
|
||||
if (skl->skl_sst->lib_count > SKL_MAX_LIB) {
|
||||
dev_err(bus->dev, "Exceeding max Library count. Got:%d\n",
|
||||
minfo->lib_count);
|
||||
ret = -EINVAL;
|
||||
skl->skl_sst->lib_count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_tplg_ops skl_tplg_ops = {
|
||||
|
|
|
@ -254,6 +254,8 @@ struct skl_pipe_params {
|
|||
u32 s_freq;
|
||||
u32 s_fmt;
|
||||
u8 linktype;
|
||||
snd_pcm_format_t format;
|
||||
int link_index;
|
||||
int stream;
|
||||
};
|
||||
|
||||
|
@ -332,6 +334,19 @@ struct skl_pipeline {
|
|||
struct list_head node;
|
||||
};
|
||||
|
||||
#define SKL_LIB_NAME_LENGTH 128
|
||||
#define SKL_MAX_LIB 16
|
||||
|
||||
struct skl_lib_info {
|
||||
char name[SKL_LIB_NAME_LENGTH];
|
||||
const struct firmware *fw;
|
||||
};
|
||||
|
||||
struct skl_manifest {
|
||||
u32 lib_count;
|
||||
struct skl_lib_info lib[SKL_MAX_LIB];
|
||||
};
|
||||
|
||||
static inline struct skl *get_skl_ctx(struct device *dev)
|
||||
{
|
||||
struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
|
||||
|
@ -383,4 +398,8 @@ int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size,
|
|||
struct skl_module_cfg *skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai,
|
||||
int stream);
|
||||
enum skl_bitdepth skl_get_bit_depth(int params);
|
||||
int skl_pcm_host_dma_prepare(struct device *dev,
|
||||
struct skl_pipe_params *params);
|
||||
int skl_pcm_link_dma_prepare(struct device *dev,
|
||||
struct skl_pipe_params *params);
|
||||
#endif
|
||||
|
|
|
@ -157,18 +157,6 @@ struct skl_dfw_algo_data {
|
|||
char params[0];
|
||||
} __packed;
|
||||
|
||||
#define LIB_NAME_LENGTH 128
|
||||
#define HDA_MAX_LIB 16
|
||||
|
||||
struct lib_info {
|
||||
char name[LIB_NAME_LENGTH];
|
||||
} __packed;
|
||||
|
||||
struct skl_dfw_manifest {
|
||||
u32 lib_count;
|
||||
struct lib_info lib[HDA_MAX_LIB];
|
||||
} __packed;
|
||||
|
||||
enum skl_tkn_dir {
|
||||
SKL_DIR_IN,
|
||||
SKL_DIR_OUT
|
||||
|
|
|
@ -732,6 +732,10 @@ static int skl_probe(struct pci_dev *pci,
|
|||
goto out_display_power_off;
|
||||
}
|
||||
|
||||
err = skl_nhlt_create_sysfs(skl);
|
||||
if (err < 0)
|
||||
goto out_nhlt_free;
|
||||
|
||||
skl_nhlt_update_topology_bin(skl);
|
||||
|
||||
pci_set_drvdata(skl->pci, ebus);
|
||||
|
@ -852,6 +856,7 @@ static void skl_remove(struct pci_dev *pci)
|
|||
skl_free_dsp(skl);
|
||||
skl_machine_device_unregister(skl);
|
||||
skl_dmic_device_unregister(skl);
|
||||
skl_nhlt_remove_sysfs(skl);
|
||||
skl_nhlt_free(skl->nhlt);
|
||||
skl_free(ebus);
|
||||
dev_set_drvdata(&pci->dev, NULL);
|
||||
|
@ -878,6 +883,10 @@ static struct sst_acpi_mach sst_kbl_devdata[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
static struct sst_acpi_mach sst_glk_devdata[] = {
|
||||
{ "INT343A", "glk_alc298s_i2s", "intel/dsp_fw_glk.bin", NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
/* PCI IDs */
|
||||
static const struct pci_device_id skl_ids[] = {
|
||||
/* Sunrise Point-LP */
|
||||
|
@ -889,6 +898,9 @@ static const struct pci_device_id skl_ids[] = {
|
|||
/* KBL */
|
||||
{ PCI_DEVICE(0x8086, 0x9D71),
|
||||
.driver_data = (unsigned long)&sst_kbl_devdata},
|
||||
/* GLK */
|
||||
{ PCI_DEVICE(0x8086, 0x3198),
|
||||
.driver_data = (unsigned long)&sst_glk_devdata},
|
||||
{ 0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, skl_ids);
|
||||
|
|
|
@ -118,7 +118,8 @@ int skl_platform_register(struct device *dev);
|
|||
struct nhlt_acpi_table *skl_nhlt_init(struct device *dev);
|
||||
void skl_nhlt_free(struct nhlt_acpi_table *addr);
|
||||
struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance,
|
||||
u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn);
|
||||
u8 link_type, u8 s_fmt, u8 no_ch,
|
||||
u32 s_rate, u8 dirn, u8 dev_type);
|
||||
|
||||
int skl_get_dmic_geo(struct skl *skl);
|
||||
int skl_nhlt_update_topology_bin(struct skl *skl);
|
||||
|
@ -130,5 +131,7 @@ int skl_resume_dsp(struct skl *skl);
|
|||
void skl_cleanup_resources(struct skl *skl);
|
||||
const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id);
|
||||
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);
|
||||
|
||||
#endif /* __SOUND_SOC_SKL_H */
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <linux/ctype.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/pcm.h>
|
||||
|
@ -1888,6 +1889,139 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt);
|
||||
|
||||
|
||||
/* Trim special characters, and replace '-' with '_' since '-' is used to
|
||||
* separate different DMI fields in the card long name. Only number and
|
||||
* alphabet characters and a few separator characters are kept.
|
||||
*/
|
||||
static void cleanup_dmi_name(char *name)
|
||||
{
|
||||
int i, j = 0;
|
||||
|
||||
for (i = 0; name[i]; i++) {
|
||||
if (isalnum(name[i]) || (name[i] == '.')
|
||||
|| (name[i] == '_'))
|
||||
name[j++] = name[i];
|
||||
else if (name[i] == '-')
|
||||
name[j++] = '_';
|
||||
}
|
||||
|
||||
name[j] = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_set_dmi_name() - Register DMI names to card
|
||||
* @card: The card to register DMI names
|
||||
* @flavour: The flavour "differentiator" for the card amongst its peers.
|
||||
*
|
||||
* An Intel machine driver may be used by many different devices but are
|
||||
* difficult for userspace to differentiate, since machine drivers ususally
|
||||
* use their own name as the card short name and leave the card long name
|
||||
* blank. To differentiate such devices and fix bugs due to lack of
|
||||
* device-specific configurations, this function allows DMI info to be used
|
||||
* as the sound card long name, in the format of
|
||||
* "vendor-product-version-board"
|
||||
* (Character '-' is used to separate different DMI fields here).
|
||||
* This will help the user space to load the device-specific Use Case Manager
|
||||
* (UCM) configurations for the card.
|
||||
*
|
||||
* Possible card long names may be:
|
||||
* DellInc.-XPS139343-01-0310JH
|
||||
* ASUSTeKCOMPUTERINC.-T100TA-1.0-T100TA
|
||||
* Circuitco-MinnowboardMaxD0PLATFORM-D0-MinnowBoardMAX
|
||||
*
|
||||
* This function also supports flavoring the card longname to provide
|
||||
* the extra differentiation, like "vendor-product-version-board-flavor".
|
||||
*
|
||||
* We only keep number and alphabet characters and a few separator characters
|
||||
* in the card long name since UCM in the user space uses the card long names
|
||||
* as card configuration directory names and AudoConf cannot support special
|
||||
* charactors like SPACE.
|
||||
*
|
||||
* Returns 0 on success, otherwise a negative error code.
|
||||
*/
|
||||
int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
|
||||
{
|
||||
const char *vendor, *product, *product_version, *board;
|
||||
size_t longname_buf_size = sizeof(card->snd_card->longname);
|
||||
size_t len;
|
||||
|
||||
if (card->long_name)
|
||||
return 0; /* long name already set by driver or from DMI */
|
||||
|
||||
/* make up dmi long name as: vendor.product.version.board */
|
||||
vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
|
||||
if (!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) {
|
||||
len = strlen(card->dmi_longname);
|
||||
snprintf(card->dmi_longname + len,
|
||||
longname_buf_size - len,
|
||||
"-%s", product);
|
||||
|
||||
len++; /* skip the separator "-" */
|
||||
if (len < longname_buf_size)
|
||||
cleanup_dmi_name(card->dmi_longname + len);
|
||||
|
||||
/* some vendors like Lenovo may only put a self-explanatory
|
||||
* name in the product version field
|
||||
*/
|
||||
product_version = dmi_get_system_info(DMI_PRODUCT_VERSION);
|
||||
if (product_version) {
|
||||
len = strlen(card->dmi_longname);
|
||||
snprintf(card->dmi_longname + len,
|
||||
longname_buf_size - len,
|
||||
"-%s", product_version);
|
||||
|
||||
len++;
|
||||
if (len < longname_buf_size)
|
||||
cleanup_dmi_name(card->dmi_longname + len);
|
||||
}
|
||||
}
|
||||
|
||||
board = dmi_get_system_info(DMI_BOARD_NAME);
|
||||
if (board) {
|
||||
len = strlen(card->dmi_longname);
|
||||
snprintf(card->dmi_longname + len,
|
||||
longname_buf_size - len,
|
||||
"-%s", board);
|
||||
|
||||
len++;
|
||||
if (len < longname_buf_size)
|
||||
cleanup_dmi_name(card->dmi_longname + len);
|
||||
} else if (!product) {
|
||||
/* fall back to using legacy name */
|
||||
dev_warn(card->dev, "ASoC: no DMI board/product name!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add flavour to dmi long name */
|
||||
if (flavour) {
|
||||
len = strlen(card->dmi_longname);
|
||||
snprintf(card->dmi_longname + len,
|
||||
longname_buf_size - len,
|
||||
"-%s", flavour);
|
||||
|
||||
len++;
|
||||
if (len < longname_buf_size)
|
||||
cleanup_dmi_name(card->dmi_longname + len);
|
||||
}
|
||||
|
||||
/* set the card long name */
|
||||
card->long_name = card->dmi_longname;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name);
|
||||
|
||||
static int snd_soc_instantiate_card(struct snd_soc_card *card)
|
||||
{
|
||||
struct snd_soc_codec *codec;
|
||||
|
|
Loading…
Reference in a new issue