This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Tool/software:
Hi TI team,
Continuing the below thread for software integration of open / short or normal load detection
https://e2e.ti.com/support/audio-group/audio/f/audio-forum/1400336/tas2563-speaker-open-and-short-detection-in-tuning-mode
We want to perform the load diagnostic check during initial boot up. Once the load diagnostic check is successful we wish to load the reg.bin with initialisation parameters however we need an additional reg.bin to perform this check before loading the actual reg.bin.
Can you let us know how to incorporate 2 reg.bin as part of the driver. Without normal playback being impacted.
cc Rekha Menon
Hi Savyasanchi,
We'll get back to you with further comments soon.
Best regards,
-Ivan Salazar
Applications Engineer
You can save the both regbin file and dsp bin file as two char-type arrays.
During codec probe, the two arrays can be loaded instead of request firmware. Hope my solution can help you.
Hi Shenghao,
Wont this limit us to update the full driver if we want to change any of the bins. As we currently need to only replace the bins in /lib/firmware. Updating the bins feature is required for our use case.
Hi Guy
You may as well have the second development based on current driver, If the driver can't find the bin file in the system, it can load the arrays saving the firmware. Thanks.
Hi Shenghao,
Our use case is as follows
We will perform load diagnostic first on our device during initial boot up and only when normal load is detected we proceed to load the default reg.bin and dsp.bin for normal playback. Is there a way to incorporate both the reg.bin and shift between one another on the go such that the normal playback is not affected after load diagnostic and does not require a reboot.
We require this because in load diagnostic check we are doing SW reset (as suggested by TI) and after SW reset the registers got to default settings but we want to reload our dsp.bin and reg.bin.
Hi Guy
Your req is too simple to add any code into the tas2563 driver. You can put them together into one regbin file and one dspbin file. Our guideline offers a similar case as yours. From P42 to P43, it describes such as case. In user space, you can create a mapping table to save the mapping relationship for the profileid in regbin and program/config id in dspbin.
Row 1, Row 5 ~ 8, Row 17 ~ 20, are used for factory test. In that case are the four pieces tas2563. I think such solution can absolutely meet your case.
As to SW reset, you have a fw force download Kcontrol. Kindly activate it after you run the load diagnostic check.
Hi Shenghao,
We tried adding one more config with in our existing reg.bin and tried switching to it using the below command
amixer -c 1 cset name="x TASDEVICE Profile id" 5
Below are our observations when speaker is not connected.
Is switching between profile id the correct way to handle multiple configurations.
Hi Savyasanchi,
When you read the register after starting the load diagnostic, make sure you wait for the diagnostic routine to complete. The script we provided includes a delay command to wait for this time.
I'll let Shenghao Ding comment about the profile switch question.
Best regards,
-Ivan Salazar
Applications Engineer
conf 5
ConfName: 05-Custom load detection
block type:PRE_SHUTDOWN device idx = 0x00
SINGLE BYTE:
BOOK0x00 PAGE0x00 REG0x02 VALUE = 0x0e
block type:PRE_POWER_UP device idx = 0x00
SINGLE BYTE:
BOOK0x00 PAGE0x00 REG0x00 VALUE = 0x00
BOOK0x00 PAGE0x00 REG0x7f VALUE = 0x00
BOOK0x00 PAGE0x00 REG0x00 VALUE = 0x00
BOOK0x00 PAGE0x00 REG0x01 VALUE = 0x01
BOOK0x00 PAGE0x00 REG0x00 VALUE = 0x00
BOOK0x00 PAGE0x00 REG0x30 VALUE = 0x1d
BOOK0x00 PAGE0x00 REG0x1b VALUE = 0xc7
BOOK0x00 PAGE0x00 REG0x1a VALUE = 0xfd
BOOK0x00 PAGE0x05 REG0x1c VALUE = 0x00
BOOK0x00 PAGE0x05 REG0x1d VALUE = 0x49
BOOK0x00 PAGE0x05 REG0x1e VALUE = 0x24
BOOK0x00 PAGE0x05 REG0x1f VALUE = 0x92
BOOK0x00 PAGE0x05 REG0x20 VALUE = 0x00
BOOK0x00 PAGE0x05 REG0x21 VALUE = 0x1d
BOOK0x00 PAGE0x05 REG0x22 VALUE = 0x41
BOOK0x00 PAGE0x05 REG0x23 VALUE = 0x4d
BOOK0x00 PAGE0x00 REG0x00 VALUE = 0x00
BOOK0x00 PAGE0x00 REG0x3d VALUE = 0x0e
this conf will sw reset the chip, after sw reset, the dsp won't work until reload the dsp firmware into tas2563.
Are you sure reset the tas2563? Adter running this conf, pls call the kcontrol for firmware force load, to download the dsp firmware again.
Can you share the cfg file for Custom load detection?
Hi Shenghao,
1. TI suggested to do the sw reset for LDG mode routine. We have implemented as per this response.
2. The zip file shared in the previous reply is the config 5 included file. It is a part of the reg.bin.
3. My primary query however is the issue with the Open load detection being inconsistent with this reg.bin.
Is switching between profile id the correct way to handle multiple configurations? Kindly address this.
4. In continuation with point 3, We are noticing that the config id is switching after aplay if we follow below steps then the load diagnostic comes correct
amixer -c 1 cset name="x TASDEVICE Profile id" 5
aplay /bin/vendor/British_Female_2.wav
i2cset -f -y 7 0x4e 0x02 0x43
i2cdump -f -y 7 0x4e
We also noticed in dmesg the config id chages in aplay
[ 78.120834] tasdevice-codec 7-004e: tasdevice_hw_params: Playback
[ 78.120855] tasdevice-codec 7-004e: tasdevice_hw_params: BCLK rate = 1536000 Channel = 2Sample rate = 48000 slot width = 16
[ 78.121028] tasdevice-codec 7-004e: SND_SOC_DAPM_POST_PMU
[ 78.134571] tasdevice-codec 7-004e: SND_SOC_DAPM_PRE_PMD
[ 78.134601] tasdevice-codec 7-004e: tasdevice_select_cfg_blk, enter
[ 78.141027] tasdevice-codec 7-004e: select_cfg_blk: profile_conf_id = 5
[ 78.141032] tasdevice-codec 7-004e: select_cfg_blk: conf 5, block type:PRE_SHUTDOWN device idx = 0x00
[ 78.142763] tasdevice-codec 7-004e: powercontrol_routine: enter
[ 78.142768] tasdevice-codec 7-004e: powercontrol_routine: power off has been done before power on has been executed
[ 78.142770] tasdevice-codec 7-004e: powercontrol_routine: leave
Please comment on the above queries
BR,
Rekha
Pls upload the json file with me.
I must highlight that you must call tasdevice_force_dsp_download() after
conf-5 shutdown, just as calibration do.
Hi Shenghao,
We have already shared "tas2563-1amp-reg.zip" in the thread above the bin is generated after importing the origin json from the driver and adding our own registers.
We tried this below methods for force download already
1. echo > force_fw_load_chip (As mentioned on page 38 of ppt)
2. We added the tasdevice_force_dsp_download() in driver also when profile is switched to 5
Even with both the above methods we saw that after aplay only the profile switch was getting reflected.
Hi Savyasanchi,
I updated new .jsn file as attachment for config 5. tas2563-1amp-reg_1021.zip
Hi Shenghao/ Ken,
We have currently implemented the load diagnostic feature as below
We have tested this approach on multiple reboots for a week and find no abnormalities so far. Is this approach reliable ? (Attached code below for reference)
We are yet to test the new .jsn file attached in previous comment.
diff --git a/Linux_for_Tegra/sources/kernel_source/kernel/kernel-4.9/sound/soc/codecs/tas2563/tas2563-load-diagnose.h b/Linux_for_Tegra/sources/kernel_source/kernel/kernel-4.9/sound/soc/codecs/tas2563/tas2563-load-diagnose.h new file mode 100644 index 0000000000..ff63b205fe --- /dev/null +++ b/Linux_for_Tegra/sources/kernel_source/kernel/kernel-4.9/sound/soc/codecs/tas2563/tas2563-load-diagnose.h @@ -0,0 +1,14 @@ +#ifndef __TAS2563_LOAD_DIAGNOSE_H_ +#define __TAS2563_LOAD_DIAGNOSE_H_ + +#define TASDEVICE_NORMAL_LOAD 0x20 + +typedef struct { + unsigned int reg; + unsigned int val; +} nd_tasdevice_register_t; + +extern const nd_tasdevice_register_t load_diagnostic_registers[]; +extern const int load_diagnostic_registers_count; + +#endif diff --git a/Linux_for_Tegra/sources/kernel_source/kernel/kernel-4.9/sound/soc/codecs/tas2563/tasdevice-codec.c b/Linux_for_Tegra/sources/kernel_source/kernel/kernel-4.9/sound/soc/codecs/tas2563/tasdevice-codec.c index 3f71ae001f..470b709128 100644 --- a/Linux_for_Tegra/sources/kernel_source/kernel/kernel-4.9/sound/soc/codecs/tas2563/tasdevice-codec.c +++ b/Linux_for_Tegra/sources/kernel_source/kernel/kernel-4.9/sound/soc/codecs/tas2563/tasdevice-codec.c @@ -30,6 +30,7 @@ #include "tasdevice-ctl.h" #include "tasdevice-regbin.h" #include "tasdevice-rw.h" +#include "tas2563-load-diagnose.h" #define TASDEVICE_CRC8_POLYNOMIAL 0x4d #define TASDEVICE_CLK_DIR_IN (0) @@ -40,6 +41,33 @@ static struct kobject *kobj_ref; bool tas2563_load_status = false; EXPORT_SYMBOL(tas2563_load_status); +static char diagnose_result[64]; + +/* + * These set the upper and lower limits threshold for the speaker + * and are required for load diagnostic routine. + * These are fixed values in our case and is suggested by TI. + */ +const nd_tasdevice_register_t load_diagnostic_registers[] = { + {TASDEVICE_REG(0x00, 0x00, 0x7F), 0x00}, + {TASDEVICE_REG(0x00, 0x00, 0x01), 0x01}, + {TASDEVICE_REG(0x00, 0x00, 0x30), 0x1D}, + {TASDEVICE_REG(0x00, 0x00, 0x1B), 0xC7}, + {TASDEVICE_REG(0x00, 0x00, 0x1A), 0xFD}, + {TASDEVICE_REG(0x00, 0x05, 0x1C), 0x00}, /* Upper threshold start */ + {TASDEVICE_REG(0x00, 0x05, 0x1D), 0x49}, + {TASDEVICE_REG(0x00, 0x05, 0x1E), 0x24}, + {TASDEVICE_REG(0x00, 0x05, 0x1F), 0x92}, /* Upper threshold end */ + {TASDEVICE_REG(0x00, 0x05, 0x20), 0x00}, /* Lower threshold start */ + {TASDEVICE_REG(0x00, 0x05, 0x21), 0x1D}, + {TASDEVICE_REG(0x00, 0x05, 0x22), 0x41}, + {TASDEVICE_REG(0x00, 0x05, 0x23), 0xD4}, /* Lower threshold end */ + {TASDEVICE_REG(0x00, 0x00, 0x3D), 0x0E}, /* Load diagnostic clock enable */ + {TASDEVICE_REG(0x00, 0x00, 0x02), 0x43} /* Entering load diagnostic mode */ +}; + +const int load_diagnostic_registers_count = ARRAY_SIZE(load_diagnostic_registers); + static int tasdevice_program_get(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *pValue) { @@ -388,7 +416,52 @@ static ssize_t tas2563_store(struct kobject *kobj, struct kobj_attribute *attr, return count; } +static ssize_t diagnose_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { + return sprintf(buf, "%s\n", diagnose_result); +} + static struct kobj_attribute tas2563_attr = __ATTR(tas2563_driver_load_status, 0660, tas2563_show, tas2563_store); +static struct kobj_attribute diagnose_attr = __ATTR(speaker_load_diagnose, 0444, diagnose_show, NULL); + +static int tasdevice_load_diagnostic(struct tasdevice_priv *tas_priv) { + int ret, i; + unsigned int read_value, read_value_24; + + // Loop through the array and write to each register + for (i = 0; i < load_diagnostic_registers_count; i++) { + ret = tasdevice_dev_write(tas_priv, 0, load_diagnostic_registers[i].reg, load_diagnostic_registers[i].val); + if (ret < 0) { + dev_err(tas_priv->dev, "Write register failed 0x%02x. Return value: %d\n", load_diagnostic_registers[i].reg, ret); + return ret; + } + } + + // Sleep for 200 ms + msleep(200); + + ret = tasdevice_dev_read(tas_priv, 0, TASDEVICE_REG(0x00, 0x00, 0x25), &read_value); + if (ret < 0) { + dev_err(tas_priv->dev, "Failed to read register 0x25. Return value: %d\n", ret); + return ret; + } + // To detect over current + ret = tasdevice_dev_read(tas_priv, 0, TASDEVICE_REG(0x00, 0x00, 0x24), &read_value_24); + if (ret < 0) { + dev_err(tas_priv->dev, "Failed to read register 0x24. Return value: %d\n", ret); + return ret; + } + + // Store the values in the diagnose_result buffer + snprintf(diagnose_result, sizeof(diagnose_result), "0x25: 0x%02x, 0x24: 0x%02x", read_value, read_value_24); + + if (read_value != TASDEVICE_NORMAL_LOAD) { + dev_err(tas_priv->dev, "Load Diagnostic Mode Not Completed: 0x25: 0x%02x, 0x24: 0x%02x\n", read_value, read_value_24); + return -EINVAL; + } + + dev_info(tas_priv->dev, "Load Diagnostic Mode completed: 0x25: 0x%02x, 0x24: 0x%02x\n", read_value, read_value_24); + return 0; +} //static int tasdevice_codec_probe(struct snd_soc_component *codec) static int tasdevice_codec_probe(struct snd_soc_codec *codec) @@ -409,11 +482,24 @@ static int tasdevice_codec_probe(struct snd_soc_codec *codec) if(ret){ printk(KERN_ERR "Cannot create sysfs file\n"); kobject_put(kobj_ref); - sysfs_remove_file(kernel_kobj, &tas2563_attr.attr); + } + + ret = sysfs_create_file(kobj_ref, &diagnose_attr.attr); + if (ret) { + printk(KERN_ERR "Cannot create sysfs file for speaker diagnose status. Return value: %d\n", ret); + kobject_put(kobj_ref); } printk(KERN_INFO "TAS2563 LOAD STATUS SYSFS Module Insert...Done!!!\n"); + ret = tasdevice_load_diagnostic(tas_priv); + if (ret < 0) { + dev_err(tas_priv->dev, "Failed TAS device load diagnostic. Return value %d\n", ret); + dev_err(tas_priv->dev, "Continuing with the driver probe\n"); + } else { + dev_info(tas_priv->dev, "Successfully completed load diagnostic\n"); + } + /* Codec Lock Hold */ mutex_lock(&tas_priv->codec_lock); tas_priv->codec = codec; @@ -453,7 +539,7 @@ static int tasdevice_codec_remove( snd_soc_codec_get_drvdata(codec); kobject_put(kobj_ref); sysfs_remove_file(kernel_kobj, &tas2563_attr.attr); - + sysfs_remove_file(kernel_kobj, &diagnose_attr.attr); /* Codec Lock Hold */ mutex_lock(&tas_dev->codec_lock); tasdevice_deinit(tas_dev);
It is fine from my side.
following
+ {TASDEVICE_REG(0x00, 0x00, 0x7F), 0x00},
+ {TASDEVICE_REG(0x00, 0x00, 0x01), 0x01},
kindly Add a sleep 50ns at least.
+ {TASDEVICE_REG(0x00, 0x00, 0x30), 0x1D},
Do not forget to reload dsp firmware after diagnosing.
One more thing, when running diagnose, which program id, config id and profile id do you select?
Hi Shenghao,
Is the sleep required in all register writes or in that particular case.
We are not setting any program id, conf id and profile id with this implementation. These registers we are writing and reading at the driver probe only before FW loads. After getting the result from these register writes we proceed further with the driver so it loads the dsp firmware as usual.
After the driver loads for playback in the userspace we set the profile id to 3 for playback.
Hi Ken/ Shenghao,
1. The below was suggested by Shenghao in the same thread. Is this sleep mandatory? Is the sleep to be added between all the registers? Any consequences if no sleep is added?
TI suggestion (:
+ {TASDEVICE_REG(0x00, 0x00, 0x7F), 0x00},
+ {TASDEVICE_REG(0x00, 0x00, 0x01), 0x01},
kindly Add a sleep 50ns at least.
+ {TASDEVICE_REG(0x00, 0x00, 0x30), 0x1D},
2. The device is always in SW shutdown (b0p0r2 = 0x0e) in our case except when playing audio (b0p0r2 = 0x00). This is because we don't have continuous SBCLK. Is this mute mode entry essential in our case?
BR,
Rekha
Hi guy
In our ppc3, if you create a cfg file which including the software reset. you will found the sleep command after the sw reset
Hi Shenghao,
The FCT cfg file includes the below registers only:
Calibration parameters locations (Book,Page,Offset,CoeffLength)
umg_SsmKEGCye = 0x00,0x0d,0x3c,0x01
iks_E0 = 0x00,0x0f,0x34,0x01
yep_LsqM0 = 0x00,0x0f,0x40,0x01
mcb_ZwiNgmaj = 0x00,0x0f,0x44,0x01
oyz_U0_ujx = 0x00,0x0f,0x48,0x01
kgd_OEldlc = 0x00,0x10,0x14,0x01
We do not see any sleep command in this configuration. Do let us know how to generate cfg file including software reset as there is no option in the PPC3.
BR,
Rekha
Hi Rekha
tasdevice_force_dsp_download will run the swreset, after calibration.
Hi Ken/Shenghao,
We are using tasdevice_dev_write to write into those registers for load diagnostic. To our understanding this api already handles the sleep between reg writes
These registers we are writing and reading at the driver probe before request_fw so the dsp bin will be loaded as per usual by the driver.
Hi Shenghao,
The api has a sleep of 200 ms already existing (as shown below). Does adding an additional 50 ns make a difference?
static int tasdevice_load_diagnostic(struct tasdevice_priv *tas_priv) {
int ret, i;
unsigned int read_value, read_value_24;
// Loop through the array and write to each register
for (i = 0; i < load_diagnostic_registers_count; i++) {
ret = tasdevice_dev_write(tas_priv, 0, load_diagnostic_registers[i].reg, load_diagnostic_registers[i].val);
if (ret < 0) {
dev_err(tas_priv->dev, "Write register failed 0x%02x. Return value: %d\n", load_diagnostic_registers[i].reg, ret);
return ret;
}
}
// Sleep for 200 ms
msleep(200);
BR,
Rekha