mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
ASoC: aw88399: fix BSTS check using vendor driver logic
Marco Giunta <marco_giunta@outlook.it> says: The aw88399 sysst check requires BSTS (boost finished) to assert during startup. On hardware where the boost converter is bypassed via external power supply (EN_HVBAT in BSTCTRL10, i.e. register 0x69 bit 2), BSTS never asserts and init fails. The vendor's generic Android driver (aw883xx, [1]) handles this by reading EN_HVBAT and conditionally skipping the BSTS check. When the original aw88399 driver was ported to the in-tree ASoC driver, this logic was not included. During the development of the HDA side codec driver, I worked around this with a per-instance bsts_unreliable flag set from the HDA scodec driver's per-model quirk table. While functional, this approach requires every new device where the boost converter is bypassed to carry a quirk entry, and prevents users from testing the driver on such devices via the model= alc269 module parameter without a custom kernel to add the entry. This series adds the correct hardware-based check from the vendor driver (patch 1) and removes the now-unnecessary workaround (patch 2), simplifying the code and removing a barrier to testing on new devices. [1] https://www.awinic.com/en/driver/AW88399QNR/594 Link: https://patch.msgid.link/SN6PR19MB230304C2E75499FE23B53885FC8F2@SN6PR19MB2303.namprd19.prod.outlook.com
This commit is contained in:
commit
6158ac6cbe
|
|
@ -449,6 +449,11 @@
|
|||
#define AW88399_NOISE_GATE_EN_MASK \
|
||||
(~(((1<<AW88399_NOISE_GATE_EN_BITS_LEN)-1) << AW88399_NOISE_GATE_EN_START_BIT))
|
||||
|
||||
#define AW88399_EPS_EN_START_BIT (2)
|
||||
#define AW88399_EPS_EN_BITS_LEN (1)
|
||||
#define AW88399_EPS_EN_MASK \
|
||||
(~(((1 << AW88399_EPS_EN_BITS_LEN) - 1) << AW88399_EPS_EN_START_BIT))
|
||||
|
||||
#define AW88399_WDT_CNT_START_BIT (0)
|
||||
#define AW88399_WDT_CNT_BITS_LEN (8)
|
||||
#define AW88399_WDT_CNT_MASK \
|
||||
|
|
@ -598,7 +603,6 @@ struct aw88399 {
|
|||
unsigned int crc_init_val;
|
||||
unsigned int vcalb_init_val;
|
||||
unsigned int dither_st;
|
||||
bool bsts_unreliable;
|
||||
bool fw_needs_reload;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -118,7 +118,6 @@ static int aw88399_hda_init(struct aw88399_hda *aw88399)
|
|||
mutex_init(&core->lock);
|
||||
core->reset_gpio = aw88399->reset_gpio;
|
||||
core->regmap = aw88399->regmap;
|
||||
core->bsts_unreliable = aw88399->bsts_unreliable;
|
||||
|
||||
aw88399_hw_reset(core);
|
||||
|
||||
|
|
@ -155,41 +154,20 @@ static int aw88399_swap_channels(struct aw88399_hda *aw88399)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int aw88399_skip_bsts_check(struct aw88399_hda *aw88399)
|
||||
{
|
||||
/*
|
||||
* BSTS (boost-finished) status bit does not reliably report on
|
||||
* some hardware. On certain Lenovo Legion laptops, both amps
|
||||
* report BSTS=0 (boost not finished) during normal playback
|
||||
* despite clean audio output. Skip BSTS in the startup status
|
||||
* check to avoid false init failures.
|
||||
*/
|
||||
aw88399->bsts_unreliable = true;
|
||||
dev_dbg(aw88399->dev, "BSTS status check disabled\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aw88399_apply_legion_quirks(struct aw88399_hda *aw88399)
|
||||
{
|
||||
aw88399_swap_channels(aw88399);
|
||||
aw88399_skip_bsts_check(aw88399);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct aw88399_prop_model {
|
||||
const char *ssid;
|
||||
int (*apply_prop)(struct aw88399_hda *aw88399);
|
||||
};
|
||||
|
||||
static const struct aw88399_prop_model aw88399_prop_model_table[] = {
|
||||
{ "17AA3906", aw88399_apply_legion_quirks },
|
||||
{ "17AA3907", aw88399_apply_legion_quirks },
|
||||
{ "17AA3927", aw88399_apply_legion_quirks },
|
||||
{ "17AA3928", aw88399_apply_legion_quirks },
|
||||
{ "17AA3936", aw88399_apply_legion_quirks },
|
||||
{ "17AA3937", aw88399_apply_legion_quirks },
|
||||
{ "17AA3938", aw88399_apply_legion_quirks },
|
||||
{ "17AA3939", aw88399_apply_legion_quirks },
|
||||
{ "17AA3906", aw88399_swap_channels },
|
||||
{ "17AA3907", aw88399_swap_channels },
|
||||
{ "17AA3927", aw88399_swap_channels },
|
||||
{ "17AA3928", aw88399_swap_channels },
|
||||
{ "17AA3936", aw88399_swap_channels },
|
||||
{ "17AA3937", aw88399_swap_channels },
|
||||
{ "17AA3938", aw88399_swap_channels },
|
||||
{ "17AA3939", aw88399_swap_channels },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ struct aw88399_hda {
|
|||
struct gpio_desc *reset_gpio;
|
||||
struct aw_device *aw_dev;
|
||||
struct aw88399 *core;
|
||||
bool bsts_unreliable;
|
||||
|
||||
const char *acpi_subsystem_id;
|
||||
int index;
|
||||
|
|
|
|||
|
|
@ -167,9 +167,8 @@ int aw_dev_check_syspll(struct aw_device *aw_dev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(aw_dev_check_syspll);
|
||||
|
||||
static int aw_dev_check_sysst(struct aw88399 *aw88399)
|
||||
static int aw_dev_check_sysst(struct aw_device *aw_dev)
|
||||
{
|
||||
struct aw_device *aw_dev = aw88399->aw_pa;
|
||||
unsigned int check_val;
|
||||
unsigned int reg_val;
|
||||
int ret, i;
|
||||
|
|
@ -184,11 +183,16 @@ static int aw_dev_check_sysst(struct aw88399 *aw88399)
|
|||
check_val = AW88399_BIT_SYSST_SWS_CHECK;
|
||||
|
||||
/*
|
||||
* On some hardware the BSTS (boost-finished) status bit does not
|
||||
* reliably assert even when audio output is working normally.
|
||||
* Allow per-instance bypass when flagged by the side-codec driver.
|
||||
* When an external power supply (EPS) is used to feed the amplifier
|
||||
* (EN_HVBAT bit in BSTCTRL10 set), the boost converter is bypassed,
|
||||
* and BSTS (boost finished) will never assert. Skip the BSTS check in
|
||||
* this case, matching the vendor driver's behavior.
|
||||
*/
|
||||
if (aw88399->bsts_unreliable)
|
||||
ret = regmap_read(aw_dev->regmap, AW88399_BSTCTRL10_REG, ®_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (reg_val & (~AW88399_EPS_EN_MASK))
|
||||
check_val &= ~AW88399_BSTS_FINISHED_VALUE;
|
||||
|
||||
for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
|
||||
|
|
@ -719,7 +723,7 @@ static int aw88399_dev_start(struct aw88399 *aw88399)
|
|||
usleep_range(AW88399_1000_US, AW88399_1000_US + 50);
|
||||
|
||||
/* check i2s status */
|
||||
ret = aw_dev_check_sysst(aw88399);
|
||||
ret = aw_dev_check_sysst(aw_dev);
|
||||
if (ret) {
|
||||
dev_err(aw_dev->dev, "sysst check failed");
|
||||
goto sysst_check_fail;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user