|
From 976ca0414020562c2efdc56e6605d136a2ba6eb5 Mon Sep 17 00:00:00 2001 |
|
From: root <[email protected]> |
|
Date: Sat, 6 Mar 2021 19:39:50 +0100 |
|
Subject: [PATCH] Compile with support for bytcr-wm5102 |
|
|
|
--- |
|
0001-WM5102.patch | 1105 +++++++++++++++++++++++++++++++++++++++ |
|
Patchlist | 1 + |
|
filter-x86_64.sh | 4 +- |
|
filter-x86_64.sh.fedora | 4 +- |
|
kernel-local | 18 + |
|
kernel.spec | 5 +- |
|
6 files changed, 1134 insertions(+), 3 deletions(-) |
|
create mode 100644 0001-WM5102.patch |
|
|
|
diff --git a/0001-WM5102.patch b/0001-WM5102.patch |
|
new file mode 100644 |
|
index 000000000..403aaa208 |
|
--- /dev/null |
|
+++ b/0001-WM5102.patch |
|
@@ -0,0 +1,1105 @@ |
|
+From 289037603a20b6cae158b34484d1d70be9a272c5 Mon Sep 17 00:00:00 2001 |
|
+From: Hans de Goede <[email protected]> |
|
+Date: Wed, 20 Jan 2021 22:49:53 +0100 |
|
+Subject: [PATCH 1/6] mfd: arizona: Add MODULE_SOFTDEP("pre: arizona_ldo1") |
|
+ |
|
+The (shared) probing code of the arizona-i2c and arizona-spi modules |
|
+takes the following steps during init: |
|
+ |
|
+1. Call mfd_add_devices() for a set of early child-devices, this |
|
+includes the arizona_ldo1 device which provides one of the |
|
+core-regulators. |
|
+ |
|
+2. Bulk enable the core-regulators. |
|
+ |
|
+3. Read the device id. |
|
+ |
|
+4. Call mfd_add_devices() for the other child-devices. |
|
+ |
|
+This sequence depends on 1. leading to not only the child-device |
|
+being created, but also the driver for the child-device binding |
|
+to it and registering its regulator. |
|
+ |
|
+This requires the arizona_ldo1 driver to be loaded before the |
|
+shared probing code runs. Add a softdep for this to both modules to |
|
+ensure that this requirement is met. |
|
+ |
|
+Note this mirrors the existing MODULE_SOFTDEP("pre: wm8994_regulator") |
|
+in the wm8994 code, which has a similar init sequence. |
|
+ |
|
+Reviewed-by: Andy Shevchenko <[email protected]> |
|
+Acked-by: Charles Keepax <[email protected]> |
|
+Signed-off-by: Hans de Goede <[email protected]> |
|
+Signed-off-by: Lee Jones <[email protected]> |
|
+--- |
|
+ drivers/mfd/arizona-i2c.c | 1 + |
|
+ drivers/mfd/arizona-spi.c | 1 + |
|
+ 2 files changed, 2 insertions(+) |
|
+ |
|
+diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c |
|
+index 4b58e3ad6..2a4a3a164 100644 |
|
+--- a/drivers/mfd/arizona-i2c.c |
|
++++ b/drivers/mfd/arizona-i2c.c |
|
+@@ -115,6 +115,7 @@ static struct i2c_driver arizona_i2c_driver = { |
|
+ |
|
+ module_i2c_driver(arizona_i2c_driver); |
|
+ |
|
++MODULE_SOFTDEP("pre: arizona_ldo1"); |
|
+ MODULE_DESCRIPTION("Arizona I2C bus interface"); |
|
+ MODULE_AUTHOR("Mark Brown <[email protected]>"); |
|
+ MODULE_LICENSE("GPL"); |
|
+diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c |
|
+index 2633e147b..704f214d2 100644 |
|
+--- a/drivers/mfd/arizona-spi.c |
|
++++ b/drivers/mfd/arizona-spi.c |
|
+@@ -110,6 +110,7 @@ static struct spi_driver arizona_spi_driver = { |
|
+ |
|
+ module_spi_driver(arizona_spi_driver); |
|
+ |
|
++MODULE_SOFTDEP("pre: arizona_ldo1"); |
|
+ MODULE_DESCRIPTION("Arizona SPI bus interface"); |
|
+ MODULE_AUTHOR("Mark Brown <[email protected]>"); |
|
+ MODULE_LICENSE("GPL"); |
|
+-- |
|
+2.29.2 |
|
+ |
|
+ |
|
+From 0ba03c22a853712f02f9dc98ba4829f12758856c Mon Sep 17 00:00:00 2001 |
|
+From: Hans de Goede <[email protected]> |
|
+Date: Wed, 20 Jan 2021 22:49:54 +0100 |
|
+Subject: [PATCH 2/6] mfd: arizona: Replace arizona_of_get_type() with |
|
+ device_get_match_data() |
|
+ |
|
+Replace the custom arizona_of_get_type() function with the generic |
|
+device_get_match_data() helper. Besides being a nice cleanup this |
|
+also makes it easier to add support for binding to ACPI enumerated |
|
+devices. |
|
+ |
|
+While at it also fix a possible NULL pointer deref of the id |
|
+argument to the probe functions (this could happen on e.g. manual |
|
+driver binding through sysfs). |
|
+ |
|
+Suggested-by: Andy Shevchenko <[email protected]> |
|
+Reviewed-by: Andy Shevchenko <[email protected]> |
|
+Acked-by: Charles Keepax <[email protected]> |
|
+Signed-off-by: Hans de Goede <[email protected]> |
|
+Signed-off-by: Lee Jones <[email protected]> |
|
+--- |
|
+ drivers/mfd/arizona-core.c | 11 ----------- |
|
+ drivers/mfd/arizona-i2c.c | 10 ++++++---- |
|
+ drivers/mfd/arizona-spi.c | 10 ++++++---- |
|
+ drivers/mfd/arizona.h | 9 --------- |
|
+ 4 files changed, 12 insertions(+), 28 deletions(-) |
|
+ |
|
+diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c |
|
+index 000cb8202..75f1bc671 100644 |
|
+--- a/drivers/mfd/arizona-core.c |
|
++++ b/drivers/mfd/arizona-core.c |
|
+@@ -797,17 +797,6 @@ const struct dev_pm_ops arizona_pm_ops = { |
|
+ EXPORT_SYMBOL_GPL(arizona_pm_ops); |
|
+ |
|
+ #ifdef CONFIG_OF |
|
+-unsigned long arizona_of_get_type(struct device *dev) |
|
+-{ |
|
+- const struct of_device_id *id = of_match_device(arizona_of_match, dev); |
|
+- |
|
+- if (id) |
|
+- return (unsigned long)id->data; |
|
+- else |
|
+- return 0; |
|
+-} |
|
+-EXPORT_SYMBOL_GPL(arizona_of_get_type); |
|
+- |
|
+ static int arizona_of_get_core_pdata(struct arizona *arizona) |
|
+ { |
|
+ struct arizona_pdata *pdata = &arizona->pdata; |
|
+diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c |
|
+index 2a4a3a164..5e83b730c 100644 |
|
+--- a/drivers/mfd/arizona-i2c.c |
|
++++ b/drivers/mfd/arizona-i2c.c |
|
+@@ -23,14 +23,16 @@ |
|
+ static int arizona_i2c_probe(struct i2c_client *i2c, |
|
+ const struct i2c_device_id *id) |
|
+ { |
|
++ const void *match_data; |
|
+ struct arizona *arizona; |
|
+ const struct regmap_config *regmap_config = NULL; |
|
+- unsigned long type; |
|
++ unsigned long type = 0; |
|
+ int ret; |
|
+ |
|
+- if (i2c->dev.of_node) |
|
+- type = arizona_of_get_type(&i2c->dev); |
|
+- else |
|
++ match_data = device_get_match_data(&i2c->dev); |
|
++ if (match_data) |
|
++ type = (unsigned long)match_data; |
|
++ else if (id) |
|
+ type = id->driver_data; |
|
+ |
|
+ switch (type) { |
|
+diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c |
|
+index 704f214d2..798b88295 100644 |
|
+--- a/drivers/mfd/arizona-spi.c |
|
++++ b/drivers/mfd/arizona-spi.c |
|
+@@ -23,14 +23,16 @@ |
|
+ static int arizona_spi_probe(struct spi_device *spi) |
|
+ { |
|
+ const struct spi_device_id *id = spi_get_device_id(spi); |
|
++ const void *match_data; |
|
+ struct arizona *arizona; |
|
+ const struct regmap_config *regmap_config = NULL; |
|
+- unsigned long type; |
|
++ unsigned long type = 0; |
|
+ int ret; |
|
+ |
|
+- if (spi->dev.of_node) |
|
+- type = arizona_of_get_type(&spi->dev); |
|
+- else |
|
++ match_data = device_get_match_data(&spi->dev); |
|
++ if (match_data) |
|
++ type = (unsigned long)match_data; |
|
++ else if (id) |
|
+ type = id->driver_data; |
|
+ |
|
+ switch (type) { |
|
+diff --git a/drivers/mfd/arizona.h b/drivers/mfd/arizona.h |
|
+index 995efc6d7..801cbbcd7 100644 |
|
+--- a/drivers/mfd/arizona.h |
|
++++ b/drivers/mfd/arizona.h |
|
+@@ -50,13 +50,4 @@ int arizona_dev_exit(struct arizona *arizona); |
|
+ int arizona_irq_init(struct arizona *arizona); |
|
+ int arizona_irq_exit(struct arizona *arizona); |
|
+ |
|
+-#ifdef CONFIG_OF |
|
+-unsigned long arizona_of_get_type(struct device *dev); |
|
+-#else |
|
+-static inline unsigned long arizona_of_get_type(struct device *dev) |
|
+-{ |
|
+- return 0; |
|
+-} |
|
+-#endif |
|
+- |
|
+ #endif |
|
+-- |
|
+2.29.2 |
|
+ |
|
+ |
|
+From f426a51814e5ce9e6a87cd283d577e9e9eee5e5d Mon Sep 17 00:00:00 2001 |
|
+From: Hans de Goede <[email protected]> |
|
+Date: Wed, 20 Jan 2021 22:49:55 +0100 |
|
+Subject: [PATCH 3/6] mfd: arizona: Add support for ACPI enumeration of WM5102 |
|
+ connected over SPI |
|
+ |
|
+The Intel Bay Trail (x86/ACPI) based Lenovo Yoga Tablet 2 series use |
|
+a WM5102 codec connected over SPI. |
|
+ |
|
+Add support for ACPI enumeration to arizona-spi so that arizona-spi can |
|
+bind to the codec on these tablets. |
|
+ |
|
+This is loosely based on an earlier attempt (for Android-x86) at this by |
|
+Christian Hartmann, combined with insights in things like the speaker GPIO |
|
+from the android-x86 android port for the Lenovo Yoga Tablet 2 1051F/L [1]. |
|
+ |
|
+[1] https://github.com/Kitsune2222/Android_Yoga_Tablet_2-1051F_Kernel |
|
+ |
|
+Cc: Christian Hartmann <[email protected]> |
|
+Reviewed-by: Andy Shevchenko <[email protected]> |
|
+Signed-off-by: Hans de Goede <[email protected]> |
|
+Acked-by: Charles Keepax <[email protected]> |
|
+Signed-off-by: Lee Jones <[email protected]> |
|
+--- |
|
+ drivers/mfd/arizona-spi.c | 127 ++++++++++++++++++++++++++++++++++++++ |
|
+ 1 file changed, 127 insertions(+) |
|
+ |
|
+diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c |
|
+index 798b88295..24a2c75d6 100644 |
|
+--- a/drivers/mfd/arizona-spi.c |
|
++++ b/drivers/mfd/arizona-spi.c |
|
+@@ -7,7 +7,10 @@ |
|
+ * Author: Mark Brown <[email protected]> |
|
+ */ |
|
+ |
|
++#include <linux/acpi.h> |
|
+ #include <linux/err.h> |
|
++#include <linux/gpio/consumer.h> |
|
++#include <linux/gpio/machine.h> |
|
+ #include <linux/module.h> |
|
+ #include <linux/pm_runtime.h> |
|
+ #include <linux/regmap.h> |
|
+@@ -15,11 +18,128 @@ |
|
+ #include <linux/slab.h> |
|
+ #include <linux/spi/spi.h> |
|
+ #include <linux/of.h> |
|
++#include <uapi/linux/input-event-codes.h> |
|
+ |
|
+ #include <linux/mfd/arizona/core.h> |
|
+ |
|
+ #include "arizona.h" |
|
+ |
|
++#ifdef CONFIG_ACPI |
|
++const struct acpi_gpio_params reset_gpios = { 1, 0, false }; |
|
++const struct acpi_gpio_params ldoena_gpios = { 2, 0, false }; |
|
++ |
|
++static const struct acpi_gpio_mapping arizona_acpi_gpios[] = { |
|
++ { "reset-gpios", &reset_gpios, 1, }, |
|
++ { "wlf,ldoena-gpios", &ldoena_gpios, 1 }, |
|
++ { } |
|
++}; |
|
++ |
|
++/* |
|
++ * The ACPI resources for the device only describe external GPIO-s. They do |
|
++ * not provide mappings for the GPIO-s coming from the Arizona codec itself. |
|
++ */ |
|
++static const struct gpiod_lookup arizona_soc_gpios[] = { |
|
++ { "arizona", 2, "wlf,spkvdd-ena", 0, GPIO_ACTIVE_HIGH }, |
|
++ { "arizona", 4, "wlf,micd-pol", 0, GPIO_ACTIVE_LOW }, |
|
++}; |
|
++ |
|
++/* |
|
++ * The AOSP 3.5 mm Headset: Accessory Specification gives the following values: |
|
++ * Function A Play/Pause: 0 ohm |
|
++ * Function D Voice assistant: 135 ohm |
|
++ * Function B Volume Up 240 ohm |
|
++ * Function C Volume Down 470 ohm |
|
++ * Minimum Mic DC resistance 1000 ohm |
|
++ * Minimum Ear speaker impedance 16 ohm |
|
++ * Note the first max value below must be less then the min. speaker impedance, |
|
++ * to allow CTIA/OMTP detection to work. The other max values are the closest |
|
++ * value from extcon-arizona.c:arizona_micd_levels halfway 2 button resistances. |
|
++ */ |
|
++static const struct arizona_micd_range arizona_micd_aosp_ranges[] = { |
|
++ { .max = 11, .key = KEY_PLAYPAUSE }, |
|
++ { .max = 186, .key = KEY_VOICECOMMAND }, |
|
++ { .max = 348, .key = KEY_VOLUMEUP }, |
|
++ { .max = 752, .key = KEY_VOLUMEDOWN }, |
|
++}; |
|
++ |
|
++static void arizona_spi_acpi_remove_lookup(void *lookup) |
|
++{ |
|
++ gpiod_remove_lookup_table(lookup); |
|
++} |
|
++ |
|
++static int arizona_spi_acpi_probe(struct arizona *arizona) |
|
++{ |
|
++ struct gpiod_lookup_table *lookup; |
|
++ acpi_status status; |
|
++ int ret; |
|
++ |
|
++ /* Add mappings for the 2 ACPI declared GPIOs used for reset and ldo-ena */ |
|
++ devm_acpi_dev_add_driver_gpios(arizona->dev, arizona_acpi_gpios); |
|
++ |
|
++ /* Add lookups for the SoCs own GPIOs used for micdet-polarity and spkVDD-enable */ |
|
++ lookup = devm_kzalloc(arizona->dev, |
|
++ struct_size(lookup, table, ARRAY_SIZE(arizona_soc_gpios) + 1), |
|
++ GFP_KERNEL); |
|
++ if (!lookup) |
|
++ return -ENOMEM; |
|
++ |
|
++ lookup->dev_id = dev_name(arizona->dev); |
|
++ memcpy(lookup->table, arizona_soc_gpios, sizeof(arizona_soc_gpios)); |
|
++ |
|
++ gpiod_add_lookup_table(lookup); |
|
++ ret = devm_add_action_or_reset(arizona->dev, arizona_spi_acpi_remove_lookup, lookup); |
|
++ if (ret) |
|
++ return ret; |
|
++ |
|
++ /* Enable 32KHz clock from SoC to codec for jack-detect */ |
|
++ status = acpi_evaluate_object(ACPI_HANDLE(arizona->dev), "CLKE", NULL, NULL); |
|
++ if (ACPI_FAILURE(status)) |
|
++ dev_warn(arizona->dev, "Failed to enable 32KHz clk ACPI error %d\n", status); |
|
++ |
|
++ /* |
|
++ * Some DSDTs wrongly declare the IRQ trigger-type as IRQF_TRIGGER_FALLING |
|
++ * The IRQ line will stay low when a new IRQ event happens between reading |
|
++ * the IRQ status flags and acknowledging them. When the IRQ line stays |
|
++ * low like this the IRQ will never trigger again when its type is set |
|
++ * to IRQF_TRIGGER_FALLING. Correct the IRQ trigger-type to fix this. |
|
++ * |
|
++ * Note theoretically it is possible that some boards are not capable |
|
++ * of handling active low level interrupts. In that case setting the |
|
++ * flag to IRQF_TRIGGER_FALLING would not be a bug (and we would need |
|
++ * to work around this) but so far all known usages of IRQF_TRIGGER_FALLING |
|
++ * are a bug in the board's DSDT. |
|
++ */ |
|
++ arizona->pdata.irq_flags = IRQF_TRIGGER_LOW; |
|
++ |
|
++ /* Wait 200 ms after jack insertion */ |
|
++ arizona->pdata.micd_detect_debounce = 200; |
|
++ |
|
++ /* Use standard AOSP values for headset-button mappings */ |
|
++ arizona->pdata.micd_ranges = arizona_micd_aosp_ranges; |
|
++ arizona->pdata.num_micd_ranges = ARRAY_SIZE(arizona_micd_aosp_ranges); |
|
++ |
|
++ return 0; |
|
++} |
|
++ |
|
++static const struct acpi_device_id arizona_acpi_match[] = { |
|
++ { |
|
++ .id = "WM510204", |
|
++ .driver_data = WM5102, |
|
++ }, |
|
++ { |
|
++ .id = "WM510205", |
|
++ .driver_data = WM5102, |
|
++ }, |
|
++ { } |
|
++}; |
|
++MODULE_DEVICE_TABLE(acpi, arizona_acpi_match); |
|
++#else |
|
++static int arizona_spi_acpi_probe(struct arizona *arizona) |
|
++{ |
|
++ return -ENODEV; |
|
++} |
|
++#endif |
|
++ |
|
+ static int arizona_spi_probe(struct spi_device *spi) |
|
+ { |
|
+ const struct spi_device_id *id = spi_get_device_id(spi); |
|
+@@ -77,6 +197,12 @@ static int arizona_spi_probe(struct spi_device *spi) |
|
+ arizona->dev = &spi->dev; |
|
+ arizona->irq = spi->irq; |
|
+ |
|
++ if (has_acpi_companion(&spi->dev)) { |
|
++ ret = arizona_spi_acpi_probe(arizona); |
|
++ if (ret) |
|
++ return ret; |
|
++ } |
|
++ |
|
+ return arizona_dev_init(arizona); |
|
+ } |
|
+ |
|
+@@ -104,6 +230,7 @@ static struct spi_driver arizona_spi_driver = { |
|
+ .name = "arizona", |
|
+ .pm = &arizona_pm_ops, |
|
+ .of_match_table = of_match_ptr(arizona_of_match), |
|
++ .acpi_match_table = ACPI_PTR(arizona_acpi_match), |
|
+ }, |
|
+ .probe = arizona_spi_probe, |
|
+ .remove = arizona_spi_remove, |
|
+-- |
|
+2.29.2 |
|
+ |
|
+ |
|
+From eb1c76ac7aa0c81e876a83e1afbf54f7256be3a8 Mon Sep 17 00:00:00 2001 |
|
+From: Hans de Goede <[email protected]> |
|
+Date: Wed, 20 Jan 2021 22:49:56 +0100 |
|
+Subject: [PATCH 4/6] ASoC: Intel: Add DMI quirk table to soc_intel_is_byt_cr() |
|
+ |
|
+Some Bay Trail systems: |
|
+1. Use a non CR version of the Bay Trail SoC |
|
+2. Contain at least 6 interrupt resources so that the |
|
+ platform_get_resource(pdev, IORESOURCE_IRQ, 5) check to workaround |
|
+ non CR systems which list their IPC IRQ at index 0 despite being |
|
+ non CR does not work |
|
+3. Despite 1. and 2. still have their IPC IRQ at index 0 rather then 5 |
|
+ |
|
+Add a DMI quirk table to check for the few known models with this issue, |
|
+so that the right IPC IRQ index is used on these systems. |
|
+ |
|
+Reviewed-by: Andy Shevchenko <[email protected]> |
|
+Acked-by: Pierre-Louis Bossart <[email protected]> |
|
+Signed-off-by: Hans de Goede <[email protected]> |
|
+Link: https://lore.kernel.org/r/[email protected] |
|
+Signed-off-by: Mark Brown <[email protected]> |
|
+--- |
|
+ sound/soc/intel/common/soc-intel-quirks.h | 25 +++++++++++++++++++++++ |
|
+ 1 file changed, 25 insertions(+) |
|
+ |
|
+diff --git a/sound/soc/intel/common/soc-intel-quirks.h b/sound/soc/intel/common/soc-intel-quirks.h |
|
+index b07df3059..a93987ab7 100644 |
|
+--- a/sound/soc/intel/common/soc-intel-quirks.h |
|
++++ b/sound/soc/intel/common/soc-intel-quirks.h |
|
+@@ -11,6 +11,7 @@ |
|
+ |
|
+ #if IS_ENABLED(CONFIG_X86) |
|
+ |
|
++#include <linux/dmi.h> |
|
+ #include <asm/cpu_device_id.h> |
|
+ #include <asm/intel-family.h> |
|
+ #include <asm/iosf_mbi.h> |
|
+@@ -38,12 +39,36 @@ SOC_INTEL_IS_CPU(cml, KABYLAKE_L); |
|
+ |
|
+ static inline bool soc_intel_is_byt_cr(struct platform_device *pdev) |
|
+ { |
|
++ /* |
|
++ * List of systems which: |
|
++ * 1. Use a non CR version of the Bay Trail SoC |
|
++ * 2. Contain at least 6 interrupt resources so that the |
|
++ * platform_get_resource(pdev, IORESOURCE_IRQ, 5) check below |
|
++ * succeeds |
|
++ * 3. Despite 1. and 2. still have their IPC IRQ at index 0 rather then 5 |
|
++ * |
|
++ * This needs to be here so that it can be shared between the SST and |
|
++ * SOF drivers. We rely on the compiler to optimize this out in files |
|
++ * where soc_intel_is_byt_cr is not used. |
|
++ */ |
|
++ static const struct dmi_system_id force_bytcr_table[] = { |
|
++ { /* Lenovo Yoga Tablet 2 series */ |
|
++ .matches = { |
|
++ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), |
|
++ DMI_MATCH(DMI_PRODUCT_FAMILY, "YOGATablet2"), |
|
++ }, |
|
++ }, |
|
++ {} |
|
++ }; |
|
+ struct device *dev = &pdev->dev; |
|
+ int status = 0; |
|
+ |
|
+ if (!soc_intel_is_byt()) |
|
+ return false; |
|
+ |
|
++ if (dmi_check_system(force_bytcr_table)) |
|
++ return true; |
|
++ |
|
+ if (iosf_mbi_available()) { |
|
+ u32 bios_status; |
|
+ |
|
+-- |
|
+2.29.2 |
|
+ |
|
+ |
|
+From 92b3356a7e2cc1f31a75f9e4f9e223d68aabfd42 Mon Sep 17 00:00:00 2001 |
|
+From: Pierre-Louis Bossart <[email protected]> |
|
+Date: Wed, 20 Jan 2021 22:49:57 +0100 |
|
+Subject: [PATCH 5/6] ASoC: Intel: bytcr_wm5102: Add machine driver for |
|
+ BYT/WM5102 |
|
+ |
|
+Add a new ASoc Machine driver for Intel Baytrail platforms with a |
|
+Wolfson Microelectronics WM5102 codec. |
|
+ |
|
+This is based on a past contributions [1] from Paulo Sergio Travaglia |
|
+<[email protected]> based on the Levono kernel [2] combined with |
|
+insights in things like the speaker GPIO from the android-x86 android |
|
+port for the Lenovo Yoga Tablet 2 1051F/L [3]. |
|
+ |
|
+[1] https://patchwork.kernel.org/project/alsa-devel/patch/[email protected]/ |
|
+[2] https://github.com/lenovo-yt2-dev/android_kernel_lenovo_baytrail/blob/cm-12.1/sound/soc/intel/board/byt_bl_wm5102.c |
|
+[3] https://github.com/Kitsune2222/Android_Yoga_Tablet_2-1051F_Kernel |
|
+ |
|
+The original machine driver from the Android ports was a crude modified |
|
+copy of bytcr_rt5640.c adjusted to work with the WM5102 codec. |
|
+This version has been extensively reworked to: |
|
+ |
|
+1. Remove all rt5640 related quirk handling. to the best of my knowledge |
|
+this setup is only used on the Lenovo Yoga Tablet 2 series (8, 10 and 13 |
|
+inch models) which all use the same setup. So there is no need to deal |
|
+with all the variations with which we need to deal on rt5640 boards. |
|
+ |
|
+2. Rework clock handling, properly turn off the FLL and the platform-clock |
|
+when they are no longer necessary and don't reconfigure the FLL |
|
+unnecessarily when it is already running. This fixes a number of: |
|
+"Timed out waiting for lock" warnings being logged. |
|
+ |
|
+3. Add the GPIO controlled Speaker-VDD regulator as a DAPM_SUPPLY |
|
+ |
|
+This only adds the machine driver and ACPI hooks, the BYT-CR detection |
|
+quirk which these devices need will be added in a separate patch. |
|
+ |
|
+BugLink: https://github.com/thesofproject/linux/issues/2485 |
|
+Co-authored-by: Pierre-Louis Bossart <[email protected]> |
|
+Signed-off-by: Pierre-Louis Bossart <[email protected]> |
|
+Reviewed-by: Andy Shevchenko <[email protected]> |
|
+Signed-off-by: Hans de Goede <[email protected]> |
|
+Reviewed-by: Charles Keepax <[email protected]> |
|
+Link: https://lore.kernel.org/r/[email protected] |
|
+Signed-off-by: Mark Brown <[email protected]> |
|
+--- |
|
+ sound/soc/intel/boards/Kconfig | 12 + |
|
+ sound/soc/intel/boards/Makefile | 2 + |
|
+ sound/soc/intel/boards/bytcr_wm5102.c | 465 ++++++++++++++++++ |
|
+ .../intel/common/soc-acpi-intel-byt-match.c | 16 + |
|
+ 4 files changed, 495 insertions(+) |
|
+ create mode 100644 sound/soc/intel/boards/bytcr_wm5102.c |
|
+ |
|
+diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig |
|
+index c10c37803..6ce04b648 100644 |
|
+--- a/sound/soc/intel/boards/Kconfig |
|
++++ b/sound/soc/intel/boards/Kconfig |
|
+@@ -111,6 +111,18 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH |
|
+ Say Y or m if you have such a device. This is a recommended option. |
|
+ If unsure select "N". |
|
+ |
|
++config SND_SOC_INTEL_BYTCR_WM5102_MACH |
|
++ tristate "Baytrail and Baytrail-CR with WM5102 codec" |
|
++ depends on MFD_ARIZONA && MFD_WM5102 && SPI_MASTER && ACPI |
|
++ depends on X86_INTEL_LPSS || COMPILE_TEST |
|
++ select SND_SOC_ACPI |
|
++ select SND_SOC_WM5102 |
|
++ help |
|
++ This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR |
|
++ platforms with WM5102 audio codec. |
|
++ Say Y if you have such a device. |
|
++ If unsure select "N". |
|
++ |
|
+ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH |
|
+ tristate "Cherrytrail & Braswell with RT5672 codec" |
|
+ depends on I2C && ACPI |
|
+diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile |
|
+index a58e4d22e..86661357b 100644 |
|
+--- a/sound/soc/intel/boards/Makefile |
|
++++ b/sound/soc/intel/boards/Makefile |
|
+@@ -10,6 +10,7 @@ snd-soc-sst-sof-wm8804-objs := sof_wm8804.o |
|
+ snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o hda_dsp_common.o |
|
+ snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o |
|
+ snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o |
|
++snd-soc-sst-bytcr-wm5102-objs := bytcr_wm5102.o |
|
+ snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o |
|
+ snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o |
|
+ snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o |
|
+@@ -51,6 +52,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5650_MACH) += snd-soc-sst-bdw-rt5650-mach.o |
|
+ obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.o |
|
+ obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o |
|
+ obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o |
|
++obj-$(CONFIG_SND_SOC_INTEL_BYTCR_WM5102_MACH) += snd-soc-sst-bytcr-wm5102.o |
|
+ obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o |
|
+ obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o |
|
+ obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o |
|
+diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c |
|
+new file mode 100644 |
|
+index 000000000..f38850eb2 |
|
+--- /dev/null |
|
++++ b/sound/soc/intel/boards/bytcr_wm5102.c |
|
+@@ -0,0 +1,465 @@ |
|
++// SPDX-License-Identifier: GPL-2.0-only |
|
++/* |
|
++ * bytcr_wm5102.c - ASoc Machine driver for Intel Baytrail platforms with a |
|
++ * Wolfson Microelectronics WM5102 codec |
|
++ * |
|
++ * Copyright (C) 2020 Hans de Goede <[email protected]> |
|
++ * Loosely based on bytcr_rt5640.c which is: |
|
++ * Copyright (C) 2014-2020 Intel Corp |
|
++ * Author: Subhransu S. Prusty <[email protected]> |
|
++ */ |
|
++ |
|
++#include <linux/acpi.h> |
|
++#include <linux/clk.h> |
|
++#include <linux/device.h> |
|
++#include <linux/init.h> |
|
++#include <linux/module.h> |
|
++#include <linux/moduleparam.h> |
|
++#include <linux/platform_device.h> |
|
++#include <linux/slab.h> |
|
++#include <linux/spi/spi.h> |
|
++#include <sound/pcm.h> |
|
++#include <sound/pcm_params.h> |
|
++#include <sound/soc.h> |
|
++#include <sound/soc-acpi.h> |
|
++#include "../../codecs/wm5102.h" |
|
++#include "../atom/sst-atom-controls.h" |
|
++ |
|
++#define MCLK_FREQ 25000000 |
|
++ |
|
++#define WM5102_MAX_SYSCLK_4K 49152000 /* max sysclk for 4K family */ |
|
++#define WM5102_MAX_SYSCLK_11025 45158400 /* max sysclk for 11.025K family */ |
|
++ |
|
++struct byt_wm5102_private { |
|
++ struct clk *mclk; |
|
++ struct gpio_desc *spkvdd_en_gpio; |
|
++}; |
|
++ |
|
++static int byt_wm5102_spkvdd_power_event(struct snd_soc_dapm_widget *w, |
|
++ struct snd_kcontrol *kcontrol, int event) |
|
++{ |
|
++ struct snd_soc_card *card = w->dapm->card; |
|
++ struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card); |
|
++ |
|
++ gpiod_set_value_cansleep(priv->spkvdd_en_gpio, |
|
++ !!SND_SOC_DAPM_EVENT_ON(event)); |
|
++ |
|
++ return 0; |
|
++} |
|
++ |
|
++static int byt_wm5102_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, int rate) |
|
++{ |
|
++ struct snd_soc_component *codec_component = codec_dai->component; |
|
++ int sr_mult = ((rate % 4000) == 0) ? |
|
++ (WM5102_MAX_SYSCLK_4K / rate) : |
|
++ (WM5102_MAX_SYSCLK_11025 / rate); |
|
++ int ret; |
|
++ |
|
++ /* Reset FLL1 */ |
|
++ snd_soc_dai_set_pll(codec_dai, WM5102_FLL1_REFCLK, ARIZONA_FLL_SRC_NONE, 0, 0); |
|
++ snd_soc_dai_set_pll(codec_dai, WM5102_FLL1, ARIZONA_FLL_SRC_NONE, 0, 0); |
|
++ |
|
++ /* Configure the FLL1 PLL before selecting it */ |
|
++ ret = snd_soc_dai_set_pll(codec_dai, WM5102_FLL1, ARIZONA_CLK_SRC_MCLK1, |
|
++ MCLK_FREQ, rate * sr_mult); |
|
++ if (ret) { |
|
++ dev_err(codec_component->dev, "Error setting PLL: %d\n", ret); |
|
++ return ret; |
|
++ } |
|
++ |
|
++ ret = snd_soc_component_set_sysclk(codec_component, ARIZONA_CLK_SYSCLK, |
|
++ ARIZONA_CLK_SRC_FLL1, rate * sr_mult, |
|
++ SND_SOC_CLOCK_IN); |
|
++ if (ret) { |
|
++ dev_err(codec_component->dev, "Error setting SYSCLK: %d\n", ret); |
|
++ return ret; |
|
++ } |
|
++ |
|
++ ret = snd_soc_dai_set_sysclk(codec_dai, ARIZONA_CLK_SYSCLK, |
|
++ rate * 512, SND_SOC_CLOCK_IN); |
|
++ if (ret) { |
|
++ dev_err(codec_component->dev, "Error setting clock: %d\n", ret); |
|
++ return ret; |
|
++ } |
|
++ |
|
++ return 0; |
|
++} |
|
++ |
|
++static int platform_clock_control(struct snd_soc_dapm_widget *w, |
|
++ struct snd_kcontrol *k, int event) |
|
++{ |
|
++ struct snd_soc_dapm_context *dapm = w->dapm; |
|
++ struct snd_soc_card *card = dapm->card; |
|
++ struct snd_soc_dai *codec_dai; |
|
++ struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card); |
|
++ int ret; |
|
++ |
|
++ codec_dai = snd_soc_card_get_codec_dai(card, "wm5102-aif1"); |
|
++ if (!codec_dai) { |
|
++ dev_err(card->dev, "Error codec DAI not found\n"); |
|
++ return -EIO; |
|
++ } |
|
++ |
|
++ if (SND_SOC_DAPM_EVENT_ON(event)) { |
|
++ ret = clk_prepare_enable(priv->mclk); |
|
++ if (ret) { |
|
++ dev_err(card->dev, "Error enabling MCLK: %d\n", ret); |
|
++ return ret; |
|
++ } |
|
++ ret = byt_wm5102_prepare_and_enable_pll1(codec_dai, 48000); |
|
++ if (ret) { |
|
++ dev_err(card->dev, "Error setting codec sysclk: %d\n", ret); |
|
++ return ret; |
|
++ } |
|
++ } else { |
|
++ /* |
|
++ * The WM5102 has a separate 32KHz clock for jack-detect |
|
++ * so we can disable the PLL, followed by disabling the |
|
++ * platform clock which is the source-clock for the PLL. |
|
++ */ |
|
++ snd_soc_dai_set_pll(codec_dai, WM5102_FLL1, ARIZONA_FLL_SRC_NONE, 0, 0); |
|
++ clk_disable_unprepare(priv->mclk); |
|
++ } |
|
++ |
|
++ return 0; |
|
++} |
|
++ |
|
++static const struct snd_soc_dapm_widget byt_wm5102_widgets[] = { |
|
++ SND_SOC_DAPM_HP("Headphone", NULL), |
|
++ SND_SOC_DAPM_MIC("Headset Mic", NULL), |
|
++ SND_SOC_DAPM_MIC("Internal Mic", NULL), |
|
++ SND_SOC_DAPM_SPK("Speaker", NULL), |
|
++ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, |
|
++ platform_clock_control, SND_SOC_DAPM_PRE_PMU | |
|
++ SND_SOC_DAPM_POST_PMD), |
|
++ SND_SOC_DAPM_SUPPLY("Speaker VDD", SND_SOC_NOPM, 0, 0, |
|
++ byt_wm5102_spkvdd_power_event, |
|
++ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), |
|
++}; |
|
++ |
|
++static const struct snd_soc_dapm_route byt_wm5102_audio_map[] = { |
|
++ {"Headphone", NULL, "Platform Clock"}, |
|
++ {"Headset Mic", NULL, "Platform Clock"}, |
|
++ {"Internal Mic", NULL, "Platform Clock"}, |
|
++ {"Speaker", NULL, "Platform Clock"}, |
|
++ |
|
++ {"Speaker", NULL, "SPKOUTLP"}, |
|
++ {"Speaker", NULL, "SPKOUTLN"}, |
|
++ {"Speaker", NULL, "SPKOUTRP"}, |
|
++ {"Speaker", NULL, "SPKOUTRN"}, |
|
++ {"Speaker", NULL, "Speaker VDD"}, |
|
++ |
|
++ {"Headphone", NULL, "HPOUT1L"}, |
|
++ {"Headphone", NULL, "HPOUT1R"}, |
|
++ |
|
++ {"Internal Mic", NULL, "MICBIAS3"}, |
|
++ {"IN3L", NULL, "Internal Mic"}, |
|
++ |
|
++ /* |
|
++ * The Headset Mix uses MICBIAS1 or 2 depending on if a CTIA/OMTP Headset |
|
++ * is connected, as the MICBIAS is applied after the CTIA/OMTP cross-switch. |
|
++ */ |
|
++ {"Headset Mic", NULL, "MICBIAS1"}, |
|
++ {"Headset Mic", NULL, "MICBIAS2"}, |
|
++ {"IN1L", NULL, "Headset Mic"}, |
|
++ |
|
++ {"AIF1 Playback", NULL, "ssp0 Tx"}, |
|
++ {"ssp0 Tx", NULL, "modem_out"}, |
|
++ |
|
++ {"modem_in", NULL, "ssp0 Rx"}, |
|
++ {"ssp0 Rx", NULL, "AIF1 Capture"}, |
|
++}; |
|
++ |
|
++static const struct snd_kcontrol_new byt_wm5102_controls[] = { |
|
++ SOC_DAPM_PIN_SWITCH("Headphone"), |
|
++ SOC_DAPM_PIN_SWITCH("Headset Mic"), |
|
++ SOC_DAPM_PIN_SWITCH("Internal Mic"), |
|
++ SOC_DAPM_PIN_SWITCH("Speaker"), |
|
++}; |
|
++ |
|
++static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime) |
|
++{ |
|
++ struct snd_soc_card *card = runtime->card; |
|
++ struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card); |
|
++ int ret; |
|
++ |
|
++ card->dapm.idle_bias_off = true; |
|
++ |
|
++ ret = snd_soc_add_card_controls(card, byt_wm5102_controls, |
|
++ ARRAY_SIZE(byt_wm5102_controls)); |
|
++ if (ret) { |
|
++ dev_err(card->dev, "Error adding card controls: %d\n", ret); |
|
++ return ret; |
|
++ } |
|
++ |
|
++ /* |
|
++ * The firmware might enable the clock at boot (this information |
|
++ * may or may not be reflected in the enable clock register). |
|
++ * To change the rate we must disable the clock first to cover these |
|
++ * cases. Due to common clock framework restrictions that do not allow |
|
++ * to disable a clock that has not been enabled, we need to enable |
|
++ * the clock first. |
|
++ */ |
|
++ ret = clk_prepare_enable(priv->mclk); |
|
++ if (!ret) |
|
++ clk_disable_unprepare(priv->mclk); |
|
++ |
|
++ ret = clk_set_rate(priv->mclk, MCLK_FREQ); |
|
++ if (ret) { |
|
++ dev_err(card->dev, "Error setting MCLK rate: %d\n", ret); |
|
++ return ret; |
|
++ } |
|
++ |
|
++ return 0; |
|
++} |
|
++ |
|
++static const struct snd_soc_pcm_stream byt_wm5102_dai_params = { |
|
++ .formats = SNDRV_PCM_FMTBIT_S16_LE, |
|
++ .rate_min = 48000, |
|
++ .rate_max = 48000, |
|
++ .channels_min = 2, |
|
++ .channels_max = 2, |
|
++}; |
|
++ |
|
++static int byt_wm5102_codec_fixup(struct snd_soc_pcm_runtime *rtd, |
|
++ struct snd_pcm_hw_params *params) |
|
++{ |
|
++ struct snd_interval *rate = hw_param_interval(params, |
|
++ SNDRV_PCM_HW_PARAM_RATE); |
|
++ struct snd_interval *channels = hw_param_interval(params, |
|
++ SNDRV_PCM_HW_PARAM_CHANNELS); |
|
++ int ret; |
|
++ |
|
++ /* The DSP will covert the FE rate to 48k, stereo */ |
|
++ rate->min = 48000; |
|
++ rate->max = 48000; |
|
++ channels->min = 2; |
|
++ channels->max = 2; |
|
++ |
|
++ /* set SSP0 to 16-bit */ |
|
++ params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); |
|
++ |
|
++ /* |
|
++ * Default mode for SSP configuration is TDM 4 slot, override config |
|
++ * with explicit setting to I2S 2ch 16-bit. The word length is set with |
|
++ * dai_set_tdm_slot() since there is no other API exposed |
|
++ */ |
|
++ ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), |
|
++ SND_SOC_DAIFMT_I2S | |
|
++ SND_SOC_DAIFMT_NB_NF | |
|
++ SND_SOC_DAIFMT_CBS_CFS); |
|
++ if (ret) { |
|
++ dev_err(rtd->dev, "Error setting format to I2S: %d\n", ret); |
|
++ return ret; |
|
++ } |
|
++ |
|
++ ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 16); |
|
++ if (ret) { |
|
++ dev_err(rtd->dev, "Error setting I2S config: %d\n", ret); |
|
++ return ret; |
|
++ } |
|
++ |
|
++ return 0; |
|
++} |
|
++ |
|
++static int byt_wm5102_aif1_startup(struct snd_pcm_substream *substream) |
|
++{ |
|
++ return snd_pcm_hw_constraint_single(substream->runtime, |
|
++ SNDRV_PCM_HW_PARAM_RATE, 48000); |
|
++} |
|
++ |
|
++static const struct snd_soc_ops byt_wm5102_aif1_ops = { |
|
++ .startup = byt_wm5102_aif1_startup, |
|
++}; |
|
++ |
|
++SND_SOC_DAILINK_DEF(dummy, |
|
++ DAILINK_COMP_ARRAY(COMP_DUMMY())); |
|
++ |
|
++SND_SOC_DAILINK_DEF(media, |
|
++ DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai"))); |
|
++ |
|
++SND_SOC_DAILINK_DEF(deepbuffer, |
|
++ DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai"))); |
|
++ |
|
++SND_SOC_DAILINK_DEF(ssp0_port, |
|
++ DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port"))); |
|
++ |
|
++SND_SOC_DAILINK_DEF(ssp0_codec, |
|
++ DAILINK_COMP_ARRAY(COMP_CODEC( |
|
++ /* |
|
++ * Note there is no need to overwrite the codec-name as is done in |
|
++ * other bytcr machine drivers, because the codec is a MFD child-dev. |
|
++ */ |
|
++ "wm5102-codec", |
|
++ "wm5102-aif1"))); |
|
++ |
|
++SND_SOC_DAILINK_DEF(platform, |
|
++ DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform"))); |
|
++ |
|
++static struct snd_soc_dai_link byt_wm5102_dais[] = { |
|
++ [MERR_DPCM_AUDIO] = { |
|
++ .name = "Baytrail Audio Port", |
|
++ .stream_name = "Baytrail Audio", |
|
++ .nonatomic = true, |
|
++ .dynamic = 1, |
|
++ .dpcm_playback = 1, |
|
++ .dpcm_capture = 1, |
|
++ .ops = &byt_wm5102_aif1_ops, |
|
++ SND_SOC_DAILINK_REG(media, dummy, platform), |
|
++ |
|
++ }, |
|
++ [MERR_DPCM_DEEP_BUFFER] = { |
|
++ .name = "Deep-Buffer Audio Port", |
|
++ .stream_name = "Deep-Buffer Audio", |
|
++ .nonatomic = true, |
|
++ .dynamic = 1, |
|
++ .dpcm_playback = 1, |
|
++ .ops = &byt_wm5102_aif1_ops, |
|
++ SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), |
|
++ }, |
|
++ /* back ends */ |
|
++ { |
|
++ /* |
|
++ * This must be named SSP2-Codec even though this machine driver |
|
++ * always uses SSP0. Most machine drivers support both and dynamically |
|
++ * update the dailink to point to SSP0 or SSP2, while keeping the name |
|
++ * as "SSP2-Codec". The SOF tplg files hardcode the "SSP2-Codec" even |
|
++ * in the byt-foo-ssp0.tplg versions because the other machine-drivers |
|
++ * use "SSP2-Codec" even when SSP0 is used. |
|
++ */ |
|
++ .name = "SSP2-Codec", |
|
++ .id = 0, |
|
++ .no_pcm = 1, |
|
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
++ | SND_SOC_DAIFMT_CBS_CFS, |
|
++ .be_hw_params_fixup = byt_wm5102_codec_fixup, |
|
++ .nonatomic = true, |
|
++ .dpcm_playback = 1, |
|
++ .dpcm_capture = 1, |
|
++ .init = byt_wm5102_init, |
|
++ SND_SOC_DAILINK_REG(ssp0_port, ssp0_codec, platform), |
|
++ }, |
|
++}; |
|
++ |
|
++/* use space before codec name to simplify card ID, and simplify driver name */ |
|
++#define SOF_CARD_NAME "bytcht wm5102" /* card name will be 'sof-bytcht wm5102' */ |
|
++#define SOF_DRIVER_NAME "SOF" |
|
++ |
|
++#define CARD_NAME "bytcr-wm5102" |
|
++#define DRIVER_NAME NULL /* card name will be used for driver name */ |
|
++ |
|
++/* SoC card */ |
|
++static struct snd_soc_card byt_wm5102_card = { |
|
++ .owner = THIS_MODULE, |
|
++ .dai_link = byt_wm5102_dais, |
|
++ .num_links = ARRAY_SIZE(byt_wm5102_dais), |
|
++ .dapm_widgets = byt_wm5102_widgets, |
|
++ .num_dapm_widgets = ARRAY_SIZE(byt_wm5102_widgets), |
|
++ .dapm_routes = byt_wm5102_audio_map, |
|
++ .num_dapm_routes = ARRAY_SIZE(byt_wm5102_audio_map), |
|
++ .fully_routed = true, |
|
++}; |
|
++ |
|
++static int snd_byt_wm5102_mc_probe(struct platform_device *pdev) |
|
++{ |
|
++ char codec_name[SND_ACPI_I2C_ID_LEN]; |
|
++ struct device *dev = &pdev->dev; |
|
++ struct byt_wm5102_private *priv; |
|
++ struct snd_soc_acpi_mach *mach; |
|
++ const char *platform_name; |
|
++ struct acpi_device *adev; |
|
++ struct device *codec_dev; |
|
++ bool sof_parent; |
|
++ int ret; |
|
++ |
|
++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_ATOMIC); |
|
++ if (!priv) |
|
++ return -ENOMEM; |
|
++ |
|
++ /* Get MCLK */ |
|
++ priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3"); |
|
++ if (IS_ERR(priv->mclk)) |
|
++ return dev_err_probe(dev, PTR_ERR(priv->mclk), "getting pmc_plt_clk_3\n"); |
|
++ |
|
++ /* |
|
++ * Get speaker VDD enable GPIO: |
|
++ * 1. Get codec-device-name |
|
++ * 2. Get codec-device |
|
++ * 3. Get GPIO from codec-device |
|
++ */ |
|
++ mach = dev->platform_data; |
|
++ adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); |
|
++ if (!adev) { |
|
++ dev_err(dev, "Error cannot find acpi-dev for codec\n"); |
|
++ return -ENOENT; |
|
++ } |
|
++ snprintf(codec_name, sizeof(codec_name), "spi-%s", acpi_dev_name(adev)); |
|
++ put_device(&adev->dev); |
|
++ |
|
++ codec_dev = bus_find_device_by_name(&spi_bus_type, NULL, codec_name); |
|
++ if (!codec_dev) |
|
++ return -EPROBE_DEFER; |
|
++ |
|
++ /* Note no devm_ here since we call gpiod_get on codec_dev rather then dev */ |
|
++ priv->spkvdd_en_gpio = gpiod_get(codec_dev, "wlf,spkvdd-ena", GPIOD_OUT_LOW); |
|
++ put_device(codec_dev); |
|
++ |
|
++ if (IS_ERR(priv->spkvdd_en_gpio)) |
|
++ return dev_err_probe(dev, PTR_ERR(priv->spkvdd_en_gpio), "getting spkvdd-GPIO\n"); |
|
++ |
|
++ /* override platform name, if required */ |
|
++ byt_wm5102_card.dev = dev; |
|
++ platform_name = mach->mach_params.platform; |
|
++ ret = snd_soc_fixup_dai_links_platform_name(&byt_wm5102_card, platform_name); |
|
++ if (ret) |
|
++ goto out_put_gpio; |
|
++ |
|
++ /* set card and driver name and pm-ops */ |
|
++ sof_parent = snd_soc_acpi_sof_parent(dev); |
|
++ if (sof_parent) { |
|
++ byt_wm5102_card.name = SOF_CARD_NAME; |
|
++ byt_wm5102_card.driver_name = SOF_DRIVER_NAME; |
|
++ dev->driver->pm = &snd_soc_pm_ops; |
|
++ } else { |
|
++ byt_wm5102_card.name = CARD_NAME; |
|
++ byt_wm5102_card.driver_name = DRIVER_NAME; |
|
++ } |
|
++ |
|
++ snd_soc_card_set_drvdata(&byt_wm5102_card, priv); |
|
++ ret = devm_snd_soc_register_card(dev, &byt_wm5102_card); |
|
++ if (ret) { |
|
++ dev_err_probe(dev, ret, "registering card\n"); |
|
++ goto out_put_gpio; |
|
++ } |
|
++ |
|
++ platform_set_drvdata(pdev, &byt_wm5102_card); |
|
++ return 0; |
|
++ |
|
++out_put_gpio: |
|
++ gpiod_put(priv->spkvdd_en_gpio); |
|
++ return ret; |
|
++} |
|
++ |
|
++static int snd_byt_wm5102_mc_remove(struct platform_device *pdev) |
|
++{ |
|
++ struct snd_soc_card *card = platform_get_drvdata(pdev); |
|
++ struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card); |
|
++ |
|
++ gpiod_put(priv->spkvdd_en_gpio); |
|
++ return 0; |
|
++} |
|
++ |
|
++static struct platform_driver snd_byt_wm5102_mc_driver = { |
|
++ .driver = { |
|
++ .name = "bytcr_wm5102", |
|
++ }, |
|
++ .probe = snd_byt_wm5102_mc_probe, |
|
++ .remove = snd_byt_wm5102_mc_remove, |
|
++}; |
|
++ |
|
++module_platform_driver(snd_byt_wm5102_mc_driver); |
|
++ |
|
++MODULE_DESCRIPTION("ASoC Baytrail with WM5102 codec machine driver"); |
|
++MODULE_AUTHOR("Hans de Goede <[email protected]>"); |
|
++MODULE_LICENSE("GPL v2"); |
|
++MODULE_ALIAS("platform:bytcr_wm5102"); |
|
+diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c |
|
+index c348607b4..ec7932549 100644 |
|
+--- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c |
|
++++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c |
|
+@@ -154,6 +154,22 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { |
|
+ .sof_fw_filename = "sof-byt.ri", |
|
+ .sof_tplg_filename = "sof-byt-rt5651.tplg", |
|
+ }, |
|
++ { |
|
++ .id = "WM510204", |
|
++ .drv_name = "bytcr_wm5102", |
|
++ .fw_filename = "intel/fw_sst_0f28.bin", |
|
++ .board = "bytcr_wm5102", |
|
++ .sof_fw_filename = "sof-byt.ri", |
|
++ .sof_tplg_filename = "sof-byt-wm5102.tplg", |
|
++ }, |
|
++ { |
|
++ .id = "WM510205", |
|
++ .drv_name = "bytcr_wm5102", |
|
++ .fw_filename = "intel/fw_sst_0f28.bin", |
|
++ .board = "bytcr_wm5102", |
|
++ .sof_fw_filename = "sof-byt.ri", |
|
++ .sof_tplg_filename = "sof-byt-wm5102.tplg", |
|
++ }, |
|
+ { |
|
+ .id = "DLGS7212", |
|
+ .drv_name = "bytcht_da7213", |
|
+-- |
|
+2.29.2 |
|
+ |
|
+ |
|
+From c118900dff8d1dc0fbee69048d12e3554efd7e89 Mon Sep 17 00:00:00 2001 |
|
+From: Pierre-Louis Bossart <[email protected]> |
|
+Date: Thu, 12 Nov 2020 16:38:15 -0600 |
|
+Subject: [PATCH 6/6] ASoC: soc-acpi: add helper to identify parent driver. |
|
+ |
|
+Intel machine drivers are used by parent platform drivers based on |
|
+closed-source firmware (Atom/SST and catpt) and SOF-based ones. |
|
+ |
|
+In some cases for ACPI-based platforms, the behavior of machine |
|
+drivers needs to be modified depending on the parent type, typically |
|
+for card names and power management. |
|
+ |
|
+An initial solution based on passing a boolean flag as a platform |
|
+device parameter was tested earlier. Since it looked overkill, this |
|
+patch suggests instead a simple string comparison to identify an SOF |
|
+parent device/driver. |
|
+ |
|
+Suggested-by: Kai Vehmanen <[email protected]> |
|
+Signed-off-by: Pierre-Louis Bossart <[email protected]> |
|
+Reviewed-by: Ranjani Sridharan <[email protected]> |
|
+Reviewed-by: Rander Wang <[email protected]> |
|
+Reviewed-by: Guennadi Liakhovetski <[email protected]> |
|
+Link: https://lore.kernel.org/r/[email protected] |
|
+Signed-off-by: Mark Brown <[email protected]> |
|
+--- |
|
+ include/sound/soc-acpi.h | 6 ++++++ |
|
+ 1 file changed, 6 insertions(+) |
|
+ |
|
+diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h |
|
+index b16a844d1..9a43c44dc 100644 |
|
+--- a/include/sound/soc-acpi.h |
|
++++ b/include/sound/soc-acpi.h |
|
+@@ -171,4 +171,10 @@ struct snd_soc_acpi_codecs { |
|
+ u8 codecs[SND_SOC_ACPI_MAX_CODECS][ACPI_ID_LEN]; |
|
+ }; |
|
+ |
|
++static inline bool snd_soc_acpi_sof_parent(struct device *dev) |
|
++{ |
|
++ return dev->parent && dev->parent->driver && dev->parent->driver->name && |
|
++ !strcmp(dev->parent->driver->name, "sof-audio-acpi"); |
|
++} |
|
++ |
|
+ #endif |
|
+-- |
|
+2.29.2 |
|
+ |
|
diff --git a/Patchlist b/Patchlist |
|
index 29f117c52..d5403dbc0 100644 |
|
--- a/Patchlist |
|
+++ b/Patchlist |
|
@@ -96,3 +96,4 @@ |
|
0001-drm-panel-st7703-Assert-reset-prior-to-powering-down.patch |
|
0001-arm64-dts-sun50i-a64-pinephone-Enable-LCD-support-on.patch |
|
0001-arm64-dts-sun50i-a64-pinephone-Add-touchscreen-suppo.patch |
|
+0001-WM5102.patch |
|
diff --git a/filter-x86_64.sh b/filter-x86_64.sh |
|
index 1aa80f2e0..08b65440b 100644 |
|
--- a/filter-x86_64.sh |
|
+++ b/filter-x86_64.sh |
|
@@ -9,4 +9,6 @@ |
|
# modifications to the overrides below. If something should be removed across |
|
# all arches, remove it in the default instead of per-arch. |
|
|
|
-# Defaults work so no need to override |
|
+driverdirs="$driverdirs extcon regulator" |
|
+ |
|
+inputdrvs="$inputdrvs misc" |
|
diff --git a/filter-x86_64.sh.fedora b/filter-x86_64.sh.fedora |
|
index 1aa80f2e0..08b65440b 100644 |
|
--- a/filter-x86_64.sh.fedora |
|
+++ b/filter-x86_64.sh.fedora |
|
@@ -9,4 +9,6 @@ |
|
# modifications to the overrides below. If something should be removed across |
|
# all arches, remove it in the default instead of per-arch. |
|
|
|
-# Defaults work so no need to override |
|
+driverdirs="$driverdirs extcon regulator" |
|
+ |
|
+inputdrvs="$inputdrvs misc" |
|
diff --git a/kernel-local b/kernel-local |
|
index 8c32be5be..dfe520aac 100644 |
|
--- a/kernel-local |
|
+++ b/kernel-local |
|
@@ -1,2 +1,20 @@ |
|
# This file is intentionally left empty in the stock kernel. Its a nicety |
|
# added for those wanting to do custom rebuilds with altered config opts. |
|
+CONFIG_SND_SOC_INTEL_BYTCR_WM5102_MACH=m |
|
+ |
|
+CONFIG_MFD_ARIZONA=y |
|
+CONFIG_MFD_ARIZONA_I2C=m |
|
+CONFIG_MFD_ARIZONA_SPI=m |
|
+ |
|
+CONFIG_REGULATOR_ARIZONA_LDO1=m |
|
+ |
|
+CONFIG_GPIO_ARIZONA=m |
|
+CONFIG_MFD_CS47L24=y |
|
+CONFIG_MFD_WM5102=y |
|
+CONFIG_MFD_WM5110=y |
|
+CONFIG_MFD_WM8997=y |
|
+CONFIG_MFD_WM8998=y |
|
+ |
|
+CONFIG_EXTCON_ARIZONA=m |
|
+CONFIG_REGULATOR_ARIZONA_MICSUPP=m |
|
+CONFIG_INPUT_ARIZONA_HAPTICS=m |
|
diff --git a/kernel.spec b/kernel.spec |
|
index c4a7c26b7..7504e0726 100644 |
|
--- a/kernel.spec |
|
+++ b/kernel.spec |
|
@@ -58,7 +58,7 @@ Summary: The Linux kernel |
|
%global zcpu `nproc --all` |
|
%endif |
|
|
|
-# define buildid .local |
|
+%define buildid wm5102_1 |
|
|
|
%if 0%{?fedora} |
|
%define primary_target fedora |
|
@@ -852,6 +852,9 @@ Patch104: 0001-brcm-rpi4-fix-usb-numeration.patch |
|
# RPi-4 and wifi issues |
|
Patch105: arm-dts-rpi-4-disable-wifi-frequencies.patch |
|
|
|
+# Add wm5102 support |
|
+Patch200: 0001-WM5102.patch |
|
+ |
|
# END OF PATCH DEFINITIONS |
|
|
|
%endif |
|
-- |
|
2.29.2 |
|
|