* [PATCH 5/5] ASoC: cs35l45: Hibernation support
@ 2023-03-02 17:26 Vlad Karpovich
2023-03-02 17:27 ` Mark Brown
0 siblings, 1 reply; 3+ messages in thread
From: Vlad Karpovich @ 2023-03-02 17:26 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Jaroslav Kysela, Takashi Iwai
Cc: alsa-devel, patches, linux-kernel, Vlad.Karpovich
From: "Vlad.Karpovich" <vkarpovi@opensource.cirrus.com>
Adds support for the amplifier hibernation controlled by
DSP firmware.
Signed-off-by: Vlad Karpovich <vkarpovi@opensource.cirrus.com>
---
sound/soc/codecs/cs35l45-i2c.c | 2 +
sound/soc/codecs/cs35l45-spi.c | 1 +
sound/soc/codecs/cs35l45-tables.c | 6 +++
sound/soc/codecs/cs35l45.c | 80 +++++++++++++++++++++++++++++++
sound/soc/codecs/cs35l45.h | 29 +++++++++++
5 files changed, 118 insertions(+)
diff --git a/sound/soc/codecs/cs35l45-i2c.c b/sound/soc/codecs/cs35l45-i2c.c
index 5224aaf584b8..1c644ddf66bc 100644
--- a/sound/soc/codecs/cs35l45-i2c.c
+++ b/sound/soc/codecs/cs35l45-i2c.c
@@ -33,6 +33,8 @@ static int cs35l45_i2c_probe(struct i2c_client *client)
cs35l45->dev = dev;
cs35l45->irq = client->irq;
+ cs35l45->bus_type = CONTROL_BUS_I2C;
+ cs35l45->i2c_addr = client->addr;
return cs35l45_probe(cs35l45);
}
diff --git a/sound/soc/codecs/cs35l45-spi.c b/sound/soc/codecs/cs35l45-spi.c
index bfb79255783e..3ea2e6fd2b88 100644
--- a/sound/soc/codecs/cs35l45-spi.c
+++ b/sound/soc/codecs/cs35l45-spi.c
@@ -36,6 +36,7 @@ static int cs35l45_spi_probe(struct spi_device *spi)
cs35l45->dev = dev;
cs35l45->irq = spi->irq;
+ cs35l45->bus_type = CONTROL_BUS_SPI;
return cs35l45_probe(cs35l45);
}
diff --git a/sound/soc/codecs/cs35l45-tables.c b/sound/soc/codecs/cs35l45-tables.c
index 6b68773979ec..212d9cb5a4fb 100644
--- a/sound/soc/codecs/cs35l45-tables.c
+++ b/sound/soc/codecs/cs35l45-tables.c
@@ -47,6 +47,8 @@ static const struct reg_default cs35l45_defaults[] = {
{ CS35L45_INTB_GPIO2_MCLK_REF, 0x00000005 },
{ CS35L45_GPIO3, 0x00000005 },
{ CS35L45_PWRMGT_CTL, 0x00000000 },
+ { CS35L45_WAKESRC_CTL, 0x00000008 },
+ { CS35L45_WKI2C_CTL, 0x00000030 },
{ CS35L45_REFCLK_INPUT, 0x00000510 },
{ CS35L45_GLOBAL_SAMPLE_RATE, 0x00000003 },
{ CS35L45_ASP_ENABLES1, 0x00000000 },
@@ -126,6 +128,9 @@ static bool cs35l45_readable_reg(struct device *dev, unsigned int reg)
case CS35L45_INTB_GPIO2_MCLK_REF:
case CS35L45_GPIO3:
case CS35L45_PWRMGT_CTL:
+ case CS35L45_WAKESRC_CTL:
+ case CS35L45_WKI2C_CTL:
+ case CS35L45_PWRMGT_STS:
case CS35L45_REFCLK_INPUT:
case CS35L45_GLOBAL_SAMPLE_RATE:
case CS35L45_ASP_ENABLES1:
@@ -210,6 +215,7 @@ static bool cs35l45_volatile_reg(struct device *dev, unsigned int reg)
case CS35L45_GLOBAL_ENABLES:
case CS35L45_ERROR_RELEASE:
case CS35L45_AMP_PCM_HPF_TST: /* not cachable */
+ case CS35L45_PWRMGT_STS:
case CS35L45_IRQ1_STATUS:
case CS35L45_IRQ1_EINT_1 ... CS35L45_IRQ1_EINT_18:
case CS35L45_IRQ1_STS_1 ... CS35L45_IRQ1_STS_18:
diff --git a/sound/soc/codecs/cs35l45.c b/sound/soc/codecs/cs35l45.c
index c5de2c8a9fe3..a2bab613daa2 100644
--- a/sound/soc/codecs/cs35l45.c
+++ b/sound/soc/codecs/cs35l45.c
@@ -36,6 +36,8 @@ static bool cs35l45_check_cspl_mbox_sts(const enum cs35l45_cspl_mboxcmd cmd,
return (sts == CSPL_MBOX_STS_RUNNING);
case CSPL_MBOX_CMD_STOP_PRE_REINIT:
return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT);
+ case CSPL_MBOX_CMD_HIBERNATE:
+ return (sts == CSPL_MBOX_STS_HIBERNATE);
default:
return false;
}
@@ -745,11 +747,81 @@ static const struct snd_soc_component_driver cs35l45_component = {
.endianness = 1,
};
+static void cs35l45_setup_hibernate(struct cs35l45_private *cs35l45)
+{
+ unsigned int wksrc;
+
+ if (cs35l45->bus_type == CONTROL_BUS_I2C)
+ wksrc = CS35L45_WKSRC_I2C;
+ else
+ wksrc = CS35L45_WKSRC_SPI;
+
+ regmap_update_bits(cs35l45->regmap, CS35L45_WAKESRC_CTL,
+ CS35L45_WKSRC_EN_MASK,
+ wksrc << CS35L45_WKSRC_EN_SHIFT);
+
+ regmap_set_bits(cs35l45->regmap, CS35L45_WAKESRC_CTL,
+ CS35L45_UPDT_WKCTL_MASK);
+
+ regmap_update_bits(cs35l45->regmap, CS35L45_WKI2C_CTL,
+ CS35L45_WKI2C_ADDR_MASK, cs35l45->i2c_addr);
+
+ regmap_set_bits(cs35l45->regmap, CS35L45_WKI2C_CTL,
+ CS35L45_UPDT_WKI2C_MASK);
+}
+
+static int cs35l45_enter_hibernate(struct cs35l45_private *cs35l45)
+{
+ dev_dbg(cs35l45->dev, "Enter hibernate\n");
+
+ cs35l45_setup_hibernate(cs35l45);
+
+ // Don't wait for ACK since bus activity would wake the device
+ regmap_write(cs35l45->regmap, CS35L45_DSP_VIRT1_MBOX_1, CSPL_MBOX_CMD_HIBERNATE);
+
+ return 0;
+}
+
+static int cs35l45_exit_hibernate(struct cs35l45_private *cs35l45)
+{
+ const int wake_retries = 20;
+ const int sleep_retries = 5;
+ int ret, i, j;
+
+ for (i = 0; i < sleep_retries; i++) {
+ dev_dbg(cs35l45->dev, "Exit hibernate\n");
+
+ for (j = 0; j < wake_retries; j++) {
+ ret = cs35l45_set_cspl_mbox_cmd(cs35l45, cs35l45->regmap,
+ CSPL_MBOX_CMD_OUT_OF_HIBERNATE);
+ if (!ret) {
+ dev_dbg(cs35l45->dev, "Wake success at cycle: %d\n", j);
+ return 0;
+ }
+ usleep_range(100, 200);
+ }
+
+ dev_err(cs35l45->dev, "Wake failed, re-enter hibernate: %d\n", ret);
+
+ cs35l45_setup_hibernate(cs35l45);
+ }
+
+ dev_err(cs35l45->dev, "Timed out waking device\n");
+
+ return -ETIMEDOUT;
+}
+
static int __maybe_unused cs35l45_runtime_suspend(struct device *dev)
{
struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
+ if (!cs35l45->dsp.preloaded || !cs35l45->dsp.cs_dsp.running)
+ return 0;
+
+ cs35l45_enter_hibernate(cs35l45);
+
regcache_cache_only(cs35l45->regmap, true);
+ regcache_mark_dirty(cs35l45->regmap);
dev_dbg(cs35l45->dev, "Runtime suspended\n");
@@ -761,9 +833,17 @@ static int __maybe_unused cs35l45_runtime_resume(struct device *dev)
struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
int ret;
+ if (!cs35l45->dsp.preloaded || !cs35l45->dsp.cs_dsp.running)
+ return 0;
+
dev_dbg(cs35l45->dev, "Runtime resume\n");
regcache_cache_only(cs35l45->regmap, false);
+
+ ret = cs35l45_exit_hibernate(cs35l45);
+ if (ret)
+ return ret;
+
ret = regcache_sync(cs35l45->regmap);
if (ret != 0)
dev_warn(cs35l45->dev, "regcache_sync failed: %d\n", ret);
diff --git a/sound/soc/codecs/cs35l45.h b/sound/soc/codecs/cs35l45.h
index 87032619b341..0da28439f628 100644
--- a/sound/soc/codecs/cs35l45.h
+++ b/sound/soc/codecs/cs35l45.h
@@ -30,6 +30,9 @@
#define CS35L45_INTB_GPIO2_MCLK_REF 0x00002434
#define CS35L45_GPIO3 0x00002438
#define CS35L45_PWRMGT_CTL 0x00002900
+#define CS35L45_WAKESRC_CTL 0x00002904
+#define CS35L45_WKI2C_CTL 0x00002908
+#define CS35L45_PWRMGT_STS 0x0000290C
#define CS35L45_REFCLK_INPUT 0x00002C04
#define CS35L45_GLOBAL_SAMPLE_RATE 0x00002C0C
#define CS35L45_BOOST_CCM_CFG 0x00003808
@@ -348,6 +351,25 @@
#define CS35L45_POST_GLOBAL_EN_US 5000
#define CS35L45_PRE_GLOBAL_DIS_US 3000
+/* WAKESRC_CTL */
+#define CS35L45_WKSRC_SYNC_GPIO1 BIT(0)
+#define CS35L45_WKSRC_INT_GPIO2 BIT(1)
+#define CS35L45_WKSRC_GPIO3 BIT(2)
+#define CS35L45_WKSRC_SPI BIT(3)
+#define CS35L45_WKSRC_I2C BIT(4)
+#define CS35L45_UPDT_WKCTL_SHIFT 15
+#define CS35L45_UPDT_WKCTL_MASK BIT(15)
+#define CS35L45_WKSRC_EN_SHIFT 8
+#define CS35L45_WKSRC_EN_MASK GENMASK(12, 8)
+#define CS35L45_WKSRC_POL_SHIFT 0
+#define CS35L45_WKSRC_POL_MASK GENMASK(3, 0)
+
+/* WAKEI2C_CTL */
+#define CS35L45_UPDT_WKI2C_SHIFT 15
+#define CS35L45_UPDT_WKI2C_MASK BIT(15)
+#define CS35L45_WKI2C_ADDR_SHIFT 0
+#define CS35L45_WKI2C_ADDR_MASK GENMASK(6, 0)
+
#define CS35L45_SPI_MAX_FREQ 4000000
enum cs35l45_cspl_mboxstate {
@@ -369,6 +391,11 @@ enum cs35l45_cspl_mboxcmd {
CSPL_MBOX_CMD_INVALID_SEQUENCE = -2,
};
+enum control_bus_type {
+ CONTROL_BUS_I2C = 0,
+ CONTROL_BUS_SPI = 1,
+};
+
#define CS35L45_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_3LE| \
SNDRV_PCM_FMTBIT_S24_LE)
@@ -439,6 +466,8 @@ struct cs35l45_private {
u8 slot_count;
int irq_invert;
int irq;
+ unsigned int i2c_addr;
+ enum control_bus_type bus_type;
struct regmap_irq_chip_data *irq_data;
};
--
2.25.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH 5/5] ASoC: cs35l45: Hibernation support
2023-03-02 17:26 [PATCH 5/5] ASoC: cs35l45: Hibernation support Vlad Karpovich
@ 2023-03-02 17:27 ` Mark Brown
0 siblings, 0 replies; 3+ messages in thread
From: Mark Brown @ 2023-03-02 17:27 UTC (permalink / raw)
To: Vlad Karpovich
Cc: Liam Girdwood, Jaroslav Kysela, Takashi Iwai, alsa-devel,
patches, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 297 bytes --]
On Thu, Mar 02, 2023 at 11:26:36AM -0600, Vlad Karpovich wrote:
> From: "Vlad.Karpovich" <vkarpovi@opensource.cirrus.com>
>
> Adds support for the amplifier hibernation controlled by
> DSP firmware.
I've now got three copies of this patch (just this one, the first four
only came once).
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH 5/5] ASoC: cs35l45: Hibernation support
@ 2023-03-02 17:27 ` Mark Brown
0 siblings, 0 replies; 3+ messages in thread
From: Mark Brown @ 2023-03-02 17:27 UTC (permalink / raw)
To: Vlad Karpovich
Cc: Liam Girdwood, Takashi Iwai, alsa-devel, patches, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 297 bytes --]
On Thu, Mar 02, 2023 at 11:26:36AM -0600, Vlad Karpovich wrote:
> From: "Vlad.Karpovich" <vkarpovi@opensource.cirrus.com>
>
> Adds support for the amplifier hibernation controlled by
> DSP firmware.
I've now got three copies of this patch (just this one, the first four
only came once).
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2023-03-06 17:44 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-02 17:26 [PATCH 5/5] ASoC: cs35l45: Hibernation support Vlad Karpovich
2023-03-02 17:27 ` Mark Brown
2023-03-02 17:27 ` Mark Brown
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.