From nobody Fri Sep 25 03:16:05 2026 Received: from outbound.qs.icloud.com (qs-2004b-snip4-4.eps.apple.com [57.103.84.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 49988463B69 for ; Thu, 17 Sep 2026 07:23:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=57.103.84.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789629831; cv=none; b=YS37M4i1BFWH/fosTctHx7XEVVCqz0FpjsoO0n2h1QzdvgVXik1WJHQff5nYlUptyeWvTQ/iMvz+4qqw+rwDyGTUWch23BVEb3icepqbnagEZqbGDjnZuxcz3sj3kFxk86Z3wdHuNu77IJ1Mjz69hRhgBnPIZkbtKg1fzz6Ridk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789629831; c=relaxed/simple; bh=lPNYRIWE5QUvNZDtQbTEBxRp2uQkkocq+i4veVp09MI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=caUGHIpvCFUaREWQl3aVei+qmL3f3b4NO4Ra+AupI70FofIiJ4us6vxAXkWSpEqU+DrVfYyZeoTz0CEDNQOVcT5Kd0q6bzk0AWgY+dt/ym544YyOnlQrZfaMH0RP3vovLCL2fKSLfcwDl9bLAE0ttthczzQ6P/FVYXjcFuGwvR0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=aurorasilicon.org; spf=pass smtp.mailfrom=aurorasilicon.org; dkim=pass (2048-bit key) header.d=aurorasilicon.org header.i=@aurorasilicon.org header.b=YcI0SXIG; arc=none smtp.client-ip=57.103.84.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=aurorasilicon.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=aurorasilicon.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=aurorasilicon.org header.i=@aurorasilicon.org header.b="YcI0SXIG" Received: from outbound.qs.icloud.com (unknown [127.0.0.2]) by p00-icloudmta-asmtp-us-east-2d-100-percent-11 (Postfix) with ESMTPS id 8C2FA180013A; Thu, 17 Sep 2026 07:23:45 +0000 (UTC) X-ICL-RepId: 01a0ae40-0176-7b00-9ec4-bffee2d4a47c X-ICL-Out-Info: HUtFAUMHWwJACUgBTUQeDx5WFlZNRAJCTQFPHVwFWhxCDUEdXANYEhVdRUEUVgVyEUwKXB9WGFscUBtcAxkEQBcZHldQVh5AH0sZQARbAlEfV1ZcH1BLQBMESQFNXw5eHwQXRhlVBEceXVZCHhkCURxWDVdDVARfUEkMQVBsWgBHF0gdXRlZb1BdHA4MQhldAlgLWgFeCF0eFxdBChcGWxQERFBaVVsLSAhOUVkGCFFDC0wFXAJYVhUMSAFeVFgHRAsdClkHCFYSC04dXABTC0YLSABeA0VVGU1WQRRWBXIRTApcH1YYWxxQG1wDGQRAFwdYRxRHDg8TTAtHAlo0Vh9UGVoD Dkim-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aurorasilicon.org; s=sig1; t=1789629829; x=1792221829; bh=KaAY72nhFKZyZCDxL9glObwTHfwItem+cUlVLX5wGX4=; h=From:To:Subject:Date:Message-ID:MIME-Version:x-icloud-hme; b=YcI0SXIG9zPdU1ztYmOyYUiQ1vrgGOx2Vk03uJo59bAxN1b9pr+HPyWBbONC4Clxs94XmuND3Iz4hySXqLB8Pc2JWvPobwYQyyvAlaMAaSNAGGbRLRj7/95LdTfWphe8myI90nx+7SJZwJ8MlLrkQ25YOyyapuTz4p4simG2Devn47QMKeBpKBsCWlQtuSKg0F3HbAS2zkxWhoceWCjGxGtdXsiFienTv2LPh1hzt7pyuXCZ2n3cAvksn39G+/7ujXeHE3FSfz/VjHfcs2jN65lNb0T73GRD/a1a98wgwM3hBdYI+MyYKjIf+GOI43qfqX29kd/jA3v0PuDX3vWKNg== mail-alias-created-date: 1786334582283 Received: from localhost.localdomain (unknown [17.57.155.37]) by p00-icloudmta-asmtp-us-east-2d-100-percent-11 (Postfix) with ESMTPSA id 95061180011A; Thu, 17 Sep 2026 07:23:41 +0000 (UTC) From: Ryan Murray To: patches@opensource.cirrus.com, linux-sound@vger.kernel.org Cc: david.rhodes@cirrus.com, rf@opensource.cirrus.com, lgirdwood@gmail.com, broonie@kernel.org, perex@perex.cz, tiwai@suse.com, james.schulman@cirrus.com, povik+lin@cutebit.org, asahi@lists.linux.dev, linux-kernel@vger.kernel.org Subject: [RFC PATCH 1/2] ASoC: cs42l42: handle jack interrupt I/O and resume errors Date: Thu, 17 Sep 2026 17:23:37 +1000 Message-ID: X-Mailer: git-send-email 2.50.1 In-Reply-To: References: Reply-To: ryan@aurorasilicon.org Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-GUID: O9-YwKNKx5GY_6UOgSq4D3iVxDHrpKQA X-Proofpoint-ORIG-GUID: O9-YwKNKx5GY_6UOgSq4D3iVxDHrpKQA X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTE3MDA5OSBTYWx0ZWRfX4Tpxlal+T56r 38aX9LG8LjsD2MjACdX7tureYfX4ncArKXiDsuqH3cyEPoF3+P69GKxUC81olAoNRJ1j4qoq+Bv i8+YLh6Er6cQDlhfR8d+v3cGeHNLjNPY9rS9wOBxUY+Fee9PVDmHrf631myS1mewC5Xhwie5dbg O9GbduxS7jks40MuOBJOZJdPZOPZGZelRUj7Pud/aI1pU9m2YAbzZslDWd21xOASA+1gUW7xe7y XaNMCffs3CbyWi5miQJf7xi3jKnPKPX55aelU/yU3jAoEEE57tNR3eziTmRDbfkS+crr3vqDFbZ l6PpmY/lfg6OkNwpuVjEG07rtKbNzPPvdh1fm2TLLaQOv7sV6RA36eQD2QXwcc= X-Authority-Info-Out: v=2.4 cv=K9Yv3iWI c=1 sm=1 tr=0 ts=6aab9583 cx=c_apl:c_pps:t_out a=bsP7O+dXZ5uKcj+dsLqiMw==:117 a=bsP7O+dXZ5uKcj+dsLqiMw==:17 a=VdqzKS8jKosA:10 a=VkNPw1HP01LnGYTKEx00:22 a=CKCxWeCRAAAA:8 a=xH05H95Wop1-WDW_iRwA:9 a=98DSvwJP-PC3Li7B9DIO:22 X-JNJ: AAAAAAABGcL+1EoTgWG7nTi7OgK8+tnObg/dRlUm1E0h3IBN9YscP22FciUuBtuTuPWhduHgutkKk0qjrn4ZzSgDMFFSQdf9DviqS6i14rz9CL8GD7Nvcvo+wL/QP+wJjvdvFdJn62Syqwu9LIqDj7kVY0jszCRx8XJor4Z8Jhy38vpEq7lfsJPUDo8phR0Lip303HhiGQPq7kVVVuvDRFz1iiKr+vSuu2K5IQUqo064jivPkuekPLh1J+vUGullizKmXhQ6tDDitxy5uF2N67wSki2BPy2EM4Ooqa1tK3vYhy4BHZlUwgGNwtxAU2Z4ylqxlyGHtMohyEjuf5g0HiAX15gfkhw1MI51kPBPUJG01+hXDpqlLzjwjK2q1guGl32ynwoUinXIhqOC7gKeC/fDrly/C5g/RVqgDxm3Tfggi0QwUEJPhX2EXsefQYIvNMFnkiahQ5+hESsGlT+sStNQvaGNdvbjRtFGLxavBwT6mwhZJlF6O1NqBczSsOuKsIqrTr9eqe4im7rWPXJpy+aF7tHpuFhMy4FPI5yMf23aKolqBAnAupPs5JY77AtpuKxfY7Uthb5ozM9nY1zJFTwPoCxOZxE2gZ9SvJZyB4PRyraWpeymMlte/6VaOKxcF0qZkSMaU8DRDPomC9+pj1Mp2FU9Obk86cfl1tjJgjIp6Qrd9iJITg86my1m1BlCCfD2YuSEi7YTREH2Fut1S/88CtQxg7emj8MLMEv8bC8WSW55H+DkcMy58XDH4LA/tvh4Z51qMKkL6dcbTDb+4mPOnAVXXTYVBk1XhwWH35V33NrYkSf1zlPkgLZ1uAgi34Q9swAdLGQV55dfP2U6nq5vPL0bveu0bkZzGCuw7g/iOJGoeQ8NHMK0aYQWybwFVlep+T29Yc2okOFLehmAWC2ug8WZxonkB6Hra2buz3ZXa9YRttvvAYMrOw+WcOhaPaLHOXchvyLlh2ub8sCIkILg0/DmtBN AX+OQpzi1zYnUNGlp6uO1+S5G8dhcyMUgElOG04gDAerp4AtIcmJvuCEP1lW8gOHvcKyhnR7jMh9DFwDoM/F3bRPx/mRJ1JS+2fUOMyxH1ptfWWM8AZJnXsg5mtl7XfCYwO0JIaIP/10XXAenrcLRdqGsLzyQ8P4rR3Vh0+KgfLqmo8HXxQmevvP3A0mH8TJ4xuMkKijhsEPZ4CEzfmKYYRs/YR7pD0GzbyWY6TgKvtKTy5LXOBVz1dLEM7ZxsgPGhmPAisx/tQKaXHIe9BD36DG5NLV3kZRkzXCP9nQtDWFAXyDO9CqAeVO+HDPWR16fgafjYADYPAYLQec43sWZYFg29DYAoiesHDA/cKw+yTfh5ccSmSwP9IPVBl0rn0OdDlA+ZUxmGHXW/UfXj9wQ/QV4BpYeTe0= Content-Type: text/plain; charset="utf-8" A failed status or mask read leaves part of the interrupt snapshot uninitialized. The handler can then interpret that data as headset or button events. It also attempts register access after a failed runtime resume. Check the runtime-PM acquisition and each snapshot read before processing any events. Use the transparent autosuspend guard so the always-powered I2C transport continues to work when runtime PM is disabled. Keep the existing scoped mutex and PM cleanup on every return path. An extracted-handler fault-injection test reproduces event processing on failed reads before this change and checks all 24 snapshot read failures after it, together with resume failure and disabled-runtime-PM cases. Fixes: 2c394ca79604 ("ASoC: Add support for CS42L42 codec") Assisted-by: LLM Signed-off-by: Ryan Murray --- sound/soc/codecs/cs42l42.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index fadf68860..2d1b45ea1 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1667,18 +1667,25 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data) unsigned int current_plug_status; unsigned int current_button_status; unsigned int i; + int ret; =20 - guard(pm_runtime_active_auto)(cs42l42->dev); + PM_RUNTIME_ACQUIRE_AUTOSUSPEND(cs42l42->dev, pm); + if (PM_RUNTIME_ACQUIRE_ERR(&pm)) + return IRQ_NONE; guard(mutex)(&cs42l42->irq_lock); if (cs42l42->suspended || !cs42l42->init_done) return IRQ_NONE; =20 - /* Read sticky registers to clear interurpt */ + /* Read sticky registers to clear interrupt */ for (i =3D 0; i < ARRAY_SIZE(stickies); i++) { - regmap_read(cs42l42->regmap, irq_params_table[i].status_addr, - &(stickies[i])); - regmap_read(cs42l42->regmap, irq_params_table[i].mask_addr, - &(masks[i])); + ret =3D regmap_read(cs42l42->regmap, irq_params_table[i].status_addr, + &stickies[i]); + if (ret) + goto out_error; + ret =3D regmap_read(cs42l42->regmap, irq_params_table[i].mask_addr, + &masks[i]); + if (ret) + goto out_error; stickies[i] =3D stickies[i] & (~masks[i]) & irq_params_table[i].mask; } @@ -1772,6 +1779,10 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data) } =20 return IRQ_HANDLED; + +out_error: + dev_err_ratelimited(cs42l42->dev, "Failed to read jack interrupt state: %= d\n", ret); + return IRQ_NONE; } EXPORT_SYMBOL_NS_GPL(cs42l42_irq_thread, "SND_SOC_CS42L42_CORE"); From nobody Fri Sep 25 03:16:05 2026 Received: from outbound.qs.icloud.com (qs-2006a-snip4-11.eps.apple.com [57.103.85.141]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9EF3D471431 for ; Thu, 17 Sep 2026 07:23:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=57.103.85.141 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789629836; cv=none; b=V4Z+PNTq3YYhF1M8WiAoZzk2a0LW8Sc1WIZceBqjqjPT8KC2FVubkepq8w752fP2MT7Nf7lFmHYaUuvWYleLLKJc64CjqCzAVhJNUOmH72CzcnY5JzIDdkSF6nkit///o9cn0c7fQf28I2dtr8TGpLADZYYddGunkcSGjWqdZ1E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789629836; c=relaxed/simple; bh=c5d9wVHghXAs3fldwRdBDEV9dgh79bdF4SijC5h1xlA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=phTx+EJfo0ZnQu3enUWlgnWIdyhpFOQg94fx9oWWMmRcevrSUDb+RKDqKOhfq5jygp0CNMLj1NSYbhopaj4VVPQLugRYmDOs/5ZKWPz/vrt5OZ+TpS2rLvVbN66ddyazkIo+24H/q3xM8iMuA4thTPqEXFJH5zAKynyeCxdPXpc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=aurorasilicon.org; spf=pass smtp.mailfrom=aurorasilicon.org; dkim=pass (2048-bit key) header.d=aurorasilicon.org header.i=@aurorasilicon.org header.b=YlHVUkf0; arc=none smtp.client-ip=57.103.85.141 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=aurorasilicon.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=aurorasilicon.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=aurorasilicon.org header.i=@aurorasilicon.org header.b="YlHVUkf0" Received: from outbound.qs.icloud.com (unknown [127.0.0.2]) by p00-icloudmta-asmtp-us-east-2d-100-percent-9 (Postfix) with ESMTPS id BB2B8180015A; Thu, 17 Sep 2026 07:23:51 +0000 (UTC) X-ICL-RepId: 01a0ae40-19e4-7295-baca-e6a793b45cef X-ICL-Out-Info: HUtFAUMHWwJACUgBTUQeDx5WFlZNRAJCTQFPHVwFWhxCDUEdXANYEhVdRUEUVgVyEUwKXB9WGFscUBtcAxkEQBcZHldQVh5AH0sZQARbAlEfV1ZcH1BLQBMESQFNXw5eHwQXRhlVBEceXVZCHhkCURxWDVdDVARfUEkMQVBsWgBHF0gdXRlZb1BdHA4MQhldAlgLWgFeCF0eFxdBChcGWxQERFVbAw8KEQwaUlUACgBDAUkEWgJdBkABSQQOBV8HFQFPAQxVUlMTCBkdXABTC0YLSABeA0VVGU1WQRRWBXIRTApcH1YYWxxQG1wDGQRAFwdYRxRHDg8TTAtHAlo0Vh9UGVoD Dkim-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aurorasilicon.org; s=sig1; t=1789629833; x=1792221833; bh=SN67ss+oaOyYTZGpxW9XKmUD0sh/EGH78bfhp/3LrEY=; h=From:To:Subject:Date:Message-ID:MIME-Version:x-icloud-hme; b=YlHVUkf0u16XqNH3XhbmVQirHSk2RTVEY2YXZjhlZ70q2vqJq0hoQ+ZYI1lYMjNK0zLfhnj0TWv1nOTgo4uhqXZWQak5cWqFK0vVUYHBiTzD/Oe/jUF8dMs3CJ5miCBhxhykz9JIT4yxETDK4CnfKRCkxxYjs73dmMXimqrCx8GQOF2ociBNNp6lh/olNbKVLz62Zg9UjwhSl+NqRaV56Y+qY8VgKhxHfcajvquT8/wV06RtUGGGyf7b6Q+C6y9WZnfn+ihzEnESVcGyD3t4r4WPG3yLW9cnLPRAq4Ha1jUkqsHziv+XCiv1clXgCgJxdQ8jQ6eU273o7AOwT5M9Yg== mail-alias-created-date: 1786334582283 Received: from localhost.localdomain (unknown [17.57.155.37]) by p00-icloudmta-asmtp-us-east-2d-100-percent-9 (Postfix) with ESMTPSA id 327171800108; Thu, 17 Sep 2026 07:23:47 +0000 (UTC) From: Ryan Murray To: patches@opensource.cirrus.com, linux-sound@vger.kernel.org Cc: david.rhodes@cirrus.com, rf@opensource.cirrus.com, lgirdwood@gmail.com, broonie@kernel.org, perex@perex.cz, tiwai@suse.com, james.schulman@cirrus.com, povik+lin@cutebit.org, asahi@lists.linux.dev, linux-kernel@vger.kernel.org Subject: [RFC PATCH 2/2] ASoC: cs42l42: support Apple headset remotes on CS42L83 Date: Thu, 17 Sep 2026 17:23:44 +1000 Message-ID: X-Mailer: git-send-email 2.50.1 In-Reply-To: References: Reply-To: ryan@aurorasilicon.org Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-ORIG-GUID: Ohcgxlyr_NSAoWeyYpPgOwbIcpIfEong X-Authority-Info-Out: v=2.4 cv=Tp7rRTXh c=1 sm=1 tr=0 ts=6aab9588 cx=c_apl:c_pps:t_out a=bsP7O+dXZ5uKcj+dsLqiMw==:117 a=bsP7O+dXZ5uKcj+dsLqiMw==:17 a=VdqzKS8jKosA:10 a=VkNPw1HP01LnGYTKEx00:22 a=CKCxWeCRAAAA:8 a=iiW-TkCOkVL_QCY16vAA:9 a=98DSvwJP-PC3Li7B9DIO:22 X-Proofpoint-GUID: Ohcgxlyr_NSAoWeyYpPgOwbIcpIfEong X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTE3MDA5OSBTYWx0ZWRfX0g6arNLUEdXY KmMjOmK0huZTNkjEQufVHZz8w5MIvHqd4upb78pGI1dCChHzhvY2gds/iYAVGf3uSNJbHty5TiZ a+vfsrPHpnhKzGPZgZSrW369GzaJQwFPFnYCy2lYGe7b0wDludpW8saccnJiXGz5TA+O9ItYVcx hBSt5S7z21H35VHB7aSLVhHcLpSpo4Q3p3UFNU+ObPm3AkxqvYM2/W440M3UU//pcClkqRrB995 ZxFVDLVpjEfR7DHQnn+Zaecgtp+3BXAqT/7NLUf4bvVvcToLliumC4An1lt0b7dm3wpiFyyaOib R3hQ5oAf9rWctmw22fATsaBCU1Ftc6eRo0dQyicGDro7LsJsemuKEVEVk1alcA= X-JNJ: AAAAAAABi9kWgPWl95JD7tpMI19F1fsZnnRhZtUZTtPV37K+c42kv50Fmss5WBuz1Urqxq6J1EsrOU25GfC0aLmIIiVazBbDXfvZXLs6KH0WAqHBP8H5+DV5jd7NHQtxgavG+qWppRMoTnwW44N/9N4s8PtOMRWODw9AxGWjeVp9wGyaz0lp0EuEBozv337K9Vd7hw00XqiBtB+ax/ORSQuiObSY68LvNEv7YMFYj9i0zNchb8PrEXZmTcnU84SpmBOCMwa+ZMWsyo0lWDmZP8M0WNmfvS8jQbo5ZUJA+y0cNA2AA2TEhmq5sfh9/mcUigQ+aZgzGi/GQ8orhiCRZ0nnzvpkMvd0UHo0LVW1S3NRJPTxHdpfFEHzZ5nVmO1yF4ZnxZnQ9G+Saocl2gYkFRhrXINgjeD1JN4IAdhpClHKU9sPYI6UGIEsWRKqNzcl9B9dx88ZjcKpMasSR9BUcMdgspNqEDZBq+FzjcfL+m+3fiqQ/NyGjxQmz81N3GGCaSLdHnQVjqQT6gCxrQOwPfnYze4dob6no/8cGv6jliNeglejb43TLC+9ulsjKueI9xpXRduekqFq3cBYRFCBG96RkOXjqnCC9GhGxdJU9n5COJkt0wnAuGxMpS2lK0RzddYxau04cE9McNa9WVWfOi2DRqUG79INsBYdBboTmdQhqlzYIzLGd8YM1TsRBWbjH9p0BTfBMQYzWcmJPi7vuZhz8mFCaujMktptxcRDGIQD/bMiVy2NEJ+jkWBeSDve/lDEZbmM/uMTqLyrTthxg/nJwcPGr1YIRDeIQx7en6xBZkooB+UkAa1a3V9jTBFGRn8LcGInMaBv8J3pGNand8PkoZJFGw4/4KWSbk902HM/qjEuUkU5K8XjMTlKMMlBw7UGgt+LGZuuPrcH+QBKOueU1RM93Ko1gCt8FVldUwxposyoypq57vIUUVcIRzmOLEmG24sgGGxFIiOgJqD/jJizF/KKiUd 9UmYBhlMcXWNU0oNUvRAA7WIG/XATZH4LrTQ93V09ABylafGWV3A5L5bQ/X7pbXdmwCrp5qJ5YRzljPYgCHukYREEgkLZqk3Zgfe/Ry5VM91Veext0plac9w4mpDK4FFu9f29LhQAl5iiLddXZddy4GgCu0iDukQqS8srBnfF5XmDdvtrC1P/s9k4Rb1xnfQIbr2RBZuaZWWbCFH14wmc2P1SmU+divOumXAOnlaK/+SUk65L8VjG9fEp6IxEoLWd6WEnH+MdsEvznSAcwQ++wPbqvOf/ly+kkFeVmWn2aTd7I6hhaahW3hi2ZOWP/I4m2bsA7l8B9xKwjk1ojnAZqxqZ7sBEWTMbkytHS3Zy1qheA0jnhL2Tez34TqOqVLY767Qp2nkj3X680zKKn+Vp0BuaKXuqFMHflBAId7WcGS0k/iePrHzBtuE= Content-Type: text/plain; charset="utf-8" Apple wired headset volume buttons use a microphone-bias signalling protocol instead of the resistor levels handled by the analogue detector. The CS42L83 can identify these remotes and decode their button indications without an audio stream or an external serial clock. After CTIA or OMTP detection, perform a bounded identification exchange on CS42L83. Wait for the receive acknowledgment rather than the earlier transmit-complete indication, which can expose an incomplete identifier. Validate all three identifier symbols before enabling remote reception. Restore the analogue detector on timeout, a short, an invalid identifier, or a register-access error. Preserve the receiver's raw volume indications before applying the analogue interrupt masks. Report volume indications as press/release pairs and use short-detect transitions for the centre button. Discard pre-identification button state and restore the saved detector settings on unplug, redetection and suspend under the existing IRQ mutex. Select this capability from the CS42L83 device identity. No board-specific property, clock provider, work item or extra power reference is needed. The CS42L42 continues to use its analogue detector. The undocumented CS42L83 sequence was independently implemented from register-level reverse engineering and validated on a J700 with a B0 codec and Apple wired earbuds. Other boards and codec revisions have not been hardware-tested. The machine driver must expose the appropriate SND_JACK_BTN capabilities and key mappings. Assisted-by: LLM Signed-off-by: Ryan Murray --- sound/soc/codecs/cs42l42.c | 263 ++++++++++++++++++++++++++++++++++++- sound/soc/codecs/cs42l42.h | 15 +++ 2 files changed, 276 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 2d1b45ea1..c510ceae8 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -1257,6 +1258,240 @@ static void cs42l42_manual_hs_type_detect(struct cs= 42l42_private *cs42l42) (CS42L42_HSDET_COMP2_LVL_DEFAULT << CS42L42_HSDET_COMP2_LVL_SHIFT)); } =20 +/* + * CS42L83 receives Apple headset remote data over the microphone-bias lin= e. + * The receiver operates on the internal oscillator, including while audio + * is idle. These control values and status bits are specific to CS42L83. + */ +#define CS42L83_REMOTE_TX_START BIT(7) +#define CS42L83_REMOTE_RX_ACK BIT(3) +#define CS42L83_REMOTE_BUTTON_IRQ BIT(5) +#define CS42L83_REMOTE_BUTTONS GENMASK(4, 0) +#define CS42L83_REMOTE_VOLUME_DOWN BIT(0) +#define CS42L83_REMOTE_VOLUME_UP BIT(1) + +/* Complete receiver control values; these are not CS42L42 detect modes. */ +#define CS42L83_REMOTE_BIAS_RESET 0x03 +#define CS42L83_REMOTE_BIAS_IDENTIFY 0x9e +#define CS42L83_REMOTE_BIAS_BUTTONS 0x5f +#define CS42L83_REMOTE_RX_CONFIG 0x8f +#define CS42L83_REMOTE_LEVEL_IDENTIFY 0x36 +#define CS42L83_REMOTE_LEVEL_BUTTONS 0x3c + +static const unsigned int cs42l83_remote_regs[] =3D { + [CS42L83_REMOTE_SAVED_HSBIAS_SC_AUTOCTL] =3D CS42L42_HSBIAS_SC_AUTOCTL, + [CS42L83_REMOTE_SAVED_WAKE_CTL] =3D CS42L42_WAKE_CTL, + [CS42L83_REMOTE_SAVED_MISC_DET_CTL] =3D CS42L42_MISC_DET_CTL, + [CS42L83_REMOTE_SAVED_MIC_DET_CTL1] =3D CS42L42_MIC_DET_CTL1, + [CS42L83_REMOTE_SAVED_MIC_DET_CTL2] =3D CS42L42_MIC_DET_CTL2, + [CS42L83_REMOTE_SAVED_DET_INT1_MASK] =3D CS42L42_DET_INT1_MASK, + [CS42L83_REMOTE_SAVED_DET_INT2_MASK] =3D CS42L42_DET_INT2_MASK, + [CS42L83_REMOTE_SAVED_HS_BIAS_CTL] =3D CS42L42_HS_BIAS_CTL, + [CS42L83_REMOTE_SAVED_HSDET_CTL2] =3D CS42L42_HSDET_CTL2, +}; + +static void cs42l83_remote_restore(struct cs42l42_private *cs42l42) +{ + int i, ret; + + for (i =3D 0; i < ARRAY_SIZE(cs42l83_remote_regs); i++) { + ret =3D regmap_write(cs42l42->regmap, cs42l83_remote_regs[i], + cs42l42->remote_saved[i]); + if (ret) + dev_warn(cs42l42->dev, "Failed to restore headset detection register %#= x: %d\n", + cs42l83_remote_regs[i], ret); + } + cs42l42->remote_active =3D false; +} + +/* + * Hold the bias reference during a bias-mode change and allow it to settle + * before starting transmission. Apply the TX bit only after the bias bits. + */ +static int cs42l83_remote_set_detect(struct cs42l42_private *cs42l42, unsi= gned int value) +{ + unsigned int old; + bool changed; + int ret; + + ret =3D regmap_read(cs42l42->regmap, CS42L42_MISC_DET_CTL, &old); + if (ret) + return ret; + changed =3D (old & CS42L42_HSBIAS_CTL_MASK) !=3D (value & CS42L42_HSBIAS_= CTL_MASK); + if (changed) { + /* CS42L83 bias transitions require clearing this undocumented field. */ + ret =3D regmap_update_bits(cs42l42->regmap, CS42L42_HS_BIAS_CTL, GENMASK= (3, 2), 0); + if (ret) + return ret; + ret =3D regmap_update_bits(cs42l42->regmap, CS42L42_HSDET_CTL2, + CS42L42_HSBIAS_REF_MASK, CS42L42_HSBIAS_REF_MASK); + if (ret) + return ret; + } + ret =3D regmap_update_bits(cs42l42->regmap, CS42L42_MISC_DET_CTL, + value & CS42L83_REMOTE_TX_START ? 0x7f : 0xff, value); + if (ret) + return ret; + if (!!(old & BIT(2)) !=3D !!(value & BIT(2))) + usleep_range(10000, 11000); + if (value & CS42L83_REMOTE_TX_START) { + ret =3D regmap_write(cs42l42->regmap, CS42L42_MISC_DET_CTL, value); + if (ret) + return ret; + } + if (changed) + return regmap_update_bits(cs42l42->regmap, CS42L42_HSDET_CTL2, + CS42L42_HSBIAS_REF_MASK, 0); + return 0; +} + +/* Called with irq_lock held; every attempt is bounded and has analogue fa= llback. */ +static void cs42l83_remote_start(struct cs42l42_private *cs42l42) +{ + static const struct reg_sequence identify[] =3D { + { CS42L42_DET_INT2_MASK, 0xff }, + { CS42L42_HSBIAS_SC_AUTOCTL, 0x03 }, + { CS42L42_WAKE_CTL, CS42L42_M_HP_WAKE_MASK | CS42L42_M_MIC_WAKE_MASK }, + { CS42L42_MIC_DET_CTL2, CS42L83_REMOTE_RX_CONFIG }, + }; + unsigned int int1, int2, status1, status2, symbols, symbol[3]; + unsigned long deadline; + int i, ret; + + if (cs42l42->devid !=3D CS42L83_CHIP_ID || + (cs42l42->hs_type !=3D CS42L42_PLUG_CTIA && + cs42l42->hs_type !=3D CS42L42_PLUG_OMTP)) + return; + + for (i =3D 0; i < ARRAY_SIZE(cs42l83_remote_regs); i++) { + ret =3D regmap_read(cs42l42->regmap, cs42l83_remote_regs[i], + &cs42l42->remote_saved[i]); + if (ret) + return; + } + + ret =3D regmap_multi_reg_write(cs42l42->regmap, identify, ARRAY_SIZE(iden= tify)); + if (ret) + goto fallback; + /* Reset the bias before applying the identification threshold. */ + ret =3D cs42l83_remote_set_detect(cs42l42, CS42L83_REMOTE_BIAS_RESET); + if (ret) + goto fallback; + usleep_range(10000, 11000); + ret =3D regmap_update_bits(cs42l42->regmap, CS42L42_MIC_DET_CTL1, + CS42L42_HS_DET_LEVEL_MASK, CS42L83_REMOTE_LEVEL_IDENTIFY); + if (ret) + goto fallback; + ret =3D regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS1, &int1); + if (ret) + goto fallback; + ret =3D regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS2, &int2); + if (ret) + goto fallback; + /* Start identification after the controlled bias rise. */ + ret =3D cs42l83_remote_set_detect(cs42l42, CS42L83_REMOTE_BIAS_IDENTIFY); + if (ret) + goto fallback; + + /* + * Bit 4 signals TX completion, before the remote reply is ready. Wait + * for RX acknowledgment (bit 3), with a bounded analogue fallback. + */ + msleep(35); + deadline =3D jiffies + msecs_to_jiffies(500); + do { + ret =3D regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS2, &int2); + if (ret) + goto fallback; + if (int2 & CS42L83_REMOTE_RX_ACK) + break; + usleep_range(5000, 6000); + } while (time_before(jiffies, deadline)); + if (!(int2 & CS42L83_REMOTE_RX_ACK)) { + ret =3D -ETIMEDOUT; + goto fallback; + } + ret =3D regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS1, &int1); + if (ret) + goto fallback; + ret =3D regmap_read(cs42l42->regmap, CS42L42_DET_STATUS1, &status1); + if (ret) + goto fallback; + ret =3D regmap_read(cs42l42->regmap, CS42L42_DET_STATUS2, &status2); + if (ret) + goto fallback; + symbols =3D (status2 >> 4) | ((status1 & 0x1f) << 4); + for (i =3D 0; i < ARRAY_SIZE(symbol); i++) + symbol[i] =3D (symbols >> (i * 3)) & 7; + /* A short or an invalid identifier must retain the analogue detector. */ + if (status2 & CS42L42_SHORT_TRUE_MASK) { + ret =3D -ENODEV; + goto fallback; + } + for (i =3D 0; i < ARRAY_SIZE(symbol); i++) { + if (symbol[i] < 1 || symbol[i] > 4) { + ret =3D -ENODEV; + goto fallback; + } + } + + /* Use the remote-button threshold only after a valid identification. */ + ret =3D regmap_update_bits(cs42l42->regmap, CS42L42_MIC_DET_CTL1, + CS42L42_HS_DET_LEVEL_MASK, CS42L83_REMOTE_LEVEL_BUTTONS); + if (ret) + goto fallback; + + /* The receiver now decodes remote button pulses autonomously. */ + ret =3D cs42l83_remote_set_detect(cs42l42, CS42L83_REMOTE_BIAS_BUTTONS); + if (ret) + goto fallback; + msleep(35); + ret =3D regmap_write(cs42l42->regmap, CS42L42_HSBIAS_SC_AUTOCTL, + (cs42l42->hs_bias_sense_en << CS42L42_HSBIAS_SENSE_EN_SHIFT) | 3); + if (ret) + goto fallback; + ret =3D regmap_write(cs42l42->regmap, CS42L42_DET_INT1_MASK, + cs42l42->remote_saved[CS42L83_REMOTE_SAVED_DET_INT1_MASK] & + ~(cs42l42->hs_bias_sense_en << CS42L42_HSBIAS_SENSE_SHIFT)); + if (ret) + goto fallback; + ret =3D regmap_write(cs42l42->regmap, CS42L42_DET_INT2_MASK, + 0xff & ~(CS42L83_REMOTE_BUTTON_IRQ | + CS42L42_M_SHORT_DET_MASK | CS42L42_M_SHORT_RLS_MASK)); + if (ret) + goto fallback; + cs42l42->remote_active =3D true; + dev_dbg(cs42l42->dev, "Apple headset remote enabled\n"); + return; + +fallback: + dev_dbg(cs42l42->dev, "Headset remote identification failed: %d\n", ret); + cs42l83_remote_restore(cs42l42); +} + +static void cs42l83_remote_buttons(struct cs42l42_private *cs42l42, + unsigned int int1, unsigned int int2) +{ + unsigned int buttons =3D 0; + + /* Volume indications are pulses, without a separate release event. */ + if (int1 & CS42L83_REMOTE_BUTTONS) { + if (int1 & CS42L83_REMOTE_VOLUME_DOWN) + buttons |=3D SND_JACK_BTN_2; + if (int1 & CS42L83_REMOTE_VOLUME_UP) + buttons |=3D SND_JACK_BTN_1; + if (buttons) + snd_soc_jack_report(cs42l42->jack, buttons, + SND_JACK_BTN_1 | SND_JACK_BTN_2); + snd_soc_jack_report(cs42l42->jack, 0, + SND_JACK_BTN_1 | SND_JACK_BTN_2); + } + if (int2 & CS42L42_M_SHORT_DET_MASK) + snd_soc_jack_report(cs42l42->jack, SND_JACK_BTN_0, SND_JACK_BTN_0); + if (int2 & CS42L42_M_SHORT_RLS_MASK) + snd_soc_jack_report(cs42l42->jack, 0, SND_JACK_BTN_0); +} + static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42) { unsigned int hs_det_status; @@ -1398,6 +1633,9 @@ static void cs42l42_process_hs_type_detect(struct cs4= 2l42_private *cs42l42) =20 static void cs42l42_init_hs_type_detect(struct cs42l42_private *cs42l42) { + if (cs42l42->remote_active) + cs42l83_remote_restore(cs42l42); + /* Mask tip sense interrupts */ regmap_update_bits(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK, @@ -1485,6 +1723,9 @@ static void cs42l42_init_hs_type_detect(struct cs42l4= 2_private *cs42l42) =20 static void cs42l42_cancel_hs_type_detect(struct cs42l42_private *cs42l42) { + if (cs42l42->remote_active) + cs42l83_remote_restore(cs42l42); + /* Mask button detect interrupts */ regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT2_MASK, @@ -1664,6 +1905,7 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data) struct cs42l42_private *cs42l42 =3D (struct cs42l42_private *)data; unsigned int stickies[12]; unsigned int masks[12]; + unsigned int raw_remote_buttons =3D 0; unsigned int current_plug_status; unsigned int current_button_status; unsigned int i; @@ -1686,8 +1928,11 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data) &masks[i]); if (ret) goto out_error; - stickies[i] =3D stickies[i] & (~masks[i]) & - irq_params_table[i].mask; + if (cs42l42->remote_active && i =3D=3D 6) + raw_remote_buttons =3D stickies[i] & CS42L83_REMOTE_BUTTONS; + stickies[i] &=3D ~masks[i]; + if (!(cs42l42->remote_active && i =3D=3D 7)) + stickies[i] &=3D irq_params_table[i].mask; } =20 /* Read tip sense status before handling type detect */ @@ -1709,6 +1954,13 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data) if ((~masks[5]) & irq_params_table[5].mask) { if (stickies[5] & CS42L42_HSDET_AUTO_DONE_MASK) { cs42l42_process_hs_type_detect(cs42l42); + if (cs42l42->devid =3D=3D CS42L83_CHIP_ID) { + cs42l83_remote_start(cs42l42); + /* Do not interpret pre-identification events as keys. */ + current_button_status =3D 0; + stickies[7] =3D 0; + raw_remote_buttons =3D 0; + } switch (cs42l42->hs_type) { case CS42L42_PLUG_CTIA: case CS42L42_PLUG_OMTP: @@ -1759,6 +2011,11 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data) } } =20 + if (cs42l42->remote_active && cs42l42->plug_state =3D=3D CS42L42_TS_PLUG)= { + cs42l83_remote_buttons(cs42l42, raw_remote_buttons, stickies[7]); + return IRQ_HANDLED; + } + /* Check button detect status */ if (cs42l42->plug_state =3D=3D CS42L42_TS_PLUG && ((~masks[7]) & irq_para= ms_table[7].mask)) { if (!(current_button_status & @@ -2169,6 +2426,8 @@ int cs42l42_suspend(struct device *dev) * is shared. */ scoped_guard(mutex, &cs42l42->irq_lock) { + if (cs42l42->remote_active) + cs42l83_remote_restore(cs42l42); cs42l42->suspended =3D true; =20 /* Save register values that will be overwritten by shutdown sequence */ diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 3d85ebc59..1065d8cd6 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -24,6 +24,19 @@ #include #include =20 +enum cs42l83_remote_saved_reg { + CS42L83_REMOTE_SAVED_HSBIAS_SC_AUTOCTL, + CS42L83_REMOTE_SAVED_WAKE_CTL, + CS42L83_REMOTE_SAVED_MISC_DET_CTL, + CS42L83_REMOTE_SAVED_MIC_DET_CTL1, + CS42L83_REMOTE_SAVED_MIC_DET_CTL2, + CS42L83_REMOTE_SAVED_DET_INT1_MASK, + CS42L83_REMOTE_SAVED_DET_INT2_MASK, + CS42L83_REMOTE_SAVED_HS_BIAS_CTL, + CS42L83_REMOTE_SAVED_HSDET_CTL2, + CS42L83_REMOTE_NUM_SAVED_REGS, +}; + struct cs42l42_private { struct regmap *regmap; struct device *dev; @@ -51,6 +64,8 @@ struct cs42l42_private { u8 hs_bias_ramp_time; u8 hs_bias_sense_en; u8 stream_use; + bool remote_active; + unsigned int remote_saved[CS42L83_REMOTE_NUM_SAVED_REGS]; bool hp_adc_up_pending; bool suspended; bool sdw_waiting_first_unattach;