File Index
Files and directories
Sign in
FILE

tas2764-quirks.h

File preview with syntax highlighting.

linux-6.19.14/sound/soc/codecs/tas2764-quirks.h C
  1/* SPDX-License-Identifier: GPL-2.0-only */
  2#ifndef __TAS2764_QUIRKS__
  3#define __TAS2764_QUIRKS__
  4
  5#include <linux/regmap.h>
  6
  7#include "tas2764.h"
  8
  9/* Bitmask of enabled Apple quirks */
 10#define ENABLED_APPLE_QUIRKS	0x3f
 11
 12/*
 13 * Disable noise gate and flip down reserved bit in NS_CFG0
 14 */
 15#define TAS2764_NOISE_GATE_DISABLE	BIT(0)
 16
 17static const struct reg_sequence tas2764_noise_gate_dis_seq[] = {
 18	REG_SEQ0(TAS2764_REG(0x0, 0x35), 0xb0)
 19};
 20
 21/*
 22 * CONV_VBAT_PVDD_MODE=1
 23 */
 24#define TAS2764_CONV_VBAT_PVDD_MODE	BIT(1)
 25
 26static const struct reg_sequence tas2764_conv_vbat_pvdd_mode_seq[] = {
 27	REG_SEQ0(TAS2764_REG(0x0, 0x6b), 0x41)
 28};
 29
 30/*
 31 * Reset of DAC modulator when DSP is OFF
 32 */
 33#define TAS2764_DMOD_RST		BIT(2)
 34
 35static const struct reg_sequence tas2764_dmod_rst_seq[] = {
 36	REG_SEQ0(TAS2764_REG(0x0, 0x76), 0x0)
 37};
 38
 39/*
 40 * Unknown 0x133/0x137 writes (maybe TDM related)
 41 */
 42#define TAS2764_UNK_SEQ0		BIT(3)
 43
 44static const struct reg_sequence tas2764_unk_seq0[] = {
 45	REG_SEQ0(TAS2764_REG(0x1, 0x33), 0x80),
 46	REG_SEQ0(TAS2764_REG(0x1, 0x37), 0x3a),
 47};
 48
 49/*
 50 * Unknown 0x614 - 0x61f writes
 51 */
 52#define TAS2764_APPLE_UNK_SEQ1		BIT(4)
 53
 54static const struct reg_sequence tas2764_unk_seq1[] = {
 55	REG_SEQ0(TAS2764_REG(0x6, 0x14), 0x0),
 56	REG_SEQ0(TAS2764_REG(0x6, 0x15), 0x13),
 57	REG_SEQ0(TAS2764_REG(0x6, 0x16), 0x52),
 58	REG_SEQ0(TAS2764_REG(0x6, 0x17), 0x0),
 59	REG_SEQ0(TAS2764_REG(0x6, 0x18), 0xe4),
 60	REG_SEQ0(TAS2764_REG(0x6, 0x19), 0xc),
 61	REG_SEQ0(TAS2764_REG(0x6, 0x16), 0xaa),
 62	REG_SEQ0(TAS2764_REG(0x6, 0x1b), 0x0),
 63	REG_SEQ0(TAS2764_REG(0x6, 0x1c), 0x12),
 64	REG_SEQ0(TAS2764_REG(0x6, 0x1d), 0xa0),
 65	REG_SEQ0(TAS2764_REG(0x6, 0x1e), 0xd8),
 66	REG_SEQ0(TAS2764_REG(0x6, 0x1f), 0x0),
 67};
 68
 69/*
 70 * Unknown writes in the 0xfd page (with secondary paging inside)
 71 */
 72#define TAS2764_APPLE_UNK_SEQ2		BIT(5)
 73
 74static const struct reg_sequence tas2764_unk_seq2[] = {
 75	REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0xd),
 76	REG_SEQ0(TAS2764_REG(0xfd, 0x6c), 0x2),
 77	REG_SEQ0(TAS2764_REG(0xfd, 0x6d), 0xf),
 78	REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0x0),
 79};
 80
 81/*
 82 * Disable 'Thermal Threshold 1'
 83 */
 84#define TAS2764_THERMAL_TH1_DISABLE	BIT(6)
 85
 86static const struct reg_sequence tas2764_thermal_th1_dis_seq[] = {
 87	REG_SEQ0(TAS2764_REG(0x1, 0x47), 0x2),
 88};
 89
 90/*
 91 * Imitate Apple's shutdown dance
 92 */
 93#define TAS2764_SHUTDOWN_DANCE		BIT(7)
 94
 95static const struct reg_sequence tas2764_shutdown_dance_init_seq[] = {
 96	/*
 97	 * SDZ_MODE=01 (immediate)
 98	 *
 99	 * We want the shutdown to happen under the influence of
100	 * the magic writes in the 0xfdXX region, so make sure
101	 * the shutdown is immediate and there's no grace period
102	 * followed by the codec part.
103	 */
104	REG_SEQ0(TAS2764_REG(0x0, 0x7), 0x60),
105};
106
107static const struct reg_sequence tas2764_pre_shutdown_seq[] = {
108	REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0xd), /* switch hidden page */
109	REG_SEQ0(TAS2764_REG(0xfd, 0x64), 0x4), /* do write (unknown semantics) */
110	REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0x0), /* switch hidden page back */
111};
112
113static const struct reg_sequence tas2764_post_shutdown_seq[] = {
114	REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0xd),
115	REG_SEQ0(TAS2764_REG(0xfd, 0x64), 0x0), /* revert write from pre sequence */
116	REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0x0),
117};
118
119static int tas2764_do_quirky_pwr_ctrl_change(struct tas2764_priv *tas2764,
120					     unsigned int target)
121{
122	unsigned int curr;
123	int ret;
124
125	curr = snd_soc_component_read_field(tas2764->component,
126					       TAS2764_PWR_CTRL,
127					       TAS2764_PWR_CTRL_MASK);
128
129	if (target == curr)
130		return 0;
131
132	/* Handle power state transition to shutdown */
133	if (target == TAS2764_PWR_CTRL_SHUTDOWN &&
134	   (curr == TAS2764_PWR_CTRL_MUTE || curr == TAS2764_PWR_CTRL_ACTIVE)) {
135		ret = regmap_multi_reg_write(tas2764->regmap, tas2764_pre_shutdown_seq,
136					ARRAY_SIZE(tas2764_pre_shutdown_seq));
137		if (!ret)
138			ret = snd_soc_component_update_bits(tas2764->component,
139							TAS2764_PWR_CTRL,
140							TAS2764_PWR_CTRL_MASK,
141							TAS2764_PWR_CTRL_SHUTDOWN);
142		if (!ret)
143			ret = regmap_multi_reg_write(tas2764->regmap,
144						tas2764_post_shutdown_seq,
145						ARRAY_SIZE(tas2764_post_shutdown_seq));
146	}
147
148	ret = snd_soc_component_update_bits(tas2764->component, TAS2764_PWR_CTRL,
149						    TAS2764_PWR_CTRL_MASK, target);
150
151	return ret;
152}
153
154/*
155 * Via devicetree (TODO):
156 *  - switch from spread spectrum to class-D switching
157 *  - disable edge control
158 *  - set BOP settings (the BOP config bits *and* BOP_SRC)
159 */
160
161/*
162 * Other setup TODOs:
163 *  - DVC ramp rate
164 */
165
166static const struct tas2764_quirk_init_sequence {
167	const struct reg_sequence *seq;
168	int len;
169} tas2764_quirk_init_sequences[] = {
170	{ tas2764_noise_gate_dis_seq, ARRAY_SIZE(tas2764_noise_gate_dis_seq) },
171	{ tas2764_dmod_rst_seq, ARRAY_SIZE(tas2764_dmod_rst_seq) },
172	{ tas2764_conv_vbat_pvdd_mode_seq, ARRAY_SIZE(tas2764_conv_vbat_pvdd_mode_seq) },
173	{ tas2764_unk_seq0, ARRAY_SIZE(tas2764_unk_seq0) },
174	{ tas2764_unk_seq1, ARRAY_SIZE(tas2764_unk_seq1) },
175	{ tas2764_unk_seq2, ARRAY_SIZE(tas2764_unk_seq2) },
176	{ tas2764_thermal_th1_dis_seq, ARRAY_SIZE(tas2764_thermal_th1_dis_seq) },
177	{ tas2764_shutdown_dance_init_seq, ARRAY_SIZE(tas2764_shutdown_dance_init_seq) },
178};
179
180#endif /* __TAS2764_QUIRKS__ */
~/ Read-only file preview.