diff options
Diffstat (limited to 'sound')
68 files changed, 3108 insertions, 419 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 5088d4b8db22..009e6c98754e 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2492,7 +2492,7 @@ static int pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol, struct snd_pcm_substream *substream; const struct snd_pcm_chmap_elem *map; - if (snd_BUG_ON(!info->chmap)) + if (!info->chmap) return -EINVAL; substream = snd_pcm_chmap_substream(info, idx); if (!substream) @@ -2524,7 +2524,7 @@ static int pcm_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int __user *dst; int c, count = 0; - if (snd_BUG_ON(!info->chmap)) + if (!info->chmap) return -EINVAL; if (size < 8) return -ENOMEM; diff --git a/sound/core/timer.c b/sound/core/timer.c index 2f836ca09860..cd67d1c12cf1 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1618,6 +1618,7 @@ static int snd_timer_user_tselect(struct file *file, if (err < 0) goto __err; + tu->qhead = tu->qtail = tu->qused = 0; kfree(tu->queue); tu->queue = NULL; kfree(tu->tqueue); @@ -1959,6 +1960,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, tu = file->private_data; unit = tu->tread ? sizeof(struct snd_timer_tread) : sizeof(struct snd_timer_read); + mutex_lock(&tu->ioctl_lock); spin_lock_irq(&tu->qlock); while ((long)count - result >= unit) { while (!tu->qused) { @@ -1974,7 +1976,9 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, add_wait_queue(&tu->qchange_sleep, &wait); spin_unlock_irq(&tu->qlock); + mutex_unlock(&tu->ioctl_lock); schedule(); + mutex_lock(&tu->ioctl_lock); spin_lock_irq(&tu->qlock); remove_wait_queue(&tu->qchange_sleep, &wait); @@ -1994,7 +1998,6 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, tu->qused--; spin_unlock_irq(&tu->qlock); - mutex_lock(&tu->ioctl_lock); if (tu->tread) { if (copy_to_user(buffer, &tu->tqueue[qhead], sizeof(struct snd_timer_tread))) @@ -2004,7 +2007,6 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, sizeof(struct snd_timer_read))) err = -EFAULT; } - mutex_unlock(&tu->ioctl_lock); spin_lock_irq(&tu->qlock); if (err < 0) @@ -2014,6 +2016,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, } _error: spin_unlock_irq(&tu->qlock); + mutex_unlock(&tu->ioctl_lock); return result > 0 ? result : err; } diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 9e6f54f8c45d..1e26854b3425 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -682,7 +682,9 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, cycle = increment_cycle_count(cycle, 1); if (s->handle_packet(s, 0, cycle, i) < 0) { s->packet_index = -1; - amdtp_stream_pcm_abort(s); + if (in_interrupt()) + amdtp_stream_pcm_abort(s); + WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN); return; } } @@ -734,7 +736,9 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, /* Queueing error or detecting invalid payload. */ if (i < packets) { s->packet_index = -1; - amdtp_stream_pcm_abort(s); + if (in_interrupt()) + amdtp_stream_pcm_abort(s); + WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN); return; } diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 7e8831722821..ea1a91e99875 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -135,7 +135,7 @@ struct amdtp_stream { /* For a PCM substream processing. */ struct snd_pcm_substream *pcm; struct tasklet_struct period_tasklet; - unsigned int pcm_buffer_pointer; + snd_pcm_uframes_t pcm_buffer_pointer; unsigned int pcm_period_pointer; /* To wait for first packet. */ diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index d6fb2d5d01a7..60ce1cfc300f 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -295,6 +295,8 @@ struct hda_codec { #define list_for_each_codec(c, bus) \ list_for_each_entry(c, &(bus)->core.codec_list, core.list) +#define list_for_each_codec_safe(c, n, bus) \ + list_for_each_entry_safe(c, n, &(bus)->core.codec_list, core.list) /* snd_hda_codec_read/write optional flags */ #define HDA_RW_NO_RESPONSE_FALLBACK (1 << 0) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 3715a5725613..1c60beb5b70a 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1337,8 +1337,12 @@ EXPORT_SYMBOL_GPL(azx_probe_codecs); /* configure each codec instance */ int azx_codec_configure(struct azx *chip) { - struct hda_codec *codec; - list_for_each_codec(codec, &chip->bus) { + struct hda_codec *codec, *next; + + /* use _safe version here since snd_hda_codec_configure() deregisters + * the device upon error and deletes itself from the bus list. + */ + list_for_each_codec_safe(codec, next, &chip->bus) { snd_hda_codec_configure(codec); } return 0; diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 2842c82363c0..71545b56b4c8 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -3174,6 +3174,7 @@ static int check_dyn_adc_switch(struct hda_codec *codec) spec->input_paths[i][nums]); spec->input_paths[i][nums] = spec->input_paths[i][n]; + spec->input_paths[i][n] = 0; } } nums++; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1770f085c2a6..01eb1dc7b5b3 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -370,10 +370,12 @@ enum { #define IS_KBL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d71) #define IS_KBL_H(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa2f0) #define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) +#define IS_BXT_T(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x1a98) #define IS_GLK(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x3198) -#define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci)) || \ - IS_KBL(pci) || IS_KBL_LP(pci) || IS_KBL_H(pci) || \ - IS_GLK(pci) +#define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348) +#define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci) || \ + IS_BXT_T(pci) || IS_KBL(pci) || IS_KBL_LP(pci) || \ + IS_KBL_H(pci) || IS_GLK(pci) || IS_CFL(pci)) static char *driver_short_names[] = { [AZX_DRIVER_ICH] = "HDA Intel", @@ -2378,6 +2380,9 @@ static const struct pci_device_id azx_ids[] = { /* Kabylake-H */ { PCI_DEVICE(0x8086, 0xa2f0), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, + /* Coffelake */ + { PCI_DEVICE(0x8086, 0xa348), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE}, /* Broxton-P(Apollolake) */ { PCI_DEVICE(0x8086, 0x5a98), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON }, diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 58df440013c5..cbeebc0a9711 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2324,10 +2324,11 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_MBA11_VREF), SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD), - SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD), - SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE), SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS), + SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD), + SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS), + SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX), SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD), @@ -2342,6 +2343,7 @@ static const struct hda_model_fixup alc882_fixup_models[] = { {.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"}, {.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"}, {.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"}, + {.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"}, {} }; @@ -5852,7 +5854,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1043, 0x10c0, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), + SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1043, 0x12a0, "ASUS X441UV", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC), @@ -5860,13 +5866,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A), SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), + SND_PCI_QUIRK(0x1043, 0x1a30, "ASUS X705UD", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC), - SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1043, 0x1bbd, "ASUS Z550MA", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1043, 0x12a0, "ASUS X441UV", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2), SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), @@ -6014,6 +6017,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"}, {.id = ALC292_FIXUP_TPT440, .name = "tpt440"}, {.id = ALC292_FIXUP_TPT460, .name = "tpt460"}, + {.id = ALC233_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"}, {} }; #define ALC225_STANDARD_PINS \ @@ -6465,8 +6469,11 @@ static int patch_alc269(struct hda_codec *codec) break; case 0x10ec0225: case 0x10ec0295: + spec->codec_variant = ALC269_TYPE_ALC225; + break; case 0x10ec0299: spec->codec_variant = ALC269_TYPE_ALC225; + spec->gen.mixer_nid = 0; /* no loopback on ALC299 */ break; case 0x10ec0234: case 0x10ec0274: @@ -7338,6 +7345,7 @@ static const struct hda_model_fixup alc662_fixup_models[] = { {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"}, {.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"}, {.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"}, + {.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"}, {} }; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index faa3d38bac0b..6cefdf6c0b75 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1559,6 +1559,8 @@ static const struct snd_pci_quirk stac9200_fixup_tbl[] = { "Dell Inspiron 1501", STAC_9200_DELL_M26), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6, "unknown Dell", STAC_9200_DELL_M26), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0201, + "Dell Latitude D430", STAC_9200_DELL_M22), /* Panasonic */ SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC), /* Gateway machines needs EAPD to be set on resume */ diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index 7ae46c2647d4..b7ef8c59b49a 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -301,6 +301,14 @@ static int atmel_classd_codec_probe(struct snd_soc_codec *codec) return 0; } +static int atmel_classd_codec_resume(struct snd_soc_codec *codec) +{ + struct snd_soc_card *card = snd_soc_codec_get_drvdata(codec); + struct atmel_classd *dd = snd_soc_card_get_drvdata(card); + + return regcache_sync(dd->regmap); +} + static struct regmap *atmel_classd_codec_get_remap(struct device *dev) { return dev_get_regmap(dev, NULL); @@ -308,6 +316,7 @@ static struct regmap *atmel_classd_codec_get_remap(struct device *dev) static struct snd_soc_codec_driver soc_codec_dev_classd = { .probe = atmel_classd_codec_probe, + .resume = atmel_classd_codec_resume, .get_regmap = atmel_classd_codec_get_remap, .component_driver = { .controls = atmel_classd_snd_controls, diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c index a72c7d642026..3a1393283156 100644 --- a/sound/soc/atmel/tse850-pcm5142.c +++ b/sound/soc/atmel/tse850-pcm5142.c @@ -227,7 +227,7 @@ int tse850_put_ana(struct snd_kcontrol *kctrl, static const char * const mux_text[] = { "Mixer", "Loop" }; static const struct soc_enum mux_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, mux_text); + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(mux_text), mux_text); static const struct snd_kcontrol_new mux1 = SOC_DAPM_ENUM_EXT("MUX1", mux_enum, tse850_get_mux1, tse850_put_mux1); @@ -252,7 +252,7 @@ static const char * const ana_text[] = { }; static const struct soc_enum ana_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 9, ana_text); + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(ana_text), ana_text); static const struct snd_kcontrol_new out = SOC_DAPM_ENUM_EXT("ANA", ana_enum, tse850_get_ana, tse850_put_ana); diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index b2dfddead227..987918628d5b 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -345,7 +345,7 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, if (ak4613_dai_fmt_matching(priv->iface, is_play, fmt, width)) iface = priv->iface; } else { - for (i = ARRAY_SIZE(ak4613_iface); i >= 0; i--) { + for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) { if (!ak4613_dai_fmt_matching(ak4613_iface + i, is_play, fmt, width)) diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index f8aef5869b03..5ff12e4116e5 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -162,6 +162,14 @@ static bool cs35l35_precious_register(struct device *dev, unsigned int reg) } } +static void cs35l35_reset(struct cs35l35_private *cs35l35) +{ + gpiod_set_value_cansleep(cs35l35->reset_gpio, 0); + usleep_range(2000, 2100); + gpiod_set_value_cansleep(cs35l35->reset_gpio, 1); + usleep_range(1000, 1100); +} + static int cs35l35_wait_for_pdn(struct cs35l35_private *cs35l35) { int ret; @@ -1454,7 +1462,7 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, } } - gpiod_set_value_cansleep(cs35l35->reset_gpio, 1); + cs35l35_reset(cs35l35); init_completion(&cs35l35->pdn_done); diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 6dd7578f0bb8..024d83fa6a7f 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -772,7 +772,7 @@ static int da7213_dai_event(struct snd_soc_dapm_widget *w, ++i; msleep(50); } - } while ((i < DA7213_SRM_CHECK_RETRIES) & (!srm_lock)); + } while ((i < DA7213_SRM_CHECK_RETRIES) && (!srm_lock)); if (!srm_lock) dev_warn(codec->dev, "SRM failed to lock\n"); diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index 6274d79c1353..1d1d10dd92ae 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -115,19 +115,21 @@ static void da7219_aad_hptest_work(struct work_struct *work) struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); u16 tonegen_freq_hptest; - u8 pll_srm_sts, gain_ramp_ctrl, accdet_cfg8; + u8 pll_srm_sts, pll_ctrl, gain_ramp_ctrl, accdet_cfg8; int report = 0, ret = 0; - /* Lock DAPM and any Kcontrols that are affected by this test */ + /* Lock DAPM, Kcontrols affected by this test and the PLL */ snd_soc_dapm_mutex_lock(dapm); - mutex_lock(&da7219->lock); + mutex_lock(&da7219->ctrl_lock); + mutex_lock(&da7219->pll_lock); /* Ensure MCLK is available for HP test procedure */ if (da7219->mclk) { ret = clk_prepare_enable(da7219->mclk); if (ret) { dev_err(codec->dev, "Failed to enable mclk - %d\n", ret); - mutex_unlock(&da7219->lock); + mutex_unlock(&da7219->pll_lock); + mutex_unlock(&da7219->ctrl_lock); snd_soc_dapm_mutex_unlock(dapm); return; } @@ -136,12 +138,21 @@ static void da7219_aad_hptest_work(struct work_struct *work) /* * If MCLK not present, then we're using the internal oscillator and * require different frequency settings to achieve the same result. + * + * If MCLK is present, but PLL is not enabled then we enable it here to + * ensure a consistent detection procedure. */ pll_srm_sts = snd_soc_read(codec, DA7219_PLL_SRM_STS); - if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) + if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) { tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ); - else + + pll_ctrl = snd_soc_read(codec, DA7219_PLL_CTRL); + if ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS) + da7219_set_pll(codec, DA7219_SYSCLK_PLL, + DA7219_PLL_FREQ_OUT_98304); + } else { tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC); + } /* Ensure gain ramping at fastest rate */ gain_ramp_ctrl = snd_soc_read(codec, DA7219_GAIN_RAMP_CTRL); @@ -302,11 +313,17 @@ static void da7219_aad_hptest_work(struct work_struct *work) snd_soc_update_bits(codec, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK, DA7219_HP_R_AMP_OE_MASK); + /* Restore PLL to previous configuration, if re-configured */ + if ((pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) && + ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS)) + da7219_set_pll(codec, DA7219_SYSCLK_MCLK, 0); + /* Remove MCLK, if previously enabled */ if (da7219->mclk) clk_disable_unprepare(da7219->mclk); - mutex_unlock(&da7219->lock); + mutex_unlock(&da7219->pll_lock); + mutex_unlock(&da7219->ctrl_lock); snd_soc_dapm_mutex_unlock(dapm); /* diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 99601627f83c..f71d72c22bfc 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -260,9 +260,9 @@ static int da7219_volsw_locked_get(struct snd_kcontrol *kcontrol, struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); int ret; - mutex_lock(&da7219->lock); + mutex_lock(&da7219->ctrl_lock); ret = snd_soc_get_volsw(kcontrol, ucontrol); - mutex_unlock(&da7219->lock); + mutex_unlock(&da7219->ctrl_lock); return ret; } @@ -274,9 +274,9 @@ static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol, struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); int ret; - mutex_lock(&da7219->lock); + mutex_lock(&da7219->ctrl_lock); ret = snd_soc_put_volsw(kcontrol, ucontrol); - mutex_unlock(&da7219->lock); + mutex_unlock(&da7219->ctrl_lock); return ret; } @@ -288,9 +288,9 @@ static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol, struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); int ret; - mutex_lock(&da7219->lock); + mutex_lock(&da7219->ctrl_lock); ret = snd_soc_get_enum_double(kcontrol, ucontrol); - mutex_unlock(&da7219->lock); + mutex_unlock(&da7219->ctrl_lock); return ret; } @@ -302,9 +302,9 @@ static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol, struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); int ret; - mutex_lock(&da7219->lock); + mutex_lock(&da7219->ctrl_lock); ret = snd_soc_put_enum_double(kcontrol, ucontrol); - mutex_unlock(&da7219->lock); + mutex_unlock(&da7219->ctrl_lock); return ret; } @@ -424,9 +424,9 @@ static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol, u16 val; int ret; - mutex_lock(&da7219->lock); + mutex_lock(&da7219->ctrl_lock); ret = regmap_raw_read(da7219->regmap, reg, &val, sizeof(val)); - mutex_unlock(&da7219->lock); + mutex_unlock(&da7219->ctrl_lock); if (ret) return ret; @@ -458,9 +458,9 @@ static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol, */ val = cpu_to_le16(ucontrol->value.integer.value[0]); - mutex_lock(&da7219->lock); + mutex_lock(&da7219->ctrl_lock); ret = regmap_raw_write(da7219->regmap, reg, &val, sizeof(val)); - mutex_unlock(&da7219->lock); + mutex_unlock(&da7219->ctrl_lock); return ret; } @@ -801,7 +801,7 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w, ++i; msleep(50); } - } while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock)); + } while ((i < DA7219_SRM_CHECK_RETRIES) & (!srm_lock)); if (!srm_lock) dev_warn(codec->dev, "SRM failed to lock\n"); @@ -1129,6 +1129,8 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, return -EINVAL; } + mutex_lock(&da7219->pll_lock); + switch (clk_id) { case DA7219_CLKSRC_MCLK_SQR: snd_soc_update_bits(codec, DA7219_PLL_CTRL, @@ -1141,6 +1143,7 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, break; default: dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id); + mutex_unlock(&da7219->pll_lock); return -EINVAL; } @@ -1152,19 +1155,20 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, if (ret) { dev_err(codec_dai->dev, "Failed to set clock rate %d\n", freq); + mutex_unlock(&da7219->pll_lock); return ret; } } da7219->mclk_rate = freq; + mutex_unlock(&da7219->pll_lock); + return 0; } -static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, - int source, unsigned int fref, unsigned int fout) +int da7219_set_pll(struct snd_soc_codec *codec, int source, unsigned int fout) { - struct snd_soc_codec *codec = codec_dai->codec; struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); u8 pll_ctrl, indiv_bits, indiv; @@ -1237,6 +1241,20 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, return 0; } +static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int fref, unsigned int fout) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); + int ret; + + mutex_lock(&da7219->pll_lock); + ret = da7219_set_pll(codec, source, fout); + mutex_unlock(&da7219->pll_lock); + + return ret; +} + static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; @@ -1741,7 +1759,8 @@ static int da7219_probe(struct snd_soc_codec *codec) unsigned int rev; int ret; - mutex_init(&da7219->lock); + mutex_init(&da7219->ctrl_lock); + mutex_init(&da7219->pll_lock); /* Regulator configuration */ ret = da7219_handle_supplies(codec); diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index 6baba7455fa1..8d6c3c8c8026 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -810,7 +810,8 @@ struct da7219_priv { bool wakeup_source; struct regulator_bulk_data supplies[DA7219_NUM_SUPPLIES]; struct regmap *regmap; - struct mutex lock; + struct mutex ctrl_lock; + struct mutex pll_lock; struct clk *mclk; unsigned int mclk_rate; @@ -821,4 +822,6 @@ struct da7219_priv { u8 gain_ramp_ctrl; }; +int da7219_set_pll(struct snd_soc_codec *codec, int source, unsigned int fout); + #endif /* __DA7219_H */ diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 9c365a7f758d..7899a2cdeb42 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -1108,6 +1108,13 @@ static const struct dmi_system_id force_combo_jack_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Kabylake Client platform") } }, + { + .ident = "Thinkpad Helix 2nd", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Helix 2nd") + } + }, { } }; diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 87844a45886a..206b41688d96 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3897,6 +3897,7 @@ static int rt5645_i2c_remove(struct i2c_client *i2c) cancel_delayed_work_sync(&rt5645->jack_detect_work); cancel_delayed_work_sync(&rt5645->rcclock_work); + del_timer_sync(&rt5645->btn_check_timer); snd_soc_unregister_codec(&i2c->dev); regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies); diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index a32508d7dcfd..a33202affeb1 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -2847,6 +2847,8 @@ static int rt5663_resume(struct snd_soc_codec *codec) regcache_cache_only(rt5663->regmap, false); regcache_sync(rt5663->regmap); + rt5663_irq(0, rt5663); + return 0; } #else @@ -3141,7 +3143,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5663->regmap, RT5663_DIG_MISC, RT5663_DIG_GATE_CTRL_MASK, RT5663_DIG_GATE_CTRL_EN); regmap_update_bits(rt5663->regmap, RT5663_AUTO_1MRC_CLK, - RT5663_IRQ_POW_SAV_MASK, RT5663_IRQ_POW_SAV_EN); + RT5663_IRQ_MANUAL_MASK, RT5663_IRQ_MANUAL_EN); regmap_update_bits(rt5663->regmap, RT5663_IRQ_1, RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN); regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, diff --git a/sound/soc/codecs/rt5663.h b/sound/soc/codecs/rt5663.h index d77fae619f2f..4621812c94d8 100644 --- a/sound/soc/codecs/rt5663.h +++ b/sound/soc/codecs/rt5663.h @@ -590,6 +590,10 @@ #define RT5663_IRQ_POW_SAV_JD1_SHIFT 14 #define RT5663_IRQ_POW_SAV_JD1_DIS (0x0 << 14) #define RT5663_IRQ_POW_SAV_JD1_EN (0x1 << 14) +#define RT5663_IRQ_MANUAL_MASK (0x1 << 8) +#define RT5663_IRQ_MANUAL_SHIFT 8 +#define RT5663_IRQ_MANUAL_DIS (0x0 << 8) +#define RT5663_IRQ_MANUAL_EN (0x1 << 8) /* IRQ Control 1 (0x00b6) */ #define RT5663_EN_CB_JD_MASK (0x1 << 3) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index e27c5a4a0a15..a5f15a104c47 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -1717,7 +1717,6 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = { SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), /* DSP */ SND_SOC_DAPM_PGA("TxDP_ADC", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -2086,13 +2085,13 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { { "IF1 ADC1 IN1 Mux", "IF1_ADC3", "IF1_ADC3" }, { "IF1 ADC1 IN2 Mux", "IF1_ADC1_IN1", "IF1 ADC1 IN1 Mux" }, - { "IF1 ADC1 IN2 Mux", "IF1_ADC4", "IF1_ADC4" }, + { "IF1 ADC1 IN2 Mux", "IF1_ADC4", "TxDP_ADC" }, { "IF1 ADC2 IN Mux", "IF_ADC2", "IF_ADC2" }, { "IF1 ADC2 IN Mux", "VAD_ADC", "VAD_ADC" }, { "IF1 ADC2 IN1 Mux", "IF1_ADC2_IN", "IF1 ADC2 IN Mux" }, - { "IF1 ADC2 IN1 Mux", "IF1_ADC4", "IF1_ADC4" }, + { "IF1 ADC2 IN1 Mux", "IF1_ADC4", "TxDP_ADC" }, { "IF1_ADC1" , NULL, "IF1 ADC1 IN2 Mux" }, { "IF1_ADC2" , NULL, "IF1 ADC2 IN1 Mux" }, @@ -2849,6 +2848,10 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Tablet B"), }, }, + {} +}; + +static const struct dmi_system_id dmi_platform_intel_bytcht_jdmode2[] = { { .ident = "Lenovo Thinkpad Tablet 10", .matches = { @@ -2883,6 +2886,11 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P; rt5670->pdata.dev_gpio = true; rt5670->pdata.jd_mode = 1; + } else if (dmi_check_system(dmi_platform_intel_bytcht_jdmode2)) { + rt5670->pdata.dmic_en = true; + rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P; + rt5670->pdata.dev_gpio = true; + rt5670->pdata.jd_mode = 2; } rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap); diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 65ac4518ad06..36e530a36c82 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -41,15 +41,6 @@ #define RT5677_PR_BASE (RT5677_PR_RANGE_BASE + (0 * RT5677_PR_SPACING)) -/* GPIO indexes defined by ACPI */ -enum { - RT5677_GPIO_PLUG_DET = 0, - RT5677_GPIO_MIC_PRESENT_L = 1, - RT5677_GPIO_HOTWORD_DET_L = 2, - RT5677_GPIO_DSP_INT = 3, - RT5677_GPIO_HP_AMP_SHDN_L = 4, -}; - static const struct regmap_range_cfg rt5677_ranges[] = { { .name = "PR", @@ -5030,7 +5021,6 @@ static const struct regmap_config rt5677_regmap = { static const struct i2c_device_id rt5677_i2c_id[] = { { "rt5677", RT5677 }, { "rt5676", RT5676 }, - { "RT5677CE:00", RT5677 }, { } }; MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); @@ -5041,28 +5031,19 @@ static const struct of_device_id rt5677_of_match[] = { }; MODULE_DEVICE_TABLE(of, rt5677_of_match); -static const struct acpi_gpio_params plug_det_gpio = { RT5677_GPIO_PLUG_DET, 0, false }; -static const struct acpi_gpio_params mic_present_gpio = { RT5677_GPIO_MIC_PRESENT_L, 0, false }; -static const struct acpi_gpio_params headphone_enable_gpio = { RT5677_GPIO_HP_AMP_SHDN_L, 0, false }; - -static const struct acpi_gpio_mapping bdw_rt5677_gpios[] = { - { "plug-det-gpios", &plug_det_gpio, 1 }, - { "mic-present-gpios", &mic_present_gpio, 1 }, - { "headphone-enable-gpios", &headphone_enable_gpio, 1 }, - { NULL }, +#ifdef CONFIG_ACPI +static const struct acpi_device_id rt5677_acpi_match[] = { + { "RT5677CE", RT5677 }, + { } }; +MODULE_DEVICE_TABLE(acpi, rt5677_acpi_match); +#endif static void rt5677_read_acpi_properties(struct rt5677_priv *rt5677, struct device *dev) { - int ret; u32 val; - ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), - bdw_rt5677_gpios); - if (ret) - dev_warn(dev, "Failed to add driver gpios\n"); - if (!device_property_read_u32(dev, "DCLK", &val)) rt5677->pdata.dmic2_clk_pin = val; @@ -5301,6 +5282,7 @@ static struct i2c_driver rt5677_i2c_driver = { .driver = { .name = "rt5677", .of_match_table = rt5677_of_match, + .acpi_match_table = ACPI_PTR(rt5677_acpi_match), }, .probe = rt5677_i2c_probe, .remove = rt5677_i2c_remove, diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index e86c6e16146b..1df69701eb12 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -202,7 +202,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) if (ret < 0) return ret; - ret = asoc_simple_card_init_mic(rtd->card, &priv->hp_jack, PREFIX); + ret = asoc_simple_card_init_mic(rtd->card, &priv->mic_jack, PREFIX); if (ret < 0) return ret; diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 67968ef3bbda..b301bfff1c09 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -214,6 +214,18 @@ config SND_SOC_INTEL_BYT_CHT_DA7213_MACH platforms with DA7212/7213 audio codec. If unsure select "N". +config SND_SOC_INTEL_BYT_CHT_ES8316_MACH + tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with ES8316 codec" + depends on X86_INTEL_LPSS && I2C && ACPI + select SND_SOC_ES8316 + select SND_SST_ATOM_HIFI2_PLATFORM + select SND_SST_IPC_ACPI + select SND_SOC_INTEL_SST_MATCH if ACPI + help + This adds support for ASoC machine driver for Intel(R) Baytrail & + Cherrytrail platforms with ES8316 audio codec. + If unsure select "N". + config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)" depends on X86_INTEL_LPSS && I2C && ACPI @@ -226,6 +238,36 @@ config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH connector If unsure select "N". +config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH + tristate "ASoC Audio driver for KBL with RT5663 and MAX98927 in I2S Mode" + depends on X86_INTEL_LPSS && I2C + select SND_SOC_INTEL_SST + select SND_SOC_INTEL_SKYLAKE + select SND_SOC_RT5663 + select SND_SOC_MAX98927 + select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC Onboard Codec I2S machine driver. This will + create an alsa sound card for RT5663 + MAX98927. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH + tristate "ASoC Audio driver for KBL with RT5663, RT5514 and MAX98927 in I2S Mode" + depends on X86_INTEL_LPSS && I2C + select SND_SOC_INTEL_SST + select SND_SOC_INTEL_SKYLAKE + select SND_SOC_RT5663 + select SND_SOC_RT5514 + select SND_SOC_MAX98927 + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC Onboard Codec I2S machine driver. This will + create an alsa sound card for RT5663 + RT5514 + MAX98927. + Say Y if you have such a device. + If unsure select "N". + config SND_SOC_INTEL_SKYLAKE tristate select SND_HDA_EXT_CORE diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 21cac1c8dd4c..b082b31023d5 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -690,7 +690,7 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) snd_dma_continuous_data(GFP_DMA), SST_MIN_BUFFER, SST_MAX_BUFFER); if (retval) { - dev_err(rtd->dev, "dma buffer allocationf fail\n"); + dev_err(rtd->dev, "dma buffer allocation failure\n"); return retval; } } diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index f9ba71315e33..8afdff457579 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -258,7 +258,7 @@ static ssize_t firmware_version_show(struct device *dev, } -DEVICE_ATTR_RO(firmware_version); +static DEVICE_ATTR_RO(firmware_version); static const struct attribute *sst_fw_version_attrs[] = { &dev_attr_firmware_version.attr, @@ -382,37 +382,6 @@ void sst_context_cleanup(struct intel_sst_drv *ctx) } EXPORT_SYMBOL_GPL(sst_context_cleanup); -static inline void sst_save_shim64(struct intel_sst_drv *ctx, - void __iomem *shim, - struct sst_shim_regs64 *shim_regs) -{ - unsigned long irq_flags; - - spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags); - - shim_regs->imrx = sst_shim_read64(shim, SST_IMRX); - shim_regs->csr = sst_shim_read64(shim, SST_CSR); - - - spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags); -} - -static inline void sst_restore_shim64(struct intel_sst_drv *ctx, - void __iomem *shim, - struct sst_shim_regs64 *shim_regs) -{ - unsigned long irq_flags; - - /* - * we only need to restore IMRX for this case, rest will be - * initialize by FW or driver when firmware is loaded - */ - spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags); - sst_shim_write64(shim, SST_IMRX, shim_regs->imrx); - sst_shim_write64(shim, SST_CSR, shim_regs->csr); - spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags); -} - void sst_configure_runtime_pm(struct intel_sst_drv *ctx) { pm_runtime_set_autosuspend_delay(ctx->dev, SST_SUSPEND_DELAY); @@ -432,8 +401,6 @@ void sst_configure_runtime_pm(struct intel_sst_drv *ctx) pm_runtime_set_active(ctx->dev); else pm_runtime_put_noidle(ctx->dev); - - sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64); } EXPORT_SYMBOL_GPL(sst_configure_runtime_pm); @@ -457,8 +424,6 @@ static int intel_sst_runtime_suspend(struct device *dev) flush_workqueue(ctx->post_msg_wq); ctx->ops->reset(ctx); - /* save the shim registers because PMC doesn't save state */ - sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64); return ret; } @@ -499,23 +464,23 @@ static int intel_sst_suspend(struct device *dev) fw_save = kzalloc(sizeof(*fw_save), GFP_KERNEL); if (!fw_save) return -ENOMEM; - fw_save->iram = kzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL); + fw_save->iram = kvzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL); if (!fw_save->iram) { ret = -ENOMEM; goto iram; } - fw_save->dram = kzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL); + fw_save->dram = kvzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL); if (!fw_save->dram) { ret = -ENOMEM; goto dram; } - fw_save->sram = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL); + fw_save->sram = kvzalloc(SST_MAILBOX_SIZE, GFP_KERNEL); if (!fw_save->sram) { ret = -ENOMEM; goto sram; } - fw_save->ddr = kzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL); + fw_save->ddr = kvzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL); if (!fw_save->ddr) { ret = -ENOMEM; goto ddr; @@ -530,11 +495,11 @@ static int intel_sst_suspend(struct device *dev) ctx->ops->reset(ctx); return 0; ddr: - kfree(fw_save->sram); + kvfree(fw_save->sram); sram: - kfree(fw_save->dram); + kvfree(fw_save->dram); dram: - kfree(fw_save->iram); + kvfree(fw_save->iram); iram: kfree(fw_save); return ret; @@ -562,10 +527,10 @@ static int intel_sst_resume(struct device *dev) memcpy32_toio(ctx->mailbox, fw_save->sram, SST_MAILBOX_SIZE); memcpy32_toio(ctx->ddr, fw_save->ddr, ctx->ddr_end - ctx->ddr_base); - kfree(fw_save->sram); - kfree(fw_save->dram); - kfree(fw_save->iram); - kfree(fw_save->ddr); + kvfree(fw_save->sram); + kvfree(fw_save->dram); + kvfree(fw_save->iram); + kvfree(fw_save->ddr); kfree(fw_save); block = sst_create_block(ctx, 0, FW_DWNL_ID); diff --git a/sound/soc/intel/atom/sst/sst.h b/sound/soc/intel/atom/sst/sst.h index 5c9a51cc77aa..e02e2b4cc08f 100644 --- a/sound/soc/intel/atom/sst/sst.h +++ b/sound/soc/intel/atom/sst/sst.h @@ -317,31 +317,11 @@ struct sst_ipc_reg { int ipcd; }; -struct sst_shim_regs64 { - u64 csr; - u64 pisr; - u64 pimr; - u64 isrx; - u64 isrd; - u64 imrx; - u64 imrd; - u64 ipcx; - u64 ipcd; - u64 isrsc; - u64 isrlpesc; - u64 imrsc; - u64 imrlpesc; - u64 ipcsc; - u64 ipclpesc; - u64 clkctl; - u64 csr2; -}; - struct sst_fw_save { - void *iram; - void *dram; - void *sram; - void *ddr; + void *iram; /* allocated via kvmalloc() */ + void *dram; /* allocated via kvmalloc() */ + void *sram; /* allocated via kvmalloc() */ + void *ddr; /* allocated via kvmalloc() */ }; /** @@ -356,7 +336,6 @@ struct sst_fw_save { * @dram : SST DRAM pointer * @pdata : SST info passed as a part of pci platform data * @shim_phy_add : SST shim phy addr - * @shim_regs64: Struct to save shim registers * @ipc_dispatch_list : ipc messages dispatched * @rx_list : to copy the process_reply/process_msg from DSP * @ipc_post_msg_wq : wq to post IPC messages context @@ -398,7 +377,6 @@ struct intel_sst_drv { unsigned int ddr_end; unsigned int ddr_base; unsigned int mailbox_recv_offset; - struct sst_shim_regs64 *shim_regs64; struct list_head block_list; struct list_head ipc_dispatch_list; struct sst_platform_info *pdata; diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index dd250b8b26f2..0e928d54305d 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -303,8 +303,6 @@ static int sst_acpi_probe(struct platform_device *pdev) dev_err(dev, "No matching machine driver found\n"); return -ENODEV; } - if (mach->machine_quirk) - mach = mach->machine_quirk(mach); pdata = mach->pdata; @@ -360,23 +358,9 @@ static int sst_acpi_probe(struct platform_device *pdev) if (ret < 0) return ret; - /* need to save shim registers in BYT */ - ctx->shim_regs64 = devm_kzalloc(ctx->dev, sizeof(*ctx->shim_regs64), - GFP_KERNEL); - if (!ctx->shim_regs64) { - ret = -ENOMEM; - goto do_sst_cleanup; - } - sst_configure_runtime_pm(ctx); platform_set_drvdata(pdev, ctx); return ret; - -do_sst_cleanup: - sst_context_cleanup(ctx); - platform_set_drvdata(pdev, NULL); - dev_err(ctx->dev, "failed with %d\n", ret); - return ret; } /** @@ -453,12 +437,20 @@ static const struct dmi_system_id cht_table[] = { static struct sst_acpi_mach cht_surface_mach = { - "10EC5640", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, - &chv_platform_data }; + .id = "10EC5640", + .drv_name = "cht-bsw-rt5645", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "cht-bsw", + .pdata = &chv_platform_data, +}; static struct sst_acpi_mach byt_thinkpad_10 = { - "10EC5640", "cht-bsw-rt5672", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, - &byt_rvp_platform_data }; + .id = "10EC5640", + .drv_name = "cht-bsw-rt5672", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "cht-bsw", + .pdata = &byt_rvp_platform_data, +}; static struct sst_acpi_mach *cht_quirk(void *arg) { @@ -486,68 +478,182 @@ static struct sst_acpi_mach *byt_quirk(void *arg) static struct sst_acpi_mach sst_acpi_bytcr[] = { - {"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", byt_quirk, - &byt_rvp_platform_data }, - {"10EC5642", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, - &byt_rvp_platform_data }, - {"INTCCFFD", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, - &byt_rvp_platform_data }, - {"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL, - &byt_rvp_platform_data }, - {"DLGS7212", "bytcht_da7213", "intel/fw_sst_0f28.bin", "bytcht_da7213", NULL, - &byt_rvp_platform_data }, - {"DLGS7213", "bytcht_da7213", "intel/fw_sst_0f28.bin", "bytcht_da7213", NULL, - &byt_rvp_platform_data }, + { + .id = "10EC5640", + .drv_name = "bytcr_rt5640", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcr_rt5640", + .machine_quirk = byt_quirk, + .pdata = &byt_rvp_platform_data, + }, + { + .id = "10EC5642", + .drv_name = "bytcr_rt5640", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcr_rt5640", + .pdata = &byt_rvp_platform_data + }, + { + .id = "INTCCFFD", + .drv_name = "bytcr_rt5640", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcr_rt5640", + .pdata = &byt_rvp_platform_data + }, + { + .id = "10EC5651", + .drv_name = "bytcr_rt5651", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcr_rt5651", + .pdata = &byt_rvp_platform_data + }, + { + .id = "DLGS7212", + .drv_name = "bytcht_da7213", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcht_da7213", + .pdata = &byt_rvp_platform_data + }, + { + .id = "DLGS7213", + .drv_name = "bytcht_da7213", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcht_da7213", + .pdata = &byt_rvp_platform_data + }, /* some Baytrail platforms rely on RT5645, use CHT machine driver */ - {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, - &byt_rvp_platform_data }, - {"10EC5648", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, - &byt_rvp_platform_data }, + { + .id = "10EC5645", + .drv_name = "cht-bsw-rt5645", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "cht-bsw", + .pdata = &byt_rvp_platform_data + }, + { + .id = "10EC5648", + .drv_name = "cht-bsw-rt5645", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "cht-bsw", + .pdata = &byt_rvp_platform_data + }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) /* * This is always last in the table so that it is selected only when * enabled explicitly and there is no codec-related information in SSDT */ - {"80860F28", "bytcht_nocodec", "intel/fw_sst_0f28.bin", "bytcht_nocodec", NULL, - &byt_rvp_platform_data }, + { + .id = "80860F28", + .drv_name = "bytcht_nocodec", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcht_nocodec", + .pdata = &byt_rvp_platform_data + }, #endif {}, }; /* Cherryview-based platforms: CherryTrail and Braswell */ static struct sst_acpi_mach sst_acpi_chv[] = { - {"10EC5670", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, - &chv_platform_data }, - {"10EC5672", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, - &chv_platform_data }, - {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, - &chv_platform_data }, - {"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, - &chv_platform_data }, - {"10EC3270", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, - &chv_platform_data }, - - {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, - &chv_platform_data }, - {"DLGS7212", "bytcht_da7213", "intel/fw_sst_22a8.bin", "bytcht_da7213", NULL, - &chv_platform_data }, - {"DLGS7213", "bytcht_da7213", "intel/fw_sst_22a8.bin", "bytcht_da7213", NULL, - &chv_platform_data }, + { + .id = "10EC5670", + .drv_name = "cht-bsw-rt5672", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "cht-bsw", + .pdata = &chv_platform_data + }, + { + .id = "10EC5672", + .drv_name = "cht-bsw-rt5672", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "cht-bsw", + .pdata = &chv_platform_data + }, + { + .id = "10EC5645", + .drv_name = "cht-bsw-rt5645", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "cht-bsw", + .pdata = &chv_platform_data + }, + { + .id = "10EC5650", + .drv_name = "cht-bsw-rt5645", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "cht-bsw", + .pdata = &chv_platform_data + }, + { + .id = "10EC3270", + .drv_name = "cht-bsw-rt5645", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "cht-bsw", + .pdata = &chv_platform_data + }, + + { + .id = "193C9890", + .drv_name = "cht-bsw-max98090", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "cht-bsw", + .pdata = &chv_platform_data + }, + { + .id = "DLGS7212", + .drv_name = "bytcht_da7213", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "bytcht_da7213", + .pdata = &chv_platform_data + }, + { + .id = "DLGS7213", + .drv_name = "bytcht_da7213", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "bytcht_da7213", + .pdata = &chv_platform_data + }, + { + .id = "ESSX8316", + .drv_name = "bytcht_es8316", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "bytcht_es8316", + .pdata = &chv_platform_data + }, /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ - {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk, - &chv_platform_data }, - {"10EC3276", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", NULL, - &chv_platform_data }, + { + .id = "10EC5640", + .drv_name = "bytcr_rt5640", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "bytcr_rt5640", + .machine_quirk = cht_quirk, + .pdata = &chv_platform_data + }, + { + .id = "10EC3276", + .drv_name = "bytcr_rt5640", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "bytcr_rt5640", + .pdata = &chv_platform_data + }, /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */ - {"10EC5651", "bytcr_rt5651", "intel/fw_sst_22a8.bin", "bytcr_rt5651", NULL, - &chv_platform_data }, + { + .id = "10EC5651", + .drv_name = "bytcr_rt5651", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "bytcr_rt5651", + .pdata = &chv_platform_data + }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) /* * This is always last in the table so that it is selected only when * enabled explicitly and there is no codec-related information in SSDT */ - {"808622A8", "bytcht_nocodec", "intel/fw_sst_22a8.bin", "bytcht_nocodec", NULL, - &chv_platform_data }, + { + .id = "808622A8", + .drv_name = "bytcht_nocodec", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "bytcht_nocodec", + .pdata = &chv_platform_data + }, #endif {}, }; diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 56896e09445d..a5c5bc5732a2 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -11,7 +11,10 @@ snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o +snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o +snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o +snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o snd-soc-skl_rt286-objs := skl_rt286.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o @@ -29,7 +32,10 @@ obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o +obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o +obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o +obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 14d9693c1641..058b8ccedf02 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -16,6 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <linux/acpi.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/gpio/consumer.h> @@ -120,6 +121,26 @@ static struct snd_soc_jack_gpio mic_jack_gpio = { .invert = 1, }; +/* GPIO indexes defined by ACPI */ +enum { + RT5677_GPIO_PLUG_DET = 0, + RT5677_GPIO_MIC_PRESENT_L = 1, + RT5677_GPIO_HOTWORD_DET_L = 2, + RT5677_GPIO_DSP_INT = 3, + RT5677_GPIO_HP_AMP_SHDN_L = 4, +}; + +static const struct acpi_gpio_params plug_det_gpio = { RT5677_GPIO_PLUG_DET, 0, false }; +static const struct acpi_gpio_params mic_present_gpio = { RT5677_GPIO_MIC_PRESENT_L, 0, false }; +static const struct acpi_gpio_params headphone_enable_gpio = { RT5677_GPIO_HP_AMP_SHDN_L, 0, false }; + +static const struct acpi_gpio_mapping bdw_rt5677_gpios[] = { + { "plug-det-gpios", &plug_det_gpio, 1 }, + { "mic-present-gpios", &mic_present_gpio, 1 }, + { "headphone-enable-gpios", &headphone_enable_gpio, 1 }, + { NULL }, +}; + static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -184,6 +205,11 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) snd_soc_card_get_drvdata(rtd->card); struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + int ret; + + ret = devm_acpi_dev_add_driver_gpios(codec->dev, bdw_rt5677_gpios); + if (ret) + dev_warn(codec->dev, "Failed to add driver gpios\n"); /* Enable codec ASRC function for Stereo DAC/Stereo1 ADC/DMIC/I2S1. * The ASRC clock source is clk_i2s1_asrc. diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 3a8c4d954a91..ce35ec7884d1 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -89,11 +89,6 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, if (ret) dev_err(card->dev, "failed to stop PLL: %d\n", ret); } else if(SND_SOC_DAPM_EVENT_ON(event)) { - ret = snd_soc_dai_set_sysclk(codec_dai, - DA7219_CLKSRC_MCLK, 19200000, SND_SOC_CLOCK_IN); - if (ret) - dev_err(card->dev, "can't set codec sysclk configuration\n"); - ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM, 0, DA7219_PLL_FREQ_OUT_98304); if (ret) @@ -187,8 +182,17 @@ static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd, static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) { int ret; + struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_codec *codec = rtd->codec; + /* Configure sysclk for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 19200000, + SND_SOC_CLOCK_IN); + if (ret) { + dev_err(rtd->dev, "can't set codec sysclk configuration\n"); + return ret; + } + /* * Headset buttons map to the google Reference headset. * These can be configured by userspace. @@ -238,31 +242,31 @@ static int broxton_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static unsigned int rates[] = { +static const unsigned int rates[] = { 48000, }; -static struct snd_pcm_hw_constraint_list constraints_rates = { +static const struct snd_pcm_hw_constraint_list constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; -static unsigned int channels[] = { +static const unsigned int channels[] = { DUAL_CHANNEL, }; -static struct snd_pcm_hw_constraint_list constraints_channels = { +static const struct snd_pcm_hw_constraint_list constraints_channels = { .count = ARRAY_SIZE(channels), .list = channels, .mask = 0, }; -static unsigned int channels_quad[] = { +static const unsigned int channels_quad[] = { QUAD_CHANNEL, }; -static struct snd_pcm_hw_constraint_list constraints_channels_quad = { +static const struct snd_pcm_hw_constraint_list constraints_channels_quad = { .count = ARRAY_SIZE(channels_quad), .list = channels_quad, .mask = 0, diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 1a68d043c803..0c3a3cbcb884 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -207,11 +207,11 @@ static const struct snd_soc_ops broxton_rt298_ops = { .hw_params = broxton_rt298_hw_params, }; -static unsigned int rates[] = { +static const unsigned int rates[] = { 48000, }; -static struct snd_pcm_hw_constraint_list constraints_rates = { +static const struct snd_pcm_hw_constraint_list constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, @@ -222,19 +222,16 @@ static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd, { struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - if (params_channels(params) == 2) - channels->min = channels->max = 2; - else - channels->min = channels->max = 4; + channels->min = channels->max = 4; return 0; } -static unsigned int channels_dmic[] = { - 2, 4, +static const unsigned int channels_dmic[] = { + 1, 2, 3, 4, }; -static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { +static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { .count = ARRAY_SIZE(channels_dmic), .list = channels_dmic, .mask = 0, @@ -256,11 +253,11 @@ static const struct snd_soc_ops broxton_dmic_ops = { .startup = broxton_dmic_startup, }; -static unsigned int channels[] = { +static const unsigned int channels[] = { 2, }; -static struct snd_pcm_hw_constraint_list constraints_channels = { +static const struct snd_pcm_hw_constraint_list constraints_channels = { .count = ARRAY_SIZE(channels), .list = channels, .mask = 0, diff --git a/sound/soc/intel/boards/byt-max98090.c b/sound/soc/intel/boards/byt-max98090.c index d9f81b8d915d..047be7fa0ce9 100644 --- a/sound/soc/intel/boards/byt-max98090.c +++ b/sound/soc/intel/boards/byt-max98090.c @@ -67,20 +67,27 @@ static struct snd_soc_jack_pin hs_jack_pins[] = { static struct snd_soc_jack_gpio hs_jack_gpios[] = { { - .name = "hp-gpio", - .idx = 0, + .name = "hp", .report = SND_JACK_HEADPHONE | SND_JACK_LINEOUT, .debounce_time = 200, }, { - .name = "mic-gpio", - .idx = 1, + .name = "mic", .invert = 1, .report = SND_JACK_MICROPHONE, .debounce_time = 200, }, }; +static const struct acpi_gpio_params hp_gpios = { 0, 0, false }; +static const struct acpi_gpio_params mic_gpios = { 1, 0, false }; + +static const struct acpi_gpio_mapping acpi_byt_max98090_gpios[] = { + { "hp-gpios", &hp_gpios, 1 }, + { "mic-gpios", &mic_gpios, 1 }, + {}, +}; + static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime) { int ret; @@ -140,8 +147,9 @@ static struct snd_soc_card byt_max98090_card = { static int byt_max98090_probe(struct platform_device *pdev) { - int ret_val = 0; + struct device *dev = &pdev->dev; struct byt_max98090_private *priv; + int ret_val; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); if (!priv) { @@ -149,6 +157,10 @@ static int byt_max98090_probe(struct platform_device *pdev) return -ENOMEM; } + ret_val = devm_acpi_dev_add_driver_gpios(dev->parent, acpi_byt_max98090_gpios); + if (ret_val) + dev_dbg(dev, "Unable to add GPIO mapping table\n"); + byt_max98090_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&byt_max98090_card, priv); ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_max98090_card); @@ -158,7 +170,7 @@ static int byt_max98090_probe(struct platform_device *pdev) return ret_val; } - return ret_val; + return 0; } static int byt_max98090_remove(struct platform_device *pdev) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c new file mode 100644 index 000000000000..52635462dac6 --- /dev/null +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -0,0 +1,300 @@ +/* + * bytcht_es8316.c - ASoc Machine driver for Intel Baytrail/Cherrytrail + * platforms with Everest ES8316 SoC + * + * Copyright (C) 2017 Endless Mobile, Inc. + * Authors: David Yang <yangxiaohua@everest-semi.com>, + * Daniel Drake <drake@endlessm.com> + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <asm/platform_sst_audio.h> +#include <linux/clk.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include "../atom/sst-atom-controls.h" +#include "../common/sst-acpi.h" +#include "../common/sst-dsp.h" + +struct byt_cht_es8316_private { + struct clk *mclk; +}; + +#define CODEC_DAI1 "ES8316 HiFi" + +static inline struct snd_soc_dai *get_codec_dai(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + + list_for_each_entry(rtd, &card->rtd_list, list) { + if (!strncmp(rtd->codec_dai->name, CODEC_DAI1, + strlen(CODEC_DAI1))) + return rtd->codec_dai; + } + return NULL; +} + +static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + + /* + * The codec supports two analog microphone inputs. I have only + * tested MIC1. A DMIC route could also potentially be added + * if such functionality is found on another platform. + */ + SND_SOC_DAPM_MIC("Microphone 1", NULL), + SND_SOC_DAPM_MIC("Microphone 2", NULL), +}; + +static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { + {"MIC1", NULL, "Microphone 1"}, + {"MIC2", NULL, "Microphone 2"}, + + {"Headphone", NULL, "HPOL"}, + {"Headphone", NULL, "HPOR"}, + + {"Playback", NULL, "ssp2 Tx"}, + {"ssp2 Tx", NULL, "codec_out0"}, + {"ssp2 Tx", NULL, "codec_out1"}, + {"codec_in0", NULL, "ssp2 Rx" }, + {"codec_in1", NULL, "ssp2 Rx" }, + {"ssp2 Rx", NULL, "Capture"}, +}; + +static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Microphone 1"), + SOC_DAPM_PIN_SWITCH("Microphone 2"), +}; + +static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_card *card = runtime->card; + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); + int ret; + + card->dapm.idle_bias_off = true; + + /* + * The firmware might enable the clock at boot (this information + * may or may not be reflected in the enable clock register). + * To change the rate we must disable the clock first to cover these + * cases. Due to common clock framework restrictions that do not allow + * to disable a clock that has not been enabled, we need to enable + * the clock first. + */ + ret = clk_prepare_enable(priv->mclk); + if (!ret) + clk_disable_unprepare(priv->mclk); + + ret = clk_set_rate(priv->mclk, 19200000); + if (ret) + dev_err(card->dev, "unable to set MCLK rate\n"); + + ret = clk_prepare_enable(priv->mclk); + if (ret) + dev_err(card->dev, "unable to enable MCLK\n"); + + ret = snd_soc_dai_set_sysclk(runtime->codec_dai, 0, 19200000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec clock %d\n", ret); + return ret; + } + + return 0; +} + +static const struct snd_soc_pcm_stream byt_cht_es8316_dai_params = { + .formats = SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, +}; + +static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + int ret; + + /* The DSP will covert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP2 to 24-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + + /* + * Default mode for SSP configuration is TDM 4 slot, override config + * with explicit setting to I2S 2ch 24-bit. The word length is set with + * dai_set_tdm_slot() since there is no other API exposed + */ + ret = snd_soc_dai_set_fmt(rtd->cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS + ); + if (ret < 0) { + dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); + if (ret < 0) { + dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); + return ret; + } + + return 0; +} + +static int byt_cht_es8316_aif1_startup(struct snd_pcm_substream *substream) +{ + return snd_pcm_hw_constraint_single(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, 48000); +} + +static const struct snd_soc_ops byt_cht_es8316_aif1_ops = { + .startup = byt_cht_es8316_aif1_startup, +}; + +static struct snd_soc_dai_link byt_cht_es8316_dais[] = { + [MERR_DPCM_AUDIO] = { + .name = "Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "media-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &byt_cht_es8316_aif1_ops, + }, + + [MERR_DPCM_DEEP_BUFFER] = { + .name = "Deep-Buffer Audio Port", + .stream_name = "Deep-Buffer Audio", + .cpu_dai_name = "deepbuffer-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .ops = &byt_cht_es8316_aif1_ops, + }, + + [MERR_DPCM_COMPR] = { + .name = "Compressed Port", + .stream_name = "Compress", + .cpu_dai_name = "compress-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + }, + + /* back ends */ + { + /* Only SSP2 has been tested here, so BYT-CR platforms that + * require SSP0 will not work. + */ + .name = "SSP2-Codec", + .id = 1, + .cpu_dai_name = "ssp2-port", + .platform_name = "sst-mfld-platform", + .no_pcm = 1, + .codec_dai_name = "ES8316 HiFi", + .codec_name = "i2c-ESSX8316:00", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .be_hw_params_fixup = byt_cht_es8316_codec_fixup, + .nonatomic = true, + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = byt_cht_es8316_init, + }, +}; + + +/* SoC card */ +static struct snd_soc_card byt_cht_es8316_card = { + .name = "bytcht-es8316", + .owner = THIS_MODULE, + .dai_link = byt_cht_es8316_dais, + .num_links = ARRAY_SIZE(byt_cht_es8316_dais), + .dapm_widgets = byt_cht_es8316_widgets, + .num_dapm_widgets = ARRAY_SIZE(byt_cht_es8316_widgets), + .dapm_routes = byt_cht_es8316_audio_map, + .num_dapm_routes = ARRAY_SIZE(byt_cht_es8316_audio_map), + .controls = byt_cht_es8316_controls, + .num_controls = ARRAY_SIZE(byt_cht_es8316_controls), + .fully_routed = true, +}; + +static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) +{ + int ret = 0; + struct byt_cht_es8316_private *priv; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); + if (!priv) + return -ENOMEM; + + /* register the soc card */ + byt_cht_es8316_card.dev = &pdev->dev; + snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); + + priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + if (IS_ERR(priv->mclk)) { + ret = PTR_ERR(priv->mclk); + dev_err(&pdev->dev, + "Failed to get MCLK from pmc_plt_clk_3: %d\n", + ret); + return ret; + } + + ret = devm_snd_soc_register_card(&pdev->dev, &byt_cht_es8316_card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); + return ret; + } + platform_set_drvdata(pdev, &byt_cht_es8316_card); + return ret; +} + +static struct platform_driver snd_byt_cht_es8316_mc_driver = { + .driver = { + .name = "bytcht_es8316", + }, + .probe = snd_byt_cht_es8316_mc_probe, +}; + +module_platform_driver(snd_byt_cht_es8316_mc_driver); +MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail Machine driver"); +MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:bytcht_es8316"); diff --git a/sound/soc/intel/boards/bytcht_nocodec.c b/sound/soc/intel/boards/bytcht_nocodec.c index 89853eeaaf9d..1dd9441806fa 100644 --- a/sound/soc/intel/boards/bytcht_nocodec.c +++ b/sound/soc/intel/boards/bytcht_nocodec.c @@ -85,11 +85,11 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static unsigned int rates_48000[] = { +static const unsigned int rates_48000[] = { 48000, }; -static struct snd_pcm_hw_constraint_list constraints_48000 = { +static const struct snd_pcm_hw_constraint_list constraints_48000 = { .count = ARRAY_SIZE(rates_48000), .list = rates_48000, }; diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 8164bec63bf1..4a3516b38c2c 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -203,11 +203,11 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static unsigned int rates_48000[] = { +static const unsigned int rates_48000[] = { 48000, }; -static struct snd_pcm_hw_constraint_list constraints_48000 = { +static const struct snd_pcm_hw_constraint_list constraints_48000 = { .count = ARRAY_SIZE(rates_48000), .list = rates_48000, }; diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 742bc0d4e681..20755ecc7f9e 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -39,18 +39,6 @@ struct cht_mc_private { bool ts3a227e_present; }; -static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) -{ - struct snd_soc_pcm_runtime *rtd; - - list_for_each_entry(rtd, &card->rtd_list, list) { - if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, - strlen(CHT_CODEC_DAI))) - return rtd->codec_dai; - } - return NULL; -} - static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index e4d46d4360d7..bc2a52de06a3 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -19,6 +19,8 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/clk.h> +#include <asm/cpu_device_id.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -31,8 +33,11 @@ #define CHT_PLAT_CLK_3_HZ 19200000 #define CHT_CODEC_DAI "rt5670-aif1" -static struct snd_soc_jack cht_bsw_headset; -static char cht_bsw_codec_name[16]; +struct cht_mc_private { + struct snd_soc_jack headset; + char codec_name[16]; + struct clk *mclk; +}; /* Headset jack detection DAPM pins */ static struct snd_soc_jack_pin cht_bsw_headset_pins[] = { @@ -64,6 +69,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct snd_soc_dai *codec_dai; + struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); int ret; codec_dai = cht_get_codec_dai(card); @@ -73,6 +79,15 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, } if (SND_SOC_DAPM_EVENT_ON(event)) { + if (ctx->mclk) { + ret = clk_prepare_enable(ctx->mclk); + if (ret < 0) { + dev_err(card->dev, + "could not configure MCLK state"); + return ret; + } + } + /* set codec PLL source to the 19.2MHz platform clock (MCLK) */ ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK, CHT_PLAT_CLK_3_HZ, 48000 * 512); @@ -96,6 +111,9 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, */ snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, 48000 * 512, SND_SOC_CLOCK_IN); + + if (ctx->mclk) + clk_disable_unprepare(ctx->mclk); } return 0; } @@ -171,6 +189,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) int ret; struct snd_soc_dai *codec_dai = runtime->codec_dai; struct snd_soc_codec *codec = codec_dai->codec; + struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); @@ -194,13 +213,37 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) RT5670_CLK_SEL_I2S1_ASRC); ret = snd_soc_card_jack_new(runtime->card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2, &cht_bsw_headset, - cht_bsw_headset_pins, ARRAY_SIZE(cht_bsw_headset_pins)); + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2, + &ctx->headset, + cht_bsw_headset_pins, + ARRAY_SIZE(cht_bsw_headset_pins)); if (ret) return ret; - rt5670_set_jack_detect(codec, &cht_bsw_headset); + rt5670_set_jack_detect(codec, &ctx->headset); + if (ctx->mclk) { + /* + * The firmware might enable the clock at + * boot (this information may or may not + * be reflected in the enable clock register). + * To change the rate we must disable the clock + * first to cover these cases. Due to common + * clock framework restrictions that do not allow + * to disable a clock that has not been enabled, + * we need to enable the clock first. + */ + ret = clk_prepare_enable(ctx->mclk); + if (!ret) + clk_disable_unprepare(ctx->mclk); + + ret = clk_set_rate(ctx->mclk, CHT_PLAT_CLK_3_HZ); + + if (ret) { + dev_err(runtime->dev, "unable to set MCLK rate\n"); + return ret; + } + } return 0; } @@ -341,34 +384,62 @@ static struct snd_soc_card snd_soc_card_cht = { .resume_post = cht_resume_post, }; +static bool is_valleyview(void) +{ + static const struct x86_cpu_id cpu_ids[] = { + { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */ + {} + }; + + if (!x86_match_cpu(cpu_ids)) + return false; + return true; +} + #define RT5672_I2C_DEFAULT "i2c-10EC5670:00" static int snd_cht_mc_probe(struct platform_device *pdev) { int ret_val = 0; + struct cht_mc_private *drv; struct sst_acpi_mach *mach = pdev->dev.platform_data; const char *i2c_name; int i; - strcpy(cht_bsw_codec_name, RT5672_I2C_DEFAULT); + drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); + if (!drv) + return -ENOMEM; + + strcpy(drv->codec_name, RT5672_I2C_DEFAULT); /* fixup codec name based on HID */ if (mach) { i2c_name = sst_acpi_find_name_from_hid(mach->id); if (i2c_name) { - snprintf(cht_bsw_codec_name, sizeof(cht_bsw_codec_name), + snprintf(drv->codec_name, sizeof(drv->codec_name), "i2c-%s", i2c_name); for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { if (!strcmp(cht_dailink[i].codec_name, RT5672_I2C_DEFAULT)) { cht_dailink[i].codec_name = - cht_bsw_codec_name; + drv->codec_name; break; } } } } + if (is_valleyview()) { + drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + if (IS_ERR(drv->mclk)) { + dev_err(&pdev->dev, + "Failed to get MCLK from pmc_plt_clk_3: %ld\n", + PTR_ERR(drv->mclk)); + return PTR_ERR(drv->mclk); + } + } + snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); + /* register the soc card */ snd_soc_card_cht.dev = &pdev->dev; ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c new file mode 100644 index 000000000000..f9ba97788157 --- /dev/null +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -0,0 +1,687 @@ +/* + * Intel Kabylake I2S Machine Driver with MAXIM98927 + * and RT5663 Codecs + * + * Copyright (C) 2017, Intel Corporation. All rights reserved. + * + * Modified from: + * Intel Skylake I2S Machine driver + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <sound/core.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include "../../codecs/rt5663.h" +#include "../../codecs/hdac_hdmi.h" +#include "../skylake/skl.h" + +#define KBL_REALTEK_CODEC_DAI "rt5663-aif" +#define KBL_MAXIM_CODEC_DAI "max98927-aif1" +#define DMIC_CH(p) p->list[p->count-1] +#define MAXIM_DEV0_NAME "i2c-MX98927:00" +#define MAXIM_DEV1_NAME "i2c-MX98927:01" + +static struct snd_soc_card kabylake_audio_card; +static const struct snd_pcm_hw_constraint_list *dmic_constraints; +static struct snd_soc_jack skylake_hdmi[3]; + +struct kbl_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct kbl_rt5663_private { + struct snd_soc_jack kabylake_headset; + struct list_head hdmi_pcm_list; +}; + +enum { + KBL_DPCM_AUDIO_PB = 0, + KBL_DPCM_AUDIO_CP, + KBL_DPCM_AUDIO_REF_CP, + KBL_DPCM_AUDIO_DMIC_CP, + KBL_DPCM_AUDIO_HDMI1_PB, + KBL_DPCM_AUDIO_HDMI2_PB, + KBL_DPCM_AUDIO_HDMI3_PB, +}; + +static const struct snd_kcontrol_new kabylake_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), +}; + +static const struct snd_soc_dapm_widget kabylake_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), + SND_SOC_DAPM_MIC("SoC DMIC", NULL), + SND_SOC_DAPM_SPK("DP", NULL), + SND_SOC_DAPM_SPK("HDMI", NULL), + +}; + +static const struct snd_soc_dapm_route kabylake_map[] = { + /* HP jack connectors - unknown if we have jack detection */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + + /* speaker */ + { "Left Spk", NULL, "Left BE_OUT" }, + { "Right Spk", NULL, "Right BE_OUT" }, + + /* other jacks */ + { "IN1P", NULL, "Headset Mic" }, + { "IN1N", NULL, "Headset Mic" }, + { "DMic", NULL, "SoC DMIC" }, + + { "HDMI", NULL, "hif5 Output" }, + { "DP", NULL, "hif6 Output" }, + + /* CODEC BE connections */ + { "Left HiFi Playback", NULL, "ssp0 Tx" }, + { "Right HiFi Playback", NULL, "ssp0 Tx" }, + { "ssp0 Tx", NULL, "codec0_out" }, + + { "AIF Playback", NULL, "ssp1 Tx" }, + { "ssp1 Tx", NULL, "codec1_out" }, + + { "codec0_in", NULL, "ssp1 Rx" }, + { "ssp1 Rx", NULL, "AIF Capture" }, + + /* DMIC */ + { "dmic01_hifi", NULL, "DMIC01 Rx" }, + { "DMIC01 Rx", NULL, "DMIC AIF" }, + + { "hifi3", NULL, "iDisp3 Tx"}, + { "iDisp3 Tx", NULL, "iDisp3_out"}, + { "hifi2", NULL, "iDisp2 Tx"}, + { "iDisp2 Tx", NULL, "iDisp2_out"}, + { "hifi1", NULL, "iDisp1 Tx"}, + { "iDisp1 Tx", NULL, "iDisp1_out"}, +}; + +static struct snd_soc_codec_conf max98927_codec_conf[] = { + { + .dev_name = MAXIM_DEV0_NAME, + .name_prefix = "Right", + }, + { + .dev_name = MAXIM_DEV1_NAME, + .name_prefix = "Left", + }, +}; + +static struct snd_soc_dai_link_component max98927_codec_components[] = { + { /* Left */ + .name = MAXIM_DEV0_NAME, + .dai_name = KBL_MAXIM_CODEC_DAI, + }, + { /* Right */ + .name = MAXIM_DEV1_NAME, + .dai_name = KBL_MAXIM_CODEC_DAI, + }, +}; + +static int kabylake_rt5663_fe_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + struct snd_soc_dapm_context *dapm; + struct snd_soc_component *component = rtd->cpu_dai->component; + + dapm = snd_soc_component_get_dapm(component); + ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); + if (ret) { + dev_err(rtd->dev, "Ref Cap ignore suspend failed %d\n", ret); + return ret; + } + + return ret; +} + +static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_codec *codec = rtd->codec; + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new(&kabylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset, + NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); + return ret; + } + + rt5663_set_jack_detect(codec, &ctx->kabylake_headset); + ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); + if (ret) { + dev_err(rtd->dev, "SoC DMIC ignore suspend failed %d\n", ret); + return ret; + } + + return ret; +} + +static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) +{ + struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct kbl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = KBL_DPCM_AUDIO_HDMI1_PB; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) +{ + struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct kbl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = KBL_DPCM_AUDIO_HDMI2_PB; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) +{ + struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct kbl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = KBL_DPCM_AUDIO_HDMI3_PB; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +static unsigned int rates[] = { + 48000, +}; + +static struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; + +static unsigned int channels[] = { + 2, +}; + +static struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, +}; + +static int kbl_fe_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + /* + * On this platform for PCM device we support, + * 48Khz + * stereo + * 16 bit audio + */ + + runtime->hw.channels_max = 2; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + + return 0; +} + +static const struct snd_soc_ops kabylake_rt5663_fe_ops = { + .startup = kbl_fe_startup, +}; + +static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + /* set SSP1 to 24 bit */ + snd_mask_none(fmt); + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, + RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN); + /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */ + rt5663_sel_asrc_clk_src(codec_dai->codec, RT5663_DA_STEREO_FILTER, 1); + + if (ret < 0) + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + + return ret; +} + +static struct snd_soc_ops kabylake_rt5663_ops = { + .hw_params = kabylake_rt5663_hw_params, +}; + +static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2) + channels->min = channels->max = 2; + else + channels->min = channels->max = 4; + + return 0; +} + +static unsigned int channels_dmic[] = { + 2, 4, +}; + +static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { + .count = ARRAY_SIZE(channels_dmic), + .list = channels_dmic, + .mask = 0, +}; + +static const unsigned int dmic_2ch[] = { + 2, +}; + +static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { + .count = ARRAY_SIZE(dmic_2ch), + .list = dmic_2ch, + .mask = 0, +}; + +static int kabylake_dmic_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = DMIC_CH(dmic_constraints); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + dmic_constraints); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); +} + +static struct snd_soc_ops kabylake_dmic_ops = { + .startup = kabylake_dmic_startup, +}; + +static unsigned int rates_16000[] = { + 16000, +}; + +static struct snd_pcm_hw_constraint_list constraints_16000 = { + .count = ARRAY_SIZE(rates_16000), + .list = rates_16000, +}; + +static const unsigned int ch_mono[] = { + 1, +}; + +static const struct snd_pcm_hw_constraint_list constraints_refcap = { + .count = ARRAY_SIZE(ch_mono), + .list = ch_mono, +}; + +static int kabylake_refcap_startup(struct snd_pcm_substream *substream) +{ + substream->runtime->hw.channels_max = 1; + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_refcap); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_16000); +} + +static struct snd_soc_ops skylaye_refcap_ops = { + .startup = kabylake_refcap_startup, +}; + +/* kabylake digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link kabylake_dais[] = { + /* Front End DAI links */ + [KBL_DPCM_AUDIO_PB] = { + .name = "Kbl Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .init = kabylake_rt5663_fe_init, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &kabylake_rt5663_fe_ops, + }, + [KBL_DPCM_AUDIO_CP] = { + .name = "Kbl Audio Capture Port", + .stream_name = "Audio Record", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_capture = 1, + .ops = &kabylake_rt5663_fe_ops, + }, + [KBL_DPCM_AUDIO_REF_CP] = { + .name = "Kbl Audio Reference cap", + .stream_name = "Wake on Voice", + .cpu_dai_name = "Reference Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylaye_refcap_ops, + }, + [KBL_DPCM_AUDIO_DMIC_CP] = { + .name = "Kbl Audio DMIC cap", + .stream_name = "dmiccap", + .cpu_dai_name = "DMIC Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &kabylake_dmic_ops, + }, + [KBL_DPCM_AUDIO_HDMI1_PB] = { + .name = "Kbl HDMI Port1", + .stream_name = "Hdmi1", + .cpu_dai_name = "HDMI1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI2_PB] = { + .name = "Kbl HDMI Port2", + .stream_name = "Hdmi2", + .cpu_dai_name = "HDMI2 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI3_PB] = { + .name = "Kbl HDMI Port3", + .stream_name = "Hdmi3", + .cpu_dai_name = "HDMI3 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .init = NULL, + .nonatomic = 1, + .dynamic = 1, + }, + + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .id = 0, + .cpu_dai_name = "SSP0 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codecs = max98927_codec_components, + .num_codecs = ARRAY_SIZE(max98927_codec_components), + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp_fixup, + .dpcm_playback = 1, + }, + { + /* SSP1 - Codec */ + .name = "SSP1-Codec", + .id = 1, + .cpu_dai_name = "SSP1 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codec_name = "i2c-10EC5663:00", + .codec_dai_name = KBL_REALTEK_CODEC_DAI, + .init = kabylake_rt5663_codec_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp_fixup, + .ops = &kabylake_rt5663_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + { + .name = "dmic01", + .id = 2, + .cpu_dai_name = "DMIC01 Pin", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", + .platform_name = "0000:00:1f.3", + .be_hw_params_fixup = kabylake_dmic_fixup, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + }, + { + .name = "iDisp1", + .id = 3, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = kabylake_hdmi1_init, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .id = 4, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi2_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .id = 5, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi3_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +#define NAME_SIZE 32 +static int kabylake_card_late_probe(struct snd_soc_card *card) +{ + struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(card); + struct kbl_hdmi_pcm *pcm; + int err, i = 0; + char jack_name[NAME_SIZE]; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &skylake_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &skylake_hdmi[i]); + if (err < 0) + return err; + + i++; + } + + return 0; +} + +/* kabylake audio machine driver for SPT + RT5663 */ +static struct snd_soc_card kabylake_audio_card = { + .name = "kblrt5663max", + .owner = THIS_MODULE, + .dai_link = kabylake_dais, + .num_links = ARRAY_SIZE(kabylake_dais), + .controls = kabylake_controls, + .num_controls = ARRAY_SIZE(kabylake_controls), + .dapm_widgets = kabylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), + .dapm_routes = kabylake_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_map), + .codec_conf = max98927_codec_conf, + .num_configs = ARRAY_SIZE(max98927_codec_conf), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + +static int kabylake_audio_probe(struct platform_device *pdev) +{ + struct kbl_rt5663_private *ctx; + struct skl_machine_pdata *pdata; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + kabylake_audio_card.dev = &pdev->dev; + snd_soc_card_set_drvdata(&kabylake_audio_card, ctx); + + pdata = dev_get_drvdata(&pdev->dev); + if (pdata) + dmic_constraints = pdata->dmic_num == 2 ? + &constraints_dmic_2ch : &constraints_dmic_channels; + + return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card); +} + +static const struct platform_device_id kbl_board_ids[] = { + { .name = "kbl_rt5663_m98927" }, + { } +}; + +static struct platform_driver kabylake_audio = { + .probe = kabylake_audio_probe, + .driver = { + .name = "kbl_rt5663_m98927", + .pm = &snd_soc_pm_ops, + }, + .id_table = kbl_board_ids, +}; + +module_platform_driver(kabylake_audio) + +/* Module information */ +MODULE_DESCRIPTION("Audio Machine driver-RT5663 & MAX98927 in I2S mode"); +MODULE_AUTHOR("Naveen M <naveen.m@intel.com>"); +MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:kbl_rt5663_m98927"); diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c new file mode 100644 index 000000000000..3fe4a0807095 --- /dev/null +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -0,0 +1,640 @@ +/* + * Intel Kabylake I2S Machine Driver with MAXIM98927 + * RT5514 and RT5663 Codecs + * + * Copyright (C) 2017, Intel Corporation. All rights reserved. + * + * Modified from: + * Intel Kabylake I2S Machine driver supporting MAXIM98927 and + * RT5663 codecs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <sound/core.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include "../../codecs/rt5514.h" +#include "../../codecs/rt5663.h" +#include "../../codecs/hdac_hdmi.h" +#include "../skylake/skl.h" + +#define KBL_REALTEK_CODEC_DAI "rt5663-aif" +#define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1" +#define KBL_MAXIM_CODEC_DAI "max98927-aif1" +#define MAXIM_DEV0_NAME "i2c-MX98927:00" +#define MAXIM_DEV1_NAME "i2c-MX98927:01" +#define RT5514_DEV_NAME "i2c-10EC5514:00" +#define RT5663_DEV_NAME "i2c-10EC5663:00" +#define RT5514_AIF1_BCLK_FREQ (48000 * 8 * 16) +#define RT5514_AIF1_SYSCLK_FREQ 12288000 +#define NAME_SIZE 32 + +#define DMIC_CH(p) p->list[p->count-1] + + +static struct snd_soc_card kabylake_audio_card; +static const struct snd_pcm_hw_constraint_list *dmic_constraints; + +struct kbl_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct kbl_codec_private { + struct snd_soc_jack kabylake_headset; + struct list_head hdmi_pcm_list; + struct snd_soc_jack kabylake_hdmi[2]; +}; + +enum { + KBL_DPCM_AUDIO_PB = 0, + KBL_DPCM_AUDIO_CP, + KBL_DPCM_AUDIO_DMIC_CP, + KBL_DPCM_AUDIO_HDMI1_PB, + KBL_DPCM_AUDIO_HDMI2_PB, +}; + +static const struct snd_kcontrol_new kabylake_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), + SOC_DAPM_PIN_SWITCH("DMIC"), +}; + +static const struct snd_soc_dapm_widget kabylake_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), + SND_SOC_DAPM_MIC("DMIC", NULL), + SND_SOC_DAPM_SPK("DP", NULL), + SND_SOC_DAPM_SPK("HDMI", NULL), + +}; + +static const struct snd_soc_dapm_route kabylake_map[] = { + /* Headphones */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + + /* speaker */ + { "Left Spk", NULL, "Left BE_OUT" }, + { "Right Spk", NULL, "Right BE_OUT" }, + + /* other jacks */ + { "IN1P", NULL, "Headset Mic" }, + { "IN1N", NULL, "Headset Mic" }, + + { "HDMI", NULL, "hif5 Output" }, + { "DP", NULL, "hif6 Output" }, + + /* CODEC BE connections */ + { "Left HiFi Playback", NULL, "ssp0 Tx" }, + { "Right HiFi Playback", NULL, "ssp0 Tx" }, + { "ssp0 Tx", NULL, "codec0_out" }, + + { "AIF Playback", NULL, "ssp1 Tx" }, + { "ssp1 Tx", NULL, "codec1_out" }, + + { "codec0_in", NULL, "ssp1 Rx" }, + { "ssp1 Rx", NULL, "AIF Capture" }, + + { "codec1_in", NULL, "ssp0 Rx" }, + { "ssp0 Rx", NULL, "AIF1 Capture" }, + + /* DMIC */ + { "DMIC1L", NULL, "DMIC" }, + { "DMIC1R", NULL, "DMIC" }, + { "DMIC2L", NULL, "DMIC" }, + { "DMIC2R", NULL, "DMIC" }, + + { "hifi2", NULL, "iDisp2 Tx" }, + { "iDisp2 Tx", NULL, "iDisp2_out" }, + { "hifi1", NULL, "iDisp1 Tx" }, + { "iDisp1 Tx", NULL, "iDisp1_out" }, +}; + +static struct snd_soc_codec_conf max98927_codec_conf[] = { + { + .dev_name = MAXIM_DEV0_NAME, + .name_prefix = "Right", + }, + { + .dev_name = MAXIM_DEV1_NAME, + .name_prefix = "Left", + }, +}; + +static struct snd_soc_dai_link_component ssp0_codec_components[] = { + { /* Left */ + .name = MAXIM_DEV0_NAME, + .dai_name = KBL_MAXIM_CODEC_DAI, + }, + { /* Right */ + .name = MAXIM_DEV1_NAME, + .dai_name = KBL_MAXIM_CODEC_DAI, + }, + { /*dmic */ + .name = RT5514_DEV_NAME, + .dai_name = KBL_REALTEK_DMIC_CODEC_DAI, + }, +}; + +static int kabylake_rt5663_fe_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dapm_context *dapm; + struct snd_soc_component *component = rtd->cpu_dai->component; + int ret; + + dapm = snd_soc_component_get_dapm(component); + ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); + if (ret) + dev_err(rtd->dev, "Ref Cap -Ignore suspend failed = %d\n", ret); + + return ret; +} + +static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_codec *codec = rtd->codec; + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new(&kabylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset, + NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); + return ret; + } + + rt5663_set_jack_detect(codec, &ctx->kabylake_headset); + + ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "DMIC"); + if (ret) + dev_err(rtd->dev, "DMIC - Ignore suspend failed = %d\n", ret); + + return ret; +} + +static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) +{ + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct kbl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = device; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); +} + +static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); +} + +static const unsigned int rates[] = { + 48000, +}; + +static const struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; + +static const unsigned int channels[] = { + 2, +}; + +static const struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, +}; + +static int kbl_fe_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + /* + * On this platform for PCM device we support, + * 48Khz + * stereo + * 16 bit audio + */ + + runtime->hw.channels_max = 2; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + + return 0; +} + +static const struct snd_soc_ops kabylake_rt5663_fe_ops = { + .startup = kbl_fe_startup, +}; + +static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + struct snd_soc_dpcm *dpcm = container_of( + params, struct snd_soc_dpcm, hw_params); + struct snd_soc_dai_link *fe_dai_link = dpcm->fe->dai_link; + struct snd_soc_dai_link *be_dai_link = dpcm->be->dai_link; + + /* + * The ADSP will convert the FE rate to 48k, stereo, 24 bit + */ + if (!strcmp(fe_dai_link->name, "Kbl Audio Port") || + !strcmp(fe_dai_link->name, "Kbl Audio Capture Port")) { + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + snd_mask_none(fmt); + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + } else if (!strcmp(fe_dai_link->name, "Kbl Audio DMIC cap")) { + if (params_channels(params) == 2 || + DMIC_CH(dmic_constraints) == 2) + channels->min = channels->max = 2; + else + channels->min = channels->max = 4; + } + /* + * The speaker on the SSP0 supports S16_LE and not S24_LE. + * thus changing the mask here + */ + if (!strcmp(be_dai_link->name, "SSP0-Codec")) + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE); + + return 0; +} + +static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */ + rt5663_sel_asrc_clk_src(codec_dai->codec, RT5663_DA_STEREO_FILTER, 1); + + ret = snd_soc_dai_set_sysclk(codec_dai, + RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + + return ret; +} + +static struct snd_soc_ops kabylake_rt5663_ops = { + .hw_params = kabylake_rt5663_hw_params, +}; + +static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int ret = 0, j; + + for (j = 0; j < rtd->num_codecs; j++) { + struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; + + if (!strcmp(codec_dai->component->name, RT5514_DEV_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0, 8, 16); + if (ret < 0) { + dev_err(rtd->dev, "set TDM slot err:%d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_pll(codec_dai, 0, + RT5514_PLL1_S_BCLK, RT5514_AIF1_BCLK_FREQ, + RT5514_AIF1_SYSCLK_FREQ); + if (ret < 0) { + dev_err(rtd->dev, "set bclk err: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, + RT5514_SCLK_S_PLL1, RT5514_AIF1_SYSCLK_FREQ, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(rtd->dev, "set sclk err: %d\n", ret); + return ret; + } + } + if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME) || + !strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF0, 3, 8, 16); + if (ret < 0) { + dev_err(rtd->dev, "set TDM slot err:%d\n", ret); + return ret; + } + } + } + return ret; +} + +static struct snd_soc_ops kabylake_ssp0_ops = { + .hw_params = kabylake_ssp0_hw_params, +}; + +static const unsigned int channels_dmic[] = { + 4, +}; + +static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { + .count = ARRAY_SIZE(channels_dmic), + .list = channels_dmic, + .mask = 0, +}; + +static const unsigned int dmic_2ch[] = { + 4, +}; + +static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { + .count = ARRAY_SIZE(dmic_2ch), + .list = dmic_2ch, + .mask = 0, +}; + +static int kabylake_dmic_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = DMIC_CH(dmic_constraints); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + dmic_constraints); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); +} + +static struct snd_soc_ops kabylake_dmic_ops = { + .startup = kabylake_dmic_startup, +}; + +/* kabylake digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link kabylake_dais[] = { + /* Front End DAI links */ + [KBL_DPCM_AUDIO_PB] = { + .name = "Kbl Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .init = kabylake_rt5663_fe_init, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &kabylake_rt5663_fe_ops, + }, + [KBL_DPCM_AUDIO_CP] = { + .name = "Kbl Audio Capture Port", + .stream_name = "Audio Record", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_capture = 1, + .ops = &kabylake_rt5663_fe_ops, + }, + [KBL_DPCM_AUDIO_DMIC_CP] = { + .name = "Kbl Audio DMIC cap", + .stream_name = "dmiccap", + .cpu_dai_name = "DMIC Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &kabylake_dmic_ops, + }, + [KBL_DPCM_AUDIO_HDMI1_PB] = { + .name = "Kbl HDMI Port1", + .stream_name = "Hdmi1", + .cpu_dai_name = "HDMI1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI2_PB] = { + .name = "Kbl HDMI Port2", + .stream_name = "Hdmi2", + .cpu_dai_name = "HDMI2 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + /* Back End DAI links */ + /* single Back end dai for both max speakers and dmic */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .id = 0, + .cpu_dai_name = "SSP0 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codecs = ssp0_codec_components, + .num_codecs = ARRAY_SIZE(ssp0_codec_components), + .dai_fmt = SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp_fixup, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &kabylake_ssp0_ops, + }, + { + .name = "SSP1-Codec", + .id = 1, + .cpu_dai_name = "SSP1 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codec_name = RT5663_DEV_NAME, + .codec_dai_name = KBL_REALTEK_CODEC_DAI, + .init = kabylake_rt5663_codec_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp_fixup, + .ops = &kabylake_rt5663_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + { + .name = "iDisp1", + .id = 3, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = kabylake_hdmi1_init, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .id = 4, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi2_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +static int kabylake_card_late_probe(struct snd_soc_card *card) +{ + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); + struct kbl_hdmi_pcm *pcm; + int err, i = 0; + char jack_name[NAME_SIZE]; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &ctx->kabylake_hdmi[i], + NULL, 0); + + if (err) + return err; + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &ctx->kabylake_hdmi[i]); + if (err < 0) + return err; + i++; + } + + return 0; +} + +/* + * kabylake audio machine driver for MAX98927 + RT5514 + RT5663 + */ +static struct snd_soc_card kabylake_audio_card = { + .name = "kbl_r5514_5663_max", + .owner = THIS_MODULE, + .dai_link = kabylake_dais, + .num_links = ARRAY_SIZE(kabylake_dais), + .controls = kabylake_controls, + .num_controls = ARRAY_SIZE(kabylake_controls), + .dapm_widgets = kabylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), + .dapm_routes = kabylake_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_map), + .codec_conf = max98927_codec_conf, + .num_configs = ARRAY_SIZE(max98927_codec_conf), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + +static int kabylake_audio_probe(struct platform_device *pdev) +{ + struct kbl_codec_private *ctx; + struct skl_machine_pdata *pdata; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + kabylake_audio_card.dev = &pdev->dev; + snd_soc_card_set_drvdata(&kabylake_audio_card, ctx); + + pdata = dev_get_drvdata(&pdev->dev); + if (pdata) + dmic_constraints = pdata->dmic_num == 2 ? + &constraints_dmic_2ch : &constraints_dmic_channels; + + return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card); +} + +static const struct platform_device_id kbl_board_ids[] = { + { .name = "kbl_r5514_5663_max" }, + { } +}; + +static struct platform_driver kabylake_audio = { + .probe = kabylake_audio_probe, + .driver = { + .name = "kbl_r5514_5663_max", + .pm = &snd_soc_pm_ops, + }, + .id_table = kbl_board_ids, +}; + +module_platform_driver(kabylake_audio) + +/* Module information */ +MODULE_DESCRIPTION("Audio Machine driver-RT5663 RT5514 & MAX98927"); +MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:kbl_r5514_5663_max"); diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 3b12bc1fa518..5ed0aa27b467 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -266,21 +266,21 @@ static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static unsigned int rates[] = { +static const unsigned int rates[] = { 48000, }; -static struct snd_pcm_hw_constraint_list constraints_rates = { +static const struct snd_pcm_hw_constraint_list constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; -static unsigned int channels[] = { +static const unsigned int channels[] = { 2, }; -static struct snd_pcm_hw_constraint_list constraints_channels = { +static const struct snd_pcm_hw_constraint_list constraints_channels = { .count = ARRAY_SIZE(channels), .list = channels, .mask = 0, @@ -348,11 +348,11 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static unsigned int channels_dmic[] = { +static const unsigned int channels_dmic[] = { 2, 4, }; -static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { +static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { .count = ARRAY_SIZE(channels_dmic), .list = channels_dmic, .mask = 0, @@ -384,11 +384,11 @@ static const struct snd_soc_ops skylake_dmic_ops = { .startup = skylake_dmic_startup, }; -static unsigned int rates_16000[] = { +static const unsigned int rates_16000[] = { 16000, }; -static struct snd_pcm_hw_constraint_list constraints_16000 = { +static const struct snd_pcm_hw_constraint_list constraints_16000 = { .count = ARRAY_SIZE(rates_16000), .list = rates_16000, }; diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index eb7751b0599b..01b8b140bb08 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -297,21 +297,21 @@ static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static unsigned int rates[] = { +static const unsigned int rates[] = { 48000, }; -static struct snd_pcm_hw_constraint_list constraints_rates = { +static const struct snd_pcm_hw_constraint_list constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; -static unsigned int channels[] = { +static const unsigned int channels[] = { 2, }; -static struct snd_pcm_hw_constraint_list constraints_channels = { +static const struct snd_pcm_hw_constraint_list constraints_channels = { .count = ARRAY_SIZE(channels), .list = channels, .mask = 0, @@ -397,11 +397,11 @@ static const struct snd_soc_ops skylake_nau8825_ops = { .hw_params = skylake_nau8825_hw_params, }; -static unsigned int channels_dmic[] = { +static const unsigned int channels_dmic[] = { 2, 4, }; -static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { +static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { .count = ARRAY_SIZE(channels_dmic), .list = channels_dmic, .mask = 0, @@ -433,11 +433,11 @@ static const struct snd_soc_ops skylake_dmic_ops = { .startup = skylake_dmic_startup, }; -static unsigned int rates_16000[] = { +static const unsigned int rates_16000[] = { 16000, }; -static struct snd_pcm_hw_constraint_list constraints_16000 = { +static const struct snd_pcm_hw_constraint_list constraints_16000 = { .count = ARRAY_SIZE(rates_16000), .list = rates_16000, }; diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index f5ab7b8d51d1..2bc4cfca594e 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -43,6 +43,7 @@ struct skl_rt286_private { enum { SKL_DPCM_AUDIO_PB = 0, + SKL_DPCM_AUDIO_DB_PB, SKL_DPCM_AUDIO_CP, SKL_DPCM_AUDIO_REF_CP, SKL_DPCM_AUDIO_DMIC_CP, @@ -165,21 +166,21 @@ static int skylake_hdmi_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static unsigned int rates[] = { +static const unsigned int rates[] = { 48000, }; -static struct snd_pcm_hw_constraint_list constraints_rates = { +static const struct snd_pcm_hw_constraint_list constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; -static unsigned int channels[] = { +static const unsigned int channels[] = { 2, }; -static struct snd_pcm_hw_constraint_list constraints_channels = { +static const struct snd_pcm_hw_constraint_list constraints_channels = { .count = ARRAY_SIZE(channels), .list = channels, .mask = 0, @@ -264,11 +265,11 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static unsigned int channels_dmic[] = { +static const unsigned int channels_dmic[] = { 2, 4, }; -static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { +static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { .count = ARRAY_SIZE(channels_dmic), .list = channels_dmic, .mask = 0, @@ -310,6 +311,23 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { .dpcm_playback = 1, .ops = &skylake_rt286_fe_ops, }, + [SKL_DPCM_AUDIO_DB_PB] = { + .name = "Skl Deepbuffer Port", + .stream_name = "Deep Buffer Audio", + .cpu_dai_name = "Deepbuffer Pin", + .platform_name = "0000:00:1f.3", + .nonatomic = 1, + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST + }, + .dpcm_playback = 1, + .ops = &skylake_rt286_fe_ops, + + }, [SKL_DPCM_AUDIO_CP] = { .name = "Skl Audio Capture Port", .stream_name = "Audio Record", diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h index 214e000667ae..afe9b87b8bd5 100644 --- a/sound/soc/intel/common/sst-acpi.h +++ b/sound/soc/intel/common/sst-acpi.h @@ -43,6 +43,9 @@ static inline bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], /* acpi match */ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines); +/* acpi check hid */ +bool sst_acpi_check_hid(const u8 hid[ACPI_ID_LEN]); + /* Descriptor for SST ASoC machine driver */ struct sst_acpi_mach { /* ACPI ID for the matching machine driver. Audio codec for instance */ @@ -55,5 +58,25 @@ struct sst_acpi_mach { /* board name */ const char *board; struct sst_acpi_mach * (*machine_quirk)(void *arg); + const void *quirk_data; void *pdata; }; + +#define SST_ACPI_MAX_CODECS 3 + +/** + * struct sst_codecs: Structure to hold secondary codec information apart from + * the matched one, this data will be passed to the quirk function to match + * with the ACPI detected devices + * + * @num_codecs: number of secondary codecs used in the platform + * @codecs: holds the codec IDs + * + */ +struct sst_codecs { + int num_codecs; + u8 codecs[SST_ACPI_MAX_CODECS][ACPI_ID_LEN]; +}; + +/* check all codecs */ +struct sst_acpi_mach *sst_acpi_codec_list(void *arg); diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index d13c84364c3c..8734040d64d3 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -77,6 +77,10 @@ struct sst_addr { u32 dram_offset; u32 dsp_iram_offset; u32 dsp_dram_offset; + u32 sram0_base; + u32 sram1_base; + u32 w0_stat_sz; + u32 w0_up_sz; void __iomem *lpe; void __iomem *shim; void __iomem *pci_cfg; diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c index 1070f3ad23e5..56d26f36a3cb 100644 --- a/sound/soc/intel/common/sst-match-acpi.c +++ b/sound/soc/intel/common/sst-match-acpi.c @@ -63,16 +63,33 @@ static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level, return AE_OK; } +bool sst_acpi_check_hid(const u8 hid[ACPI_ID_LEN]) +{ + acpi_status status; + bool found = false; + + status = acpi_get_devices(hid, sst_acpi_mach_match, &found, NULL); + + if (ACPI_FAILURE(status)) + return false; + + return found; +} +EXPORT_SYMBOL_GPL(sst_acpi_check_hid); + struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines) { struct sst_acpi_mach *mach; - bool found = false; - for (mach = machines; mach->id[0]; mach++) - if (ACPI_SUCCESS(acpi_get_devices(mach->id, - sst_acpi_mach_match, - &found, NULL)) && found) - return mach; + for (mach = machines; mach->id[0]; mach++) { + if (sst_acpi_check_hid(mach->id) == true) { + if (mach->machine_quirk == NULL) + return mach; + + if (mach->machine_quirk(mach) != NULL) + return mach; + } + } return NULL; } EXPORT_SYMBOL_GPL(sst_acpi_find_machine); @@ -134,5 +151,23 @@ bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], } EXPORT_SYMBOL_GPL(sst_acpi_find_package_from_hid); +struct sst_acpi_mach *sst_acpi_codec_list(void *arg) +{ + struct sst_acpi_mach *mach = arg; + struct sst_codecs *codec_list = (struct sst_codecs *) mach->quirk_data; + int i; + + if (mach->quirk_data == NULL) + return mach; + + for (i = 0; i < codec_list->num_codecs; i++) { + if (sst_acpi_check_hid(codec_list->codecs[i]) != true) + return NULL; + } + + return mach; +} +EXPORT_SYMBOL_GPL(sst_acpi_codec_list); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel Common ACPI Match module"); diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index 60fbc9bbe473..e7d77722d560 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -1,6 +1,10 @@ snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o skl-messages.o \ skl-topology.o +ifdef CONFIG_DEBUG_FS + snd-soc-skl-objs += skl-debug.o +endif + obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o # Skylake IPC Support diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index f5e7dbb1ba39..cf11b84888b9 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -573,6 +573,10 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, sst->fw_ops = bxt_fw_ops; sst->addr.lpe = mmio_base; sst->addr.shim = mmio_base; + sst->addr.sram0_base = BXT_ADSP_SRAM0_BASE; + sst->addr.sram1_base = BXT_ADSP_SRAM1_BASE; + sst->addr.w0_stat_sz = SKL_ADSP_W0_STAT_SZ; + sst->addr.w0_up_sz = SKL_ADSP_W0_UP_SZ; sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c new file mode 100644 index 000000000000..75497b1fda45 --- /dev/null +++ b/sound/soc/intel/skylake/skl-debug.c @@ -0,0 +1,268 @@ +/* + * skl-debug.c - Debugfs for skl driver + * + * Copyright (C) 2016-17 Intel Corp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <linux/pci.h> +#include <linux/debugfs.h> +#include "skl.h" +#include "skl-sst-dsp.h" +#include "skl-sst-ipc.h" +#include "skl-tplg-interface.h" +#include "skl-topology.h" +#include "../common/sst-dsp-priv.h" + +#define MOD_BUF PAGE_SIZE +#define FW_REG_BUF PAGE_SIZE +#define FW_REG_SIZE 0x60 + +struct skl_debug { + struct skl *skl; + struct device *dev; + + struct dentry *fs; + struct dentry *modules; + u8 fw_read_buff[FW_REG_BUF]; +}; + +static ssize_t skl_print_pins(struct skl_module_pin *m_pin, char *buf, + int max_pin, ssize_t size, bool direction) +{ + int i; + ssize_t ret = 0; + + for (i = 0; i < max_pin; i++) + ret += snprintf(buf + size, MOD_BUF - size, + "%s %d\n\tModule %d\n\tInstance %d\n\t" + "In-used %s\n\tType %s\n" + "\tState %d\n\tIndex %d\n", + direction ? "Input Pin:" : "Output Pin:", + i, m_pin[i].id.module_id, + m_pin[i].id.instance_id, + m_pin[i].in_use ? "Used" : "Unused", + m_pin[i].is_dynamic ? "Dynamic" : "Static", + m_pin[i].pin_state, i); + return ret; +} + +static ssize_t skl_print_fmt(struct skl_module_fmt *fmt, char *buf, + ssize_t size, bool direction) +{ + return snprintf(buf + size, MOD_BUF - size, + "%s\n\tCh %d\n\tFreq %d\n\tBit depth %d\n\t" + "Valid bit depth %d\n\tCh config %#x\n\tInterleaving %d\n\t" + "Sample Type %d\n\tCh Map %#x\n", + direction ? "Input Format:" : "Output Format:", + fmt->channels, fmt->s_freq, fmt->bit_depth, + fmt->valid_bit_depth, fmt->ch_cfg, + fmt->interleaving_style, fmt->sample_type, + fmt->ch_map); +} + +static ssize_t module_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct skl_module_cfg *mconfig = file->private_data; + char *buf; + ssize_t ret; + + buf = kzalloc(MOD_BUF, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = snprintf(buf, MOD_BUF, "Module:\n\tUUID %pUL\n\tModule id %d\n" + "\tInstance id %d\n\tPvt_id %d\n", mconfig->guid, + mconfig->id.module_id, mconfig->id.instance_id, + mconfig->id.pvt_id); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "Resources:\n\tMCPS %#x\n\tIBS %#x\n\tOBS %#x\t\n", + mconfig->mcps, mconfig->ibs, mconfig->obs); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "Module data:\n\tCore %d\n\tIn queue %d\n\t" + "Out queue %d\n\tType %s\n", + mconfig->core_id, mconfig->max_in_queue, + mconfig->max_out_queue, + mconfig->is_loadable ? "loadable" : "inbuilt"); + + ret += skl_print_fmt(mconfig->in_fmt, buf, ret, true); + ret += skl_print_fmt(mconfig->out_fmt, buf, ret, false); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "Fixup:\n\tParams %#x\n\tConverter %#x\n", + mconfig->params_fixup, mconfig->converter); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "Module Gateway:\n\tType %#x\n\tVbus %#x\n\tHW conn %#x\n\tSlot %#x\n", + mconfig->dev_type, mconfig->vbus_id, + mconfig->hw_conn_type, mconfig->time_slot); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "Pipeline:\n\tID %d\n\tPriority %d\n\tConn Type %d\n\t" + "Pages %#x\n", mconfig->pipe->ppl_id, + mconfig->pipe->pipe_priority, mconfig->pipe->conn_type, + mconfig->pipe->memory_pages); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "\tParams:\n\t\tHost DMA %d\n\t\tLink DMA %d\n", + mconfig->pipe->p_params->host_dma_id, + mconfig->pipe->p_params->link_dma_id); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "\tPCM params:\n\t\tCh %d\n\t\tFreq %d\n\t\tFormat %d\n", + mconfig->pipe->p_params->ch, + mconfig->pipe->p_params->s_freq, + mconfig->pipe->p_params->s_fmt); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "\tLink %#x\n\tStream %#x\n", + mconfig->pipe->p_params->linktype, + mconfig->pipe->p_params->stream); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "\tState %d\n\tPassthru %s\n", + mconfig->pipe->state, + mconfig->pipe->passthru ? "true" : "false"); + + ret += skl_print_pins(mconfig->m_in_pin, buf, + mconfig->max_in_queue, ret, true); + ret += skl_print_pins(mconfig->m_out_pin, buf, + mconfig->max_out_queue, ret, false); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "Other:\n\tDomain %d\n\tHomogenous Input %s\n\t" + "Homogenous Output %s\n\tIn Queue Mask %d\n\t" + "Out Queue Mask %d\n\tDMA ID %d\n\tMem Pages %d\n\t" + "Module Type %d\n\tModule State %d\n", + mconfig->domain, + mconfig->homogenous_inputs ? "true" : "false", + mconfig->homogenous_outputs ? "true" : "false", + mconfig->in_queue_mask, mconfig->out_queue_mask, + mconfig->dma_id, mconfig->mem_pages, mconfig->m_state, + mconfig->m_type); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); + + kfree(buf); + return ret; +} + +static const struct file_operations mcfg_fops = { + .open = simple_open, + .read = module_read, + .llseek = default_llseek, +}; + + +void skl_debug_init_module(struct skl_debug *d, + struct snd_soc_dapm_widget *w, + struct skl_module_cfg *mconfig) +{ + if (!debugfs_create_file(w->name, 0444, + d->modules, mconfig, + &mcfg_fops)) + dev_err(d->dev, "%s: module debugfs init failed\n", w->name); +} + +static ssize_t fw_softreg_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct skl_debug *d = file->private_data; + struct sst_dsp *sst = d->skl->skl_sst->dsp; + size_t w0_stat_sz = sst->addr.w0_stat_sz; + void __iomem *in_base = sst->mailbox.in_base; + void __iomem *fw_reg_addr; + unsigned int offset; + char *tmp; + ssize_t ret = 0; + + tmp = kzalloc(FW_REG_BUF, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + fw_reg_addr = in_base - w0_stat_sz; + memset(d->fw_read_buff, 0, FW_REG_BUF); + + if (w0_stat_sz > 0) + __iowrite32_copy(d->fw_read_buff, fw_reg_addr, w0_stat_sz >> 2); + + for (offset = 0; offset < FW_REG_SIZE; offset += 16) { + ret += snprintf(tmp + ret, FW_REG_BUF - ret, "%#.4x: ", offset); + hex_dump_to_buffer(d->fw_read_buff + offset, 16, 16, 4, + tmp + ret, FW_REG_BUF - ret, 0); + ret += strlen(tmp + ret); + + /* print newline for each offset */ + if (FW_REG_BUF - ret > 0) + tmp[ret++] = '\n'; + } + + ret = simple_read_from_buffer(user_buf, count, ppos, tmp, ret); + kfree(tmp); + + return ret; +} + +static const struct file_operations soft_regs_ctrl_fops = { + .open = simple_open, + .read = fw_softreg_read, + .llseek = default_llseek, +}; + +struct skl_debug *skl_debugfs_init(struct skl *skl) +{ + struct skl_debug *d; + + d = devm_kzalloc(&skl->pci->dev, sizeof(*d), GFP_KERNEL); + if (!d) + return NULL; + + /* create the debugfs dir with platform component's debugfs as parent */ + d->fs = debugfs_create_dir("dsp", + skl->platform->component.debugfs_root); + if (IS_ERR(d->fs) || !d->fs) { + dev_err(&skl->pci->dev, "debugfs root creation failed\n"); + return NULL; + } + + d->skl = skl; + d->dev = &skl->pci->dev; + + /* now create the module dir */ + d->modules = debugfs_create_dir("modules", d->fs); + if (IS_ERR(d->modules) || !d->modules) { + dev_err(&skl->pci->dev, "modules debugfs create failed\n"); + goto err; + } + + if (!debugfs_create_file("fw_soft_regs_rd", 0444, d->fs, d, + &soft_regs_ctrl_fops)) { + dev_err(d->dev, "fw soft regs control debugfs init failed\n"); + goto err; + } + + return d; + +err: + debugfs_remove_recursive(d->fs); + return NULL; +} + +void skl_debugfs_exit(struct skl_debug *d) +{ + debugfs_remove_recursive(d->fs); + + kfree(d); + +} diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index ab1adc0c9cc3..eca85827dbd2 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -507,6 +507,8 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, struct skl_module_cfg *mconfig, struct skl_cpr_cfg *cpr_mconfig) { + u32 dma_io_buf; + cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(ctx, mconfig); if (cpr_mconfig->gtw_cfg.node_id == SKL_NON_GATEWAY_CPR_NODE_ID) { @@ -514,10 +516,29 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, return; } - if (SKL_CONN_SOURCE == mconfig->hw_conn_type) - cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->obs; - else - cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->ibs; + switch (mconfig->hw_conn_type) { + case SKL_CONN_SOURCE: + if (mconfig->dev_type == SKL_DEVICE_HDAHOST) + dma_io_buf = mconfig->ibs; + else + dma_io_buf = mconfig->obs; + break; + + case SKL_CONN_SINK: + if (mconfig->dev_type == SKL_DEVICE_HDAHOST) + dma_io_buf = mconfig->obs; + else + dma_io_buf = mconfig->ibs; + break; + + default: + dev_warn(ctx->dev, "wrong connection type: %d\n", + mconfig->hw_conn_type); + return; + } + + cpr_mconfig->gtw_cfg.dma_buffer_size = + mconfig->dma_buffer_size * dma_io_buf; cpr_mconfig->cpr_feature_mask = 0; cpr_mconfig->gtw_cfg.config_length = 0; @@ -707,6 +728,7 @@ static u16 skl_get_module_param_size(struct skl_sst *ctx, return param_size; case SKL_MODULE_TYPE_BASE_OUTFMT: + case SKL_MODULE_TYPE_MIC_SELECT: case SKL_MODULE_TYPE_KPB: return sizeof(struct skl_base_outfmt_cfg); @@ -761,6 +783,7 @@ static int skl_set_module_format(struct skl_sst *ctx, break; case SKL_MODULE_TYPE_BASE_OUTFMT: + case SKL_MODULE_TYPE_MIC_SELECT: case SKL_MODULE_TYPE_KPB: skl_set_base_outfmt_format(ctx, module_config, *param_data); break; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index e91bbcffc856..0ebea34a4988 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1249,12 +1249,16 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform) pm_runtime_get_sync(platform->dev); if ((ebus_to_hbus(ebus))->ppcap) { + skl->platform = platform; + + /* init debugfs */ + skl->debugfs = skl_debugfs_init(skl); + ret = skl_tplg_init(platform, ebus); if (ret < 0) { dev_err(platform->dev, "Failed to init topology!\n"); return ret; } - skl->platform = platform; /* load the firmwares, since all is set */ ops = skl_get_dsp_ops(skl->pci->device); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 58c525096a7c..498b15345b1a 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -413,8 +413,11 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK; u64 *ipc_header = (u64 *)(&header); struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc); + unsigned long flags; + spin_lock_irqsave(&ipc->dsp->spinlock, flags); msg = skl_ipc_reply_get_msg(ipc, *ipc_header); + spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); if (msg == NULL) { dev_dbg(ipc->dev, "ipc: rx list is empty\n"); return; @@ -456,8 +459,10 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, } } + spin_lock_irqsave(&ipc->dsp->spinlock, flags); list_del(&msg->list); sst_ipc_tx_msg_reply_complete(ipc, msg); + spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); } irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 155e456b7a3a..aba9ea11ac74 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -553,6 +553,11 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, sst = skl->dsp; sst->addr.lpe = mmio_base; sst->addr.shim = mmio_base; + sst->addr.sram0_base = SKL_ADSP_SRAM0_BASE; + sst->addr.sram1_base = SKL_ADSP_SRAM1_BASE; + sst->addr.w0_stat_sz = SKL_ADSP_W0_STAT_SZ; + sst->addr.w0_up_sz = SKL_ADSP_W0_UP_SZ; + sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 3a99712e44a8..68c3f121efc3 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -36,6 +36,19 @@ #define SKL_IN_DIR_BIT_MASK BIT(0) #define SKL_PIN_COUNT_MASK GENMASK(7, 4) +static const int mic_mono_list[] = { +0, 1, 2, 3, +}; +static const int mic_stereo_list[][SKL_CH_STEREO] = { +{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}, +}; +static const int mic_trio_list[][SKL_CH_TRIO] = { +{0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3}, +}; +static const int mic_quatro_list[][SKL_CH_QUATRO] = { +{0, 1, 2, 3}, +}; + void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps) { struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; @@ -1314,6 +1327,111 @@ static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, return 0; } +static int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); + struct skl_module_cfg *mconfig = w->priv; + struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; + u32 ch_type = *((u32 *)ec->dobj.private); + + if (mconfig->dmic_ch_type == ch_type) + ucontrol->value.enumerated.item[0] = + mconfig->dmic_ch_combo_index; + else + ucontrol->value.enumerated.item[0] = 0; + + return 0; +} + +static int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig, + struct skl_mic_sel_config *mic_cfg, struct device *dev) +{ + struct skl_specific_cfg *sp_cfg = &mconfig->formats_config; + + sp_cfg->caps_size = sizeof(struct skl_mic_sel_config); + sp_cfg->set_params = SKL_PARAM_SET; + sp_cfg->param_id = 0x00; + if (!sp_cfg->caps) { + sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL); + if (!sp_cfg->caps) + return -ENOMEM; + } + + mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH; + mic_cfg->flags = 0; + memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size); + + return 0; +} + +static int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); + struct skl_module_cfg *mconfig = w->priv; + struct skl_mic_sel_config mic_cfg = {0}; + struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; + u32 ch_type = *((u32 *)ec->dobj.private); + const int *list; + u8 in_ch, out_ch, index; + + mconfig->dmic_ch_type = ch_type; + mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0]; + + /* enum control index 0 is INVALID, so no channels to be set */ + if (mconfig->dmic_ch_combo_index == 0) + return 0; + + /* No valid channel selection map for index 0, so offset by 1 */ + index = mconfig->dmic_ch_combo_index - 1; + + switch (ch_type) { + case SKL_CH_MONO: + if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list)) + return -EINVAL; + + list = &mic_mono_list[index]; + break; + + case SKL_CH_STEREO: + if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list)) + return -EINVAL; + + list = mic_stereo_list[index]; + break; + + case SKL_CH_TRIO: + if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list)) + return -EINVAL; + + list = mic_trio_list[index]; + break; + + case SKL_CH_QUATRO: + if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list)) + return -EINVAL; + + list = mic_quatro_list[index]; + break; + + default: + dev_err(w->dapm->dev, + "Invalid channel %d for mic_select module\n", + ch_type); + return -EINVAL; + + } + + /* channel type enum map to number of chanels for that type */ + for (out_ch = 0; out_ch < ch_type; out_ch++) { + in_ch = list[out_ch]; + mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN; + } + + return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev); +} + /* * Fill the dma id for host and link. In case of passthrough * pipeline, this will both host and link in the same @@ -1666,6 +1784,14 @@ static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = { skl_tplg_tlv_control_set}, }; +static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = { + { + .id = SKL_CONTROL_TYPE_MIC_SELECT, + .get = skl_tplg_mic_control_get, + .put = skl_tplg_mic_control_set, + }, +}; + static int skl_tplg_fill_pipe_tkn(struct device *dev, struct skl_pipe *pipe, u32 tkn, u32 tkn_val) @@ -1995,7 +2121,7 @@ static int skl_tplg_get_token(struct device *dev, mconfig->converter = tkn_elem->value; break; - case SKL_TKL_U32_D0I3_CAPS: + case SKL_TKN_U32_D0I3_CAPS: mconfig->d0i3_caps = tkn_elem->value; break; @@ -2070,12 +2196,26 @@ static int skl_tplg_get_token(struct device *dev, break; + case SKL_TKN_U32_CAPS_SET_PARAMS: + mconfig->formats_config.set_params = + tkn_elem->value; + break; + + case SKL_TKN_U32_CAPS_PARAMS_ID: + mconfig->formats_config.param_id = + tkn_elem->value; + break; + case SKL_TKN_U32_PROC_DOMAIN: mconfig->domain = tkn_elem->value; break; + case SKL_TKN_U32_DMA_BUF_SIZE: + mconfig->dma_buffer_size = tkn_elem->value; + break; + case SKL_TKN_U8_IN_PIN_TYPE: case SKL_TKN_U8_OUT_PIN_TYPE: case SKL_TKN_U8_CONN_TYPE: @@ -2147,7 +2287,7 @@ static int skl_tplg_get_tokens(struct device *dev, tuple_size += tkn_count * sizeof(*tkn_elem); } - return 0; + return off; } /* @@ -2198,10 +2338,11 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, num_blocks = ret; off += array->size; - array = (struct snd_soc_tplg_vendor_array *)(tplg_w->priv.data + off); - /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ while (num_blocks > 0) { + array = (struct snd_soc_tplg_vendor_array *) + (tplg_w->priv.data + off); + ret = skl_tplg_get_desc_blocks(dev, array); if (ret < 0) @@ -2237,7 +2378,9 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, memcpy(mconfig->formats_config.caps, data, mconfig->formats_config.caps_size); --num_blocks; + ret = mconfig->formats_config.caps_size; } + off += ret; } return 0; @@ -2329,6 +2472,9 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig); if (ret < 0) return ret; + + skl_debug_init_module(skl->debugfs, w, mconfig); + bind_event: if (tplg_w->event_type == 0) { dev_dbg(bus->dev, "ASoC: No event handler required\n"); @@ -2377,14 +2523,34 @@ static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, return 0; } +static int skl_init_enum_data(struct device *dev, struct soc_enum *se, + struct snd_soc_tplg_enum_control *ec) +{ + + void *data; + + if (ec->priv.size) { + data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL); + if (!data) + return -ENOMEM; + memcpy(data, ec->priv.data, ec->priv.size); + se->dobj.private = data; + } + + return 0; + +} + static int skl_tplg_control_load(struct snd_soc_component *cmpnt, struct snd_kcontrol_new *kctl, struct snd_soc_tplg_ctl_hdr *hdr) { struct soc_bytes_ext *sb; struct snd_soc_tplg_bytes_control *tplg_bc; + struct snd_soc_tplg_enum_control *tplg_ec; struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); struct hdac_bus *bus = ebus_to_hbus(ebus); + struct soc_enum *se; switch (hdr->ops.info) { case SND_SOC_TPLG_CTL_BYTES: @@ -2398,6 +2564,17 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt, } break; + case SND_SOC_TPLG_CTL_ENUM: + tplg_ec = container_of(hdr, + struct snd_soc_tplg_enum_control, hdr); + if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READWRITE) { + se = (struct soc_enum *)kctl->private_value; + if (tplg_ec->priv.size) + return skl_init_enum_data(bus->dev, se, + tplg_ec); + } + break; + default: dev_warn(bus->dev, "Control load not supported %d:%d:%d\n", hdr->ops.get, hdr->ops.put, hdr->ops.info); @@ -2502,7 +2679,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev, if (ret < 0) return ret; - tkn_count += ret; + tkn_count = ret; tuple_size += tkn_count * sizeof(struct snd_soc_tplg_vendor_string_elem); @@ -2626,6 +2803,8 @@ static struct snd_soc_tplg_ops skl_tplg_ops = { .control_load = skl_tplg_control_load, .bytes_ext_ops = skl_tlv_ops, .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), + .io_ops = skl_tplg_kcontrol_ops, + .io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops), .manifest = skl_manifest_load, }; diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index cc64d6bdb4f6..c25e8868b84e 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -39,6 +39,11 @@ #define MODULE_MAX_IN_PINS 8 #define MODULE_MAX_OUT_PINS 8 +#define SKL_MIC_CH_SUPPORT 4 +#define SKL_MIC_MAX_CH_SUPPORT 8 +#define SKL_DEFAULT_MIC_SEL_GAIN 0x3FF +#define SKL_MIC_SEL_SWITCH 0x3 + enum skl_channel_index { SKL_CHANNEL_LEFT = 0, SKL_CHANNEL_RIGHT = 1, @@ -309,11 +314,14 @@ struct skl_module_cfg { u8 dev_type; u8 dma_id; u8 time_slot; + u8 dmic_ch_combo_index; + u32 dmic_ch_type; u32 params_fixup; u32 converter; u32 vbus_id; u32 mem_pages; enum d0i3_capability d0i3_caps; + u32 dma_buffer_size; /* in milli seconds */ struct skl_module_pin *m_in_pin; struct skl_module_pin *m_out_pin; enum skl_module_type m_type; @@ -342,6 +350,19 @@ struct skl_module_deferred_bind { struct list_head node; }; +struct skl_mic_sel_config { + u16 mic_switch; + u16 flags; + u16 blob[SKL_MIC_MAX_CH_SUPPORT][SKL_MIC_MAX_CH_SUPPORT]; +} __packed; + +enum skl_channel { + SKL_CH_MONO = 1, + SKL_CH_STEREO = 2, + SKL_CH_TRIO = 3, + SKL_CH_QUATRO = 4, +}; + static inline struct skl *get_skl_ctx(struct device *dev) { struct hdac_ext_bus *ebus = dev_get_drvdata(dev); diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index 7a2febf99019..f8d1749a2e0c 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h @@ -24,6 +24,7 @@ * SST types start at higher to avoid any overlapping in future */ #define SKL_CONTROL_TYPE_BYTE_TLV 0x100 +#define SKL_CONTROL_TYPE_MIC_SELECT 0x102 #define HDA_SST_CFG_MAX 900 /* size of copier cfg*/ #define MAX_IN_QUEUE 8 @@ -82,6 +83,7 @@ enum skl_module_type { SKL_MODULE_TYPE_ALGO, SKL_MODULE_TYPE_BASE_OUTFMT, SKL_MODULE_TYPE_KPB, + SKL_MODULE_TYPE_MIC_SELECT, }; enum skl_core_affinity { diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 6df3b317a476..410ce83f4a49 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -410,7 +410,7 @@ static int skl_free(struct hdac_ext_bus *ebus) struct skl *skl = ebus_to_skl(ebus); struct hdac_bus *bus = ebus_to_hbus(ebus); - skl->init_failed = 1; /* to be sure */ + skl->init_done = 0; /* to be sure */ snd_hdac_ext_stop_streams(ebus); @@ -428,8 +428,10 @@ static int skl_free(struct hdac_ext_bus *ebus) snd_hdac_ext_bus_exit(ebus); + cancel_work_sync(&skl->probe_work); if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) snd_hdac_i915_exit(&ebus->bus); + return 0; } @@ -566,6 +568,84 @@ static const struct hdac_bus_ops bus_core_ops = { .get_response = snd_hdac_bus_get_response, }; +static int skl_i915_init(struct hdac_bus *bus) +{ + int err; + + /* + * The HDMI codec is in GPU so we need to ensure that it is powered + * up and ready for probe + */ + err = snd_hdac_i915_init(bus); + if (err < 0) + return err; + + err = snd_hdac_display_power(bus, true); + if (err < 0) + dev_err(bus->dev, "Cannot turn on display power on i915\n"); + + return err; +} + +static void skl_probe_work(struct work_struct *work) +{ + struct skl *skl = container_of(work, struct skl, probe_work); + struct hdac_ext_bus *ebus = &skl->ebus; + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct hdac_ext_link *hlink = NULL; + int err; + + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { + err = skl_i915_init(bus); + if (err < 0) + return; + } + + err = skl_init_chip(bus, true); + if (err < 0) { + dev_err(bus->dev, "Init chip failed with err: %d\n", err); + goto out_err; + } + + /* codec detection */ + if (!bus->codec_mask) + dev_info(bus->dev, "no hda codecs found!\n"); + + /* create codec instances */ + err = skl_codec_create(ebus); + if (err < 0) + goto out_err; + + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { + err = snd_hdac_display_power(bus, false); + if (err < 0) { + dev_err(bus->dev, "Cannot turn off display power on i915\n"); + return; + } + } + + /* register platform dai and controls */ + err = skl_platform_register(bus->dev); + if (err < 0) + return; + /* + * we are done probing so decrement link counts + */ + list_for_each_entry(hlink, &ebus->hlink_list, list) + snd_hdac_ext_bus_link_put(ebus, hlink); + + /* configure PM */ + pm_runtime_put_noidle(bus->dev); + pm_runtime_allow(bus->dev); + skl->init_done = 1; + + return; + +out_err: + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + err = snd_hdac_display_power(bus, false); +} + /* * constructor */ @@ -593,6 +673,7 @@ static int skl_create(struct pci_dev *pci, snd_hdac_ext_bus_init(ebus, &pci->dev, &bus_core_ops, io_ops); ebus->bus.use_posbuf = 1; skl->pci = pci; + INIT_WORK(&skl->probe_work, skl_probe_work); ebus->bus.bdl_pos_adj = 0; @@ -601,27 +682,6 @@ static int skl_create(struct pci_dev *pci, return 0; } -static int skl_i915_init(struct hdac_bus *bus) -{ - int err; - - /* - * The HDMI codec is in GPU so we need to ensure that it is powered - * up and ready for probe - */ - err = snd_hdac_i915_init(bus); - if (err < 0) - return err; - - err = snd_hdac_display_power(bus, true); - if (err < 0) { - dev_err(bus->dev, "Cannot turn on display power on i915\n"); - return err; - } - - return err; -} - static int skl_first_init(struct hdac_ext_bus *ebus) { struct skl *skl = ebus_to_skl(ebus); @@ -684,20 +744,7 @@ static int skl_first_init(struct hdac_ext_bus *ebus) /* initialize chip */ skl_init_pci(skl); - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - err = skl_i915_init(bus); - if (err < 0) - return err; - } - - skl_init_chip(bus, true); - - /* codec detection */ - if (!bus->codec_mask) { - dev_info(bus->dev, "no hda codecs found!\n"); - } - - return 0; + return skl_init_chip(bus, true); } static int skl_probe(struct pci_dev *pci, @@ -706,7 +753,6 @@ static int skl_probe(struct pci_dev *pci, struct skl *skl; struct hdac_ext_bus *ebus = NULL; struct hdac_bus *bus = NULL; - struct hdac_ext_link *hlink = NULL; int err; /* we use ext core ops, so provide NULL for ops here */ @@ -729,7 +775,7 @@ static int skl_probe(struct pci_dev *pci, if (skl->nhlt == NULL) { err = -ENODEV; - goto out_display_power_off; + goto out_free; } err = skl_nhlt_create_sysfs(skl); @@ -760,56 +806,24 @@ static int skl_probe(struct pci_dev *pci, if (bus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(ebus); + snd_hdac_bus_stop_chip(bus); + /* create device for soc dmic */ err = skl_dmic_device_register(skl); if (err < 0) goto out_dsp_free; - /* register platform dai and controls */ - err = skl_platform_register(bus->dev); - if (err < 0) - goto out_dmic_free; - - /* create codec instances */ - err = skl_codec_create(ebus); - if (err < 0) - goto out_unregister; - - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - err = snd_hdac_display_power(bus, false); - if (err < 0) { - dev_err(bus->dev, "Cannot turn off display power on i915\n"); - return err; - } - } - - /* - * we are done probling so decrement link counts - */ - list_for_each_entry(hlink, &ebus->hlink_list, list) - snd_hdac_ext_bus_link_put(ebus, hlink); - - /* configure PM */ - pm_runtime_put_noidle(bus->dev); - pm_runtime_allow(bus->dev); + schedule_work(&skl->probe_work); return 0; -out_unregister: - skl_platform_unregister(bus->dev); -out_dmic_free: - skl_dmic_device_unregister(skl); out_dsp_free: skl_free_dsp(skl); out_mach_free: skl_machine_device_unregister(skl); out_nhlt_free: skl_nhlt_free(skl->nhlt); -out_display_power_off: - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - snd_hdac_display_power(bus, false); out_free: - skl->init_failed = 1; skl_free(ebus); return err; @@ -828,7 +842,7 @@ static void skl_shutdown(struct pci_dev *pci) skl = ebus_to_skl(ebus); - if (skl->init_failed) + if (!skl->init_done) return; snd_hdac_ext_stop_streams(ebus); @@ -852,6 +866,8 @@ static void skl_remove(struct pci_dev *pci) /* codec removal, invoke bus_device_remove */ snd_hdac_ext_bus_device_remove(ebus); + skl_debugfs_exit(skl->debugfs); + skl->debugfs = NULL; skl_platform_unregister(&pci->dev); skl_free_dsp(skl); skl_machine_device_unregister(skl); @@ -862,29 +878,120 @@ static void skl_remove(struct pci_dev *pci) dev_set_drvdata(&pci->dev, NULL); } +static struct sst_codecs skl_codecs = { + .num_codecs = 1, + .codecs = {"NAU88L25"} +}; + +static struct sst_codecs kbl_codecs = { + .num_codecs = 1, + .codecs = {"NAU88L25"} +}; + +static struct sst_codecs bxt_codecs = { + .num_codecs = 1, + .codecs = {"MX98357A"} +}; + +static struct sst_codecs kbl_poppy_codecs = { + .num_codecs = 1, + .codecs = {"10EC5663"} +}; + +static struct sst_codecs kbl_5663_5514_codecs = { + .num_codecs = 2, + .codecs = {"10EC5663", "10EC5514"} +}; + + static struct sst_acpi_mach sst_skl_devdata[] = { - { "INT343A", "skl_alc286s_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL }, - { "INT343B", "skl_n88l25_s4567", "intel/dsp_fw_release.bin", - NULL, NULL, &skl_dmic_data }, - { "MX98357A", "skl_n88l25_m98357a", "intel/dsp_fw_release.bin", - NULL, NULL, &skl_dmic_data }, + { + .id = "INT343A", + .drv_name = "skl_alc286s_i2s", + .fw_filename = "intel/dsp_fw_release.bin", + }, + { + .id = "INT343B", + .drv_name = "skl_n88l25_s4567", + .fw_filename = "intel/dsp_fw_release.bin", + .machine_quirk = sst_acpi_codec_list, + .quirk_data = &skl_codecs, + .pdata = &skl_dmic_data + }, + { + .id = "MX98357A", + .drv_name = "skl_n88l25_m98357a", + .fw_filename = "intel/dsp_fw_release.bin", + .machine_quirk = sst_acpi_codec_list, + .quirk_data = &skl_codecs, + .pdata = &skl_dmic_data + }, {} }; static struct sst_acpi_mach sst_bxtp_devdata[] = { - { "INT343A", "bxt_alc298s_i2s", "intel/dsp_fw_bxtn.bin", NULL, NULL, NULL }, - { "DLGS7219", "bxt_da7219_max98357a_i2s", "intel/dsp_fw_bxtn.bin", NULL, NULL, NULL }, + { + .id = "INT343A", + .drv_name = "bxt_alc298s_i2s", + .fw_filename = "intel/dsp_fw_bxtn.bin", + }, + { + .id = "DLGS7219", + .drv_name = "bxt_da7219_max98357a_i2s", + .fw_filename = "intel/dsp_fw_bxtn.bin", + .machine_quirk = sst_acpi_codec_list, + .quirk_data = &bxt_codecs, + }, }; static struct sst_acpi_mach sst_kbl_devdata[] = { - { "INT343A", "kbl_alc286s_i2s", "intel/dsp_fw_kbl.bin", NULL, NULL, NULL }, - { "INT343B", "kbl_n88l25_s4567", "intel/dsp_fw_kbl.bin", NULL, NULL, &skl_dmic_data }, - { "MX98357A", "kbl_n88l25_m98357a", "intel/dsp_fw_kbl.bin", NULL, NULL, &skl_dmic_data }, + { + .id = "INT343A", + .drv_name = "kbl_alc286s_i2s", + .fw_filename = "intel/dsp_fw_kbl.bin", + }, + { + .id = "INT343B", + .drv_name = "kbl_n88l25_s4567", + .fw_filename = "intel/dsp_fw_kbl.bin", + .machine_quirk = sst_acpi_codec_list, + .quirk_data = &kbl_codecs, + .pdata = &skl_dmic_data + }, + { + .id = "MX98357A", + .drv_name = "kbl_n88l25_m98357a", + .fw_filename = "intel/dsp_fw_kbl.bin", + .machine_quirk = sst_acpi_codec_list, + .quirk_data = &kbl_codecs, + .pdata = &skl_dmic_data + }, + { + .id = "MX98927", + .drv_name = "kbl_r5514_5663_max", + .fw_filename = "intel/dsp_fw_kbl.bin", + .machine_quirk = sst_acpi_codec_list, + .quirk_data = &kbl_5663_5514_codecs, + .pdata = &skl_dmic_data + }, + { + .id = "MX98927", + .drv_name = "kbl_rt5663_m98927", + .fw_filename = "intel/dsp_fw_kbl.bin", + .machine_quirk = sst_acpi_codec_list, + .quirk_data = &kbl_poppy_codecs, + .pdata = &skl_dmic_data + }, + {} }; static struct sst_acpi_mach sst_glk_devdata[] = { - { "INT343A", "glk_alc298s_i2s", "intel/dsp_fw_glk.bin", NULL, NULL, NULL }, + { + .id = "INT343A", + .drv_name = "glk_alc298s_i2s", + .fw_filename = "intel/dsp_fw_glk.bin", + }, }; /* PCI IDs */ diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index a454f6035f3e..14e7778d7f80 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -23,6 +23,7 @@ #include <sound/hda_register.h> #include <sound/hdaudio_ext.h> +#include <sound/soc.h> #include "skl-nhlt.h" #define SKL_SUSPEND_DELAY 2000 @@ -42,11 +43,13 @@ struct skl_dsp_resource { u32 mem; }; +struct skl_debug; + struct skl { struct hdac_ext_bus ebus; struct pci_dev *pci; - unsigned int init_failed:1; /* delayed init failed */ + unsigned int init_done:1; /* delayed init status */ struct platform_device *dmic_dev; struct platform_device *i2s_dev; struct snd_soc_platform *platform; @@ -64,6 +67,10 @@ struct skl { const struct firmware *tplg; int supend_active; + + struct work_struct probe_work; + + struct skl_debug *debugfs; }; #define skl_to_ebus(s) (&(s)->ebus) @@ -114,4 +121,25 @@ void skl_update_d0i3c(struct device *dev, bool enable); int skl_nhlt_create_sysfs(struct skl *skl); void skl_nhlt_remove_sysfs(struct skl *skl); +struct skl_module_cfg; + +#ifdef CONFIG_DEBUG_FS +struct skl_debug *skl_debugfs_init(struct skl *skl); +void skl_debugfs_exit(struct skl_debug *d); +void skl_debug_init_module(struct skl_debug *d, + struct snd_soc_dapm_widget *w, + struct skl_module_cfg *mconfig); +#else +static inline struct skl_debug *skl_debugfs_init(struct skl *skl) +{ + return NULL; +} +static inline void skl_debugfs_exit(struct skl_debug *d) +{} +static inline void skl_debug_init_module(struct skl_debug *d, + struct snd_soc_dapm_widget *w, + struct skl_module_cfg *mconfig) +{} +#endif + #endif /* __SOUND_SOC_SKL_H */ diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 974915cb4c4f..f54843342ee2 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -116,6 +116,7 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP); + udelay(150); regmap_update_bits(i2s->regmap, I2S_CLR, I2S_CLR_TXC | I2S_CLR_RXC, I2S_CLR_TXC | I2S_CLR_RXC); @@ -162,6 +163,7 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP); + udelay(150); regmap_update_bits(i2s->regmap, I2S_CLR, I2S_CLR_TXC | I2S_CLR_RXC, I2S_CLR_TXC | I2S_CLR_RXC); diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index bfd71b873ca2..206f36bf43e8 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -81,7 +81,8 @@ out: static int soc_compr_open_fe(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *fe = cstream->private_data; - struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream; + struct snd_pcm_substream *fe_substream = + fe->pcm->streams[cstream->direction].substream; struct snd_soc_platform *platform = fe->platform; struct snd_soc_dai *cpu_dai = fe->cpu_dai; struct snd_soc_dpcm *dpcm; @@ -467,7 +468,8 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, struct snd_compr_params *params) { struct snd_soc_pcm_runtime *fe = cstream->private_data; - struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream; + struct snd_pcm_substream *fe_substream = + fe->pcm->streams[cstream->direction].substream; struct snd_soc_platform *platform = fe->platform; struct snd_soc_dai *cpu_dai = fe->cpu_dai; int ret = 0, stream; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9ba183781017..921622a01944 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -69,6 +69,20 @@ static int pmdown_time = 5000; module_param(pmdown_time, int, 0); MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); +/* If a DMI filed contain strings in this blacklist (e.g. + * "Type2 - Board Manufacturer" or "Type1 - TBD by OEM"), it will be taken + * as invalid and dropped when setting the card long name from DMI info. + */ +static const char * const dmi_blacklist[] = { + "To be filled by OEM", + "TBD by OEM", + "Default String", + "Board Manufacturer", + "Board Vendor Name", + "Board Product Name", + NULL, /* terminator */ +}; + /* returns the minimum number of bytes needed to represent * a particular given value */ static int min_bytes_needed(unsigned long val) @@ -1934,6 +1948,22 @@ static void cleanup_dmi_name(char *name) name[j] = '\0'; } +/* Check if a DMI field is valid, i.e. not containing any string + * in the black list. + */ +static int is_dmi_valid(const char *field) +{ + int i = 0; + + while (dmi_blacklist[i]) { + if (strstr(field, dmi_blacklist[i])) + return 0; + i++; + } + + return 1; +} + /** * snd_soc_set_dmi_name() - Register DMI names to card * @card: The card to register DMI names @@ -1976,17 +2006,18 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) /* make up dmi long name as: vendor.product.version.board */ vendor = dmi_get_system_info(DMI_BOARD_VENDOR); - if (!vendor) { + if (!vendor || !is_dmi_valid(vendor)) { dev_warn(card->dev, "ASoC: no DMI vendor name!\n"); return 0; } + snprintf(card->dmi_longname, sizeof(card->snd_card->longname), "%s", vendor); cleanup_dmi_name(card->dmi_longname); product = dmi_get_system_info(DMI_PRODUCT_NAME); - if (product) { + if (product && is_dmi_valid(product)) { len = strlen(card->dmi_longname); snprintf(card->dmi_longname + len, longname_buf_size - len, @@ -2000,7 +2031,7 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) * name in the product version field */ product_version = dmi_get_system_info(DMI_PRODUCT_VERSION); - if (product_version) { + if (product_version && is_dmi_valid(product_version)) { len = strlen(card->dmi_longname); snprintf(card->dmi_longname + len, longname_buf_size - len, @@ -2013,7 +2044,7 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) } board = dmi_get_system_info(DMI_BOARD_NAME); - if (board) { + if (board && is_dmi_valid(board)) { len = strlen(card->dmi_longname); snprintf(card->dmi_longname + len, longname_buf_size - len, @@ -2287,6 +2318,9 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) list_for_each_entry(rtd, &card->rtd_list, list) flush_delayed_work(&rtd->delayed_work); + /* free the ALSA card at first; this syncs with pending operations */ + snd_card_free(card->snd_card); + /* remove and free each DAI */ soc_remove_dai_links(card); soc_remove_pcm_runtimes(card); @@ -2301,9 +2335,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) if (card->remove) card->remove(card); - snd_card_free(card->snd_card); return 0; - } /* removes a socdev */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 002772e3ba2c..dd3a391476ae 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -242,6 +242,14 @@ static const struct soc_tplg_map dapm_map[] = { {SND_SOC_TPLG_DAPM_DAI_IN, snd_soc_dapm_dai_in}, {SND_SOC_TPLG_DAPM_DAI_OUT, snd_soc_dapm_dai_out}, {SND_SOC_TPLG_DAPM_DAI_LINK, snd_soc_dapm_dai_link}, + {SND_SOC_TPLG_DAPM_BUFFER, snd_soc_dapm_buffer}, + {SND_SOC_TPLG_DAPM_SCHEDULER, snd_soc_dapm_scheduler}, + {SND_SOC_TPLG_DAPM_EFFECT, snd_soc_dapm_effect}, + {SND_SOC_TPLG_DAPM_SIGGEN, snd_soc_dapm_siggen}, + {SND_SOC_TPLG_DAPM_SRC, snd_soc_dapm_src}, + {SND_SOC_TPLG_DAPM_ASRC, snd_soc_dapm_asrc}, + {SND_SOC_TPLG_DAPM_ENCODER, snd_soc_dapm_encoder}, + {SND_SOC_TPLG_DAPM_DECODER, snd_soc_dapm_decoder}, }; static int tplc_chan_get_reg(struct soc_tplg *tplg, diff --git a/sound/soc/zte/zx-i2s.c b/sound/soc/zte/zx-i2s.c index a865f37c2a56..8bbad1d72bc5 100644 --- a/sound/soc/zte/zx-i2s.c +++ b/sound/soc/zte/zx-i2s.c @@ -203,13 +203,15 @@ static int zx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: - i2s->master = 1; - val |= ZX_I2S_TIMING_MAST; - break; - case SND_SOC_DAIFMT_CBS_CFS: + /* Codec is master, and I2S is slave. */ i2s->master = 0; val |= ZX_I2S_TIMING_SLAVE; break; + case SND_SOC_DAIFMT_CBS_CFS: + /* Codec is slave, and I2S is master. */ + i2s->master = 1; + val |= ZX_I2S_TIMING_MAST; + break; default: dev_err(cpu_dai->dev, "Unknown master/slave format\n"); return -EINVAL; @@ -226,11 +228,12 @@ static int zx_i2s_hw_params(struct snd_pcm_substream *substream, struct zx_i2s_info *i2s = snd_soc_dai_get_drvdata(socdai); struct snd_dmaengine_dai_dma_data *dma_data; unsigned int lane, ch_num, len, ret = 0; + unsigned int ts_width = 32; unsigned long val; unsigned long chn_cfg; dma_data = snd_soc_dai_get_dma_data(socdai, substream); - dma_data->addr_width = params_width(params) >> 3; + dma_data->addr_width = ts_width >> 3; val = readl_relaxed(i2s->reg_base + ZX_I2S_TIMING_CTRL); val &= ~(ZX_I2S_TIMING_TS_WIDTH_MASK | ZX_I2S_TIMING_DATA_SIZE_MASK | @@ -251,7 +254,7 @@ static int zx_i2s_hw_params(struct snd_pcm_substream *substream, dev_err(socdai->dev, "Unknown data format\n"); return -EINVAL; } - val |= ZX_I2S_TIMING_TS_WIDTH(len) | ZX_I2S_TIMING_DATA_SIZE(len); + val |= ZX_I2S_TIMING_TS_WIDTH(ts_width) | ZX_I2S_TIMING_DATA_SIZE(len); ch_num = params_channels(params); switch (ch_num) { diff --git a/sound/usb/mixer_us16x08.c b/sound/usb/mixer_us16x08.c index dc48eedea92e..26ed23b18b77 100644 --- a/sound/usb/mixer_us16x08.c +++ b/sound/usb/mixer_us16x08.c @@ -698,16 +698,18 @@ static int snd_us16x08_meter_get(struct snd_kcontrol *kcontrol, struct snd_usb_audio *chip = elem->head.mixer->chip; struct snd_us16x08_meter_store *store = elem->private_data; u8 meter_urb[64]; - char tmp[sizeof(mix_init_msg2)] = {0}; switch (kcontrol->private_value) { - case 0: - snd_us16x08_send_urb(chip, (char *)mix_init_msg1, - sizeof(mix_init_msg1)); + case 0: { + char tmp[sizeof(mix_init_msg1)]; + + memcpy(tmp, mix_init_msg1, sizeof(mix_init_msg1)); + snd_us16x08_send_urb(chip, tmp, 4); snd_us16x08_recv_urb(chip, meter_urb, sizeof(meter_urb)); kcontrol->private_value++; break; + } case 1: snd_us16x08_recv_urb(chip, meter_urb, sizeof(meter_urb)); @@ -718,15 +720,18 @@ static int snd_us16x08_meter_get(struct snd_kcontrol *kcontrol, sizeof(meter_urb)); kcontrol->private_value++; break; - case 3: + case 3: { + char tmp[sizeof(mix_init_msg2)]; + memcpy(tmp, mix_init_msg2, sizeof(mix_init_msg2)); tmp[2] = snd_get_meter_comp_index(store); - snd_us16x08_send_urb(chip, tmp, sizeof(mix_init_msg2)); + snd_us16x08_send_urb(chip, tmp, 10); snd_us16x08_recv_urb(chip, meter_urb, sizeof(meter_urb)); kcontrol->private_value = 0; break; } + } for (set = 0; set < 6; set++) get_meter_levels_from_urb(set, store, meter_urb); @@ -1135,7 +1140,7 @@ static const struct snd_us16x08_control_params eq_controls[] = { .control_id = SND_US16X08_ID_EQLOWMIDWIDTH, .type = USB_MIXER_U8, .num_channels = 16, - .name = "EQ MidQLow Q", + .name = "EQ MidLow Q", }, { /* EQ mid high gain */ .kcontrol_new = &snd_us16x08_eq_gain_ctl, diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 01eff6ce6401..d7b0b0a3a2db 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1364,7 +1364,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, /* Amanero Combo384 USB interface with native DSD support */ case USB_ID(0x16d0, 0x071a): if (fp->altsetting == 2) { - switch (chip->dev->descriptor.bcdDevice) { + switch (le16_to_cpu(chip->dev->descriptor.bcdDevice)) { case 0x199: return SNDRV_PCM_FMTBIT_DSD_U32_LE; case 0x19b: diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 664b7fe206d6..b11d3920b9a5 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1809,10 +1809,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) pdata->notify_pending = false; spin_unlock_irq(&pdata->lpe_audio_slock); - /* runtime PM isn't enabled as default, since it won't save much on - * BYT/CHT devices; user who want the runtime PM should adjust the - * power/ontrol and power/autosuspend_delay_ms sysfs entries instead - */ pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_set_active(&pdev->dev); |