[d-kernel] [PATCH 1/4] ASoC: AMD: add ACP machine driver for ES8336
nickel на altlinux.org
nickel на altlinux.org
Ср Апр 5 19:59:40 MSK 2023
From: Vasiliy Kovalev <kovalev at altlinux.org>
Backport from 6.1.3
Based on commit 6976fc0fea0dcc5a367580cd7edf94574601837e from
fork of Marian Postevca aka @codepayne
Link: https://github.com/thesofproject/linux/issues/3249#issuecomment-1378025039
Link: https://github.com/codepayne/linux-sound-huawei/issues/5
fix conflict use pci-acp driver for ES8336 codec (kovalev)
For a family of machines whose pci revision ID is 0x1 (renoir),
working with the es8336 codec is only available through the
snd-pci-acp3x driver (raven). Now we will use a specific driver
if there is an acpi device detected as "ESSX8336" in the machine.
Signed-off-by: Vasiliy Kovalev <kovalev at altlinux.org>
Signed-off-by: Nikolai Kostrigin <nickel at altlinux.org>
---
config | 1 +
sound/soc/amd/Kconfig | 13 ++
sound/soc/amd/Makefile | 2 +
sound/soc/amd/acp3x-es8336.c | 395 ++++++++++++++++++++++++++++++++
sound/soc/amd/raven/pci-acp3x.c | 7 +-
sound/soc/codecs/es8316.c | 85 +++++--
6 files changed, 476 insertions(+), 27 deletions(-)
create mode 100644 sound/soc/amd/acp3x-es8336.c
diff --git a/config b/config
index 7a9be2c8203ff..61e6930c3b532 100644
--- a/config
+++ b/config
@@ -6833,6 +6833,7 @@ CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH=m
CONFIG_SND_SOC_AMD_CZ_RT5645_MACH=m
CONFIG_SND_SOC_AMD_ST_ES8336_MACH=m
CONFIG_SND_SOC_AMD_ACP3x=m
+CONFIG_SND_SOC_AMD_ACP3x_ES8336_MACH=m
CONFIG_SND_SOC_AMD_RV_RT5682_MACH=m
CONFIG_SND_SOC_AMD_RENOIR=m
CONFIG_SND_SOC_AMD_RENOIR_MACH=m
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
index 150786279257d..605e332cb6f30 100644
--- a/sound/soc/amd/Kconfig
+++ b/sound/soc/amd/Kconfig
@@ -41,6 +41,19 @@ config SND_SOC_AMD_ACP3x
help
This option enables ACP v3.x I2S support on AMD platform
+config SND_SOC_AMD_ACP3x_ES8336_MACH
+ tristate "AMD ACP3x support for ES8336"
+ select SND_SOC_ACPI if ACPI
+ select SND_SOC_ES8316
+ depends on ACPI
+ depends on I2C
+ depends on SND_SOC_AMD_ACP3x
+ help
+ This option enables machine driver for ACP3x platform
+ using es8336 codec.
+ Say m if you have such a device.
+ If unsure select "N".
+
config SND_SOC_AMD_RV_RT5682_MACH
tristate "AMD RV support for RT5682"
select CLK_FIXED_FCH
diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile
index 82e1cf864a409..959b3439b03dc 100644
--- a/sound/soc/amd/Makefile
+++ b/sound/soc/amd/Makefile
@@ -5,6 +5,7 @@ snd-soc-acp-rt5645-mach-objs := acp-rt5645.o
snd-soc-acp-es8336-mach-objs := acp-es8336.o
snd-soc-acp-rt5682-mach-objs := acp3x-rt5682-max9836.o
snd-acp-config-objs := acp-config.o
+snd-soc-acp3x-es8336-mach-objs := acp3x-es8336.o
obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o
obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o
@@ -19,3 +20,4 @@ obj-$(CONFIG_SND_SOC_AMD_ACP_COMMON) += acp/
obj-$(CONFIG_SND_AMD_ACP_CONFIG) += snd-acp-config.o
obj-$(CONFIG_SND_SOC_AMD_RPL_ACP6x) += rpl/
obj-$(CONFIG_SND_SOC_AMD_PS) += ps/
+obj-$(CONFIG_SND_SOC_AMD_ACP3x_ES8336_MACH) += snd-soc-acp3x-es8336-mach.o
diff --git a/sound/soc/amd/acp3x-es8336.c b/sound/soc/amd/acp3x-es8336.c
new file mode 100644
index 0000000000000..fd23afa50eb52
--- /dev/null
+++ b/sound/soc/amd/acp3x-es8336.c
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Machine driver for AMD ACP Audio engine using DA7219 & MAX98357 codec.
+//
+//Copyright 2016 Advanced Micro Devices, Inc.
+
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+
+#include "raven/acp3x.h"
+
+#define DRV_NAME "amd-acp3x-essx8336"
+#define SND_CARD_NAME DRV_NAME
+#define DUAL_CHANNEL 2
+
+struct acp3x_es8336_private {
+ /* struct acp3x_platform_info machine must always be
+ * the first entry in the structure,
+ * the acp3x-i2s driver casts the card private data to
+ * struct acp3x_platform_info
+ */
+ struct acp3x_platform_info machine;
+ struct device *codec_dev;
+ struct gpio_desc *gpio_speakers;
+ bool speaker_en;
+};
+
+static const unsigned int channels[] = {
+ DUAL_CHANNEL,
+};
+
+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 struct snd_pcm_hw_constraint_list constraints_channels = {
+ .count = ARRAY_SIZE(channels),
+ .list = channels,
+ .mask = 0,
+};
+#define ES8336_MCLK_FREQ (48000 * 1000)
+
+static int acp3x_es8336_codec_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime;
+ struct snd_soc_pcm_runtime *rtd;
+ struct acp3x_platform_info *machine;
+ struct acp3x_es8336_private *priv;
+ struct snd_soc_dai *codec_dai;
+ int ret;
+
+ runtime = substream->runtime;
+ rtd = asoc_substream_to_rtd(substream);
+ priv = snd_soc_card_get_drvdata(rtd->card);
+ machine = &priv->machine;
+ codec_dai = asoc_rtd_to_codec(rtd, 0);
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, ES8336_MCLK_FREQ, SND_SOC_CLOCK_OUT);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBP_CFP);
+ if (ret < 0) {
+ dev_err(rtd->dev, "failed to set DAI fmt: %d\n", ret);
+ return ret;
+ }
+ /* Report to userspace ALSA that we don't support suspending and resuming pcm streams,
+ * this means that during suspends and resumes of the PC, pulseaudio will not try to resume
+ * the substream, but will drop the connection and establish a new one.
+ * This is needed because sometimes after resume pulseaudio is unable to resume the stream
+ * and no sound can be heard. As a workaround for this issue, pulseaudio needs to be restarted.
+ */
+ runtime->hw.info &= ~(SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME);
+
+ runtime->hw.channels_max = DUAL_CHANNEL;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_rates);
+ runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
+ machine->play_i2s_instance = I2S_SP_INSTANCE;
+
+ return 0;
+}
+
+static int acp3x_es8336_speaker_power_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+
+static struct snd_soc_jack es8336_jack;
+
+static struct snd_soc_jack_pin es8336_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static const struct snd_soc_dapm_widget acp3x_es8336_widgets[] = {
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Internal Mic", NULL),
+
+ SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0,
+ acp3x_es8336_speaker_power_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+};
+
+static const struct snd_soc_dapm_route acp3x_es8336_audio_map[] = {
+ {"Headphone", NULL, "HPOL"},
+ {"Headphone", NULL, "HPOR"},
+
+ /*
+ * There is no separate speaker output instead the speakers are muxed to
+ * the HP outputs. The mux is controlled Speaker and/or headphone switch.
+ */
+ {"Speaker", NULL, "HPOL"},
+ {"Speaker", NULL, "HPOR"},
+ {"MIC1", NULL, "Headset Mic"},
+ {"Speaker", NULL, "Speaker Power"},
+};
+
+
+static const struct snd_kcontrol_new acp3x_es8336_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct acpi_gpio_params enable_gpio0 = { 0, 0, true };
+
+static const struct acpi_gpio_mapping acpi_speakers_enable_gpio0[] = {
+ { "speakers-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
+ { }
+};
+
+static int acp3x_es8336_speaker_power_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct acp3x_es8336_private *priv = snd_soc_card_get_drvdata(w->dapm->card);
+
+ if (priv->speaker_en == !SND_SOC_DAPM_EVENT_ON(event))
+ return 0;
+
+ priv->speaker_en = !SND_SOC_DAPM_EVENT_ON(event);
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ msleep(70);
+
+ gpiod_set_value_cansleep(priv->gpio_speakers, priv->speaker_en);
+
+ return 0;
+}
+
+static int acp3x_es8336_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_component *codec = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_card *card = runtime->card;
+ struct acp3x_es8336_private *priv = snd_soc_card_get_drvdata(card);
+ int ret;
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset",
+ SND_JACK_HEADSET | SND_JACK_BTN_0,
+ &es8336_jack, es8336_jack_pins,
+ ARRAY_SIZE(es8336_jack_pins));
+ if (ret) {
+ dev_err(card->dev, "jack creation failed %d\n", ret);
+ return ret;
+ }
+
+ snd_jack_set_key(es8336_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+
+ snd_soc_component_set_jack(codec, &es8336_jack, NULL);
+
+ ret = devm_acpi_dev_add_driver_gpios(codec->dev, acpi_speakers_enable_gpio0);
+ if (ret)
+ dev_warn(codec->dev, "failed to add speaker gpio\n");
+
+ priv->codec_dev = codec->dev;
+ priv->gpio_speakers = gpiod_get_optional(codec->dev, "speakers-enable", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->gpio_speakers)) {
+ dev_err(codec->dev, "could not get speakers-enable GPIO\n");
+ return PTR_ERR(priv->gpio_speakers);
+ }
+
+ return 0;
+}
+
+static struct snd_soc_ops acp3x_es8336_ops = {
+ .startup = acp3x_es8336_codec_startup,
+};
+
+
+SND_SOC_DAILINK_DEF(acp3x_i2s,
+ DAILINK_COMP_ARRAY(COMP_CPU("acp3x_i2s_playcap.0")));
+SND_SOC_DAILINK_DEF(codec,
+ DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ESSX8336:00", "ES8316 HiFi")));
+SND_SOC_DAILINK_DEF(platform,
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("acp3x_rv_i2s_dma.0")));
+
+static struct snd_soc_dai_link acp3x_dai_es8336[] = {
+ {
+ .name = "amd-acp3x-es8336-dai",
+ .stream_name = "ES8336 HiFi Play",
+ .stop_dma_first = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .init = acp3x_es8336_init,
+ .ops = &acp3x_es8336_ops,
+ SND_SOC_DAILINK_REG(acp3x_i2s, codec, platform),
+ },
+};
+
+static struct snd_soc_card acp3x_es8336 = {
+ .name = SND_CARD_NAME,
+ .owner = THIS_MODULE,
+ .dai_link = acp3x_dai_es8336,
+ .num_links = ARRAY_SIZE(acp3x_dai_es8336),
+ .dapm_widgets = acp3x_es8336_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(acp3x_es8336_widgets),
+ .dapm_routes = acp3x_es8336_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(acp3x_es8336_audio_map),
+ .controls = acp3x_es8336_controls,
+ .num_controls = ARRAY_SIZE(acp3x_es8336_controls),
+};
+
+static const struct dmi_system_id acp3x_es8336_dmi_table[] = {
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "KLVL-WXXW"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
+ },
+ .driver_data = &acp3x_es8336,
+ },
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "KLVL-WXX9"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
+ },
+ .driver_data = &acp3x_es8336,
+ },
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "BOM-WXX9"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
+ },
+ .driver_data = &acp3x_es8336,
+ },
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1040"),
+ },
+ .driver_data = &acp3x_es8336,
+ },
+ {}
+};
+
+static int acp3x_probe(struct platform_device *pdev)
+{
+ int ret = -ENODEV;
+ struct device *dev = &pdev->dev;
+ const struct dmi_system_id *dmi_id;
+
+ dmi_id = dmi_first_match(acp3x_es8336_dmi_table);
+ if (dmi_id && dmi_id->driver_data) {
+ struct acp3x_es8336_private *priv;
+ struct snd_soc_card *card;
+
+ dev_info(dev, "matched DMI table with this system, trying to register sound card\n");
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(dev, "can't alloc priv structure\n");
+ return -ENOMEM;
+ }
+
+ card = (struct snd_soc_card *)dmi_id->driver_data;
+
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ snd_soc_card_set_drvdata(card, priv);
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret) {
+ dev_err(dev, "failed to register sound card, ret = %d\n", ret);
+ return dev_err_probe(&pdev->dev, ret,
+ "devm_snd_soc_register_card(%s) failed\n",
+ card->name);
+ } else {
+ dev_info(dev, "successfully registered the sound card\n");
+ }
+ }
+ return ret;
+}
+
+static int acp3x_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct acp3x_es8336_private *priv = snd_soc_card_get_drvdata(card);
+ struct device *dev = &pdev->dev;
+
+ gpiod_put(priv->gpio_speakers);
+
+ dev_info(dev, "removing sound card\n");
+ return 0;
+}
+
+static const struct acpi_device_id acp3x_audio_acpi_match[] = {
+ {"ESSX8336", 0},
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, acp3x_audio_acpi_match);
+
+static struct platform_driver acp3x_audio = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = acp3x_probe,
+ .remove = acp3x_remove,
+};
+
+static struct platform_device *acp3x_es8336_snd_device;
+
+static int __init acp3x_es8336_module_init(void)
+{
+ int ret = -ENODEV;
+
+ msleep(5000);
+ ret = platform_driver_register(&acp3x_audio);
+ if (ret < 0) {
+ printk(KERN_ERR DRV_NAME": can't register platform driver\n");
+ return ret;
+ }
+
+ acp3x_es8336_snd_device = platform_device_register_simple(DRV_NAME, 0, NULL, 0);
+ if (IS_ERR(acp3x_es8336_snd_device)) {
+ printk(KERN_ERR DRV_NAME": couldn't register platform device\n");
+ platform_driver_unregister(&acp3x_audio);
+ return PTR_ERR(acp3x_es8336_snd_device);
+ }
+
+ if (!platform_get_drvdata(acp3x_es8336_snd_device)) {
+ platform_device_unregister(acp3x_es8336_snd_device);
+ platform_driver_unregister(&acp3x_audio);
+ return -ENODEV;
+ }
+ printk(KERN_INFO DRV_NAME": platform device registered successfully\n");
+
+ return ret;
+}
+module_init(acp3x_es8336_module_init);
+
+static void __exit acp3x_es8336_module_exit(void)
+{
+ printk(KERN_INFO DRV_NAME": module unloading\n");
+ platform_device_unregister(acp3x_es8336_snd_device);
+ platform_driver_unregister(&acp3x_audio);
+}
+module_exit(acp3x_es8336_module_exit);
+
+MODULE_AUTHOR("posteuca at mutex.one");
+MODULE_DESCRIPTION("ACP3x rev 1 ES8336 audio support");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c
index a013a607b3d47..312a16c0e624f 100644
--- a/sound/soc/amd/raven/pci-acp3x.c
+++ b/sound/soc/amd/raven/pci-acp3x.c
@@ -11,6 +11,7 @@
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include <linux/delay.h>
+#include <sound/soc-acpi.h>
#include "acp3x.h"
@@ -133,8 +134,10 @@ static int snd_acp3x_probe(struct pci_dev *pci,
int ret, i;
u32 addr, val;
- /* Raven device detection */
- if (pci->revision != 0x00)
+ /* Raven and lucienne device detection */
+ if (acpi_dev_get_first_match_dev("ESSX8336", NULL, -1))
+ dev_info(&pci->dev, "use pci-acp for ES8336 codec\n");
+ else if (pci->revision != 0x00)
return -ENODEV;
if (pci_enable_device(pci)) {
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
index 056c3082fe02c..20a47573409a9 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -27,9 +27,9 @@
* MCLK/LRCK ratios, but we also add ratio 400, which is commonly used on
* Intel Cherry Trail platforms (19.2MHz MCLK, 48kHz LRCK).
*/
-#define NR_SUPPORTED_MCLK_LRCK_RATIOS 6
+#define NR_SUPPORTED_MCLK_LRCK_RATIOS 7
static const unsigned int supported_mclk_lrck_ratios[] = {
- 256, 384, 400, 512, 768, 1024
+ 256, 384, 400, 512, 768, 1000, 1024
};
struct es8316_priv {
@@ -465,10 +465,12 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
u8 bclk_divider;
u16 lrck_divider;
int i;
+ int mclk_div = 1;
+ unsigned int ratio;
/* Validate supported sample rates that are autodetected from MCLK */
for (i = 0; i < NR_SUPPORTED_MCLK_LRCK_RATIOS; i++) {
- const unsigned int ratio = supported_mclk_lrck_ratios[i];
+ ratio = supported_mclk_lrck_ratios[i];
if (es8316->sysclk % ratio != 0)
continue;
@@ -477,7 +479,13 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
}
if (i == NR_SUPPORTED_MCLK_LRCK_RATIOS)
return -EINVAL;
- lrck_divider = es8316->sysclk / params_rate(params);
+
+ if (ratio == 1000) {
+ snd_soc_component_update_bits(component, 0x01, 0x80, 0x80);
+ mclk_div = 2;
+ }
+
+ lrck_divider = es8316->sysclk / params_rate(params) / mclk_div;
bclk_divider = lrck_divider / 4;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
@@ -500,6 +508,15 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ static u8 only_one = 0;
+ if (!only_one) {
+ only_one = 1;
+ if (mclk_div == 2)
+ dev_info(component->dev, "Activating MCLK div by 2\n");
+
+ dev_info(component->dev, "Using lrck div = %d, bclk div = %d, wordlen = %d\n", lrck_divider, bclk_divider, wordlen);
+ }
+
snd_soc_component_update_bits(component, ES8316_SERDATA_DAC,
ES8316_SERDATA2_LEN_MASK, wordlen);
snd_soc_component_update_bits(component, ES8316_SERDATA_ADC,
@@ -520,7 +537,7 @@ static int es8316_mute(struct snd_soc_dai *dai, int mute, int direction)
}
#define ES8316_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
- SNDRV_PCM_FMTBIT_S24_LE)
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops es8316_ops = {
.startup = es8316_pcm_startup,
@@ -717,6 +734,41 @@ static int es8316_set_jack(struct snd_soc_component *component,
return 0;
}
+#ifdef CONFIG_PM
+
+static int es8316_suspend(struct snd_soc_component *component)
+{
+ struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
+ regcache_cache_only(es8316->regmap, true);
+
+ return 0;
+}
+
+static int es8316_resume(struct snd_soc_component *component)
+{
+ struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(es8316->regmap, false);
+ /* Reset codec and enable current state machine */
+ snd_soc_component_write(component, ES8316_RESET, 0x3f);
+ usleep_range(5000, 5500);
+ snd_soc_component_write(component, ES8316_RESET, ES8316_RESET_CSM_ON);
+ msleep(30);
+
+ snd_soc_component_write(component, ES8316_SYS_VMIDSEL, 0xff);
+
+ snd_soc_component_write(component, ES8316_CLKMGR_ADCOSR, 0x32);
+
+ regcache_mark_dirty(es8316->regmap);
+ regcache_sync(es8316->regmap);
+
+ return 0;
+}
+#else
+#define es8316_suspend NULL
+#define es8316_resume NULL
+#endif
+
static int es8316_probe(struct snd_soc_component *component)
{
struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
@@ -767,26 +819,6 @@ static void es8316_remove(struct snd_soc_component *component)
clk_disable_unprepare(es8316->mclk);
}
-static int es8316_resume(struct snd_soc_component *component)
-{
- struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
-
- regcache_cache_only(es8316->regmap, false);
- regcache_sync(es8316->regmap);
-
- return 0;
-}
-
-static int es8316_suspend(struct snd_soc_component *component)
-{
- struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
-
- regcache_cache_only(es8316->regmap, true);
- regcache_mark_dirty(es8316->regmap);
-
- return 0;
-}
-
static const struct snd_soc_component_driver soc_component_dev_es8316 = {
.probe = es8316_probe,
.remove = es8316_remove,
@@ -805,6 +837,9 @@ static const struct snd_soc_component_driver soc_component_dev_es8316 = {
static const struct regmap_range es8316_volatile_ranges[] = {
regmap_reg_range(ES8316_GPIO_FLAG, ES8316_GPIO_FLAG),
+ regmap_reg_range(ES8316_RESET, ES8316_RESET),
+ regmap_reg_range(ES8316_SYS_VMIDSEL,ES8316_SYS_VMIDSEL),
+ regmap_reg_range(ES8316_CLKMGR_ADCOSR,ES8316_CLKMGR_ADCOSR),
};
static const struct regmap_access_table es8316_volatile_table = {
--
2.33.5
Подробная информация о списке рассылки devel-kernel