From patchwork Sat Apr 5 00:12:45 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: James Calligeros X-Patchwork-Id: 14039041 Received: from mail-pj1-f41.google.com (mail-pj1-f41.google.com [209.85.216.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DE7A732C8B; Sat, 5 Apr 2025 00:14:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743812046; cv=none; b=KTGyRKQt1utE0Ig943uwvWKHiJX1hmNjbdHgqA7h+JSQZVTtq9/+74ZQbS2ppQgVJVLP8WkXPQ9quDDLx8afpGYkBZIQoY+Odfm/Wjpc2tB/8VA5REcySUufJODdFClBloq3DSN8RTbkeRFoP5JFwxh2gLL0HjdgXiI18Kpw4Tk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743812046; c=relaxed/simple; bh=s6KM1QAANWnrCslUisPm5f5o8wdQp3/HY7jThNWGnME=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=XvG6oJgcNnUb6RUKoq8ef7BPgwmoYE/ac9gmzl2gRr3CxmTJBbimfQ02UDIjthav5IVibmzj4i1ZjBBqZ/XqcDUqYVWFWED+6r4T0/WdjUSRZLffHm7fqvg/5pB947V83JfRcnQK7C/XHZKcZON6fcqh/ovN9UZt94jS5xSTDLM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=EAWb1wHN; arc=none smtp.client-ip=209.85.216.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="EAWb1wHN" Received: by mail-pj1-f41.google.com with SMTP id 98e67ed59e1d1-2ff64550991so2040365a91.0; Fri, 04 Apr 2025 17:14:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1743812044; x=1744416844; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=hub/Un41YMQsR7dUpdo7EJdzYgRTMgzcDJ2xtzPcSzo=; b=EAWb1wHNredyO5Ah/nd3WVcc3zH6qgDsLZnuMyWmq5EnDH6dJD2LsbrIYOk83qBHPf TmKeWICY7InHtUMja0L8CNREppW6fWznJXWVpleZUHmg4FkQ8us1zc1vDuevkBDpQVmo sIv1e/d6laTSEZD/o5w7pAXiVu9prDEuLe8Euis4rrkH7OY5yN8efF5qrAK5To24Qn/F rbyM2qufZi2eIePC5EuLPQB6RxpWkq/EQKX+G7F+tdMj94E9CrXel5yV4vSRZ/SIvVQ4 xaxa7FIRy4VmZWO+RzKvH6PUXzzot28Qk3Pa6gCzw6r/6dQ2OcsnDD5yCL1mjoEYO0mY spMw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1743812044; x=1744416844; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=hub/Un41YMQsR7dUpdo7EJdzYgRTMgzcDJ2xtzPcSzo=; b=aHk61IXg31y6+7ha9xULrFHlK5KkVougB9u5I4y/WMk38dQyQ8NnTBzMkYHstAF2g1 4AaQZLxVYNimPEWb2vfP1ALZ11xcznQl4YSubH6WnhJ2UOhfEGcgyMIXwduJASZLkvIN Q7OFT42x+ALkPWAwrtCA/0j00pwUD/RMqmqJp06pUbDVh7tGUUfgZ4EHnCsM3Mjbs4fz s+m6pGL+TuEeOD9rftZ5ehTDfyxKZOdTFYkLUAs93XeFfsNkEIaSQLrXR+vxaAwgVNd5 dOD/JrPJ3kl+qB2RPSZx+cP243iABPalVE2cETxbcJycm71e093kMJ1rfe9FDY3eiYXH 4eDw== X-Forwarded-Encrypted: i=1; AJvYcCUaaQt3dZ6VV/A8EIYJFhvtwV1IDwBpoNkW6qresyH87Ys65sEUEGL1gI9mnOcOOPsa6BKq9t33bi7UIrE=@vger.kernel.org, AJvYcCVUyMyenyy+JzUcNO1HKSGTzHvn5hn4fG/BP4cqwmxwqvfPqjJTpJGyv6Y/N3JKE9JSpLDTyNsUvR9NPpY7@vger.kernel.org, AJvYcCWUZwZhlJ6IQgNtyzhNuzB0BHYSNuvj1dQxt6covSzk8jz7pGCzq+efHIFmSPxY8s7VVHNUXqbW0voe@vger.kernel.org, AJvYcCXo8uF8wfunB0OyAp24zwkp2XXCa+wefDd+b0xzXSHIZkbXz8vAnKs0Nv2fMVusm+9jVXgVqt/IKREpFuA=@vger.kernel.org X-Gm-Message-State: AOJu0YzZqerzIEWxVInMKac3MjFIEkpydFmhKT2awYy4OS1XoJGIz46H 11zKT4UxNp7FAeHwjMAbhsDZUTb0Ec03FqmMHclbSgRBOqXlPecVLSiO+W7j X-Gm-Gg: ASbGncs6D7Czlf8CQ21T6e32KDUT6UM/1e2Lp9BERe4WJCwxZl/eiNy4zdn7BcWok9k fGajdzA079AXYVQjlwjYY089zP9aWAieUHYNnZpAY8IhjVTqLC/0hWNiVKhytoGlo+7n+uX5X3A WXUp7X+X7StldHQb4R9hUeUHD25Zt38VjAJa8JilyVBA5inwcAU1Ku5IwgSfgsXpBet20VM02XJ KEp7Mq6zwXMOQh5WcOOb4fPRYgJvlIKBJ6Cr7wj3cg8dhHBnBwxPE1/B5Jai9MreuECvpX3a86W rteM0kqI7vlC6znapq4gXjQ+6+JBYM15MNqPnHc4+SkPaY9zx67OWyIHDqM56mMTR0NuC6I/gfY nW4wWTmZQYDT42k12etqqZPSnKo9hl5r+dMxCyLE= X-Google-Smtp-Source: AGHT+IFQGhk4XA8B7A1Ts6D+xYDlFxRXw42UR6BIqVhV1Q2hGwHS/VR/cM81zdP6bPP11UYrO0KXdQ== X-Received: by 2002:a17:90a:e18f:b0:2f1:2fa5:1924 with SMTP id 98e67ed59e1d1-306a62138a0mr4869142a91.26.1743812043871; Fri, 04 Apr 2025 17:14:03 -0700 (PDT) Received: from [192.168.2.3] (2403-580a-80ed-0-4835-5a07-49e7-f115.ip6.aussiebb.net. [2403:580a:80ed:0:4835:5a07:49e7:f115]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-3057cb5d665sm4327855a91.30.2025.04.04.17.13.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Apr 2025 17:14:03 -0700 (PDT) From: James Calligeros Date: Sat, 05 Apr 2025 10:12:45 +1000 Subject: [PATCH v4 08/10] ASoC: tas2764: Apply Apple quirks Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250405-apple-codec-changes-v4-8-d007e46ce4a2@gmail.com> References: <20250405-apple-codec-changes-v4-0-d007e46ce4a2@gmail.com> In-Reply-To: <20250405-apple-codec-changes-v4-0-d007e46ce4a2@gmail.com> To: Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shenghao Ding , Kevin Lu , Baojun Xu , Dan Murphy , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Shi Fu , Jean Delvare , Guenter Roeck Cc: Alyssa Rosenzweig , =?utf-8?q?Martin_Povi=C5=A1er?= , Hector Martin , linux-sound@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, asahi@lists.linux.dev, linux-hwmon@vger.kernel.org, Neal Gompa , James Calligeros X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=9009; i=jcalligeros99@gmail.com; h=from:subject:message-id; bh=cUqY8I/Yl0eZkFbXiF/e5Zn9O7qbT39FuuAhn86zVgg=; b=owGbwMvMwCV2xczoYuD3ygTG02pJDOkfStskE+4VZWSlCrnfPjK3/VVT84P70tF96t+kF8Z5C PRKJf/qKGVhEONikBVTZNnQJOQx24jtZr9I5V6YOaxMIEMYuDgFYCLxzAz/FOZ9DD9nPtViUVix 6e7TW05uOzYj69okgStBGdarTupONWL4X7h05+Xopr0Tfs9duCQsbIvA41mM3/9sWpYXo3jTWjr yFxMA X-Developer-Key: i=jcalligeros99@gmail.com; a=openpgp; fpr=B08212489B3206D98F1479BDD43632D151F77960 From: Martin Povišer Apple's SN012776 driver has some peculiar aspects to its behavior that are suspected to work around issues in the codec part. Add a module parameter for enabling individual quirks that should be imitated after the Apple driver. Setting some of these by default seems to be required. For example, setting 0xf fixes an issue with transient overcurrent errors which can crash the chip until the next system reboot. To be safe, let's enable all of them by default. Reviewed-by: Neal Gompa Co-developed-by: Hector Martin Signed-off-by: Hector Martin Signed-off-by: Martin Povišer Co-developed-by: James Calligeros Signed-off-by: James Calligeros --- sound/soc/codecs/tas2764-quirks.h | 180 +++++++++++++++++++++++++ sound/soc/codecs/tas2764.c | 39 ++++++ 2 files changed, 219 insertions(+) diff --git a/sound/soc/codecs/tas2764-quirks.h b/sound/soc/codecs/tas2764-quirks.h new file mode 100644 index 0000000000000000000000000000000000000000..7a62b3ba5b40b3f06fc1ebeb590d9c32b1b2c7d3 --- /dev/null +++ b/sound/soc/codecs/tas2764-quirks.h @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __TAS2764_QUIRKS__ +#define __TAS2764_QUIRKS__ + +#include + +#include "tas2764.h" + +/* Bitmask of enabled Apple quirks */ +#define ENABLED_APPLE_QUIRKS 0x3f + +/* + * Disable noise gate and flip down reserved bit in NS_CFG0 + */ +#define TAS2764_NOISE_GATE_DISABLE BIT(0) + +static const struct reg_sequence tas2764_noise_gate_dis_seq[] = { + REG_SEQ0(TAS2764_REG(0x0, 0x35), 0xb0) +}; + +/* + * CONV_VBAT_PVDD_MODE=1 + */ +#define TAS2764_CONV_VBAT_PVDD_MODE BIT(1) + +static const struct reg_sequence tas2764_conv_vbat_pvdd_mode_seq[] = { + REG_SEQ0(TAS2764_REG(0x0, 0x6b), 0x41) +}; + +/* + * Reset of DAC modulator when DSP is OFF + */ +#define TAS2764_DMOD_RST BIT(2) + +static const struct reg_sequence tas2764_dmod_rst_seq[] = { + REG_SEQ0(TAS2764_REG(0x0, 0x76), 0x0) +}; + +/* + * Unknown 0x133/0x137 writes (maybe TDM related) + */ +#define TAS2764_UNK_SEQ0 BIT(3) + +static const struct reg_sequence tas2764_unk_seq0[] = { + REG_SEQ0(TAS2764_REG(0x1, 0x33), 0x80), + REG_SEQ0(TAS2764_REG(0x1, 0x37), 0x3a), +}; + +/* + * Unknown 0x614 - 0x61f writes + */ +#define TAS2764_APPLE_UNK_SEQ1 BIT(4) + +static const struct reg_sequence tas2764_unk_seq1[] = { + REG_SEQ0(TAS2764_REG(0x6, 0x14), 0x0), + REG_SEQ0(TAS2764_REG(0x6, 0x15), 0x13), + REG_SEQ0(TAS2764_REG(0x6, 0x16), 0x52), + REG_SEQ0(TAS2764_REG(0x6, 0x17), 0x0), + REG_SEQ0(TAS2764_REG(0x6, 0x18), 0xe4), + REG_SEQ0(TAS2764_REG(0x6, 0x19), 0xc), + REG_SEQ0(TAS2764_REG(0x6, 0x16), 0xaa), + REG_SEQ0(TAS2764_REG(0x6, 0x1b), 0x0), + REG_SEQ0(TAS2764_REG(0x6, 0x1c), 0x12), + REG_SEQ0(TAS2764_REG(0x6, 0x1d), 0xa0), + REG_SEQ0(TAS2764_REG(0x6, 0x1e), 0xd8), + REG_SEQ0(TAS2764_REG(0x6, 0x1f), 0x0), +}; + +/* + * Unknown writes in the 0xfd page (with secondary paging inside) + */ +#define TAS2764_APPLE_UNK_SEQ2 BIT(5) + +static const struct reg_sequence tas2764_unk_seq2[] = { + REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0xd), + REG_SEQ0(TAS2764_REG(0xfd, 0x6c), 0x2), + REG_SEQ0(TAS2764_REG(0xfd, 0x6d), 0xf), + REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0x0), +}; + +/* + * Disable 'Thermal Threshold 1' + */ +#define TAS2764_THERMAL_TH1_DISABLE BIT(6) + +static const struct reg_sequence tas2764_thermal_th1_dis_seq[] = { + REG_SEQ0(TAS2764_REG(0x1, 0x47), 0x2), +}; + +/* + * Imitate Apple's shutdown dance + */ +#define TAS2764_SHUTDOWN_DANCE BIT(7) + +static const struct reg_sequence tas2764_shutdown_dance_init_seq[] = { + /* + * SDZ_MODE=01 (immediate) + * + * We want the shutdown to happen under the influence of + * the magic writes in the 0xfdXX region, so make sure + * the shutdown is immediate and there's no grace period + * followed by the codec part. + */ + REG_SEQ0(TAS2764_REG(0x0, 0x7), 0x60), +}; + +static const struct reg_sequence tas2764_pre_shutdown_seq[] = { + REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0xd), /* switch hidden page */ + REG_SEQ0(TAS2764_REG(0xfd, 0x64), 0x4), /* do write (unknown semantics) */ + REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0x0), /* switch hidden page back */ +}; + +static const struct reg_sequence tas2764_post_shutdown_seq[] = { + REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0xd), + REG_SEQ0(TAS2764_REG(0xfd, 0x64), 0x0), /* revert write from pre sequence */ + REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0x0), +}; + +static int tas2764_do_quirky_pwr_ctrl_change(struct tas2764_priv *tas2764, + unsigned int target) +{ + unsigned int curr; + int ret; + + curr = snd_soc_component_read_field(tas2764->component, + TAS2764_PWR_CTRL, + TAS2764_PWR_CTRL_MASK); + + if (target == curr) + return 0; + + /* Handle power state transition to shutdown */ + if (target == TAS2764_PWR_CTRL_SHUTDOWN && + (curr == TAS2764_PWR_CTRL_MUTE || curr == TAS2764_PWR_CTRL_ACTIVE)) { + ret = regmap_multi_reg_write(tas2764->regmap, tas2764_pre_shutdown_seq, + ARRAY_SIZE(tas2764_pre_shutdown_seq)); + if (!ret) + ret = snd_soc_component_update_bits(tas2764->component, + TAS2764_PWR_CTRL, + TAS2764_PWR_CTRL_MASK, + TAS2764_PWR_CTRL_SHUTDOWN); + if (!ret) + ret = regmap_multi_reg_write(tas2764->regmap, + tas2764_post_shutdown_seq, + ARRAY_SIZE(tas2764_post_shutdown_seq)); + } + + ret = snd_soc_component_update_bits(tas2764->component, TAS2764_PWR_CTRL, + TAS2764_PWR_CTRL_MASK, target); + + return ret; +} + +/* + * Via devicetree (TODO): + * - switch from spread spectrum to class-D switching + * - disable edge control + * - set BOP settings (the BOP config bits *and* BOP_SRC) + */ + +/* + * Other setup TODOs: + * - DVC ramp rate + */ + +static const struct tas2764_quirk_init_sequence { + const struct reg_sequence *seq; + int len; +} tas2764_quirk_init_sequences[] = { + { tas2764_noise_gate_dis_seq, ARRAY_SIZE(tas2764_noise_gate_dis_seq) }, + { tas2764_dmod_rst_seq, ARRAY_SIZE(tas2764_dmod_rst_seq) }, + { tas2764_conv_vbat_pvdd_mode_seq, ARRAY_SIZE(tas2764_conv_vbat_pvdd_mode_seq) }, + { tas2764_unk_seq0, ARRAY_SIZE(tas2764_unk_seq0) }, + { tas2764_unk_seq1, ARRAY_SIZE(tas2764_unk_seq1) }, + { tas2764_unk_seq2, ARRAY_SIZE(tas2764_unk_seq2) }, + { tas2764_thermal_th1_dis_seq, ARRAY_SIZE(tas2764_thermal_th1_dis_seq) }, + { tas2764_shutdown_dance_init_seq, ARRAY_SIZE(tas2764_shutdown_dance_init_seq) }, +}; + +#endif /* __TAS2764_QUIRKS__ */ diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c index c55c6e4ea1e2ce0051e43120a71e229238204fd5..e45b34fe4ffd4ffb902e33783e9655e858ce5bb1 100644 --- a/sound/soc/codecs/tas2764.c +++ b/sound/soc/codecs/tas2764.c @@ -45,6 +45,8 @@ struct tas2764_priv { bool unmuted; }; +#include "tas2764-quirks.h" + static const char *tas2764_int_ltch0_msgs[8] = { "fault: over temperature", /* INT_LTCH0 & BIT(0) */ "fault: over current", @@ -122,6 +124,9 @@ static int tas2764_update_pwr_ctrl(struct tas2764_priv *tas2764) else val = TAS2764_PWR_CTRL_SHUTDOWN; + if (ENABLED_APPLE_QUIRKS & TAS2764_SHUTDOWN_DANCE) + return tas2764_do_quirky_pwr_ctrl_change(tas2764, val); + ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, TAS2764_PWR_CTRL_MASK, val); if (ret < 0) @@ -587,6 +592,30 @@ static uint8_t sn012776_bop_presets[] = { static const struct regmap_config tas2764_i2c_regmap; +static int tas2764_apply_init_quirks(struct tas2764_priv *tas2764) +{ + int ret, i; + + for (i = 0; i < ARRAY_SIZE(tas2764_quirk_init_sequences); i++) { + const struct tas2764_quirk_init_sequence *init_seq = + &tas2764_quirk_init_sequences[i]; + + if (!init_seq->seq) + continue; + + if (!(BIT(i) & ENABLED_APPLE_QUIRKS)) + continue; + + ret = regmap_multi_reg_write(tas2764->regmap, init_seq->seq, + init_seq->len); + + if (ret < 0) + return ret; + } + + return 0; +} + static int tas2764_codec_probe(struct snd_soc_component *component) { struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); @@ -656,6 +685,13 @@ static int tas2764_codec_probe(struct snd_soc_component *component) if (ret < 0) return ret; } + + /* Apply all enabled Apple quirks */ + ret = tas2764_apply_init_quirks(tas2764); + + if (ret < 0) + return ret; + break; default: break; @@ -740,6 +776,9 @@ static bool tas2764_volatile_register(struct device *dev, unsigned int reg) case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4: case TAS2764_INT_CLK_CFG: return true; + case TAS2764_REG(0xf0, 0x0) ... TAS2764_REG(0xff, 0x0): + /* TI's undocumented registers for the application of quirks */ + return true; default: return false; }