Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

TAS2764 fixes/extensions

Merge series from Martin Povišer <povik+lin@cutebit.org>:

First three patches are fixes analogical to those recently done to
the TAS2770 driver.
Link: https://lore.kernel.org/asahi/20220808141246.5749-1-povik+lin@cutebit.org/T/#t

The latter two add IRQ handler to log faults and expose a new control.

+152 -52
+129 -52
sound/soc/codecs/tas2764.c
··· 31 31 struct gpio_desc *sdz_gpio; 32 32 struct regmap *regmap; 33 33 struct device *dev; 34 + int irq; 34 35 35 36 int v_sense_slot; 36 37 int i_sense_slot; 38 + 39 + bool dac_powered; 40 + bool unmuted; 37 41 }; 42 + 43 + static const char *tas2764_int_ltch0_msgs[8] = { 44 + "fault: over temperature", /* INT_LTCH0 & BIT(0) */ 45 + "fault: over current", 46 + "fault: bad TDM clock", 47 + "limiter active", 48 + "fault: PVDD below limiter inflection point", 49 + "fault: limiter max attenuation", 50 + "fault: BOP infinite hold", 51 + "fault: BOP mute", /* INT_LTCH0 & BIT(7) */ 52 + }; 53 + 54 + static const unsigned int tas2764_int_readout_regs[6] = { 55 + TAS2764_INT_LTCH0, 56 + TAS2764_INT_LTCH1, 57 + TAS2764_INT_LTCH1_0, 58 + TAS2764_INT_LTCH2, 59 + TAS2764_INT_LTCH3, 60 + TAS2764_INT_LTCH4, 61 + }; 62 + 63 + static irqreturn_t tas2764_irq(int irq, void *data) 64 + { 65 + struct tas2764_priv *tas2764 = data; 66 + u8 latched[6] = {0, 0, 0, 0, 0, 0}; 67 + int ret = IRQ_NONE; 68 + int i; 69 + 70 + for (i = 0; i < ARRAY_SIZE(latched); i++) 71 + latched[i] = snd_soc_component_read(tas2764->component, 72 + tas2764_int_readout_regs[i]); 73 + 74 + for (i = 0; i < 8; i++) { 75 + if (latched[0] & BIT(i)) { 76 + dev_crit_ratelimited(tas2764->dev, "%s\n", 77 + tas2764_int_ltch0_msgs[i]); 78 + ret = IRQ_HANDLED; 79 + } 80 + } 81 + 82 + if (latched[0]) { 83 + dev_err_ratelimited(tas2764->dev, "other context to the fault: %02x,%02x,%02x,%02x,%02x", 84 + latched[1], latched[2], latched[3], latched[4], latched[5]); 85 + snd_soc_component_update_bits(tas2764->component, 86 + TAS2764_INT_CLK_CFG, 87 + TAS2764_INT_CLK_CFG_IRQZ_CLR, 88 + TAS2764_INT_CLK_CFG_IRQZ_CLR); 89 + } 90 + 91 + return ret; 92 + } 38 93 39 94 static void tas2764_reset(struct tas2764_priv *tas2764) 40 95 { ··· 105 50 usleep_range(1000, 2000); 106 51 } 107 52 108 - static int tas2764_set_bias_level(struct snd_soc_component *component, 109 - enum snd_soc_bias_level level) 53 + static int tas2764_update_pwr_ctrl(struct tas2764_priv *tas2764) 110 54 { 111 - struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); 55 + struct snd_soc_component *component = tas2764->component; 56 + unsigned int val; 57 + int ret; 112 58 113 - switch (level) { 114 - case SND_SOC_BIAS_ON: 115 - snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, 116 - TAS2764_PWR_CTRL_MASK, 117 - TAS2764_PWR_CTRL_ACTIVE); 118 - break; 119 - case SND_SOC_BIAS_STANDBY: 120 - case SND_SOC_BIAS_PREPARE: 121 - snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, 122 - TAS2764_PWR_CTRL_MASK, 123 - TAS2764_PWR_CTRL_MUTE); 124 - break; 125 - case SND_SOC_BIAS_OFF: 126 - snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, 127 - TAS2764_PWR_CTRL_MASK, 128 - TAS2764_PWR_CTRL_SHUTDOWN); 129 - break; 59 + if (tas2764->dac_powered) 60 + val = tas2764->unmuted ? 61 + TAS2764_PWR_CTRL_ACTIVE : TAS2764_PWR_CTRL_MUTE; 62 + else 63 + val = TAS2764_PWR_CTRL_SHUTDOWN; 130 64 131 - default: 132 - dev_err(tas2764->dev, 133 - "wrong power level setting %d\n", level); 134 - return -EINVAL; 135 - } 65 + ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, 66 + TAS2764_PWR_CTRL_MASK, val); 67 + if (ret < 0) 68 + return ret; 136 69 137 70 return 0; 138 71 } ··· 157 114 usleep_range(1000, 2000); 158 115 } 159 116 160 - ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, 161 - TAS2764_PWR_CTRL_MASK, 162 - TAS2764_PWR_CTRL_ACTIVE); 117 + ret = tas2764_update_pwr_ctrl(tas2764); 163 118 164 119 if (ret < 0) 165 120 return ret; ··· 191 150 192 151 switch (event) { 193 152 case SND_SOC_DAPM_POST_PMU: 194 - ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, 195 - TAS2764_PWR_CTRL_MASK, 196 - TAS2764_PWR_CTRL_MUTE); 153 + tas2764->dac_powered = true; 154 + ret = tas2764_update_pwr_ctrl(tas2764); 197 155 break; 198 156 case SND_SOC_DAPM_PRE_PMD: 199 - ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, 200 - TAS2764_PWR_CTRL_MASK, 201 - TAS2764_PWR_CTRL_SHUTDOWN); 157 + tas2764->dac_powered = false; 158 + ret = tas2764_update_pwr_ctrl(tas2764); 202 159 break; 203 160 default: 204 161 dev_err(tas2764->dev, "Unsupported event\n"); ··· 241 202 242 203 static int tas2764_mute(struct snd_soc_dai *dai, int mute, int direction) 243 204 { 244 - struct snd_soc_component *component = dai->component; 245 - int ret; 205 + struct tas2764_priv *tas2764 = 206 + snd_soc_component_get_drvdata(dai->component); 246 207 247 - ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, 248 - TAS2764_PWR_CTRL_MASK, 249 - mute ? TAS2764_PWR_CTRL_MUTE : 0); 250 - 251 - if (ret < 0) 252 - return ret; 253 - 254 - return 0; 208 + tas2764->unmuted = !mute; 209 + return tas2764_update_pwr_ctrl(tas2764); 255 210 } 256 211 257 212 static int tas2764_set_bitwidth(struct tas2764_priv *tas2764, int bitwidth) ··· 518 485 .id = 0, 519 486 .playback = { 520 487 .stream_name = "ASI1 Playback", 521 - .channels_min = 2, 488 + .channels_min = 1, 522 489 .channels_max = 2, 523 490 .rates = TAS2764_RATES, 524 491 .formats = TAS2764_FORMATS, ··· 549 516 550 517 tas2764_reset(tas2764); 551 518 519 + if (tas2764->irq) { 520 + ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK0, 0xff); 521 + if (ret < 0) 522 + return ret; 523 + 524 + ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK1, 0xff); 525 + if (ret < 0) 526 + return ret; 527 + 528 + ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK2, 0xff); 529 + if (ret < 0) 530 + return ret; 531 + 532 + ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK3, 0xff); 533 + if (ret < 0) 534 + return ret; 535 + 536 + ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK4, 0xff); 537 + if (ret < 0) 538 + return ret; 539 + 540 + ret = devm_request_threaded_irq(tas2764->dev, tas2764->irq, NULL, tas2764_irq, 541 + IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW, 542 + "tas2764", tas2764); 543 + if (ret) 544 + dev_warn(tas2764->dev, "failed to request IRQ: %d\n", ret); 545 + } 546 + 552 547 ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG5, 553 548 TAS2764_TDM_CFG5_VSNS_ENABLE, 0); 554 549 if (ret < 0) ··· 587 526 if (ret < 0) 588 527 return ret; 589 528 590 - ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, 591 - TAS2764_PWR_CTRL_MASK, 592 - TAS2764_PWR_CTRL_MUTE); 593 - if (ret < 0) 594 - return ret; 595 - 596 529 return 0; 597 530 } 598 531 599 532 static DECLARE_TLV_DB_SCALE(tas2764_digital_tlv, 1100, 50, 0); 600 533 static DECLARE_TLV_DB_SCALE(tas2764_playback_volume, -10050, 50, 1); 601 534 535 + static const char * const tas2764_hpf_texts[] = { 536 + "Disabled", "2 Hz", "50 Hz", "100 Hz", "200 Hz", 537 + "400 Hz", "800 Hz" 538 + }; 539 + 540 + static SOC_ENUM_SINGLE_DECL( 541 + tas2764_hpf_enum, TAS2764_DC_BLK0, 542 + TAS2764_DC_BLK0_HPF_FREQ_PB_SHIFT, tas2764_hpf_texts); 543 + 602 544 static const struct snd_kcontrol_new tas2764_snd_controls[] = { 603 545 SOC_SINGLE_TLV("Speaker Volume", TAS2764_DVC, 0, 604 546 TAS2764_DVC_MAX, 1, tas2764_playback_volume), 605 547 SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 1, 0x14, 0, 606 548 tas2764_digital_tlv), 549 + SOC_ENUM("HPF Corner Frequency", tas2764_hpf_enum), 607 550 }; 608 551 609 552 static const struct snd_soc_component_driver soc_component_driver_tas2764 = { 610 553 .probe = tas2764_codec_probe, 611 554 .suspend = tas2764_codec_suspend, 612 555 .resume = tas2764_codec_resume, 613 - .set_bias_level = tas2764_set_bias_level, 614 556 .controls = tas2764_snd_controls, 615 557 .num_controls = ARRAY_SIZE(tas2764_snd_controls), 616 558 .dapm_widgets = tas2764_dapm_widgets, ··· 649 585 }, 650 586 }; 651 587 588 + static bool tas2764_volatile_register(struct device *dev, unsigned int reg) 589 + { 590 + switch (reg) { 591 + case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4: 592 + case TAS2764_INT_CLK_CFG: 593 + return true; 594 + default: 595 + return false; 596 + } 597 + } 598 + 652 599 static const struct regmap_config tas2764_i2c_regmap = { 653 600 .reg_bits = 8, 654 601 .val_bits = 8, 602 + .volatile_reg = tas2764_volatile_register, 655 603 .reg_defaults = tas2764_reg_defaults, 656 604 .num_reg_defaults = ARRAY_SIZE(tas2764_reg_defaults), 657 605 .cache_type = REGCACHE_RBTREE, ··· 717 641 return -ENOMEM; 718 642 719 643 tas2764->dev = &client->dev; 644 + tas2764->irq = client->irq; 720 645 i2c_set_clientdata(client, tas2764); 721 646 dev_set_drvdata(&client->dev, tas2764); 722 647
+23
sound/soc/codecs/tas2764.h
··· 33 33 #define TAS2764_VSENSE_POWER_EN 3 34 34 #define TAS2764_ISENSE_POWER_EN 4 35 35 36 + /* DC Blocker Control */ 37 + #define TAS2764_DC_BLK0 TAS2764_REG(0x0, 0x04) 38 + #define TAS2764_DC_BLK0_HPF_FREQ_PB_SHIFT 0 39 + 36 40 /* Digital Volume Control */ 37 41 #define TAS2764_DVC TAS2764_REG(0X0, 0x1a) 38 42 #define TAS2764_DVC_MAX 0xc9 ··· 90 86 #define TAS2764_TDM_CFG6_ISNS_MASK BIT(6) 91 87 #define TAS2764_TDM_CFG6_ISNS_ENABLE BIT(6) 92 88 #define TAS2764_TDM_CFG6_50_MASK GENMASK(5, 0) 89 + 90 + /* Interrupt Masks */ 91 + #define TAS2764_INT_MASK0 TAS2764_REG(0x0, 0x3b) 92 + #define TAS2764_INT_MASK1 TAS2764_REG(0x0, 0x3c) 93 + #define TAS2764_INT_MASK2 TAS2764_REG(0x0, 0x40) 94 + #define TAS2764_INT_MASK3 TAS2764_REG(0x0, 0x41) 95 + #define TAS2764_INT_MASK4 TAS2764_REG(0x0, 0x3d) 96 + 97 + /* Latched Fault Registers */ 98 + #define TAS2764_INT_LTCH0 TAS2764_REG(0x0, 0x49) 99 + #define TAS2764_INT_LTCH1 TAS2764_REG(0x0, 0x4a) 100 + #define TAS2764_INT_LTCH1_0 TAS2764_REG(0x0, 0x4b) 101 + #define TAS2764_INT_LTCH2 TAS2764_REG(0x0, 0x4f) 102 + #define TAS2764_INT_LTCH3 TAS2764_REG(0x0, 0x50) 103 + #define TAS2764_INT_LTCH4 TAS2764_REG(0x0, 0x51) 104 + 105 + /* Clock/IRQ Settings */ 106 + #define TAS2764_INT_CLK_CFG TAS2764_REG(0x0, 0x5c) 107 + #define TAS2764_INT_CLK_CFG_IRQZ_CLR BIT(2) 93 108 94 109 #endif /* __TAS2764__ */