[alsa-devel] [PATCH 00/19] ASoC: rt5640: Add jack-detect and button-press support
Hi All,
This series has been long in the making, but it is finally ready now. This series adds jack-detect support for rt5640 using devices.
This is modelled after the recent rt5651 codec- and bytcr-rt5651 machine- driver jack-detect changes (which were actually based on a WIP version of this series).
As discussed on the list already unfortunately there are no really good defaults which work everywhere, so patch 18 adds quirks for 10 devices, I've decided to do this in one go rather then split this into 10 patches.
Patch 19 makes the bytcr-rt5640 set a longname based on the speaker and input-map quirks, so that userspace can pick a correct UCM profile based on the longname with working jack-detect based input / output switching. I've matching patches adding UCM profiles for this to alsa-lib here: https://github.com/jwrdegoede/alsa-lib/commits/master I'm waiting with submitting those upstream until patch 19 is accepted for merging.
Regards,
Hans
is_sys_clk_from_pll() is used as a snd_soc_dapm_route.connected callback, checking RT5640_GBL_CLK to determine if the sys-clk is PLL1 and thus the PWR_PLL bit in reg PWR_ANLG2 must be set.
RT5640_GBL_CLK is changed by rt5640_set_dai_sysclk(), which gets called by the pre_pmu / post_pmd functions of the "Platform Clock" dapm-supply.
This creates an ordering issue, during a dapm transition first all connected() callbacks are called to build a list of supplies to enable and then the complete list is walked to enable the supplies. Since the connected() check happens before enabling any supplies, is_sys_clk_from_pll() ends up deciding if the PWR_PLL bit should be set based on the state the "Platform Clock" supply had *before* the transition. This sometimes results in PWR_PLL being off, even though *after* the transition PLL1 is configured as sys-clk.
This commit removes is_sys_clk_from_pll() instead simply setting / clearing PWR_PLL in rt5640_set_dai_sysclk() based on the selected sys-clk, which fixes this and as a bonus results in a nice cleanup.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/soc/codecs/rt5640.c | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-)
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 05567426f211..140bad07429e 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -476,20 +476,6 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, return idx; }
-static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, - struct snd_soc_dapm_widget *sink) -{ - struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm); - unsigned int val; - - val = snd_soc_component_read32(component, RT5640_GLB_CLK); - val &= RT5640_SCLK_SRC_MASK; - if (val == RT5640_SCLK_SRC_PLL1) - return 1; - else - return 0; -} - static int is_using_asrc(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { @@ -1071,9 +1057,6 @@ static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w, }
static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = { - SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2, - RT5640_PWR_PLL_BIT, 0, NULL, 0), - /* ASRC */ SND_SOC_DAPM_SUPPLY_S("Stereo Filter ASRC", 1, RT5640_ASRC_1, 15, 0, NULL, 0), @@ -1427,22 +1410,18 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = { {"Stereo ADC MIXL", "ADC1 Switch", "Stereo ADC L1 Mux"}, {"Stereo ADC MIXL", "ADC2 Switch", "Stereo ADC L2 Mux"}, {"Stereo ADC MIXL", NULL, "Stereo Filter"}, - {"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll},
{"Stereo ADC MIXR", "ADC1 Switch", "Stereo ADC R1 Mux"}, {"Stereo ADC MIXR", "ADC2 Switch", "Stereo ADC R2 Mux"}, {"Stereo ADC MIXR", NULL, "Stereo Filter"}, - {"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll},
{"Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux"}, {"Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux"}, {"Mono ADC MIXL", NULL, "Mono Left Filter"}, - {"Mono Left Filter", NULL, "PLL1", is_sys_clk_from_pll},
{"Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux"}, {"Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux"}, {"Mono ADC MIXR", NULL, "Mono Right Filter"}, - {"Mono Right Filter", NULL, "PLL1", is_sys_clk_from_pll},
{"IF2 ADC L", NULL, "Mono ADC MIXL"}, {"IF2 ADC R", NULL, "Mono ADC MIXR"}, @@ -1512,10 +1491,8 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = { {"DIG MIXR", "DAC R1 Switch", "DAC MIXR"},
{"DAC L1", NULL, "Stereo DAC MIXL"}, - {"DAC L1", NULL, "PLL1", is_sys_clk_from_pll}, {"DAC L1", NULL, "DAC L1 Power"}, {"DAC R1", NULL, "Stereo DAC MIXR"}, - {"DAC R1", NULL, "PLL1", is_sys_clk_from_pll}, {"DAC R1", NULL, "DAC R1 Power"},
{"SPK MIXL", "REC MIXL Switch", "RECMIXL"}, @@ -1622,10 +1599,8 @@ static const struct snd_soc_dapm_route rt5640_specific_dapm_routes[] = { {"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"},
{"DAC L2", NULL, "Mono DAC MIXL"}, - {"DAC L2", NULL, "PLL1", is_sys_clk_from_pll}, {"DAC L2", NULL, "DAC L2 Power"}, {"DAC R2", NULL, "Mono DAC MIXR"}, - {"DAC R2", NULL, "PLL1", is_sys_clk_from_pll}, {"DAC R2", NULL, "DAC R2 Power"},
{"SPK MIXL", "DAC L2 Switch", "DAC L2"}, @@ -1861,6 +1836,7 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai, struct snd_soc_component *component = dai->component; struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); unsigned int reg_val = 0; + unsigned int pll_bit = 0;
if (freq == rt5640->sysclk && clk_id == rt5640->sysclk_src) return 0; @@ -1871,6 +1847,7 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai, break; case RT5640_SCLK_S_PLL1: reg_val |= RT5640_SCLK_SRC_PLL1; + pll_bit |= RT5640_PWR_PLL; break; case RT5640_SCLK_S_RCCLK: reg_val |= RT5640_SCLK_SRC_RCCLK; @@ -1879,6 +1856,8 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai, dev_err(component->dev, "Invalid clock id (%d)\n", clk_id); return -EINVAL; } + snd_soc_component_update_bits(component, RT5640_PWR_ANLG2, + RT5640_PWR_PLL, pll_bit); snd_soc_component_update_bits(component, RT5640_GLB_CLK, RT5640_SCLK_SRC_MASK, reg_val); rt5640->sysclk = freq;
Add devicetree-bindings for the dmic, jack-detect source and overcurrent- detect threshold settings.
The dmic bindings mirror the existing bindings for the rt5645. The jd-src and ovcd bindings mirror the existing bindings for the rt5651.
Cc devicetree@vger.kernel.org Signed-off-by: Hans de Goede hdegoede@redhat.com --- .../devicetree/bindings/sound/rt5640.txt | 35 +++++++++++++++++++ include/dt-bindings/sound/rt5640.h | 25 +++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 include/dt-bindings/sound/rt5640.h
diff --git a/Documentation/devicetree/bindings/sound/rt5640.txt b/Documentation/devicetree/bindings/sound/rt5640.txt index 57fe64643050..e40e4893eed8 100644 --- a/Documentation/devicetree/bindings/sound/rt5640.txt +++ b/Documentation/devicetree/bindings/sound/rt5640.txt @@ -22,6 +22,41 @@ Optional properties:
- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
+- realtek,dmic1-data-pin + 0: dmic1 is not used + 1: using IN1P pin as dmic1 data pin + 2: using GPIO3 pin as dmic1 data pin + +- realtek,dmic2-data-pin + 0: dmic2 is not used + 1: using IN1N pin as dmic2 data pin + 2: using GPIO4 pin as dmic2 data pin + +- realtek,jack-detect-source + u32. Valid values: + 0: jack-detect is not used + 1: Use GPIO1 for jack-detect + 2: Use JD1_IN4P for jack-detect + 3: Use JD2_IN4N for jack-detect + 4: Use GPIO2 for jack-detect + 5: Use GPIO3 for jack-detect + 6: Use GPIO4 for jack-detect + +- realtek,jack-detect-not-inverted + bool. Normal jack-detect switches give an inverted signal, set this bool + in the rare case you've a jack-detect switch which is not inverted. + +- realtek,over-current-threshold-microamp + u32, micbias over-current detection threshold in µA, valid values are + 600, 1500 and 2000µA. + +- realtek,over-current-scale-factor + u32, micbias over-current detection scale-factor, valid values are: + 0: Scale current by 0.5 + 1: Scale current by 0.75 + 2: Scale current by 1.0 + 3: Scale current by 1.5 + Pins on the device (for linking into audio routes) for RT5639/RT5640:
* DMIC1 diff --git a/include/dt-bindings/sound/rt5640.h b/include/dt-bindings/sound/rt5640.h new file mode 100644 index 000000000000..154c9b4414f2 --- /dev/null +++ b/include/dt-bindings/sound/rt5640.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __DT_RT5640_H +#define __DT_RT5640_H + +#define RT5640_DMIC1_DATA_PIN_NONE 0 +#define RT5640_DMIC1_DATA_PIN_IN1P 1 +#define RT5640_DMIC1_DATA_PIN_GPIO3 2 + +#define RT5640_DMIC2_DATA_PIN_NONE 0 +#define RT5640_DMIC2_DATA_PIN_IN1N 1 +#define RT5640_DMIC2_DATA_PIN_GPIO4 2 + +#define RT5640_JD_SRC_GPIO1 1 +#define RT5640_JD_SRC_JD1_IN4P 2 +#define RT5640_JD_SRC_JD2_IN4N 3 +#define RT5640_JD_SRC_GPIO2 4 +#define RT5640_JD_SRC_GPIO3 5 +#define RT5640_JD_SRC_GPIO4 6 + +#define RT5640_OVCD_SF_0P5 0 +#define RT5640_OVCD_SF_0P75 1 +#define RT5640_OVCD_SF_1P0 2 +#define RT5640_OVCD_SF_1P5 3 + +#endif /* __DT_RT5640_H */
There are no in tree users of platform-data for the rt5640 codec driver, so lets remove support for it.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- include/sound/rt5640.h | 27 -------------------- sound/soc/codecs/rt5640.c | 53 ++++++++++++--------------------------- sound/soc/codecs/rt5640.h | 3 +-- 3 files changed, 17 insertions(+), 66 deletions(-) delete mode 100644 include/sound/rt5640.h
diff --git a/include/sound/rt5640.h b/include/sound/rt5640.h deleted file mode 100644 index e3c84b92ff70..000000000000 --- a/include/sound/rt5640.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * linux/sound/rt5640.h -- Platform data for RT5640 - * - * Copyright 2011 Realtek Microelectronics - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __LINUX_SND_RT5640_H -#define __LINUX_SND_RT5640_H - -struct rt5640_platform_data { - /* IN1 & IN2 & IN3 can optionally be differential */ - bool in1_diff; - bool in2_diff; - bool in3_diff; - - bool dmic_en; - bool dmic1_data_pin; /* 0 = IN1P; 1 = GPIO3 */ - bool dmic2_data_pin; /* 0 = IN1N; 1 = GPIO4 */ - - int ldo1_en; /* GPIO for LDO1_EN */ -}; - -#endif diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 140bad07429e..616f0a69b850 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2138,10 +2138,6 @@ static int rt5640_probe(struct snd_soc_component *component) return -ENODEV; }
- if (rt5640->pdata.dmic_en) - rt5640_dmic_enable(component, rt5640->pdata.dmic1_data_pin, - rt5640->pdata.dmic2_data_pin); - return 0; }
@@ -2159,8 +2155,8 @@ static int rt5640_suspend(struct snd_soc_component *component) rt5640_reset(component); regcache_cache_only(rt5640->regmap, true); regcache_mark_dirty(rt5640->regmap); - if (gpio_is_valid(rt5640->pdata.ldo1_en)) - gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 0); + if (gpio_is_valid(rt5640->ldo1_en)) + gpio_set_value_cansleep(rt5640->ldo1_en, 0);
return 0; } @@ -2169,8 +2165,8 @@ static int rt5640_resume(struct snd_soc_component *component) { struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
- if (gpio_is_valid(rt5640->pdata.ldo1_en)) { - gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 1); + if (gpio_is_valid(rt5640->ldo1_en)) { + gpio_set_value_cansleep(rt5640->ldo1_en, 1); msleep(400); }
@@ -2302,22 +2298,16 @@ MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np) { - rt5640->pdata.in1_diff = of_property_read_bool(np, - "realtek,in1-differential"); - rt5640->pdata.in2_diff = of_property_read_bool(np, - "realtek,in2-differential"); - - rt5640->pdata.ldo1_en = of_get_named_gpio(np, - "realtek,ldo1-en-gpios", 0); + rt5640->ldo1_en = of_get_named_gpio(np, "realtek,ldo1-en-gpios", 0); /* * LDO1_EN is optional (it may be statically tied on the board). * -ENOENT means that the property doesn't exist, i.e. there is no * GPIO, so is not an error. Any other error code means the property * exists, but could not be parsed. */ - if (!gpio_is_valid(rt5640->pdata.ldo1_en) && - (rt5640->pdata.ldo1_en != -ENOENT)) - return rt5640->pdata.ldo1_en; + if (!gpio_is_valid(rt5640->ldo1_en) && + (rt5640->ldo1_en != -ENOENT)) + return rt5640->ldo1_en;
return 0; } @@ -2325,7 +2315,6 @@ static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np) static int rt5640_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct rt5640_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5640_priv *rt5640; int ret; unsigned int val; @@ -2337,22 +2326,12 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, return -ENOMEM; i2c_set_clientdata(i2c, rt5640);
- if (pdata) { - rt5640->pdata = *pdata; - /* - * Translate zero'd out (default) pdata value to an invalid - * GPIO ID. This makes the pdata and DT paths consistent in - * terms of the value left in this field when no GPIO is - * specified, but means we can't actually use GPIO 0. - */ - if (!rt5640->pdata.ldo1_en) - rt5640->pdata.ldo1_en = -EINVAL; - } else if (i2c->dev.of_node) { + if (i2c->dev.of_node) { ret = rt5640_parse_dt(rt5640, i2c->dev.of_node); if (ret) return ret; } else - rt5640->pdata.ldo1_en = -EINVAL; + rt5640->ldo1_en = -EINVAL;
rt5640->regmap = devm_regmap_init_i2c(i2c, &rt5640_regmap); if (IS_ERR(rt5640->regmap)) { @@ -2362,13 +2341,13 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, return ret; }
- if (gpio_is_valid(rt5640->pdata.ldo1_en)) { - ret = devm_gpio_request_one(&i2c->dev, rt5640->pdata.ldo1_en, + if (gpio_is_valid(rt5640->ldo1_en)) { + ret = devm_gpio_request_one(&i2c->dev, rt5640->ldo1_en, GPIOF_OUT_INIT_HIGH, "RT5640 LDO1_EN"); if (ret < 0) { dev_err(&i2c->dev, "Failed to request LDO1_EN %d: %d\n", - rt5640->pdata.ldo1_en, ret); + rt5640->ldo1_en, ret); return ret; } msleep(400); @@ -2391,15 +2370,15 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5640->regmap, RT5640_DUMMY1, RT5640_MCLK_DET, RT5640_MCLK_DET);
- if (rt5640->pdata.in1_diff) + if (device_property_read_bool(&i2c->dev, "realtek,in1-differential")) regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2, RT5640_IN_DF1, RT5640_IN_DF1);
- if (rt5640->pdata.in2_diff) + if (device_property_read_bool(&i2c->dev, "realtek,in2-differential")) regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4, RT5640_IN_DF2, RT5640_IN_DF2);
- if (rt5640->pdata.in3_diff) + if (device_property_read_bool(&i2c->dev, "realtek,in3-differential")) regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2, RT5640_IN_DF2, RT5640_IN_DF2);
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index c473e8ae2eda..2db6586f5ab4 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -13,7 +13,6 @@ #define _RT5640_H
#include <linux/clk.h> -#include <sound/rt5640.h>
/* Info */ #define RT5640_RESET 0x00 @@ -2103,10 +2102,10 @@ enum {
struct rt5640_priv { struct snd_soc_component *component; - struct rt5640_platform_data pdata; struct regmap *regmap; struct clk *mclk;
+ int ldo1_en; /* GPIO for LDO1_EN */ int sysclk; int sysclk_src; int lrck[RT5640_AIFS];
On Tue, May 08, 2018 at 05:35:48PM +0200, Hans de Goede wrote:
There are no in tree users of platform-data for the rt5640 codec driver, so lets remove support for it.
Like we went through last time this is not a strong reason for removing support for platform data, it's not a positive reason for removing things when not everything uses DT or ACPI.
The patch
ASoC: rt5640: Remove unused rt5640_platform_data
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 8e3ebf5e8f0a6da53795d940763cc34f5073c4c3 Mon Sep 17 00:00:00 2001
From: Hans de Goede hdegoede@redhat.com Date: Tue, 8 May 2018 17:35:48 +0200 Subject: [PATCH] ASoC: rt5640: Remove unused rt5640_platform_data
There are no in tree users of platform-data for the rt5640 codec driver, so lets remove support for it.
Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Mark Brown broonie@kernel.org --- include/sound/rt5640.h | 27 -------------------- sound/soc/codecs/rt5640.c | 53 ++++++++++++--------------------------- sound/soc/codecs/rt5640.h | 3 +-- 3 files changed, 17 insertions(+), 66 deletions(-) delete mode 100644 include/sound/rt5640.h
diff --git a/include/sound/rt5640.h b/include/sound/rt5640.h deleted file mode 100644 index e3c84b92ff70..000000000000 --- a/include/sound/rt5640.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * linux/sound/rt5640.h -- Platform data for RT5640 - * - * Copyright 2011 Realtek Microelectronics - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __LINUX_SND_RT5640_H -#define __LINUX_SND_RT5640_H - -struct rt5640_platform_data { - /* IN1 & IN2 & IN3 can optionally be differential */ - bool in1_diff; - bool in2_diff; - bool in3_diff; - - bool dmic_en; - bool dmic1_data_pin; /* 0 = IN1P; 1 = GPIO3 */ - bool dmic2_data_pin; /* 0 = IN1N; 1 = GPIO4 */ - - int ldo1_en; /* GPIO for LDO1_EN */ -}; - -#endif diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 140bad07429e..616f0a69b850 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2138,10 +2138,6 @@ static int rt5640_probe(struct snd_soc_component *component) return -ENODEV; }
- if (rt5640->pdata.dmic_en) - rt5640_dmic_enable(component, rt5640->pdata.dmic1_data_pin, - rt5640->pdata.dmic2_data_pin); - return 0; }
@@ -2159,8 +2155,8 @@ static int rt5640_suspend(struct snd_soc_component *component) rt5640_reset(component); regcache_cache_only(rt5640->regmap, true); regcache_mark_dirty(rt5640->regmap); - if (gpio_is_valid(rt5640->pdata.ldo1_en)) - gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 0); + if (gpio_is_valid(rt5640->ldo1_en)) + gpio_set_value_cansleep(rt5640->ldo1_en, 0);
return 0; } @@ -2169,8 +2165,8 @@ static int rt5640_resume(struct snd_soc_component *component) { struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
- if (gpio_is_valid(rt5640->pdata.ldo1_en)) { - gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 1); + if (gpio_is_valid(rt5640->ldo1_en)) { + gpio_set_value_cansleep(rt5640->ldo1_en, 1); msleep(400); }
@@ -2302,22 +2298,16 @@ MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np) { - rt5640->pdata.in1_diff = of_property_read_bool(np, - "realtek,in1-differential"); - rt5640->pdata.in2_diff = of_property_read_bool(np, - "realtek,in2-differential"); - - rt5640->pdata.ldo1_en = of_get_named_gpio(np, - "realtek,ldo1-en-gpios", 0); + rt5640->ldo1_en = of_get_named_gpio(np, "realtek,ldo1-en-gpios", 0); /* * LDO1_EN is optional (it may be statically tied on the board). * -ENOENT means that the property doesn't exist, i.e. there is no * GPIO, so is not an error. Any other error code means the property * exists, but could not be parsed. */ - if (!gpio_is_valid(rt5640->pdata.ldo1_en) && - (rt5640->pdata.ldo1_en != -ENOENT)) - return rt5640->pdata.ldo1_en; + if (!gpio_is_valid(rt5640->ldo1_en) && + (rt5640->ldo1_en != -ENOENT)) + return rt5640->ldo1_en;
return 0; } @@ -2325,7 +2315,6 @@ static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np) static int rt5640_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct rt5640_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5640_priv *rt5640; int ret; unsigned int val; @@ -2337,22 +2326,12 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, return -ENOMEM; i2c_set_clientdata(i2c, rt5640);
- if (pdata) { - rt5640->pdata = *pdata; - /* - * Translate zero'd out (default) pdata value to an invalid - * GPIO ID. This makes the pdata and DT paths consistent in - * terms of the value left in this field when no GPIO is - * specified, but means we can't actually use GPIO 0. - */ - if (!rt5640->pdata.ldo1_en) - rt5640->pdata.ldo1_en = -EINVAL; - } else if (i2c->dev.of_node) { + if (i2c->dev.of_node) { ret = rt5640_parse_dt(rt5640, i2c->dev.of_node); if (ret) return ret; } else - rt5640->pdata.ldo1_en = -EINVAL; + rt5640->ldo1_en = -EINVAL;
rt5640->regmap = devm_regmap_init_i2c(i2c, &rt5640_regmap); if (IS_ERR(rt5640->regmap)) { @@ -2362,13 +2341,13 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, return ret; }
- if (gpio_is_valid(rt5640->pdata.ldo1_en)) { - ret = devm_gpio_request_one(&i2c->dev, rt5640->pdata.ldo1_en, + if (gpio_is_valid(rt5640->ldo1_en)) { + ret = devm_gpio_request_one(&i2c->dev, rt5640->ldo1_en, GPIOF_OUT_INIT_HIGH, "RT5640 LDO1_EN"); if (ret < 0) { dev_err(&i2c->dev, "Failed to request LDO1_EN %d: %d\n", - rt5640->pdata.ldo1_en, ret); + rt5640->ldo1_en, ret); return ret; } msleep(400); @@ -2391,15 +2370,15 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5640->regmap, RT5640_DUMMY1, RT5640_MCLK_DET, RT5640_MCLK_DET);
- if (rt5640->pdata.in1_diff) + if (device_property_read_bool(&i2c->dev, "realtek,in1-differential")) regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2, RT5640_IN_DF1, RT5640_IN_DF1);
- if (rt5640->pdata.in2_diff) + if (device_property_read_bool(&i2c->dev, "realtek,in2-differential")) regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4, RT5640_IN_DF2, RT5640_IN_DF2);
- if (rt5640->pdata.in3_diff) + if (device_property_read_bool(&i2c->dev, "realtek,in3-differential")) regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2, RT5640_IN_DF2, RT5640_IN_DF2);
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index c473e8ae2eda..2db6586f5ab4 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -13,7 +13,6 @@ #define _RT5640_H
#include <linux/clk.h> -#include <sound/rt5640.h>
/* Info */ #define RT5640_RESET 0x00 @@ -2103,10 +2102,10 @@ enum {
struct rt5640_priv { struct snd_soc_component *component; - struct rt5640_platform_data pdata; struct regmap *regmap; struct clk *mclk;
+ int ldo1_en; /* GPIO for LDO1_EN */ int sysclk; int sysclk_src; int lrck[RT5640_AIFS];
On some platforms the platform code may need to add device-properties, rather then relying only on properties set by the firmware.
This commit moves the parsing of the device-properties from the i2c-driver probe() function, which may be called at any time, to the component-driver probe() function, which gets called after the platform code calls snd_soc_register_card().
This allows the platform code to attach extra device-properties before the device-properties are parsed.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/soc/codecs/rt5640.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-)
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 616f0a69b850..265a0786851d 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2138,6 +2138,25 @@ static int rt5640_probe(struct snd_soc_component *component) return -ENODEV; }
+ /* + * Note on some platforms the platform code may need to add device-props + * rather then relying only on properties set by the firmware. + * Therefor the property parsing MUST be done here, rather then from + * rt5640_i2c_probe(), so that the platform-code can attach extra + * properties before calling snd_soc_register_card(). + */ + if (device_property_read_bool(component->dev, "realtek,in1-differential")) + snd_soc_component_update_bits(component, RT5640_IN1_IN2, + RT5640_IN_DF1, RT5640_IN_DF1); + + if (device_property_read_bool(component->dev, "realtek,in2-differential")) + snd_soc_component_update_bits(component, RT5640_IN3_IN4, + RT5640_IN_DF2, RT5640_IN_DF2); + + if (device_property_read_bool(component->dev, "realtek,in3-differential")) + snd_soc_component_update_bits(component, RT5640_IN1_IN2, + RT5640_IN_DF2, RT5640_IN_DF2); + return 0; }
@@ -2370,18 +2389,6 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5640->regmap, RT5640_DUMMY1, RT5640_MCLK_DET, RT5640_MCLK_DET);
- if (device_property_read_bool(&i2c->dev, "realtek,in1-differential")) - regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2, - RT5640_IN_DF1, RT5640_IN_DF1); - - if (device_property_read_bool(&i2c->dev, "realtek,in2-differential")) - regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4, - RT5640_IN_DF2, RT5640_IN_DF2); - - if (device_property_read_bool(&i2c->dev, "realtek,in3-differential")) - regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2, - RT5640_IN_DF2, RT5640_IN_DF2); - rt5640->hp_mute = 1;
return devm_snd_soc_register_component(&i2c->dev,
The patch
ASoC: rt5640: Move checking of device-properties to component probe callback
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 988a5e0162ce75a4440c9181ad6d900473e428ae Mon Sep 17 00:00:00 2001
From: Hans de Goede hdegoede@redhat.com Date: Tue, 8 May 2018 17:35:49 +0200 Subject: [PATCH] ASoC: rt5640: Move checking of device-properties to component probe callback
On some platforms the platform code may need to add device-properties, rather then relying only on properties set by the firmware.
This commit moves the parsing of the device-properties from the i2c-driver probe() function, which may be called at any time, to the component-driver probe() function, which gets called after the platform code calls snd_soc_register_card().
This allows the platform code to attach extra device-properties before the device-properties are parsed.
Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/rt5640.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-)
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 616f0a69b850..265a0786851d 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2138,6 +2138,25 @@ static int rt5640_probe(struct snd_soc_component *component) return -ENODEV; }
+ /* + * Note on some platforms the platform code may need to add device-props + * rather then relying only on properties set by the firmware. + * Therefor the property parsing MUST be done here, rather then from + * rt5640_i2c_probe(), so that the platform-code can attach extra + * properties before calling snd_soc_register_card(). + */ + if (device_property_read_bool(component->dev, "realtek,in1-differential")) + snd_soc_component_update_bits(component, RT5640_IN1_IN2, + RT5640_IN_DF1, RT5640_IN_DF1); + + if (device_property_read_bool(component->dev, "realtek,in2-differential")) + snd_soc_component_update_bits(component, RT5640_IN3_IN4, + RT5640_IN_DF2, RT5640_IN_DF2); + + if (device_property_read_bool(component->dev, "realtek,in3-differential")) + snd_soc_component_update_bits(component, RT5640_IN1_IN2, + RT5640_IN_DF2, RT5640_IN_DF2); + return 0; }
@@ -2370,18 +2389,6 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5640->regmap, RT5640_DUMMY1, RT5640_MCLK_DET, RT5640_MCLK_DET);
- if (device_property_read_bool(&i2c->dev, "realtek,in1-differential")) - regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2, - RT5640_IN_DF1, RT5640_IN_DF1); - - if (device_property_read_bool(&i2c->dev, "realtek,in2-differential")) - regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4, - RT5640_IN_DF2, RT5640_IN_DF2); - - if (device_property_read_bool(&i2c->dev, "realtek,in3-differential")) - regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2, - RT5640_IN_DF2, RT5640_IN_DF2); - rt5640->hp_mute = 1;
return devm_snd_soc_register_component(&i2c->dev,
Allow specifying dmic data pins through device-properties / dt. This will allow us to stop exporting rt5640_dmic_enable() once all callers of it have been converted to setting device-properties for this instead.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/soc/codecs/rt5640.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 265a0786851d..d7c7b207f3cc 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2097,6 +2097,10 @@ static int rt5640_probe(struct snd_soc_component *component) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + u32 dmic1_data_pin = 0; + u32 dmic2_data_pin = 0; + bool dmic_en = false; + u32 val;
/* Check if MCLK provided */ rt5640->mclk = devm_clk_get(component->dev, "mclk"); @@ -2157,6 +2161,21 @@ static int rt5640_probe(struct snd_soc_component *component) snd_soc_component_update_bits(component, RT5640_IN1_IN2, RT5640_IN_DF2, RT5640_IN_DF2);
+ if (device_property_read_u32(component->dev, "realtek,dmic1-data-pin", + &val) == 0 && val) { + dmic1_data_pin = val - 1; + dmic_en = true; + } + + if (device_property_read_u32(component->dev, "realtek,dmic2-data-pin", + &val) == 0 && val) { + dmic2_data_pin = val - 1; + dmic_en = true; + } + + if (dmic_en) + rt5640_dmic_enable(component, dmic1_data_pin, dmic2_data_pin); + return 0; }
The patch
ASoC: rt5640: Allow specifying dmic data pins through device-properties
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From fb509fa962243e20bddcc5cab74c4a2153c01ff6 Mon Sep 17 00:00:00 2001
From: Hans de Goede hdegoede@redhat.com Date: Tue, 8 May 2018 17:35:50 +0200 Subject: [PATCH] ASoC: rt5640: Allow specifying dmic data pins through device-properties
Allow specifying dmic data pins through device-properties / dt. This will allow us to stop exporting rt5640_dmic_enable() once all callers of it have been converted to setting device-properties for this instead.
Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/rt5640.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 265a0786851d..d7c7b207f3cc 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2097,6 +2097,10 @@ static int rt5640_probe(struct snd_soc_component *component) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + u32 dmic1_data_pin = 0; + u32 dmic2_data_pin = 0; + bool dmic_en = false; + u32 val;
/* Check if MCLK provided */ rt5640->mclk = devm_clk_get(component->dev, "mclk"); @@ -2157,6 +2161,21 @@ static int rt5640_probe(struct snd_soc_component *component) snd_soc_component_update_bits(component, RT5640_IN1_IN2, RT5640_IN_DF2, RT5640_IN_DF2);
+ if (device_property_read_u32(component->dev, "realtek,dmic1-data-pin", + &val) == 0 && val) { + dmic1_data_pin = val - 1; + dmic_en = true; + } + + if (device_property_read_u32(component->dev, "realtek,dmic2-data-pin", + &val) == 0 && val) { + dmic2_data_pin = val - 1; + dmic_en = true; + } + + if (dmic_en) + rt5640_dmic_enable(component, dmic1_data_pin, dmic2_data_pin); + return 0; }
Add jack-detect support, loosely based on earlier work on this by:
Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Francisco mendez francisco.mendez@intel.com
Note getting the OVCD to work reliable was sort of finicky, so there are quite a few comments on this to hopefully avoid people breaking it in the future.
This (and the follow-up button press support) has been tested on the following devices:
Acer Iconia Tab 8 W1-810 Asus T100CHI Asus T100TA Asus T200TA Axxo WT1011 Chuwi Vi8 Dell Venue 8 Pro 5830 HP Pavilion X2 10-n000nd HP Stream 7 I.T. Works TW891 Lamina I8270 MSI S100 Peaq C1010 Pipo W4 PoV MobiiTAB-P800W (v2.0) Toshiba Click Mini L9W-B
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=196377 Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/soc/codecs/rt5640.c | 286 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt5640.h | 36 ++++- 2 files changed, 318 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index d7c7b207f3cc..8e306f509601 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -24,6 +24,7 @@ #include <linux/spi/spi.h> #include <linux/acpi.h> #include <sound/core.h> +#include <sound/jack.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -2093,6 +2094,224 @@ int rt5640_sel_asrc_clk_src(struct snd_soc_component *component, } EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src);
+static void rt5640_enable_micbias1_for_ovcd(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS1"); + /* OVCD is unreliable when used with RCCLK as sysclk-source */ + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Platform Clock"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); +} + +static void rt5640_disable_micbias1_for_ovcd(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_disable_pin_unlocked(dapm, "Platform Clock"); + snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS1"); + snd_soc_dapm_disable_pin_unlocked(dapm, "LDO2"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); +} + +static void rt5640_clear_micbias1_ovcd(struct snd_soc_component *component) +{ + snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2, + RT5640_MB1_OC_STATUS, 0); +} + +static bool rt5640_micbias1_ovcd(struct snd_soc_component *component) +{ + int val; + + val = snd_soc_component_read32(component, RT5640_IRQ_CTRL2); + dev_dbg(component->dev, "irq ctrl2 %#04x\n", val); + + return (val & RT5640_MB1_OC_STATUS); +} + +static bool rt5640_jack_inserted(struct snd_soc_component *component) +{ + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + int val; + + val = snd_soc_component_read32(component, RT5640_INT_IRQ_ST); + dev_dbg(component->dev, "irq status %#04x\n", val); + + if (rt5640->jd_inverted) + return !(val & RT5640_JD_STATUS); + else + return (val & RT5640_JD_STATUS); +} + +/* Jack detect timings */ +#define JACK_SETTLE_TIME 100 /* milli seconds */ +#define JACK_DETECT_COUNT 5 +#define JACK_DETECT_MAXCOUNT 20 /* Aprox. 2 seconds worth of tries */ + +static int rt5640_detect_headset(struct snd_soc_component *component) +{ + int i, headset_count = 0, headphone_count = 0; + + /* + * We get the insertion event before the jack is fully inserted at which + * point the second ring on a TRRS connector may short the 2nd ring and + * sleeve contacts, also the overcurrent detection is not entirely + * reliable. So we try several times with a wait in between until we + * detect the same type JACK_DETECT_COUNT times in a row. + */ + for (i = 0; i < JACK_DETECT_MAXCOUNT; i++) { + /* Clear any previous over-current status flag */ + rt5640_clear_micbias1_ovcd(component); + + msleep(JACK_SETTLE_TIME); + + /* Check the jack is still connected before checking ovcd */ + if (!rt5640_jack_inserted(component)) + return 0; + + if (rt5640_micbias1_ovcd(component)) { + /* + * Over current detected, there is a short between the + * 2nd ring contact and the ground, so a TRS connector + * without a mic contact and thus plain headphones. + */ + dev_dbg(component->dev, "jack mic-gnd shorted\n"); + headset_count = 0; + headphone_count++; + if (headphone_count == JACK_DETECT_COUNT) + return SND_JACK_HEADPHONE; + } else { + dev_dbg(component->dev, "jack mic-gnd open\n"); + headphone_count = 0; + headset_count++; + if (headset_count == JACK_DETECT_COUNT) + return SND_JACK_HEADSET; + } + } + + dev_err(component->dev, "Error detecting headset vs headphones, bad contact?, assuming headphones\n"); + return SND_JACK_HEADPHONE; +} + +static void rt5640_jack_work(struct work_struct *work) +{ + struct rt5640_priv *rt5640 = + container_of(work, struct rt5640_priv, jack_work); + struct snd_soc_component *component = rt5640->component; + int status; + + if (!rt5640_jack_inserted(component)) { + /* Jack removed, or spurious IRQ? */ + if (rt5640->jack->status & SND_JACK_HEADPHONE) { + snd_soc_jack_report(rt5640->jack, 0, SND_JACK_HEADSET); + dev_dbg(component->dev, "jack unplugged\n"); + } + } else if (!(rt5640->jack->status & SND_JACK_HEADPHONE)) { + /* Jack inserted */ + rt5640_enable_micbias1_for_ovcd(component); + status = rt5640_detect_headset(component); + rt5640_disable_micbias1_for_ovcd(component); + + dev_dbg(component->dev, "detect status %#02x\n", status); + snd_soc_jack_report(rt5640->jack, status, SND_JACK_HEADSET); + } +} + +static irqreturn_t rt5640_irq(int irq, void *data) +{ + struct rt5640_priv *rt5640 = data; + + if (rt5640->jack) + queue_work(system_long_wq, &rt5640->jack_work); + + return IRQ_HANDLED; +} + +static void rt5640_cancel_work(void *data) +{ + struct rt5640_priv *rt5640 = data; + + cancel_work_sync(&rt5640->jack_work); +} + +static void rt5640_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack) +{ + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + + /* Select JD-source */ + snd_soc_component_update_bits(component, RT5640_JD_CTRL, + RT5640_JD_MASK, rt5640->jd_src); + + /* Selecting GPIO01 as an interrupt */ + snd_soc_component_update_bits(component, RT5640_GPIO_CTRL1, + RT5640_GP1_PIN_MASK, RT5640_GP1_PIN_IRQ); + + /* Set GPIO1 output */ + snd_soc_component_update_bits(component, RT5640_GPIO_CTRL3, + RT5640_GP1_PF_MASK, RT5640_GP1_PF_OUT); + + /* Enabling jd2 in general control 1 */ + snd_soc_component_write(component, RT5640_DUMMY1, 0x3f41); + + /* Enabling jd2 in general control 2 */ + snd_soc_component_write(component, RT5640_DUMMY2, 0x4001); + + snd_soc_component_write(component, RT5640_PR_BASE + RT5640_BIAS_CUR4, + 0xa800 | rt5640->ovcd_sf); + + snd_soc_component_update_bits(component, RT5640_MICBIAS, + RT5640_MIC1_OVTH_MASK | RT5640_MIC1_OVCD_MASK, + rt5640->ovcd_th | RT5640_MIC1_OVCD_EN); + + /* + * The over-current-detect is only reliable in detecting the absence + * of over-current, when the mic-contact in the jack is short-circuited, + * the hardware periodically retries if it can apply the bias-current + * leading to the ovcd status flip-flopping 1-0-1 with it being 0 about + * 10% of the time, as we poll the ovcd status bit we might hit that + * 10%, so we enable sticky mode and when checking OVCD we clear the + * status, msleep() a bit and then check to get a reliable reading. + */ + snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2, + RT5640_MB1_OC_STKY_MASK, RT5640_MB1_OC_STKY_EN); + + snd_soc_component_write(component, RT5640_IRQ_CTRL1, + RT5640_IRQ_JD_NOR); + + rt5640->jack = jack; + enable_irq(rt5640->irq); + /* sync initial jack state */ + queue_work(system_long_wq, &rt5640->jack_work); +} + +static void rt5640_disable_jack_detect(struct snd_soc_component *component) +{ + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + + disable_irq(rt5640->irq); + rt5640_cancel_work(rt5640); + + rt5640->jack = NULL; +} + +static int rt5640_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) +{ + if (jack) + rt5640_enable_jack_detect(component, jack); + else + rt5640_disable_jack_detect(component); + + return 0; +} + static int rt5640_probe(struct snd_soc_component *component) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); @@ -2176,6 +2395,53 @@ static int rt5640_probe(struct snd_soc_component *component) if (dmic_en) rt5640_dmic_enable(component, dmic1_data_pin, dmic2_data_pin);
+ if (device_property_read_u32(component->dev, + "realtek,jack-detect-source", &val) == 0) { + if (val <= RT5640_JD_SRC_GPIO4) + rt5640->jd_src = val << RT5640_JD_SFT; + else + dev_warn(component->dev, "Warning: Invalid jack-detect-source value: %d, leaving jack-detect disabled\n", + val); + } + + if (!device_property_read_bool(component->dev, "realtek,jack-detect-not-inverted")) + rt5640->jd_inverted = true; + + /* + * Testing on various boards has shown that good defaults for the OVCD + * threshold and scale-factor are 2000µA and 0.75. For an effective + * limit of 1500µA, this seems to be more reliable then 1500µA and 1.0. + */ + rt5640->ovcd_th = RT5640_MIC1_OVTH_2000UA; + rt5640->ovcd_sf = RT5640_MIC_OVCD_SF_0P75; + + if (device_property_read_u32(component->dev, + "realtek,over-current-threshold-microamp", &val) == 0) { + switch (val) { + case 600: + rt5640->ovcd_th = RT5640_MIC1_OVTH_600UA; + break; + case 1500: + rt5640->ovcd_th = RT5640_MIC1_OVTH_1500UA; + break; + case 2000: + rt5640->ovcd_th = RT5640_MIC1_OVTH_2000UA; + break; + default: + dev_warn(component->dev, "Warning: Invalid over-current-threshold-microamp value: %d, defaulting to 2000uA\n", + val); + } + } + + if (device_property_read_u32(component->dev, + "realtek,over-current-scale-factor", &val) == 0) { + if (val <= RT5640_OVCD_SF_1P5) + rt5640->ovcd_sf = val << RT5640_MIC_OVCD_SF_SFT; + else + dev_warn(component->dev, "Warning: Invalid over-current-scale-factor value: %d, defaulting to 0.75\n", + val); + } + return 0; }
@@ -2276,6 +2542,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt5640 = { .suspend = rt5640_suspend, .resume = rt5640_resume, .set_bias_level = rt5640_set_bias_level, + .set_jack = rt5640_set_jack, .controls = rt5640_snd_controls, .num_controls = ARRAY_SIZE(rt5640_snd_controls), .dapm_widgets = rt5640_dapm_widgets, @@ -2409,6 +2676,25 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, RT5640_MCLK_DET, RT5640_MCLK_DET);
rt5640->hp_mute = 1; + rt5640->irq = i2c->irq; + INIT_WORK(&rt5640->jack_work, rt5640_jack_work); + + /* Make sure work is stopped on probe-error / remove */ + ret = devm_add_action_or_reset(&i2c->dev, rt5640_cancel_work, rt5640); + if (ret) + return ret; + + ret = devm_request_irq(&i2c->dev, rt5640->irq, rt5640_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING + | IRQF_ONESHOT, "rt5640", rt5640); + if (ret == 0) { + /* Gets re-enabled by rt5640_set_jack() */ + disable_irq(rt5640->irq); + } else { + dev_warn(&i2c->dev, "Failed to reguest IRQ %d: %d\n", + rt5640->irq, ret); + rt5640->irq = -ENXIO; + }
return devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5640, diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 2db6586f5ab4..9d08471734b3 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -13,6 +13,8 @@ #define _RT5640_H
#include <linux/clk.h> +#include <linux/workqueue.h> +#include <dt-bindings/sound/rt5640.h>
/* Info */ #define RT5640_RESET 0x00 @@ -145,6 +147,7 @@
/* Index of Codec Private Register definition */ +#define RT5640_BIAS_CUR4 0x15 #define RT5640_CHPUMP_INT_REG1 0x24 #define RT5640_MAMP_INT_REG2 0x37 #define RT5640_3D_SPK 0x63 @@ -1606,10 +1609,17 @@ #define RT5640_MB2_OC_P_SFT 6 #define RT5640_MB2_OC_P_NOR (0x0 << 6) #define RT5640_MB2_OC_P_INV (0x1 << 6) -#define RT5640_MB1_OC_CLR (0x1 << 3) -#define RT5640_MB1_OC_CLR_SFT 3 -#define RT5640_MB2_OC_CLR (0x1 << 2) -#define RT5640_MB2_OC_CLR_SFT 2 +#define RT5640_MB1_OC_STATUS (0x1 << 3) +#define RT5640_MB1_OC_STATUS_SFT 3 +#define RT5640_MB2_OC_STATUS (0x1 << 2) +#define RT5640_MB2_OC_STATUS_SFT 2 + +/* GPIO and Internal Status (0xbf) */ +#define RT5640_GPIO1_STATUS (0x1 << 8) +#define RT5640_GPIO2_STATUS (0x1 << 7) +#define RT5640_JD_STATUS (0x1 << 4) +#define RT5640_OVT_STATUS (0x1 << 3) +#define RT5640_CLS_D_OVCD_STATUS (0x1 << 0)
/* GPIO Control 1 (0xc0) */ #define RT5640_GP1_PIN_MASK (0x1 << 15) @@ -1977,6 +1987,15 @@ #define RT5640_MCLK_DET (0x1 << 11)
/* Codec Private Register definition */ + +/* MIC Over current threshold scale factor (0x15) */ +#define RT5640_MIC_OVCD_SF_MASK (0x3 << 8) +#define RT5640_MIC_OVCD_SF_SFT 8 +#define RT5640_MIC_OVCD_SF_0P5 (0x0 << 8) +#define RT5640_MIC_OVCD_SF_0P75 (0x1 << 8) +#define RT5640_MIC_OVCD_SF_1P0 (0x2 << 8) +#define RT5640_MIC_OVCD_SF_1P5 (0x3 << 8) + /* 3D Speaker Control (0x63) */ #define RT5640_3D_SPK_MASK (0x1 << 15) #define RT5640_3D_SPK_SFT 15 @@ -2106,6 +2125,7 @@ struct rt5640_priv { struct clk *mclk;
int ldo1_en; /* GPIO for LDO1_EN */ + int irq; int sysclk; int sysclk_src; int lrck[RT5640_AIFS]; @@ -2118,6 +2138,14 @@ struct rt5640_priv {
bool hp_mute; bool asrc_en; + + /* Jack detect data */ + struct work_struct jack_work; + struct snd_soc_jack *jack; + unsigned int jd_src; + bool jd_inverted; + unsigned int ovcd_th; + unsigned int ovcd_sf; };
int rt5640_dmic_enable(struct snd_soc_component *component,
The patch
ASoC: rt5640: Add jack-detect support
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 8210804bcf40b837f8560c99efb315c0bbfc8c7b Mon Sep 17 00:00:00 2001
From: Hans de Goede hdegoede@redhat.com Date: Tue, 8 May 2018 17:35:51 +0200 Subject: [PATCH] ASoC: rt5640: Add jack-detect support
Add jack-detect support, loosely based on earlier work on this by:
Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Francisco mendez francisco.mendez@intel.com
Note getting the OVCD to work reliable was sort of finicky, so there are quite a few comments on this to hopefully avoid people breaking it in the future.
This (and the follow-up button press support) has been tested on the following devices:
Acer Iconia Tab 8 W1-810 Asus T100CHI Asus T100TA Asus T200TA Axxo WT1011 Chuwi Vi8 Dell Venue 8 Pro 5830 HP Pavilion X2 10-n000nd HP Stream 7 I.T. Works TW891 Lamina I8270 MSI S100 Peaq C1010 Pipo W4 PoV MobiiTAB-P800W (v2.0) Toshiba Click Mini L9W-B
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=196377 Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/rt5640.c | 286 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt5640.h | 36 ++++- 2 files changed, 318 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index d7c7b207f3cc..8e306f509601 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -24,6 +24,7 @@ #include <linux/spi/spi.h> #include <linux/acpi.h> #include <sound/core.h> +#include <sound/jack.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -2093,6 +2094,224 @@ int rt5640_sel_asrc_clk_src(struct snd_soc_component *component, } EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src);
+static void rt5640_enable_micbias1_for_ovcd(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS1"); + /* OVCD is unreliable when used with RCCLK as sysclk-source */ + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Platform Clock"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); +} + +static void rt5640_disable_micbias1_for_ovcd(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_disable_pin_unlocked(dapm, "Platform Clock"); + snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS1"); + snd_soc_dapm_disable_pin_unlocked(dapm, "LDO2"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); +} + +static void rt5640_clear_micbias1_ovcd(struct snd_soc_component *component) +{ + snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2, + RT5640_MB1_OC_STATUS, 0); +} + +static bool rt5640_micbias1_ovcd(struct snd_soc_component *component) +{ + int val; + + val = snd_soc_component_read32(component, RT5640_IRQ_CTRL2); + dev_dbg(component->dev, "irq ctrl2 %#04x\n", val); + + return (val & RT5640_MB1_OC_STATUS); +} + +static bool rt5640_jack_inserted(struct snd_soc_component *component) +{ + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + int val; + + val = snd_soc_component_read32(component, RT5640_INT_IRQ_ST); + dev_dbg(component->dev, "irq status %#04x\n", val); + + if (rt5640->jd_inverted) + return !(val & RT5640_JD_STATUS); + else + return (val & RT5640_JD_STATUS); +} + +/* Jack detect timings */ +#define JACK_SETTLE_TIME 100 /* milli seconds */ +#define JACK_DETECT_COUNT 5 +#define JACK_DETECT_MAXCOUNT 20 /* Aprox. 2 seconds worth of tries */ + +static int rt5640_detect_headset(struct snd_soc_component *component) +{ + int i, headset_count = 0, headphone_count = 0; + + /* + * We get the insertion event before the jack is fully inserted at which + * point the second ring on a TRRS connector may short the 2nd ring and + * sleeve contacts, also the overcurrent detection is not entirely + * reliable. So we try several times with a wait in between until we + * detect the same type JACK_DETECT_COUNT times in a row. + */ + for (i = 0; i < JACK_DETECT_MAXCOUNT; i++) { + /* Clear any previous over-current status flag */ + rt5640_clear_micbias1_ovcd(component); + + msleep(JACK_SETTLE_TIME); + + /* Check the jack is still connected before checking ovcd */ + if (!rt5640_jack_inserted(component)) + return 0; + + if (rt5640_micbias1_ovcd(component)) { + /* + * Over current detected, there is a short between the + * 2nd ring contact and the ground, so a TRS connector + * without a mic contact and thus plain headphones. + */ + dev_dbg(component->dev, "jack mic-gnd shorted\n"); + headset_count = 0; + headphone_count++; + if (headphone_count == JACK_DETECT_COUNT) + return SND_JACK_HEADPHONE; + } else { + dev_dbg(component->dev, "jack mic-gnd open\n"); + headphone_count = 0; + headset_count++; + if (headset_count == JACK_DETECT_COUNT) + return SND_JACK_HEADSET; + } + } + + dev_err(component->dev, "Error detecting headset vs headphones, bad contact?, assuming headphones\n"); + return SND_JACK_HEADPHONE; +} + +static void rt5640_jack_work(struct work_struct *work) +{ + struct rt5640_priv *rt5640 = + container_of(work, struct rt5640_priv, jack_work); + struct snd_soc_component *component = rt5640->component; + int status; + + if (!rt5640_jack_inserted(component)) { + /* Jack removed, or spurious IRQ? */ + if (rt5640->jack->status & SND_JACK_HEADPHONE) { + snd_soc_jack_report(rt5640->jack, 0, SND_JACK_HEADSET); + dev_dbg(component->dev, "jack unplugged\n"); + } + } else if (!(rt5640->jack->status & SND_JACK_HEADPHONE)) { + /* Jack inserted */ + rt5640_enable_micbias1_for_ovcd(component); + status = rt5640_detect_headset(component); + rt5640_disable_micbias1_for_ovcd(component); + + dev_dbg(component->dev, "detect status %#02x\n", status); + snd_soc_jack_report(rt5640->jack, status, SND_JACK_HEADSET); + } +} + +static irqreturn_t rt5640_irq(int irq, void *data) +{ + struct rt5640_priv *rt5640 = data; + + if (rt5640->jack) + queue_work(system_long_wq, &rt5640->jack_work); + + return IRQ_HANDLED; +} + +static void rt5640_cancel_work(void *data) +{ + struct rt5640_priv *rt5640 = data; + + cancel_work_sync(&rt5640->jack_work); +} + +static void rt5640_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack) +{ + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + + /* Select JD-source */ + snd_soc_component_update_bits(component, RT5640_JD_CTRL, + RT5640_JD_MASK, rt5640->jd_src); + + /* Selecting GPIO01 as an interrupt */ + snd_soc_component_update_bits(component, RT5640_GPIO_CTRL1, + RT5640_GP1_PIN_MASK, RT5640_GP1_PIN_IRQ); + + /* Set GPIO1 output */ + snd_soc_component_update_bits(component, RT5640_GPIO_CTRL3, + RT5640_GP1_PF_MASK, RT5640_GP1_PF_OUT); + + /* Enabling jd2 in general control 1 */ + snd_soc_component_write(component, RT5640_DUMMY1, 0x3f41); + + /* Enabling jd2 in general control 2 */ + snd_soc_component_write(component, RT5640_DUMMY2, 0x4001); + + snd_soc_component_write(component, RT5640_PR_BASE + RT5640_BIAS_CUR4, + 0xa800 | rt5640->ovcd_sf); + + snd_soc_component_update_bits(component, RT5640_MICBIAS, + RT5640_MIC1_OVTH_MASK | RT5640_MIC1_OVCD_MASK, + rt5640->ovcd_th | RT5640_MIC1_OVCD_EN); + + /* + * The over-current-detect is only reliable in detecting the absence + * of over-current, when the mic-contact in the jack is short-circuited, + * the hardware periodically retries if it can apply the bias-current + * leading to the ovcd status flip-flopping 1-0-1 with it being 0 about + * 10% of the time, as we poll the ovcd status bit we might hit that + * 10%, so we enable sticky mode and when checking OVCD we clear the + * status, msleep() a bit and then check to get a reliable reading. + */ + snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2, + RT5640_MB1_OC_STKY_MASK, RT5640_MB1_OC_STKY_EN); + + snd_soc_component_write(component, RT5640_IRQ_CTRL1, + RT5640_IRQ_JD_NOR); + + rt5640->jack = jack; + enable_irq(rt5640->irq); + /* sync initial jack state */ + queue_work(system_long_wq, &rt5640->jack_work); +} + +static void rt5640_disable_jack_detect(struct snd_soc_component *component) +{ + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + + disable_irq(rt5640->irq); + rt5640_cancel_work(rt5640); + + rt5640->jack = NULL; +} + +static int rt5640_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) +{ + if (jack) + rt5640_enable_jack_detect(component, jack); + else + rt5640_disable_jack_detect(component); + + return 0; +} + static int rt5640_probe(struct snd_soc_component *component) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); @@ -2176,6 +2395,53 @@ static int rt5640_probe(struct snd_soc_component *component) if (dmic_en) rt5640_dmic_enable(component, dmic1_data_pin, dmic2_data_pin);
+ if (device_property_read_u32(component->dev, + "realtek,jack-detect-source", &val) == 0) { + if (val <= RT5640_JD_SRC_GPIO4) + rt5640->jd_src = val << RT5640_JD_SFT; + else + dev_warn(component->dev, "Warning: Invalid jack-detect-source value: %d, leaving jack-detect disabled\n", + val); + } + + if (!device_property_read_bool(component->dev, "realtek,jack-detect-not-inverted")) + rt5640->jd_inverted = true; + + /* + * Testing on various boards has shown that good defaults for the OVCD + * threshold and scale-factor are 2000µA and 0.75. For an effective + * limit of 1500µA, this seems to be more reliable then 1500µA and 1.0. + */ + rt5640->ovcd_th = RT5640_MIC1_OVTH_2000UA; + rt5640->ovcd_sf = RT5640_MIC_OVCD_SF_0P75; + + if (device_property_read_u32(component->dev, + "realtek,over-current-threshold-microamp", &val) == 0) { + switch (val) { + case 600: + rt5640->ovcd_th = RT5640_MIC1_OVTH_600UA; + break; + case 1500: + rt5640->ovcd_th = RT5640_MIC1_OVTH_1500UA; + break; + case 2000: + rt5640->ovcd_th = RT5640_MIC1_OVTH_2000UA; + break; + default: + dev_warn(component->dev, "Warning: Invalid over-current-threshold-microamp value: %d, defaulting to 2000uA\n", + val); + } + } + + if (device_property_read_u32(component->dev, + "realtek,over-current-scale-factor", &val) == 0) { + if (val <= RT5640_OVCD_SF_1P5) + rt5640->ovcd_sf = val << RT5640_MIC_OVCD_SF_SFT; + else + dev_warn(component->dev, "Warning: Invalid over-current-scale-factor value: %d, defaulting to 0.75\n", + val); + } + return 0; }
@@ -2276,6 +2542,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt5640 = { .suspend = rt5640_suspend, .resume = rt5640_resume, .set_bias_level = rt5640_set_bias_level, + .set_jack = rt5640_set_jack, .controls = rt5640_snd_controls, .num_controls = ARRAY_SIZE(rt5640_snd_controls), .dapm_widgets = rt5640_dapm_widgets, @@ -2409,6 +2676,25 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, RT5640_MCLK_DET, RT5640_MCLK_DET);
rt5640->hp_mute = 1; + rt5640->irq = i2c->irq; + INIT_WORK(&rt5640->jack_work, rt5640_jack_work); + + /* Make sure work is stopped on probe-error / remove */ + ret = devm_add_action_or_reset(&i2c->dev, rt5640_cancel_work, rt5640); + if (ret) + return ret; + + ret = devm_request_irq(&i2c->dev, rt5640->irq, rt5640_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING + | IRQF_ONESHOT, "rt5640", rt5640); + if (ret == 0) { + /* Gets re-enabled by rt5640_set_jack() */ + disable_irq(rt5640->irq); + } else { + dev_warn(&i2c->dev, "Failed to reguest IRQ %d: %d\n", + rt5640->irq, ret); + rt5640->irq = -ENXIO; + }
return devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5640, diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 2db6586f5ab4..9d08471734b3 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -13,6 +13,8 @@ #define _RT5640_H
#include <linux/clk.h> +#include <linux/workqueue.h> +#include <dt-bindings/sound/rt5640.h>
/* Info */ #define RT5640_RESET 0x00 @@ -145,6 +147,7 @@
/* Index of Codec Private Register definition */ +#define RT5640_BIAS_CUR4 0x15 #define RT5640_CHPUMP_INT_REG1 0x24 #define RT5640_MAMP_INT_REG2 0x37 #define RT5640_3D_SPK 0x63 @@ -1606,10 +1609,17 @@ #define RT5640_MB2_OC_P_SFT 6 #define RT5640_MB2_OC_P_NOR (0x0 << 6) #define RT5640_MB2_OC_P_INV (0x1 << 6) -#define RT5640_MB1_OC_CLR (0x1 << 3) -#define RT5640_MB1_OC_CLR_SFT 3 -#define RT5640_MB2_OC_CLR (0x1 << 2) -#define RT5640_MB2_OC_CLR_SFT 2 +#define RT5640_MB1_OC_STATUS (0x1 << 3) +#define RT5640_MB1_OC_STATUS_SFT 3 +#define RT5640_MB2_OC_STATUS (0x1 << 2) +#define RT5640_MB2_OC_STATUS_SFT 2 + +/* GPIO and Internal Status (0xbf) */ +#define RT5640_GPIO1_STATUS (0x1 << 8) +#define RT5640_GPIO2_STATUS (0x1 << 7) +#define RT5640_JD_STATUS (0x1 << 4) +#define RT5640_OVT_STATUS (0x1 << 3) +#define RT5640_CLS_D_OVCD_STATUS (0x1 << 0)
/* GPIO Control 1 (0xc0) */ #define RT5640_GP1_PIN_MASK (0x1 << 15) @@ -1977,6 +1987,15 @@ #define RT5640_MCLK_DET (0x1 << 11)
/* Codec Private Register definition */ + +/* MIC Over current threshold scale factor (0x15) */ +#define RT5640_MIC_OVCD_SF_MASK (0x3 << 8) +#define RT5640_MIC_OVCD_SF_SFT 8 +#define RT5640_MIC_OVCD_SF_0P5 (0x0 << 8) +#define RT5640_MIC_OVCD_SF_0P75 (0x1 << 8) +#define RT5640_MIC_OVCD_SF_1P0 (0x2 << 8) +#define RT5640_MIC_OVCD_SF_1P5 (0x3 << 8) + /* 3D Speaker Control (0x63) */ #define RT5640_3D_SPK_MASK (0x1 << 15) #define RT5640_3D_SPK_SFT 15 @@ -2106,6 +2125,7 @@ struct rt5640_priv { struct clk *mclk;
int ldo1_en; /* GPIO for LDO1_EN */ + int irq; int sysclk; int sysclk_src; int lrck[RT5640_AIFS]; @@ -2118,6 +2138,14 @@ struct rt5640_priv {
bool hp_mute; bool asrc_en; + + /* Jack detect data */ + struct work_struct jack_work; + struct snd_soc_jack *jack; + unsigned int jd_src; + bool jd_inverted; + unsigned int ovcd_th; + unsigned int ovcd_sf; };
int rt5640_dmic_enable(struct snd_soc_component *component,
Enable button press detection for headsets by using the ovcd IRQ to get notified of button presses.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/soc/codecs/rt5640.c | 157 ++++++++++++++++++++++++++++++++++++-- sound/soc/codecs/rt5640.h | 9 ++- 2 files changed, 159 insertions(+), 7 deletions(-)
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 8e306f509601..8bf8d360c25f 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2119,6 +2119,24 @@ static void rt5640_disable_micbias1_for_ovcd(struct snd_soc_component *component snd_soc_dapm_mutex_unlock(dapm); }
+static void rt5640_enable_micbias1_ovcd_irq(struct snd_soc_component *component) +{ + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + + snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2, + RT5640_IRQ_MB1_OC_MASK, RT5640_IRQ_MB1_OC_NOR); + rt5640->ovcd_irq_enabled = true; +} + +static void rt5640_disable_micbias1_ovcd_irq(struct snd_soc_component *component) +{ + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + + snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2, + RT5640_IRQ_MB1_OC_MASK, RT5640_IRQ_MB1_OC_BP); + rt5640->ovcd_irq_enabled = false; +} + static void rt5640_clear_micbias1_ovcd(struct snd_soc_component *component) { snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2, @@ -2149,10 +2167,80 @@ static bool rt5640_jack_inserted(struct snd_soc_component *component) return (val & RT5640_JD_STATUS); }
-/* Jack detect timings */ +/* Jack detect and button-press timings */ #define JACK_SETTLE_TIME 100 /* milli seconds */ #define JACK_DETECT_COUNT 5 #define JACK_DETECT_MAXCOUNT 20 /* Aprox. 2 seconds worth of tries */ +#define JACK_UNPLUG_TIME 80 /* milli seconds */ +#define BP_POLL_TIME 10 /* milli seconds */ +#define BP_POLL_MAXCOUNT 200 /* assume something is wrong after this */ +#define BP_THRESHOLD 3 + +static void rt5640_start_button_press_work(struct snd_soc_component *component) +{ + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + + rt5640->poll_count = 0; + rt5640->press_count = 0; + rt5640->release_count = 0; + rt5640->pressed = false; + rt5640->press_reported = false; + rt5640_clear_micbias1_ovcd(component); + schedule_delayed_work(&rt5640->bp_work, msecs_to_jiffies(BP_POLL_TIME)); +} + +static void rt5640_button_press_work(struct work_struct *work) +{ + struct rt5640_priv *rt5640 = + container_of(work, struct rt5640_priv, bp_work.work); + struct snd_soc_component *component = rt5640->component; + + /* Check the jack was not removed underneath us */ + if (!rt5640_jack_inserted(component)) + return; + + if (rt5640_micbias1_ovcd(component)) { + rt5640->release_count = 0; + rt5640->press_count++; + /* Remember till after JACK_UNPLUG_TIME wait */ + if (rt5640->press_count >= BP_THRESHOLD) + rt5640->pressed = true; + rt5640_clear_micbias1_ovcd(component); + } else { + rt5640->press_count = 0; + rt5640->release_count++; + } + + /* + * The pins get temporarily shorted on jack unplug, so we poll for + * at least JACK_UNPLUG_TIME milli-seconds before reporting a press. + */ + rt5640->poll_count++; + if (rt5640->poll_count < (JACK_UNPLUG_TIME / BP_POLL_TIME)) { + schedule_delayed_work(&rt5640->bp_work, + msecs_to_jiffies(BP_POLL_TIME)); + return; + } + + if (rt5640->pressed && !rt5640->press_reported) { + dev_dbg(component->dev, "headset button press\n"); + snd_soc_jack_report(rt5640->jack, SND_JACK_BTN_0, + SND_JACK_BTN_0); + rt5640->press_reported = true; + } + + if (rt5640->release_count >= BP_THRESHOLD) { + if (rt5640->press_reported) { + dev_dbg(component->dev, "headset button release\n"); + snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0); + } + /* Re-enable OVCD IRQ to detect next press */ + rt5640_enable_micbias1_ovcd_irq(component); + return; /* Stop polling */ + } + + schedule_delayed_work(&rt5640->bp_work, msecs_to_jiffies(BP_POLL_TIME)); +}
static int rt5640_detect_headset(struct snd_soc_component *component) { @@ -2209,17 +2297,51 @@ static void rt5640_jack_work(struct work_struct *work) if (!rt5640_jack_inserted(component)) { /* Jack removed, or spurious IRQ? */ if (rt5640->jack->status & SND_JACK_HEADPHONE) { - snd_soc_jack_report(rt5640->jack, 0, SND_JACK_HEADSET); + if (rt5640->jack->status & SND_JACK_MICROPHONE) { + cancel_delayed_work_sync(&rt5640->bp_work); + rt5640_disable_micbias1_ovcd_irq(component); + rt5640_disable_micbias1_for_ovcd(component); + } + snd_soc_jack_report(rt5640->jack, 0, + SND_JACK_HEADSET | SND_JACK_BTN_0); dev_dbg(component->dev, "jack unplugged\n"); } } else if (!(rt5640->jack->status & SND_JACK_HEADPHONE)) { /* Jack inserted */ + WARN_ON(rt5640->ovcd_irq_enabled); rt5640_enable_micbias1_for_ovcd(component); status = rt5640_detect_headset(component); - rt5640_disable_micbias1_for_ovcd(component); - + if (status == SND_JACK_HEADSET) { + /* Enable ovcd IRQ for button press detect. */ + rt5640_enable_micbias1_ovcd_irq(component); + } else { + /* No more need for overcurrent detect. */ + rt5640_disable_micbias1_for_ovcd(component); + } dev_dbg(component->dev, "detect status %#02x\n", status); snd_soc_jack_report(rt5640->jack, status, SND_JACK_HEADSET); + } else if (rt5640->ovcd_irq_enabled && rt5640_micbias1_ovcd(component)) { + dev_dbg(component->dev, "OVCD IRQ\n"); + + /* + * The ovcd IRQ keeps firing while the button is pressed, so + * we disable it and start polling the button until released. + * + * The disable will make the IRQ pin 0 again and since we get + * IRQs on both edges (so as to detect both jack plugin and + * unplug) this means we will immediately get another IRQ. + * The ovcd_irq_enabled check above makes the 2ND IRQ a NOP. + */ + rt5640_disable_micbias1_ovcd_irq(component); + rt5640_start_button_press_work(component); + + /* + * If the jack-detect IRQ flag goes high (unplug) after our + * above rt5640_jack_inserted() check and before we have + * disabled the OVCD IRQ, the IRQ pin will stay high and as + * we react to edges, we miss the unplug event -> recheck. + */ + queue_work(system_long_wq, &rt5640->jack_work); } }
@@ -2238,6 +2360,7 @@ static void rt5640_cancel_work(void *data) struct rt5640_priv *rt5640 = data;
cancel_work_sync(&rt5640->jack_work); + cancel_delayed_work_sync(&rt5640->bp_work); }
static void rt5640_enable_jack_detect(struct snd_soc_component *component, @@ -2282,10 +2405,25 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2, RT5640_MB1_OC_STKY_MASK, RT5640_MB1_OC_STKY_EN);
- snd_soc_component_write(component, RT5640_IRQ_CTRL1, - RT5640_IRQ_JD_NOR); + /* + * All IRQs get or-ed together, so we need the jack IRQ to report 0 + * when a jack is inserted so that the OVCD IRQ then toggles the IRQ + * pin 0/1 instead of it being stuck to 1. So we invert the JD polarity + * on systems where the hardware does not already do this. + */ + if (rt5640->jd_inverted) + snd_soc_component_write(component, RT5640_IRQ_CTRL1, + RT5640_IRQ_JD_NOR); + else + snd_soc_component_write(component, RT5640_IRQ_CTRL1, + RT5640_IRQ_JD_NOR | RT5640_JD_P_INV);
rt5640->jack = jack; + if (rt5640->jack->status & SND_JACK_MICROPHONE) { + rt5640_enable_micbias1_for_ovcd(component); + rt5640_enable_micbias1_ovcd_irq(component); + } + enable_irq(rt5640->irq); /* sync initial jack state */ queue_work(system_long_wq, &rt5640->jack_work); @@ -2298,6 +2436,12 @@ static void rt5640_disable_jack_detect(struct snd_soc_component *component) disable_irq(rt5640->irq); rt5640_cancel_work(rt5640);
+ if (rt5640->jack->status & SND_JACK_MICROPHONE) { + rt5640_disable_micbias1_ovcd_irq(component); + rt5640_disable_micbias1_for_ovcd(component); + snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0); + } + rt5640->jack = NULL; }
@@ -2677,6 +2821,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
rt5640->hp_mute = 1; rt5640->irq = i2c->irq; + INIT_DELAYED_WORK(&rt5640->bp_work, rt5640_button_press_work); INIT_WORK(&rt5640->jack_work, rt5640_jack_work);
/* Make sure work is stopped on probe-error / remove */ diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 9d08471734b3..e29e3e7d61b0 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -2139,7 +2139,14 @@ struct rt5640_priv { bool hp_mute; bool asrc_en;
- /* Jack detect data */ + /* Jack and button detect data */ + bool ovcd_irq_enabled; + bool pressed; + bool press_reported; + int press_count; + int release_count; + int poll_count; + struct delayed_work bp_work; struct work_struct jack_work; struct snd_soc_jack *jack; unsigned int jd_src;
The patch
ASoC: rt5640: Add button press support
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From b16188a20f62b4d2f2bc7ede2ca3b15253184352 Mon Sep 17 00:00:00 2001
From: Hans de Goede hdegoede@redhat.com Date: Tue, 8 May 2018 17:35:52 +0200 Subject: [PATCH] ASoC: rt5640: Add button press support
Enable button press detection for headsets by using the ovcd IRQ to get notified of button presses.
Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/rt5640.c | 157 ++++++++++++++++++++++++++++++++++++-- sound/soc/codecs/rt5640.h | 9 ++- 2 files changed, 159 insertions(+), 7 deletions(-)
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 8e306f509601..8bf8d360c25f 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2119,6 +2119,24 @@ static void rt5640_disable_micbias1_for_ovcd(struct snd_soc_component *component snd_soc_dapm_mutex_unlock(dapm); }
+static void rt5640_enable_micbias1_ovcd_irq(struct snd_soc_component *component) +{ + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + + snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2, + RT5640_IRQ_MB1_OC_MASK, RT5640_IRQ_MB1_OC_NOR); + rt5640->ovcd_irq_enabled = true; +} + +static void rt5640_disable_micbias1_ovcd_irq(struct snd_soc_component *component) +{ + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + + snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2, + RT5640_IRQ_MB1_OC_MASK, RT5640_IRQ_MB1_OC_BP); + rt5640->ovcd_irq_enabled = false; +} + static void rt5640_clear_micbias1_ovcd(struct snd_soc_component *component) { snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2, @@ -2149,10 +2167,80 @@ static bool rt5640_jack_inserted(struct snd_soc_component *component) return (val & RT5640_JD_STATUS); }
-/* Jack detect timings */ +/* Jack detect and button-press timings */ #define JACK_SETTLE_TIME 100 /* milli seconds */ #define JACK_DETECT_COUNT 5 #define JACK_DETECT_MAXCOUNT 20 /* Aprox. 2 seconds worth of tries */ +#define JACK_UNPLUG_TIME 80 /* milli seconds */ +#define BP_POLL_TIME 10 /* milli seconds */ +#define BP_POLL_MAXCOUNT 200 /* assume something is wrong after this */ +#define BP_THRESHOLD 3 + +static void rt5640_start_button_press_work(struct snd_soc_component *component) +{ + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + + rt5640->poll_count = 0; + rt5640->press_count = 0; + rt5640->release_count = 0; + rt5640->pressed = false; + rt5640->press_reported = false; + rt5640_clear_micbias1_ovcd(component); + schedule_delayed_work(&rt5640->bp_work, msecs_to_jiffies(BP_POLL_TIME)); +} + +static void rt5640_button_press_work(struct work_struct *work) +{ + struct rt5640_priv *rt5640 = + container_of(work, struct rt5640_priv, bp_work.work); + struct snd_soc_component *component = rt5640->component; + + /* Check the jack was not removed underneath us */ + if (!rt5640_jack_inserted(component)) + return; + + if (rt5640_micbias1_ovcd(component)) { + rt5640->release_count = 0; + rt5640->press_count++; + /* Remember till after JACK_UNPLUG_TIME wait */ + if (rt5640->press_count >= BP_THRESHOLD) + rt5640->pressed = true; + rt5640_clear_micbias1_ovcd(component); + } else { + rt5640->press_count = 0; + rt5640->release_count++; + } + + /* + * The pins get temporarily shorted on jack unplug, so we poll for + * at least JACK_UNPLUG_TIME milli-seconds before reporting a press. + */ + rt5640->poll_count++; + if (rt5640->poll_count < (JACK_UNPLUG_TIME / BP_POLL_TIME)) { + schedule_delayed_work(&rt5640->bp_work, + msecs_to_jiffies(BP_POLL_TIME)); + return; + } + + if (rt5640->pressed && !rt5640->press_reported) { + dev_dbg(component->dev, "headset button press\n"); + snd_soc_jack_report(rt5640->jack, SND_JACK_BTN_0, + SND_JACK_BTN_0); + rt5640->press_reported = true; + } + + if (rt5640->release_count >= BP_THRESHOLD) { + if (rt5640->press_reported) { + dev_dbg(component->dev, "headset button release\n"); + snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0); + } + /* Re-enable OVCD IRQ to detect next press */ + rt5640_enable_micbias1_ovcd_irq(component); + return; /* Stop polling */ + } + + schedule_delayed_work(&rt5640->bp_work, msecs_to_jiffies(BP_POLL_TIME)); +}
static int rt5640_detect_headset(struct snd_soc_component *component) { @@ -2209,17 +2297,51 @@ static void rt5640_jack_work(struct work_struct *work) if (!rt5640_jack_inserted(component)) { /* Jack removed, or spurious IRQ? */ if (rt5640->jack->status & SND_JACK_HEADPHONE) { - snd_soc_jack_report(rt5640->jack, 0, SND_JACK_HEADSET); + if (rt5640->jack->status & SND_JACK_MICROPHONE) { + cancel_delayed_work_sync(&rt5640->bp_work); + rt5640_disable_micbias1_ovcd_irq(component); + rt5640_disable_micbias1_for_ovcd(component); + } + snd_soc_jack_report(rt5640->jack, 0, + SND_JACK_HEADSET | SND_JACK_BTN_0); dev_dbg(component->dev, "jack unplugged\n"); } } else if (!(rt5640->jack->status & SND_JACK_HEADPHONE)) { /* Jack inserted */ + WARN_ON(rt5640->ovcd_irq_enabled); rt5640_enable_micbias1_for_ovcd(component); status = rt5640_detect_headset(component); - rt5640_disable_micbias1_for_ovcd(component); - + if (status == SND_JACK_HEADSET) { + /* Enable ovcd IRQ for button press detect. */ + rt5640_enable_micbias1_ovcd_irq(component); + } else { + /* No more need for overcurrent detect. */ + rt5640_disable_micbias1_for_ovcd(component); + } dev_dbg(component->dev, "detect status %#02x\n", status); snd_soc_jack_report(rt5640->jack, status, SND_JACK_HEADSET); + } else if (rt5640->ovcd_irq_enabled && rt5640_micbias1_ovcd(component)) { + dev_dbg(component->dev, "OVCD IRQ\n"); + + /* + * The ovcd IRQ keeps firing while the button is pressed, so + * we disable it and start polling the button until released. + * + * The disable will make the IRQ pin 0 again and since we get + * IRQs on both edges (so as to detect both jack plugin and + * unplug) this means we will immediately get another IRQ. + * The ovcd_irq_enabled check above makes the 2ND IRQ a NOP. + */ + rt5640_disable_micbias1_ovcd_irq(component); + rt5640_start_button_press_work(component); + + /* + * If the jack-detect IRQ flag goes high (unplug) after our + * above rt5640_jack_inserted() check and before we have + * disabled the OVCD IRQ, the IRQ pin will stay high and as + * we react to edges, we miss the unplug event -> recheck. + */ + queue_work(system_long_wq, &rt5640->jack_work); } }
@@ -2238,6 +2360,7 @@ static void rt5640_cancel_work(void *data) struct rt5640_priv *rt5640 = data;
cancel_work_sync(&rt5640->jack_work); + cancel_delayed_work_sync(&rt5640->bp_work); }
static void rt5640_enable_jack_detect(struct snd_soc_component *component, @@ -2282,10 +2405,25 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2, RT5640_MB1_OC_STKY_MASK, RT5640_MB1_OC_STKY_EN);
- snd_soc_component_write(component, RT5640_IRQ_CTRL1, - RT5640_IRQ_JD_NOR); + /* + * All IRQs get or-ed together, so we need the jack IRQ to report 0 + * when a jack is inserted so that the OVCD IRQ then toggles the IRQ + * pin 0/1 instead of it being stuck to 1. So we invert the JD polarity + * on systems where the hardware does not already do this. + */ + if (rt5640->jd_inverted) + snd_soc_component_write(component, RT5640_IRQ_CTRL1, + RT5640_IRQ_JD_NOR); + else + snd_soc_component_write(component, RT5640_IRQ_CTRL1, + RT5640_IRQ_JD_NOR | RT5640_JD_P_INV);
rt5640->jack = jack; + if (rt5640->jack->status & SND_JACK_MICROPHONE) { + rt5640_enable_micbias1_for_ovcd(component); + rt5640_enable_micbias1_ovcd_irq(component); + } + enable_irq(rt5640->irq); /* sync initial jack state */ queue_work(system_long_wq, &rt5640->jack_work); @@ -2298,6 +2436,12 @@ static void rt5640_disable_jack_detect(struct snd_soc_component *component) disable_irq(rt5640->irq); rt5640_cancel_work(rt5640);
+ if (rt5640->jack->status & SND_JACK_MICROPHONE) { + rt5640_disable_micbias1_ovcd_irq(component); + rt5640_disable_micbias1_for_ovcd(component); + snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0); + } + rt5640->jack = NULL; }
@@ -2677,6 +2821,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
rt5640->hp_mute = 1; rt5640->irq = i2c->irq; + INIT_DELAYED_WORK(&rt5640->bp_work, rt5640_button_press_work); INIT_WORK(&rt5640->jack_work, rt5640_jack_work);
/* Make sure work is stopped on probe-error / remove */ diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 9d08471734b3..e29e3e7d61b0 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -2139,7 +2139,14 @@ struct rt5640_priv { bool hp_mute; bool asrc_en;
- /* Jack detect data */ + /* Jack and button detect data */ + bool ovcd_irq_enabled; + bool pressed; + bool press_reported; + int press_count; + int release_count; + int poll_count; + struct delayed_work bp_work; struct work_struct jack_work; struct snd_soc_jack *jack; unsigned int jd_src;
When platform_clock_control() first selects PLL1 as sysclk the PLL_CTRL registers have not been setup yet and we effectively have an invalid clock configuration until byt_rt5640_aif1_hw_params() gets called.
Add a new byt_rt5640_prepare_and_enable_pll1() helper and use that from both platform_clock_control() and byt_rt5640_aif1_hw_params() to fix this.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/soc/intel/boards/bytcr_rt5640.c | 100 +++++++++++++------------- 1 file changed, 49 insertions(+), 51 deletions(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 84ce98ebd00e..0f587d394b06 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -141,6 +141,52 @@ static void log_quirks(struct device *dev) } }
+static int byt_rt5640_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, + int rate) +{ + int ret; + + /* Configure the PLL before selecting it */ + if (!(byt_rt5640_quirk & BYT_RT5640_MCLK_EN)) { + /* use bitclock as PLL input */ + if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || + (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { + /* 2x16 bit slots on SSP0 */ + ret = snd_soc_dai_set_pll(codec_dai, 0, + RT5640_PLL1_S_BCLK1, + rate * 32, rate * 512); + } else { + /* 2x15 bit slots on SSP2 */ + ret = snd_soc_dai_set_pll(codec_dai, 0, + RT5640_PLL1_S_BCLK1, + rate * 50, rate * 512); + } + } else { + if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) { + ret = snd_soc_dai_set_pll(codec_dai, 0, + RT5640_PLL1_S_MCLK, + 25000000, rate * 512); + } else { + ret = snd_soc_dai_set_pll(codec_dai, 0, + RT5640_PLL1_S_MCLK, + 19200000, rate * 512); + } + } + + if (ret < 0) { + dev_err(codec_dai->codec->dev, "can't set pll: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, + rate * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->codec->dev, "can't set clock %d\n", ret); + return ret; + } + + return 0; +}
#define BYT_CODEC_DAI1 "rt5640-aif1" #define BYT_CODEC_DAI2 "rt5640-aif2" @@ -173,9 +219,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, return ret; } } - ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, - 48000 * 512, - SND_SOC_CLOCK_IN); + ret = byt_rt5640_prepare_and_enable_pll1(codec_dai, 48000); } else { /* * Set codec clock source to internal clock before @@ -299,55 +343,9 @@ static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, - params_rate(params) * 512, - SND_SOC_CLOCK_IN); - - if (ret < 0) { - dev_err(rtd->dev, "can't set codec clock %d\n", ret); - return ret; - } + struct snd_soc_dai *dai = rtd->codec_dai;
- if (!(byt_rt5640_quirk & BYT_RT5640_MCLK_EN)) { - /* use bitclock as PLL input */ - if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || - (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { - - /* 2x16 bit slots on SSP0 */ - ret = snd_soc_dai_set_pll(codec_dai, 0, - RT5640_PLL1_S_BCLK1, - params_rate(params) * 32, - params_rate(params) * 512); - } else { - /* 2x15 bit slots on SSP2 */ - ret = snd_soc_dai_set_pll(codec_dai, 0, - RT5640_PLL1_S_BCLK1, - params_rate(params) * 50, - params_rate(params) * 512); - } - } else { - if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) { - ret = snd_soc_dai_set_pll(codec_dai, 0, - RT5640_PLL1_S_MCLK, - 25000000, - params_rate(params) * 512); - } else { - ret = snd_soc_dai_set_pll(codec_dai, 0, - RT5640_PLL1_S_MCLK, - 19200000, - params_rate(params) * 512); - } - } - - if (ret < 0) { - dev_err(rtd->dev, "can't set codec pll: %d\n", ret); - return ret; - } - - return 0; + return byt_rt5640_prepare_and_enable_pll1(dai, params_rate(params)); }
static int byt_rt5640_quirk_cb(const struct dmi_system_id *id)
The patch
ASoC: Intel: bytcr_rt5640: Configure PLL1 before using it
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From bcd9a325f0b0f407c4559779a94e802977c67274 Mon Sep 17 00:00:00 2001
From: Hans de Goede hdegoede@redhat.com Date: Tue, 8 May 2018 17:35:53 +0200 Subject: [PATCH] ASoC: Intel: bytcr_rt5640: Configure PLL1 before using it
When platform_clock_control() first selects PLL1 as sysclk the PLL_CTRL registers have not been setup yet and we effectively have an invalid clock configuration until byt_rt5640_aif1_hw_params() gets called.
Add a new byt_rt5640_prepare_and_enable_pll1() helper and use that from both platform_clock_control() and byt_rt5640_aif1_hw_params() to fix this.
Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bytcr_rt5640.c | 100 +++++++++++++------------- 1 file changed, 49 insertions(+), 51 deletions(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index ad5fcd5a1762..c540dfdf045d 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -141,6 +141,52 @@ static void log_quirks(struct device *dev) } }
+static int byt_rt5640_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, + int rate) +{ + int ret; + + /* Configure the PLL before selecting it */ + if (!(byt_rt5640_quirk & BYT_RT5640_MCLK_EN)) { + /* use bitclock as PLL input */ + if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || + (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { + /* 2x16 bit slots on SSP0 */ + ret = snd_soc_dai_set_pll(codec_dai, 0, + RT5640_PLL1_S_BCLK1, + rate * 32, rate * 512); + } else { + /* 2x15 bit slots on SSP2 */ + ret = snd_soc_dai_set_pll(codec_dai, 0, + RT5640_PLL1_S_BCLK1, + rate * 50, rate * 512); + } + } else { + if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) { + ret = snd_soc_dai_set_pll(codec_dai, 0, + RT5640_PLL1_S_MCLK, + 25000000, rate * 512); + } else { + ret = snd_soc_dai_set_pll(codec_dai, 0, + RT5640_PLL1_S_MCLK, + 19200000, rate * 512); + } + } + + if (ret < 0) { + dev_err(codec_dai->codec->dev, "can't set pll: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, + rate * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->codec->dev, "can't set clock %d\n", ret); + return ret; + } + + return 0; +}
#define BYT_CODEC_DAI1 "rt5640-aif1" #define BYT_CODEC_DAI2 "rt5640-aif2" @@ -173,9 +219,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, return ret; } } - ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, - 48000 * 512, - SND_SOC_CLOCK_IN); + ret = byt_rt5640_prepare_and_enable_pll1(codec_dai, 48000); } else { /* * Set codec clock source to internal clock before @@ -299,55 +343,9 @@ static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, - params_rate(params) * 512, - SND_SOC_CLOCK_IN); - - if (ret < 0) { - dev_err(rtd->dev, "can't set codec clock %d\n", ret); - return ret; - } + struct snd_soc_dai *dai = rtd->codec_dai;
- if (!(byt_rt5640_quirk & BYT_RT5640_MCLK_EN)) { - /* use bitclock as PLL input */ - if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || - (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { - - /* 2x16 bit slots on SSP0 */ - ret = snd_soc_dai_set_pll(codec_dai, 0, - RT5640_PLL1_S_BCLK1, - params_rate(params) * 32, - params_rate(params) * 512); - } else { - /* 2x15 bit slots on SSP2 */ - ret = snd_soc_dai_set_pll(codec_dai, 0, - RT5640_PLL1_S_BCLK1, - params_rate(params) * 50, - params_rate(params) * 512); - } - } else { - if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) { - ret = snd_soc_dai_set_pll(codec_dai, 0, - RT5640_PLL1_S_MCLK, - 25000000, - params_rate(params) * 512); - } else { - ret = snd_soc_dai_set_pll(codec_dai, 0, - RT5640_PLL1_S_MCLK, - 19200000, - params_rate(params) * 512); - } - } - - if (ret < 0) { - dev_err(rtd->dev, "can't set codec pll: %d\n", ret); - return ret; - } - - return 0; + return byt_rt5640_prepare_and_enable_pll1(dai, params_rate(params)); }
static int byt_rt5640_quirk_cb(const struct dmi_system_id *id)
Set the "realtek,in1-differential" or "realtek,in3-differential" device-property when the BYT_RT5640_DIFF_MIC quirk is set instead of directly poking the codec registers.
This also fixes the BYT_RT5640_DIFF_MIC quirk not working when combined with BYT_RT5640_IN3_MAP.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/soc/intel/boards/bytcr_rt5640.c | 48 ++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 0f587d394b06..81d0d07449a8 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -17,6 +17,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+#include <linux/i2c.h> #include <linux/init.h> #include <linux/module.h> #include <linux/moduleparam.h> @@ -54,6 +55,9 @@ enum { #define BYT_RT5640_MCLK_EN BIT(22) #define BYT_RT5640_MCLK_25MHZ BIT(23)
+/* in-diff + terminating empty entry */ +#define MAX_NO_PROPS 2 + struct byt_rt5640_private { struct clk *mclk; }; @@ -438,6 +442,39 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { {} };
+/* + * Note this MUST be called before snd_soc_register_card(), so that the props + * are in place before the codec component driver's probe function parses them. + */ +static int byt_rt5640_add_codec_device_props(const char *i2c_dev_name) +{ + struct property_entry props[MAX_NO_PROPS] = {}; + struct device *i2c_dev; + int ret, cnt = 0; + + i2c_dev = bus_find_device_by_name(&i2c_bus_type, NULL, i2c_dev_name); + if (!i2c_dev) + return -EPROBE_DEFER; + + switch (BYT_RT5640_MAP(byt_rt5640_quirk)) { + case BYT_RT5640_IN1_MAP: + if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) + props[cnt++] = + PROPERTY_ENTRY_BOOL("realtek,in1-differential"); + break; + case BYT_RT5640_IN3_MAP: + if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) + props[cnt++] = + PROPERTY_ENTRY_BOOL("realtek,in3-differential"); + break; + } + + ret = device_add_properties(i2c_dev, props); + put_device(i2c_dev); + + return ret; +} + static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_card *card = runtime->card; @@ -519,11 +556,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) if (ret) return ret;
- if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) { - snd_soc_component_update_bits(component, RT5640_IN1_IN2, RT5640_IN_DF1, - RT5640_IN_DF1); - } - if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) { ret = rt5640_dmic_enable(component, 0, 0); if (ret) @@ -837,6 +869,12 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) (unsigned int)byt_rt5640_quirk, quirk_override); byt_rt5640_quirk = quirk_override; } + + /* Must be called before register_card, also see declaration comment. */ + ret_val = byt_rt5640_add_codec_device_props(byt_rt5640_codec_name); + if (ret_val) + return ret_val; + log_quirks(&pdev->dev);
if ((byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) ||
The patch
ASoC: Intel: bytcr_rt5640: Use device-property for differential mics
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 6a7c05e55c0a3d6d4f092d734cd8fee798cf044b Mon Sep 17 00:00:00 2001
From: Hans de Goede hdegoede@redhat.com Date: Tue, 8 May 2018 17:35:54 +0200 Subject: [PATCH] ASoC: Intel: bytcr_rt5640: Use device-property for differential mics
Set the "realtek,in1-differential" or "realtek,in3-differential" device-property when the BYT_RT5640_DIFF_MIC quirk is set instead of directly poking the codec registers.
This also fixes the BYT_RT5640_DIFF_MIC quirk not working when combined with BYT_RT5640_IN3_MAP.
Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bytcr_rt5640.c | 48 ++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index c540dfdf045d..404aa7355912 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -17,6 +17,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+#include <linux/i2c.h> #include <linux/init.h> #include <linux/module.h> #include <linux/moduleparam.h> @@ -54,6 +55,9 @@ enum { #define BYT_RT5640_MCLK_EN BIT(22) #define BYT_RT5640_MCLK_25MHZ BIT(23)
+/* in-diff + terminating empty entry */ +#define MAX_NO_PROPS 2 + struct byt_rt5640_private { struct clk *mclk; }; @@ -438,6 +442,39 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { {} };
+/* + * Note this MUST be called before snd_soc_register_card(), so that the props + * are in place before the codec component driver's probe function parses them. + */ +static int byt_rt5640_add_codec_device_props(const char *i2c_dev_name) +{ + struct property_entry props[MAX_NO_PROPS] = {}; + struct device *i2c_dev; + int ret, cnt = 0; + + i2c_dev = bus_find_device_by_name(&i2c_bus_type, NULL, i2c_dev_name); + if (!i2c_dev) + return -EPROBE_DEFER; + + switch (BYT_RT5640_MAP(byt_rt5640_quirk)) { + case BYT_RT5640_IN1_MAP: + if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) + props[cnt++] = + PROPERTY_ENTRY_BOOL("realtek,in1-differential"); + break; + case BYT_RT5640_IN3_MAP: + if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) + props[cnt++] = + PROPERTY_ENTRY_BOOL("realtek,in3-differential"); + break; + } + + ret = device_add_properties(i2c_dev, props); + put_device(i2c_dev); + + return ret; +} + static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_card *card = runtime->card; @@ -519,11 +556,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) if (ret) return ret;
- if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) { - snd_soc_component_update_bits(component, RT5640_IN1_IN2, RT5640_IN_DF1, - RT5640_IN_DF1); - } - if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) { ret = rt5640_dmic_enable(component, 0, 0); if (ret) @@ -841,6 +873,12 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) (unsigned int)byt_rt5640_quirk, quirk_override); byt_rt5640_quirk = quirk_override; } + + /* Must be called before register_card, also see declaration comment. */ + ret_val = byt_rt5640_add_codec_device_props(byt_rt5640_codec_name); + if (ret_val) + return ret_val; + log_quirks(&pdev->dev);
if ((byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) ||
Use device-properties for setting up the dmic, based on the BYT_RT5640_MAP() value, instead of using the codec specific rt5640_dmic_enable() function for this. This also removes the need for the BYT_RT5640_DMIC_EN quirk, which was always set together with a MAP() quirk of DMIC1_MAP or DMIC2_MAP.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/soc/intel/boards/bytcr_rt5640.c | 42 +++++++++------------------ 1 file changed, 14 insertions(+), 28 deletions(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 81d0d07449a8..8b8716575910 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -34,6 +34,7 @@ #include <sound/soc.h> #include <sound/jack.h> #include <sound/soc-acpi.h> +#include <dt-bindings/sound/rt5640.h> #include "../../codecs/rt5640.h" #include "../atom/sst-atom-controls.h" #include "../common/sst-dsp.h" @@ -46,7 +47,6 @@ enum { };
#define BYT_RT5640_MAP(quirk) ((quirk) & GENMASK(7, 0)) -#define BYT_RT5640_DMIC_EN BIT(16) #define BYT_RT5640_MONO_SPEAKER BIT(17) #define BYT_RT5640_DIFF_MIC BIT(18) /* defaut is single-ended */ #define BYT_RT5640_SSP2_AIF2 BIT(19) /* default is using AIF1 */ @@ -55,7 +55,7 @@ enum { #define BYT_RT5640_MCLK_EN BIT(22) #define BYT_RT5640_MCLK_25MHZ BIT(23)
-/* in-diff + terminating empty entry */ +/* in-diff or dmic-pin + terminating empty entry */ #define MAX_NO_PROPS 2
struct byt_rt5640_private { @@ -71,7 +71,6 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override"); static void log_quirks(struct device *dev) { int map; - bool has_dmic = false; bool has_mclk = false; bool has_ssp0 = false; bool has_ssp0_aif1 = false; @@ -82,11 +81,9 @@ static void log_quirks(struct device *dev) switch (map) { case BYT_RT5640_DMIC1_MAP: dev_info(dev, "quirk DMIC1_MAP enabled\n"); - has_dmic = true; break; case BYT_RT5640_DMIC2_MAP: dev_info(dev, "quirk DMIC2_MAP enabled\n"); - has_dmic = true; break; case BYT_RT5640_IN1_MAP: dev_info(dev, "quirk IN1_MAP enabled\n"); @@ -98,20 +95,10 @@ static void log_quirks(struct device *dev) dev_err(dev, "quirk map 0x%x is not supported, microphone input will not work\n", map); break; } - if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) { - if (has_dmic) - dev_info(dev, "quirk DMIC enabled\n"); - else - dev_err(dev, "quirk DMIC enabled but no DMIC input set, will be ignored\n"); - } if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) dev_info(dev, "quirk MONO_SPEAKER enabled\n"); - if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) { - if (!has_dmic) - dev_info(dev, "quirk DIFF_MIC enabled\n"); - else - dev_info(dev, "quirk DIFF_MIC enabled but DMIC input selected, will be ignored\n"); - } + if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) + dev_info(dev, "quirk DIFF_MIC enabled\n"); if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) { dev_info(dev, "quirk SSP0_AIF1 enabled\n"); has_ssp0 = true; @@ -387,7 +374,6 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), }, .driver_data = (void *)(BYT_RT5640_DMIC2_MAP | - BYT_RT5640_DMIC_EN | BYT_RT5640_MCLK_EN), }, { @@ -405,8 +391,7 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"), }, - .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | - BYT_RT5640_DMIC_EN), + .driver_data = (void *)(BYT_RT5640_DMIC1_MAP), }, { .callback = byt_rt5640_quirk_cb, @@ -457,6 +442,14 @@ static int byt_rt5640_add_codec_device_props(const char *i2c_dev_name) return -EPROBE_DEFER;
switch (BYT_RT5640_MAP(byt_rt5640_quirk)) { + case BYT_RT5640_DMIC1_MAP: + props[cnt++] = PROPERTY_ENTRY_U32("realtek,dmic1-data-pin", + RT5640_DMIC1_DATA_PIN_IN1P); + break; + case BYT_RT5640_DMIC2_MAP: + props[cnt++] = PROPERTY_ENTRY_U32("realtek,dmic2-data-pin", + RT5640_DMIC2_DATA_PIN_IN1N); + break; case BYT_RT5640_IN1_MAP: if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) props[cnt++] = @@ -556,12 +549,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) if (ret) return ret;
- if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) { - ret = rt5640_dmic_enable(component, 0, 0); - if (ret) - return ret; - } - if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) { /* * The firmware might enable the clock at @@ -858,8 +845,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) byt_rt5640_quirk |= BYT_RT5640_IN1_MAP; byt_rt5640_quirk |= BYT_RT5640_DIFF_MIC; } else { - byt_rt5640_quirk |= (BYT_RT5640_DMIC1_MAP | - BYT_RT5640_DMIC_EN); + byt_rt5640_quirk |= BYT_RT5640_DMIC1_MAP; }
/* check quirks before creating card */
On Tue, May 08, 2018 at 05:35:55PM +0200, Hans de Goede wrote:
Use device-properties for setting up the dmic, based on the BYT_RT5640_MAP() value, instead of using the codec specific rt5640_dmic_enable() function for this. This also removes the need for the BYT_RT5640_DMIC_EN quirk, which was always set together with a MAP() quirk of DMIC1_MAP or DMIC2_MAP.
This doesn't apply against current code, please check and resend.
This fixes the following 3 issues:
1) The sys_vendor match should be for "Dell Inc." not "DellInc.", without this fixed the quirk never gets applied 2) DMIC1 is used not DMIC2, this was not a problem sofar because for regular BYT boards (rather then BYTCR) we default to DMIC1 and because of 1. the quirk was not being applied 3) The Dell Venue 8 5830 Pro only has a single speaker
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/soc/intel/boards/bytcr_rt5640.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 8b8716575910..ac9ba5aa2dc3 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -370,10 +370,11 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { { .callback = byt_rt5640_quirk_cb, .matches = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "DellInc."), + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), }, - .driver_data = (void *)(BYT_RT5640_DMIC2_MAP | + .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | + BYT_RT5640_MONO_SPEAKER | BYT_RT5640_MCLK_EN), }, {
The patch
ASoC: Intel: bytcr_rt5640: Fix Dell Venue 8 5830 Pro quirk
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 6748fb7e77ebff6a216243076cf162c1c700e9d6 Mon Sep 17 00:00:00 2001
From: Hans de Goede hdegoede@redhat.com Date: Sun, 13 May 2018 09:24:27 +0200 Subject: [PATCH] ASoC: Intel: bytcr_rt5640: Fix Dell Venue 8 5830 Pro quirk
This fixes the following 3 issues:
1) The sys_vendor match should be for "Dell Inc." not "DellInc.", without this fixed the quirk never gets applied 2) DMIC1 is used not DMIC2, this was not a problem sofar because for regular BYT boards (rather then BYTCR) we default to DMIC1 and because of 1. the quirk was not being applied 3) The Dell Venue 8 5830 Pro only has a single speaker
Signed-off-by: Hans de Goede hdegoede@redhat.com Acked-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bytcr_rt5640.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index cc607cfeda56..d0706ea3b04f 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -370,10 +370,11 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { { .callback = byt_rt5640_quirk_cb, .matches = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "DellInc."), + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), }, - .driver_data = (void *)(BYT_RT5640_DMIC2_MAP | + .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | + BYT_RT5640_MONO_SPEAKER | BYT_RT5640_MCLK_EN), }, {
Add code to support setting jack-detect parameters through quirks and extend the existing DMI quirk table entries for the Asus T100TA and the Dell Venue 8 Pro 5830 to enable jack detection.
Tested-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/soc/intel/boards/bytcr_rt5640.c | 164 +++++++++++++++++++++++--- 1 file changed, 148 insertions(+), 16 deletions(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index ac9ba5aa2dc3..6be4e8972010 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -26,6 +26,7 @@ #include <linux/clk.h> #include <linux/device.h> #include <linux/dmi.h> +#include <linux/input.h> #include <linux/slab.h> #include <asm/cpu_device_id.h> #include <asm/platform_sst_audio.h> @@ -46,19 +47,46 @@ enum { BYT_RT5640_IN3_MAP, };
-#define BYT_RT5640_MAP(quirk) ((quirk) & GENMASK(7, 0)) -#define BYT_RT5640_MONO_SPEAKER BIT(17) -#define BYT_RT5640_DIFF_MIC BIT(18) /* defaut is single-ended */ -#define BYT_RT5640_SSP2_AIF2 BIT(19) /* default is using AIF1 */ -#define BYT_RT5640_SSP0_AIF1 BIT(20) -#define BYT_RT5640_SSP0_AIF2 BIT(21) -#define BYT_RT5640_MCLK_EN BIT(22) -#define BYT_RT5640_MCLK_25MHZ BIT(23) +enum { + BYT_RT5640_JD_SRC_GPIO1 = (RT5640_JD_SRC_GPIO1 << 4), + BYT_RT5640_JD_SRC_JD1_IN4P = (RT5640_JD_SRC_JD1_IN4P << 4), + BYT_RT5640_JD_SRC_JD2_IN4N = (RT5640_JD_SRC_JD2_IN4N << 4), + BYT_RT5640_JD_SRC_GPIO2 = (RT5640_JD_SRC_GPIO2 << 4), + BYT_RT5640_JD_SRC_GPIO3 = (RT5640_JD_SRC_GPIO3 << 4), + BYT_RT5640_JD_SRC_GPIO4 = (RT5640_JD_SRC_GPIO4 << 4), +}; + +enum { + BYT_RT5640_OVCD_TH_600UA = (6 << 8), + BYT_RT5640_OVCD_TH_1500UA = (15 << 8), + BYT_RT5640_OVCD_TH_2000UA = (20 << 8), +}; + +enum { + BYT_RT5640_OVCD_SF_0P5 = (RT5640_OVCD_SF_0P5 << 13), + BYT_RT5640_OVCD_SF_0P75 = (RT5640_OVCD_SF_0P75 << 13), + BYT_RT5640_OVCD_SF_1P0 = (RT5640_OVCD_SF_1P0 << 13), + BYT_RT5640_OVCD_SF_1P5 = (RT5640_OVCD_SF_1P5 << 13), +};
-/* in-diff or dmic-pin + terminating empty entry */ -#define MAX_NO_PROPS 2 +#define BYT_RT5640_MAP(quirk) ((quirk) & GENMASK(3, 0)) +#define BYT_RT5640_JDSRC(quirk) (((quirk) & GENMASK(7, 4)) >> 4) +#define BYT_RT5640_OVCD_TH(quirk) (((quirk) & GENMASK(12, 8)) >> 8) +#define BYT_RT5640_OVCD_SF(quirk) (((quirk) & GENMASK(14, 13)) >> 13) +#define BYT_RT5640_JD_NOT_INV BIT(16) +#define BYT_RT5640_MONO_SPEAKER BIT(17) +#define BYT_RT5640_DIFF_MIC BIT(18) /* default is single-ended */ +#define BYT_RT5640_SSP2_AIF2 BIT(19) /* default is using AIF1 */ +#define BYT_RT5640_SSP0_AIF1 BIT(20) +#define BYT_RT5640_SSP0_AIF2 BIT(21) +#define BYT_RT5640_MCLK_EN BIT(22) +#define BYT_RT5640_MCLK_25MHZ BIT(23) + +/* in-diff or dmic-pin + jdsrc + ovcd-th + -sf + jd-inv + terminating entry */ +#define MAX_NO_PROPS 6
struct byt_rt5640_private { + struct snd_soc_jack jack; struct clk *mclk; }; static bool is_bytcr; @@ -95,6 +123,16 @@ static void log_quirks(struct device *dev) dev_err(dev, "quirk map 0x%x is not supported, microphone input will not work\n", map); break; } + if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) { + dev_info(dev, "quirk realtek,jack-detect-source %ld\n", + BYT_RT5640_JDSRC(byt_rt5640_quirk)); + dev_info(dev, "quirk realtek,over-current-threshold-microamp %ld\n", + BYT_RT5640_OVCD_TH(byt_rt5640_quirk) * 100); + dev_info(dev, "quirk realtek,over-current-scale-factor %ld\n", + BYT_RT5640_OVCD_SF(byt_rt5640_quirk)); + } + if (byt_rt5640_quirk & BYT_RT5640_JD_NOT_INV) + dev_info(dev, "quirk JD_NOT_INV enabled\n"); if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) dev_info(dev, "quirk MONO_SPEAKER enabled\n"); if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) @@ -330,6 +368,17 @@ static const struct snd_kcontrol_new byt_rt5640_controls[] = { SOC_DAPM_PIN_SWITCH("Speaker"), };
+static struct snd_soc_jack_pin rt5640_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -353,6 +402,9 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"), }, .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | BYT_RT5640_MCLK_EN), }, { @@ -374,6 +426,9 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), }, .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | BYT_RT5640_MONO_SPEAKER | BYT_RT5640_MCLK_EN), }, @@ -463,6 +518,23 @@ static int byt_rt5640_add_codec_device_props(const char *i2c_dev_name) break; }
+ if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) { + props[cnt++] = PROPERTY_ENTRY_U32( + "realtek,jack-detect-source", + BYT_RT5640_JDSRC(byt_rt5640_quirk)); + + props[cnt++] = PROPERTY_ENTRY_U32( + "realtek,over-current-threshold-microamp", + BYT_RT5640_OVCD_TH(byt_rt5640_quirk) * 100); + + props[cnt++] = PROPERTY_ENTRY_U32( + "realtek,over-current-scale-factor", + BYT_RT5640_OVCD_SF(byt_rt5640_quirk)); + } + + if (byt_rt5640_quirk & BYT_RT5640_JD_NOT_INV) + props[cnt++] = PROPERTY_ENTRY_BOOL("realtek,jack-detect-not-inverted"); + ret = device_add_properties(i2c_dev, props); put_device(i2c_dev);
@@ -480,6 +552,11 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
card->dapm.idle_bias_off = true;
+ /* Start with RC clk for jack-detect (we disable MCLK below) */ + if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) + snd_soc_component_update_bits(component, RT5640_GLB_CLK, + RT5640_SCLK_SRC_MASK, RT5640_SCLK_SRC_RCCLK); + rt5640_sel_asrc_clk_src(component, RT5640_DA_STEREO_FILTER | RT5640_DA_MONO_L_FILTER | @@ -570,11 +647,27 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) else ret = clk_set_rate(priv->mclk, 19200000);
- if (ret) + if (ret) { dev_err(card->dev, "unable to set MCLK rate\n"); + return ret; + } }
- return ret; + if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) { + ret = snd_soc_card_jack_new(card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &priv->jack, rt5640_pins, + ARRAY_SIZE(rt5640_pins)); + if (ret) { + dev_err(card->dev, "Jack creation failed %d\n", ret); + return ret; + } + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, + KEY_PLAYPAUSE); + snd_soc_component_set_jack(component, &priv->jack, NULL); + } + + return 0; }
static const struct snd_soc_pcm_stream byt_rt5640_dai_params = { @@ -715,6 +808,47 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { };
/* SoC card */ +static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN]; +static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ +static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ + +static int byt_rt5640_suspend(struct snd_soc_card *card) +{ + struct snd_soc_component *component; + + if (!BYT_RT5640_JDSRC(byt_rt5640_quirk)) + return 0; + + list_for_each_entry(component, &card->component_dev_list, card_list) { + if (!strcmp(component->name, byt_rt5640_codec_name)) { + dev_dbg(component->dev, "disabling jack detect before suspend\n"); + snd_soc_component_set_jack(component, NULL, NULL); + break; + } + } + + return 0; +} + +static int byt_rt5640_resume(struct snd_soc_card *card) +{ + struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component; + + if (!BYT_RT5640_JDSRC(byt_rt5640_quirk)) + return 0; + + list_for_each_entry(component, &card->component_dev_list, card_list) { + if (!strcmp(component->name, byt_rt5640_codec_name)) { + dev_dbg(component->dev, "re-enabling jack detect after resume\n"); + snd_soc_component_set_jack(component, &priv->jack, NULL); + break; + } + } + + return 0; +} + static struct snd_soc_card byt_rt5640_card = { .name = "bytcr-rt5640", .owner = THIS_MODULE, @@ -725,12 +859,10 @@ static struct snd_soc_card byt_rt5640_card = { .dapm_routes = byt_rt5640_audio_map, .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map), .fully_routed = true, + .suspend_pre = byt_rt5640_suspend, + .resume_post = byt_rt5640_resume, };
-static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN]; -static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ -static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ - static bool is_valleyview(void) { static const struct x86_cpu_id cpu_ids[] = {
The patch
ASoC: Intel: bytcr_rt5640: Enable jack detection
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 7732310839f61658162967cb43e044311196edf2 Mon Sep 17 00:00:00 2001
From: Hans de Goede hdegoede@redhat.com Date: Sun, 13 May 2018 09:24:28 +0200 Subject: [PATCH] ASoC: Intel: bytcr_rt5640: Enable jack detection
Add code to support setting jack-detect parameters through quirks and extend the existing DMI quirk table entries for the Asus T100TA and the Dell Venue 8 Pro 5830 to enable jack detection.
Tested-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Hans de Goede hdegoede@redhat.com Acked-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bytcr_rt5640.c | 164 +++++++++++++++++++++++--- 1 file changed, 148 insertions(+), 16 deletions(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index d0706ea3b04f..3cdaf87480ef 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -26,6 +26,7 @@ #include <linux/clk.h> #include <linux/device.h> #include <linux/dmi.h> +#include <linux/input.h> #include <linux/slab.h> #include <asm/cpu_device_id.h> #include <asm/platform_sst_audio.h> @@ -46,19 +47,46 @@ enum { BYT_RT5640_IN3_MAP, };
-#define BYT_RT5640_MAP(quirk) ((quirk) & GENMASK(7, 0)) -#define BYT_RT5640_MONO_SPEAKER BIT(17) -#define BYT_RT5640_DIFF_MIC BIT(18) /* defaut is single-ended */ -#define BYT_RT5640_SSP2_AIF2 BIT(19) /* default is using AIF1 */ -#define BYT_RT5640_SSP0_AIF1 BIT(20) -#define BYT_RT5640_SSP0_AIF2 BIT(21) -#define BYT_RT5640_MCLK_EN BIT(22) -#define BYT_RT5640_MCLK_25MHZ BIT(23) +enum { + BYT_RT5640_JD_SRC_GPIO1 = (RT5640_JD_SRC_GPIO1 << 4), + BYT_RT5640_JD_SRC_JD1_IN4P = (RT5640_JD_SRC_JD1_IN4P << 4), + BYT_RT5640_JD_SRC_JD2_IN4N = (RT5640_JD_SRC_JD2_IN4N << 4), + BYT_RT5640_JD_SRC_GPIO2 = (RT5640_JD_SRC_GPIO2 << 4), + BYT_RT5640_JD_SRC_GPIO3 = (RT5640_JD_SRC_GPIO3 << 4), + BYT_RT5640_JD_SRC_GPIO4 = (RT5640_JD_SRC_GPIO4 << 4), +}; + +enum { + BYT_RT5640_OVCD_TH_600UA = (6 << 8), + BYT_RT5640_OVCD_TH_1500UA = (15 << 8), + BYT_RT5640_OVCD_TH_2000UA = (20 << 8), +}; + +enum { + BYT_RT5640_OVCD_SF_0P5 = (RT5640_OVCD_SF_0P5 << 13), + BYT_RT5640_OVCD_SF_0P75 = (RT5640_OVCD_SF_0P75 << 13), + BYT_RT5640_OVCD_SF_1P0 = (RT5640_OVCD_SF_1P0 << 13), + BYT_RT5640_OVCD_SF_1P5 = (RT5640_OVCD_SF_1P5 << 13), +};
-/* in-diff or dmic-pin + terminating empty entry */ -#define MAX_NO_PROPS 2 +#define BYT_RT5640_MAP(quirk) ((quirk) & GENMASK(3, 0)) +#define BYT_RT5640_JDSRC(quirk) (((quirk) & GENMASK(7, 4)) >> 4) +#define BYT_RT5640_OVCD_TH(quirk) (((quirk) & GENMASK(12, 8)) >> 8) +#define BYT_RT5640_OVCD_SF(quirk) (((quirk) & GENMASK(14, 13)) >> 13) +#define BYT_RT5640_JD_NOT_INV BIT(16) +#define BYT_RT5640_MONO_SPEAKER BIT(17) +#define BYT_RT5640_DIFF_MIC BIT(18) /* default is single-ended */ +#define BYT_RT5640_SSP2_AIF2 BIT(19) /* default is using AIF1 */ +#define BYT_RT5640_SSP0_AIF1 BIT(20) +#define BYT_RT5640_SSP0_AIF2 BIT(21) +#define BYT_RT5640_MCLK_EN BIT(22) +#define BYT_RT5640_MCLK_25MHZ BIT(23) + +/* in-diff or dmic-pin + jdsrc + ovcd-th + -sf + jd-inv + terminating entry */ +#define MAX_NO_PROPS 6
struct byt_rt5640_private { + struct snd_soc_jack jack; struct clk *mclk; }; static bool is_bytcr; @@ -95,6 +123,16 @@ static void log_quirks(struct device *dev) dev_err(dev, "quirk map 0x%x is not supported, microphone input will not work\n", map); break; } + if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) { + dev_info(dev, "quirk realtek,jack-detect-source %ld\n", + BYT_RT5640_JDSRC(byt_rt5640_quirk)); + dev_info(dev, "quirk realtek,over-current-threshold-microamp %ld\n", + BYT_RT5640_OVCD_TH(byt_rt5640_quirk) * 100); + dev_info(dev, "quirk realtek,over-current-scale-factor %ld\n", + BYT_RT5640_OVCD_SF(byt_rt5640_quirk)); + } + if (byt_rt5640_quirk & BYT_RT5640_JD_NOT_INV) + dev_info(dev, "quirk JD_NOT_INV enabled\n"); if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) dev_info(dev, "quirk MONO_SPEAKER enabled\n"); if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) @@ -330,6 +368,17 @@ static const struct snd_kcontrol_new byt_rt5640_controls[] = { SOC_DAPM_PIN_SWITCH("Speaker"), };
+static struct snd_soc_jack_pin rt5640_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -353,6 +402,9 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"), }, .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | BYT_RT5640_MCLK_EN), }, { @@ -374,6 +426,9 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), }, .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | BYT_RT5640_MONO_SPEAKER | BYT_RT5640_MCLK_EN), }, @@ -463,6 +518,23 @@ static int byt_rt5640_add_codec_device_props(const char *i2c_dev_name) break; }
+ if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) { + props[cnt++] = PROPERTY_ENTRY_U32( + "realtek,jack-detect-source", + BYT_RT5640_JDSRC(byt_rt5640_quirk)); + + props[cnt++] = PROPERTY_ENTRY_U32( + "realtek,over-current-threshold-microamp", + BYT_RT5640_OVCD_TH(byt_rt5640_quirk) * 100); + + props[cnt++] = PROPERTY_ENTRY_U32( + "realtek,over-current-scale-factor", + BYT_RT5640_OVCD_SF(byt_rt5640_quirk)); + } + + if (byt_rt5640_quirk & BYT_RT5640_JD_NOT_INV) + props[cnt++] = PROPERTY_ENTRY_BOOL("realtek,jack-detect-not-inverted"); + ret = device_add_properties(i2c_dev, props); put_device(i2c_dev);
@@ -480,6 +552,11 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
card->dapm.idle_bias_off = true;
+ /* Start with RC clk for jack-detect (we disable MCLK below) */ + if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) + snd_soc_component_update_bits(component, RT5640_GLB_CLK, + RT5640_SCLK_SRC_MASK, RT5640_SCLK_SRC_RCCLK); + rt5640_sel_asrc_clk_src(component, RT5640_DA_STEREO_FILTER | RT5640_DA_MONO_L_FILTER | @@ -573,11 +650,27 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) else ret = clk_set_rate(priv->mclk, 19200000);
- if (ret) + if (ret) { dev_err(card->dev, "unable to set MCLK rate\n"); + return ret; + } }
- return ret; + if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) { + ret = snd_soc_card_jack_new(card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &priv->jack, rt5640_pins, + ARRAY_SIZE(rt5640_pins)); + if (ret) { + dev_err(card->dev, "Jack creation failed %d\n", ret); + return ret; + } + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, + KEY_PLAYPAUSE); + snd_soc_component_set_jack(component, &priv->jack, NULL); + } + + return 0; }
static const struct snd_soc_pcm_stream byt_rt5640_dai_params = { @@ -719,6 +812,47 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { };
/* SoC card */ +static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN]; +static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ +static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ + +static int byt_rt5640_suspend(struct snd_soc_card *card) +{ + struct snd_soc_component *component; + + if (!BYT_RT5640_JDSRC(byt_rt5640_quirk)) + return 0; + + list_for_each_entry(component, &card->component_dev_list, card_list) { + if (!strcmp(component->name, byt_rt5640_codec_name)) { + dev_dbg(component->dev, "disabling jack detect before suspend\n"); + snd_soc_component_set_jack(component, NULL, NULL); + break; + } + } + + return 0; +} + +static int byt_rt5640_resume(struct snd_soc_card *card) +{ + struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component; + + if (!BYT_RT5640_JDSRC(byt_rt5640_quirk)) + return 0; + + list_for_each_entry(component, &card->component_dev_list, card_list) { + if (!strcmp(component->name, byt_rt5640_codec_name)) { + dev_dbg(component->dev, "re-enabling jack detect after resume\n"); + snd_soc_component_set_jack(component, &priv->jack, NULL); + break; + } + } + + return 0; +} + static struct snd_soc_card byt_rt5640_card = { .name = "bytcr-rt5640", .owner = THIS_MODULE, @@ -729,12 +863,10 @@ static struct snd_soc_card byt_rt5640_card = { .dapm_routes = byt_rt5640_audio_map, .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map), .fully_routed = true, + .suspend_pre = byt_rt5640_suspend, + .resume_post = byt_rt5640_resume, };
-static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN]; -static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ -static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ - static bool is_valleyview(void) { static const struct x86_cpu_id cpu_ids[] = {
Out of the 11 BYTCR devices which I have access to for testing, 7 use IN3 for the internal mic and only 1 uses IN1 for the internal mic, the other 3 use DMIC1.
So IN3 clearly is a better default, using IN3 as default avoids the need to add DMI quirks for some of these devices.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/soc/intel/boards/bytcr_rt5640.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 6be4e8972010..bc0b85ec0b16 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -975,7 +975,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) }
/* change defaults for Baytrail-CR capture */ - byt_rt5640_quirk |= BYT_RT5640_IN1_MAP; + byt_rt5640_quirk |= BYT_RT5640_IN3_MAP; byt_rt5640_quirk |= BYT_RT5640_DIFF_MIC; } else { byt_rt5640_quirk |= BYT_RT5640_DMIC1_MAP;
The patch
ASoC: Intel: bytcr_rt5640: Change BYTCR default input to IN3
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 737c14641a411b2a6bea61203c4aecb62de35d72 Mon Sep 17 00:00:00 2001
From: Hans de Goede hdegoede@redhat.com Date: Sun, 13 May 2018 09:24:29 +0200 Subject: [PATCH] ASoC: Intel: bytcr_rt5640: Change BYTCR default input to IN3
Out of the 11 BYTCR devices which I have access to for testing, 7 use IN3 for the internal mic and only 1 uses IN1 for the internal mic, the other 3 use DMIC1.
So IN3 clearly is a better default, using IN3 as default avoids the need to add DMI quirks for some of these devices.
Signed-off-by: Hans de Goede hdegoede@redhat.com Acked-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bytcr_rt5640.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 3cdaf87480ef..09cdfd57e383 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -979,7 +979,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) }
/* change defaults for Baytrail-CR capture */ - byt_rt5640_quirk |= BYT_RT5640_IN1_MAP; + byt_rt5640_quirk |= BYT_RT5640_IN3_MAP; byt_rt5640_quirk |= BYT_RT5640_DIFF_MIC; } else { byt_rt5640_quirk |= BYT_RT5640_DMIC1_MAP;
Currently we've 2 places with BYTCR defaults: 1. The generic catch-all DMI_SYS_VENDOR=="Insyde" DMI quirk which selects SSP0-AIF1 for generic Insyde BYTCR tablets without the ACPI channel package; and 2. the defaults in the if (is_bytcr) {} code block.
Currently these are not identical, both select IN3 as the internal mic output, but the "Insyde" DMI quirk leaves out the DIFF_MIC quirk. The DIFF_MIC quirk should be enabled by default, because enabling diff. input helps a lot for devices with a differential mic, where as it is a nop on devices with a normal mic.
This commit adds the DIFF_MIC quirk to the "Insyde" DMI quirk path, by adding a new BYTCR_INPUT_DEFAULTS define and using that in both code paths which set BYTCR defaults.
Having a single place where the BYTCR input defaults are defined also allows defining jack-detect defaults in a single place in a follow-up commit.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/soc/intel/boards/bytcr_rt5640.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index bc0b85ec0b16..0ec3aac62a07 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -82,6 +82,10 @@ enum { #define BYT_RT5640_MCLK_EN BIT(22) #define BYT_RT5640_MCLK_25MHZ BIT(23)
+#define BYTCR_INPUT_DEFAULTS \ + (BYT_RT5640_IN3_MAP | \ + BYT_RT5640_DIFF_MIC) + /* in-diff or dmic-pin + jdsrc + ovcd-th + -sf + jd-inv + terminating entry */ #define MAX_NO_PROPS 6
@@ -475,7 +479,7 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), }, - .driver_data = (void *)(BYT_RT5640_IN3_MAP | + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | BYT_RT5640_MCLK_EN | BYT_RT5640_SSP0_AIF1),
@@ -975,8 +979,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) }
/* change defaults for Baytrail-CR capture */ - byt_rt5640_quirk |= BYT_RT5640_IN3_MAP; - byt_rt5640_quirk |= BYT_RT5640_DIFF_MIC; + byt_rt5640_quirk |= BYTCR_INPUT_DEFAULTS; } else { byt_rt5640_quirk |= BYT_RT5640_DMIC1_MAP; }
The patch
ASoC: Intel: bytcr_rt5640: Unify BYTCR input defaults
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 96a388feb29474729a24703db99db72b283f977a Mon Sep 17 00:00:00 2001
From: Hans de Goede hdegoede@redhat.com Date: Sun, 13 May 2018 09:24:30 +0200 Subject: [PATCH] ASoC: Intel: bytcr_rt5640: Unify BYTCR input defaults
Currently we've 2 places with BYTCR defaults: 1. The generic catch-all DMI_SYS_VENDOR=="Insyde" DMI quirk which selects SSP0-AIF1 for generic Insyde BYTCR tablets without the ACPI channel package; and 2. the defaults in the if (is_bytcr) {} code block.
Currently these are not identical, both select IN3 as the internal mic output, but the "Insyde" DMI quirk leaves out the DIFF_MIC quirk. The DIFF_MIC quirk should be enabled by default, because enabling diff. input helps a lot for devices with a differential mic, where as it is a nop on devices with a normal mic.
This commit adds the DIFF_MIC quirk to the "Insyde" DMI quirk path, by adding a new BYTCR_INPUT_DEFAULTS define and using that in both code paths which set BYTCR defaults.
Having a single place where the BYTCR input defaults are defined also allows defining jack-detect defaults in a single place in a follow-up commit.
Signed-off-by: Hans de Goede hdegoede@redhat.com Acked-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bytcr_rt5640.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 09cdfd57e383..355c241470b5 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -82,6 +82,10 @@ enum { #define BYT_RT5640_MCLK_EN BIT(22) #define BYT_RT5640_MCLK_25MHZ BIT(23)
+#define BYTCR_INPUT_DEFAULTS \ + (BYT_RT5640_IN3_MAP | \ + BYT_RT5640_DIFF_MIC) + /* in-diff or dmic-pin + jdsrc + ovcd-th + -sf + jd-inv + terminating entry */ #define MAX_NO_PROPS 6
@@ -475,7 +479,7 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), }, - .driver_data = (void *)(BYT_RT5640_IN3_MAP | + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | BYT_RT5640_MCLK_EN | BYT_RT5640_SSP0_AIF1),
@@ -979,8 +983,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) }
/* change defaults for Baytrail-CR capture */ - byt_rt5640_quirk |= BYT_RT5640_IN3_MAP; - byt_rt5640_quirk |= BYT_RT5640_DIFF_MIC; + byt_rt5640_quirk |= BYTCR_INPUT_DEFAULTS; } else { byt_rt5640_quirk |= BYT_RT5640_DMIC1_MAP; }
Out of the 11 BYTCR devices which I have access to for testing, 6 use JD1IN4P for jack-detect, 2 use JD1IN4P non-inverted and the other 3 use JD2IN4N, the ones not using JD1IN4P are all also special in other ways and need a DMI quirk regardless.
All 5 BYT (non CR) devices which I have access to use JD2IN4N.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/soc/intel/boards/bytcr_rt5640.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 0ec3aac62a07..d600a7cc9ca7 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -84,6 +84,9 @@ enum {
#define BYTCR_INPUT_DEFAULTS \ (BYT_RT5640_IN3_MAP | \ + BYT_RT5640_JD_SRC_JD1_IN4P | \ + BYT_RT5640_OVCD_TH_2000UA | \ + BYT_RT5640_OVCD_SF_0P75 | \ BYT_RT5640_DIFF_MIC)
/* in-diff or dmic-pin + jdsrc + ovcd-th + -sf + jd-inv + terminating entry */ @@ -981,7 +984,10 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) /* change defaults for Baytrail-CR capture */ byt_rt5640_quirk |= BYTCR_INPUT_DEFAULTS; } else { - byt_rt5640_quirk |= BYT_RT5640_DMIC1_MAP; + byt_rt5640_quirk |= BYT_RT5640_DMIC1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75; }
/* check quirks before creating card */
The patch
ASoC: Intel: bytcr_rt5640: Add default jack-detect settings
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 56ff44094501787e5901669d6e880ca2065206fe Mon Sep 17 00:00:00 2001
From: Hans de Goede hdegoede@redhat.com Date: Sun, 13 May 2018 09:24:31 +0200 Subject: [PATCH] ASoC: Intel: bytcr_rt5640: Add default jack-detect settings
Out of the 11 BYTCR devices which I have access to for testing, 6 use JD1IN4P for jack-detect, 2 use JD1IN4P non-inverted and the other 3 use JD2IN4N, the ones not using JD1IN4P are all also special in other ways and need a DMI quirk regardless.
All 5 BYT (non CR) devices which I have access to use JD2IN4N.
Signed-off-by: Hans de Goede hdegoede@redhat.com Acked-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bytcr_rt5640.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 355c241470b5..b00f21ed4357 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -84,6 +84,9 @@ enum {
#define BYTCR_INPUT_DEFAULTS \ (BYT_RT5640_IN3_MAP | \ + BYT_RT5640_JD_SRC_JD1_IN4P | \ + BYT_RT5640_OVCD_TH_2000UA | \ + BYT_RT5640_OVCD_SF_0P75 | \ BYT_RT5640_DIFF_MIC)
/* in-diff or dmic-pin + jdsrc + ovcd-th + -sf + jd-inv + terminating entry */ @@ -985,7 +988,10 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) /* change defaults for Baytrail-CR capture */ byt_rt5640_quirk |= BYTCR_INPUT_DEFAULTS; } else { - byt_rt5640_quirk |= BYT_RT5640_DMIC1_MAP; + byt_rt5640_quirk |= BYT_RT5640_DMIC1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75; }
/* check quirks before creating card */
As we add more quirks it is useful to have some sort of order in the quirk list, sort it alphabetically.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/soc/intel/boards/bytcr_rt5640.c | 41 ++++++++++++++------------- 1 file changed, 21 insertions(+), 20 deletions(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index d600a7cc9ca7..07df097e3f48 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -401,7 +401,19 @@ static int byt_rt5640_quirk_cb(const struct dmi_system_id *id) return 1; }
+/* Please keep this list alphabetically sorted */ static const struct dmi_system_id byt_rt5640_quirk_table[] = { + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_MCLK_EN | + BYT_RT5640_SSP0_AIF1), + + }, { .callback = byt_rt5640_quirk_cb, .matches = { @@ -426,6 +438,14 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF2 | BYT_RT5640_MCLK_EN), }, + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), + DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"), + }, + .driver_data = (void *)(BYT_RT5640_DMIC1_MAP), + }, { .callback = byt_rt5640_quirk_cb, .matches = { @@ -448,14 +468,6 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { .driver_data = (void *)(BYT_RT5640_IN1_MAP | BYT_RT5640_MCLK_EN), }, - { - .callback = byt_rt5640_quirk_cb, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), - DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"), - }, - .driver_data = (void *)(BYT_RT5640_DMIC1_MAP), - }, { .callback = byt_rt5640_quirk_cb, .matches = { @@ -466,18 +478,7 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_MCLK_EN | BYT_RT5640_SSP0_AIF1), }, - { - .callback = byt_rt5640_quirk_cb, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"), - }, - .driver_data = (void *)(BYT_RT5640_IN1_MAP | - BYT_RT5640_MCLK_EN | - BYT_RT5640_SSP0_AIF1), - - }, - { + { /* Catch-all for generic Insyde tablets, must be last */ .callback = byt_rt5640_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
The patch
ASoC: Intel: bytcr_rt5640: Sort DMI quirk list alphabetically
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 3c0d01160899576af068ce293f5688b3f0bcce3c Mon Sep 17 00:00:00 2001
From: Hans de Goede hdegoede@redhat.com Date: Sun, 13 May 2018 09:24:32 +0200 Subject: [PATCH] ASoC: Intel: bytcr_rt5640: Sort DMI quirk list alphabetically
As we add more quirks it is useful to have some sort of order in the quirk list, sort it alphabetically.
Signed-off-by: Hans de Goede hdegoede@redhat.com Acked-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bytcr_rt5640.c | 41 ++++++++++++++------------- 1 file changed, 21 insertions(+), 20 deletions(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index b00f21ed4357..965721663749 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -401,7 +401,19 @@ static int byt_rt5640_quirk_cb(const struct dmi_system_id *id) return 1; }
+/* Please keep this list alphabetically sorted */ static const struct dmi_system_id byt_rt5640_quirk_table[] = { + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_MCLK_EN | + BYT_RT5640_SSP0_AIF1), + + }, { .callback = byt_rt5640_quirk_cb, .matches = { @@ -426,6 +438,14 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF2 | BYT_RT5640_MCLK_EN), }, + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), + DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"), + }, + .driver_data = (void *)(BYT_RT5640_DMIC1_MAP), + }, { .callback = byt_rt5640_quirk_cb, .matches = { @@ -448,14 +468,6 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { .driver_data = (void *)(BYT_RT5640_IN1_MAP | BYT_RT5640_MCLK_EN), }, - { - .callback = byt_rt5640_quirk_cb, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), - DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"), - }, - .driver_data = (void *)(BYT_RT5640_DMIC1_MAP), - }, { .callback = byt_rt5640_quirk_cb, .matches = { @@ -466,18 +478,7 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_MCLK_EN | BYT_RT5640_SSP0_AIF1), }, - { - .callback = byt_rt5640_quirk_cb, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"), - }, - .driver_data = (void *)(BYT_RT5640_IN1_MAP | - BYT_RT5640_MCLK_EN | - BYT_RT5640_SSP0_AIF1), - - }, - { + { /* Catch-all for generic Insyde tablets, must be last */ .callback = byt_rt5640_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
Use dmi_first_match() instead of dmi_check_system() + callbacks, this avoid the need to initialize dmi_system_id.callback for each byt_rt5640_quirk_table entry.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/soc/intel/boards/bytcr_rt5640.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 07df097e3f48..fcea409f3a92 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -395,16 +395,9 @@ static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream, return byt_rt5640_prepare_and_enable_pll1(dai, params_rate(params)); }
-static int byt_rt5640_quirk_cb(const struct dmi_system_id *id) -{ - byt_rt5640_quirk = (unsigned long)id->driver_data; - return 1; -} - /* Please keep this list alphabetically sorted */ static const struct dmi_system_id byt_rt5640_quirk_table[] = { { - .callback = byt_rt5640_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"), @@ -415,7 +408,6 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
}, { - .callback = byt_rt5640_quirk_cb, .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"), @@ -427,7 +419,6 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_MCLK_EN), }, { - .callback = byt_rt5640_quirk_cb, .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"), @@ -439,7 +430,6 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_MCLK_EN), }, { - .callback = byt_rt5640_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"), @@ -447,7 +437,6 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { .driver_data = (void *)(BYT_RT5640_DMIC1_MAP), }, { - .callback = byt_rt5640_quirk_cb, .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), @@ -460,7 +449,6 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_MCLK_EN), }, { - .callback = byt_rt5640_quirk_cb, .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"), @@ -469,7 +457,6 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_MCLK_EN), }, { - .callback = byt_rt5640_quirk_cb, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"), DMI_MATCH(DMI_BOARD_NAME, "tPAD"), @@ -479,7 +466,6 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF1), }, { /* Catch-all for generic Insyde tablets, must be last */ - .callback = byt_rt5640_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), }, @@ -890,6 +876,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */
static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { + const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; const char *i2c_name = NULL; @@ -992,7 +979,9 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) }
/* check quirks before creating card */ - dmi_check_system(byt_rt5640_quirk_table); + dmi_id = dmi_first_match(byt_rt5640_quirk_table); + if (dmi_id) + byt_rt5640_quirk = (unsigned long)dmi_id->driver_data; if (quirk_override) { dev_info(&pdev->dev, "Overriding quirk 0x%x => 0x%x\n", (unsigned int)byt_rt5640_quirk, quirk_override);
The patch
ASoC: Intel: bytcr_rt5640: Use dmi_first_match() for DMI quirk handling
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 6d1bfcc5e7d196416c2ac2d5aead05c0d7acffb0 Mon Sep 17 00:00:00 2001
From: Hans de Goede hdegoede@redhat.com Date: Sun, 13 May 2018 09:24:33 +0200 Subject: [PATCH] ASoC: Intel: bytcr_rt5640: Use dmi_first_match() for DMI quirk handling
Use dmi_first_match() instead of dmi_check_system() + callbacks, this avoid the need to initialize dmi_system_id.callback for each byt_rt5640_quirk_table entry.
Signed-off-by: Hans de Goede hdegoede@redhat.com Acked-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bytcr_rt5640.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 965721663749..0f80deaf7fce 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -395,16 +395,9 @@ static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream, return byt_rt5640_prepare_and_enable_pll1(dai, params_rate(params)); }
-static int byt_rt5640_quirk_cb(const struct dmi_system_id *id) -{ - byt_rt5640_quirk = (unsigned long)id->driver_data; - return 1; -} - /* Please keep this list alphabetically sorted */ static const struct dmi_system_id byt_rt5640_quirk_table[] = { { - .callback = byt_rt5640_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"), @@ -415,7 +408,6 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
}, { - .callback = byt_rt5640_quirk_cb, .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"), @@ -427,7 +419,6 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_MCLK_EN), }, { - .callback = byt_rt5640_quirk_cb, .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"), @@ -439,7 +430,6 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_MCLK_EN), }, { - .callback = byt_rt5640_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"), @@ -447,7 +437,6 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { .driver_data = (void *)(BYT_RT5640_DMIC1_MAP), }, { - .callback = byt_rt5640_quirk_cb, .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), @@ -460,7 +449,6 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_MCLK_EN), }, { - .callback = byt_rt5640_quirk_cb, .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"), @@ -469,7 +457,6 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_MCLK_EN), }, { - .callback = byt_rt5640_quirk_cb, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"), DMI_MATCH(DMI_BOARD_NAME, "tPAD"), @@ -479,7 +466,6 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF1), }, { /* Catch-all for generic Insyde tablets, must be last */ - .callback = byt_rt5640_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), }, @@ -894,6 +880,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */
static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { + const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; const char *i2c_name = NULL; @@ -996,7 +983,9 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) }
/* check quirks before creating card */ - dmi_check_system(byt_rt5640_quirk_table); + dmi_id = dmi_first_match(byt_rt5640_quirk_table); + if (dmi_id) + byt_rt5640_quirk = (unsigned long)dmi_id->driver_data; if (quirk_override) { dev_info(&pdev->dev, "Overriding quirk 0x%x => 0x%x\n", (unsigned int)byt_rt5640_quirk, quirk_override);
Even with our recently tweaked defaults, quite a few bytcr_rt5640 devices still need quirks to be fully functional. This commits adds quirks where necessary for the 16 bytcr_rt5640 devices I have access to.
The quirks are added for the following reasons:
1) Devices with only one speaker need the mono quirk to avoid driving an unused and potentially short-circuited output. 8 of my sample of 16 devs are mono, 4 of these would work with the defaults if it were not for their mono speaker.
2) Devices using a different input for the internal mic then the default, this is the case for 6 of my sample of 16 devices.
3) BYTCR devices without an ACPI channel map, which do not work with the default of SSP0-AIF2, this is the case for 2 of my sample of 16 devices.
4) Devices which need non-default jack-detect settings, this is the case for 6 of my sample of 16 devices.
This commit add quirks for the following devices:
Acer Iconia Tab 8 W1-810 Chuwi Vi8 HP Pavilion X2 10-n000nd HP Stream 7 I.T. Works TW891 Lamina I8270 MSI S100 Pipo W4 PoV-mobii-800w Toshiba Click Mini L9W-B
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/soc/intel/boards/bytcr_rt5640.c | 124 ++++++++++++++++++++++++++ 1 file changed, 124 insertions(+)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index fcea409f3a92..cfc520200214 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -397,6 +397,18 @@ static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream,
/* Please keep this list alphabetically sorted */ static const struct dmi_system_id byt_rt5640_quirk_table[] = { + { /* Acer Iconia Tab 8 W1-810 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Iconia W1-810"), + }, + .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | + BYT_RT5640_JD_SRC_JD1_IN4P | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), @@ -429,6 +441,18 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF2 | BYT_RT5640_MCLK_EN), }, + { /* Chuwi Vi8 (CWI506) */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "i86"), + /* The above are too generic, also match BIOS info */ + DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.D86JLBNR"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_MONO_SPEAKER | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), @@ -456,6 +480,94 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { .driver_data = (void *)(BYT_RT5640_IN1_MAP | BYT_RT5640_MCLK_EN), }, + { /* HP Pavilion x2 10-n000nd */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"), + }, + .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_1500UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, + { /* HP Stream 7 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP Stream 7 Tablet"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_MONO_SPEAKER | + BYT_RT5640_JD_NOT_INV | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, + { /* I.T.Works TW891 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "TW891"), + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "To be filled by O.E.M."), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "TW891"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_MONO_SPEAKER | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, + { /* Lamina I8270 / T701BR.SE */ + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Lamina"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "T701BR.SE"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_MONO_SPEAKER | + BYT_RT5640_JD_NOT_INV | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, + { /* MSI S100 tablet */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "S100"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_MONO_SPEAKER | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_MCLK_EN), + }, + { /* Pipo W4 */ + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + /* The above are too generic, also match BIOS info */ + DMI_MATCH(DMI_BIOS_VERSION, "V8L_WIN32_CHIPHD"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_MONO_SPEAKER | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, + { /* Point of View Mobii TAB-P800W (V2.1) */ + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + /* The above are too generic, also match BIOS info */ + DMI_EXACT_MATCH(DMI_BIOS_VERSION, "3BAIR1013"), + DMI_EXACT_MATCH(DMI_BIOS_DATE, "08/22/2014"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_MONO_SPEAKER | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF2 | + BYT_RT5640_MCLK_EN), + }, { .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"), @@ -465,6 +577,18 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_MCLK_EN | BYT_RT5640_SSP0_AIF1), }, + { /* Toshiba Satellite Click Mini L9W-B */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SATELLITE Click Mini L9W-B"), + }, + .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_1500UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { /* Catch-all for generic Insyde tablets, must be last */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
Many X86 devices using a BYT SoC + RT5640 codec are cheap devices with generic DMI strings, causing snd_soc_set_dmi_name() to fail to set a long_name, making it impossible for userspace to have a correct UCM profile which only uses inputs / outputs which are actually hooked up on the device.
Our quirks already specify which input the internal mic is connected to and if a single (mono) speaker is used or if the device has stereo speakers.
This commit sets a long_name based on the quirks so that userspace can have UCM profiles doing the right thing based on the long_name.
Note that if we ever encounter the need for a special UCM profile for some device we can add a quirk to set a specific long_name for the device,
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/soc/intel/boards/bytcr_rt5640.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index cfc520200214..9a1204dcdbc6 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -929,6 +929,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN]; static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ +static char byt_rt5640_long_name[40]; /* = "bytcr-rt5640-*-spk-*-mic" */
static int byt_rt5640_suspend(struct snd_soc_card *card) { @@ -1000,6 +1001,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */
static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { + const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; @@ -1163,6 +1165,13 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) } }
+ snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name), + "bytcr-rt5640-%s-spk-%s-mic", + (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? + "mono" : "stereo", + map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); + byt_rt5640_card.long_name = byt_rt5640_long_name; + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card);
if (ret_val) {
On 5/8/18 10:36 AM, Hans de Goede wrote:
Many X86 devices using a BYT SoC + RT5640 codec are cheap devices with generic DMI strings, causing snd_soc_set_dmi_name() to fail to set a long_name, making it impossible for userspace to have a correct UCM profile which only uses inputs / outputs which are actually hooked up on the device.
Our quirks already specify which input the internal mic is connected to and if a single (mono) speaker is used or if the device has stereo speakers.
This commit sets a long_name based on the quirks so that userspace can have UCM profiles doing the right thing based on the long_name.
Isn't this going to be complicated to manage for UCM? Just with this patch alone, you'd need 8 UCM files to cover all the combinations. 16 if you add the 'sof-' prefix.
seems like UCM should become more 'dynamic' and get quirk information somehow (sysfs?) to enable/disable endpoints rather than rely on name encoding to select the right profile?
Note that if we ever encounter the need for a special UCM profile for some device we can add a quirk to set a specific long_name for the device,
Signed-off-by: Hans de Goede hdegoede@redhat.com
sound/soc/intel/boards/bytcr_rt5640.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index cfc520200214..9a1204dcdbc6 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -929,6 +929,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN]; static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ +static char byt_rt5640_long_name[40]; /* = "bytcr-rt5640-*-spk-*-mic" */
static int byt_rt5640_suspend(struct snd_soc_card *card) { @@ -1000,6 +1001,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */
static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) {
- const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach;
@@ -1163,6 +1165,13 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) } }
snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name),
"bytcr-rt5640-%s-spk-%s-mic",
(byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ?
"mono" : "stereo",
map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]);
byt_rt5640_card.long_name = byt_rt5640_long_name;
ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card);
if (ret_val) {
Hi,
On 08-05-18 20:35, Pierre-Louis Bossart wrote:
On 5/8/18 10:36 AM, Hans de Goede wrote:
Many X86 devices using a BYT SoC + RT5640 codec are cheap devices with generic DMI strings, causing snd_soc_set_dmi_name() to fail to set a long_name, making it impossible for userspace to have a correct UCM profile which only uses inputs / outputs which are actually hooked up on the device.
Our quirks already specify which input the internal mic is connected to and if a single (mono) speaker is used or if the device has stereo speakers.
This commit sets a long_name based on the quirks so that userspace can have UCM profiles doing the right thing based on the long_name.
Isn't this going to be complicated to manage for UCM? Just with this patch alone, you'd need 8 UCM files to cover all the combinations. 16 if you add the 'sof-' prefix.
seems like UCM should become more 'dynamic' and get quirk information somehow (sysfs?) to enable/disable endpoints rather than rely on name encoding to select the right profile?
I agree that this is not ideal, but this is an improvement from the current state where we would need 1 UCM profile per board (assuming valid DMI data and thus a proper long-name being set), 6 profiles (dmic2 is not used anywhere sofar) is a whole lot easier to manage then 1 profile per board. So as said I believe this is a step in the right direction.
And looking at the foreseeable future I simply don't see any of us having the time to implement an ideal solution for this. I would really like for end users to be able to run the latest upstream kernel + alsa-lib and have things just work, before this hardware becomes obsolete. I know that no-one having time to work on reworking UCM to make it more dynamic is not the best of arguments but it is something to take into consideration.
Thinking more about this on the alsa-lib / UCM profile side we could have something like this:
/usr/share/alsa/ucm/bytcr-rt5640-mono-spk-in1-mic/bytcr-rt5640-mono-spk-in1-mic.conf:
SectionUseCase."HiFi" { File "../bytcr-rt5640/Generic.conf" File "../bytcr-rt5640/MonoSpeaker.conf" File "../bytcr-rt5640/In1Mic.conf" Comment "Play HiFi quality Music" }
SectionDefaults [ cdev "hw:bytcrrt5640" ]
The only problem I can see with that is that the "ConflictingDevice" sections for the various inputs / outputs then would refer to not present SectionDevice sections. I have not tested this suggestion yet, but I'm willing to write an alsa-lib patch to ignore non present ConflictingDevice references, to make my suggestion work.
I think doing things this way, thus avoiding the need to copy and paste a whole lot of UCM code for the 6 profiles it will not be a problem to maintain 6 profiles, as we're really just maintaining 6 config snippets such as the above example and only one complete profile.
Would the solution I outlined above be acceptable to you?
Regards,
Hans
Note that if we ever encounter the need for a special UCM profile for some device we can add a quirk to set a specific long_name for the device,
Signed-off-by: Hans de Goede hdegoede@redhat.com
sound/soc/intel/boards/bytcr_rt5640.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index cfc520200214..9a1204dcdbc6 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -929,6 +929,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN]; static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ +static char byt_rt5640_long_name[40]; /* = "bytcr-rt5640-*-spk-*-mic" */ static int byt_rt5640_suspend(struct snd_soc_card *card) { @@ -1000,6 +1001,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { + const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; @@ -1163,6 +1165,13 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) } } + snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name), + "bytcr-rt5640-%s-spk-%s-mic", + (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? + "mono" : "stereo", + map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); + byt_rt5640_card.long_name = byt_rt5640_long_name;
ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); if (ret_val) {
On 5/10/18 5:27 AM, Hans de Goede wrote:
Hi,
On 08-05-18 20:35, Pierre-Louis Bossart wrote:
On 5/8/18 10:36 AM, Hans de Goede wrote:
Many X86 devices using a BYT SoC + RT5640 codec are cheap devices with generic DMI strings, causing snd_soc_set_dmi_name() to fail to set a long_name, making it impossible for userspace to have a correct UCM profile which only uses inputs / outputs which are actually hooked up on the device.
Our quirks already specify which input the internal mic is connected to and if a single (mono) speaker is used or if the device has stereo speakers.
This commit sets a long_name based on the quirks so that userspace can have UCM profiles doing the right thing based on the long_name.
Isn't this going to be complicated to manage for UCM? Just with this patch alone, you'd need 8 UCM files to cover all the combinations. 16 if you add the 'sof-' prefix.
seems like UCM should become more 'dynamic' and get quirk information somehow (sysfs?) to enable/disable endpoints rather than rely on name encoding to select the right profile?
I agree that this is not ideal, but this is an improvement from the current state where we would need 1 UCM profile per board (assuming valid DMI data and thus a proper long-name being set), 6 profiles (dmic2 is not used anywhere sofar) is a whole lot easier to manage then 1 profile per board. So as said I believe this is a step in the right direction.
And looking at the foreseeable future I simply don't see any of us having the time to implement an ideal solution for this. I would really like for end users to be able to run the latest upstream kernel + alsa-lib and have things just work, before this hardware becomes obsolete. I know that no-one having time to work on reworking UCM to make it more dynamic is not the best of arguments but it is something to take into consideration.
Thinking more about this on the alsa-lib / UCM profile side we could have something like this:
/usr/share/alsa/ucm/bytcr-rt5640-mono-spk-in1-mic/bytcr-rt5640-mono-spk-in1-mic.conf:
SectionUseCase."HiFi" { File "../bytcr-rt5640/Generic.conf" File "../bytcr-rt5640/MonoSpeaker.conf" File "../bytcr-rt5640/In1Mic.conf" Comment "Play HiFi quality Music" }
SectionDefaults [ cdev "hw:bytcrrt5640" ]
The only problem I can see with that is that the "ConflictingDevice" sections for the various inputs / outputs then would refer to not present SectionDevice sections. I have not tested this suggestion yet, but I'm willing to write an alsa-lib patch to ignore non present ConflictingDevice references, to make my suggestion work.
I think doing things this way, thus avoiding the need to copy and paste a whole lot of UCM code for the 6 profiles it will not be a problem to maintain 6 profiles, as we're really just maintaining 6 config snippets such as the above example and only one complete profile.
Would the solution I outlined above be acceptable to you?
The includes and disabling conflicting devices that aren't present make sense. I have another issue though: for SOF integration I already prepared a set of files, which are mostly identical to the regular ones except that the platform-side mixer controls are removed (or different) and the name of the card/device is different (sof- prefix). See on github.
I was nearly ready to submit all those files to the new repository, I wasn't aware of your work so now need to figure out how to reuse all this once we upstream SOF (any time now if I look at Liam's patches).
Regards,
Hans
Note that if we ever encounter the need for a special UCM profile for some device we can add a quirk to set a specific long_name for the device,
Signed-off-by: Hans de Goede hdegoede@redhat.com
sound/soc/intel/boards/bytcr_rt5640.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index cfc520200214..9a1204dcdbc6 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -929,6 +929,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN]; static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ +static char byt_rt5640_long_name[40]; /* = "bytcr-rt5640-*-spk-*-mic" */ static int byt_rt5640_suspend(struct snd_soc_card *card) { @@ -1000,6 +1001,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { + const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; @@ -1163,6 +1165,13 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) } } + snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name), + "bytcr-rt5640-%s-spk-%s-mic", + (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? + "mono" : "stereo", + map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); + byt_rt5640_card.long_name = byt_rt5640_long_name;
ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); if (ret_val) {
Hi,
On 10-05-18 17:00, Pierre-Louis Bossart wrote:
On 5/10/18 5:27 AM, Hans de Goede wrote:
Hi,
On 08-05-18 20:35, Pierre-Louis Bossart wrote:
On 5/8/18 10:36 AM, Hans de Goede wrote:
Many X86 devices using a BYT SoC + RT5640 codec are cheap devices with generic DMI strings, causing snd_soc_set_dmi_name() to fail to set a long_name, making it impossible for userspace to have a correct UCM profile which only uses inputs / outputs which are actually hooked up on the device.
Our quirks already specify which input the internal mic is connected to and if a single (mono) speaker is used or if the device has stereo speakers.
This commit sets a long_name based on the quirks so that userspace can have UCM profiles doing the right thing based on the long_name.
Isn't this going to be complicated to manage for UCM? Just with this patch alone, you'd need 8 UCM files to cover all the combinations. 16 if you add the 'sof-' prefix.
seems like UCM should become more 'dynamic' and get quirk information somehow (sysfs?) to enable/disable endpoints rather than rely on name encoding to select the right profile?
I agree that this is not ideal, but this is an improvement from the current state where we would need 1 UCM profile per board (assuming valid DMI data and thus a proper long-name being set), 6 profiles (dmic2 is not used anywhere sofar) is a whole lot easier to manage then 1 profile per board. So as said I believe this is a step in the right direction.
And looking at the foreseeable future I simply don't see any of us having the time to implement an ideal solution for this. I would really like for end users to be able to run the latest upstream kernel + alsa-lib and have things just work, before this hardware becomes obsolete. I know that no-one having time to work on reworking UCM to make it more dynamic is not the best of arguments but it is something to take into consideration.
Thinking more about this on the alsa-lib / UCM profile side we could have something like this:
/usr/share/alsa/ucm/bytcr-rt5640-mono-spk-in1-mic/bytcr-rt5640-mono-spk-in1-mic.conf:
SectionUseCase."HiFi" { File "../bytcr-rt5640/Generic.conf" File "../bytcr-rt5640/MonoSpeaker.conf" File "../bytcr-rt5640/In1Mic.conf" Comment "Play HiFi quality Music" }
SectionDefaults [ cdev "hw:bytcrrt5640" ]
The only problem I can see with that is that the "ConflictingDevice" sections for the various inputs / outputs then would refer to not present SectionDevice sections. I have not tested this suggestion yet, but I'm willing to write an alsa-lib patch to ignore non present ConflictingDevice references, to make my suggestion work.
I think doing things this way, thus avoiding the need to copy and paste a whole lot of UCM code for the 6 profiles it will not be a problem to maintain 6 profiles, as we're really just maintaining 6 config snippets such as the above example and only one complete profile.
Would the solution I outlined above be acceptable to you?
The includes and disabling conflicting devices that aren't present make sense. I have another issue though: for SOF integration I already prepared a set of files, which are mostly identical to the regular ones except that the platform-side mixer controls are removed (or different) and the name of the card/device is different (sof- prefix). See on github.
Hmm, it might make sense to split the includes in platform and codec includes, so to pick my example again we would get:
/usr/share/alsa/ucm/bytcr-rt5640-mono-spk-in1-mic/bytcr-rt5640-mono-spk-in1-mic.conf:
SectionUseCase."HiFi" { SectionVerb { EnableSequence [ cdev "hw:bytcrrt5640"
File "../bytcr-rt5640/EnableSeq.conf" # This contains the platform mixer settings File "../rt5640/EnableSeq.conf" ]
DisableSequence [ ]
Value { PlaybackPCM "hw:bytcrrt5640" CapturePCM "hw:bytcrrt5640" } }
File "../rt5640/Headset.conf" File "../rt5640/MonoSpeaker.conf" File "../rt5640/In1Mic.conf" Comment "Play HiFi quality Music" }
SectionDefaults [ cdev "hw:bytcrrt5640" ]
And then for sof you would just need to offer a sof-rt5640/EnableSeq.conf, or maybe even leave it out completely.
And we might also be able to merge the platform enable sequences into a generic:
bytcr/EnableSeq.conf
I think that will at least fly for bytcr-rt5640 and butcr-rt5651, leading us being able to remove more duplicated UCM config.
How does this sound?
Regards,
Hans
I was nearly ready to submit all those files to the new repository, I wasn't aware of your work so now need to figure out how to reuse all this once we upstream SOF (any time now if I look at Liam's patches).
Regards,
Hans
Note that if we ever encounter the need for a special UCM profile for some device we can add a quirk to set a specific long_name for the device,
Signed-off-by: Hans de Goede hdegoede@redhat.com
sound/soc/intel/boards/bytcr_rt5640.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index cfc520200214..9a1204dcdbc6 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -929,6 +929,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN]; static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ +static char byt_rt5640_long_name[40]; /* = "bytcr-rt5640-*-spk-*-mic" */ static int byt_rt5640_suspend(struct snd_soc_card *card) { @@ -1000,6 +1001,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { + const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; @@ -1163,6 +1165,13 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) } } + snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name), + "bytcr-rt5640-%s-spk-%s-mic", + (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? + "mono" : "stereo", + map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); + byt_rt5640_card.long_name = byt_rt5640_long_name;
ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); if (ret_val) {
On 5/10/18 10:48 AM, Hans de Goede wrote:
Hi,
On 10-05-18 17:00, Pierre-Louis Bossart wrote:
On 5/10/18 5:27 AM, Hans de Goede wrote:
Hi,
On 08-05-18 20:35, Pierre-Louis Bossart wrote:
On 5/8/18 10:36 AM, Hans de Goede wrote:
Many X86 devices using a BYT SoC + RT5640 codec are cheap devices with generic DMI strings, causing snd_soc_set_dmi_name() to fail to set a long_name, making it impossible for userspace to have a correct UCM profile which only uses inputs / outputs which are actually hooked up on the device.
Our quirks already specify which input the internal mic is connected to and if a single (mono) speaker is used or if the device has stereo speakers.
This commit sets a long_name based on the quirks so that userspace can have UCM profiles doing the right thing based on the long_name.
Isn't this going to be complicated to manage for UCM? Just with this patch alone, you'd need 8 UCM files to cover all the combinations. 16 if you add the 'sof-' prefix.
seems like UCM should become more 'dynamic' and get quirk information somehow (sysfs?) to enable/disable endpoints rather than rely on name encoding to select the right profile?
I agree that this is not ideal, but this is an improvement from the current state where we would need 1 UCM profile per board (assuming valid DMI data and thus a proper long-name being set), 6 profiles (dmic2 is not used anywhere sofar) is a whole lot easier to manage then 1 profile per board. So as said I believe this is a step in the right direction.
And looking at the foreseeable future I simply don't see any of us having the time to implement an ideal solution for this. I would really like for end users to be able to run the latest upstream kernel + alsa-lib and have things just work, before this hardware becomes obsolete. I know that no-one having time to work on reworking UCM to make it more dynamic is not the best of arguments but it is something to take into consideration.
Thinking more about this on the alsa-lib / UCM profile side we could have something like this:
/usr/share/alsa/ucm/bytcr-rt5640-mono-spk-in1-mic/bytcr-rt5640-mono-spk-in1-mic.conf:
SectionUseCase."HiFi" { File "../bytcr-rt5640/Generic.conf" File "../bytcr-rt5640/MonoSpeaker.conf" File "../bytcr-rt5640/In1Mic.conf" Comment "Play HiFi quality Music" }
SectionDefaults [ cdev "hw:bytcrrt5640" ]
The only problem I can see with that is that the "ConflictingDevice" sections for the various inputs / outputs then would refer to not present SectionDevice sections. I have not tested this suggestion yet, but I'm willing to write an alsa-lib patch to ignore non present ConflictingDevice references, to make my suggestion work.
I think doing things this way, thus avoiding the need to copy and paste a whole lot of UCM code for the 6 profiles it will not be a problem to maintain 6 profiles, as we're really just maintaining 6 config snippets such as the above example and only one complete profile.
Would the solution I outlined above be acceptable to you?
The includes and disabling conflicting devices that aren't present make sense. I have another issue though: for SOF integration I already prepared a set of files, which are mostly identical to the regular ones except that the platform-side mixer controls are removed (or different) and the name of the card/device is different (sof- prefix). See on github.
Hmm, it might make sense to split the includes in platform and codec includes, so to pick my example again we would get:
/usr/share/alsa/ucm/bytcr-rt5640-mono-spk-in1-mic/bytcr-rt5640-mono-spk-in1-mic.conf:
SectionUseCase."HiFi" { SectionVerb { EnableSequence [ cdev "hw:bytcrrt5640"
File "../bytcr-rt5640/EnableSeq.conf" # This contains the platform mixer settings File "../rt5640/EnableSeq.conf" ]
DisableSequence [ ]
Value { PlaybackPCM "hw:bytcrrt5640" CapturePCM "hw:bytcrrt5640" } }
File "../rt5640/Headset.conf" File "../rt5640/MonoSpeaker.conf" File "../rt5640/In1Mic.conf" Comment "Play HiFi quality Music" }
SectionDefaults [ cdev "hw:bytcrrt5640" ]
And then for sof you would just need to offer a sof-rt5640/EnableSeq.conf, or maybe even leave it out completely.
And we might also be able to merge the platform enable sequences into a generic:
bytcr/EnableSeq.conf
I think that will at least fly for bytcr-rt5640 and butcr-rt5651, leading us being able to remove more duplicated UCM config.
How does this sound?
splitting platform and codec sides is a good idea (and something that was done by removing all platform mixer settings from the HiFi files)
the problem remains that we have all these cdev strings that are hard-codec with a card name. Same when the match happens based on a DMI string, how would I know which of the platform settings to apply without querying what the platform driver is?
Regards,
Hans
I was nearly ready to submit all those files to the new repository, I wasn't aware of your work so now need to figure out how to reuse all this once we upstream SOF (any time now if I look at Liam's patches).
Regards,
Hans
Note that if we ever encounter the need for a special UCM profile for some device we can add a quirk to set a specific long_name for the device,
Signed-off-by: Hans de Goede hdegoede@redhat.com
sound/soc/intel/boards/bytcr_rt5640.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index cfc520200214..9a1204dcdbc6 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -929,6 +929,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN]; static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ +static char byt_rt5640_long_name[40]; /* = "bytcr-rt5640-*-spk-*-mic" */ static int byt_rt5640_suspend(struct snd_soc_card *card) { @@ -1000,6 +1001,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { + const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; @@ -1163,6 +1165,13 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) } } + snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name), + "bytcr-rt5640-%s-spk-%s-mic", + (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? + "mono" : "stereo", + map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); + byt_rt5640_card.long_name = byt_rt5640_long_name;
ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); if (ret_val) {
Hi,
On 10-05-18 19:46, Pierre-Louis Bossart wrote:
On 5/10/18 10:48 AM, Hans de Goede wrote:
Hi,
On 10-05-18 17:00, Pierre-Louis Bossart wrote:
On 5/10/18 5:27 AM, Hans de Goede wrote:
Hi,
On 08-05-18 20:35, Pierre-Louis Bossart wrote:
On 5/8/18 10:36 AM, Hans de Goede wrote:
Many X86 devices using a BYT SoC + RT5640 codec are cheap devices with generic DMI strings, causing snd_soc_set_dmi_name() to fail to set a long_name, making it impossible for userspace to have a correct UCM profile which only uses inputs / outputs which are actually hooked up on the device.
Our quirks already specify which input the internal mic is connected to and if a single (mono) speaker is used or if the device has stereo speakers.
This commit sets a long_name based on the quirks so that userspace can have UCM profiles doing the right thing based on the long_name.
Isn't this going to be complicated to manage for UCM? Just with this patch alone, you'd need 8 UCM files to cover all the combinations. 16 if you add the 'sof-' prefix.
seems like UCM should become more 'dynamic' and get quirk information somehow (sysfs?) to enable/disable endpoints rather than rely on name encoding to select the right profile?
I agree that this is not ideal, but this is an improvement from the current state where we would need 1 UCM profile per board (assuming valid DMI data and thus a proper long-name being set), 6 profiles (dmic2 is not used anywhere sofar) is a whole lot easier to manage then 1 profile per board. So as said I believe this is a step in the right direction.
And looking at the foreseeable future I simply don't see any of us having the time to implement an ideal solution for this. I would really like for end users to be able to run the latest upstream kernel + alsa-lib and have things just work, before this hardware becomes obsolete. I know that no-one having time to work on reworking UCM to make it more dynamic is not the best of arguments but it is something to take into consideration.
Thinking more about this on the alsa-lib / UCM profile side we could have something like this:
/usr/share/alsa/ucm/bytcr-rt5640-mono-spk-in1-mic/bytcr-rt5640-mono-spk-in1-mic.conf:
SectionUseCase."HiFi" { File "../bytcr-rt5640/Generic.conf" File "../bytcr-rt5640/MonoSpeaker.conf" File "../bytcr-rt5640/In1Mic.conf" Comment "Play HiFi quality Music" }
SectionDefaults [ cdev "hw:bytcrrt5640" ]
The only problem I can see with that is that the "ConflictingDevice" sections for the various inputs / outputs then would refer to not present SectionDevice sections. I have not tested this suggestion yet, but I'm willing to write an alsa-lib patch to ignore non present ConflictingDevice references, to make my suggestion work.
I think doing things this way, thus avoiding the need to copy and paste a whole lot of UCM code for the 6 profiles it will not be a problem to maintain 6 profiles, as we're really just maintaining 6 config snippets such as the above example and only one complete profile.
Would the solution I outlined above be acceptable to you?
The includes and disabling conflicting devices that aren't present make sense. I have another issue though: for SOF integration I already prepared a set of files, which are mostly identical to the regular ones except that the platform-side mixer controls are removed (or different) and the name of the card/device is different (sof- prefix). See on github.
Hmm, it might make sense to split the includes in platform and codec includes, so to pick my example again we would get:
/usr/share/alsa/ucm/bytcr-rt5640-mono-spk-in1-mic/bytcr-rt5640-mono-spk-in1-mic.conf:
SectionUseCase."HiFi" { SectionVerb { EnableSequence [ cdev "hw:bytcrrt5640"
File "../bytcr-rt5640/EnableSeq.conf" # This contains the platform mixer settings File "../rt5640/EnableSeq.conf" ]
DisableSequence [ ]
Value { PlaybackPCM "hw:bytcrrt5640" CapturePCM "hw:bytcrrt5640" } }
File "../rt5640/Headset.conf" File "../rt5640/MonoSpeaker.conf" File "../rt5640/In1Mic.conf" Comment "Play HiFi quality Music" }
SectionDefaults [ cdev "hw:bytcrrt5640" ]
And then for sof you would just need to offer a sof-rt5640/EnableSeq.conf, or maybe even leave it out completely.
And we might also be able to merge the platform enable sequences into a generic:
bytcr/EnableSeq.conf
I think that will at least fly for bytcr-rt5640 and butcr-rt5651, leading us being able to remove more duplicated UCM config.
How does this sound?
splitting platform and codec sides is a good idea (and something that was done by removing all platform mixer settings from the HiFi files)
the problem remains that we have all these cdev strings that are hard-codec with a card name. Same when the match happens based on a DMI string, how would I know which of the platform settings to apply without querying what the platform driver is?
Well the DMI string would uniquely identify a certain model device, when we write the UCM file we should know what the platform + codec for that device is and we can simply hardcode them, like in my example above.
But maybe I'm misunderstanding you?
Regards,
Hans
sound/soc/intel/boards/bytcr_rt5640.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index cfc520200214..9a1204dcdbc6 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -929,6 +929,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN]; static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ +static char byt_rt5640_long_name[40]; /* = "bytcr-rt5640-*-spk-*-mic" */ static int byt_rt5640_suspend(struct snd_soc_card *card) { @@ -1000,6 +1001,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { + const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; @@ -1163,6 +1165,13 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) } } + snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name), + "bytcr-rt5640-%s-spk-%s-mic", + (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? + "mono" : "stereo", + map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); + byt_rt5640_card.long_name = byt_rt5640_long_name;
ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); if (ret_val) {
On 05/10/2018 01:01 PM, Hans de Goede wrote:
Hi,
On 10-05-18 19:46, Pierre-Louis Bossart wrote:
On 5/10/18 10:48 AM, Hans de Goede wrote:
Hi,
On 10-05-18 17:00, Pierre-Louis Bossart wrote:
On 5/10/18 5:27 AM, Hans de Goede wrote:
Hi,
On 08-05-18 20:35, Pierre-Louis Bossart wrote:
On 5/8/18 10:36 AM, Hans de Goede wrote: > Many X86 devices using a BYT SoC + RT5640 codec are cheap > devices with > generic DMI strings, causing snd_soc_set_dmi_name() to fail to > set a > long_name, making it impossible for userspace to have a correct UCM > profile which only uses inputs / outputs which are actually > hooked up > on the device. > > Our quirks already specify which input the internal mic is > connected to > and if a single (mono) speaker is used or if the device has stereo > speakers. > > This commit sets a long_name based on the quirks so that > userspace can > have UCM profiles doing the right thing based on the long_name.
Isn't this going to be complicated to manage for UCM? Just with this patch alone, you'd need 8 UCM files to cover all the combinations. 16 if you add the 'sof-' prefix.
seems like UCM should become more 'dynamic' and get quirk information somehow (sysfs?) to enable/disable endpoints rather than rely on name encoding to select the right profile?
I agree that this is not ideal, but this is an improvement from the current state where we would need 1 UCM profile per board (assuming valid DMI data and thus a proper long-name being set), 6 profiles (dmic2 is not used anywhere sofar) is a whole lot easier to manage then 1 profile per board. So as said I believe this is a step in the right direction.
And looking at the foreseeable future I simply don't see any of us having the time to implement an ideal solution for this. I would really like for end users to be able to run the latest upstream kernel + alsa-lib and have things just work, before this hardware becomes obsolete. I know that no-one having time to work on reworking UCM to make it more dynamic is not the best of arguments but it is something to take into consideration.
Thinking more about this on the alsa-lib / UCM profile side we could have something like this:
/usr/share/alsa/ucm/bytcr-rt5640-mono-spk-in1-mic/bytcr-rt5640-mono-spk-in1-mic.conf:
SectionUseCase."HiFi" { File "../bytcr-rt5640/Generic.conf" File "../bytcr-rt5640/MonoSpeaker.conf" File "../bytcr-rt5640/In1Mic.conf" Comment "Play HiFi quality Music" }
SectionDefaults [ cdev "hw:bytcrrt5640" ]
The only problem I can see with that is that the "ConflictingDevice" sections for the various inputs / outputs then would refer to not present SectionDevice sections. I have not tested this suggestion yet, but I'm willing to write an alsa-lib patch to ignore non present ConflictingDevice references, to make my suggestion work.
I think doing things this way, thus avoiding the need to copy and paste a whole lot of UCM code for the 6 profiles it will not be a problem to maintain 6 profiles, as we're really just maintaining 6 config snippets such as the above example and only one complete profile.
Would the solution I outlined above be acceptable to you?
The includes and disabling conflicting devices that aren't present make sense. I have another issue though: for SOF integration I already prepared a set of files, which are mostly identical to the regular ones except that the platform-side mixer controls are removed (or different) and the name of the card/device is different (sof- prefix). See on github.
Hmm, it might make sense to split the includes in platform and codec includes, so to pick my example again we would get:
/usr/share/alsa/ucm/bytcr-rt5640-mono-spk-in1-mic/bytcr-rt5640-mono-spk-in1-mic.conf:
SectionUseCase."HiFi" { SectionVerb { EnableSequence [ cdev "hw:bytcrrt5640"
File "../bytcr-rt5640/EnableSeq.conf" # This contains the platform mixer settings File "../rt5640/EnableSeq.conf" ]
DisableSequence [ ]
Value { PlaybackPCM "hw:bytcrrt5640" CapturePCM "hw:bytcrrt5640" } }
File "../rt5640/Headset.conf" File "../rt5640/MonoSpeaker.conf" File "../rt5640/In1Mic.conf" Comment "Play HiFi quality Music" }
SectionDefaults [ cdev "hw:bytcrrt5640" ]
And then for sof you would just need to offer a sof-rt5640/EnableSeq.conf, or maybe even leave it out completely.
And we might also be able to merge the platform enable sequences into a generic:
bytcr/EnableSeq.conf
I think that will at least fly for bytcr-rt5640 and butcr-rt5651, leading us being able to remove more duplicated UCM config.
How does this sound?
splitting platform and codec sides is a good idea (and something that was done by removing all platform mixer settings from the HiFi files)
the problem remains that we have all these cdev strings that are hard-codec with a card name. Same when the match happens based on a DMI string, how would I know which of the platform settings to apply without querying what the platform driver is?
Well the DMI string would uniquely identify a certain model device, when we write the UCM file we should know what the platform + codec for that device is and we can simply hardcode them, like in my example above.
But maybe I'm misunderstanding you?
For the same DMI device, you could either enable the existing intel/sst or SOF drivers. How would we handle UCM configs then? The DMI name would need to be augmented with a prefix, or we use *something* to add the references to SOF in the platform include and ALSA device string.
On Sat, 12 May 2018 23:21:58 +0200, Pierre-Louis Bossart wrote:
splitting platform and codec sides is a good idea (and something that was done by removing all platform mixer settings from the HiFi files)
the problem remains that we have all these cdev strings that are hard-codec with a card name. Same when the match happens based on a DMI string, how would I know which of the platform settings to apply without querying what the platform driver is?
Well the DMI string would uniquely identify a certain model device, when we write the UCM file we should know what the platform + codec for that device is and we can simply hardcode them, like in my example above.
But maybe I'm misunderstanding you?
For the same DMI device, you could either enable the existing intel/sst or SOF drivers. How would we handle UCM configs then? The DMI name would need to be augmented with a prefix, or we use *something* to add the references to SOF in the platform include and ALSA device string.
You've already added the flavor suffix to snd_soc_set_dmi_name(), so they'll be unique, no?
Takashi
Hi,
On 05/13/2018 09:11 AM, Takashi Iwai wrote:
On Sat, 12 May 2018 23:21:58 +0200, Pierre-Louis Bossart wrote:
splitting platform and codec sides is a good idea (and something that was done by removing all platform mixer settings from the HiFi files)
the problem remains that we have all these cdev strings that are hard-codec with a card name. Same when the match happens based on a DMI string, how would I know which of the platform settings to apply without querying what the platform driver is?
Well the DMI string would uniquely identify a certain model device, when we write the UCM file we should know what the platform + codec for that device is and we can simply hardcode them, like in my example above.
But maybe I'm misunderstanding you?
For the same DMI device, you could either enable the existing intel/sst or SOF drivers. How would we handle UCM configs then? The DMI name would need to be augmented with a prefix, or we use *something* to add the references to SOF in the platform include and ALSA device string.
You've already added the flavor suffix to snd_soc_set_dmi_name(), so they'll be unique, no?
Yes I was going to suggest doing something like that, but if we already have that even better.
Note that the patch setting the longname based on the quirks overrides (pre-empts really) snd_soc_set_dmi_name() and does include bytcr_rt5640 prefix, so this patch should make sure that there is no name conflict between the sof and bytcr machine drivers UCM profiles.
As mentioned in the commit message this pre-emption means we loose the ability to have an UCM profile optimized for a specific device, but we can work around this if necessary with a flag which sets to not do set the quirk based long-name on some models (if the need ever arises for this).
Regards,
Hans
Hi Pierre-Louis,
On 10-05-18 17:48, Hans de Goede wrote:
Hi,
On 10-05-18 17:00, Pierre-Louis Bossart wrote:
On 5/10/18 5:27 AM, Hans de Goede wrote:
Hi,
On 08-05-18 20:35, Pierre-Louis Bossart wrote:
On 5/8/18 10:36 AM, Hans de Goede wrote:
Many X86 devices using a BYT SoC + RT5640 codec are cheap devices with generic DMI strings, causing snd_soc_set_dmi_name() to fail to set a long_name, making it impossible for userspace to have a correct UCM profile which only uses inputs / outputs which are actually hooked up on the device.
Our quirks already specify which input the internal mic is connected to and if a single (mono) speaker is used or if the device has stereo speakers.
This commit sets a long_name based on the quirks so that userspace can have UCM profiles doing the right thing based on the long_name.
Isn't this going to be complicated to manage for UCM? Just with this patch alone, you'd need 8 UCM files to cover all the combinations. 16 if you add the 'sof-' prefix.
seems like UCM should become more 'dynamic' and get quirk information somehow (sysfs?) to enable/disable endpoints rather than rely on name encoding to select the right profile?
I agree that this is not ideal, but this is an improvement from the current state where we would need 1 UCM profile per board (assuming valid DMI data and thus a proper long-name being set), 6 profiles (dmic2 is not used anywhere sofar) is a whole lot easier to manage then 1 profile per board. So as said I believe this is a step in the right direction.
And looking at the foreseeable future I simply don't see any of us having the time to implement an ideal solution for this. I would really like for end users to be able to run the latest upstream kernel + alsa-lib and have things just work, before this hardware becomes obsolete. I know that no-one having time to work on reworking UCM to make it more dynamic is not the best of arguments but it is something to take into consideration.
Thinking more about this on the alsa-lib / UCM profile side we could have something like this:
/usr/share/alsa/ucm/bytcr-rt5640-mono-spk-in1-mic/bytcr-rt5640-mono-spk-in1-mic.conf:
SectionUseCase."HiFi" { File "../bytcr-rt5640/Generic.conf" File "../bytcr-rt5640/MonoSpeaker.conf" File "../bytcr-rt5640/In1Mic.conf" Comment "Play HiFi quality Music" }
SectionDefaults [ cdev "hw:bytcrrt5640" ]
The only problem I can see with that is that the "ConflictingDevice" sections for the various inputs / outputs then would refer to not present SectionDevice sections. I have not tested this suggestion yet, but I'm willing to write an alsa-lib patch to ignore non present ConflictingDevice references, to make my suggestion work.
I think doing things this way, thus avoiding the need to copy and paste a whole lot of UCM code for the 6 profiles it will not be a problem to maintain 6 profiles, as we're really just maintaining 6 config snippets such as the above example and only one complete profile.
Would the solution I outlined above be acceptable to you?
The includes and disabling conflicting devices that aren't present make sense. I have another issue though: for SOF integration I already prepared a set of files, which are mostly identical to the regular ones except that the platform-side mixer controls are removed (or different) and the name of the card/device is different (sof- prefix). See on github.
Hmm, it might make sense to split the includes in platform and codec includes, so to pick my example again we would get:
/usr/share/alsa/ucm/bytcr-rt5640-mono-spk-in1-mic/bytcr-rt5640-mono-spk-in1-mic.conf:
SectionUseCase."HiFi" { SectionVerb { EnableSequence [ cdev "hw:bytcrrt5640"
File "../bytcr-rt5640/EnableSeq.conf" # This contains the platform mixer settings File "../rt5640/EnableSeq.conf" ]
DisableSequence [ ]
Value { PlaybackPCM "hw:bytcrrt5640" CapturePCM "hw:bytcrrt5640" } }
File "../rt5640/Headset.conf" File "../rt5640/MonoSpeaker.conf" File "../rt5640/In1Mic.conf" Comment "Play HiFi quality Music" }
SectionDefaults [ cdev "hw:bytcrrt5640" ]
And then for sof you would just need to offer a sof-rt5640/EnableSeq.conf, or maybe even leave it out completely.
And we might also be able to merge the platform enable sequences into a generic:
bytcr/EnableSeq.conf
I think that will at least fly for bytcr-rt5640 and butcr-rt5651, leading us being able to remove more duplicated UCM config. > How does this sound?
I've implemented the above scheme, see: https://github.com/jwrdegoede/alsa-lib/commits/master
This seems to work well (I still need to test a bit more, but so far the generic and one long-name based profile work fine) and Mark has merged the "ASoC: Intel: bytcr_rt5640: Set card long_name based on quirks" patch in his for-next branch, so I plan to submit the matching alsa-lib patches from my github for upstream alsa-lib inclusion soon.
Regards,
Hans
On 5/18/18 10:55 AM, Hans de Goede wrote:
Hi Pierre-Louis,
On 10-05-18 17:48, Hans de Goede wrote:
Hi,
On 10-05-18 17:00, Pierre-Louis Bossart wrote:
On 5/10/18 5:27 AM, Hans de Goede wrote:
Hi,
On 08-05-18 20:35, Pierre-Louis Bossart wrote:
On 5/8/18 10:36 AM, Hans de Goede wrote:
Many X86 devices using a BYT SoC + RT5640 codec are cheap devices with generic DMI strings, causing snd_soc_set_dmi_name() to fail to set a long_name, making it impossible for userspace to have a correct UCM profile which only uses inputs / outputs which are actually hooked up on the device.
Our quirks already specify which input the internal mic is connected to and if a single (mono) speaker is used or if the device has stereo speakers.
This commit sets a long_name based on the quirks so that userspace can have UCM profiles doing the right thing based on the long_name.
Isn't this going to be complicated to manage for UCM? Just with this patch alone, you'd need 8 UCM files to cover all the combinations. 16 if you add the 'sof-' prefix.
seems like UCM should become more 'dynamic' and get quirk information somehow (sysfs?) to enable/disable endpoints rather than rely on name encoding to select the right profile?
I agree that this is not ideal, but this is an improvement from the current state where we would need 1 UCM profile per board (assuming valid DMI data and thus a proper long-name being set), 6 profiles (dmic2 is not used anywhere sofar) is a whole lot easier to manage then 1 profile per board. So as said I believe this is a step in the right direction.
And looking at the foreseeable future I simply don't see any of us having the time to implement an ideal solution for this. I would really like for end users to be able to run the latest upstream kernel + alsa-lib and have things just work, before this hardware becomes obsolete. I know that no-one having time to work on reworking UCM to make it more dynamic is not the best of arguments but it is something to take into consideration.
Thinking more about this on the alsa-lib / UCM profile side we could have something like this:
/usr/share/alsa/ucm/bytcr-rt5640-mono-spk-in1-mic/bytcr-rt5640-mono-spk-in1-mic.conf:
SectionUseCase."HiFi" { File "../bytcr-rt5640/Generic.conf" File "../bytcr-rt5640/MonoSpeaker.conf" File "../bytcr-rt5640/In1Mic.conf" Comment "Play HiFi quality Music" }
SectionDefaults [ cdev "hw:bytcrrt5640" ]
The only problem I can see with that is that the "ConflictingDevice" sections for the various inputs / outputs then would refer to not present SectionDevice sections. I have not tested this suggestion yet, but I'm willing to write an alsa-lib patch to ignore non present ConflictingDevice references, to make my suggestion work.
I think doing things this way, thus avoiding the need to copy and paste a whole lot of UCM code for the 6 profiles it will not be a problem to maintain 6 profiles, as we're really just maintaining 6 config snippets such as the above example and only one complete profile.
Would the solution I outlined above be acceptable to you?
The includes and disabling conflicting devices that aren't present make sense. I have another issue though: for SOF integration I already prepared a set of files, which are mostly identical to the regular ones except that the platform-side mixer controls are removed (or different) and the name of the card/device is different (sof- prefix). See on github.
Hmm, it might make sense to split the includes in platform and codec includes, so to pick my example again we would get:
/usr/share/alsa/ucm/bytcr-rt5640-mono-spk-in1-mic/bytcr-rt5640-mono-spk-in1-mic.conf:
SectionUseCase."HiFi" { SectionVerb { EnableSequence [ cdev "hw:bytcrrt5640"
File "../bytcr-rt5640/EnableSeq.conf" # This contains the platform mixer settings File "../rt5640/EnableSeq.conf" ]
DisableSequence [ ]
Value { PlaybackPCM "hw:bytcrrt5640" CapturePCM "hw:bytcrrt5640" } }
File "../rt5640/Headset.conf" File "../rt5640/MonoSpeaker.conf" File "../rt5640/In1Mic.conf" Comment "Play HiFi quality Music" }
SectionDefaults [ cdev "hw:bytcrrt5640" ]
And then for sof you would just need to offer a sof-rt5640/EnableSeq.conf, or maybe even leave it out completely.
And we might also be able to merge the platform enable sequences into a generic:
bytcr/EnableSeq.conf
I think that will at least fly for bytcr-rt5640 and butcr-rt5651, leading us being able to remove more duplicated UCM config. > How does this sound?
I've implemented the above scheme, see: https://github.com/jwrdegoede/alsa-lib/commits/master
This seems to work well (I still need to test a bit more, but so far the generic and one long-name based profile work fine) and Mark has merged the "ASoC: Intel: bytcr_rt5640: Set card long_name based on quirks" patch in his for-next branch, so I plan to submit the matching alsa-lib patches from my github for upstream alsa-lib inclusion soon.
This looks pretty good, thanks!
The part that is still problematic is the cdev "hw:bytcrrt5640" that is pretty much everywhere. I don't know if it's useful to be repeated in all files. If there was a way to assign it at a higher level or to override it when SOF is present it'd solve most of the issues I see.
Please go ahead and submit these patches, I am not going to have iso-functionality for rt5640 and 51 in the next weeks with SOF - I don't have a clean way to deal with SSP0/SSP2 automatic configuration at the firmware level for now, so don't want to stop your work because I have something on the back burner.
The patch
ASoC: Intel: bytcr_rt5640: Set card long_name based on quirks
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 063422ca2a9de238401c3848c1b3641c07b6316c Mon Sep 17 00:00:00 2001
From: Hans de Goede hdegoede@redhat.com Date: Sun, 13 May 2018 09:24:35 +0200 Subject: [PATCH] ASoC: Intel: bytcr_rt5640: Set card long_name based on quirks
Many X86 devices using a BYT SoC + RT5640 codec are cheap devices with generic DMI strings, causing snd_soc_set_dmi_name() to fail to set a long_name, making it impossible for userspace to have a correct UCM profile which only uses inputs / outputs which are actually hooked up on the device.
Our quirks already specify which input the internal mic is connected to and if a single (mono) speaker is used or if the device has stereo speakers.
This commit sets a long_name based on the quirks so that userspace can have UCM profiles doing the right thing based on the long_name.
Note that if we ever encounter the need for a special UCM profile for some device we can add a quirk to set a specific long_name for the device,
Signed-off-by: Hans de Goede hdegoede@redhat.com Acked-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bytcr_rt5640.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 686d00405493..b0eec0a9b7b9 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -950,6 +950,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN]; static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ +static char byt_rt5640_long_name[40]; /* = "bytcr-rt5640-*-spk-*-mic" */
static int byt_rt5640_suspend(struct snd_soc_card *card) { @@ -1021,6 +1022,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */
static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { + const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; @@ -1184,6 +1186,13 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) } }
+ snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name), + "bytcr-rt5640-%s-spk-%s-mic", + (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? + "mono" : "stereo", + map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); + byt_rt5640_card.long_name = byt_rt5640_long_name; + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card);
if (ret_val) {
On 5/8/18 10:35 AM, Hans de Goede wrote:
Hi All,
This series has been long in the making, but it is finally ready now. This series adds jack-detect support for rt5640 using devices.
This is modelled after the recent rt5651 codec- and bytcr-rt5651 machine- driver jack-detect changes (which were actually based on a WIP version of this series).
As discussed on the list already unfortunately there are no really good defaults which work everywhere, so patch 18 adds quirks for 10 devices, I've decided to do this in one go rather then split this into 10 patches.
Impressive work, thanks!
patches 8..18 Acked-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com
Patch 19 makes the bytcr-rt5640 set a longname based on the speaker and input-map quirks, so that userspace can pick a correct UCM profile based on the longname with working jack-detect based input / output switching. I've matching patches adding UCM profiles for this to alsa-lib here: https://github.com/jwrdegoede/alsa-lib/commits/master I'm waiting with submitting those upstream until patch 19 is accepted for merging.
That last patch is a bit controversial. I am not sure this is the right direction to add a new profile for every combination of quirks. At the very least, we should have a mechanism to include basic parts (and I think UCM already has a concept of include). Or better one UCM file that combines all possible combinations and disables some parts based on quirk information fetched during initialization.
Regards,
Hans
participants (4)
-
Hans de Goede
-
Mark Brown
-
Pierre-Louis Bossart
-
Takashi Iwai