|
diff --git a/Documentation/devicetree/bindings/sound/tas2562.yaml b/Documentation/devicetree/bindings/sound/tas2562.yaml |
|
index 30f6b029ac08..9af81faf4b42 100644 |
|
--- a/Documentation/devicetree/bindings/sound/tas2562.yaml |
|
+++ b/Documentation/devicetree/bindings/sound/tas2562.yaml |
|
@@ -54,6 +54,10 @@ properties: |
|
'#sound-dai-cells': |
|
const: 1 |
|
|
|
+ firmware-name: |
|
+ $ref: /schemas/types.yaml#/definitions/string |
|
+ description: Name of the firmware to be loaded to the DSP. TAS2563 only. |
|
+ |
|
required: |
|
- compatible |
|
- reg |
|
diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c |
|
index f9ac12b778e6..46b83f9451be 100644 |
|
--- a/drivers/acpi/x86/s2idle.c |
|
+++ b/drivers/acpi/x86/s2idle.c |
|
@@ -17,6 +17,7 @@ |
|
|
|
#include <linux/acpi.h> |
|
#include <linux/device.h> |
|
+#include <linux/dmi.h> |
|
#include <linux/suspend.h> |
|
|
|
#include "../sleep.h" |
|
@@ -27,6 +28,10 @@ static bool sleep_no_lps0 __read_mostly; |
|
module_param(sleep_no_lps0, bool, 0644); |
|
MODULE_PARM_DESC(sleep_no_lps0, "Do not use the special LPS0 device interface"); |
|
|
|
+static bool prefer_microsoft_dsm_guid __read_mostly; |
|
+module_param(prefer_microsoft_dsm_guid, bool, 0644); |
|
+MODULE_PARM_DESC(prefer_microsoft_dsm_guid, "Prefer using Microsoft GUID in LPS0 device _DSM evaluation"); |
|
+ |
|
static const struct acpi_device_id lps0_device_ids[] = { |
|
{"PNP0D80", }, |
|
{"", }, |
|
@@ -363,40 +368,120 @@ static int validate_dsm(acpi_handle handle, const char *uuid, int rev, guid_t *d |
|
return ret; |
|
} |
|
|
|
+ |
|
+struct amd_lps0_hid_device_data { |
|
+ const unsigned int rev_id; |
|
+ const bool check_off_by_one; |
|
+ const bool prefer_amd_guid; |
|
+}; |
|
+ |
|
+static const struct amd_lps0_hid_device_data amd_picasso = { |
|
+ .rev_id = 0, |
|
+ .check_off_by_one = true, |
|
+ .prefer_amd_guid = false, |
|
+}; |
|
+ |
|
+static const struct amd_lps0_hid_device_data amd_cezanne = { |
|
+ .rev_id = 0, |
|
+ .check_off_by_one = false, |
|
+ .prefer_amd_guid = false, |
|
+}; |
|
+ |
|
+static const struct amd_lps0_hid_device_data amd_rembrandt = { |
|
+ .rev_id = 2, |
|
+ .check_off_by_one = false, |
|
+ .prefer_amd_guid = true, |
|
+}; |
|
+ |
|
+static const struct acpi_device_id amd_hid_ids[] = { |
|
+ {"AMD0004", (kernel_ulong_t)&amd_picasso, }, |
|
+ {"AMD0005", (kernel_ulong_t)&amd_picasso, }, |
|
+ {"AMDI0005", (kernel_ulong_t)&amd_picasso, }, |
|
+ {"AMDI0006", (kernel_ulong_t)&amd_cezanne, }, |
|
+ {"AMDI0007", (kernel_ulong_t)&amd_rembrandt, }, |
|
+ {} |
|
+}; |
|
+ |
|
+static int lps0_prefer_microsoft(const struct dmi_system_id *id) |
|
+{ |
|
+ pr_debug("Preferring Microsoft GUID.\n"); |
|
+ prefer_microsoft_dsm_guid = true; |
|
+ return 0; |
|
+} |
|
+ |
|
+static const struct dmi_system_id s2idle_dmi_table[] __initconst = { |
|
+ { |
|
+ /* |
|
+ * ASUS TUF Gaming A17 FA707RE |
|
+ * https://bugzilla.kernel.org/show_bug.cgi?id=216101 |
|
+ */ |
|
+ .callback = lps0_prefer_microsoft, |
|
+ .matches = { |
|
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "ASUS TUF Gaming A17"), |
|
+ }, |
|
+ }, |
|
+ { |
|
+ /* ASUS ROG Zephyrus G14 (2022) */ |
|
+ .callback = lps0_prefer_microsoft, |
|
+ .matches = { |
|
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "ROG Zephyrus G14 GA402"), |
|
+ }, |
|
+ }, |
|
+ { |
|
+ /* ASUS ROG Zephyrus G14 (2022) */ |
|
+ .callback = lps0_prefer_microsoft, |
|
+ .matches = { |
|
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "ROG Zephyrus G14 GA402"), |
|
+ }, |
|
+ }, |
|
+ { |
|
+ /* |
|
+ * Lenovo Yoga Slim 7 Pro X 14ARH7 |
|
+ * https://bugzilla.kernel.org/show_bug.cgi?id=216473 : 82V2 |
|
+ * https://bugzilla.kernel.org/show_bug.cgi?id=216438 : 82TL |
|
+ */ |
|
+ .callback = lps0_prefer_microsoft, |
|
+ .matches = { |
|
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), |
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "82"), |
|
+ }, |
|
+ }, |
|
+ {} |
|
+}; |
|
+ |
|
+ |
|
static int lps0_device_attach(struct acpi_device *adev, |
|
const struct acpi_device_id *not_used) |
|
{ |
|
if (lps0_device_handle) |
|
return 0; |
|
|
|
+ lps0_dsm_func_mask_microsoft = validate_dsm(adev->handle, |
|
+ ACPI_LPS0_DSM_UUID_MICROSOFT, 0, |
|
+ &lps0_dsm_guid_microsoft); |
|
+ |
|
if (acpi_s2idle_vendor_amd()) { |
|
- /* AMD0004, AMD0005, AMDI0005: |
|
- * - Should use rev_id 0x0 |
|
- * - function mask > 0x3: Should use AMD method, but has off by one bug |
|
- * - function mask = 0x3: Should use Microsoft method |
|
- * AMDI0006: |
|
- * - should use rev_id 0x0 |
|
- * - function mask = 0x3: Should use Microsoft method |
|
- * AMDI0007: |
|
- * - Should use rev_id 0x2 |
|
- * - Should only use AMD method |
|
- */ |
|
- const char *hid = acpi_device_hid(adev); |
|
- rev_id = strcmp(hid, "AMDI0007") ? 0 : 2; |
|
+ static const struct acpi_device_id *dev_id; |
|
+ const struct amd_lps0_hid_device_data *data; |
|
+ for (dev_id = &amd_hid_ids[0]; dev_id->id[0]; dev_id++) |
|
+ if (acpi_dev_hid_uid_match(adev, dev_id->id, NULL)) |
|
+ break; |
|
+ if (dev_id) |
|
+ data = (const struct amd_lps0_hid_device_data *) dev_id->driver_data; |
|
+ else |
|
+ data = &amd_rembrandt; |
|
+ rev_id = data->rev_id; |
|
lps0_dsm_func_mask = validate_dsm(adev->handle, |
|
ACPI_LPS0_DSM_UUID_AMD, rev_id, &lps0_dsm_guid); |
|
- lps0_dsm_func_mask_microsoft = validate_dsm(adev->handle, |
|
- ACPI_LPS0_DSM_UUID_MICROSOFT, 0, |
|
- &lps0_dsm_guid_microsoft); |
|
- if (lps0_dsm_func_mask > 0x3 && (!strcmp(hid, "AMD0004") || |
|
- !strcmp(hid, "AMD0005") || |
|
- !strcmp(hid, "AMDI0005"))) { |
|
+ if (lps0_dsm_func_mask > 0x3 && data->check_off_by_one) { |
|
lps0_dsm_func_mask = (lps0_dsm_func_mask << 1) | 0x1; |
|
acpi_handle_debug(adev->handle, "_DSM UUID %s: Adjusted function mask: 0x%x\n", |
|
ACPI_LPS0_DSM_UUID_AMD, lps0_dsm_func_mask); |
|
- } else if (lps0_dsm_func_mask_microsoft > 0 && |
|
- (!strcmp(hid, "AMDI0007") || |
|
- !strcmp(hid, "AMDI0008"))) { |
|
+ } else if (lps0_dsm_func_mask_microsoft > 0 && data->prefer_amd_guid && |
|
+ !prefer_microsoft_dsm_guid) { |
|
lps0_dsm_func_mask_microsoft = -EINVAL; |
|
acpi_handle_debug(adev->handle, "_DSM Using AMD method\n"); |
|
} |
|
@@ -404,7 +489,8 @@ static int lps0_device_attach(struct acpi_device *adev, |
|
rev_id = 1; |
|
lps0_dsm_func_mask = validate_dsm(adev->handle, |
|
ACPI_LPS0_DSM_UUID, rev_id, &lps0_dsm_guid); |
|
- lps0_dsm_func_mask_microsoft = -EINVAL; |
|
+ if (!prefer_microsoft_dsm_guid) |
|
+ lps0_dsm_func_mask_microsoft = -EINVAL; |
|
} |
|
|
|
if (lps0_dsm_func_mask < 0 && lps0_dsm_func_mask_microsoft < 0) |
|
@@ -533,8 +619,9 @@ static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = { |
|
.end = acpi_s2idle_end, |
|
}; |
|
|
|
-void acpi_s2idle_setup(void) |
|
+void __init acpi_s2idle_setup(void) |
|
{ |
|
+ dmi_check_system(s2idle_dmi_table); |
|
acpi_scan_add_handler(&lps0_handler); |
|
s2idle_set_ops(&acpi_s2idle_ops_lps0); |
|
} |
|
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c |
|
index e0b24e1daef3..0812a60d271a 100644 |
|
--- a/sound/soc/amd/yc/acp6x-mach.c |
|
+++ b/sound/soc/amd/yc/acp6x-mach.c |
|
@@ -45,6 +45,13 @@ static struct snd_soc_card acp6x_card = { |
|
}; |
|
|
|
static const struct dmi_system_id yc_acp_quirk_table[] = { |
|
+ { |
|
+ .driver_data = &acp6x_card, |
|
+ .matches = { |
|
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), |
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "82"), |
|
+ } |
|
+ }, |
|
{ |
|
.driver_data = &acp6x_card, |
|
.matches = { |
|
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile |
|
index 92fd441d426a..685a855aae73 100644 |
|
--- a/sound/soc/codecs/Makefile |
|
+++ b/sound/soc/codecs/Makefile |
|
@@ -346,7 +346,7 @@ snd-soc-max98504-objs := max98504.o |
|
snd-soc-simple-amplifier-objs := simple-amplifier.o |
|
snd-soc-tpa6130a2-objs := tpa6130a2.o |
|
snd-soc-tas2552-objs := tas2552.o |
|
-snd-soc-tas2562-objs := tas2562.o |
|
+snd-soc-tas2562-objs := tas2562.o tas25xx_dsp_loader.o |
|
snd-soc-tas2764-objs := tas2764.o |
|
snd-soc-tas2780-objs := tas2780.o |
|
# Mux |
|
diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c |
|
index dc088a1c6721..9a4945c07d59 100644 |
|
--- a/sound/soc/codecs/tas2562.c |
|
+++ b/sound/soc/codecs/tas2562.c |
|
@@ -7,6 +7,7 @@ |
|
#include <linux/module.h> |
|
#include <linux/errno.h> |
|
#include <linux/device.h> |
|
+#include <linux/firmware.h> |
|
#include <linux/i2c.h> |
|
#include <linux/pm_runtime.h> |
|
#include <linux/regmap.h> |
|
@@ -22,6 +23,7 @@ |
|
#include <sound/tlv.h> |
|
|
|
#include "tas2562.h" |
|
+#include "tas25xx_dsp_loader.h" |
|
|
|
#define TAS2562_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\ |
|
SNDRV_PCM_FORMAT_S32_LE) |
|
@@ -44,25 +46,6 @@ static const unsigned int float_vol_db_lookup[] = { |
|
0x197a967f, 0x2013739e, 0x28619ae9, 0x32d64617, 0x40000000 |
|
}; |
|
|
|
-struct tas2562_data { |
|
- struct snd_soc_component *component; |
|
- struct gpio_desc *sdz_gpio; |
|
- struct regmap *regmap; |
|
- struct device *dev; |
|
- struct i2c_client *client; |
|
- int v_sense_slot; |
|
- int i_sense_slot; |
|
- int volume_lvl; |
|
- int model_id; |
|
-}; |
|
- |
|
-enum tas256x_model { |
|
- TAS2562, |
|
- TAS2563, |
|
- TAS2564, |
|
- TAS2110, |
|
-}; |
|
- |
|
static int tas2562_set_bias_level(struct snd_soc_component *component, |
|
enum snd_soc_bias_level level) |
|
{ |
|
@@ -393,6 +376,17 @@ static int tas2562_mute(struct snd_soc_dai *dai, int mute, int direction) |
|
mute ? TAS2562_MUTE : 0); |
|
} |
|
|
|
+static void tas2562_fw_loaded(const struct firmware *fw, void *context) |
|
+{ |
|
+ struct snd_soc_component *component = context; |
|
+ struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); |
|
+ int ret; |
|
+ |
|
+ ret = tas25xx_init_fw(tas2562, fw); |
|
+ if (ret) |
|
+ dev_err(tas2562->dev, "Firmware failed to initialize\n"); |
|
+} |
|
+ |
|
static int tas2562_codec_probe(struct snd_soc_component *component) |
|
{ |
|
struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); |
|
@@ -408,6 +402,12 @@ static int tas2562_codec_probe(struct snd_soc_component *component) |
|
if (ret < 0) |
|
return ret; |
|
|
|
+ if (tas2562->load_firmware == 0 && tas2562->model_id == TAS2563) |
|
+ request_firmware_nowait(THIS_MODULE, 1, |
|
+ tas2562->firmware_name, component->dev, |
|
+ GFP_KERNEL, component, |
|
+ tas2562_fw_loaded); |
|
+ |
|
return 0; |
|
} |
|
|
|
@@ -663,7 +663,7 @@ static struct snd_soc_dai_driver tas2562_dai[] = { |
|
static const struct regmap_range_cfg tas2562_ranges[] = { |
|
{ |
|
.range_min = 0, |
|
- .range_max = 5 * 128, |
|
+ .range_max = 255 * 128, |
|
.selector_reg = TAS2562_PAGE_CTRL, |
|
.selector_mask = 0xff, |
|
.selector_shift = 0, |
|
@@ -689,7 +689,7 @@ static const struct regmap_config tas2562_regmap_config = { |
|
.reg_bits = 8, |
|
.val_bits = 8, |
|
|
|
- .max_register = 5 * 128, |
|
+ .max_register = 255 * 128, |
|
.cache_type = REGCACHE_RBTREE, |
|
.reg_defaults = tas2562_reg_defaults, |
|
.num_reg_defaults = ARRAY_SIZE(tas2562_reg_defaults), |
|
@@ -749,6 +749,14 @@ static int tas2562_parse_dt(struct tas2562_data *tas2562) |
|
return -EINVAL; |
|
} |
|
|
|
+ if (tas2562->model_id != TAS2562) { |
|
+ tas2562->load_firmware = fwnode_property_read_string(dev->fwnode, |
|
+ "firmware-name", |
|
+ &tas2562->firmware_name); |
|
+ if (tas2562->load_firmware) |
|
+ dev_info(dev, "No firmware file to request\n"); |
|
+ } |
|
+ |
|
return ret; |
|
} |
|
|
|
diff --git a/sound/soc/codecs/tas2562.h b/sound/soc/codecs/tas2562.h |
|
index 55b2a1f52ca3..a47c35ab06f4 100644 |
|
--- a/sound/soc/codecs/tas2562.h |
|
+++ b/sound/soc/codecs/tas2562.h |
|
@@ -11,6 +11,7 @@ |
|
#define __TAS2562_H__ |
|
|
|
#define TAS2562_PAGE_CTRL 0x00 |
|
+#define TAS2562_BOOK_CTRL 0x7f |
|
|
|
#define TAS2562_REG(page, reg) ((page * 128) + reg) |
|
|
|
@@ -44,6 +45,8 @@ |
|
#define TAS2562_DVC_CFG3 TAS2562_REG(2, 0x0e) |
|
#define TAS2562_DVC_CFG4 TAS2562_REG(2, 0x0f) |
|
|
|
+#define TAS25XX_DSP_MODE TAS2562_REG(1, 2) |
|
+ |
|
#define TAS2562_RESET BIT(0) |
|
|
|
#define TAS2562_MODE_MASK GENMASK(1,0) |
|
@@ -87,4 +90,28 @@ |
|
#define TAS2562_TDM_CFG6_ISNS_EN BIT(6) |
|
#define TAS2562_TDM_CFG6_ISNS_SLOT_MASK GENMASK(5, 0) |
|
|
|
+#define TAS2563_FW_HDR_OFFSET 134 |
|
+ |
|
+struct tas2562_data { |
|
+ struct snd_soc_component *component; |
|
+ struct gpio_desc *sdz_gpio; |
|
+ struct regmap *regmap; |
|
+ struct device *dev; |
|
+ struct i2c_client *client; |
|
+ struct tas25xx_fw_data *fw_data; |
|
+ const char *firmware_name; |
|
+ int load_firmware; |
|
+ int model_id; |
|
+ int v_sense_slot; |
|
+ int i_sense_slot; |
|
+ int volume_lvl; |
|
+}; |
|
+ |
|
+enum tas2562_id { |
|
+ TAS2110, |
|
+ TAS2562, |
|
+ TAS2563, |
|
+ TAS2564 |
|
+}; |
|
+ |
|
#endif /* __TAS2562_H__ */ |
awesome, will this get pushed to upstream?