adev = acpi_dev_get_first_match_dev(hid, NULL, -1); if (!adev) {
dev_err(p->dev, "Failed to find an ACPI device for %s\n", hid); return -ENODEV;
}
physdev = get_device(acpi_get_first_physical_node(adev));
ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p); if (ret < 0) {
dev_err(p->dev, "Failed to get ACPI resource.\n"); goto err;
}
sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); if (IS_ERR(sub)) { /* No subsys id in older tas2563 projects. */ if (!strncmp(hid, "INT8866", sizeof("INT8866"))) goto end_2563;
dev_err(p->dev, "Failed to get SUBSYS ID.\n");
ret = PTR_ERR(sub); goto err;
} /* Speaker id was needed for ASUS projects. */
ret = kstrtou32(sub, 16, &subid); if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) {
ret = devm_acpi_dev_add_driver_gpios(p->dev,
tas2781_speaker_id_gpios); if (ret < 0)
dev_err(p->dev, "Failed to add driver gpio %d.\n",
ret);
p->speaker_id = devm_gpiod_get(p->dev, "speakerid", GPIOD_IN); if (IS_ERR(p->speaker_id)) {
dev_err(p->dev, "Failed to get Speaker id.\n");
ret = PTR_ERR(p->speaker_id); goto err;
}
} else {
p->speaker_id = NULL;
}
/* extra byte for each device is the device number */
cd->total_sz = (cd->cali_dat_sz_per_dev + 1) * p->ndev;
data = cd->data = devm_kzalloc(p->dev, cd->total_sz,
GFP_KERNEL); if (!data) return -ENOMEM;
for (i = 0; i < p->ndev; ++i) {
data[offset] = i;
offset++; for (j = 0; j < TASDEV_CALIB_N; ++j) { /* EFI name for calibration started with 1, not 0 */
ret = snprintf(var8, sizeof(var8), vars[j], i + 1); if (ret < 0 || ret >= sizeof(var8) - 1) {
dev_err(p->dev, "%s: Read %s failed\n",
__func__, var8); return -EINVAL;
} /* * Our variable names are ASCII by construction, but * EFI names are wide chars. Convert and zero-pad.
*/
memset(efi_name, 0, sizeof(efi_name)); for (k = 0; k < sizeof(var8) && var8[k]; k++)
efi_name[k] = var8[k];
status = efi.get_variable(efi_name,
&efi_guid, &attr, &max_size,
&data[offset]); if (status != EFI_SUCCESS ||
max_size != TAS2563_CAL_DATA_SIZE) {
dev_warn(p->dev, "Dev %d: Caldat[%d] read failed %ld\n",
i, j, status); return -EINVAL;
}
bedata = cpu_to_be32(*(uint32_t *)&data[offset]);
memcpy(&data[offset], &bedata, sizeof(bedata));
offset += TAS2563_CAL_DATA_SIZE;
}
}
if (cd->total_sz != offset) {
dev_err(p->dev, "%s: tot_size(%lu) and offset(%u) dismatch\n",
__func__, cd->total_sz, offset); return -EINVAL;
}
/* * TAS2781_FMWLIB supports two solutions of calibrated data. One is * from the driver itself: driver reads the calibrated files directly * during probe; The other from user space: during init of audio hal, * the audio hal will pass the calibrated data via kcontrol interface. * Driver will store this data in "struct calidata" for use. For hda * device, calibrated data are usunally saved into UEFI. So Hda side * codec driver use the mixture of these two solutions, driver reads * the data from UEFI, then store this data in "struct calidata" for * use.
*/
p->is_user_space_calidata = true;
tasdevice_dsp_remove(tas_priv);
tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; if (tas_priv->speaker_id != NULL) { // Speaker id need to be checked for ASUS only.
spk_id = gpiod_get_value(tas_priv->speaker_id); if (spk_id < 0) { // Speaker id is not valid, use default.
dev_dbg(tas_priv->dev, "Wrong spk_id = %d\n", spk_id);
spk_id = 0;
}
snprintf(tas_priv->coef_binaryname, sizeof(tas_priv->coef_binaryname), "TAS2XXX%04X%d.bin",
lower_16_bits(codec->core.subsystem_id),
spk_id);
} else {
snprintf(tas_priv->coef_binaryname, sizeof(tas_priv->coef_binaryname), "TAS2XXX%04X.bin",
lower_16_bits(codec->core.subsystem_id));
}
ret = tasdevice_dsp_parser(tas_priv); if (ret) {
dev_err(tas_priv->dev, "dspfw load %s error\n",
tas_priv->coef_binaryname);
tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; return;
}
tasdev_add_kcontrols(tas_priv, &tas_hda->dsp_prog_ctl, codec,
&tasdevice_dsp_prog_ctrl, 1);
tasdev_add_kcontrols(tas_priv, &tas_hda->dsp_conf_ctl, codec,
&tasdevice_dsp_conf_ctrl, 1);
tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
tasdevice_prmg_load(tas_priv, 0); if (tas_priv->fmw->nr_programs > 0)
tas_priv->cur_prog = 0; if (tas_priv->fmw->nr_configurations > 0)
tas_priv->cur_conf = 0;
/* Init common setting for different audio profiles */ if (tas_priv->rcabin.init_profile_id >= 0)
tasdevice_select_cfg_blk(tas_priv,
tas_priv->rcabin.init_profile_id,
TASDEVICE_BIN_BLK_PRE_POWER_UP);
/* If calibrated data occurs error, dsp will still works with default * calibrated data inside algo.
*/
hda_priv->save_calibration(tas_hda);
}
tas_hda->priv = tasdevice_kzalloc(clt); if (!tas_hda->priv) return -ENOMEM;
if (strstr(dev_name(&clt->dev), "TIAS2781")) { /* * TAS2781, integrated on-chip DSP with * global I2C address supported.
*/
device_name = "TIAS2781";
hda_priv->hda_chip_id = HDA_TAS2781;
hda_priv->save_calibration = tas2781_save_calibration;
tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
} elseif (strstarts(dev_name(&clt->dev), "i2c-TXNW2770")) { /* * TAS2770, has no on-chip DSP, so no calibration data * required; has no global I2C address supported.
*/
device_name = "TXNW2770";
hda_priv->hda_chip_id = HDA_TAS2770;
} elseif (strstarts(dev_name(&clt->dev), "i2c-TXNW2781:00-tas2781-hda.0")) {
device_name = "TXNW2781";
hda_priv->save_calibration = tas2781_save_calibration;
tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
} elseif (strstr(dev_name(&clt->dev), "INT8866")) { /* * TAS2563, integrated on-chip DSP with * global I2C address supported.
*/
device_name = "INT8866";
hda_priv->hda_chip_id = HDA_TAS2563;
hda_priv->save_calibration = tas2563_save_calibration;
tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR;
} else { return -ENODEV;
}
tas_hda->priv->irq = clt->irq;
ret = tas2781_read_acpi(tas_hda->priv, device_name); if (ret) return dev_err_probe(tas_hda->dev, ret, "Platform not supported\n");
ret = tasdevice_init(tas_hda->priv); if (ret) goto err;
/* The driver powers up the amplifiers at module load time. * Stop the playback if it's unused.
*/ if (tas_hda->priv->playback_started) {
tasdevice_tuning_switch(tas_hda->priv, 1);
tas_hda->priv->playback_started = false;
}
for (i = 0; i < tas_hda->priv->ndev; i++) {
tas_hda->priv->tasdevice[i].cur_book = -1;
tas_hda->priv->tasdevice[i].cur_prog = -1;
tas_hda->priv->tasdevice[i].cur_conf = -1;
}
tasdevice_reset(tas_hda->priv);
tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog);
/* Init common setting for different audio profiles */ if (tas_hda->priv->rcabin.init_profile_id >= 0)
tasdevice_select_cfg_blk(tas_hda->priv,
tas_hda->priv->rcabin.init_profile_id,
TASDEVICE_BIN_BLK_PRE_POWER_UP);
if (tas_hda->priv->playback_started)
tasdevice_tuning_switch(tas_hda->priv, 0);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.