From: Vitaly Rodionov <vitalyr@opensource.cirrus.com>
To: Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.com>,
Mark Brown <broonie@kernel.org>
Cc: patches@opensource.cirrus.com, alsa-devel@alsa-project.org,
linux-kernel@vger.kernel.org,
Stefan Binding <sbinding@opensource.cirrus.com>
Subject: [PATCH 04/26] ALSA: hda: cs35l41: Add Support for Interrupts
Date: Wed, 27 Apr 2022 16:06:58 +0100 [thread overview]
Message-ID: <20220427150720.9194-5-vitalyr@opensource.cirrus.com> (raw)
In-Reply-To: <20220427150720.9194-1-vitalyr@opensource.cirrus.com>
From: Stefan Binding <sbinding@opensource.cirrus.com>
The CS35L41 can produce interrupts on error.
When the interrupts occur, the driver will report
the error, but errors will only be fixed after playback
finishes.
Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com>
Signed-off-by: Vitaly Rodionov <vitalyr@opensource.cirrus.com>
---
include/sound/cs35l41.h | 54 +++++++++++++++
sound/pci/hda/Kconfig | 2 +
sound/pci/hda/cs35l41_hda.c | 134 +++++++++++++++++++++++++++++++++++-
sound/pci/hda/cs35l41_hda.h | 2 +
4 files changed, 191 insertions(+), 1 deletion(-)
diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h
index dbe8d9c0191b..8e4b125c81c8 100644
--- a/include/sound/cs35l41.h
+++ b/include/sound/cs35l41.h
@@ -691,6 +691,13 @@
#define CS35L41_TEMP_WARN_ERR_RLS 0x20
#define CS35L41_TEMP_ERR_RLS 0x40
+#define CS35L41_AMP_SHORT_ERR_RLS_SHIFT 1
+#define CS35L41_BST_SHORT_ERR_RLS_SHIFT 2
+#define CS35L41_BST_OVP_ERR_RLS_SHIFT 3
+#define CS35L41_BST_UVP_ERR_RLS_SHIFT 4
+#define CS35L41_TEMP_WARN_ERR_RLS_SHIFT 5
+#define CS35L41_TEMP_ERR_RLS_SHIFT 6
+
#define CS35L41_INT1_MASK_DEFAULT 0x7FFCFE3F
#define CS35L41_INT1_UNMASK_PUP 0xFEFFFFFF
#define CS35L41_INT1_UNMASK_PDN 0xFF7FFFFF
@@ -794,6 +801,53 @@ struct cs35l41_otp_map_element_t {
u32 word_offset;
};
+/*
+ * IRQs
+ */
+#define CS35L41_IRQ(_irq, _name, _hand) \
+ { \
+ .irq = CS35L41_ ## _irq ## _IRQ,\
+ .name = _name, \
+ .handler = _hand, \
+ }
+
+struct cs35l41_irq {
+ int irq;
+ const char *name;
+ irqreturn_t (*handler)(int irq, void *data);
+};
+
+#define CS35L41_REG_IRQ(_reg, _irq) \
+ [CS35L41_ ## _irq ## _IRQ] = { \
+ .reg_offset = (CS35L41_ ## _reg) - CS35L41_IRQ1_STATUS1,\
+ .mask = CS35L41_ ## _irq ## _MASK \
+ }
+
+/* (0x0000E010) CS35L41_IRQ1_STATUS1 */
+#define CS35L41_BST_OVP_ERR_SHIFT 6
+#define CS35L41_BST_OVP_ERR_MASK BIT(CS35L41_BST_OVP_ERR_SHIFT)
+#define CS35L41_BST_DCM_UVP_ERR_SHIFT 7
+#define CS35L41_BST_DCM_UVP_ERR_MASK BIT(CS35L41_BST_DCM_UVP_ERR_SHIFT)
+#define CS35L41_BST_SHORT_ERR_SHIFT 8
+#define CS35L41_BST_SHORT_ERR_MASK BIT(CS35L41_BST_SHORT_ERR_SHIFT)
+#define CS35L41_TEMP_WARN_SHIFT 15
+#define CS35L41_TEMP_WARN_MASK BIT(CS35L41_TEMP_WARN_SHIFT)
+#define CS35L41_TEMP_ERR_SHIFT 17
+#define CS35L41_TEMP_ERR_MASK BIT(CS35L41_TEMP_ERR_SHIFT)
+#define CS35L41_AMP_SHORT_ERR_SHIFT 31
+#define CS35L41_AMP_SHORT_ERR_MASK BIT(CS35L41_AMP_SHORT_ERR_SHIFT)
+
+enum cs35l41_irq_list {
+ CS35L41_BST_OVP_ERR_IRQ,
+ CS35L41_BST_DCM_UVP_ERR_IRQ,
+ CS35L41_BST_SHORT_ERR_IRQ,
+ CS35L41_TEMP_WARN_IRQ,
+ CS35L41_TEMP_ERR_IRQ,
+ CS35L41_AMP_SHORT_ERR_IRQ,
+
+ CS35L41_NUM_IRQ
+};
+
extern struct regmap_config cs35l41_regmap_i2c;
extern struct regmap_config cs35l41_regmap_spi;
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 9f6c99c1d87b..79ade4787d95 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -102,6 +102,7 @@ config SND_HDA_SCODEC_CS35L41_I2C
select SND_HDA_GENERIC
select SND_SOC_CS35L41_LIB
select SND_HDA_SCODEC_CS35L41
+ select REGMAP_IRQ
help
Say Y or M here to include CS35L41 I2C HD-audio side codec support
in snd-hda-intel driver, such as ALC287.
@@ -117,6 +118,7 @@ config SND_HDA_SCODEC_CS35L41_SPI
select SND_HDA_GENERIC
select SND_SOC_CS35L41_LIB
select SND_HDA_SCODEC_CS35L41
+ select REGMAP_IRQ
help
Say Y or M here to include CS35L41 SPI HD-audio side codec support
in snd-hda-intel driver, such as ALC287.
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
index 96c3e541696d..bd52e0c2c772 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/pci/hda/cs35l41_hda.c
@@ -32,6 +32,21 @@ static const struct reg_sequence cs35l41_hda_mute[] = {
{ CS35L41_AMP_DIG_VOL_CTRL, 0x0000A678 }, // AMP_VOL_PCM Mute
};
+/* Protection release cycle to get the speaker out of Safe-Mode */
+static void cs35l41_error_release(struct device *dev, struct regmap *regmap, unsigned int mask)
+{
+ regmap_write(regmap, CS35L41_PROTECT_REL_ERR_IGN, 0);
+ regmap_set_bits(regmap, CS35L41_PROTECT_REL_ERR_IGN, mask);
+ regmap_clear_bits(regmap, CS35L41_PROTECT_REL_ERR_IGN, mask);
+}
+
+/* Clear all errors to release safe mode. Global Enable must be cleared first. */
+static void cs35l41_irq_release(struct cs35l41_hda *cs35l41)
+{
+ cs35l41_error_release(cs35l41->dev, cs35l41->regmap, cs35l41->irq_errors);
+ cs35l41->irq_errors = 0;
+}
+
static void cs35l41_hda_playback_hook(struct device *dev, int action)
{
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
@@ -58,6 +73,7 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT);
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00000001);
+ cs35l41_irq_release(cs35l41);
break;
default:
dev_warn(cs35l41->dev, "Playback action not supported: %d\n", action);
@@ -110,10 +126,101 @@ static const struct component_ops cs35l41_hda_comp_ops = {
.unbind = cs35l41_hda_unbind,
};
+static irqreturn_t cs35l41_bst_short_err(int irq, void *data)
+{
+ struct cs35l41_hda *cs35l41 = data;
+
+ dev_crit_ratelimited(cs35l41->dev, "LBST Error\n");
+ set_bit(CS35L41_BST_SHORT_ERR_RLS_SHIFT, &cs35l41->irq_errors);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t cs35l41_bst_dcm_uvp_err(int irq, void *data)
+{
+ struct cs35l41_hda *cs35l41 = data;
+
+ dev_crit_ratelimited(cs35l41->dev, "DCM VBST Under Voltage Error\n");
+ set_bit(CS35L41_BST_UVP_ERR_RLS_SHIFT, &cs35l41->irq_errors);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t cs35l41_bst_ovp_err(int irq, void *data)
+{
+ struct cs35l41_hda *cs35l41 = data;
+
+ dev_crit_ratelimited(cs35l41->dev, "VBST Over Voltage error\n");
+ set_bit(CS35L41_BST_OVP_ERR_RLS_SHIFT, &cs35l41->irq_errors);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t cs35l41_temp_err(int irq, void *data)
+{
+ struct cs35l41_hda *cs35l41 = data;
+
+ dev_crit_ratelimited(cs35l41->dev, "Over temperature error\n");
+ set_bit(CS35L41_TEMP_ERR_RLS_SHIFT, &cs35l41->irq_errors);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t cs35l41_temp_warn(int irq, void *data)
+{
+ struct cs35l41_hda *cs35l41 = data;
+
+ dev_crit_ratelimited(cs35l41->dev, "Over temperature warning\n");
+ set_bit(CS35L41_TEMP_WARN_ERR_RLS_SHIFT, &cs35l41->irq_errors);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t cs35l41_amp_short(int irq, void *data)
+{
+ struct cs35l41_hda *cs35l41 = data;
+
+ dev_crit_ratelimited(cs35l41->dev, "Amp short error\n");
+ set_bit(CS35L41_AMP_SHORT_ERR_RLS_SHIFT, &cs35l41->irq_errors);
+
+ return IRQ_HANDLED;
+}
+
+static const struct cs35l41_irq cs35l41_irqs[] = {
+ CS35L41_IRQ(BST_OVP_ERR, "Boost Overvoltage Error", cs35l41_bst_ovp_err),
+ CS35L41_IRQ(BST_DCM_UVP_ERR, "Boost Undervoltage Error", cs35l41_bst_dcm_uvp_err),
+ CS35L41_IRQ(BST_SHORT_ERR, "Boost Inductor Short Error", cs35l41_bst_short_err),
+ CS35L41_IRQ(TEMP_WARN, "Temperature Warning", cs35l41_temp_warn),
+ CS35L41_IRQ(TEMP_ERR, "Temperature Error", cs35l41_temp_err),
+ CS35L41_IRQ(AMP_SHORT_ERR, "Amp Short", cs35l41_amp_short),
+};
+
+static const struct regmap_irq cs35l41_reg_irqs[] = {
+ CS35L41_REG_IRQ(IRQ1_STATUS1, BST_OVP_ERR),
+ CS35L41_REG_IRQ(IRQ1_STATUS1, BST_DCM_UVP_ERR),
+ CS35L41_REG_IRQ(IRQ1_STATUS1, BST_SHORT_ERR),
+ CS35L41_REG_IRQ(IRQ1_STATUS1, TEMP_WARN),
+ CS35L41_REG_IRQ(IRQ1_STATUS1, TEMP_ERR),
+ CS35L41_REG_IRQ(IRQ1_STATUS1, AMP_SHORT_ERR),
+};
+
+static const struct regmap_irq_chip cs35l41_regmap_irq_chip = {
+ .name = "cs35l41 IRQ1 Controller",
+ .status_base = CS35L41_IRQ1_STATUS1,
+ .mask_base = CS35L41_IRQ1_MASK1,
+ .ack_base = CS35L41_IRQ1_STATUS1,
+ .num_regs = 4,
+ .irqs = cs35l41_reg_irqs,
+ .num_irqs = ARRAY_SIZE(cs35l41_reg_irqs),
+};
+
static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
{
struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
+ bool using_irq = false;
+ int irq, irq_pol;
int ret;
+ int i;
if (!cs35l41->hw_cfg.valid)
return -EINVAL;
@@ -145,6 +252,7 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
case CS35L41_NOT_USED:
break;
case CS35L41_INTERRUPT:
+ using_irq = true;
break;
default:
dev_err(cs35l41->dev, "Invalid GPIO2 function %d\n", hw_cfg->gpio2.func);
@@ -152,7 +260,28 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
}
}
- cs35l41_gpio_config(cs35l41->regmap, hw_cfg);
+ irq_pol = cs35l41_gpio_config(cs35l41->regmap, hw_cfg);
+
+ if (cs35l41->irq && using_irq) {
+ ret = devm_regmap_add_irq_chip(cs35l41->dev, cs35l41->regmap, cs35l41->irq,
+ IRQF_ONESHOT | IRQF_SHARED | irq_pol,
+ 0, &cs35l41_regmap_irq_chip, &cs35l41->irq_data);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(cs35l41_irqs); i++) {
+ irq = regmap_irq_get_virq(cs35l41->irq_data, cs35l41_irqs[i].irq);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_threaded_irq(cs35l41->dev, irq, NULL,
+ cs35l41_irqs[i].handler,
+ IRQF_ONESHOT | IRQF_SHARED | irq_pol,
+ cs35l41_irqs[i].name, cs35l41);
+ if (ret)
+ return ret;
+ }
+ }
return cs35l41_hda_channel_map(cs35l41->dev, 0, NULL, 1, &hw_cfg->spk_pos);
}
@@ -296,6 +425,9 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
struct cs35l41_hda *cs35l41;
int ret;
+ BUILD_BUG_ON(ARRAY_SIZE(cs35l41_irqs) != ARRAY_SIZE(cs35l41_reg_irqs));
+ BUILD_BUG_ON(ARRAY_SIZE(cs35l41_irqs) != CS35L41_NUM_IRQ);
+
if (IS_ERR(regmap))
return PTR_ERR(regmap);
diff --git a/sound/pci/hda/cs35l41_hda.h b/sound/pci/hda/cs35l41_hda.h
index 44d9204ffdf1..c486e4a5bb24 100644
--- a/sound/pci/hda/cs35l41_hda.h
+++ b/sound/pci/hda/cs35l41_hda.h
@@ -35,6 +35,8 @@ struct cs35l41_hda {
int irq;
int index;
+ unsigned volatile long irq_errors;
+ struct regmap_irq_chip_data *irq_data;
};
int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq,
--
2.32.0
next prev parent reply other threads:[~2022-04-27 15:09 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-04-27 15:06 [PATCH 00/26] ALSA: hda: cirrus: Add initial DSP support and firmware loading Vitaly Rodionov
2022-04-27 15:06 ` [PATCH 01/26] ALSA: hda: cs35l41: Fix error in spi cs35l41 hda driver name Vitaly Rodionov
2022-04-27 15:06 ` [PATCH 02/26] ALSA: hda: cs35l41: Set Speaker Position for CLSA0100 Laptop Vitaly Rodionov
2022-04-27 15:06 ` [PATCH 03/26] ALSA: hda: cs35l41: Remove Set Channel Map api from binding Vitaly Rodionov
2022-04-27 15:06 ` Vitaly Rodionov [this message]
2022-04-27 15:06 ` [PATCH 05/26] ALSA: hda: cs35l41: Enable GPIO2 Interrupt for CLSA0100 laptops Vitaly Rodionov
2022-04-27 15:07 ` [PATCH 06/26] ASoC: cs35l41: Move cs35l41_set_cspl_mbox_cmd to shared code Vitaly Rodionov
2022-04-28 8:57 ` Charles Keepax
2022-04-27 15:07 ` [PATCH 07/26] ASoC: cs35l41: Move cs35l41 fs errata into " Vitaly Rodionov
2022-04-28 9:07 ` Charles Keepax
2022-04-27 15:07 ` [PATCH 08/26] ASoC: cs35l41: Move cs_dsp config struct " Vitaly Rodionov
2022-04-28 9:08 ` Charles Keepax
2022-04-27 15:07 ` [PATCH 09/26] ALSA: hda: cs35l41: Add Amp Name based on channel and index Vitaly Rodionov
2022-04-27 15:07 ` [PATCH 10/26] ALSA: hda: hda_cs_dsp_ctl: Add Library to support CS_DSP ALSA controls Vitaly Rodionov
2022-04-27 15:07 ` [PATCH 11/26] ALSA: hda: hda_cs_dsp_ctl: Add apis to write the controls directly Vitaly Rodionov
2022-04-27 15:07 ` [PATCH 12/26] ALSA: hda: cs35l41: Save codec object inside component struct Vitaly Rodionov
2022-04-27 15:07 ` [PATCH 13/26] ALSA: hda: cs35l41: Add initial DSP support and firmware loading Vitaly Rodionov
2022-04-27 15:07 ` [PATCH 14/26] ALSA: hda: cs35l41: Save Subsystem ID inside CS35L41 Driver Vitaly Rodionov
2022-04-27 15:07 ` [PATCH 15/26] ALSA: hda: cs35l41: Support reading subsystem id from ACPI Vitaly Rodionov
2022-04-27 15:07 ` [PATCH 16/26] ALSA: hda: cs35l41: Support multiple load paths for firmware Vitaly Rodionov
2022-04-27 15:07 ` [PATCH 17/26] ALSA: hda: cs35l41: Support Speaker ID for laptops Vitaly Rodionov
2022-04-27 15:07 ` [PATCH 18/26] ASoC: cs35l41: Move cs35l41 exit hibernate function into shared code Vitaly Rodionov
2022-04-28 9:09 ` Charles Keepax
2022-04-27 15:07 ` [PATCH 19/26] ALSA: cs35l41: Do not print error when waking from hibernation Vitaly Rodionov
2022-04-28 9:11 ` Charles Keepax
2022-04-27 15:07 ` [PATCH 20/26] ASoC: cs35l41: Add common cs35l41 enter hibernate function Vitaly Rodionov
2022-04-28 9:12 ` Charles Keepax
2022-04-27 15:07 ` [PATCH 21/26] ALSA: hda: cs35l41: Support Hibernation during Suspend Vitaly Rodionov
2022-04-27 15:07 ` [PATCH 22/26] ALSA: hda: cs35l41: Read Speaker Calibration data from UEFI variables Vitaly Rodionov
2022-04-27 15:07 ` [PATCH 23/26] ALSA: hda: hda_cs_dsp_ctl: Add fw id strings Vitaly Rodionov
2022-04-27 15:07 ` [PATCH 24/26] ALSA: hda: cs35l41: Add defaulted values into dsp bypass config sequence Vitaly Rodionov
2022-04-27 15:07 ` [PATCH 25/26] ALSA: hda: cs35l41: Support Firmware switching and reloading Vitaly Rodionov
2022-04-27 15:07 ` [PATCH 26/26] ALSA: hda: cs35l41: Add kernel config to disable firmware autoload Vitaly Rodionov
2022-04-27 15:36 ` [PATCH 00/26] ALSA: hda: cirrus: Add initial DSP support and firmware loading Mark Brown
2022-05-09 8:55 ` Takashi Iwai
2022-05-09 11:21 ` Mark Brown
2022-05-09 17:34 ` Vitaly Rodionov
2022-06-07 10:54 ` (subset) " Mark Brown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220427150720.9194-5-vitalyr@opensource.cirrus.com \
--to=vitalyr@opensource.cirrus.com \
--cc=alsa-devel@alsa-project.org \
--cc=broonie@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=patches@opensource.cirrus.com \
--cc=perex@perex.cz \
--cc=sbinding@opensource.cirrus.com \
--cc=tiwai@suse.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox