diff options
Diffstat (limited to 'sound/soc/codecs/rt5651.c')
| -rw-r--r-- | sound/soc/codecs/rt5651.c | 180 |
1 files changed, 119 insertions, 61 deletions
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index b7ba64350a07..9af65a38f0ee 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -1,18 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rt5651.c -- RT5651 ALSA SoC audio codec driver * * Copyright 2014 Realtek Semiconductor Corp. * Author: Bard Liao <bardliao@realtek.com> - * - * 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. */ #include <linux/module.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/regmap.h> #include <linux/platform_device.h> @@ -287,9 +285,9 @@ static bool rt5651_readable_register(struct device *dev, unsigned int reg) } static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); -static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); +static const DECLARE_TLV_DB_MINMAX(dac_vol_tlv, -6562, 0); static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); -static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_MINMAX(adc_vol_tlv, -1762, 3000); static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ @@ -747,11 +745,11 @@ static int rt5651_hp_event(struct snd_soc_dapm_widget *w, RT5651_HP_CP_PD | RT5651_HP_SG_EN); regmap_update_bits(rt5651->regmap, RT5651_PR_BASE + RT5651_CHPUMP_INT_REG1, 0x0700, 0x0400); - rt5651->hp_mute = 0; + rt5651->hp_mute = false; break; case SND_SOC_DAPM_PRE_PMD: - rt5651->hp_mute = 1; + rt5651->hp_mute = true; usleep_range(70000, 75000); break; @@ -1354,10 +1352,10 @@ static int rt5651_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int reg_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: rt5651->master[dai->id] = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg_val |= RT5651_I2S_MS_S; rt5651->master[dai->id] = 0; break; @@ -1489,7 +1487,7 @@ static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } @@ -1500,8 +1498,8 @@ static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, snd_soc_component_write(component, RT5651_PLL_CTRL1, pll_code.n_code << RT5651_PLL_N_SFT | pll_code.k_code); snd_soc_component_write(component, RT5651_PLL_CTRL2, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT5651_PLL_M_SFT | - pll_code.m_bp << RT5651_PLL_M_BP_SFT); + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5651_PLL_M_SFT) | + (pll_code.m_bp << RT5651_PLL_M_BP_SFT)); rt5651->pll_in = freq_in; rt5651->pll_out = freq_out; @@ -1513,16 +1511,18 @@ static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, static int rt5651_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); + switch (level) { case SND_SOC_BIAS_PREPARE: - if (SND_SOC_BIAS_STANDBY == snd_soc_component_get_bias_level(component)) { - if (snd_soc_component_read32(component, RT5651_PLL_MODE_1) & 0x9200) + if (SND_SOC_BIAS_STANDBY == snd_soc_dapm_get_bias_level(dapm)) { + if (snd_soc_component_read(component, RT5651_PLL_MODE_1) & 0x9200) snd_soc_component_update_bits(component, RT5651_D_MISC, 0xc00, 0xc00); } break; case SND_SOC_BIAS_STANDBY: - if (SND_SOC_BIAS_OFF == snd_soc_component_get_bias_level(component)) { + if (SND_SOC_BIAS_OFF == snd_soc_dapm_get_bias_level(dapm)) { snd_soc_component_update_bits(component, RT5651_PWR_ANLG1, RT5651_PWR_VREF1 | RT5651_PWR_MB | RT5651_PWR_BG | RT5651_PWR_VREF2, @@ -1559,7 +1559,7 @@ static int rt5651_set_bias_level(struct snd_soc_component *component, static void rt5651_enable_micbias1_for_ovcd(struct snd_soc_component *component) { - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); snd_soc_dapm_mutex_lock(dapm); snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO"); @@ -1572,7 +1572,7 @@ static void rt5651_enable_micbias1_for_ovcd(struct snd_soc_component *component) static void rt5651_disable_micbias1_for_ovcd(struct snd_soc_component *component) { - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); snd_soc_dapm_mutex_lock(dapm); snd_soc_dapm_disable_pin_unlocked(dapm, "Platform Clock"); @@ -1610,7 +1610,7 @@ static bool rt5651_micbias1_ovcd(struct snd_soc_component *component) { int val; - val = snd_soc_component_read32(component, RT5651_IRQ_CTRL2); + val = snd_soc_component_read(component, RT5651_IRQ_CTRL2); dev_dbg(component->dev, "irq ctrl2 %#04x\n", val); return (val & RT5651_MB1_OC_CLR); @@ -1621,7 +1621,13 @@ static bool rt5651_jack_inserted(struct snd_soc_component *component) struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component); int val; - val = snd_soc_component_read32(component, RT5651_INT_IRQ_ST); + if (rt5651->gpiod_hp_det) { + val = gpiod_get_value_cansleep(rt5651->gpiod_hp_det); + dev_dbg(component->dev, "jack-detect gpio %d\n", val); + return val; + } + + val = snd_soc_component_read(component, RT5651_INT_IRQ_ST); dev_dbg(component->dev, "irq status %#04x\n", val); switch (rt5651->jd_src) { @@ -1638,7 +1644,10 @@ static bool rt5651_jack_inserted(struct snd_soc_component *component) break; } - return val == 0; + if (rt5651->jd_active_high) + return val != 0; + else + return val == 0; } /* Jack detect and button-press timings */ @@ -1761,12 +1770,22 @@ static int rt5651_detect_headset(struct snd_soc_component *component) return SND_JACK_HEADPHONE; } +static bool rt5651_support_button_press(struct rt5651_priv *rt5651) +{ + if (!rt5651->hp_jack) + return false; + + /* Button press support only works with internal jack-detection */ + return (rt5651->hp_jack->status & SND_JACK_MICROPHONE) && + rt5651->gpiod_hp_det == NULL; +} + static void rt5651_jack_detect_work(struct work_struct *work) { struct rt5651_priv *rt5651 = container_of(work, struct rt5651_priv, jack_detect_work); struct snd_soc_component *component = rt5651->component; - int report = 0; + int report; if (!rt5651_jack_inserted(component)) { /* Jack removed, or spurious IRQ? */ @@ -1785,15 +1804,15 @@ static void rt5651_jack_detect_work(struct work_struct *work) WARN_ON(rt5651->ovcd_irq_enabled); rt5651_enable_micbias1_for_ovcd(component); report = rt5651_detect_headset(component); - if (report == SND_JACK_HEADSET) { + dev_dbg(component->dev, "detect report %#02x\n", report); + snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET); + if (rt5651_support_button_press(rt5651)) { /* Enable ovcd IRQ for button press detect. */ rt5651_enable_micbias1_ovcd_irq(component); } else { /* No more need for overcurrent detect. */ rt5651_disable_micbias1_for_ovcd(component); } - dev_dbg(component->dev, "detect report %#02x\n", report); - snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET); } else if (rt5651->ovcd_irq_enabled && rt5651_micbias1_ovcd(component)) { dev_dbg(component->dev, "OVCD IRQ\n"); @@ -1837,44 +1856,79 @@ static void rt5651_cancel_work(void *data) } static void rt5651_enable_jack_detect(struct snd_soc_component *component, - struct snd_soc_jack *hp_jack) + struct snd_soc_jack *hp_jack, + struct gpio_desc *gpiod_hp_det) { struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component); - - /* IRQ output on GPIO1 */ - snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1, - RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ); + bool using_internal_jack_detect = true; /* Select jack detect source */ switch (rt5651->jd_src) { + case RT5651_JD_NULL: + rt5651->gpiod_hp_det = gpiod_hp_det; + if (!rt5651->gpiod_hp_det) + return; /* No jack detect */ + using_internal_jack_detect = false; + break; case RT5651_JD1_1: snd_soc_component_update_bits(component, RT5651_JD_CTRL2, RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_1); - snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1, - RT5651_JD1_1_IRQ_EN, RT5651_JD1_1_IRQ_EN); + /* active-low is normal, set inv flag for active-high */ + if (rt5651->jd_active_high) + snd_soc_component_update_bits(component, + RT5651_IRQ_CTRL1, + RT5651_JD1_1_IRQ_EN | RT5651_JD1_1_INV, + RT5651_JD1_1_IRQ_EN | RT5651_JD1_1_INV); + else + snd_soc_component_update_bits(component, + RT5651_IRQ_CTRL1, + RT5651_JD1_1_IRQ_EN | RT5651_JD1_1_INV, + RT5651_JD1_1_IRQ_EN); break; case RT5651_JD1_2: snd_soc_component_update_bits(component, RT5651_JD_CTRL2, RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_2); - snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1, - RT5651_JD1_2_IRQ_EN, RT5651_JD1_2_IRQ_EN); + /* active-low is normal, set inv flag for active-high */ + if (rt5651->jd_active_high) + snd_soc_component_update_bits(component, + RT5651_IRQ_CTRL1, + RT5651_JD1_2_IRQ_EN | RT5651_JD1_2_INV, + RT5651_JD1_2_IRQ_EN | RT5651_JD1_2_INV); + else + snd_soc_component_update_bits(component, + RT5651_IRQ_CTRL1, + RT5651_JD1_2_IRQ_EN | RT5651_JD1_2_INV, + RT5651_JD1_2_IRQ_EN); break; case RT5651_JD2: snd_soc_component_update_bits(component, RT5651_JD_CTRL2, RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD2); - snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1, - RT5651_JD2_IRQ_EN, RT5651_JD2_IRQ_EN); + /* active-low is normal, set inv flag for active-high */ + if (rt5651->jd_active_high) + snd_soc_component_update_bits(component, + RT5651_IRQ_CTRL1, + RT5651_JD2_IRQ_EN | RT5651_JD2_INV, + RT5651_JD2_IRQ_EN | RT5651_JD2_INV); + else + snd_soc_component_update_bits(component, + RT5651_IRQ_CTRL1, + RT5651_JD2_IRQ_EN | RT5651_JD2_INV, + RT5651_JD2_IRQ_EN); break; - case RT5651_JD_NULL: - return; default: dev_err(component->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n"); return; } - /* Enable jack detect power */ - snd_soc_component_update_bits(component, RT5651_PWR_ANLG2, - RT5651_PWR_JD_M, RT5651_PWR_JD_M); + if (using_internal_jack_detect) { + /* IRQ output on GPIO1 */ + snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1, + RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ); + + /* Enable jack detect power */ + snd_soc_component_update_bits(component, RT5651_PWR_ANLG2, + RT5651_PWR_JD_M, RT5651_PWR_JD_M); + } /* Set OVCD threshold current and scale-factor */ snd_soc_component_write(component, RT5651_PR_BASE + RT5651_BIAS_CUR4, @@ -1903,7 +1957,7 @@ static void rt5651_enable_jack_detect(struct snd_soc_component *component, RT5651_MB1_OC_STKY_MASK, RT5651_MB1_OC_STKY_EN); rt5651->hp_jack = hp_jack; - if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) { + if (rt5651_support_button_press(rt5651)) { rt5651_enable_micbias1_for_ovcd(component); rt5651_enable_micbias1_ovcd_irq(component); } @@ -1920,7 +1974,7 @@ static void rt5651_disable_jack_detect(struct snd_soc_component *component) disable_irq(rt5651->irq); rt5651_cancel_work(rt5651); - if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) { + if (rt5651_support_button_press(rt5651)) { rt5651_disable_micbias1_ovcd_irq(component); rt5651_disable_micbias1_for_ovcd(component); snd_soc_jack_report(rt5651->hp_jack, 0, SND_JACK_BTN_0); @@ -1933,7 +1987,7 @@ static int rt5651_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jack, void *data) { if (jack) - rt5651_enable_jack_detect(component, jack); + rt5651_enable_jack_detect(component, jack, data); else rt5651_disable_jack_detect(component); @@ -1964,6 +2018,9 @@ static void rt5651_apply_properties(struct snd_soc_component *component) "realtek,jack-detect-source", &val) == 0) rt5651->jd_src = val; + if (device_property_read_bool(component->dev, "realtek,jack-detect-not-inverted")) + rt5651->jd_active_high = 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 @@ -2003,13 +2060,14 @@ static void rt5651_apply_properties(struct snd_soc_component *component) static int rt5651_probe(struct snd_soc_component *component) { struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); rt5651->component = component; snd_soc_component_update_bits(component, RT5651_PWR_ANLG1, RT5651_PWR_LDO_DVO_MASK, RT5651_PWR_LDO_DVO_1_2V); - snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF); + snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF); rt5651_apply_properties(component); @@ -2106,7 +2164,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5651 = { .num_dapm_routes = ARRAY_SIZE(rt5651_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5651_regmap = { @@ -2118,7 +2175,7 @@ static const struct regmap_config rt5651_regmap = { .volatile_reg = rt5651_volatile_register, .readable_reg = rt5651_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = rt5651_reg, .num_reg_defaults = ARRAY_SIZE(rt5651_reg), .ranges = rt5651_ranges, @@ -2130,21 +2187,22 @@ static const struct regmap_config rt5651_regmap = { #if defined(CONFIG_OF) static const struct of_device_id rt5651_of_match[] = { { .compatible = "realtek,rt5651", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, rt5651_of_match); #endif #ifdef CONFIG_ACPI static const struct acpi_device_id rt5651_acpi_match[] = { - { "10EC5651", 0 }, - { }, + { "10EC5640" }, + { "10EC5651" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt5651_acpi_match); #endif static const struct i2c_device_id rt5651_i2c_id[] = { - { "rt5651", 0 }, + { "rt5651" }, { } }; MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id); @@ -2153,11 +2211,11 @@ MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id); * Note this function MUST not look at device-properties, see the comment * above rt5651_apply_properties(). */ -static int rt5651_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5651_i2c_probe(struct i2c_client *i2c) { struct rt5651_priv *rt5651; int ret; + int err; rt5651 = devm_kzalloc(&i2c->dev, sizeof(*rt5651), GFP_KERNEL); @@ -2174,7 +2232,10 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, return ret; } - regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret); + err = regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret); + if (err) + return err; + if (ret != RT5651_DEVICE_ID_VALUE) { dev_err(&i2c->dev, "Device with ID register %#x is not rt5651\n", ret); @@ -2189,7 +2250,7 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); rt5651->irq = i2c->irq; - rt5651->hp_mute = 1; + rt5651->hp_mute = true; INIT_DELAYED_WORK(&rt5651->bp_work, rt5651_button_press_work); INIT_WORK(&rt5651->jack_detect_work, rt5651_jack_detect_work); @@ -2201,12 +2262,9 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, ret = devm_request_irq(&i2c->dev, rt5651->irq, rt5651_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING - | IRQF_ONESHOT, "rt5651", rt5651); - if (ret == 0) { - /* Gets re-enabled by rt5651_set_jack() */ - disable_irq(rt5651->irq); - } else { - dev_warn(&i2c->dev, "Failed to reguest IRQ %d: %d\n", + | IRQF_ONESHOT | IRQF_NO_AUTOEN, "rt5651", rt5651); + if (ret) { + dev_warn(&i2c->dev, "Failed to request IRQ %d: %d\n", rt5651->irq, ret); rt5651->irq = -ENXIO; } |
