I believe I found a suitable solution. I intend to put the system into standby mode and resume from standby when i enter this reduced power battery backed up state.
I added the following to the tlv320aic31xx.c and eukrea drivers. I believe the critical changes is the suspend function for eureka which unregisters the card as well as the remove function in tlv320aic31xx.c which cleans up the regulator notifiers. This allows me to unregister/remove the card on entering low power and restore it correctly on getting power back.
I am now working on using a single GPIO to trigger suspend on falling edge and resume on rising edge.
I can clean up the below patch and trim it down to just the essentials if it is of interest to the community. This is based on our modified eukrea-tlv320 driver for use with the TLV320AIC3120. When cleaned up I believe it can be used with the mainline eukrea driver as well.
From 8c7998dba1510f2cbab20c69af1f89c807018a6e Mon Sep 17 00:00:00 2001
From: Dexter Travis dexter.travis@precisionplanting.com Date: Wed, 29 Apr 2020 14:24:56 -0500 Subject: [PATCH] add suspend/remove functions to eukrea and tlv to register and unregister the sound card on suspend/resume.
--- sound/soc/codecs/tlv320aic31xx.c | 45 +++++++++++++++++++++++++++++++- sound/soc/fsl/eukrea-tlv320.c | 17 ++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 31daa60695bd..e7db7399fee7 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1314,12 +1314,22 @@ static int aic31xx_set_jack(struct snd_soc_component *component, return 0; }
+static int aic31xx_codec_suspend(struct snd_soc_component *component) { + printk("DGT: %s:%d\n", __func__, __LINE__); + return 0; +} + +static int aic31xx_codec_resume(struct snd_soc_component *component) { + printk("DGT: %s, %d\n", __func__, __LINE__); + return 0; +} + static int aic31xx_codec_probe(struct snd_soc_component *component) { struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component); int i, ret;
- dev_dbg(aic31xx->dev, "## %s\n", __func__); + dev_dbg(aic31xx->dev, "DGT ## %s\n", __func__);
aic31xx->component = component;
@@ -1357,8 +1367,27 @@ static int aic31xx_codec_probe(struct snd_soc_component *component) return 0; }
+static void aic31xx_codec_remove(struct snd_soc_component *component) { + struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component); + int i; + + dev_dbg(aic31xx->dev, "DGT: ## %s\n", __func__); + + for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) { + aic31xx->disable_nb[i].nb.notifier_call = + aic31xx_regulator_event; + aic31xx->disable_nb[i].aic31xx = aic31xx; + devm_regulator_unregister_notifier( + aic31xx->supplies[i].consumer, + &aic31xx->disable_nb[i].nb); + } +}; + static const struct snd_soc_component_driver soc_codec_driver_aic31xx = { .probe = aic31xx_codec_probe, + .suspend = aic31xx_codec_suspend, + .resume = aic31xx_codec_resume, + .remove = aic31xx_codec_remove, .set_jack = aic31xx_set_jack, .set_bias_level = aic31xx_set_bias_level, .controls = common31xx_snd_controls, @@ -1372,6 +1401,7 @@ static const struct snd_soc_component_driver soc_codec_driver_aic31xx = { .use_pmdown_time = 1, .endianness = 1, .non_legacy_dai_naming = 1, + };
static const struct snd_soc_dai_ops aic31xx_dai_ops = { @@ -1698,11 +1728,24 @@ static const struct i2c_device_id aic31xx_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id);
+static int aic31xx_i2c_suspend(struct device *dev, pm_message_t state) { + + printk("DGT: %d, %s:%d\n", state.event, __func__, __LINE__); + return 0; +} + +static int aic31xx_i2c_resume(struct device *dev) { + printk("DGT: %s, %d\n", __func__, __LINE__); + return 0; +} + static struct i2c_driver aic31xx_i2c_driver = { .driver = { .name = "tlv320aic31xx-codec", .of_match_table = of_match_ptr(tlv320aic31xx_of_match), .acpi_match_table = ACPI_PTR(aic31xx_acpi_match), + .suspend = aic31xx_i2c_suspend, + .resume = aic31xx_i2c_resume, }, .probe = aic31xx_i2c_probe, .id_table = aic31xx_i2c_id, diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index 09133b085fd2..f4a598a5f18e 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c @@ -82,6 +82,18 @@ static struct snd_soc_card eukrea_tlv320 = { .num_links = 1, };
+static int eukrea_tlv320_suspend(struct platform_device *pdev, pm_message_t state) { + printk("DGT: %s,%d state: %d\n", __func__, __LINE__, state.event); + snd_soc_unregister_card(&eukrea_tlv320); + return 0; +} + +static int eukrea_tlv320_resume(struct platform_device *pdev) { + printk("DGT: %s,%d\n", __func__, __LINE__); + snd_soc_register_card(&eukrea_tlv320); + return 0; +} + static int eukrea_tlv320_probe(struct platform_device *pdev) { int ret; @@ -89,6 +101,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct device_node *ssi_np = NULL, *codec_np = NULL; struct clk *codec_clk = NULL; + printk("DGT: %s,%d\n", __func__, __LINE__); eukrea_tlv320.dev = &pdev->dev; if (np) { ret = snd_soc_of_parse_card_name(&eukrea_tlv320, @@ -120,6 +133,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) "fsl,mux-int-port node missing or invalid.\n"); goto err; } + ret = of_property_read_u32(np, "fsl,mux-ext-port", &ext_port); if (ret) { dev_err(&pdev->dev, @@ -214,6 +228,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev)
static int eukrea_tlv320_remove(struct platform_device *pdev) { + printk("DGT: %s,%d\n", __func__, __LINE__); snd_soc_unregister_card(&eukrea_tlv320);
return 0; @@ -232,6 +247,8 @@ static struct platform_driver eukrea_tlv320_driver = { }, .probe = eukrea_tlv320_probe, .remove = eukrea_tlv320_remove, + .suspend = eukrea_tlv320_suspend, + .resume = eukrea_tlv320_resume, };
module_platform_driver(eukrea_tlv320_driver);