|
From b2df58f937bf6d9ea3891361e5edc037672b20f9 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+jack-detect |
|
|
|
--- |
|
0001-YogaTablet2.patch | 2467 +++++++++++++++++++++++++++++++++++++++ |
|
filter-x86_64.sh.fedora | 4 +- |
|
kernel-local | 18 + |
|
kernel.spec | 4 +- |
|
4 files changed, 2491 insertions(+), 2 deletions(-) |
|
create mode 100644 0001-YogaTablet2.patch |
|
|
|
diff --git a/0001-YogaTablet2.patch b/0001-YogaTablet2.patch |
|
new file mode 100644 |
|
index 000000000..2b6c9160d |
|
--- /dev/null |
|
+++ b/0001-YogaTablet2.patch |
|
@@ -0,0 +1,2467 @@ |
|
+diff --git a/MAINTAINERS b/MAINTAINERS |
|
+index bfc1b86e3..9c33595d4 100644 |
|
+--- a/MAINTAINERS |
|
++++ b/MAINTAINERS |
|
+@@ -19237,7 +19237,6 @@ F: Documentation/devicetree/bindings/sound/wlf,arizona.yaml |
|
+ F: Documentation/hwmon/wm83??.rst |
|
+ F: arch/arm/mach-s3c/mach-crag6410* |
|
+ F: drivers/clk/clk-wm83*.c |
|
+-F: drivers/extcon/extcon-arizona.c |
|
+ F: drivers/gpio/gpio-*wm*.c |
|
+ F: drivers/gpio/gpio-arizona.c |
|
+ F: drivers/hwmon/wm83??-hwmon.c |
|
+@@ -19261,7 +19260,7 @@ F: include/linux/mfd/wm8400* |
|
+ F: include/linux/regulator/arizona* |
|
+ F: include/linux/wm97xx.h |
|
+ F: include/sound/wm????.h |
|
+-F: sound/soc/codecs/arizona.? |
|
++F: sound/soc/codecs/arizona* |
|
+ F: sound/soc/codecs/cs47l24* |
|
+ F: sound/soc/codecs/wm* |
|
+ |
|
+diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig |
|
+index af58ebca2..e3db936be 100644 |
|
+--- a/drivers/extcon/Kconfig |
|
++++ b/drivers/extcon/Kconfig |
|
+@@ -21,14 +21,6 @@ config EXTCON_ADC_JACK |
|
+ help |
|
+ Say Y here to enable extcon device driver based on ADC values. |
|
+ |
|
+-config EXTCON_ARIZONA |
|
+- tristate "Wolfson Arizona EXTCON support" |
|
+- depends on MFD_ARIZONA && INPUT && SND_SOC |
|
+- help |
|
+- Say Y here to enable support for external accessory detection |
|
+- with Wolfson Arizona devices. These are audio CODECs with |
|
+- advanced audio accessory detection support. |
|
+- |
|
+ config EXTCON_AXP288 |
|
+ tristate "X-Power AXP288 EXTCON support" |
|
+ depends on MFD_AXP20X && USB_SUPPORT && X86 && ACPI |
|
+diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile |
|
+index fe10a1b7d..1b390d934 100644 |
|
+--- a/drivers/extcon/Makefile |
|
++++ b/drivers/extcon/Makefile |
|
+@@ -6,7 +6,6 @@ |
|
+ obj-$(CONFIG_EXTCON) += extcon-core.o |
|
+ extcon-core-objs += extcon.o devres.o |
|
+ obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o |
|
+-obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o |
|
+ obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o |
|
+ obj-$(CONFIG_EXTCON_FSA9480) += extcon-fsa9480.o |
|
+ obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o |
|
+diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c |
|
+index cb6ec59a0..c61fe8423 100644 |
|
+--- a/drivers/input/misc/soc_button_array.c |
|
++++ b/drivers/input/misc/soc_button_array.c |
|
+@@ -94,6 +94,17 @@ static const struct dmi_system_id dmi_use_low_level_irq[] = { |
|
+ DMI_MATCH(DMI_PRODUCT_VERSION, "1051L"), |
|
+ }, |
|
+ }, |
|
++ { |
|
++ /* |
|
++ * Lenovo Yoga Tab2 1051F, something messes with the home-button |
|
++ * IRQ settings, leading to a non working home-button. |
|
++ */ |
|
++ .matches = { |
|
++ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), |
|
++ DMI_MATCH(DMI_PRODUCT_NAME, "60073"), |
|
++ DMI_MATCH(DMI_PRODUCT_VERSION, "1051F"), |
|
++ }, |
|
++ }, |
|
+ {} /* Terminating entry */ |
|
+ }; |
|
+ |
|
+diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c |
|
+index 000cb8202..ce6fe6de3 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; |
|
+@@ -892,11 +881,6 @@ static const char * const wm5102_supplies[] = { |
|
+ static const struct mfd_cell wm5102_devs[] = { |
|
+ { .name = "arizona-micsupp" }, |
|
+ { .name = "arizona-gpio" }, |
|
+- { |
|
+- .name = "arizona-extcon", |
|
+- .parent_supplies = wm5102_supplies, |
|
+- .num_parent_supplies = 1, /* We only need MICVDD */ |
|
+- }, |
|
+ { .name = "arizona-haptics" }, |
|
+ { .name = "arizona-pwm" }, |
|
+ { |
|
+@@ -909,11 +893,6 @@ static const struct mfd_cell wm5102_devs[] = { |
|
+ static const struct mfd_cell wm5110_devs[] = { |
|
+ { .name = "arizona-micsupp" }, |
|
+ { .name = "arizona-gpio" }, |
|
+- { |
|
+- .name = "arizona-extcon", |
|
+- .parent_supplies = wm5102_supplies, |
|
+- .num_parent_supplies = 1, /* We only need MICVDD */ |
|
+- }, |
|
+ { .name = "arizona-haptics" }, |
|
+ { .name = "arizona-pwm" }, |
|
+ { |
|
+@@ -950,11 +929,6 @@ static const char * const wm8997_supplies[] = { |
|
+ static const struct mfd_cell wm8997_devs[] = { |
|
+ { .name = "arizona-micsupp" }, |
|
+ { .name = "arizona-gpio" }, |
|
+- { |
|
+- .name = "arizona-extcon", |
|
+- .parent_supplies = wm8997_supplies, |
|
+- .num_parent_supplies = 1, /* We only need MICVDD */ |
|
+- }, |
|
+ { .name = "arizona-haptics" }, |
|
+ { .name = "arizona-pwm" }, |
|
+ { |
|
+@@ -967,11 +941,6 @@ static const struct mfd_cell wm8997_devs[] = { |
|
+ static const struct mfd_cell wm8998_devs[] = { |
|
+ { .name = "arizona-micsupp" }, |
|
+ { .name = "arizona-gpio" }, |
|
+- { |
|
+- .name = "arizona-extcon", |
|
+- .parent_supplies = wm5102_supplies, |
|
+- .num_parent_supplies = 1, /* We only need MICVDD */ |
|
+- }, |
|
+ { .name = "arizona-haptics" }, |
|
+ { .name = "arizona-pwm" }, |
|
+ { |
|
+diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c |
|
+index 4b58e3ad6..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) { |
|
+@@ -115,6 +117,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..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,22 +18,141 @@ |
|
+ #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); |
|
++ 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) { |
|
+@@ -75,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); |
|
+ } |
|
+ |
|
+@@ -102,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, |
|
+@@ -110,6 +239,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"); |
|
+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 |
|
+diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile |
|
+index d277f0366..2e976cfaa 100644 |
|
+--- a/sound/soc/codecs/Makefile |
|
++++ b/sound/soc/codecs/Makefile |
|
+@@ -43,7 +43,7 @@ snd-soc-ak4642-objs := ak4642.o |
|
+ snd-soc-ak4671-objs := ak4671.o |
|
+ snd-soc-ak5386-objs := ak5386.o |
|
+ snd-soc-ak5558-objs := ak5558.o |
|
+-snd-soc-arizona-objs := arizona.o |
|
++snd-soc-arizona-objs := arizona.o arizona-jack.o |
|
+ snd-soc-bd28623-objs := bd28623.o |
|
+ snd-soc-bt-sco-objs := bt-sco.o |
|
+ snd-soc-cpcap-objs := cpcap.o |
|
+diff --git a/drivers/extcon/extcon-arizona.c b/sound/soc/codecs/arizona-jack.c |
|
+similarity index 76% |
|
+rename from drivers/extcon/extcon-arizona.c |
|
+rename to sound/soc/codecs/arizona-jack.c |
|
+index aae82db54..9c15ddba6 100644 |
|
+--- a/drivers/extcon/extcon-arizona.c |
|
++++ b/sound/soc/codecs/arizona-jack.c |
|
+@@ -7,19 +7,17 @@ |
|
+ |
|
+ #include <linux/kernel.h> |
|
+ #include <linux/module.h> |
|
+-#include <linux/i2c.h> |
|
+ #include <linux/slab.h> |
|
+ #include <linux/interrupt.h> |
|
+ #include <linux/err.h> |
|
+ #include <linux/gpio/consumer.h> |
|
+ #include <linux/gpio.h> |
|
+ #include <linux/input.h> |
|
+-#include <linux/platform_device.h> |
|
+ #include <linux/pm_runtime.h> |
|
+ #include <linux/property.h> |
|
+ #include <linux/regulator/consumer.h> |
|
+-#include <linux/extcon-provider.h> |
|
+ |
|
++#include <sound/jack.h> |
|
+ #include <sound/soc.h> |
|
+ |
|
+ #include <linux/mfd/arizona/core.h> |
|
+@@ -27,8 +25,16 @@ |
|
+ #include <linux/mfd/arizona/registers.h> |
|
+ #include <dt-bindings/mfd/arizona.h> |
|
+ |
|
++#include "arizona.h" |
|
++ |
|
+ #define ARIZONA_MAX_MICD_RANGE 8 |
|
+ |
|
++/* |
|
++ * The hardware supports 8 ranges / buttons, but the snd-jack interface |
|
++ * only supports 6 buttons (button 0-5). |
|
++ */ |
|
++#define ARIZONA_MAX_MICD_BUTTONS 6 |
|
++ |
|
+ #define ARIZONA_MICD_CLAMP_MODE_JDL 0x4 |
|
+ #define ARIZONA_MICD_CLAMP_MODE_JDH 0x5 |
|
+ #define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9 |
|
+@@ -61,47 +67,6 @@ |
|
+ |
|
+ #define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8) |
|
+ |
|
+-struct arizona_extcon_info { |
|
+- struct device *dev; |
|
+- struct arizona *arizona; |
|
+- struct mutex lock; |
|
+- struct regulator *micvdd; |
|
+- struct input_dev *input; |
|
+- |
|
+- u16 last_jackdet; |
|
+- |
|
+- int micd_mode; |
|
+- const struct arizona_micd_config *micd_modes; |
|
+- int micd_num_modes; |
|
+- |
|
+- const struct arizona_micd_range *micd_ranges; |
|
+- int num_micd_ranges; |
|
+- |
|
+- bool micd_reva; |
|
+- bool micd_clamp; |
|
+- |
|
+- struct delayed_work hpdet_work; |
|
+- struct delayed_work micd_detect_work; |
|
+- struct delayed_work micd_timeout_work; |
|
+- |
|
+- bool hpdet_active; |
|
+- bool hpdet_done; |
|
+- bool hpdet_retried; |
|
+- |
|
+- int num_hpdet_res; |
|
+- unsigned int hpdet_res[3]; |
|
+- |
|
+- bool mic; |
|
+- bool detecting; |
|
+- int jack_flips; |
|
+- |
|
+- int hpdet_ip_version; |
|
+- |
|
+- struct extcon_dev *edev; |
|
+- |
|
+- struct gpio_desc *micd_pol_gpio; |
|
+-}; |
|
+- |
|
+ static const struct arizona_micd_config micd_default_modes[] = { |
|
+ { ARIZONA_ACCDET_SRC, 1, 0 }, |
|
+ { 0, 2, 1 }, |
|
+@@ -127,17 +92,9 @@ static const int arizona_micd_levels[] = { |
|
+ 1257, 30000, |
|
+ }; |
|
+ |
|
+-static const unsigned int arizona_cable[] = { |
|
+- EXTCON_MECHANICAL, |
|
+- EXTCON_JACK_MICROPHONE, |
|
+- EXTCON_JACK_HEADPHONE, |
|
+- EXTCON_JACK_LINE_OUT, |
|
+- EXTCON_NONE, |
|
+-}; |
|
+- |
|
+-static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info); |
|
++static void arizona_start_hpdet_acc_id(struct arizona_priv *info); |
|
+ |
|
+-static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info, |
|
++static void arizona_extcon_hp_clamp(struct arizona_priv *info, |
|
+ bool clamp) |
|
+ { |
|
+ struct arizona *arizona = info->arizona; |
|
+@@ -166,9 +123,8 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info, |
|
+ ARIZONA_HP_TEST_CTRL_1, |
|
+ ARIZONA_HP1_TST_CAP_SEL_MASK, |
|
+ cap_sel); |
|
+- if (ret != 0) |
|
+- dev_warn(arizona->dev, |
|
+- "Failed to set TST_CAP_SEL: %d\n", ret); |
|
++ if (ret) |
|
++ dev_warn(arizona->dev, "Failed to set TST_CAP_SEL: %d\n", ret); |
|
+ break; |
|
+ default: |
|
+ mask = ARIZONA_RMV_SHRT_HP1L; |
|
+@@ -187,24 +143,20 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info, |
|
+ ARIZONA_OUTPUT_ENABLES_1, |
|
+ ARIZONA_OUT1L_ENA | |
|
+ ARIZONA_OUT1R_ENA, 0); |
|
+- if (ret != 0) |
|
+- dev_warn(arizona->dev, |
|
+- "Failed to disable headphone outputs: %d\n", |
|
+- ret); |
|
++ if (ret) |
|
++ dev_warn(arizona->dev, "Failed to disable headphone outputs: %d\n", ret); |
|
+ } |
|
+ |
|
+ if (mask) { |
|
+ ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L, |
|
+ mask, val); |
|
+- if (ret != 0) |
|
+- dev_warn(arizona->dev, "Failed to do clamp: %d\n", |
|
+- ret); |
|
++ if (ret) |
|
++ dev_warn(arizona->dev, "Failed to do clamp: %d\n", ret); |
|
+ |
|
+ ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R, |
|
+ mask, val); |
|
+- if (ret != 0) |
|
+- dev_warn(arizona->dev, "Failed to do clamp: %d\n", |
|
+- ret); |
|
++ if (ret) |
|
++ dev_warn(arizona->dev, "Failed to do clamp: %d\n", ret); |
|
+ } |
|
+ |
|
+ /* Restore the desired state while not doing the clamp */ |
|
+@@ -213,16 +165,14 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info, |
|
+ ARIZONA_OUTPUT_ENABLES_1, |
|
+ ARIZONA_OUT1L_ENA | |
|
+ ARIZONA_OUT1R_ENA, arizona->hp_ena); |
|
+- if (ret != 0) |
|
+- dev_warn(arizona->dev, |
|
+- "Failed to restore headphone outputs: %d\n", |
|
+- ret); |
|
++ if (ret) |
|
++ dev_warn(arizona->dev, "Failed to restore headphone outputs: %d\n", ret); |
|
+ } |
|
+ |
|
+ snd_soc_dapm_mutex_unlock(arizona->dapm); |
|
+ } |
|
+ |
|
+-static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) |
|
++static void arizona_extcon_set_mode(struct arizona_priv *info, int mode) |
|
+ { |
|
+ struct arizona *arizona = info->arizona; |
|
+ |
|
+@@ -243,7 +193,7 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) |
|
+ dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode); |
|
+ } |
|
+ |
|
+-static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info) |
|
++static const char *arizona_extcon_get_micbias(struct arizona_priv *info) |
|
+ { |
|
+ switch (info->micd_modes[0].bias) { |
|
+ case 1: |
|
+@@ -257,7 +207,7 @@ static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info) |
|
+ } |
|
+ } |
|
+ |
|
+-static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info) |
|
++static void arizona_extcon_pulse_micbias(struct arizona_priv *info) |
|
+ { |
|
+ struct arizona *arizona = info->arizona; |
|
+ const char *widget = arizona_extcon_get_micbias(info); |
|
+@@ -266,23 +216,21 @@ static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info) |
|
+ int ret; |
|
+ |
|
+ ret = snd_soc_component_force_enable_pin(component, widget); |
|
+- if (ret != 0) |
|
+- dev_warn(arizona->dev, "Failed to enable %s: %d\n", |
|
+- widget, ret); |
|
++ if (ret) |
|
++ dev_warn(arizona->dev, "Failed to enable %s: %d\n", widget, ret); |
|
+ |
|
+ snd_soc_dapm_sync(dapm); |
|
+ |
|
+ if (!arizona->pdata.micd_force_micbias) { |
|
+ ret = snd_soc_component_disable_pin(component, widget); |
|
+- if (ret != 0) |
|
+- dev_warn(arizona->dev, "Failed to disable %s: %d\n", |
|
+- widget, ret); |
|
++ if (ret) |
|
++ dev_warn(arizona->dev, "Failed to disable %s: %d\n", widget, ret); |
|
+ |
|
+ snd_soc_dapm_sync(dapm); |
|
+ } |
|
+ } |
|
+ |
|
+-static void arizona_start_mic(struct arizona_extcon_info *info) |
|
++static void arizona_start_mic(struct arizona_priv *info) |
|
+ { |
|
+ struct arizona *arizona = info->arizona; |
|
+ bool change; |
|
+@@ -290,22 +238,17 @@ static void arizona_start_mic(struct arizona_extcon_info *info) |
|
+ unsigned int mode; |
|
+ |
|
+ /* Microphone detection can't use idle mode */ |
|
+- pm_runtime_get(info->dev); |
|
++ pm_runtime_get_sync(arizona->dev); |
|
+ |
|
+ if (info->detecting) { |
|
+ ret = regulator_allow_bypass(info->micvdd, false); |
|
+- if (ret != 0) { |
|
+- dev_err(arizona->dev, |
|
+- "Failed to regulate MICVDD: %d\n", |
|
+- ret); |
|
+- } |
|
++ if (ret) |
|
++ dev_err(arizona->dev, "Failed to regulate MICVDD: %d\n", ret); |
|
+ } |
|
+ |
|
+ ret = regulator_enable(info->micvdd); |
|
+- if (ret != 0) { |
|
+- dev_err(arizona->dev, "Failed to enable MICVDD: %d\n", |
|
+- ret); |
|
+- } |
|
++ if (ret) |
|
++ dev_err(arizona->dev, "Failed to enable MICVDD: %d\n", ret); |
|
+ |
|
+ if (info->micd_reva) { |
|
+ const struct reg_sequence reva[] = { |
|
+@@ -335,11 +278,11 @@ static void arizona_start_mic(struct arizona_extcon_info *info) |
|
+ dev_err(arizona->dev, "Failed to enable micd: %d\n", ret); |
|
+ } else if (!change) { |
|
+ regulator_disable(info->micvdd); |
|
+- pm_runtime_put_autosuspend(info->dev); |
|
++ pm_runtime_put_autosuspend(arizona->dev); |
|
+ } |
|
+ } |
|
+ |
|
+-static void arizona_stop_mic(struct arizona_extcon_info *info) |
|
++static void arizona_stop_mic(struct arizona_priv *info) |
|
+ { |
|
+ struct arizona *arizona = info->arizona; |
|
+ const char *widget = arizona_extcon_get_micbias(info); |
|
+@@ -355,10 +298,8 @@ static void arizona_stop_mic(struct arizona_extcon_info *info) |
|
+ dev_err(arizona->dev, "Failed to disable micd: %d\n", ret); |
|
+ |
|
+ ret = snd_soc_component_disable_pin(component, widget); |
|
+- if (ret != 0) |
|
+- dev_warn(arizona->dev, |
|
+- "Failed to disable %s: %d\n", |
|
+- widget, ret); |
|
++ if (ret) |
|
++ dev_warn(arizona->dev, "Failed to disable %s: %d\n", widget, ret); |
|
+ |
|
+ snd_soc_dapm_sync(dapm); |
|
+ |
|
+@@ -373,15 +314,13 @@ static void arizona_stop_mic(struct arizona_extcon_info *info) |
|
+ } |
|
+ |
|
+ ret = regulator_allow_bypass(info->micvdd, true); |
|
+- if (ret != 0) { |
|
+- dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", |
|
+- ret); |
|
+- } |
|
++ if (ret) |
|
++ dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", ret); |
|
+ |
|
+ if (change) { |
|
+ regulator_disable(info->micvdd); |
|
+- pm_runtime_mark_last_busy(info->dev); |
|
+- pm_runtime_put_autosuspend(info->dev); |
|
++ pm_runtime_mark_last_busy(arizona->dev); |
|
++ pm_runtime_put_autosuspend(arizona->dev); |
|
+ } |
|
+ } |
|
+ |
|
+@@ -407,24 +346,22 @@ static struct { |
|
+ { 1000, 10000 }, |
|
+ }; |
|
+ |
|
+-static int arizona_hpdet_read(struct arizona_extcon_info *info) |
|
++static int arizona_hpdet_read(struct arizona_priv *info) |
|
+ { |
|
+ struct arizona *arizona = info->arizona; |
|
+ unsigned int val, range; |
|
+ int ret; |
|
+ |
|
+ ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val); |
|
+- if (ret != 0) { |
|
+- dev_err(arizona->dev, "Failed to read HPDET status: %d\n", |
|
+- ret); |
|
++ if (ret) { |
|
++ dev_err(arizona->dev, "Failed to read HPDET status: %d\n", ret); |
|
+ return ret; |
|
+ } |
|
+ |
|
+ switch (info->hpdet_ip_version) { |
|
+ case 0: |
|
+ if (!(val & ARIZONA_HP_DONE)) { |
|
+- dev_err(arizona->dev, "HPDET did not complete: %x\n", |
|
+- val); |
|
++ dev_err(arizona->dev, "HPDET did not complete: %x\n", val); |
|
+ return -EAGAIN; |
|
+ } |
|
+ |
|
+@@ -433,15 +370,13 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) |
|
+ |
|
+ case 1: |
|
+ if (!(val & ARIZONA_HP_DONE_B)) { |
|
+- dev_err(arizona->dev, "HPDET did not complete: %x\n", |
|
+- val); |
|
++ dev_err(arizona->dev, "HPDET did not complete: %x\n", val); |
|
+ return -EAGAIN; |
|
+ } |
|
+ |
|
+ ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val); |
|
+- if (ret != 0) { |
|
+- dev_err(arizona->dev, "Failed to read HP value: %d\n", |
|
+- ret); |
|
++ if (ret) { |
|
++ dev_err(arizona->dev, "Failed to read HP value: %d\n", ret); |
|
+ return -EAGAIN; |
|
+ } |
|
+ |
|
+@@ -454,8 +389,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) |
|
+ (val < arizona_hpdet_b_ranges[range].threshold || |
|
+ val >= ARIZONA_HPDET_B_RANGE_MAX)) { |
|
+ range++; |
|
+- dev_dbg(arizona->dev, "Moving to HPDET range %d\n", |
|
+- range); |
|
++ dev_dbg(arizona->dev, "Moving to HPDET range %d\n", range); |
|
+ regmap_update_bits(arizona->regmap, |
|
+ ARIZONA_HEADPHONE_DETECT_1, |
|
+ ARIZONA_HP_IMPEDANCE_RANGE_MASK, |
|
+@@ -471,8 +405,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) |
|
+ return ARIZONA_HPDET_MAX; |
|
+ } |
|
+ |
|
+- dev_dbg(arizona->dev, "HPDET read %d in range %d\n", |
|
+- val, range); |
|
++ dev_dbg(arizona->dev, "HPDET read %d in range %d\n", val, range); |
|
+ |
|
+ val = arizona_hpdet_b_ranges[range].factor_b |
|
+ / ((val * 100) - |
|
+@@ -481,8 +414,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) |
|
+ |
|
+ case 2: |
|
+ if (!(val & ARIZONA_HP_DONE_B)) { |
|
+- dev_err(arizona->dev, "HPDET did not complete: %x\n", |
|
+- val); |
|
++ dev_err(arizona->dev, "HPDET did not complete: %x\n", val); |
|
+ return -EAGAIN; |
|
+ } |
|
+ |
|
+@@ -518,8 +450,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) |
|
+ break; |
|
+ |
|
+ default: |
|
+- dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n", |
|
+- info->hpdet_ip_version); |
|
++ dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n", info->hpdet_ip_version); |
|
+ return -EINVAL; |
|
+ } |
|
+ |
|
+@@ -527,7 +458,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) |
|
+ return val; |
|
+ } |
|
+ |
|
+-static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading, |
|
++static int arizona_hpdet_do_id(struct arizona_priv *info, int *reading, |
|
+ bool *mic) |
|
+ { |
|
+ struct arizona *arizona = info->arizona; |
|
+@@ -573,7 +504,7 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading, |
|
+ info->num_hpdet_res = 0; |
|
+ info->hpdet_retried = true; |
|
+ arizona_start_hpdet_acc_id(info); |
|
+- pm_runtime_put(info->dev); |
|
++ pm_runtime_put(arizona->dev); |
|
+ return -EAGAIN; |
|
+ } |
|
+ |
|
+@@ -597,11 +528,10 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading, |
|
+ |
|
+ static irqreturn_t arizona_hpdet_irq(int irq, void *data) |
|
+ { |
|
+- struct arizona_extcon_info *info = data; |
|
++ struct arizona_priv *info = data; |
|
+ struct arizona *arizona = info->arizona; |
|
+ int id_gpio = arizona->pdata.hpdet_id_gpio; |
|
+- unsigned int report = EXTCON_JACK_HEADPHONE; |
|
+- int ret, reading; |
|
++ int ret, reading, state, report; |
|
+ bool mic = false; |
|
+ |
|
+ mutex_lock(&info->lock); |
|
+@@ -614,12 +544,8 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) |
|
+ } |
|
+ |
|
+ /* If the cable was removed while measuring ignore the result */ |
|
+- ret = extcon_get_state(info->edev, EXTCON_MECHANICAL); |
|
+- if (ret < 0) { |
|
+- dev_err(arizona->dev, "Failed to check cable state: %d\n", |
|
+- ret); |
|
+- goto out; |
|
+- } else if (!ret) { |
|
++ state = info->jack->status & SND_JACK_MECHANICAL; |
|
++ if (!state) { |
|
+ dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n"); |
|
+ goto done; |
|
+ } |
|
+@@ -645,14 +571,11 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) |
|
+ |
|
+ /* Report high impedence cables as line outputs */ |
|
+ if (reading >= 5000) |
|
+- report = EXTCON_JACK_LINE_OUT; |
|
++ report = SND_JACK_LINEOUT; |
|
+ else |
|
+- report = EXTCON_JACK_HEADPHONE; |
|
++ report = SND_JACK_HEADPHONE; |
|
+ |
|
+- ret = extcon_set_state_sync(info->edev, report, true); |
|
+- if (ret != 0) |
|
+- dev_err(arizona->dev, "Failed to report HP/line: %d\n", |
|
+- ret); |
|
++ snd_soc_jack_report(info->jack, report, SND_JACK_LINEOUT | SND_JACK_HEADPHONE); |
|
+ |
|
+ done: |
|
+ /* Reset back to starting range */ |
|
+@@ -667,15 +590,17 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) |
|
+ gpio_set_value_cansleep(id_gpio, 0); |
|
+ |
|
+ /* If we have a mic then reenable MICDET */ |
|
+- if (mic || info->mic) |
|
++ if (state && (mic || info->mic)) |
|
+ arizona_start_mic(info); |
|
+ |
|
+ if (info->hpdet_active) { |
|
+- pm_runtime_put_autosuspend(info->dev); |
|
++ pm_runtime_put_autosuspend(arizona->dev); |
|
+ info->hpdet_active = false; |
|
+ } |
|
+ |
|
+- info->hpdet_done = true; |
|
++ /* Do not set hp_det done when the cable has been unplugged */ |
|
++ if (state) |
|
++ info->hpdet_done = true; |
|
+ |
|
+ out: |
|
+ mutex_unlock(&info->lock); |
|
+@@ -683,7 +608,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) |
|
+ return IRQ_HANDLED; |
|
+ } |
|
+ |
|
+-static void arizona_identify_headphone(struct arizona_extcon_info *info) |
|
++static void arizona_identify_headphone(struct arizona_priv *info) |
|
+ { |
|
+ struct arizona *arizona = info->arizona; |
|
+ int ret; |
|
+@@ -694,7 +619,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info) |
|
+ dev_dbg(arizona->dev, "Starting HPDET\n"); |
|
+ |
|
+ /* Make sure we keep the device enabled during the measurement */ |
|
+- pm_runtime_get(info->dev); |
|
++ pm_runtime_get_sync(arizona->dev); |
|
+ |
|
+ info->hpdet_active = true; |
|
+ |
|
+@@ -713,9 +638,8 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info) |
|
+ |
|
+ ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, |
|
+ ARIZONA_HP_POLL, ARIZONA_HP_POLL); |
|
+- if (ret != 0) { |
|
+- dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n", |
|
+- ret); |
|
++ if (ret) { |
|
++ dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n", ret); |
|
+ goto err; |
|
+ } |
|
+ |
|
+@@ -723,12 +647,11 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info) |
|
+ |
|
+ err: |
|
+ arizona_extcon_hp_clamp(info, false); |
|
+- pm_runtime_put_autosuspend(info->dev); |
|
++ pm_runtime_put_autosuspend(arizona->dev); |
|
+ |
|
+ /* Just report headphone */ |
|
+- ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true); |
|
+- if (ret != 0) |
|
+- dev_err(arizona->dev, "Failed to report headphone: %d\n", ret); |
|
++ snd_soc_jack_report(info->jack, SND_JACK_HEADPHONE, |
|
++ SND_JACK_LINEOUT | SND_JACK_HEADPHONE); |
|
+ |
|
+ if (info->mic) |
|
+ arizona_start_mic(info); |
|
+@@ -736,7 +659,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info) |
|
+ info->hpdet_active = false; |
|
+ } |
|
+ |
|
+-static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) |
|
++static void arizona_start_hpdet_acc_id(struct arizona_priv *info) |
|
+ { |
|
+ struct arizona *arizona = info->arizona; |
|
+ int hp_reading = 32; |
|
+@@ -746,7 +669,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) |
|
+ dev_dbg(arizona->dev, "Starting identification via HPDET\n"); |
|
+ |
|
+ /* Make sure we keep the device enabled during the measurement */ |
|
+- pm_runtime_get_sync(info->dev); |
|
++ pm_runtime_get_sync(arizona->dev); |
|
+ |
|
+ info->hpdet_active = true; |
|
+ |
|
+@@ -766,10 +689,8 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) |
|
+ ret = regmap_update_bits(arizona->regmap, |
|
+ ARIZONA_HEADPHONE_DETECT_1, |
|
+ ARIZONA_HP_POLL, ARIZONA_HP_POLL); |
|
+- if (ret != 0) { |
|
+- dev_err(arizona->dev, |
|
+- "Can't start HPDETL measurement: %d\n", |
|
+- ret); |
|
++ if (ret) { |
|
++ dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n", ret); |
|
+ goto err; |
|
+ } |
|
+ } else { |
|
+@@ -780,17 +701,16 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) |
|
+ |
|
+ err: |
|
+ /* Just report headphone */ |
|
+- ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true); |
|
+- if (ret != 0) |
|
+- dev_err(arizona->dev, "Failed to report headphone: %d\n", ret); |
|
++ snd_soc_jack_report(info->jack, SND_JACK_HEADPHONE, |
|
++ SND_JACK_LINEOUT | SND_JACK_HEADPHONE); |
|
+ |
|
+ info->hpdet_active = false; |
|
+ } |
|
+ |
|
+ static void arizona_micd_timeout_work(struct work_struct *work) |
|
+ { |
|
+- struct arizona_extcon_info *info = container_of(work, |
|
+- struct arizona_extcon_info, |
|
++ struct arizona_priv *info = container_of(work, |
|
++ struct arizona_priv, |
|
+ micd_timeout_work.work); |
|
+ |
|
+ mutex_lock(&info->lock); |
|
+@@ -804,7 +724,7 @@ static void arizona_micd_timeout_work(struct work_struct *work) |
|
+ mutex_unlock(&info->lock); |
|
+ } |
|
+ |
|
+-static int arizona_micd_adc_read(struct arizona_extcon_info *info) |
|
++static int arizona_micd_adc_read(struct arizona_priv *info) |
|
+ { |
|
+ struct arizona *arizona = info->arizona; |
|
+ unsigned int val; |
|
+@@ -815,9 +735,8 @@ static int arizona_micd_adc_read(struct arizona_extcon_info *info) |
|
+ ARIZONA_MICD_ENA, 0); |
|
+ |
|
+ ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val); |
|
+- if (ret != 0) { |
|
+- dev_err(arizona->dev, |
|
+- "Failed to read MICDET_ADCVAL: %d\n", ret); |
|
++ if (ret) { |
|
++ dev_err(arizona->dev, "Failed to read MICDET_ADCVAL: %d\n", ret); |
|
+ return ret; |
|
+ } |
|
+ |
|
+@@ -841,7 +760,7 @@ static int arizona_micd_adc_read(struct arizona_extcon_info *info) |
|
+ return val; |
|
+ } |
|
+ |
|
+-static int arizona_micd_read(struct arizona_extcon_info *info) |
|
++static int arizona_micd_read(struct arizona_priv *info) |
|
+ { |
|
+ struct arizona *arizona = info->arizona; |
|
+ unsigned int val = 0; |
|
+@@ -849,17 +768,15 @@ static int arizona_micd_read(struct arizona_extcon_info *info) |
|
+ |
|
+ for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) { |
|
+ ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); |
|
+- if (ret != 0) { |
|
+- dev_err(arizona->dev, |
|
+- "Failed to read MICDET: %d\n", ret); |
|
++ if (ret) { |
|
++ dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret); |
|
+ return ret; |
|
+ } |
|
+ |
|
+ dev_dbg(arizona->dev, "MICDET: %x\n", val); |
|
+ |
|
+ if (!(val & ARIZONA_MICD_VALID)) { |
|
+- dev_warn(arizona->dev, |
|
+- "Microphone detection state invalid\n"); |
|
++ dev_warn(arizona->dev, "Microphone detection state invalid\n"); |
|
+ return -EINVAL; |
|
+ } |
|
+ } |
|
+@@ -874,7 +791,7 @@ static int arizona_micd_read(struct arizona_extcon_info *info) |
|
+ |
|
+ static int arizona_micdet_reading(void *priv) |
|
+ { |
|
+- struct arizona_extcon_info *info = priv; |
|
++ struct arizona_priv *info = priv; |
|
+ struct arizona *arizona = info->arizona; |
|
+ int ret, val; |
|
+ |
|
+@@ -903,18 +820,12 @@ static int arizona_micdet_reading(void *priv) |
|
+ |
|
+ arizona_identify_headphone(info); |
|
+ |
|
+- ret = extcon_set_state_sync(info->edev, |
|
+- EXTCON_JACK_MICROPHONE, true); |
|
+- if (ret != 0) |
|
+- dev_err(arizona->dev, "Headset report failed: %d\n", |
|
+- ret); |
|
++ snd_soc_jack_report(info->jack, SND_JACK_MICROPHONE, SND_JACK_MICROPHONE); |
|
+ |
|
+ /* Don't need to regulate for button detection */ |
|
+ ret = regulator_allow_bypass(info->micvdd, true); |
|
+- if (ret != 0) { |
|
+- dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", |
|
+- ret); |
|
+- } |
|
++ if (ret) |
|
++ dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", ret); |
|
+ |
|
+ return 0; |
|
+ } |
|
+@@ -968,9 +879,9 @@ static int arizona_micdet_reading(void *priv) |
|
+ |
|
+ static int arizona_button_reading(void *priv) |
|
+ { |
|
+- struct arizona_extcon_info *info = priv; |
|
++ struct arizona_priv *info = priv; |
|
+ struct arizona *arizona = info->arizona; |
|
+- int val, key, lvl, i; |
|
++ int val, key, lvl; |
|
+ |
|
+ val = arizona_micd_read(info); |
|
+ if (val < 0) |
|
+@@ -987,27 +898,20 @@ static int arizona_button_reading(void *priv) |
|
+ lvl = val & ARIZONA_MICD_LVL_MASK; |
|
+ lvl >>= ARIZONA_MICD_LVL_SHIFT; |
|
+ |
|
+- for (i = 0; i < info->num_micd_ranges; i++) |
|
+- input_report_key(info->input, |
|
+- info->micd_ranges[i].key, 0); |
|
+- |
|
+ if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) { |
|
+- key = info->micd_ranges[ffs(lvl) - 1].key; |
|
+- input_report_key(info->input, key, 1); |
|
+- input_sync(info->input); |
|
++ key = ffs(lvl) - 1; |
|
++ snd_soc_jack_report(info->jack, |
|
++ SND_JACK_BTN_0 >> key, |
|
++ info->micd_button_mask); |
|
+ } else { |
|
+ dev_err(arizona->dev, "Button out of range\n"); |
|
+ } |
|
+ } else { |
|
+- dev_warn(arizona->dev, "Button with no mic: %x\n", |
|
+- val); |
|
++ dev_warn(arizona->dev, "Button with no mic: %x\n", val); |
|
+ } |
|
+ } else { |
|
+ dev_dbg(arizona->dev, "Mic button released\n"); |
|
+- for (i = 0; i < info->num_micd_ranges; i++) |
|
+- input_report_key(info->input, |
|
+- info->micd_ranges[i].key, 0); |
|
+- input_sync(info->input); |
|
++ snd_soc_jack_report(info->jack, 0, info->micd_button_mask); |
|
+ arizona_extcon_pulse_micbias(info); |
|
+ } |
|
+ |
|
+@@ -1016,24 +920,17 @@ static int arizona_button_reading(void *priv) |
|
+ |
|
+ static void arizona_micd_detect(struct work_struct *work) |
|
+ { |
|
+- struct arizona_extcon_info *info = container_of(work, |
|
+- struct arizona_extcon_info, |
|
++ struct arizona_priv *info = container_of(work, |
|
++ struct arizona_priv, |
|
+ micd_detect_work.work); |
|
+ struct arizona *arizona = info->arizona; |
|
+- int ret; |
|
+ |
|
+ cancel_delayed_work_sync(&info->micd_timeout_work); |
|
+ |
|
+ mutex_lock(&info->lock); |
|
+ |
|
+ /* If the cable was removed while measuring ignore the result */ |
|
+- ret = extcon_get_state(info->edev, EXTCON_MECHANICAL); |
|
+- if (ret < 0) { |
|
+- dev_err(arizona->dev, "Failed to check cable state: %d\n", |
|
+- ret); |
|
+- mutex_unlock(&info->lock); |
|
+- return; |
|
+- } else if (!ret) { |
|
++ if (!(info->jack->status & SND_JACK_MECHANICAL)) { |
|
+ dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n"); |
|
+ mutex_unlock(&info->lock); |
|
+ return; |
|
+@@ -1044,13 +941,13 @@ static void arizona_micd_detect(struct work_struct *work) |
|
+ else |
|
+ arizona_button_reading(info); |
|
+ |
|
+- pm_runtime_mark_last_busy(info->dev); |
|
++ pm_runtime_mark_last_busy(arizona->dev); |
|
+ mutex_unlock(&info->lock); |
|
+ } |
|
+ |
|
+ static irqreturn_t arizona_micdet(int irq, void *data) |
|
+ { |
|
+- struct arizona_extcon_info *info = data; |
|
++ struct arizona_priv *info = data; |
|
+ struct arizona *arizona = info->arizona; |
|
+ int debounce = arizona->pdata.micd_detect_debounce; |
|
+ |
|
+@@ -1074,8 +971,8 @@ static irqreturn_t arizona_micdet(int irq, void *data) |
|
+ |
|
+ static void arizona_hpdet_work(struct work_struct *work) |
|
+ { |
|
+- struct arizona_extcon_info *info = container_of(work, |
|
+- struct arizona_extcon_info, |
|
++ struct arizona_priv *info = container_of(work, |
|
++ struct arizona_priv, |
|
+ hpdet_work.work); |
|
+ |
|
+ mutex_lock(&info->lock); |
|
+@@ -1083,7 +980,7 @@ static void arizona_hpdet_work(struct work_struct *work) |
|
+ mutex_unlock(&info->lock); |
|
+ } |
|
+ |
|
+-static int arizona_hpdet_wait(struct arizona_extcon_info *info) |
|
++static int arizona_hpdet_wait(struct arizona_priv *info) |
|
+ { |
|
+ struct arizona *arizona = info->arizona; |
|
+ unsigned int val; |
|
+@@ -1093,8 +990,7 @@ static int arizona_hpdet_wait(struct arizona_extcon_info *info) |
|
+ ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, |
|
+ &val); |
|
+ if (ret) { |
|
+- dev_err(arizona->dev, |
|
+- "Failed to read HPDET state: %d\n", ret); |
|
++ dev_err(arizona->dev, "Failed to read HPDET state: %d\n", ret); |
|
+ return ret; |
|
+ } |
|
+ |
|
+@@ -1119,7 +1015,7 @@ static int arizona_hpdet_wait(struct arizona_extcon_info *info) |
|
+ |
|
+ static irqreturn_t arizona_jackdet(int irq, void *data) |
|
+ { |
|
+- struct arizona_extcon_info *info = data; |
|
++ struct arizona_priv *info = data; |
|
+ struct arizona *arizona = info->arizona; |
|
+ unsigned int val, present, mask; |
|
+ bool cancelled_hp, cancelled_mic; |
|
+@@ -1128,7 +1024,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) |
|
+ cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work); |
|
+ cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work); |
|
+ |
|
+- pm_runtime_get_sync(info->dev); |
|
++ pm_runtime_get_sync(arizona->dev); |
|
+ |
|
+ mutex_lock(&info->lock); |
|
+ |
|
+@@ -1144,11 +1040,10 @@ static irqreturn_t arizona_jackdet(int irq, void *data) |
|
+ } |
|
+ |
|
+ ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val); |
|
+- if (ret != 0) { |
|
+- dev_err(arizona->dev, "Failed to read jackdet status: %d\n", |
|
+- ret); |
|
++ if (ret) { |
|
++ dev_err(arizona->dev, "Failed to read jackdet status: %d\n", ret); |
|
+ mutex_unlock(&info->lock); |
|
+- pm_runtime_put_autosuspend(info->dev); |
|
++ pm_runtime_put_autosuspend(arizona->dev); |
|
+ return IRQ_NONE; |
|
+ } |
|
+ |
|
+@@ -1174,12 +1069,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) |
|
+ |
|
+ if (info->last_jackdet == present) { |
|
+ dev_dbg(arizona->dev, "Detected jack\n"); |
|
+- ret = extcon_set_state_sync(info->edev, |
|
+- EXTCON_MECHANICAL, true); |
|
+- |
|
+- if (ret != 0) |
|
+- dev_err(arizona->dev, "Mechanical report failed: %d\n", |
|
+- ret); |
|
++ snd_soc_jack_report(info->jack, SND_JACK_MECHANICAL, SND_JACK_MECHANICAL); |
|
+ |
|
+ info->detecting = true; |
|
+ info->mic = false; |
|
+@@ -1210,18 +1100,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) |
|
+ info->hpdet_done = false; |
|
+ info->hpdet_retried = false; |
|
+ |
|
+- for (i = 0; i < info->num_micd_ranges; i++) |
|
+- input_report_key(info->input, |
|
+- info->micd_ranges[i].key, 0); |
|
+- input_sync(info->input); |
|
+- |
|
+- for (i = 0; i < ARRAY_SIZE(arizona_cable) - 1; i++) { |
|
+- ret = extcon_set_state_sync(info->edev, |
|
+- arizona_cable[i], false); |
|
+- if (ret != 0) |
|
+- dev_err(arizona->dev, |
|
+- "Removal report failed: %d\n", ret); |
|
+- } |
|
++ snd_soc_jack_report(info->jack, 0, ARIZONA_JACK_MASK | info->micd_button_mask); |
|
+ |
|
+ /* |
|
+ * If the jack was removed during a headphone detection we |
|
+@@ -1248,8 +1127,8 @@ static irqreturn_t arizona_jackdet(int irq, void *data) |
|
+ |
|
+ mutex_unlock(&info->lock); |
|
+ |
|
+- pm_runtime_mark_last_busy(info->dev); |
|
+- pm_runtime_put_autosuspend(info->dev); |
|
++ pm_runtime_mark_last_busy(arizona->dev); |
|
++ pm_runtime_put_autosuspend(arizona->dev); |
|
+ |
|
+ return IRQ_HANDLED; |
|
+ } |
|
+@@ -1332,8 +1211,7 @@ static int arizona_extcon_device_get_pdata(struct device *dev, |
|
+ pdata->hpdet_channel = val; |
|
+ break; |
|
+ default: |
|
+- dev_err(arizona->dev, |
|
+- "Wrong wlf,hpdet-channel DT value %d\n", val); |
|
++ dev_err(arizona->dev, "Wrong wlf,hpdet-channel DT value %d\n", val); |
|
+ pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL; |
|
+ } |
|
+ |
|
+@@ -1375,41 +1253,24 @@ static int arizona_extcon_device_get_pdata(struct device *dev, |
|
+ return 0; |
|
+ } |
|
+ |
|
+-static int arizona_extcon_probe(struct platform_device *pdev) |
|
++int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev) |
|
+ { |
|
+- struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); |
|
++ struct arizona *arizona = info->arizona; |
|
+ struct arizona_pdata *pdata = &arizona->pdata; |
|
+- struct arizona_extcon_info *info; |
|
+- unsigned int val; |
|
+- unsigned int clamp_mode; |
|
+- int jack_irq_fall, jack_irq_rise; |
|
+- int ret, mode, i, j; |
|
+- |
|
+- if (!arizona->dapm || !arizona->dapm->card) |
|
+- return -EPROBE_DEFER; |
|
+- |
|
+- info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); |
|
+- if (!info) |
|
+- return -ENOMEM; |
|
++ int ret, mode; |
|
+ |
|
+ if (!dev_get_platdata(arizona->dev)) |
|
+- arizona_extcon_device_get_pdata(&pdev->dev, arizona); |
|
++ arizona_extcon_device_get_pdata(dev, arizona); |
|
+ |
|
+- info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD"); |
|
+- if (IS_ERR(info->micvdd)) { |
|
+- ret = PTR_ERR(info->micvdd); |
|
+- dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret); |
|
+- return ret; |
|
+- } |
|
++ info->micvdd = devm_regulator_get(dev, "MICVDD"); |
|
++ if (IS_ERR(info->micvdd)) |
|
++ return dev_err_probe(arizona->dev, PTR_ERR(info->micvdd), "getting MICVDD\n"); |
|
+ |
|
+ mutex_init(&info->lock); |
|
+- info->arizona = arizona; |
|
+- info->dev = &pdev->dev; |
|
+ info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS); |
|
+ INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work); |
|
+ INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect); |
|
+ INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work); |
|
+- platform_set_drvdata(pdev, info); |
|
+ |
|
+ switch (arizona->type) { |
|
+ case WM5102: |
|
+@@ -1443,29 +1304,6 @@ static int arizona_extcon_probe(struct platform_device *pdev) |
|
+ break; |
|
+ } |
|
+ |
|
+- info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable); |
|
+- if (IS_ERR(info->edev)) { |
|
+- dev_err(&pdev->dev, "failed to allocate extcon device\n"); |
|
+- return -ENOMEM; |
|
+- } |
|
+- |
|
+- ret = devm_extcon_dev_register(&pdev->dev, info->edev); |
|
+- if (ret < 0) { |
|
+- dev_err(arizona->dev, "extcon_dev_register() failed: %d\n", |
|
+- ret); |
|
+- return ret; |
|
+- } |
|
+- |
|
+- info->input = devm_input_allocate_device(&pdev->dev); |
|
+- if (!info->input) { |
|
+- dev_err(arizona->dev, "Can't allocate input dev\n"); |
|
+- ret = -ENOMEM; |
|
+- return ret; |
|
+- } |
|
+- |
|
+- info->input->name = "Headset"; |
|
+- info->input->phys = "arizona/extcon"; |
|
+- |
|
+ if (!pdata->micd_timeout) |
|
+ pdata->micd_timeout = DEFAULT_MICD_TIMEOUT; |
|
+ |
|
+@@ -1487,7 +1325,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) |
|
+ else |
|
+ mode = GPIOF_OUT_INIT_LOW; |
|
+ |
|
+- ret = devm_gpio_request_one(&pdev->dev, pdata->micd_pol_gpio, |
|
++ ret = devm_gpio_request_one(dev, pdata->micd_pol_gpio, |
|
+ mode, "MICD polarity"); |
|
+ if (ret != 0) { |
|
+ dev_err(arizona->dev, "Failed to request GPIO%d: %d\n", |
|
+@@ -1509,28 +1347,47 @@ static int arizona_extcon_probe(struct platform_device *pdev) |
|
+ */ |
|
+ info->micd_pol_gpio = gpiod_get_optional(arizona->dev, |
|
+ "wlf,micd-pol", |
|
+- GPIOD_OUT_LOW); |
|
++ mode); |
|
+ if (IS_ERR(info->micd_pol_gpio)) { |
|
+ ret = PTR_ERR(info->micd_pol_gpio); |
|
+- dev_err(arizona->dev, |
|
+- "Failed to get microphone polarity GPIO: %d\n", |
|
+- ret); |
|
++ dev_err_probe(arizona->dev, ret, "getting microphone polarity GPIO\n"); |
|
+ return ret; |
|
+ } |
|
+ } |
|
+ |
|
+ if (arizona->pdata.hpdet_id_gpio > 0) { |
|
+- ret = devm_gpio_request_one(&pdev->dev, |
|
+- arizona->pdata.hpdet_id_gpio, |
|
++ ret = devm_gpio_request_one(dev, arizona->pdata.hpdet_id_gpio, |
|
+ GPIOF_OUT_INIT_LOW, |
|
+ "HPDET"); |
|
+ if (ret != 0) { |
|
+ dev_err(arizona->dev, "Failed to request GPIO%d: %d\n", |
|
+ arizona->pdata.hpdet_id_gpio, ret); |
|
+- goto err_gpio; |
|
++ gpiod_put(info->micd_pol_gpio); |
|
++ return ret; |
|
+ } |
|
+ } |
|
+ |
|
++ return 0; |
|
++} |
|
++EXPORT_SYMBOL_GPL(arizona_jack_codec_dev_probe); |
|
++ |
|
++int arizona_jack_codec_dev_remove(struct arizona_priv *info) |
|
++{ |
|
++ gpiod_put(info->micd_pol_gpio); |
|
++ return 0; |
|
++} |
|
++EXPORT_SYMBOL_GPL(arizona_jack_codec_dev_remove); |
|
++ |
|
++static int arizona_jack_enable_jack_detect(struct arizona_priv *info, |
|
++ struct snd_soc_jack *jack) |
|
++{ |
|
++ struct arizona *arizona = info->arizona; |
|
++ struct arizona_pdata *pdata = &arizona->pdata; |
|
++ unsigned int val; |
|
++ unsigned int clamp_mode; |
|
++ int jack_irq_fall, jack_irq_rise; |
|
++ int ret, i, j; |
|
++ |
|
+ if (arizona->pdata.micd_bias_start_time) |
|
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, |
|
+ ARIZONA_MICD_BIAS_STARTTIME_MASK, |
|
+@@ -1568,19 +1425,18 @@ static int arizona_extcon_probe(struct platform_device *pdev) |
|
+ info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges); |
|
+ } |
|
+ |
|
+- if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) { |
|
+- dev_err(arizona->dev, "Too many MICD ranges: %d\n", |
|
+- arizona->pdata.num_micd_ranges); |
|
++ if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_BUTTONS) { |
|
++ dev_err(arizona->dev, "Too many MICD ranges: %d > %d\n", |
|
++ arizona->pdata.num_micd_ranges, ARIZONA_MAX_MICD_BUTTONS); |
|
++ return -EINVAL; |
|
+ } |
|
+ |
|
+ if (info->num_micd_ranges > 1) { |
|
+ for (i = 1; i < info->num_micd_ranges; i++) { |
|
+ if (info->micd_ranges[i - 1].max > |
|
+ info->micd_ranges[i].max) { |
|
+- dev_err(arizona->dev, |
|
+- "MICD ranges must be sorted\n"); |
|
+- ret = -EINVAL; |
|
+- goto err_gpio; |
|
++ dev_err(arizona->dev, "MICD ranges must be sorted\n"); |
|
++ return -EINVAL; |
|
+ } |
|
+ } |
|
+ } |
|
+@@ -1598,16 +1454,18 @@ static int arizona_extcon_probe(struct platform_device *pdev) |
|
+ if (j == ARIZONA_NUM_MICD_BUTTON_LEVELS) { |
|
+ dev_err(arizona->dev, "Unsupported MICD level %d\n", |
|
+ info->micd_ranges[i].max); |
|
+- ret = -EINVAL; |
|
+- goto err_gpio; |
|
++ return -EINVAL; |
|
+ } |
|
+ |
|
+ dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n", |
|
+ arizona_micd_levels[j], i); |
|
+ |
|
+ arizona_micd_set_level(arizona, i, j); |
|
+- input_set_capability(info->input, EV_KEY, |
|
+- info->micd_ranges[i].key); |
|
++ |
|
++ /* SND_JACK_BTN_# masks start with the most significant bit */ |
|
++ info->micd_button_mask |= SND_JACK_BTN_0 >> i; |
|
++ snd_jack_set_key(jack->jack, SND_JACK_BTN_0 >> i, |
|
++ info->micd_ranges[i].key); |
|
+ |
|
+ /* Enable reporting of that range */ |
|
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2, |
|
+@@ -1655,9 +1513,9 @@ static int arizona_extcon_probe(struct platform_device *pdev) |
|
+ |
|
+ arizona_extcon_set_mode(info, 0); |
|
+ |
|
+- pm_runtime_enable(&pdev->dev); |
|
+- pm_runtime_idle(&pdev->dev); |
|
+- pm_runtime_get_sync(&pdev->dev); |
|
++ info->jack = jack; |
|
++ |
|
++ pm_runtime_get_sync(arizona->dev); |
|
+ |
|
+ if (info->micd_clamp) { |
|
+ jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE; |
|
+@@ -1670,43 +1528,40 @@ static int arizona_extcon_probe(struct platform_device *pdev) |
|
+ ret = arizona_request_irq(arizona, jack_irq_rise, |
|
+ "JACKDET rise", arizona_jackdet, info); |
|
+ if (ret != 0) { |
|
+- dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n", |
|
+- ret); |
|
++ dev_err(arizona->dev, "Failed to get JACKDET rise IRQ: %d\n", ret); |
|
+ goto err_pm; |
|
+ } |
|
+ |
|
+ ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1); |
|
+ if (ret != 0) { |
|
+- dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n", |
|
+- ret); |
|
++ dev_err(arizona->dev, "Failed to set JD rise IRQ wake: %d\n", ret); |
|
+ goto err_rise; |
|
+ } |
|
+ |
|
+ ret = arizona_request_irq(arizona, jack_irq_fall, |
|
+ "JACKDET fall", arizona_jackdet, info); |
|
+ if (ret != 0) { |
|
+- dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret); |
|
++ dev_err(arizona->dev, "Failed to get JD fall IRQ: %d\n", ret); |
|
+ goto err_rise_wake; |
|
+ } |
|
+ |
|
+ ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1); |
|
+ if (ret != 0) { |
|
+- dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n", |
|
+- ret); |
|
++ dev_err(arizona->dev, "Failed to set JD fall IRQ wake: %d\n", ret); |
|
+ goto err_fall; |
|
+ } |
|
+ |
|
+ ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET, |
|
+ "MICDET", arizona_micdet, info); |
|
+ if (ret != 0) { |
|
+- dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret); |
|
++ dev_err(arizona->dev, "Failed to get MICDET IRQ: %d\n", ret); |
|
+ goto err_fall_wake; |
|
+ } |
|
+ |
|
+ ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET, |
|
+ "HPDET", arizona_hpdet_irq, info); |
|
+ if (ret != 0) { |
|
+- dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret); |
|
++ dev_err(arizona->dev, "Failed to get HPDET IRQ: %d\n", ret); |
|
+ goto err_micdet; |
|
+ } |
|
+ |
|
+@@ -1718,21 +1573,12 @@ static int arizona_extcon_probe(struct platform_device *pdev) |
|
+ |
|
+ ret = regulator_allow_bypass(info->micvdd, true); |
|
+ if (ret != 0) |
|
+- dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n", |
|
+- ret); |
|
+- |
|
+- ret = input_register_device(info->input); |
|
+- if (ret) { |
|
+- dev_err(&pdev->dev, "Can't register input device: %d\n", ret); |
|
+- goto err_hpdet; |
|
+- } |
|
++ dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n", ret); |
|
+ |
|
+- pm_runtime_put(&pdev->dev); |
|
++ pm_runtime_put(arizona->dev); |
|
+ |
|
+ return 0; |
|
+ |
|
+-err_hpdet: |
|
+- arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info); |
|
+ err_micdet: |
|
+ arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info); |
|
+ err_fall_wake: |
|
+@@ -1744,39 +1590,20 @@ static int arizona_extcon_probe(struct platform_device *pdev) |
|
+ err_rise: |
|
+ arizona_free_irq(arizona, jack_irq_rise, info); |
|
+ err_pm: |
|
+- pm_runtime_put(&pdev->dev); |
|
+- pm_runtime_disable(&pdev->dev); |
|
+-err_gpio: |
|
+- gpiod_put(info->micd_pol_gpio); |
|
++ pm_runtime_put(arizona->dev); |
|
++ info->jack = NULL; |
|
+ return ret; |
|
+ } |
|
+ |
|
+-static int arizona_extcon_remove(struct platform_device *pdev) |
|
++static int arizona_jack_disable_jack_detect(struct arizona_priv *info) |
|
+ { |
|
+- struct arizona_extcon_info *info = platform_get_drvdata(pdev); |
|
+ struct arizona *arizona = info->arizona; |
|
+ int jack_irq_rise, jack_irq_fall; |
|
+ bool change; |
|
+ int ret; |
|
+ |
|
+- ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, |
|
+- ARIZONA_MICD_ENA, 0, |
|
+- &change); |
|
+- if (ret < 0) { |
|
+- dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n", |
|
+- ret); |
|
+- } else if (change) { |
|
+- regulator_disable(info->micvdd); |
|
+- pm_runtime_put(info->dev); |
|
+- } |
|
+- |
|
+- gpiod_put(info->micd_pol_gpio); |
|
+- |
|
+- pm_runtime_disable(&pdev->dev); |
|
+- |
|
+- regmap_update_bits(arizona->regmap, |
|
+- ARIZONA_MICD_CLAMP_CONTROL, |
|
+- ARIZONA_MICD_CLAMP_MODE_MASK, 0); |
|
++ if (!info->jack) |
|
++ return 0; |
|
+ |
|
+ if (info->micd_clamp) { |
|
+ jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE; |
|
+@@ -1793,24 +1620,38 @@ static int arizona_extcon_remove(struct platform_device *pdev) |
|
+ arizona_free_irq(arizona, jack_irq_rise, info); |
|
+ arizona_free_irq(arizona, jack_irq_fall, info); |
|
+ cancel_delayed_work_sync(&info->hpdet_work); |
|
++ cancel_delayed_work_sync(&info->micd_detect_work); |
|
++ cancel_delayed_work_sync(&info->micd_timeout_work); |
|
++ |
|
++ ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, |
|
++ ARIZONA_MICD_ENA, 0, |
|
++ &change); |
|
++ if (ret < 0) { |
|
++ dev_err(arizona->dev, "Failed to disable micd on remove: %d\n", ret); |
|
++ } else if (change) { |
|
++ regulator_disable(info->micvdd); |
|
++ pm_runtime_put(arizona->dev); |
|
++ } |
|
++ |
|
++ regmap_update_bits(arizona->regmap, |
|
++ ARIZONA_MICD_CLAMP_CONTROL, |
|
++ ARIZONA_MICD_CLAMP_MODE_MASK, 0); |
|
+ regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, |
|
+ ARIZONA_JD1_ENA, 0); |
|
+ arizona_clk32k_disable(arizona); |
|
++ info->jack = NULL; |
|
+ |
|
+ return 0; |
|
+ } |
|
+ |
|
+-static struct platform_driver arizona_extcon_driver = { |
|
+- .driver = { |
|
+- .name = "arizona-extcon", |
|
+- }, |
|
+- .probe = arizona_extcon_probe, |
|
+- .remove = arizona_extcon_remove, |
|
+-}; |
|
+- |
|
+-module_platform_driver(arizona_extcon_driver); |
|
++int arizona_jack_set_jack(struct snd_soc_component *component, |
|
++ struct snd_soc_jack *jack, void *data) |
|
++{ |
|
++ struct arizona_priv *info = snd_soc_component_get_drvdata(component); |
|
+ |
|
+-MODULE_DESCRIPTION("Arizona Extcon driver"); |
|
+-MODULE_AUTHOR("Mark Brown <[email protected]>"); |
|
+-MODULE_LICENSE("GPL"); |
|
+-MODULE_ALIAS("platform:extcon-arizona"); |
|
++ if (jack) |
|
++ return arizona_jack_enable_jack_detect(info, jack); |
|
++ else |
|
++ return arizona_jack_disable_jack_detect(info); |
|
++} |
|
++EXPORT_SYMBOL_GPL(arizona_jack_set_jack); |
|
+diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h |
|
+index b893d3e4c..173ebd0bf 100644 |
|
+--- a/sound/soc/codecs/arizona.h |
|
++++ b/sound/soc/codecs/arizona.h |
|
+@@ -91,6 +91,41 @@ struct arizona_priv { |
|
+ unsigned int dvfs_reqs; |
|
+ struct mutex dvfs_lock; |
|
+ bool dvfs_cached; |
|
++ |
|
++ /* Variables used by arizona-jack.c code */ |
|
++ struct mutex lock; |
|
++ struct delayed_work hpdet_work; |
|
++ struct delayed_work micd_detect_work; |
|
++ struct delayed_work micd_timeout_work; |
|
++ struct snd_soc_jack *jack; |
|
++ struct regulator *micvdd; |
|
++ struct gpio_desc *micd_pol_gpio; |
|
++ |
|
++ u16 last_jackdet; |
|
++ |
|
++ int micd_mode; |
|
++ const struct arizona_micd_config *micd_modes; |
|
++ int micd_num_modes; |
|
++ |
|
++ int micd_button_mask; |
|
++ const struct arizona_micd_range *micd_ranges; |
|
++ int num_micd_ranges; |
|
++ |
|
++ bool micd_reva; |
|
++ bool micd_clamp; |
|
++ |
|
++ bool hpdet_active; |
|
++ bool hpdet_done; |
|
++ bool hpdet_retried; |
|
++ |
|
++ bool mic; |
|
++ bool detecting; |
|
++ |
|
++ int num_hpdet_res; |
|
++ unsigned int hpdet_res[3]; |
|
++ |
|
++ int jack_flips; |
|
++ int hpdet_ip_version; |
|
+ }; |
|
+ |
|
+ struct arizona_voice_trigger_info { |
|
+@@ -222,6 +257,9 @@ extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; |
|
+ #define ARIZONA_RATE_ENUM_SIZE 4 |
|
+ #define ARIZONA_SAMPLE_RATE_ENUM_SIZE 14 |
|
+ |
|
++/* SND_JACK_* mask for supported cable/switch types */ |
|
++#define ARIZONA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_MECHANICAL) |
|
++ |
|
+ extern const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE]; |
|
+ extern const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE]; |
|
+ extern const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE]; |
|
+@@ -351,4 +389,10 @@ static inline int arizona_unregister_notifier(struct snd_soc_component *componen |
|
+ |
|
+ int arizona_of_get_audio_pdata(struct arizona *arizona); |
|
+ |
|
++int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev); |
|
++int arizona_jack_codec_dev_remove(struct arizona_priv *info); |
|
++ |
|
++int arizona_jack_set_jack(struct snd_soc_component *component, |
|
++ struct snd_soc_jack *jack, void *data); |
|
++ |
|
+ #endif |
|
+diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c |
|
+index 70d353b63..b77595fb3 100644 |
|
+--- a/sound/soc/codecs/wm5102.c |
|
++++ b/sound/soc/codecs/wm5102.c |
|
+@@ -2004,6 +2004,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm5102 = { |
|
+ .remove = wm5102_component_remove, |
|
+ .set_sysclk = arizona_set_sysclk, |
|
+ .set_pll = wm5102_set_fll, |
|
++ .set_jack = arizona_jack_set_jack, |
|
+ .name = DRV_NAME, |
|
+ .compress_ops = &wm5102_compress_ops, |
|
+ .controls = wm5102_snd_controls, |
|
+@@ -2057,6 +2058,11 @@ static int wm5102_probe(struct platform_device *pdev) |
|
+ if (ret != 0) |
|
+ return ret; |
|
+ |
|
++ /* This may return -EPROBE_DEFER, so do this early on */ |
|
++ ret = arizona_jack_codec_dev_probe(&wm5102->core, &pdev->dev); |
|
++ if (ret) |
|
++ return ret; |
|
++ |
|
+ for (i = 0; i < ARRAY_SIZE(wm5102->fll); i++) |
|
+ wm5102->fll[i].vco_mult = 1; |
|
+ |
|
+@@ -2089,7 +2095,7 @@ static int wm5102_probe(struct platform_device *pdev) |
|
+ wm5102); |
|
+ if (ret != 0) { |
|
+ dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); |
|
+- return ret; |
|
++ goto err_jack_codec_dev; |
|
+ } |
|
+ |
|
+ ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 1); |
|
+@@ -2123,6 +2129,8 @@ static int wm5102_probe(struct platform_device *pdev) |
|
+ err_dsp_irq: |
|
+ arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0); |
|
+ arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102); |
|
++err_jack_codec_dev: |
|
++ arizona_jack_codec_dev_remove(&wm5102->core); |
|
+ |
|
+ return ret; |
|
+ } |
|
+@@ -2141,6 +2149,8 @@ static int wm5102_remove(struct platform_device *pdev) |
|
+ arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0); |
|
+ arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102); |
|
+ |
|
++ arizona_jack_codec_dev_remove(&wm5102->core); |
|
++ |
|
+ return 0; |
|
+ } |
|
+ |
|
+diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c |
|
+index 4238929b2..ef22051a3 100644 |
|
+--- a/sound/soc/codecs/wm5110.c |
|
++++ b/sound/soc/codecs/wm5110.c |
|
+@@ -2370,6 +2370,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm5110 = { |
|
+ .remove = wm5110_component_remove, |
|
+ .set_sysclk = arizona_set_sysclk, |
|
+ .set_pll = wm5110_set_fll, |
|
++ .set_jack = arizona_jack_set_jack, |
|
+ .name = DRV_NAME, |
|
+ .compress_ops = &wm5110_compress_ops, |
|
+ .controls = wm5110_snd_controls, |
|
+@@ -2424,6 +2425,11 @@ static int wm5110_probe(struct platform_device *pdev) |
|
+ return ret; |
|
+ } |
|
+ |
|
++ /* This may return -EPROBE_DEFER, so do this early on */ |
|
++ ret = arizona_jack_codec_dev_probe(&wm5110->core, &pdev->dev); |
|
++ if (ret) |
|
++ return ret; |
|
++ |
|
+ for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++) |
|
+ wm5110->fll[i].vco_mult = 3; |
|
+ |
|
+@@ -2456,7 +2462,7 @@ static int wm5110_probe(struct platform_device *pdev) |
|
+ wm5110); |
|
+ if (ret != 0) { |
|
+ dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); |
|
+- return ret; |
|
++ goto err_jack_codec_dev; |
|
+ } |
|
+ |
|
+ ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 1); |
|
+@@ -2490,6 +2496,8 @@ static int wm5110_probe(struct platform_device *pdev) |
|
+ err_dsp_irq: |
|
+ arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0); |
|
+ arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110); |
|
++err_jack_codec_dev: |
|
++ arizona_jack_codec_dev_remove(&wm5110->core); |
|
+ |
|
+ return ret; |
|
+ } |
|
+@@ -2510,6 +2518,8 @@ static int wm5110_remove(struct platform_device *pdev) |
|
+ arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0); |
|
+ arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110); |
|
+ |
|
++ arizona_jack_codec_dev_remove(&wm5110->core); |
|
++ |
|
+ return 0; |
|
+ } |
|
+ |
|
+diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c |
|
+index 229f2986c..4f5a84896 100644 |
|
+--- a/sound/soc/codecs/wm8997.c |
|
++++ b/sound/soc/codecs/wm8997.c |
|
+@@ -1096,6 +1096,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm8997 = { |
|
+ .remove = wm8997_component_remove, |
|
+ .set_sysclk = arizona_set_sysclk, |
|
+ .set_pll = wm8997_set_fll, |
|
++ .set_jack = arizona_jack_set_jack, |
|
+ .controls = wm8997_snd_controls, |
|
+ .num_controls = ARRAY_SIZE(wm8997_snd_controls), |
|
+ .dapm_widgets = wm8997_dapm_widgets, |
|
+@@ -1132,6 +1133,11 @@ static int wm8997_probe(struct platform_device *pdev) |
|
+ |
|
+ arizona_init_dvfs(&wm8997->core); |
|
+ |
|
++ /* This may return -EPROBE_DEFER, so do this early on */ |
|
++ ret = arizona_jack_codec_dev_probe(&wm8997->core, &pdev->dev); |
|
++ if (ret) |
|
++ return ret; |
|
++ |
|
+ for (i = 0; i < ARRAY_SIZE(wm8997->fll); i++) |
|
+ wm8997->fll[i].vco_mult = 1; |
|
+ |
|
+@@ -1163,10 +1169,10 @@ static int wm8997_probe(struct platform_device *pdev) |
|
+ |
|
+ ret = arizona_init_vol_limit(arizona); |
|
+ if (ret < 0) |
|
+- return ret; |
|
++ goto err_jack_codec_dev; |
|
+ ret = arizona_init_spk_irqs(arizona); |
|
+ if (ret < 0) |
|
+- return ret; |
|
++ goto err_jack_codec_dev; |
|
+ |
|
+ ret = devm_snd_soc_register_component(&pdev->dev, |
|
+ &soc_component_dev_wm8997, |
|
+@@ -1181,6 +1187,8 @@ static int wm8997_probe(struct platform_device *pdev) |
|
+ |
|
+ err_spk_irqs: |
|
+ arizona_free_spk_irqs(arizona); |
|
++err_jack_codec_dev: |
|
++ arizona_jack_codec_dev_remove(&wm8997->core); |
|
+ |
|
+ return ret; |
|
+ } |
|
+@@ -1194,6 +1202,8 @@ static int wm8997_remove(struct platform_device *pdev) |
|
+ |
|
+ arizona_free_spk_irqs(arizona); |
|
+ |
|
++ arizona_jack_codec_dev_remove(&wm8997->core); |
|
++ |
|
+ return 0; |
|
+ } |
|
+ |
|
+diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c |
|
+index 541325429..f74af1c46 100644 |
|
+--- a/sound/soc/codecs/wm8998.c |
|
++++ b/sound/soc/codecs/wm8998.c |
|
+@@ -1316,6 +1316,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm8998 = { |
|
+ .remove = wm8998_component_remove, |
|
+ .set_sysclk = arizona_set_sysclk, |
|
+ .set_pll = wm8998_set_fll, |
|
++ .set_jack = arizona_jack_set_jack, |
|
+ .controls = wm8998_snd_controls, |
|
+ .num_controls = ARRAY_SIZE(wm8998_snd_controls), |
|
+ .dapm_widgets = wm8998_dapm_widgets, |
|
+@@ -1350,6 +1351,11 @@ static int wm8998_probe(struct platform_device *pdev) |
|
+ wm8998->core.arizona = arizona; |
|
+ wm8998->core.num_inputs = 3; /* IN1L, IN1R, IN2 */ |
|
+ |
|
++ /* This may return -EPROBE_DEFER, so do this early on */ |
|
++ ret = arizona_jack_codec_dev_probe(&wm8998->core, &pdev->dev); |
|
++ if (ret) |
|
++ return ret; |
|
++ |
|
+ for (i = 0; i < ARRAY_SIZE(wm8998->fll); i++) |
|
+ wm8998->fll[i].vco_mult = 1; |
|
+ |
|
+@@ -1392,6 +1398,7 @@ static int wm8998_probe(struct platform_device *pdev) |
|
+ arizona_free_spk_irqs(arizona); |
|
+ err_pm_disable: |
|
+ pm_runtime_disable(&pdev->dev); |
|
++ arizona_jack_codec_dev_remove(&wm8998->core); |
|
+ |
|
+ return ret; |
|
+ } |
|
+@@ -1405,6 +1412,8 @@ static int wm8998_remove(struct platform_device *pdev) |
|
+ |
|
+ arizona_free_spk_irqs(arizona); |
|
+ |
|
++ arizona_jack_codec_dev_remove(&wm8998->core); |
|
++ |
|
+ return 0; |
|
+ } |
|
+ |
|
+diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig |
|
+index b58b9b60d..d1d28129a 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 5f03e484b..616c5fbab 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..cdfe203ed |
|
+--- /dev/null |
|
++++ b/sound/soc/intel/boards/bytcr_wm5102.c |
|
+@@ -0,0 +1,491 @@ |
|
++// 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/jack.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 snd_soc_jack jack; |
|
++ 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 struct snd_soc_jack_pin byt_wm5102_pins[] = { |
|
++ { |
|
++ .pin = "Headphone", |
|
++ .mask = SND_JACK_HEADPHONE, |
|
++ }, |
|
++ { |
|
++ .pin = "Headset Mic", |
|
++ .mask = SND_JACK_MICROPHONE, |
|
++ }, |
|
++}; |
|
++ |
|
++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); |
|
++ struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component; |
|
++ int ret, jack_type; |
|
++ |
|
++ 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; |
|
++ } |
|
++ |
|
++ jack_type = ARIZONA_JACK_MASK | SND_JACK_BTN_0 | SND_JACK_BTN_1 | |
|
++ SND_JACK_BTN_2 | SND_JACK_BTN_3; |
|
++ ret = snd_soc_card_jack_new(card, "Headset", jack_type, |
|
++ &priv->jack, byt_wm5102_pins, |
|
++ ARRAY_SIZE(byt_wm5102_pins)); |
|
++ if (ret) { |
|
++ dev_err(card->dev, "Error creating jack: %d\n", ret); |
|
++ return ret; |
|
++ } |
|
++ |
|
++ snd_soc_component_set_jack(component, &priv->jack, NULL); |
|
++ |
|
++ 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", |
|
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 1da3bc3c5..181aa0542 100755 |
|
--- a/kernel.spec |
|
+++ b/kernel.spec |
|
@@ -95,7 +95,7 @@ Summary: The Linux kernel |
|
%global zcpu `nproc --all` |
|
%endif |
|
|
|
-# define buildid .local |
|
+%define buildid yogatablet2_0 |
|
|
|
|
|
%if 0%{?fedora} |
|
@@ -759,6 +759,7 @@ Source4000: README.rst |
|
Patch1: patch-%{stableversion}-redhat.patch |
|
%endif |
|
|
|
+Patch200: 0001-YogaTablet2.patch |
|
# empty final patch to facilitate testing of kernel patches |
|
Patch999999: linux-kernel-test.patch |
|
|
|
@@ -1262,6 +1263,7 @@ cp -a %{SOURCE1} . |
|
ApplyOptionalPatch patch-%{stableversion}-redhat.patch |
|
%endif |
|
|
|
+ApplyOptionalPatch 0001-YogaTablet2.patch |
|
ApplyOptionalPatch linux-kernel-test.patch |
|
|
|
# END OF PATCH APPLICATIONS |
|
-- |
|
2.29.2 |
|
|