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 17 static 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 26 static 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 35 static 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 44 static 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 54 static 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 74 static 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 86 static 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 95 static 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 107 static 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 113 static 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 119 static 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 166 static 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__ */ 181