mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-17 01:04:19 +08:00
Merge remote-tracking branches 'asoc/topic/rt5645', 'asoc/topic/rt5651', 'asoc/topic/rt5659', 'asoc/topic/rt5663' and 'asoc/topic/rt5670' into asoc-next
This commit is contained in:
commit
84400d7ff8
@ -19,6 +19,22 @@ Optional properties:
|
||||
Based on the different PCB layout, add the manual offset value to
|
||||
compensate the DC offset for each L and R channel, and they are different
|
||||
between headphone and headset.
|
||||
- "realtek,impedance_sensing_num"
|
||||
The matrix row number of the impedance sensing table.
|
||||
If the value is 0, it means the impedance sensing is not supported.
|
||||
- "realtek,impedance_sensing_table"
|
||||
The matrix rows of the impedance sensing table are consisted by impedance
|
||||
minimum, impedance maximun, volume, DC offset w/o and w/ mic of each L and
|
||||
R channel accordingly. Example is shown as following.
|
||||
< 0 300 7 0xffd160 0xffd1c0 0xff8a10 0xff8ab0
|
||||
301 65535 4 0xffe470 0xffe470 0xffb8e0 0xffb8e0>
|
||||
The first and second column are defined for the impedance range. If the
|
||||
detected impedance value is in the range, then the volume value of the
|
||||
third column will be set to codec. In our codec design, each volume value
|
||||
should compensate different DC offset to avoid the pop sound, and it is
|
||||
also different between headphone and headset. In the example, the
|
||||
"realtek,impedance_sensing_num" is 2. It means that there are 2 ranges of
|
||||
impedance in the impedance sensing function.
|
||||
|
||||
Pins on the device (for linking into audio routes) for RT5663:
|
||||
|
||||
|
@ -11,11 +11,19 @@
|
||||
#ifndef __LINUX_SND_RT5651_H
|
||||
#define __LINUX_SND_RT5651_H
|
||||
|
||||
enum rt5651_jd_src {
|
||||
RT5651_JD_NULL,
|
||||
RT5651_JD1_1,
|
||||
RT5651_JD1_2,
|
||||
RT5651_JD2,
|
||||
};
|
||||
|
||||
struct rt5651_platform_data {
|
||||
/* IN2 can optionally be differential */
|
||||
bool in2_diff;
|
||||
|
||||
bool dmic_en;
|
||||
enum rt5651_jd_src jd_src;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -16,6 +16,9 @@ struct rt5663_platform_data {
|
||||
unsigned int dc_offset_r_manual;
|
||||
unsigned int dc_offset_l_manual_mic;
|
||||
unsigned int dc_offset_r_manual_mic;
|
||||
|
||||
unsigned int impedance_sensing_num;
|
||||
unsigned int *impedance_sensing_table;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -55,6 +55,8 @@ MODULE_PARM_DESC(quirk, "RT5645 pdata quirk override");
|
||||
|
||||
#define RT5645_HWEQ_NUM 57
|
||||
|
||||
#define TIME_TO_POWER_MS 400
|
||||
|
||||
static const struct regmap_range_cfg rt5645_ranges[] = {
|
||||
{
|
||||
.name = "PR",
|
||||
@ -432,6 +434,7 @@ struct rt5645_priv {
|
||||
int jack_type;
|
||||
bool en_button_func;
|
||||
bool hp_on;
|
||||
int v_id;
|
||||
};
|
||||
|
||||
static int rt5645_reset(struct snd_soc_codec *codec)
|
||||
@ -2516,9 +2519,7 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
|
||||
{ "SPKVOL L", "Switch", "SPK MIXL" },
|
||||
{ "SPKVOL R", "Switch", "SPK MIXR" },
|
||||
|
||||
{ "SPOL MIX", "DAC R1 Switch", "DAC R1" },
|
||||
{ "SPOL MIX", "DAC L1 Switch", "DAC L1" },
|
||||
{ "SPOL MIX", "SPKVOL R Switch", "SPKVOL R" },
|
||||
{ "SPOL MIX", "SPKVOL L Switch", "SPKVOL L" },
|
||||
{ "SPOR MIX", "DAC R1 Switch", "DAC R1" },
|
||||
{ "SPOR MIX", "SPKVOL R Switch", "SPKVOL R" },
|
||||
@ -2707,6 +2708,11 @@ static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = {
|
||||
{ "DAC R2 Mux", "IF1 DAC", "RT5645 IF1 DAC2 R Mux" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route rt5645_old_dapm_routes[] = {
|
||||
{ "SPOL MIX", "DAC R1 Switch", "DAC R1" },
|
||||
{ "SPOL MIX", "SPKVOL R Switch", "SPKVOL R" },
|
||||
};
|
||||
|
||||
static int rt5645_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
@ -3363,6 +3369,11 @@ static int rt5645_probe(struct snd_soc_codec *codec)
|
||||
snd_soc_dapm_add_routes(dapm,
|
||||
rt5645_specific_dapm_routes,
|
||||
ARRAY_SIZE(rt5645_specific_dapm_routes));
|
||||
if (rt5645->v_id < 3) {
|
||||
snd_soc_dapm_add_routes(dapm,
|
||||
rt5645_old_dapm_routes,
|
||||
ARRAY_SIZE(rt5645_old_dapm_routes));
|
||||
}
|
||||
break;
|
||||
case CODEC_TYPE_RT5650:
|
||||
snd_soc_dapm_new_controls(dapm,
|
||||
@ -3637,14 +3648,14 @@ static const struct dmi_system_id dmi_platform_gpd_win[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static struct rt5645_platform_data general_platform_data2 = {
|
||||
static const struct rt5645_platform_data general_platform_data2 = {
|
||||
.dmic1_data_pin = RT5645_DMIC_DATA_IN2N,
|
||||
.dmic2_data_pin = RT5645_DMIC2_DISABLE,
|
||||
.jd_mode = 3,
|
||||
.inv_jd1_1 = true,
|
||||
};
|
||||
|
||||
static struct dmi_system_id dmi_platform_asus_t100ha[] = {
|
||||
static const struct dmi_system_id dmi_platform_asus_t100ha[] = {
|
||||
{
|
||||
.ident = "ASUS T100HAN",
|
||||
.matches = {
|
||||
@ -3655,11 +3666,11 @@ static struct dmi_system_id dmi_platform_asus_t100ha[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct rt5645_platform_data minix_z83_4_platform_data = {
|
||||
static const struct rt5645_platform_data minix_z83_4_platform_data = {
|
||||
.jd_mode = 3,
|
||||
};
|
||||
|
||||
static struct dmi_system_id dmi_platform_minix_z83_4[] = {
|
||||
static const struct dmi_system_id dmi_platform_minix_z83_4[] = {
|
||||
{
|
||||
.ident = "MINIX Z83-4",
|
||||
.matches = {
|
||||
@ -3775,6 +3786,12 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read after 400msec, as it is the interval required between
|
||||
* read and power On.
|
||||
*/
|
||||
msleep(TIME_TO_POWER_MS);
|
||||
regmap_read(regmap, RT5645_VENDOR_ID2, &val);
|
||||
|
||||
switch (val) {
|
||||
@ -3803,6 +3820,9 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
|
||||
|
||||
regmap_write(rt5645->regmap, RT5645_RESET, 0);
|
||||
|
||||
regmap_read(regmap, RT5645_VENDOR_ID, &val);
|
||||
rt5645->v_id = val & 0xff;
|
||||
|
||||
ret = regmap_register_patch(rt5645->regmap, init_list,
|
||||
ARRAY_SIZE(init_list));
|
||||
if (ret != 0)
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
@ -26,10 +27,15 @@
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/jack.h>
|
||||
|
||||
#include "rl6231.h"
|
||||
#include "rt5651.h"
|
||||
|
||||
#define RT5651_JD_MAP(quirk) ((quirk) & GENMASK(7, 0))
|
||||
#define RT5651_IN2_DIFF BIT(16)
|
||||
#define RT5651_DMIC_EN BIT(17)
|
||||
|
||||
#define RT5651_DEVICE_ID_VALUE 0x6281
|
||||
|
||||
#define RT5651_PR_RANGE_BASE (0xff + 1)
|
||||
@ -37,6 +43,8 @@
|
||||
|
||||
#define RT5651_PR_BASE (RT5651_PR_RANGE_BASE + (0 * RT5651_PR_SPACING))
|
||||
|
||||
static unsigned long rt5651_quirk;
|
||||
|
||||
static const struct regmap_range_cfg rt5651_ranges[] = {
|
||||
{ .name = "PR", .range_min = RT5651_PR_BASE,
|
||||
.range_max = RT5651_PR_BASE + 0xb4,
|
||||
@ -880,11 +888,14 @@ static const struct snd_soc_dapm_widget rt5651_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY("PLL1", RT5651_PWR_ANLG2,
|
||||
RT5651_PWR_PLL_BIT, 0, NULL, 0),
|
||||
/* Input Side */
|
||||
SND_SOC_DAPM_SUPPLY("JD Power", RT5651_PWR_ANLG2,
|
||||
RT5651_PWM_JD_M_BIT, 0, NULL, 0),
|
||||
|
||||
/* 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"),
|
||||
@ -1528,6 +1539,8 @@ 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_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) {
|
||||
@ -1556,8 +1569,13 @@ static int rt5651_set_bias_level(struct snd_soc_codec *codec,
|
||||
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);
|
||||
if (rt5651->pdata.jd_src) {
|
||||
snd_soc_write(codec, RT5651_PWR_ANLG2, 0x0204);
|
||||
snd_soc_write(codec, RT5651_PWR_ANLG1, 0x0002);
|
||||
} else {
|
||||
snd_soc_write(codec, RT5651_PWR_ANLG1, 0x0000);
|
||||
snd_soc_write(codec, RT5651_PWR_ANLG2, 0x0000);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1570,6 +1588,7 @@ static int rt5651_set_bias_level(struct snd_soc_codec *codec,
|
||||
static int rt5651_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
|
||||
|
||||
rt5651->codec = codec;
|
||||
|
||||
@ -1585,6 +1604,15 @@ static int rt5651_probe(struct snd_soc_codec *codec)
|
||||
|
||||
snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
if (rt5651->pdata.jd_src) {
|
||||
snd_soc_dapm_force_enable_pin(dapm, "JD Power");
|
||||
snd_soc_dapm_force_enable_pin(dapm, "LDO");
|
||||
snd_soc_dapm_sync(dapm);
|
||||
|
||||
regmap_update_bits(rt5651->regmap, RT5651_MICBIAS,
|
||||
0x38, 0x38);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1718,16 +1746,131 @@ static const struct i2c_device_id rt5651_i2c_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id);
|
||||
|
||||
static int rt5651_quirk_cb(const struct dmi_system_id *id)
|
||||
{
|
||||
rt5651_quirk = (unsigned long) id->driver_data;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id rt5651_quirk_table[] = {
|
||||
{
|
||||
.callback = rt5651_quirk_cb,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "KIANO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "KIANO SlimNote 14.2"),
|
||||
},
|
||||
.driver_data = (unsigned long *) RT5651_JD1_1,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
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");
|
||||
if (of_property_read_bool(np, "realtek,in2-differential"))
|
||||
rt5651_quirk |= RT5651_IN2_DIFF;
|
||||
if (of_property_read_bool(np, "realtek,dmic-en"))
|
||||
rt5651_quirk |= RT5651_DMIC_EN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rt5651_set_pdata(struct rt5651_priv *rt5651)
|
||||
{
|
||||
if (rt5651_quirk & RT5651_IN2_DIFF)
|
||||
rt5651->pdata.in2_diff = true;
|
||||
if (rt5651_quirk & RT5651_DMIC_EN)
|
||||
rt5651->pdata.dmic_en = true;
|
||||
if (RT5651_JD_MAP(rt5651_quirk))
|
||||
rt5651->pdata.jd_src = RT5651_JD_MAP(rt5651_quirk);
|
||||
}
|
||||
|
||||
static irqreturn_t rt5651_irq(int irq, void *data)
|
||||
{
|
||||
struct rt5651_priv *rt5651 = data;
|
||||
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
&rt5651->jack_detect_work, msecs_to_jiffies(250));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int rt5651_jack_detect(struct snd_soc_codec *codec, int jack_insert)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
|
||||
int jack_type;
|
||||
|
||||
if (jack_insert) {
|
||||
snd_soc_dapm_force_enable_pin(dapm, "LDO");
|
||||
snd_soc_dapm_sync(dapm);
|
||||
|
||||
snd_soc_update_bits(codec, RT5651_MICBIAS,
|
||||
RT5651_MIC1_OVCD_MASK |
|
||||
RT5651_MIC1_OVTH_MASK |
|
||||
RT5651_PWR_CLK12M_MASK |
|
||||
RT5651_PWR_MB_MASK,
|
||||
RT5651_MIC1_OVCD_EN |
|
||||
RT5651_MIC1_OVTH_600UA |
|
||||
RT5651_PWR_MB_PU |
|
||||
RT5651_PWR_CLK12M_PU);
|
||||
msleep(100);
|
||||
if (snd_soc_read(codec, RT5651_IRQ_CTRL2) & RT5651_MB1_OC_CLR)
|
||||
jack_type = SND_JACK_HEADPHONE;
|
||||
else
|
||||
jack_type = SND_JACK_HEADSET;
|
||||
snd_soc_update_bits(codec, RT5651_IRQ_CTRL2,
|
||||
RT5651_MB1_OC_CLR, 0);
|
||||
} else { /* jack out */
|
||||
jack_type = 0;
|
||||
|
||||
snd_soc_update_bits(codec, RT5651_MICBIAS,
|
||||
RT5651_MIC1_OVCD_MASK,
|
||||
RT5651_MIC1_OVCD_DIS);
|
||||
}
|
||||
|
||||
return jack_type;
|
||||
}
|
||||
|
||||
static void rt5651_jack_detect_work(struct work_struct *work)
|
||||
{
|
||||
struct rt5651_priv *rt5651 =
|
||||
container_of(work, struct rt5651_priv, jack_detect_work.work);
|
||||
|
||||
int report, val = 0;
|
||||
|
||||
if (!rt5651->codec)
|
||||
return;
|
||||
|
||||
switch (rt5651->pdata.jd_src) {
|
||||
case RT5651_JD1_1:
|
||||
val = snd_soc_read(rt5651->codec, RT5651_INT_IRQ_ST) & 0x1000;
|
||||
break;
|
||||
case RT5651_JD1_2:
|
||||
val = snd_soc_read(rt5651->codec, RT5651_INT_IRQ_ST) & 0x2000;
|
||||
break;
|
||||
case RT5651_JD2:
|
||||
val = snd_soc_read(rt5651->codec, RT5651_INT_IRQ_ST) & 0x4000;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
report = rt5651_jack_detect(rt5651->codec, !val);
|
||||
|
||||
snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET);
|
||||
}
|
||||
|
||||
int rt5651_set_jack_detect(struct snd_soc_codec *codec,
|
||||
struct snd_soc_jack *hp_jack)
|
||||
{
|
||||
struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
rt5651->hp_jack = hp_jack;
|
||||
rt5651_irq(0, rt5651);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt5651_set_jack_detect);
|
||||
|
||||
static int rt5651_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@ -1746,6 +1889,10 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
|
||||
rt5651->pdata = *pdata;
|
||||
else if (i2c->dev.of_node)
|
||||
rt5651_parse_dt(rt5651, i2c->dev.of_node);
|
||||
else
|
||||
dmi_check_system(rt5651_quirk_table);
|
||||
|
||||
rt5651_set_pdata(rt5651);
|
||||
|
||||
rt5651->regmap = devm_regmap_init_i2c(i2c, &rt5651_regmap);
|
||||
if (IS_ERR(rt5651->regmap)) {
|
||||
@ -1779,6 +1926,59 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
|
||||
|
||||
rt5651->hp_mute = 1;
|
||||
|
||||
if (rt5651->pdata.jd_src) {
|
||||
|
||||
/* IRQ output on GPIO1 */
|
||||
regmap_update_bits(rt5651->regmap, RT5651_GPIO_CTRL1,
|
||||
RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ);
|
||||
|
||||
switch (rt5651->pdata.jd_src) {
|
||||
case RT5651_JD1_1:
|
||||
regmap_update_bits(rt5651->regmap, RT5651_JD_CTRL2,
|
||||
RT5651_JD_TRG_SEL_MASK,
|
||||
RT5651_JD_TRG_SEL_JD1_1);
|
||||
regmap_update_bits(rt5651->regmap, RT5651_IRQ_CTRL1,
|
||||
RT5651_JD1_1_IRQ_EN,
|
||||
RT5651_JD1_1_IRQ_EN);
|
||||
break;
|
||||
case RT5651_JD1_2:
|
||||
regmap_update_bits(rt5651->regmap, RT5651_JD_CTRL2,
|
||||
RT5651_JD_TRG_SEL_MASK,
|
||||
RT5651_JD_TRG_SEL_JD1_2);
|
||||
regmap_update_bits(rt5651->regmap, RT5651_IRQ_CTRL1,
|
||||
RT5651_JD1_2_IRQ_EN,
|
||||
RT5651_JD1_2_IRQ_EN);
|
||||
break;
|
||||
case RT5651_JD2:
|
||||
regmap_update_bits(rt5651->regmap, RT5651_JD_CTRL2,
|
||||
RT5651_JD_TRG_SEL_MASK,
|
||||
RT5651_JD_TRG_SEL_JD2);
|
||||
regmap_update_bits(rt5651->regmap, RT5651_IRQ_CTRL1,
|
||||
RT5651_JD2_IRQ_EN,
|
||||
RT5651_JD2_IRQ_EN);
|
||||
break;
|
||||
case RT5651_JD_NULL:
|
||||
break;
|
||||
default:
|
||||
dev_warn(&i2c->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&rt5651->jack_detect_work, rt5651_jack_detect_work);
|
||||
|
||||
if (i2c->irq) {
|
||||
ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
|
||||
rt5651_irq,
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_TRIGGER_FALLING |
|
||||
IRQF_ONESHOT, "rt5651", rt5651);
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5651,
|
||||
rt5651_dai, ARRAY_SIZE(rt5651_dai));
|
||||
|
||||
@ -1787,6 +1987,9 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
|
||||
|
||||
static int rt5651_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct rt5651_priv *rt5651 = i2c_get_clientdata(i2c);
|
||||
|
||||
cancel_delayed_work_sync(&rt5651->jack_detect_work);
|
||||
snd_soc_unregister_codec(&i2c->dev);
|
||||
|
||||
return 0;
|
||||
|
@ -2062,6 +2062,8 @@ struct rt5651_priv {
|
||||
struct snd_soc_codec *codec;
|
||||
struct rt5651_platform_data pdata;
|
||||
struct regmap *regmap;
|
||||
struct snd_soc_jack *hp_jack;
|
||||
struct delayed_work jack_detect_work;
|
||||
|
||||
int sysclk;
|
||||
int sysclk_src;
|
||||
@ -2077,4 +2079,6 @@ struct rt5651_priv {
|
||||
bool hp_mute;
|
||||
};
|
||||
|
||||
int rt5651_set_jack_detect(struct snd_soc_codec *codec,
|
||||
struct snd_soc_jack *hp_jack);
|
||||
#endif /* __RT5651_H__ */
|
||||
|
@ -3385,10 +3385,9 @@ static int rt5659_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt5659_set_dai_sysclk(struct snd_soc_dai *dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
static int rt5659_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id,
|
||||
int source, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int reg_val = 0;
|
||||
|
||||
@ -3414,20 +3413,21 @@ static int rt5659_set_dai_sysclk(struct snd_soc_dai *dai,
|
||||
rt5659->sysclk = freq;
|
||||
rt5659->sysclk_src = clk_id;
|
||||
|
||||
dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
|
||||
dev_dbg(codec->dev, "Sysclk is %dHz and clock id is %d\n",
|
||||
freq, clk_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt5659_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source,
|
||||
unsigned int freq_in, unsigned int freq_out)
|
||||
static int rt5659_set_codec_pll(struct snd_soc_codec *codec, int pll_id,
|
||||
int source, unsigned int freq_in,
|
||||
unsigned int freq_out)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
|
||||
struct rl6231_pll_code pll_code;
|
||||
int ret;
|
||||
|
||||
if (Source == rt5659->pll_src && freq_in == rt5659->pll_in &&
|
||||
if (source == rt5659->pll_src && freq_in == rt5659->pll_in &&
|
||||
freq_out == rt5659->pll_out)
|
||||
return 0;
|
||||
|
||||
@ -3441,7 +3441,7 @@ static int rt5659_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source,
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (Source) {
|
||||
switch (source) {
|
||||
case RT5659_PLL1_S_MCLK:
|
||||
snd_soc_update_bits(codec, RT5659_GLB_CLK,
|
||||
RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_MCLK);
|
||||
@ -3459,7 +3459,7 @@ static int rt5659_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source,
|
||||
RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK3);
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "Unknown PLL Source %d\n", Source);
|
||||
dev_err(codec->dev, "Unknown PLL source %d\n", source);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -3481,7 +3481,7 @@ static int rt5659_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source,
|
||||
|
||||
rt5659->pll_in = freq_in;
|
||||
rt5659->pll_out = freq_out;
|
||||
rt5659->pll_src = Source;
|
||||
rt5659->pll_src = source;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3666,9 +3666,7 @@ static int rt5659_resume(struct snd_soc_codec *codec)
|
||||
static const struct snd_soc_dai_ops rt5659_aif_dai_ops = {
|
||||
.hw_params = rt5659_hw_params,
|
||||
.set_fmt = rt5659_set_dai_fmt,
|
||||
.set_sysclk = rt5659_set_dai_sysclk,
|
||||
.set_tdm_slot = rt5659_set_tdm_slot,
|
||||
.set_pll = rt5659_set_dai_pll,
|
||||
.set_bclk_ratio = rt5659_set_bclk_ratio,
|
||||
};
|
||||
|
||||
@ -3747,6 +3745,8 @@ static const struct snd_soc_codec_driver soc_codec_dev_rt5659 = {
|
||||
.dapm_routes = rt5659_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(rt5659_dapm_routes),
|
||||
},
|
||||
.set_sysclk = rt5659_set_codec_sysclk,
|
||||
.set_pll = rt5659_set_codec_pll,
|
||||
};
|
||||
|
||||
|
||||
|
@ -38,13 +38,24 @@ enum {
|
||||
CODEC_VER_0,
|
||||
};
|
||||
|
||||
struct impedance_mapping_table {
|
||||
unsigned int imp_min;
|
||||
unsigned int imp_max;
|
||||
unsigned int vol;
|
||||
unsigned int dc_offset_l_manual;
|
||||
unsigned int dc_offset_r_manual;
|
||||
unsigned int dc_offset_l_manual_mic;
|
||||
unsigned int dc_offset_r_manual_mic;
|
||||
};
|
||||
|
||||
struct rt5663_priv {
|
||||
struct snd_soc_codec *codec;
|
||||
struct rt5663_platform_data pdata;
|
||||
struct regmap *regmap;
|
||||
struct delayed_work jack_detect_work;
|
||||
struct delayed_work jack_detect_work, jd_unplug_work;
|
||||
struct snd_soc_jack *hs_jack;
|
||||
struct timer_list btn_check_timer;
|
||||
struct impedance_mapping_table *imp_table;
|
||||
|
||||
int codec_ver;
|
||||
int sysclk;
|
||||
@ -1575,6 +1586,9 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
|
||||
rt5663->jack_type = SND_JACK_HEADSET;
|
||||
rt5663_enable_push_button_irq(codec, true);
|
||||
|
||||
if (rt5663->pdata.impedance_sensing_num)
|
||||
break;
|
||||
|
||||
if (rt5663->pdata.dc_offset_l_manual_mic) {
|
||||
regmap_write(rt5663->regmap, RT5663_MIC_DECRO_2,
|
||||
rt5663->pdata.dc_offset_l_manual_mic >>
|
||||
@ -1596,6 +1610,9 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
|
||||
default:
|
||||
rt5663->jack_type = SND_JACK_HEADPHONE;
|
||||
|
||||
if (rt5663->pdata.impedance_sensing_num)
|
||||
break;
|
||||
|
||||
if (rt5663->pdata.dc_offset_l_manual) {
|
||||
regmap_write(rt5663->regmap, RT5663_MIC_DECRO_2,
|
||||
rt5663->pdata.dc_offset_l_manual >> 16);
|
||||
@ -1623,6 +1640,177 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
|
||||
return rt5663->jack_type;
|
||||
}
|
||||
|
||||
static int rt5663_impedance_sensing(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int value, i, reg84, reg26, reg2fa, reg91, reg10, reg80;
|
||||
|
||||
for (i = 0; i < rt5663->pdata.impedance_sensing_num; i++) {
|
||||
if (rt5663->imp_table[i].vol == 7)
|
||||
break;
|
||||
}
|
||||
|
||||
if (rt5663->jack_type == SND_JACK_HEADSET) {
|
||||
snd_soc_write(codec, RT5663_MIC_DECRO_2,
|
||||
rt5663->imp_table[i].dc_offset_l_manual_mic >> 16);
|
||||
snd_soc_write(codec, RT5663_MIC_DECRO_3,
|
||||
rt5663->imp_table[i].dc_offset_l_manual_mic & 0xffff);
|
||||
snd_soc_write(codec, RT5663_MIC_DECRO_5,
|
||||
rt5663->imp_table[i].dc_offset_r_manual_mic >> 16);
|
||||
snd_soc_write(codec, RT5663_MIC_DECRO_6,
|
||||
rt5663->imp_table[i].dc_offset_r_manual_mic & 0xffff);
|
||||
} else {
|
||||
snd_soc_write(codec, RT5663_MIC_DECRO_2,
|
||||
rt5663->imp_table[i].dc_offset_l_manual >> 16);
|
||||
snd_soc_write(codec, RT5663_MIC_DECRO_3,
|
||||
rt5663->imp_table[i].dc_offset_l_manual & 0xffff);
|
||||
snd_soc_write(codec, RT5663_MIC_DECRO_5,
|
||||
rt5663->imp_table[i].dc_offset_r_manual >> 16);
|
||||
snd_soc_write(codec, RT5663_MIC_DECRO_6,
|
||||
rt5663->imp_table[i].dc_offset_r_manual & 0xffff);
|
||||
}
|
||||
|
||||
reg84 = snd_soc_read(codec, RT5663_ASRC_2);
|
||||
reg26 = snd_soc_read(codec, RT5663_STO1_ADC_MIXER);
|
||||
reg2fa = snd_soc_read(codec, RT5663_DUMMY_1);
|
||||
reg91 = snd_soc_read(codec, RT5663_HP_CHARGE_PUMP_1);
|
||||
reg10 = snd_soc_read(codec, RT5663_RECMIX);
|
||||
reg80 = snd_soc_read(codec, RT5663_GLB_CLK);
|
||||
|
||||
snd_soc_update_bits(codec, RT5663_STO_DRE_1, 0x8000, 0);
|
||||
snd_soc_write(codec, RT5663_ASRC_2, 0);
|
||||
snd_soc_write(codec, RT5663_STO1_ADC_MIXER, 0x4040);
|
||||
snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
|
||||
RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK |
|
||||
RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
|
||||
RT5663_PWR_VREF1 | RT5663_PWR_VREF2);
|
||||
usleep_range(10000, 10005);
|
||||
snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
|
||||
RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
|
||||
RT5663_PWR_FV1 | RT5663_PWR_FV2);
|
||||
snd_soc_update_bits(codec, RT5663_GLB_CLK, RT5663_SCLK_SRC_MASK,
|
||||
RT5663_SCLK_SRC_RCCLK);
|
||||
snd_soc_update_bits(codec, RT5663_RC_CLK, RT5663_DIG_25M_CLK_MASK,
|
||||
RT5663_DIG_25M_CLK_EN);
|
||||
snd_soc_update_bits(codec, RT5663_ADDA_CLK_1, RT5663_I2S_PD1_MASK, 0);
|
||||
snd_soc_write(codec, RT5663_PRE_DIV_GATING_1, 0xff00);
|
||||
snd_soc_write(codec, RT5663_PRE_DIV_GATING_2, 0xfffc);
|
||||
snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_1, 0x1232);
|
||||
snd_soc_write(codec, RT5663_HP_LOGIC_2, 0x0005);
|
||||
snd_soc_write(codec, RT5663_DEPOP_2, 0x3003);
|
||||
snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0x0030);
|
||||
snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0003, 0x0003);
|
||||
snd_soc_update_bits(codec, RT5663_PWR_DIG_2,
|
||||
RT5663_PWR_ADC_S1F | RT5663_PWR_DAC_S1F,
|
||||
RT5663_PWR_ADC_S1F | RT5663_PWR_DAC_S1F);
|
||||
snd_soc_update_bits(codec, RT5663_PWR_DIG_1,
|
||||
RT5663_PWR_DAC_L1 | RT5663_PWR_DAC_R1 |
|
||||
RT5663_PWR_LDO_DACREF_MASK | RT5663_PWR_ADC_L1 |
|
||||
RT5663_PWR_ADC_R1,
|
||||
RT5663_PWR_DAC_L1 | RT5663_PWR_DAC_R1 |
|
||||
RT5663_PWR_LDO_DACREF_ON | RT5663_PWR_ADC_L1 |
|
||||
RT5663_PWR_ADC_R1);
|
||||
msleep(40);
|
||||
snd_soc_update_bits(codec, RT5663_PWR_ANLG_2,
|
||||
RT5663_PWR_RECMIX1 | RT5663_PWR_RECMIX2,
|
||||
RT5663_PWR_RECMIX1 | RT5663_PWR_RECMIX2);
|
||||
msleep(30);
|
||||
snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_2, 0x1371);
|
||||
snd_soc_write(codec, RT5663_STO_DAC_MIXER, 0);
|
||||
snd_soc_write(codec, RT5663_BYPASS_STO_DAC, 0x000c);
|
||||
snd_soc_write(codec, RT5663_HP_BIAS, 0xafaa);
|
||||
snd_soc_write(codec, RT5663_CHARGE_PUMP_1, 0x2224);
|
||||
snd_soc_write(codec, RT5663_HP_OUT_EN, 0x8088);
|
||||
snd_soc_write(codec, RT5663_CHOP_ADC, 0x3000);
|
||||
snd_soc_write(codec, RT5663_ADDA_RST, 0xc000);
|
||||
snd_soc_write(codec, RT5663_STO1_HPF_ADJ1, 0x3320);
|
||||
snd_soc_write(codec, RT5663_HP_CALIB_2, 0x00c9);
|
||||
snd_soc_write(codec, RT5663_DUMMY_1, 0x004c);
|
||||
snd_soc_write(codec, RT5663_ANA_BIAS_CUR_1, 0x7733);
|
||||
snd_soc_write(codec, RT5663_CHARGE_PUMP_2, 0x7777);
|
||||
snd_soc_write(codec, RT5663_STO_DRE_9, 0x0007);
|
||||
snd_soc_write(codec, RT5663_STO_DRE_10, 0x0007);
|
||||
snd_soc_write(codec, RT5663_DUMMY_2, 0x02a4);
|
||||
snd_soc_write(codec, RT5663_RECMIX, 0x0005);
|
||||
snd_soc_write(codec, RT5663_HP_IMP_SEN_1, 0x4334);
|
||||
snd_soc_update_bits(codec, RT5663_IRQ_3, 0x0004, 0x0004);
|
||||
snd_soc_write(codec, RT5663_HP_LOGIC_1, 0x2200);
|
||||
snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0x3000);
|
||||
snd_soc_write(codec, RT5663_HP_LOGIC_1, 0x6200);
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
msleep(20);
|
||||
if (snd_soc_read(codec, RT5663_INT_ST_1) & 0x2)
|
||||
break;
|
||||
}
|
||||
|
||||
value = snd_soc_read(codec, RT5663_HP_IMP_SEN_4);
|
||||
|
||||
snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0);
|
||||
snd_soc_write(codec, RT5663_INT_ST_1, 0);
|
||||
snd_soc_write(codec, RT5663_HP_LOGIC_1, 0);
|
||||
snd_soc_update_bits(codec, RT5663_RC_CLK, RT5663_DIG_25M_CLK_MASK,
|
||||
RT5663_DIG_25M_CLK_DIS);
|
||||
snd_soc_write(codec, RT5663_GLB_CLK, reg80);
|
||||
snd_soc_write(codec, RT5663_RECMIX, reg10);
|
||||
snd_soc_write(codec, RT5663_DUMMY_2, 0x00a4);
|
||||
snd_soc_write(codec, RT5663_DUMMY_1, reg2fa);
|
||||
snd_soc_write(codec, RT5663_HP_CALIB_2, 0x00c8);
|
||||
snd_soc_write(codec, RT5663_STO1_HPF_ADJ1, 0xb320);
|
||||
snd_soc_write(codec, RT5663_ADDA_RST, 0xe400);
|
||||
snd_soc_write(codec, RT5663_CHOP_ADC, 0x2000);
|
||||
snd_soc_write(codec, RT5663_HP_OUT_EN, 0x0008);
|
||||
snd_soc_update_bits(codec, RT5663_PWR_ANLG_2,
|
||||
RT5663_PWR_RECMIX1 | RT5663_PWR_RECMIX2, 0);
|
||||
snd_soc_update_bits(codec, RT5663_PWR_DIG_1,
|
||||
RT5663_PWR_DAC_L1 | RT5663_PWR_DAC_R1 |
|
||||
RT5663_PWR_LDO_DACREF_MASK | RT5663_PWR_ADC_L1 |
|
||||
RT5663_PWR_ADC_R1, 0);
|
||||
snd_soc_update_bits(codec, RT5663_PWR_DIG_2,
|
||||
RT5663_PWR_ADC_S1F | RT5663_PWR_DAC_S1F, 0);
|
||||
snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0003, 0);
|
||||
snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0);
|
||||
snd_soc_write(codec, RT5663_HP_LOGIC_2, 0);
|
||||
snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_1, reg91);
|
||||
snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
|
||||
RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK, 0);
|
||||
snd_soc_write(codec, RT5663_STO1_ADC_MIXER, reg26);
|
||||
snd_soc_write(codec, RT5663_ASRC_2, reg84);
|
||||
|
||||
for (i = 0; i < rt5663->pdata.impedance_sensing_num; i++) {
|
||||
if (value >= rt5663->imp_table[i].imp_min &&
|
||||
value <= rt5663->imp_table[i].imp_max)
|
||||
break;
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, RT5663_STO_DRE_9, RT5663_DRE_GAIN_HP_MASK,
|
||||
rt5663->imp_table[i].vol);
|
||||
snd_soc_update_bits(codec, RT5663_STO_DRE_10, RT5663_DRE_GAIN_HP_MASK,
|
||||
rt5663->imp_table[i].vol);
|
||||
|
||||
if (rt5663->jack_type == SND_JACK_HEADSET) {
|
||||
snd_soc_write(codec, RT5663_MIC_DECRO_2,
|
||||
rt5663->imp_table[i].dc_offset_l_manual_mic >> 16);
|
||||
snd_soc_write(codec, RT5663_MIC_DECRO_3,
|
||||
rt5663->imp_table[i].dc_offset_l_manual_mic & 0xffff);
|
||||
snd_soc_write(codec, RT5663_MIC_DECRO_5,
|
||||
rt5663->imp_table[i].dc_offset_r_manual_mic >> 16);
|
||||
snd_soc_write(codec, RT5663_MIC_DECRO_6,
|
||||
rt5663->imp_table[i].dc_offset_r_manual_mic & 0xffff);
|
||||
} else {
|
||||
snd_soc_write(codec, RT5663_MIC_DECRO_2,
|
||||
rt5663->imp_table[i].dc_offset_l_manual >> 16);
|
||||
snd_soc_write(codec, RT5663_MIC_DECRO_3,
|
||||
rt5663->imp_table[i].dc_offset_l_manual & 0xffff);
|
||||
snd_soc_write(codec, RT5663_MIC_DECRO_5,
|
||||
rt5663->imp_table[i].dc_offset_r_manual >> 16);
|
||||
snd_soc_write(codec, RT5663_MIC_DECRO_6,
|
||||
rt5663->imp_table[i].dc_offset_r_manual & 0xffff);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt5663_button_detect(struct snd_soc_codec *codec)
|
||||
{
|
||||
int btn_type, val;
|
||||
@ -1702,6 +1890,8 @@ static void rt5663_jack_detect_work(struct work_struct *work)
|
||||
break;
|
||||
case CODEC_VER_0:
|
||||
report = rt5663_jack_detect(rt5663->codec, 1);
|
||||
if (rt5663->pdata.impedance_sensing_num)
|
||||
rt5663_impedance_sensing(rt5663->codec);
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "Unknown CODEC Version\n");
|
||||
@ -1751,8 +1941,15 @@ static void rt5663_jack_detect_work(struct work_struct *work)
|
||||
break;
|
||||
}
|
||||
/* button release or spurious interrput*/
|
||||
if (btn_type == 0)
|
||||
if (btn_type == 0) {
|
||||
report = rt5663->jack_type;
|
||||
cancel_delayed_work_sync(
|
||||
&rt5663->jd_unplug_work);
|
||||
} else {
|
||||
queue_delayed_work(system_wq,
|
||||
&rt5663->jd_unplug_work,
|
||||
msecs_to_jiffies(500));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* jack out */
|
||||
@ -1773,6 +1970,37 @@ static void rt5663_jack_detect_work(struct work_struct *work)
|
||||
SND_JACK_BTN_2 | SND_JACK_BTN_3);
|
||||
}
|
||||
|
||||
static void rt5663_jd_unplug_work(struct work_struct *work)
|
||||
{
|
||||
struct rt5663_priv *rt5663 =
|
||||
container_of(work, struct rt5663_priv, jd_unplug_work.work);
|
||||
struct snd_soc_codec *codec = rt5663->codec;
|
||||
|
||||
if (!codec)
|
||||
return;
|
||||
|
||||
if (!rt5663_check_jd_status(codec)) {
|
||||
/* jack out */
|
||||
switch (rt5663->codec_ver) {
|
||||
case CODEC_VER_1:
|
||||
rt5663_v2_jack_detect(rt5663->codec, 0);
|
||||
break;
|
||||
case CODEC_VER_0:
|
||||
rt5663_jack_detect(rt5663->codec, 0);
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "Unknown CODEC Version\n");
|
||||
}
|
||||
|
||||
snd_soc_jack_report(rt5663->hs_jack, 0, SND_JACK_HEADSET |
|
||||
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
|
||||
SND_JACK_BTN_2 | SND_JACK_BTN_3);
|
||||
} else {
|
||||
queue_delayed_work(system_wq, &rt5663->jd_unplug_work,
|
||||
msecs_to_jiffies(500));
|
||||
}
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new rt5663_snd_controls[] = {
|
||||
/* DAC Digital Volume */
|
||||
SOC_DOUBLE_TLV("DAC Playback Volume", RT5663_STO1_DAC_DIG_VOL,
|
||||
@ -1797,10 +2025,6 @@ static const struct snd_kcontrol_new rt5663_v2_specific_controls[] = {
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new rt5663_specific_controls[] = {
|
||||
/* Headphone Output Volume */
|
||||
SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5663_STO_DRE_9,
|
||||
RT5663_STO_DRE_10, RT5663_DRE_GAIN_HP_SHIFT, 23, 1,
|
||||
rt5663_hp_vol_tlv),
|
||||
/* Mic Boost Volume*/
|
||||
SOC_SINGLE_TLV("IN1 Capture Volume", RT5663_CBJ_2,
|
||||
RT5663_GAIN_BST1_SHIFT, 8, 0, in_bst_tlv),
|
||||
@ -1808,6 +2032,13 @@ static const struct snd_kcontrol_new rt5663_specific_controls[] = {
|
||||
SOC_ENUM("IF1 ADC Data Swap", rt5663_if1_adc_enum),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new rt5663_hpvol_controls[] = {
|
||||
/* Headphone Output Volume */
|
||||
SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5663_STO_DRE_9,
|
||||
RT5663_STO_DRE_10, RT5663_DRE_GAIN_HP_SHIFT, 23, 1,
|
||||
rt5663_hp_vol_tlv),
|
||||
};
|
||||
|
||||
static int rt5663_is_sys_clk_from_pll(struct snd_soc_dapm_widget *w,
|
||||
struct snd_soc_dapm_widget *sink)
|
||||
{
|
||||
@ -2890,6 +3121,10 @@ static int rt5663_probe(struct snd_soc_codec *codec)
|
||||
ARRAY_SIZE(rt5663_specific_dapm_routes));
|
||||
snd_soc_add_codec_controls(codec, rt5663_specific_controls,
|
||||
ARRAY_SIZE(rt5663_specific_controls));
|
||||
|
||||
if (!rt5663->imp_table)
|
||||
snd_soc_add_codec_controls(codec, rt5663_hpvol_controls,
|
||||
ARRAY_SIZE(rt5663_hpvol_controls));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3178,6 +3413,8 @@ static void rt5663_calibrate(struct rt5663_priv *rt5663)
|
||||
|
||||
static int rt5663_parse_dp(struct rt5663_priv *rt5663, struct device *dev)
|
||||
{
|
||||
int table_size;
|
||||
|
||||
device_property_read_u32(dev, "realtek,dc_offset_l_manual",
|
||||
&rt5663->pdata.dc_offset_l_manual);
|
||||
device_property_read_u32(dev, "realtek,dc_offset_r_manual",
|
||||
@ -3186,6 +3423,17 @@ static int rt5663_parse_dp(struct rt5663_priv *rt5663, struct device *dev)
|
||||
&rt5663->pdata.dc_offset_l_manual_mic);
|
||||
device_property_read_u32(dev, "realtek,dc_offset_r_manual_mic",
|
||||
&rt5663->pdata.dc_offset_r_manual_mic);
|
||||
device_property_read_u32(dev, "realtek,impedance_sensing_num",
|
||||
&rt5663->pdata.impedance_sensing_num);
|
||||
|
||||
if (rt5663->pdata.impedance_sensing_num) {
|
||||
table_size = sizeof(struct impedance_mapping_table) *
|
||||
rt5663->pdata.impedance_sensing_num;
|
||||
rt5663->imp_table = devm_kzalloc(dev, table_size, GFP_KERNEL);
|
||||
device_property_read_u32_array(dev,
|
||||
"realtek,impedance_sensing_table",
|
||||
(u32 *)rt5663->imp_table, table_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3219,7 +3467,16 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
regmap_read(regmap, RT5663_VENDOR_ID_2, &val);
|
||||
|
||||
ret = regmap_read(regmap, RT5663_VENDOR_ID_2, &val);
|
||||
if (ret || (val != RT5663_DEVICE_ID_2 && val != RT5663_DEVICE_ID_1)) {
|
||||
dev_err(&i2c->dev,
|
||||
"Device with ID register %#x is not rt5663, retry one time.\n",
|
||||
val);
|
||||
msleep(100);
|
||||
regmap_read(regmap, RT5663_VENDOR_ID_2, &val);
|
||||
}
|
||||
|
||||
switch (val) {
|
||||
case RT5663_DEVICE_ID_2:
|
||||
rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5663_v2_regmap);
|
||||
@ -3338,6 +3595,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&rt5663->jack_detect_work, rt5663_jack_detect_work);
|
||||
INIT_DELAYED_WORK(&rt5663->jd_unplug_work, rt5663_jd_unplug_work);
|
||||
|
||||
if (i2c->irq) {
|
||||
ret = request_irq(i2c->irq, rt5663_irq,
|
||||
|
@ -34,6 +34,24 @@
|
||||
#include "rt5670.h"
|
||||
#include "rt5670-dsp.h"
|
||||
|
||||
#define RT5670_DEV_GPIO BIT(0)
|
||||
#define RT5670_IN2_DIFF BIT(1)
|
||||
#define RT5670_DMIC_EN BIT(2)
|
||||
#define RT5670_DMIC1_IN2P BIT(3)
|
||||
#define RT5670_DMIC1_GPIO6 BIT(4)
|
||||
#define RT5670_DMIC1_GPIO7 BIT(5)
|
||||
#define RT5670_DMIC2_INR BIT(6)
|
||||
#define RT5670_DMIC2_GPIO8 BIT(7)
|
||||
#define RT5670_DMIC3_GPIO5 BIT(8)
|
||||
#define RT5670_JD_MODE1 BIT(9)
|
||||
#define RT5670_JD_MODE2 BIT(10)
|
||||
#define RT5670_JD_MODE3 BIT(11)
|
||||
|
||||
static unsigned long rt5670_quirk;
|
||||
static unsigned int quirk_override;
|
||||
module_param_named(quirk, quirk_override, uint, 0444);
|
||||
MODULE_PARM_DESC(quirk, "Board-specific quirk override");
|
||||
|
||||
#define RT5670_DEVICE_ID 0x6271
|
||||
|
||||
#define RT5670_PR_RANGE_BASE (0xff + 1)
|
||||
@ -2582,6 +2600,24 @@ static int rt5670_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt5670_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
|
||||
dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio);
|
||||
if (dai->id != RT5670_AIF1)
|
||||
return 0;
|
||||
|
||||
if ((ratio % 50) == 0)
|
||||
snd_soc_update_bits(codec, RT5670_GEN_CTRL3,
|
||||
RT5670_TDM_DATA_MODE_SEL, RT5670_TDM_DATA_MODE_50FS);
|
||||
else
|
||||
snd_soc_update_bits(codec, RT5670_GEN_CTRL3,
|
||||
RT5670_TDM_DATA_MODE_SEL, RT5670_TDM_DATA_MODE_NOR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt5670_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
@ -2712,6 +2748,7 @@ static const struct snd_soc_dai_ops rt5670_aif_dai_ops = {
|
||||
.set_fmt = rt5670_set_dai_fmt,
|
||||
.set_tdm_slot = rt5670_set_tdm_slot,
|
||||
.set_pll = rt5670_set_dai_pll,
|
||||
.set_bclk_ratio = rt5670_set_bclk_ratio,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver rt5670_dai[] = {
|
||||
@ -2808,56 +2845,84 @@ static const struct acpi_device_id rt5670_acpi_match[] = {
|
||||
MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);
|
||||
#endif
|
||||
|
||||
static const struct dmi_system_id dmi_platform_intel_braswell[] = {
|
||||
static int rt5670_quirk_cb(const struct dmi_system_id *id)
|
||||
{
|
||||
rt5670_quirk = (unsigned long)id->driver_data;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id dmi_platform_intel_quirks[] = {
|
||||
{
|
||||
.callback = rt5670_quirk_cb,
|
||||
.ident = "Intel Braswell",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"),
|
||||
},
|
||||
.driver_data = (unsigned long *)(RT5670_DMIC_EN |
|
||||
RT5670_DMIC1_IN2P |
|
||||
RT5670_DEV_GPIO |
|
||||
RT5670_JD_MODE1),
|
||||
},
|
||||
{
|
||||
.callback = rt5670_quirk_cb,
|
||||
.ident = "Dell Wyse 3040",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Wyse 3040"),
|
||||
},
|
||||
.driver_data = (unsigned long *)(RT5670_DMIC_EN |
|
||||
RT5670_DMIC1_IN2P |
|
||||
RT5670_DEV_GPIO |
|
||||
RT5670_JD_MODE1),
|
||||
},
|
||||
{
|
||||
.callback = rt5670_quirk_cb,
|
||||
.ident = "Lenovo Thinkpad Tablet 10",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 10"),
|
||||
},
|
||||
.driver_data = (unsigned long *)(RT5670_DMIC_EN |
|
||||
RT5670_DMIC1_IN2P |
|
||||
RT5670_DEV_GPIO |
|
||||
RT5670_JD_MODE1),
|
||||
},
|
||||
{
|
||||
.callback = rt5670_quirk_cb,
|
||||
.ident = "Lenovo Thinkpad Tablet 10",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Tablet B"),
|
||||
},
|
||||
.driver_data = (unsigned long *)(RT5670_DMIC_EN |
|
||||
RT5670_DMIC1_IN2P |
|
||||
RT5670_DEV_GPIO |
|
||||
RT5670_JD_MODE1),
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct dmi_system_id dmi_platform_intel_bytcht_jdmode2[] = {
|
||||
{
|
||||
.callback = rt5670_quirk_cb,
|
||||
.ident = "Lenovo Thinkpad Tablet 10",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Miix 2 10"),
|
||||
},
|
||||
.driver_data = (unsigned long *)(RT5670_DMIC_EN |
|
||||
RT5670_DMIC1_IN2P |
|
||||
RT5670_DEV_GPIO |
|
||||
RT5670_JD_MODE2),
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct dmi_system_id dmi_platform_intel_bytcht_jdmode3[] = {
|
||||
{
|
||||
.callback = rt5670_quirk_cb,
|
||||
.ident = "Dell Venue 8 Pro 5855",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5855"),
|
||||
},
|
||||
.driver_data = (unsigned long *)(RT5670_DMIC_EN |
|
||||
RT5670_DMIC2_INR |
|
||||
RT5670_DEV_GPIO |
|
||||
RT5670_JD_MODE3),
|
||||
},
|
||||
{}
|
||||
};
|
||||
@ -2881,21 +2946,61 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
|
||||
if (pdata)
|
||||
rt5670->pdata = *pdata;
|
||||
|
||||
if (dmi_check_system(dmi_platform_intel_braswell)) {
|
||||
rt5670->pdata.dmic_en = true;
|
||||
rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
|
||||
dmi_check_system(dmi_platform_intel_quirks);
|
||||
if (quirk_override) {
|
||||
dev_info(&i2c->dev, "Overriding quirk 0x%x => 0x%x\n",
|
||||
(unsigned int)rt5670_quirk, quirk_override);
|
||||
rt5670_quirk = quirk_override;
|
||||
}
|
||||
|
||||
if (rt5670_quirk & RT5670_DEV_GPIO) {
|
||||
rt5670->pdata.dev_gpio = true;
|
||||
dev_info(&i2c->dev, "quirk dev_gpio\n");
|
||||
}
|
||||
if (rt5670_quirk & RT5670_IN2_DIFF) {
|
||||
rt5670->pdata.in2_diff = true;
|
||||
dev_info(&i2c->dev, "quirk IN2_DIFF\n");
|
||||
}
|
||||
if (rt5670_quirk & RT5670_DMIC_EN) {
|
||||
rt5670->pdata.dmic_en = true;
|
||||
dev_info(&i2c->dev, "quirk DMIC enabled\n");
|
||||
}
|
||||
if (rt5670_quirk & RT5670_DMIC1_IN2P) {
|
||||
rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
|
||||
dev_info(&i2c->dev, "quirk DMIC1 on IN2P pin\n");
|
||||
}
|
||||
if (rt5670_quirk & RT5670_DMIC1_GPIO6) {
|
||||
rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_GPIO6;
|
||||
dev_info(&i2c->dev, "quirk DMIC1 on GPIO6 pin\n");
|
||||
}
|
||||
if (rt5670_quirk & RT5670_DMIC1_GPIO7) {
|
||||
rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_GPIO7;
|
||||
dev_info(&i2c->dev, "quirk DMIC1 on GPIO7 pin\n");
|
||||
}
|
||||
if (rt5670_quirk & RT5670_DMIC2_INR) {
|
||||
rt5670->pdata.dmic2_data_pin = RT5670_DMIC_DATA_IN3N;
|
||||
dev_info(&i2c->dev, "quirk DMIC2 on INR pin\n");
|
||||
}
|
||||
if (rt5670_quirk & RT5670_DMIC2_GPIO8) {
|
||||
rt5670->pdata.dmic2_data_pin = RT5670_DMIC_DATA_GPIO8;
|
||||
dev_info(&i2c->dev, "quirk DMIC2 on GPIO8 pin\n");
|
||||
}
|
||||
if (rt5670_quirk & RT5670_DMIC3_GPIO5) {
|
||||
rt5670->pdata.dmic3_data_pin = RT5670_DMIC_DATA_GPIO5;
|
||||
dev_info(&i2c->dev, "quirk DMIC3 on GPIO5 pin\n");
|
||||
}
|
||||
|
||||
if (rt5670_quirk & RT5670_JD_MODE1) {
|
||||
rt5670->pdata.jd_mode = 1;
|
||||
} else if (dmi_check_system(dmi_platform_intel_bytcht_jdmode2)) {
|
||||
rt5670->pdata.dmic_en = true;
|
||||
rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
|
||||
rt5670->pdata.dev_gpio = true;
|
||||
dev_info(&i2c->dev, "quirk JD mode 1\n");
|
||||
}
|
||||
if (rt5670_quirk & RT5670_JD_MODE2) {
|
||||
rt5670->pdata.jd_mode = 2;
|
||||
} else if (dmi_check_system(dmi_platform_intel_bytcht_jdmode3)) {
|
||||
rt5670->pdata.dmic_en = true;
|
||||
rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
|
||||
rt5670->pdata.dev_gpio = true;
|
||||
dev_info(&i2c->dev, "quirk JD mode 2\n");
|
||||
}
|
||||
if (rt5670_quirk & RT5670_JD_MODE3) {
|
||||
rt5670->pdata.jd_mode = 3;
|
||||
dev_info(&i2c->dev, "quirk JD mode 3\n");
|
||||
}
|
||||
|
||||
rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap);
|
||||
|
@ -1816,6 +1816,10 @@
|
||||
#define RT5670_ZCD_HP_DIS (0x0 << 15)
|
||||
#define RT5670_ZCD_HP_EN (0x1 << 15)
|
||||
|
||||
/* General Control 3 (0xfc) */
|
||||
#define RT5670_TDM_DATA_MODE_SEL (0x1 << 11)
|
||||
#define RT5670_TDM_DATA_MODE_NOR (0x0 << 11)
|
||||
#define RT5670_TDM_DATA_MODE_50FS (0x1 << 11)
|
||||
|
||||
/* Codec Private Register definition */
|
||||
/* 3D Speaker Control (0x63) */
|
||||
|
Loading…
Reference in New Issue
Block a user