From nobody Tue Jun 30 08:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7B3CEC433EF for ; Fri, 21 Jan 2022 12:04:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1380311AbiAUMEd (ORCPT ); Fri, 21 Jan 2022 07:04:33 -0500 Received: from mx0a-001ae601.pphosted.com ([67.231.149.25]:10376 "EHLO mx0b-001ae601.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1350379AbiAUME2 (ORCPT ); Fri, 21 Jan 2022 07:04:28 -0500 Received: from pps.filterd (m0077473.ppops.net [127.0.0.1]) by mx0a-001ae601.pphosted.com (8.16.1.2/8.16.1.2) with ESMTP id 20L6W2RK017662; Fri, 21 Jan 2022 06:04:17 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cirrus.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=PODMain02222019; bh=/5EEVxedqyc4lS3w9/oKz7sNBu3Ep8/TONL9EDmsebU=; b=jFuPLgzH0D8YDfL+NZAykCuPJ4QZu1grLVvZS5PWYR3jwhVP+TvFacR/6Cf/rjrbLigW WJcOKWHSv3QogtorJHc6z0NvRc7U8mIOWHfIzSsopeJ6pgcG7pNpnHA1cvmRZUOERuWi IDamZR/MsA0/rCtXvv08lYOQtWFMo2pWRdFPLUGHa1j4Pnxnzx9HG6q/dFkbuIbGjhfH EuZrlpf+Yz/FgNtyZZcxBVYZw3fj/HvnkV1/UD9KGWhdii1dCpWnj3pi3jxA5VCz8mfj XcU89/8JjwQJsL3NRDIskek6J0I2fzbgXU8N1BgwbUvJY2ENlmA5SzJvkODsKhBFJddv EQ== Received: from ediex02.ad.cirrus.com ([84.19.233.68]) by mx0a-001ae601.pphosted.com (PPS) with ESMTPS id 3dqhyq0nwc-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT); Fri, 21 Jan 2022 06:04:17 -0600 Received: from EDIEX01.ad.cirrus.com (198.61.84.80) by EDIEX02.ad.cirrus.com (198.61.84.81) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.18; Fri, 21 Jan 2022 12:04:15 +0000 Received: from ediswmail.ad.cirrus.com (198.61.86.93) by EDIEX01.ad.cirrus.com (198.61.84.80) with Microsoft SMTP Server id 15.1.2375.18 via Frontend Transport; Fri, 21 Jan 2022 12:04:15 +0000 Received: from AUSNPC0LSNW1-debian.cirrus.com (AUSNPC0LSNW1.ad.cirrus.com [198.61.65.33]) by ediswmail.ad.cirrus.com (Postfix) with ESMTP id 07D7346D; Fri, 21 Jan 2022 12:04:14 +0000 (UTC) From: Richard Fitzgerald To: CC: , , , Richard Fitzgerald Subject: [PATCH v2 1/3] ASoC: cs42l42: Report full jack status when plug is detected Date: Fri, 21 Jan 2022 12:04:10 +0000 Message-ID: <20220121120412.672284-2-rf@opensource.cirrus.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220121120412.672284-1-rf@opensource.cirrus.com> References: <20220121120412.672284-1-rf@opensource.cirrus.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-GUID: JnDjrwlJwd9kkfhT0hsB5Ro-Q5fHUQ19 X-Proofpoint-ORIG-GUID: JnDjrwlJwd9kkfhT0hsB5Ro-Q5fHUQ19 X-Proofpoint-Spam-Reason: safe Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" When a plug event is detect report the full state of all status bits, don't assume that there will have been a previous unplug event to clear all the bits. Report the state of both HEADPHONE and MICROPHONE bits according to detected type, and clear all the button status bits. The current button status is already checked and reported at the end of the function. During a system suspend the jack could be unplugged and plugged, possibly changing the jack type. On resume the interrupt status will indicate a plug event - there will not be an unplug event to clear the bits. Signed-off-by: Richard Fitzgerald --- sound/soc/codecs/cs42l42.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 43d98bdb5b5b..2c294868008e 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1637,7 +1637,11 @@ static irqreturn_t cs42l42_irq_thread(int irq, void = *data) =20 mutex_lock(&cs42l42->jack_detect_mutex); =20 - /* Check auto-detect status */ + /* + * Check auto-detect status. Don't assume a previous unplug event has + * cleared the flags. If the jack is unplugged and plugged during + * system suspend there won't have been an unplug event. + */ if ((~masks[5]) & irq_params_table[5].mask) { if (stickies[5] & CS42L42_HSDET_AUTO_DONE_MASK) { cs42l42_process_hs_type_detect(cs42l42); @@ -1645,11 +1649,15 @@ static irqreturn_t cs42l42_irq_thread(int irq, void= *data) case CS42L42_PLUG_CTIA: case CS42L42_PLUG_OMTP: snd_soc_jack_report(cs42l42->jack, SND_JACK_HEADSET, - SND_JACK_HEADSET); + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); break; case CS42L42_PLUG_HEADPHONE: snd_soc_jack_report(cs42l42->jack, SND_JACK_HEADPHONE, - SND_JACK_HEADPHONE); + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); break; default: break; --=20 2.11.0 From nobody Tue Jun 30 08:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7CBFAC433F5 for ; Fri, 21 Jan 2022 12:04:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350430AbiAUME3 (ORCPT ); Fri, 21 Jan 2022 07:04:29 -0500 Received: from mx0a-001ae601.pphosted.com ([67.231.149.25]:14640 "EHLO mx0b-001ae601.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1350332AbiAUMEX (ORCPT ); Fri, 21 Jan 2022 07:04:23 -0500 Received: from pps.filterd (m0077473.ppops.net [127.0.0.1]) by mx0a-001ae601.pphosted.com (8.16.1.2/8.16.1.2) with ESMTP id 20L4qraX012563; Fri, 21 Jan 2022 06:04:17 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cirrus.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=PODMain02222019; bh=qpxI/iRkVYhxItmhbuo5ZUu8r1IM5OGMC1OqPFE0SUg=; b=H8TQXKe96/Vwn/B9h2tqMDRQ/+jAl68vCE5lfVfcUX5LoIUoCwjpnCkTyo1y0k1tT7mP yTRne6A4kfwI6luG/f7gop/99L9yUGkaRyaNGYvo1Xr2kdum3gIyvMQhhwUNOq9PjylQ hO8OWK7kaTF0kK1dxgTKKcf8Ld5yxYn4/0g+gCoidglFiZ1XfqFY2OL/0Kou0XXXJgmI f/jriizQliFdN4IC0Pt/WKYXFbyQ+G6uAeVOGrMlck+HaI4QN7VW0X4Opkbbw7knKD2S QUO5s7pekPep/bU8q/zTqaWj1O/3hlviqHHb8xdUABvTcY4Km1aHjM9jAZveKcue1NLU cQ== Received: from ediex01.ad.cirrus.com ([84.19.233.68]) by mx0a-001ae601.pphosted.com (PPS) with ESMTPS id 3dqhyq0nwd-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT); Fri, 21 Jan 2022 06:04:17 -0600 Received: from EDIEX01.ad.cirrus.com (198.61.84.80) by EDIEX01.ad.cirrus.com (198.61.84.80) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.18; Fri, 21 Jan 2022 12:04:15 +0000 Received: from ediswmail.ad.cirrus.com (198.61.86.93) by EDIEX01.ad.cirrus.com (198.61.84.80) with Microsoft SMTP Server id 15.1.2375.18 via Frontend Transport; Fri, 21 Jan 2022 12:04:15 +0000 Received: from AUSNPC0LSNW1-debian.cirrus.com (AUSNPC0LSNW1.ad.cirrus.com [198.61.65.33]) by ediswmail.ad.cirrus.com (Postfix) with ESMTP id 5A69945D; Fri, 21 Jan 2022 12:04:15 +0000 (UTC) From: Richard Fitzgerald To: CC: , , , Richard Fitzgerald Subject: [PATCH v2 2/3] ASoC: cs42l42: Change jack_detect_mutex to a lock of all IRQ handling Date: Fri, 21 Jan 2022 12:04:11 +0000 Message-ID: <20220121120412.672284-3-rf@opensource.cirrus.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220121120412.672284-1-rf@opensource.cirrus.com> References: <20220121120412.672284-1-rf@opensource.cirrus.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-GUID: 4Ju7wjB4LrJh6g9r7WNJpbdF_bYP6rAT X-Proofpoint-ORIG-GUID: 4Ju7wjB4LrJh6g9r7WNJpbdF_bYP6rAT X-Proofpoint-Spam-Reason: safe Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Rename jack_detect_mutex to irq_lock and make it lock the entire IRQ handling. The jack_detect_mutex was introduced to synchronize registering an ALSA jack handler, via cs42l42_set_jack(), with the jack state processing in the IRQ handler, and was taken only around the relevant part of the IRQ handling code. System suspend will need to synchronize with the IRQ handler thread so will need a similar mutex that surrounds all of the IRQ handling. Repurposing the existing jack_detect_mutex is the simplest option. It does no harm for a call to cs42l42_set_jack() to additionally block the first few lines of IRQ handling, and the only interrupts used by the driver are all for jack handling. Signed-off-by: Richard Fitzgerald --- sound/soc/codecs/cs42l42.c | 11 +++++------ sound/soc/codecs/cs42l42.h | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 2c294868008e..f1b95d45af4a 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -550,7 +550,7 @@ static int cs42l42_set_jack(struct snd_soc_component *c= omponent, struct snd_soc_ struct cs42l42_private *cs42l42 =3D snd_soc_component_get_drvdata(compone= nt); =20 /* Prevent race with interrupt handler */ - mutex_lock(&cs42l42->jack_detect_mutex); + mutex_lock(&cs42l42->irq_lock); cs42l42->jack =3D jk; =20 if (jk) { @@ -566,7 +566,7 @@ static int cs42l42_set_jack(struct snd_soc_component *c= omponent, struct snd_soc_ break; } } - mutex_unlock(&cs42l42->jack_detect_mutex); + mutex_unlock(&cs42l42->irq_lock); =20 return 0; } @@ -1613,6 +1613,7 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *= data) unsigned int i; int report =3D 0; =20 + mutex_lock(&cs42l42->irq_lock); =20 /* Read sticky registers to clear interurpt */ for (i =3D 0; i < ARRAY_SIZE(stickies); i++) { @@ -1635,8 +1636,6 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *= data) CS42L42_M_DETECT_FT_MASK | CS42L42_M_HSBIAS_HIZ_MASK); =20 - mutex_lock(&cs42l42->jack_detect_mutex); - /* * Check auto-detect status. Don't assume a previous unplug event has * cleared the flags. If the jack is unplugged and plugged during @@ -1713,7 +1712,7 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *= data) } } =20 - mutex_unlock(&cs42l42->jack_detect_mutex); + mutex_unlock(&cs42l42->irq_lock); =20 return IRQ_HANDLED; } @@ -2062,7 +2061,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_c= lient, =20 cs42l42->dev =3D &i2c_client->dev; i2c_set_clientdata(i2c_client, cs42l42); - mutex_init(&cs42l42->jack_detect_mutex); + mutex_init(&cs42l42->irq_lock); =20 cs42l42->regmap =3D devm_regmap_init_i2c(i2c_client, &cs42l42_regmap); if (IS_ERR(cs42l42->regmap)) { diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 9fff183dce8e..53d96287abba 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -842,7 +842,7 @@ struct cs42l42_private { struct gpio_desc *reset_gpio; struct completion pdn_done; struct snd_soc_jack *jack; - struct mutex jack_detect_mutex; + struct mutex irq_lock; int pll_config; int bclk; u32 sclk; --=20 2.11.0 From nobody Tue Jun 30 08:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3A6FCC433FE for ; Fri, 21 Jan 2022 12:04:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350381AbiAUME2 (ORCPT ); Fri, 21 Jan 2022 07:04:28 -0500 Received: from mx0a-001ae601.pphosted.com ([67.231.149.25]:12854 "EHLO mx0b-001ae601.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1350347AbiAUMEX (ORCPT ); Fri, 21 Jan 2022 07:04:23 -0500 Received: from pps.filterd (m0077473.ppops.net [127.0.0.1]) by mx0a-001ae601.pphosted.com (8.16.1.2/8.16.1.2) with ESMTP id 20L4qraY012563; Fri, 21 Jan 2022 06:04:18 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cirrus.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=PODMain02222019; bh=BoNiG02pYsgRnqXR1vMPhv+H38ToRb/HQJp34J6qJug=; b=X6tqrPOyQt5Qya1dgBYg8p31ys16F4yCHmpcZrTp6yF09DEbVQ6hApRGvIkx3j2psNaL zTHfN42U6vmGJcdoafx57Kq0d9ddg8s1MVLyasfr9L3drH7Zc+Hsz82gvtWyJyIy35gD NHLqgrGcKYwxpIV/pizpMRWmlqovsoa97Co+isnvjvLU9WGWdtLEsNY6GKa/6gP8DV2A oNXLZBi/8+FLBnr7AFcZyX2A/bYWd1/NBP/a9oGbLdqphBnlAq1y0uWl1qMKrst+pAQ+ ibuII2hB+r1fA0yusZ4hrGstGZlsxQ6wz6gKOGBnHdXa1h3Yhp3tLYJYg9cVraTlncqB Iw== Received: from ediex01.ad.cirrus.com ([84.19.233.68]) by mx0a-001ae601.pphosted.com (PPS) with ESMTPS id 3dqhyq0nwd-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT); Fri, 21 Jan 2022 06:04:18 -0600 Received: from EDIEX01.ad.cirrus.com (198.61.84.80) by EDIEX01.ad.cirrus.com (198.61.84.80) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.18; Fri, 21 Jan 2022 12:04:16 +0000 Received: from ediswmail.ad.cirrus.com (198.61.86.93) by EDIEX01.ad.cirrus.com (198.61.84.80) with Microsoft SMTP Server id 15.1.2375.18 via Frontend Transport; Fri, 21 Jan 2022 12:04:16 +0000 Received: from AUSNPC0LSNW1-debian.cirrus.com (AUSNPC0LSNW1.ad.cirrus.com [198.61.65.33]) by ediswmail.ad.cirrus.com (Postfix) with ESMTP id B36A211D7; Fri, 21 Jan 2022 12:04:15 +0000 (UTC) From: Richard Fitzgerald To: CC: , , , Richard Fitzgerald Subject: [PATCH v2 3/3] ASoC: cs42l42: Handle system suspend Date: Fri, 21 Jan 2022 12:04:12 +0000 Message-ID: <20220121120412.672284-4-rf@opensource.cirrus.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220121120412.672284-1-rf@opensource.cirrus.com> References: <20220121120412.672284-1-rf@opensource.cirrus.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-GUID: IXD6vLJAl8mTJyXki8EcMx2BOtvFpeEf X-Proofpoint-ORIG-GUID: IXD6vLJAl8mTJyXki8EcMx2BOtvFpeEf X-Proofpoint-Spam-Reason: safe Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add system suspend functions to handle clean power-down on suspend and restoring registers on resume. The jack state could change during suspend. Plug->unplug and unplug->plug are straightforward because this looks no different from any other plug state change - there will be a plugged or unplugged interrupt pending. The jack could be unplugged and a different type of jack plugged, and on resume the plug state would not have changed. Setting plug_state back to TS_TRANS (transitioning) will make the next plug interrupt after resume run a type detection. During system suspend any jack plug/unplug and button events will not be reported or generate a system wakeup. If the plug state or headset type has changed it will be reported after resume. Signed-off-by: Richard Fitzgerald --- sound/soc/codecs/cs42l42.c | 141 +++++++++++++++++++++++++++++++++++++++++= ++++ sound/soc/codecs/cs42l42.h | 5 ++ 2 files changed, 146 insertions(+) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index f1b95d45af4a..db6ef6cdce15 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1614,6 +1614,10 @@ static irqreturn_t cs42l42_irq_thread(int irq, void = *data) int report =3D 0; =20 mutex_lock(&cs42l42->irq_lock); + if (cs42l42->suspended) { + mutex_unlock(&cs42l42->irq_lock); + return IRQ_NONE; + } =20 /* Read sticky registers to clear interurpt */ for (i =3D 0; i < ARRAY_SIZE(stickies); i++) { @@ -2047,6 +2051,138 @@ static int cs42l42_handle_device_data(struct device= *dev, return 0; } =20 +/* Datasheet suspend sequence */ +static const struct reg_sequence __maybe_unused cs42l42_shutdown_seq[] =3D= { + REG_SEQ0(CS42L42_MIC_DET_CTL1, 0x9F), + REG_SEQ0(CS42L42_ADC_OVFL_INT_MASK, 0x01), + REG_SEQ0(CS42L42_MIXER_INT_MASK, 0x0F), + REG_SEQ0(CS42L42_SRC_INT_MASK, 0x0F), + REG_SEQ0(CS42L42_ASP_RX_INT_MASK, 0x1F), + REG_SEQ0(CS42L42_ASP_TX_INT_MASK, 0x0F), + REG_SEQ0(CS42L42_CODEC_INT_MASK, 0x03), + REG_SEQ0(CS42L42_SRCPL_INT_MASK, 0x7F), + REG_SEQ0(CS42L42_VPMON_INT_MASK, 0x01), + REG_SEQ0(CS42L42_PLL_LOCK_INT_MASK, 0x01), + REG_SEQ0(CS42L42_TSRS_PLUG_INT_MASK, 0x0F), + REG_SEQ0(CS42L42_WAKE_CTL, 0xE1), + REG_SEQ0(CS42L42_DET_INT1_MASK, 0xE0), + REG_SEQ0(CS42L42_DET_INT2_MASK, 0xFF), + REG_SEQ0(CS42L42_MIXER_CHA_VOL, 0x3F), + REG_SEQ0(CS42L42_MIXER_ADC_VOL, 0x3F), + REG_SEQ0(CS42L42_MIXER_CHB_VOL, 0x3F), + REG_SEQ0(CS42L42_HP_CTL, 0x0F), + REG_SEQ0(CS42L42_ASP_RX_DAI0_EN, 0x00), + REG_SEQ0(CS42L42_ASP_CLK_CFG, 0x00), + REG_SEQ0(CS42L42_HSDET_CTL2, 0x00), + REG_SEQ0(CS42L42_PWR_CTL1, 0xFE), + REG_SEQ0(CS42L42_PWR_CTL2, 0x8C), + REG_SEQ0(CS42L42_DAC_CTL2, 0x02), + REG_SEQ0(CS42L42_HS_CLAMP_DISABLE, 0x00), + REG_SEQ0(CS42L42_MISC_DET_CTL, 0x03), + REG_SEQ0(CS42L42_TIPSENSE_CTL, 0x02), + REG_SEQ0(CS42L42_HSBIAS_SC_AUTOCTL, 0x03), + REG_SEQ0(CS42L42_PWR_CTL1, 0xFF) +}; + +static int __maybe_unused cs42l42_suspend(struct device *dev) +{ + struct cs42l42_private *cs42l42 =3D dev_get_drvdata(dev); + unsigned int reg; + u8 save_regs[ARRAY_SIZE(cs42l42_shutdown_seq)]; + int i, ret; + + /* + * Wait for threaded irq handler to be idle and stop it processing + * future interrupts. This ensures a safe disable if the interrupt + * is shared. + */ + mutex_lock(&cs42l42->irq_lock); + cs42l42->suspended =3D true; + + /* Save register values that will be overwritten by shutdown sequence */ + for (i =3D 0; i < ARRAY_SIZE(cs42l42_shutdown_seq); ++i) { + regmap_read(cs42l42->regmap, cs42l42_shutdown_seq[i].reg, ®); + save_regs[i] =3D (u8)reg; + } + + /* Shutdown codec */ + regmap_multi_reg_write(cs42l42->regmap, + cs42l42_shutdown_seq, + ARRAY_SIZE(cs42l42_shutdown_seq)); + + /* All interrupt sources are now disabled */ + mutex_unlock(&cs42l42->irq_lock); + + /* Wait for power-down complete */ + msleep(CS42L42_PDN_DONE_TIME_MS); + ret =3D regmap_read_poll_timeout(cs42l42->regmap, + CS42L42_CODEC_STATUS, reg, + (reg & CS42L42_PDN_DONE_MASK), + CS42L42_PDN_DONE_POLL_US, + CS42L42_PDN_DONE_TIMEOUT_US); + if (ret) + dev_warn(dev, "Failed to get PDN_DONE: %d\n", ret); + + /* Discharge FILT+ */ + regmap_update_bits(cs42l42->regmap, CS42L42_PWR_CTL2, + CS42L42_DISCHARGE_FILT_MASK, CS42L42_DISCHARGE_FILT_MASK); + msleep(CS42L42_FILT_DISCHARGE_TIME_MS); + + regcache_cache_only(cs42l42->regmap, true); + gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); + regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); + + /* Restore register values to the regmap cache */ + for (i =3D 0; i < ARRAY_SIZE(cs42l42_shutdown_seq); ++i) + regmap_write(cs42l42->regmap, cs42l42_shutdown_seq[i].reg, save_regs[i]); + + /* The cached address page register value is now stale */ + regcache_drop_region(cs42l42->regmap, CS42L42_PAGE_REGISTER, CS42L42_PAGE= _REGISTER); + + dev_dbg(dev, "System suspended\n"); + + return 0; + +} + +static int __maybe_unused cs42l42_resume(struct device *dev) +{ + struct cs42l42_private *cs42l42 =3D dev_get_drvdata(dev); + int ret; + + /* + * If jack was unplugged and re-plugged during suspend it could + * have changed type but the tip-sense state hasn't changed. + * Force a plugged state to be re-evaluated. + */ + if (cs42l42->plug_state !=3D CS42L42_TS_UNPLUG) + cs42l42->plug_state =3D CS42L42_TS_TRANS; + + ret =3D regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies), cs42l42->sup= plies); + if (ret !=3D 0) { + dev_err(dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + + gpiod_set_value_cansleep(cs42l42->reset_gpio, 1); + usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2); + + regcache_cache_only(cs42l42->regmap, false); + regcache_mark_dirty(cs42l42->regmap); + + mutex_lock(&cs42l42->irq_lock); + /* Sync LATCH_TO_VP first so the VP domain registers sync correctly */ + regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_D= ET_CTL1); + regcache_sync(cs42l42->regmap); + + cs42l42->suspended =3D false; + mutex_unlock(&cs42l42->irq_lock); + + dev_dbg(dev, "System resumed\n"); + + return 0; +} + static int cs42l42_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { @@ -2217,6 +2353,10 @@ static int cs42l42_i2c_remove(struct i2c_client *i2c= _client) return 0; } =20 +static const struct dev_pm_ops cs42l42_pm_ops =3D { + SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_resume) +}; + #ifdef CONFIG_OF static const struct of_device_id cs42l42_of_match[] =3D { { .compatible =3D "cirrus,cs42l42", }, @@ -2243,6 +2383,7 @@ MODULE_DEVICE_TABLE(i2c, cs42l42_id); static struct i2c_driver cs42l42_i2c_driver =3D { .driver =3D { .name =3D "cs42l42", + .pm =3D &cs42l42_pm_ops, .of_match_table =3D of_match_ptr(cs42l42_of_match), .acpi_match_table =3D ACPI_PTR(cs42l42_acpi_match), }, diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 53d96287abba..244b24d1f5e9 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -826,6 +826,10 @@ #define CS42L42_PLL_LOCK_POLL_US 250 #define CS42L42_PLL_LOCK_TIMEOUT_US 1250 #define CS42L42_HP_ADC_EN_TIME_US 20000 +#define CS42L42_PDN_DONE_POLL_US 1000 +#define CS42L42_PDN_DONE_TIMEOUT_US 200000 +#define CS42L42_PDN_DONE_TIME_MS 100 +#define CS42L42_FILT_DISCHARGE_TIME_MS 46 =20 static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] =3D { "VA", @@ -860,6 +864,7 @@ struct cs42l42_private { u8 hs_bias_sense_en; u8 stream_use; bool hp_adc_up_pending; + bool suspended; }; =20 #endif /* __CS42L42_H__ */ --=20 2.11.0