summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/rt5651.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/rt5651.c')
-rw-r--r--sound/soc/codecs/rt5651.c837
1 files changed, 660 insertions, 177 deletions
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index db05b60d5002..9af65a38f0ee 100644
--- a/sound/soc/codecs/rt5651.c
+++ b/sound/soc/codecs/rt5651.c
@@ -1,19 +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/moduleparam.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>
@@ -26,6 +23,7 @@
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
+#include <sound/jack.h>
#include "rl6231.h"
#include "rt5651.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 */
@@ -330,11 +328,13 @@ static const struct snd_kcontrol_new rt5651_snd_controls[] = {
SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5651_DAC2_DIG_VOL,
RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
175, 0, dac_vol_tlv),
- /* IN1/IN2 Control */
+ /* IN1/IN2/IN3 Control */
SOC_SINGLE_TLV("IN1 Boost", RT5651_IN1_IN2,
RT5651_BST_SFT1, 8, 0, bst_tlv),
SOC_SINGLE_TLV("IN2 Boost", RT5651_IN1_IN2,
RT5651_BST_SFT2, 8, 0, bst_tlv),
+ SOC_SINGLE_TLV("IN3 Boost", RT5651_IN3,
+ RT5651_BST_SFT1, 8, 0, bst_tlv),
/* INL/INR Volume Control */
SOC_DOUBLE_TLV("IN Capture Volume", RT5651_INL1_INR1_VOL,
RT5651_INL_VOL_SFT, RT5651_INR_VOL_SFT,
@@ -376,36 +376,22 @@ static const struct snd_kcontrol_new rt5651_snd_controls[] = {
static int set_dmic_clk(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
int idx, rate;
rate = rt5651->sysclk / rl6231_get_pre_div(rt5651->regmap,
RT5651_ADDA_CLK1, RT5651_I2S_PD1_SFT);
idx = rl6231_calc_dmic_clk(rate);
if (idx < 0)
- dev_err(codec->dev, "Failed to set DMIC clock\n");
+ dev_err(component->dev, "Failed to set DMIC clock\n");
else
- snd_soc_update_bits(codec, RT5651_DMIC, RT5651_DMIC_CLK_MASK,
+ snd_soc_component_update_bits(component, RT5651_DMIC, RT5651_DMIC_CLK_MASK,
idx << RT5651_DMIC_CLK_SFT);
return idx;
}
-static int is_sysclk_from_pll(struct snd_soc_dapm_widget *source,
- struct snd_soc_dapm_widget *sink)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
- unsigned int val;
-
- val = snd_soc_read(codec, RT5651_GLB_CLK);
- val &= RT5651_SCLK_SRC_MASK;
- if (val == RT5651_SCLK_SRC_PLL1)
- return 1;
- else
- return 0;
-}
-
/* Digital Mixer */
static const struct snd_kcontrol_new rt5651_sto1_adc_l_mix[] = {
SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO1_ADC_MIXER,
@@ -695,8 +681,8 @@ static const struct snd_kcontrol_new rt5651_pdm_r_mux =
static int rt5651_amp_power_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
@@ -733,8 +719,8 @@ static int rt5651_amp_power_event(struct snd_soc_dapm_widget *w,
static int rt5651_hp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
@@ -759,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;
@@ -778,8 +764,8 @@ static int rt5651_hp_post_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
@@ -798,16 +784,16 @@ static int rt5651_hp_post_event(struct snd_soc_dapm_widget *w,
static int rt5651_bst1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+ snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
RT5651_PWR_BST1_OP2, RT5651_PWR_BST1_OP2);
break;
case SND_SOC_DAPM_PRE_PMD:
- snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+ snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
RT5651_PWR_BST1_OP2, 0);
break;
@@ -821,16 +807,16 @@ static int rt5651_bst1_event(struct snd_soc_dapm_widget *w,
static int rt5651_bst2_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+ snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
RT5651_PWR_BST2_OP2, RT5651_PWR_BST2_OP2);
break;
case SND_SOC_DAPM_PRE_PMD:
- snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+ snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
RT5651_PWR_BST2_OP2, 0);
break;
@@ -844,16 +830,16 @@ static int rt5651_bst2_event(struct snd_soc_dapm_widget *w,
static int rt5651_bst3_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+ snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
RT5651_PWR_BST3_OP2, RT5651_PWR_BST3_OP2);
break;
case SND_SOC_DAPM_PRE_PMD:
- snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+ snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
RT5651_PWR_BST3_OP2, 0);
break;
@@ -877,14 +863,11 @@ static const struct snd_soc_dapm_widget rt5651_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY_S("ADC ASRC", 1, RT5651_PLL_MODE_2,
11, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("PLL1", RT5651_PWR_ANLG2,
- RT5651_PWR_PLL_BIT, 0, NULL, 0),
- /* Input Side */
/* micbias */
SND_SOC_DAPM_SUPPLY("LDO", RT5651_PWR_ANLG1,
RT5651_PWR_LDO_BIT, 0, NULL, 0),
- SND_SOC_DAPM_MICBIAS("micbias1", RT5651_PWR_ANLG2,
- RT5651_PWR_MB1_BIT, 0),
+ SND_SOC_DAPM_SUPPLY("micbias1", RT5651_PWR_ANLG2,
+ RT5651_PWR_MB1_BIT, 0, NULL, 0),
/* Input Lines */
SND_SOC_DAPM_INPUT("MIC1"),
SND_SOC_DAPM_INPUT("MIC2"),
@@ -1158,7 +1141,6 @@ static const struct snd_soc_dapm_route rt5651_dapm_routes[] = {
{"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"},
{"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"},
{"Stereo1 ADC MIXL", NULL, "Stereo1 Filter"},
- {"Stereo1 Filter", NULL, "PLL1", is_sysclk_from_pll},
{"Stereo1 Filter", NULL, "ADC ASRC"},
{"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"},
@@ -1168,7 +1150,6 @@ static const struct snd_soc_dapm_route rt5651_dapm_routes[] = {
{"Stereo2 ADC MIXL", "ADC1 Switch", "Stereo2 ADC L1 Mux"},
{"Stereo2 ADC MIXL", "ADC2 Switch", "Stereo2 ADC L2 Mux"},
{"Stereo2 ADC MIXL", NULL, "Stereo2 Filter"},
- {"Stereo2 Filter", NULL, "PLL1", is_sysclk_from_pll},
{"Stereo2 Filter", NULL, "ADC ASRC"},
{"Stereo2 ADC MIXR", "ADC1 Switch", "Stereo2 ADC R1 Mux"},
@@ -1235,10 +1216,8 @@ static const struct snd_soc_dapm_route rt5651_dapm_routes[] = {
{"PDM R Mux", "DD MIX", "DAC MIXR"},
{"DAC L1", NULL, "Stereo DAC MIXL"},
- {"DAC L1", NULL, "PLL1", is_sysclk_from_pll},
{"DAC L1", NULL, "DAC L1 Power"},
{"DAC R1", NULL, "Stereo DAC MIXR"},
- {"DAC R1", NULL, "PLL1", is_sysclk_from_pll},
{"DAC R1", NULL, "DAC R1 Power"},
{"DD MIXL", "DAC L1 Switch", "DAC MIXL"},
@@ -1302,8 +1281,8 @@ static const struct snd_soc_dapm_route rt5651_dapm_routes[] = {
static int rt5651_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
- struct snd_soc_codec *codec = dai->codec;
- struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = dai->component;
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
unsigned int val_len = 0, val_clk, mask_clk;
int pre_div, bclk_ms, frame_size;
@@ -1311,12 +1290,12 @@ static int rt5651_hw_params(struct snd_pcm_substream *substream,
pre_div = rl6231_get_clk_info(rt5651->sysclk, rt5651->lrck[dai->id]);
if (pre_div < 0) {
- dev_err(codec->dev, "Unsupported clock setting\n");
+ dev_err(component->dev, "Unsupported clock setting\n");
return -EINVAL;
}
frame_size = snd_soc_params_to_frame_size(params);
if (frame_size < 0) {
- dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+ dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
return -EINVAL;
}
bclk_ms = frame_size > 32 ? 1 : 0;
@@ -1347,19 +1326,19 @@ static int rt5651_hw_params(struct snd_pcm_substream *substream,
case RT5651_AIF1:
mask_clk = RT5651_I2S_PD1_MASK;
val_clk = pre_div << RT5651_I2S_PD1_SFT;
- snd_soc_update_bits(codec, RT5651_I2S1_SDP,
+ snd_soc_component_update_bits(component, RT5651_I2S1_SDP,
RT5651_I2S_DL_MASK, val_len);
- snd_soc_update_bits(codec, RT5651_ADDA_CLK1, mask_clk, val_clk);
+ snd_soc_component_update_bits(component, RT5651_ADDA_CLK1, mask_clk, val_clk);
break;
case RT5651_AIF2:
mask_clk = RT5651_I2S_BCLK_MS2_MASK | RT5651_I2S_PD2_MASK;
val_clk = pre_div << RT5651_I2S_PD2_SFT;
- snd_soc_update_bits(codec, RT5651_I2S2_SDP,
+ snd_soc_component_update_bits(component, RT5651_I2S2_SDP,
RT5651_I2S_DL_MASK, val_len);
- snd_soc_update_bits(codec, RT5651_ADDA_CLK1, mask_clk, val_clk);
+ snd_soc_component_update_bits(component, RT5651_ADDA_CLK1, mask_clk, val_clk);
break;
default:
- dev_err(codec->dev, "Wrong dai->id: %d\n", dai->id);
+ dev_err(component->dev, "Wrong dai->id: %d\n", dai->id);
return -EINVAL;
}
@@ -1368,15 +1347,15 @@ static int rt5651_hw_params(struct snd_pcm_substream *substream,
static int rt5651_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
- struct snd_soc_codec *codec = dai->codec;
- struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = dai->component;
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
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;
@@ -1412,17 +1391,17 @@ static int rt5651_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
switch (dai->id) {
case RT5651_AIF1:
- snd_soc_update_bits(codec, RT5651_I2S1_SDP,
+ snd_soc_component_update_bits(component, RT5651_I2S1_SDP,
RT5651_I2S_MS_MASK | RT5651_I2S_BP_MASK |
RT5651_I2S_DF_MASK, reg_val);
break;
case RT5651_AIF2:
- snd_soc_update_bits(codec, RT5651_I2S2_SDP,
+ snd_soc_component_update_bits(component, RT5651_I2S2_SDP,
RT5651_I2S_MS_MASK | RT5651_I2S_BP_MASK |
RT5651_I2S_DF_MASK, reg_val);
break;
default:
- dev_err(codec->dev, "Wrong dai->id: %d\n", dai->id);
+ dev_err(component->dev, "Wrong dai->id: %d\n", dai->id);
return -EINVAL;
}
return 0;
@@ -1431,9 +1410,10 @@ static int rt5651_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
static int rt5651_set_dai_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
- struct snd_soc_codec *codec = dai->codec;
- struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = dai->component;
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
unsigned int reg_val = 0;
+ unsigned int pll_bit = 0;
if (freq == rt5651->sysclk && clk_id == rt5651->sysclk_src)
return 0;
@@ -1444,15 +1424,18 @@ static int rt5651_set_dai_sysclk(struct snd_soc_dai *dai,
break;
case RT5651_SCLK_S_PLL1:
reg_val |= RT5651_SCLK_SRC_PLL1;
+ pll_bit |= RT5651_PWR_PLL;
break;
case RT5651_SCLK_S_RCCLK:
reg_val |= RT5651_SCLK_SRC_RCCLK;
break;
default:
- dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+ dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
return -EINVAL;
}
- snd_soc_update_bits(codec, RT5651_GLB_CLK,
+ snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
+ RT5651_PWR_PLL, pll_bit);
+ snd_soc_component_update_bits(component, RT5651_GLB_CLK,
RT5651_SCLK_SRC_MASK, reg_val);
rt5651->sysclk = freq;
rt5651->sysclk_src = clk_id;
@@ -1465,8 +1448,8 @@ static int rt5651_set_dai_sysclk(struct snd_soc_dai *dai,
static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
unsigned int freq_in, unsigned int freq_out)
{
- struct snd_soc_codec *codec = dai->codec;
- struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = dai->component;
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
struct rl6231_pll_code pll_code;
int ret;
@@ -1475,48 +1458,48 @@ static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
return 0;
if (!freq_in || !freq_out) {
- dev_dbg(codec->dev, "PLL disabled\n");
+ dev_dbg(component->dev, "PLL disabled\n");
rt5651->pll_in = 0;
rt5651->pll_out = 0;
- snd_soc_update_bits(codec, RT5651_GLB_CLK,
+ snd_soc_component_update_bits(component, RT5651_GLB_CLK,
RT5651_SCLK_SRC_MASK, RT5651_SCLK_SRC_MCLK);
return 0;
}
switch (source) {
case RT5651_PLL1_S_MCLK:
- snd_soc_update_bits(codec, RT5651_GLB_CLK,
+ snd_soc_component_update_bits(component, RT5651_GLB_CLK,
RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_MCLK);
break;
case RT5651_PLL1_S_BCLK1:
- snd_soc_update_bits(codec, RT5651_GLB_CLK,
+ snd_soc_component_update_bits(component, RT5651_GLB_CLK,
RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_BCLK1);
break;
case RT5651_PLL1_S_BCLK2:
- snd_soc_update_bits(codec, RT5651_GLB_CLK,
+ snd_soc_component_update_bits(component, RT5651_GLB_CLK,
RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_BCLK2);
break;
default:
- dev_err(codec->dev, "Unknown PLL source %d\n", source);
+ dev_err(component->dev, "Unknown PLL source %d\n", source);
return -EINVAL;
}
ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
if (ret < 0) {
- dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+ dev_err(component->dev, "Unsupported input clock %d\n", freq_in);
return ret;
}
- dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+ dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
pll_code.n_code, pll_code.k_code);
- snd_soc_write(codec, RT5651_PLL_CTRL1,
+ snd_soc_component_write(component, RT5651_PLL_CTRL1,
pll_code.n_code << RT5651_PLL_N_SFT | pll_code.k_code);
- snd_soc_write(codec, 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);
+ 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));
rt5651->pll_in = freq_in;
rt5651->pll_out = freq_out;
@@ -1525,39 +1508,46 @@ static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
return 0;
}
-static int rt5651_set_bias_level(struct snd_soc_codec *codec,
+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_codec_get_bias_level(codec)) {
- snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
+ 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_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,
RT5651_PWR_VREF1 | RT5651_PWR_MB |
RT5651_PWR_BG | RT5651_PWR_VREF2);
usleep_range(10000, 15000);
- snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
+ snd_soc_component_update_bits(component, RT5651_PWR_ANLG1,
RT5651_PWR_FV1 | RT5651_PWR_FV2,
RT5651_PWR_FV1 | RT5651_PWR_FV2);
- snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
- RT5651_PWR_LDO_DVO_MASK,
- RT5651_PWR_LDO_DVO_1_2V);
- snd_soc_update_bits(codec, RT5651_D_MISC, 0x1, 0x1);
- if (snd_soc_read(codec, RT5651_PLL_MODE_1) & 0x9200)
- snd_soc_update_bits(codec, RT5651_D_MISC,
- 0xc00, 0xc00);
+ snd_soc_component_update_bits(component, RT5651_D_MISC, 0x1, 0x1);
}
break;
- case SND_SOC_BIAS_STANDBY:
- snd_soc_write(codec, RT5651_D_MISC, 0x0010);
- snd_soc_write(codec, RT5651_PWR_DIG1, 0x0000);
- snd_soc_write(codec, RT5651_PWR_DIG2, 0x0000);
- snd_soc_write(codec, RT5651_PWR_VOL, 0x0000);
- snd_soc_write(codec, RT5651_PWR_MIXER, 0x0000);
- snd_soc_write(codec, RT5651_PWR_ANLG1, 0x0000);
- snd_soc_write(codec, RT5651_PWR_ANLG2, 0x0000);
+ case SND_SOC_BIAS_OFF:
+ snd_soc_component_write(component, RT5651_D_MISC, 0x0010);
+ snd_soc_component_write(component, RT5651_PWR_DIG1, 0x0000);
+ snd_soc_component_write(component, RT5651_PWR_DIG2, 0x0000);
+ snd_soc_component_write(component, RT5651_PWR_VOL, 0x0000);
+ snd_soc_component_write(component, RT5651_PWR_MIXER, 0x0000);
+ /* Do not touch the LDO voltage select bits on bias-off */
+ snd_soc_component_update_bits(component, RT5651_PWR_ANLG1,
+ ~RT5651_PWR_LDO_DVO_MASK, 0);
+ /* Leave PLL1 and jack-detect power as is, all others off */
+ snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
+ ~(RT5651_PWR_PLL | RT5651_PWR_JD_M), 0);
break;
default:
@@ -1567,43 +1557,539 @@ static int rt5651_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static int rt5651_probe(struct snd_soc_codec *codec)
+static void rt5651_enable_micbias1_for_ovcd(struct snd_soc_component *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");
+ 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 rt5651_disable_micbias1_for_ovcd(struct snd_soc_component *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");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "micbias1");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "LDO");
+ snd_soc_dapm_sync_unlocked(dapm);
+ snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static void rt5651_enable_micbias1_ovcd_irq(struct snd_soc_component *component)
+{
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+ snd_soc_component_update_bits(component, RT5651_IRQ_CTRL2,
+ RT5651_IRQ_MB1_OC_MASK, RT5651_IRQ_MB1_OC_NOR);
+ rt5651->ovcd_irq_enabled = true;
+}
+
+static void rt5651_disable_micbias1_ovcd_irq(struct snd_soc_component *component)
+{
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+ snd_soc_component_update_bits(component, RT5651_IRQ_CTRL2,
+ RT5651_IRQ_MB1_OC_MASK, RT5651_IRQ_MB1_OC_BP);
+ rt5651->ovcd_irq_enabled = false;
+}
+
+static void rt5651_clear_micbias1_ovcd(struct snd_soc_component *component)
+{
+ snd_soc_component_update_bits(component, RT5651_IRQ_CTRL2,
+ RT5651_MB1_OC_CLR, 0);
+}
+
+static bool rt5651_micbias1_ovcd(struct snd_soc_component *component)
{
- struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+ int val;
+
+ val = snd_soc_component_read(component, RT5651_IRQ_CTRL2);
+ dev_dbg(component->dev, "irq ctrl2 %#04x\n", val);
+
+ return (val & RT5651_MB1_OC_CLR);
+}
- rt5651->codec = codec;
+static bool rt5651_jack_inserted(struct snd_soc_component *component)
+{
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+ int val;
- snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
- RT5651_PWR_VREF1 | RT5651_PWR_MB |
- RT5651_PWR_BG | RT5651_PWR_VREF2,
- RT5651_PWR_VREF1 | RT5651_PWR_MB |
- RT5651_PWR_BG | RT5651_PWR_VREF2);
- usleep_range(10000, 15000);
- snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
- RT5651_PWR_FV1 | RT5651_PWR_FV2,
- RT5651_PWR_FV1 | RT5651_PWR_FV2);
+ 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;
+ }
- snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+ val = snd_soc_component_read(component, RT5651_INT_IRQ_ST);
+ dev_dbg(component->dev, "irq status %#04x\n", val);
+
+ switch (rt5651->jd_src) {
+ case RT5651_JD1_1:
+ val &= 0x1000;
+ break;
+ case RT5651_JD1_2:
+ val &= 0x2000;
+ break;
+ case RT5651_JD2:
+ val &= 0x4000;
+ break;
+ default:
+ break;
+ }
+
+ if (rt5651->jd_active_high)
+ return val != 0;
+ else
+ return val == 0;
+}
+
+/* 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 rt5651_start_button_press_work(struct snd_soc_component *component)
+{
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+ rt5651->poll_count = 0;
+ rt5651->press_count = 0;
+ rt5651->release_count = 0;
+ rt5651->pressed = false;
+ rt5651->press_reported = false;
+ rt5651_clear_micbias1_ovcd(component);
+ schedule_delayed_work(&rt5651->bp_work, msecs_to_jiffies(BP_POLL_TIME));
+}
+
+static void rt5651_button_press_work(struct work_struct *work)
+{
+ struct rt5651_priv *rt5651 =
+ container_of(work, struct rt5651_priv, bp_work.work);
+ struct snd_soc_component *component = rt5651->component;
+
+ /* Check the jack was not removed underneath us */
+ if (!rt5651_jack_inserted(component))
+ return;
+
+ if (rt5651_micbias1_ovcd(component)) {
+ rt5651->release_count = 0;
+ rt5651->press_count++;
+ /* Remember till after JACK_UNPLUG_TIME wait */
+ if (rt5651->press_count >= BP_THRESHOLD)
+ rt5651->pressed = true;
+ rt5651_clear_micbias1_ovcd(component);
+ } else {
+ rt5651->press_count = 0;
+ rt5651->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.
+ */
+ rt5651->poll_count++;
+ if (rt5651->poll_count < (JACK_UNPLUG_TIME / BP_POLL_TIME)) {
+ schedule_delayed_work(&rt5651->bp_work,
+ msecs_to_jiffies(BP_POLL_TIME));
+ return;
+ }
+
+ if (rt5651->pressed && !rt5651->press_reported) {
+ dev_dbg(component->dev, "headset button press\n");
+ snd_soc_jack_report(rt5651->hp_jack, SND_JACK_BTN_0,
+ SND_JACK_BTN_0);
+ rt5651->press_reported = true;
+ }
+
+ if (rt5651->release_count >= BP_THRESHOLD) {
+ if (rt5651->press_reported) {
+ dev_dbg(component->dev, "headset button release\n");
+ snd_soc_jack_report(rt5651->hp_jack, 0, SND_JACK_BTN_0);
+ }
+ /* Re-enable OVCD IRQ to detect next press */
+ rt5651_enable_micbias1_ovcd_irq(component);
+ return; /* Stop polling */
+ }
+
+ schedule_delayed_work(&rt5651->bp_work, msecs_to_jiffies(BP_POLL_TIME));
+}
+
+static int rt5651_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 */
+ rt5651_clear_micbias1_ovcd(component);
+
+ msleep(JACK_SETTLE_TIME);
+
+ /* Check the jack is still connected before checking ovcd */
+ if (!rt5651_jack_inserted(component))
+ return 0;
+
+ if (rt5651_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, "mic-gnd shorted\n");
+ headset_count = 0;
+ headphone_count++;
+ if (headphone_count == JACK_DETECT_COUNT)
+ return SND_JACK_HEADPHONE;
+ } else {
+ dev_dbg(component->dev, "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 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;
+
+ if (!rt5651_jack_inserted(component)) {
+ /* Jack removed, or spurious IRQ? */
+ if (rt5651->hp_jack->status & SND_JACK_HEADPHONE) {
+ if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) {
+ cancel_delayed_work_sync(&rt5651->bp_work);
+ rt5651_disable_micbias1_ovcd_irq(component);
+ rt5651_disable_micbias1_for_ovcd(component);
+ }
+ snd_soc_jack_report(rt5651->hp_jack, 0,
+ SND_JACK_HEADSET | SND_JACK_BTN_0);
+ dev_dbg(component->dev, "jack unplugged\n");
+ }
+ } else if (!(rt5651->hp_jack->status & SND_JACK_HEADPHONE)) {
+ /* Jack inserted */
+ WARN_ON(rt5651->ovcd_irq_enabled);
+ rt5651_enable_micbias1_for_ovcd(component);
+ report = rt5651_detect_headset(component);
+ 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);
+ }
+ } else if (rt5651->ovcd_irq_enabled && rt5651_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.
+ */
+ rt5651_disable_micbias1_ovcd_irq(component);
+ rt5651_start_button_press_work(component);
+
+ /*
+ * If the jack-detect IRQ flag goes high (unplug) after our
+ * above rt5651_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, &rt5651->jack_detect_work);
+ }
+}
+
+static irqreturn_t rt5651_irq(int irq, void *data)
+{
+ struct rt5651_priv *rt5651 = data;
+
+ queue_work(system_power_efficient_wq, &rt5651->jack_detect_work);
+
+ return IRQ_HANDLED;
+}
+
+static void rt5651_cancel_work(void *data)
+{
+ struct rt5651_priv *rt5651 = data;
+
+ cancel_work_sync(&rt5651->jack_detect_work);
+ cancel_delayed_work_sync(&rt5651->bp_work);
+}
+
+static void rt5651_enable_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *hp_jack,
+ struct gpio_desc *gpiod_hp_det)
+{
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+ 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);
+ /* 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);
+ /* 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);
+ /* 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;
+ default:
+ dev_err(component->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n");
+ return;
+ }
+
+ 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,
+ 0xa800 | rt5651->ovcd_sf);
+
+ snd_soc_component_update_bits(component, RT5651_MICBIAS,
+ RT5651_MIC1_OVCD_MASK |
+ RT5651_MIC1_OVTH_MASK |
+ RT5651_PWR_CLK12M_MASK |
+ RT5651_PWR_MB_MASK,
+ RT5651_MIC1_OVCD_EN |
+ rt5651->ovcd_th |
+ RT5651_PWR_MB_PU |
+ RT5651_PWR_CLK12M_PU);
+
+ /*
+ * 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, RT5651_IRQ_CTRL2,
+ RT5651_MB1_OC_STKY_MASK, RT5651_MB1_OC_STKY_EN);
+
+ rt5651->hp_jack = hp_jack;
+ if (rt5651_support_button_press(rt5651)) {
+ rt5651_enable_micbias1_for_ovcd(component);
+ rt5651_enable_micbias1_ovcd_irq(component);
+ }
+
+ enable_irq(rt5651->irq);
+ /* sync initial jack state */
+ queue_work(system_power_efficient_wq, &rt5651->jack_detect_work);
+}
+
+static void rt5651_disable_jack_detect(struct snd_soc_component *component)
+{
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+ disable_irq(rt5651->irq);
+ rt5651_cancel_work(rt5651);
+
+ 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);
+ }
+
+ rt5651->hp_jack = NULL;
+}
+
+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, data);
+ else
+ rt5651_disable_jack_detect(component);
+
+ return 0;
+}
+
+/*
+ * Note on some platforms the platform code may need to add device-properties,
+ * rather then relying only on properties set by the firmware. Therefor the
+ * property parsing MUST be done from the component driver's probe function,
+ * rather then from the i2c driver's probe function, so that the platform-code
+ * can attach extra properties before calling snd_soc_register_card().
+ */
+static void rt5651_apply_properties(struct snd_soc_component *component)
+{
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+ u32 val;
+
+ if (device_property_read_bool(component->dev, "realtek,in2-differential"))
+ snd_soc_component_update_bits(component, RT5651_IN1_IN2,
+ RT5651_IN_DF2, RT5651_IN_DF2);
+
+ if (device_property_read_bool(component->dev, "realtek,dmic-en"))
+ snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1,
+ RT5651_GP2_PIN_MASK, RT5651_GP2_PIN_DMIC1_SCL);
+
+ if (device_property_read_u32(component->dev,
+ "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
+ * limit of 1500µA, this seems to be more reliable then 1500µA and 1.0.
+ */
+ rt5651->ovcd_th = RT5651_MIC1_OVTH_2000UA;
+ rt5651->ovcd_sf = RT5651_MIC_OVCD_SF_0P75;
+
+ if (device_property_read_u32(component->dev,
+ "realtek,over-current-threshold-microamp", &val) == 0) {
+ switch (val) {
+ case 600:
+ rt5651->ovcd_th = RT5651_MIC1_OVTH_600UA;
+ break;
+ case 1500:
+ rt5651->ovcd_th = RT5651_MIC1_OVTH_1500UA;
+ break;
+ case 2000:
+ rt5651->ovcd_th = RT5651_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 <= RT5651_OVCD_SF_1P5)
+ rt5651->ovcd_sf = val << RT5651_MIC_OVCD_SF_SFT;
+ else
+ dev_warn(component->dev, "Warning: Invalid over-current-scale-factor value: %d, defaulting to 0.75\n",
+ val);
+ }
+}
+
+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_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
+
+ rt5651_apply_properties(component);
return 0;
}
#ifdef CONFIG_PM
-static int rt5651_suspend(struct snd_soc_codec *codec)
+static int rt5651_suspend(struct snd_soc_component *component)
{
- struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
regcache_cache_only(rt5651->regmap, true);
regcache_mark_dirty(rt5651->regmap);
return 0;
}
-static int rt5651_resume(struct snd_soc_codec *codec)
+static int rt5651_resume(struct snd_soc_component *component)
{
- struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
regcache_cache_only(rt5651->regmap, false);
- snd_soc_cache_sync(codec);
+ snd_soc_component_cache_sync(component);
return 0;
}
@@ -1664,20 +2150,20 @@ static struct snd_soc_dai_driver rt5651_dai[] = {
},
};
-static struct snd_soc_codec_driver soc_codec_dev_rt5651 = {
- .probe = rt5651_probe,
- .suspend = rt5651_suspend,
- .resume = rt5651_resume,
- .set_bias_level = rt5651_set_bias_level,
- .idle_bias_off = true,
- .component_driver = {
- .controls = rt5651_snd_controls,
- .num_controls = ARRAY_SIZE(rt5651_snd_controls),
- .dapm_widgets = rt5651_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(rt5651_dapm_widgets),
- .dapm_routes = rt5651_dapm_routes,
- .num_dapm_routes = ARRAY_SIZE(rt5651_dapm_routes),
- },
+static const struct snd_soc_component_driver soc_component_dev_rt5651 = {
+ .probe = rt5651_probe,
+ .suspend = rt5651_suspend,
+ .resume = rt5651_resume,
+ .set_bias_level = rt5651_set_bias_level,
+ .set_jack = rt5651_set_jack,
+ .controls = rt5651_snd_controls,
+ .num_controls = ARRAY_SIZE(rt5651_snd_controls),
+ .dapm_widgets = rt5651_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt5651_dapm_widgets),
+ .dapm_routes = rt5651_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt5651_dapm_routes),
+ .use_pmdown_time = 1,
+ .endianness = 1,
};
static const struct regmap_config rt5651_regmap = {
@@ -1689,51 +2175,47 @@ 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,
.num_ranges = ARRAY_SIZE(rt5651_ranges),
+ .use_single_read = true,
+ .use_single_write = true,
};
#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);
-static int rt5651_parse_dt(struct rt5651_priv *rt5651, struct device_node *np)
-{
- rt5651->pdata.in2_diff = of_property_read_bool(np,
- "realtek,in2-differential");
- rt5651->pdata.dmic_en = of_property_read_bool(np,
- "realtek,dmic-en");
-
- return 0;
-}
-
-static int rt5651_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *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)
{
- struct rt5651_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct rt5651_priv *rt5651;
int ret;
+ int err;
rt5651 = devm_kzalloc(&i2c->dev, sizeof(*rt5651),
GFP_KERNEL);
@@ -1742,11 +2224,6 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, rt5651);
- if (pdata)
- rt5651->pdata = *pdata;
- else if (i2c->dev.of_node)
- rt5651_parse_dt(rt5651, i2c->dev.of_node);
-
rt5651->regmap = devm_regmap_init_i2c(i2c, &rt5651_regmap);
if (IS_ERR(rt5651->regmap)) {
ret = PTR_ERR(rt5651->regmap);
@@ -1755,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);
@@ -1769,29 +2249,33 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
if (ret != 0)
dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
- if (rt5651->pdata.in2_diff)
- regmap_update_bits(rt5651->regmap, RT5651_IN1_IN2,
- RT5651_IN_DF2, RT5651_IN_DF2);
+ rt5651->irq = i2c->irq;
+ rt5651->hp_mute = true;
- if (rt5651->pdata.dmic_en)
- regmap_update_bits(rt5651->regmap, RT5651_GPIO_CTRL1,
- RT5651_GP2_PIN_MASK, RT5651_GP2_PIN_DMIC1_SCL);
+ INIT_DELAYED_WORK(&rt5651->bp_work, rt5651_button_press_work);
+ INIT_WORK(&rt5651->jack_detect_work, rt5651_jack_detect_work);
- rt5651->hp_mute = 1;
+ /* Make sure work is stopped on probe-error / remove */
+ ret = devm_add_action_or_reset(&i2c->dev, rt5651_cancel_work, rt5651);
+ if (ret)
+ return ret;
- ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5651,
+ ret = devm_request_irq(&i2c->dev, rt5651->irq, rt5651_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+ | 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;
+ }
+
+ ret = devm_snd_soc_register_component(&i2c->dev,
+ &soc_component_dev_rt5651,
rt5651_dai, ARRAY_SIZE(rt5651_dai));
return ret;
}
-static int rt5651_i2c_remove(struct i2c_client *i2c)
-{
- snd_soc_unregister_codec(&i2c->dev);
-
- return 0;
-}
-
static struct i2c_driver rt5651_i2c_driver = {
.driver = {
.name = "rt5651",
@@ -1799,7 +2283,6 @@ static struct i2c_driver rt5651_i2c_driver = {
.of_match_table = of_match_ptr(rt5651_of_match),
},
.probe = rt5651_i2c_probe,
- .remove = rt5651_i2c_remove,
.id_table = rt5651_i2c_id,
};
module_i2c_driver(rt5651_i2c_driver);