Skip to content

Commit c3ca445

Browse files
soyersoyertiwai
authored andcommitted
ALSA: hda/tas2781: add TAS2563 support for 14ARB7
The INT8866 belongs to the Lenovo Yoga 7 Gen 7 AMD 14ARB7 laptop. It has two TAS2563 amplifier. Add the PNP ID and calibration functions to handle them. ACPI excerpt: Scope (_SB.I2CD) { Device (TAS) { Name (_HID, "INT8866") // _HID: Hardware ID Name (_UID, Zero) // _UID: Unique ID Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings { Name (RBUF, ResourceTemplate () { I2cSerialBusV2 (0x004C, ControllerInitiated, 0x00061A80, AddressingMode7Bit, "\\_SB.I2CD", 0x00, ResourceConsumer, , Exclusive, ) I2cSerialBusV2 (0x004D, ControllerInitiated, 0x00061A80, AddressingMode7Bit, "\\_SB.I2CD", 0x00, ResourceConsumer, , Exclusive, ) GpioInt (Edge, ActiveLow, SharedAndWake, PullNone, 0x0000, "\\_SB.GPIO", 0x00, ResourceConsumer, , ) { // Pin list 0x0020 } }) Return (RBUF) /* \_SB_.I2CD.TAS_._CRS.RBUF */ } Method (_STA, 0, NotSerialized) // _STA: Status { Return (0x0F) } } } Signed-off-by: Gergo Koteles <soyer@irl.hu> Link: https://lore.kernel.org/r/3b8d4c602e1a46922f53bc9afc8b705d55aa4872.1703891777.git.soyer@irl.hu Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent c021ca7 commit c3ca445

2 files changed

Lines changed: 88 additions & 0 deletions

File tree

include/sound/tas2781.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#define TAS2781_DRV_VER 1
2323
#define SMARTAMP_MODULE_NAME "tas2781"
2424
#define TAS2781_GLOBAL_ADDR 0x40
25+
#define TAS2563_GLOBAL_ADDR 0x48
2526
#define TASDEVICE_RATES (SNDRV_PCM_RATE_44100 |\
2627
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |\
2728
SNDRV_PCM_RATE_88200)

sound/pci/hda/tas2781_hda_i2c.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,24 @@ enum calib_data {
6565
CALIB_MAX
6666
};
6767

68+
#define TAS2563_MAX_CHANNELS 4
69+
70+
#define TAS2563_CAL_POWER TASDEVICE_REG(0, 0x0d, 0x3c)
71+
#define TAS2563_CAL_R0 TASDEVICE_REG(0, 0x0f, 0x34)
72+
#define TAS2563_CAL_INVR0 TASDEVICE_REG(0, 0x0f, 0x40)
73+
#define TAS2563_CAL_R0_LOW TASDEVICE_REG(0, 0x0f, 0x48)
74+
#define TAS2563_CAL_TLIM TASDEVICE_REG(0, 0x10, 0x14)
75+
#define TAS2563_CAL_N 5
76+
#define TAS2563_CAL_DATA_SIZE 4
77+
#define TAS2563_CAL_CH_SIZE 20
78+
#define TAS2563_CAL_ARRAY_SIZE 80
79+
80+
static unsigned int cal_regs[TAS2563_CAL_N] = {
81+
TAS2563_CAL_POWER, TAS2563_CAL_R0, TAS2563_CAL_INVR0,
82+
TAS2563_CAL_R0_LOW, TAS2563_CAL_TLIM,
83+
};
84+
85+
6886
struct tas2781_hda {
6987
struct device *dev;
7088
struct tasdevice_priv *priv;
@@ -404,6 +422,69 @@ static const struct snd_kcontrol_new tas2781_dsp_conf_ctrl = {
404422
.put = tasdevice_config_put,
405423
};
406424

425+
static void tas2563_apply_calib(struct tasdevice_priv *tas_priv)
426+
{
427+
unsigned int data;
428+
int offset = 0;
429+
int ret;
430+
431+
for (int i = 0; i < tas_priv->ndev; i++) {
432+
for (int j = 0; j < TAS2563_CAL_N; ++j) {
433+
data = cpu_to_be32(
434+
*(uint32_t *)&tas_priv->cali_data.data[offset]);
435+
ret = tasdevice_dev_bulk_write(tas_priv, i, cal_regs[j],
436+
(unsigned char *)&data, TAS2563_CAL_DATA_SIZE);
437+
if (ret)
438+
dev_err(tas_priv->dev,
439+
"Error writing calib regs\n");
440+
offset += TAS2563_CAL_DATA_SIZE;
441+
}
442+
}
443+
}
444+
445+
static int tas2563_save_calibration(struct tasdevice_priv *tas_priv)
446+
{
447+
static efi_guid_t efi_guid = EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc,
448+
0x09, 0x43, 0xa3, 0xf4, 0x31, 0x0a, 0x92);
449+
450+
static efi_char16_t *efi_vars[TAS2563_MAX_CHANNELS][TAS2563_CAL_N] = {
451+
{ L"Power_1", L"R0_1", L"InvR0_1", L"R0_Low_1", L"TLim_1" },
452+
{ L"Power_2", L"R0_2", L"InvR0_2", L"R0_Low_2", L"TLim_2" },
453+
{ L"Power_3", L"R0_3", L"InvR0_3", L"R0_Low_3", L"TLim_3" },
454+
{ L"Power_4", L"R0_4", L"InvR0_4", L"R0_Low_4", L"TLim_4" },
455+
};
456+
457+
unsigned long max_size = TAS2563_CAL_DATA_SIZE;
458+
unsigned int offset = 0;
459+
efi_status_t status;
460+
unsigned int attr;
461+
462+
tas_priv->cali_data.data = devm_kzalloc(tas_priv->dev,
463+
TAS2563_CAL_ARRAY_SIZE, GFP_KERNEL);
464+
if (!tas_priv->cali_data.data)
465+
return -ENOMEM;
466+
467+
for (int i = 0; i < tas_priv->ndev; ++i) {
468+
for (int j = 0; j < TAS2563_CAL_N; ++j) {
469+
status = efi.get_variable(efi_vars[i][j],
470+
&efi_guid, &attr, &max_size,
471+
&tas_priv->cali_data.data[offset]);
472+
if (status != EFI_SUCCESS ||
473+
max_size != TAS2563_CAL_DATA_SIZE) {
474+
dev_warn(tas_priv->dev,
475+
"Calibration data read failed %ld\n", status);
476+
return -EINVAL;
477+
}
478+
offset += TAS2563_CAL_DATA_SIZE;
479+
}
480+
}
481+
482+
tas_priv->cali_data.total_sz = offset;
483+
tasdevice_apply_calibration(tas_priv);
484+
485+
return 0;
486+
}
487+
407488
static void tas2781_apply_calib(struct tasdevice_priv *tas_priv)
408489
{
409490
static const unsigned char page_array[CALIB_MAX] = {
@@ -702,6 +783,11 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt)
702783
tas_hda->priv->save_calibration = tas2781_save_calibration;
703784
tas_hda->priv->apply_calibration = tas2781_apply_calib;
704785
tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
786+
} else if (strstr(dev_name(&clt->dev), "INT8866")) {
787+
device_name = "INT8866";
788+
tas_hda->priv->save_calibration = tas2563_save_calibration;
789+
tas_hda->priv->apply_calibration = tas2563_apply_calib;
790+
tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR;
705791
} else
706792
return -ENODEV;
707793

@@ -851,6 +937,7 @@ static const struct i2c_device_id tas2781_hda_i2c_id[] = {
851937

852938
static const struct acpi_device_id tas2781_acpi_hda_match[] = {
853939
{"TIAS2781", 0 },
940+
{"INT8866", 0 },
854941
{}
855942
};
856943
MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match);

0 commit comments

Comments
 (0)