From: James Calligeros <jcalligeros99@gmail.com>
To: "Martin Povišer" <povik+lin@cutebit.org>,
"James Calligeros" <jcalligeros99@gmail.com>,
"David Rhodes" <david.rhodes@cirrus.com>,
"Richard Fitzgerald" <rf@opensource.cirrus.com>,
"Liam Girdwood" <lgirdwood@gmail.com>,
"Mark Brown" <broonie@kernel.org>,
"Rob Herring" <robh@kernel.org>,
"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
"Conor Dooley" <conor+dt@kernel.org>,
"Jaroslav Kysela" <perex@perex.cz>,
"Takashi Iwai" <tiwai@suse.com>
Cc: asahi@lists.linux.dev, linux-sound@vger.kernel.org,
patches@opensource.cirrus.com, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, Hector Martin <marcan@marcan.st>,
Neal Gompa <neal@gompa.dev>
Subject: [PATCH v2 3/3] ASoC: cs42l84: leverage ring sense IRQs to correctly detect headsets
Date: Sun, 20 Oct 2024 00:47:33 +1000 [thread overview]
Message-ID: <20241020-cs42l84-v2-3-37ba2b6721d9@gmail.com> (raw)
In-Reply-To: <20241020-cs42l84-v2-0-37ba2b6721d9@gmail.com>
Some jacks integrated on devices with this codec, such as certain
Apple Silicon Macs, have quite trigger-happy tip sense switches that
cause a tip sense IRQ before the plug is fully seated. If users are
unfortunate with their timing, this can lead to headsets being detected
as mic-less headphones among other issues with the codec's device
detection routines.
Introduce some rudimentary ring sense interrupt handling so that we
can re-trigger the codec's detection routines when we are certain
that the plug is fully seated.
This seems to differ from what other Cirrus drivers do, but is
necessary for devices to be reliably detected properly here.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
Reviewed-by: Neal Gompa <neal@gompa.dev>
---
sound/soc/codecs/cs42l84.c | 90 ++++++++++++++++---------
1 file changed, 60 insertions(+), 30 deletions(-)
diff --git a/sound/soc/codecs/cs42l84.c b/sound/soc/codecs/cs42l84.c
index 84a1e8ac818cc21be6da3f59af6da1a2fc4ed223..47731cdc0e67f4921051ea7130299eb6fffc5fd7 100644
--- a/sound/soc/codecs/cs42l84.c
+++ b/sound/soc/codecs/cs42l84.c
@@ -44,7 +44,8 @@ struct cs42l84_private {
struct gpio_desc *reset_gpio;
struct snd_soc_jack *jack;
struct mutex irq_lock;
- u8 plug_state;
+ u8 tip_state;
+ u8 ring_state;
int pll_config;
int bclk;
u8 pll_mclk_f;
@@ -798,13 +799,23 @@ static void cs42l84_revert_hs(struct cs42l84_private *cs42l84)
FIELD_PREP(CS42L84_HS_DET_CTL2_SET, 2));
}
+static void cs42l84_set_interrupt_masks(struct cs42l84_private *cs42l84,
+ unsigned int val)
+{
+ regmap_update_bits(cs42l84->regmap, CS42L84_TSRS_PLUG_INT_MASK,
+ CS42L84_RS_PLUG | CS42L84_RS_UNPLUG |
+ CS42L84_TS_PLUG | CS42L84_TS_UNPLUG,
+ val);
+}
+
static irqreturn_t cs42l84_irq_thread(int irq, void *data)
{
struct cs42l84_private *cs42l84 = (struct cs42l84_private *)data;
unsigned int stickies[1];
unsigned int masks[1];
unsigned int reg;
- u8 current_plug_status;
+ u8 current_tip_state;
+ u8 current_ring_state;
int i;
mutex_lock(&cs42l84->irq_lock);
@@ -818,16 +829,24 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data)
irq_params_table[i].mask;
}
+ /* When handling plug sene IRQs, we only care about EITHER tip OR ring.
+ * Ring is useless on remove, and is only useful on insert for
+ * detecting if the plug state has changed AFTER we have handled the
+ * tip sense IRQ, e.g. if the plug was not fully seated within the tip
+ * sense debounce time.
+ */
+
if ((~masks[0]) & irq_params_table[0].mask) {
regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, ®);
- current_plug_status = (((char) reg) &
+
+ current_tip_state = (((char) reg) &
(CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >>
CS42L84_TS_PLUG_SHIFT;
- switch (current_plug_status) {
- case CS42L84_PLUG:
- if (cs42l84->plug_state != CS42L84_PLUG) {
- cs42l84->plug_state = CS42L84_PLUG;
+ if (current_tip_state != cs42l84->tip_state) {
+ cs42l84->tip_state = current_tip_state;
+ switch (current_tip_state) {
+ case CS42L84_PLUG:
dev_dbg(cs42l84->dev, "Plug event\n");
cs42l84_detect_hs(cs42l84);
@@ -840,47 +859,58 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data)
* was disconnected at any point during the detection procedure.
*/
regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, ®);
- current_plug_status = (((char) reg) &
+ current_tip_state = (((char) reg) &
(CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >>
CS42L84_TS_PLUG_SHIFT;
- if (current_plug_status != CS42L84_PLUG) {
+ if (current_tip_state != CS42L84_PLUG) {
dev_dbg(cs42l84->dev, "Wobbly connection, detection invalidated\n");
- cs42l84->plug_state = CS42L84_UNPLUG;
+ cs42l84->tip_state = CS42L84_UNPLUG;
cs42l84_revert_hs(cs42l84);
}
- }
- break;
- case CS42L84_UNPLUG:
- if (cs42l84->plug_state != CS42L84_UNPLUG) {
- cs42l84->plug_state = CS42L84_UNPLUG;
+ /* Unmask ring sense interrupts */
+ cs42l84_set_interrupt_masks(cs42l84, 0);
+ break;
+ case CS42L84_UNPLUG:
+ cs42l84->ring_state = CS42L84_UNPLUG;
dev_dbg(cs42l84->dev, "Unplug event\n");
cs42l84_revert_hs(cs42l84);
cs42l84->hs_type = 0;
snd_soc_jack_report(cs42l84->jack, 0,
SND_JACK_HEADSET);
+
+ /* Mask ring sense interrupts */
+ cs42l84_set_interrupt_masks(cs42l84,
+ CS42L84_RS_PLUG | CS42L84_RS_UNPLUG);
+ break;
+ default:
+ cs42l84->ring_state = CS42L84_TRANS;
+ break;
}
- break;
- default:
- if (cs42l84->plug_state != CS42L84_TRANS)
- cs42l84->plug_state = CS42L84_TRANS;
+ mutex_unlock(&cs42l84->irq_lock);
+
+ return IRQ_HANDLED;
+ }
+
+ /* Tip state didn't change, we must've got a ring sense IRQ */
+ current_ring_state = (((char) reg) &
+ (CS42L84_RS_PLUG | CS42L84_RS_UNPLUG)) >>
+ CS42L84_RS_PLUG_SHIFT;
+
+ if (current_ring_state != cs42l84->ring_state) {
+ cs42l84->ring_state = current_ring_state;
+ if (current_ring_state == CS42L84_PLUG)
+ cs42l84_detect_hs(cs42l84);
}
}
+
mutex_unlock(&cs42l84->irq_lock);
return IRQ_HANDLED;
}
-static void cs42l84_set_interrupt_masks(struct cs42l84_private *cs42l84)
-{
- regmap_update_bits(cs42l84->regmap, CS42L84_TSRS_PLUG_INT_MASK,
- CS42L84_RS_PLUG | CS42L84_RS_UNPLUG |
- CS42L84_TS_PLUG | CS42L84_TS_UNPLUG,
- CS42L84_RS_PLUG | CS42L84_RS_UNPLUG);
-}
-
static void cs42l84_setup_plug_detect(struct cs42l84_private *cs42l84)
{
unsigned int reg;
@@ -910,7 +940,7 @@ static void cs42l84_setup_plug_detect(struct cs42l84_private *cs42l84)
/* Save the initial status of the tip sense */
regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, ®);
- cs42l84->plug_state = (((char) reg) &
+ cs42l84->tip_state = (((char) reg) &
(CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >>
CS42L84_TS_PLUG_SHIFT;
@@ -1017,8 +1047,8 @@ static int cs42l84_i2c_probe(struct i2c_client *i2c_client)
/* Setup plug detection */
cs42l84_setup_plug_detect(cs42l84);
- /* Mask/Unmask Interrupts */
- cs42l84_set_interrupt_masks(cs42l84);
+ /* Mask ring sense interrupts */
+ cs42l84_set_interrupt_masks(cs42l84, CS42L84_RS_PLUG | CS42L84_RS_UNPLUG);
/* Register codec for machine driver */
ret = devm_snd_soc_register_component(&i2c_client->dev,
--
2.47.0
next prev parent reply other threads:[~2024-10-19 14:49 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-19 14:47 [PATCH v2 0/3] ASoC: add CS42L84 codec driver James Calligeros
2024-10-19 14:47 ` [PATCH v2 1/3] dt-bindings: sound: Add CS42L84 codec James Calligeros
2024-10-21 19:26 ` Rob Herring
2024-10-21 22:15 ` Mark Brown
2024-10-22 7:14 ` James Calligeros
2024-10-24 14:59 ` Rob Herring (Arm)
2024-10-24 15:09 ` Mark Brown
2024-10-19 14:47 ` [PATCH v2 2/3] ASoC: cs42l84: Add new codec driver James Calligeros
2024-10-19 14:47 ` James Calligeros [this message]
2024-10-24 20:16 ` [PATCH v2 0/3] ASoC: add CS42L84 " 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=20241020-cs42l84-v2-3-37ba2b6721d9@gmail.com \
--to=jcalligeros99@gmail.com \
--cc=asahi@lists.linux.dev \
--cc=broonie@kernel.org \
--cc=conor+dt@kernel.org \
--cc=david.rhodes@cirrus.com \
--cc=devicetree@vger.kernel.org \
--cc=krzk+dt@kernel.org \
--cc=lgirdwood@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-sound@vger.kernel.org \
--cc=marcan@marcan.st \
--cc=neal@gompa.dev \
--cc=patches@opensource.cirrus.com \
--cc=perex@perex.cz \
--cc=povik+lin@cutebit.org \
--cc=rf@opensource.cirrus.com \
--cc=robh@kernel.org \
--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;
as well as URLs for NNTP newsgroup(s).