mirror of
https://github.com/physwizz/a155-U-u1.git
synced 2024-11-19 13:27:49 +00:00
7734 lines
249 KiB
C
7734 lines
249 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
//
|
|
// mt6358.c -- mt6358 ALSA SoC audio codec driver
|
|
//
|
|
// Copyright (c) 2018 MediaTek Inc.
|
|
// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
|
|
|
|
#include <linux/platform_device.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/iio/consumer.h>
|
|
#include <linux/nvmem-consumer.h>
|
|
#include <linux/mfd/mt6397/core.h>
|
|
#include <linux/regulator/consumer.h>
|
|
#include <sound/tlv.h>
|
|
#include <sound/soc.h>
|
|
#include <sound/core.h>
|
|
|
|
#include "mt6358.h"
|
|
#if IS_ENABLED(CONFIG_SND_SOC_MT6366_ACCDET) || IS_ENABLED(CONFIG_SND_SOC_MT6358_ACCDET)
|
|
#include "mt6358-accdet.h"
|
|
#endif
|
|
|
|
#define MAX_DEBUG_WRITE_INPUT 256
|
|
#define CODEC_SYS_DEBUG_SIZE (1024 * 32)
|
|
|
|
static ssize_t mt6358_codec_sysfs_read(struct file *filep, struct kobject *kobj,
|
|
struct bin_attribute *attr,
|
|
char *buf, loff_t offset, size_t size);
|
|
static ssize_t mt6358_codec_sysfs_write(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *bin_attr,
|
|
char *buf, loff_t off, size_t count);
|
|
|
|
int mt6358_set_codec_ops(struct snd_soc_component *cmpnt,
|
|
struct mt6358_codec_ops *ops)
|
|
{
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
priv->ops.enable_dc_compensation = ops->enable_dc_compensation;
|
|
priv->ops.set_lch_dc_compensation = ops->set_lch_dc_compensation;
|
|
priv->ops.set_rch_dc_compensation = ops->set_rch_dc_compensation;
|
|
priv->ops.adda_dl_gain_control = ops->adda_dl_gain_control;
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(mt6358_set_codec_ops);
|
|
|
|
static struct bin_attribute codec_dev_attr_reg = {
|
|
.attr = {
|
|
.name = "mtk_audio_codec",
|
|
.mode = 0600, /* permission */
|
|
},
|
|
.size = CODEC_SYS_DEBUG_SIZE,
|
|
.read = mt6358_codec_sysfs_read,
|
|
.write = mt6358_codec_sysfs_write,
|
|
};
|
|
|
|
static struct bin_attribute *mtk_codec_bin_attrs[] = {
|
|
&codec_dev_attr_reg,
|
|
NULL,
|
|
};
|
|
|
|
static struct attribute_group codec_bin_attr_group = {
|
|
.name = "mtk_codec_attrs",
|
|
.bin_attrs = mtk_codec_bin_attrs,
|
|
};
|
|
|
|
static int dc_trim_thread(void *arg);
|
|
static int mt_dc_trim_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
struct dc_trim_data *dc_trim = &priv->dc_trim;
|
|
|
|
dev_dbg(priv->dev, "%s(), event = 0x%x, dc_trim->calibrated %u\n",
|
|
__func__, event, dc_trim->calibrated);
|
|
|
|
if (dc_trim->calibrated)
|
|
return 0;
|
|
|
|
kthread_run(dc_trim_thread, priv, "dc_trim_thread");
|
|
return 0;
|
|
}
|
|
|
|
int mt6358_set_mtkaif_protocol(struct snd_soc_component *cmpnt,
|
|
int mtkaif_protocol)
|
|
{
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
priv->mtkaif_protocol = mtkaif_protocol;
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(mt6358_set_mtkaif_protocol);
|
|
|
|
static void playback_gpio_set(struct mt6358_priv *priv)
|
|
{
|
|
/* set gpio mosi mode */
|
|
regmap_update_bits(priv->regmap, MT6358_GPIO_MODE2_CLR,
|
|
0x01f8, 0x01f8);
|
|
regmap_update_bits(priv->regmap, MT6358_GPIO_MODE2_SET,
|
|
0xffff, 0x0249);
|
|
regmap_update_bits(priv->regmap, MT6358_GPIO_MODE2,
|
|
0xffff, 0x0249);
|
|
|
|
/* with high slew rate bit[3]=1, Driving: 8:4mA(default), a:8mA, c:12mA, e:16mA */
|
|
/* regmap_write(priv->regmap, MT6358_DRV_CON2, 0x8888); */
|
|
}
|
|
|
|
static void playback_gpio_reset(struct mt6358_priv *priv)
|
|
{
|
|
/* set pad_aud_*_mosi to GPIO mode and dir input
|
|
* reason:
|
|
* pad_aud_dat_mosi*, because the pin is used as boot strap
|
|
* don't clean clk/sync, for mtkaif protocol 2
|
|
*/
|
|
regmap_update_bits(priv->regmap, MT6358_GPIO_MODE2_CLR,
|
|
0x01f8, 0x01f8);
|
|
regmap_update_bits(priv->regmap, MT6358_GPIO_MODE2,
|
|
0x01f8, 0x0000);
|
|
regmap_update_bits(priv->regmap, MT6358_GPIO_DIR0,
|
|
0xf << 8, 0x0);
|
|
|
|
/* gpio mosi driving set to default 4mA */
|
|
/* regmap_write(priv->regmap, MT6358_DRV_CON2, 0x8888); */
|
|
}
|
|
|
|
static void capture_gpio_set(struct mt6358_priv *priv)
|
|
{
|
|
/* set gpio miso mode */
|
|
regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3_CLR,
|
|
0xffff, 0xffff);
|
|
regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3_SET,
|
|
0xffff, 0x0249);
|
|
regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3,
|
|
0xffff, 0x0249);
|
|
|
|
/* with high slew rate bit[3]=1, Driving: 8:4mA(default), a:8mA, c:12mA, e:16mA */
|
|
/* regmap_write(priv->regmap, MT6358_DRV_CON3, 0x8888); */
|
|
}
|
|
|
|
static void capture_gpio_reset(struct mt6358_priv *priv)
|
|
{
|
|
/* set pad_aud_*_miso to GPIO mode and dir input
|
|
* reason:
|
|
* pad_aud_clk_miso, because when playback only the miso_clk
|
|
* will also have 26m, so will have power leak
|
|
* pad_aud_dat_miso*, because the pin is used as boot strap
|
|
*/
|
|
regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3_CLR,
|
|
0xffff, 0xffff);
|
|
regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3,
|
|
0xffff, 0x0000);
|
|
regmap_update_bits(priv->regmap, MT6358_GPIO_DIR0,
|
|
0xf << 12, 0x0);
|
|
|
|
/* gpio miso driving set to default 4mA */
|
|
/* regmap_write(priv->regmap, MT6358_DRV_CON3, 0x8888); */
|
|
}
|
|
|
|
/* use only when not govern by DAPM */
|
|
static int mt6358_set_dcxo(struct mt6358_priv *priv, bool enable)
|
|
{
|
|
/* XO_AUDIO_EN_M Enable */
|
|
regmap_update_bits(priv->regmap, MT6358_DCXO_CW14,
|
|
0x1 << RG_XO_AUDIO_EN_M_SFT,
|
|
(enable ? 1 : 0) << RG_XO_AUDIO_EN_M_SFT);
|
|
return 0;
|
|
}
|
|
|
|
/* use only when not govern by DAPM */
|
|
static int mt6358_set_clksq(struct mt6358_priv *priv, bool enable)
|
|
{
|
|
/* audio clk source from internal dcxo */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON6,
|
|
RG_CLKSQ_IN_SEL_TEST_MASK_SFT,
|
|
0x0);
|
|
|
|
/* Enable/disable CLKSQ 26MHz */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON6,
|
|
RG_CLKSQ_EN_MASK_SFT,
|
|
(enable ? 1 : 0) << RG_CLKSQ_EN_SFT);
|
|
return 0;
|
|
}
|
|
|
|
/* use only when not govern by DAPM */
|
|
static int mt6358_set_aud_global_bias(struct mt6358_priv *priv, bool enable)
|
|
{
|
|
/* Enable audio global bias */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13,
|
|
RG_AUDGLB_PWRDN_VA28_MASK_SFT,
|
|
(enable ? 0 : 1) << RG_AUDGLB_PWRDN_VA28_SFT);
|
|
return 0;
|
|
}
|
|
|
|
/* use only when not govern by DAPM */
|
|
static int mt6358_set_topck(struct mt6358_priv *priv, bool enable)
|
|
{
|
|
regmap_update_bits(priv->regmap, MT6358_AUD_TOP_CKPDN_CON0,
|
|
0x0066, enable ? 0x0 : 0x66);
|
|
return 0;
|
|
}
|
|
|
|
static int mt6358_mtkaif_tx_enable(struct mt6358_priv *priv)
|
|
{
|
|
switch (priv->mtkaif_protocol) {
|
|
case MT6358_MTKAIF_PROTOCOL_2_CLK_P2:
|
|
/* MTKAIF TX format setting */
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AFE_ADDA_MTKAIF_CFG0,
|
|
0xffff, 0x0010);
|
|
/* enable aud_pad TX fifos */
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AFE_AUD_PAD_TOP,
|
|
0xff00, 0x3800);
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AFE_AUD_PAD_TOP,
|
|
0xff00, 0x3900);
|
|
break;
|
|
case MT6358_MTKAIF_PROTOCOL_2:
|
|
/* MTKAIF TX format setting */
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AFE_ADDA_MTKAIF_CFG0,
|
|
0xffff, 0x0010);
|
|
/* enable aud_pad TX fifos */
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AFE_AUD_PAD_TOP,
|
|
0xff00, 0x3100);
|
|
break;
|
|
case MT6358_MTKAIF_PROTOCOL_1:
|
|
default:
|
|
/* MTKAIF TX format setting */
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AFE_ADDA_MTKAIF_CFG0,
|
|
0xffff, 0x0000);
|
|
/* enable aud_pad TX fifos */
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AFE_AUD_PAD_TOP,
|
|
0xff00, 0x3100);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int mt6358_mtkaif_tx_disable(struct mt6358_priv *priv)
|
|
{
|
|
/* disable aud_pad TX fifos */
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_AUD_PAD_TOP,
|
|
0xff00, 0x3000);
|
|
return 0;
|
|
}
|
|
|
|
int mt6358_mtkaif_calibration_enable(struct snd_soc_component *cmpnt)
|
|
{
|
|
#if !defined(CONFIG_FPGA_EARLY_PORTING) && !defined(SKIP_SB)
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
playback_gpio_set(priv);
|
|
capture_gpio_set(priv);
|
|
mt6358_mtkaif_tx_enable(priv);
|
|
|
|
mt6358_set_dcxo(priv, true);
|
|
mt6358_set_aud_global_bias(priv, true);
|
|
mt6358_set_clksq(priv, true);
|
|
mt6358_set_topck(priv, true);
|
|
|
|
/* set dat_miso_loopback on */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG,
|
|
RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT,
|
|
1 << RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG,
|
|
RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT,
|
|
1 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT);
|
|
#endif
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(mt6358_mtkaif_calibration_enable);
|
|
|
|
int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt)
|
|
{
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
/* set dat_miso_loopback off */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG,
|
|
RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT,
|
|
0 << RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG,
|
|
RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT,
|
|
0 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT);
|
|
|
|
mt6358_set_topck(priv, false);
|
|
mt6358_set_clksq(priv, false);
|
|
mt6358_set_aud_global_bias(priv, false);
|
|
mt6358_set_dcxo(priv, false);
|
|
|
|
mt6358_mtkaif_tx_disable(priv);
|
|
playback_gpio_reset(priv);
|
|
capture_gpio_reset(priv);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(mt6358_mtkaif_calibration_disable);
|
|
|
|
int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt,
|
|
int phase_1, int phase_2)
|
|
{
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG,
|
|
RG_AUD_PAD_TOP_PHASE_MODE_MASK_SFT,
|
|
phase_1 << RG_AUD_PAD_TOP_PHASE_MODE_SFT);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG,
|
|
RG_AUD_PAD_TOP_PHASE_MODE2_MASK_SFT,
|
|
phase_2 << RG_AUD_PAD_TOP_PHASE_MODE2_SFT);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(mt6358_set_mtkaif_calibration_phase);
|
|
|
|
/* dc trim */
|
|
static int mt6358_get_hpofs_auxadc(struct mt6358_priv *priv)
|
|
{
|
|
int value = 0;
|
|
#if !IS_ENABLED(CONFIG_FPGA_EARLY_PORTING) && !defined(SKIP_SB)
|
|
int ret;
|
|
struct iio_channel *auxadc = priv->hpofs_cal_auxadc;
|
|
|
|
if (!IS_ERR(auxadc)) {
|
|
ret = iio_read_channel_raw(auxadc, &value);
|
|
if (ret < 0) {
|
|
dev_err(priv->dev, "Error: %s read fail (%d)\n",
|
|
__func__, ret);
|
|
return ret;
|
|
}
|
|
}
|
|
#endif /* #if !IS_ENABLED(CONFIG_FPGA_EARLY_PORTING) */
|
|
return value;
|
|
}
|
|
|
|
/* dl pga gain */
|
|
static const char *const dl_pga_gain[] = {
|
|
"8Db", "7Db", "6Db", "5Db", "4Db",
|
|
"3Db", "2Db", "1Db", "0Db", "-1Db",
|
|
"-2Db", "-3Db", "-4Db", "-5Db", "-6Db",
|
|
"-7Db", "-8Db", "-9Db", "-10Db", "-40Db"
|
|
};
|
|
|
|
static void zcd_enable(struct mt6358_priv *priv, bool enable, int device)
|
|
{
|
|
if (enable) {
|
|
switch (device) {
|
|
case DEVICE_RCV:
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDDEC_ANA_CON11,
|
|
0x7, 0x2);
|
|
break;
|
|
case DEVICE_LO:
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDDEC_ANA_CON11,
|
|
0x7, 0x0);
|
|
break;
|
|
case DEVICE_HP:
|
|
default:
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDDEC_ANA_CON11,
|
|
0x7, 0x1);
|
|
break;
|
|
}
|
|
/* Enable ZCD, for minimize pop noise */
|
|
/* when adjust gain during HP buffer on */
|
|
regmap_update_bits(priv->regmap, MT6358_ZCD_CON0,
|
|
0x7 << 8, 0x1 << 8);
|
|
regmap_update_bits(priv->regmap, MT6358_ZCD_CON0,
|
|
0x1 << 7, 0x0 << 7);
|
|
/* timeout, 1 = 5ms, 0 = 30ms */
|
|
regmap_update_bits(priv->regmap, MT6358_ZCD_CON0,
|
|
0x1 << 6, 0x0 << 6);
|
|
regmap_update_bits(priv->regmap, MT6358_ZCD_CON0,
|
|
0x3 << 4, 0x0 << 4);
|
|
regmap_update_bits(priv->regmap, MT6358_ZCD_CON0,
|
|
0x7 << 1, 0x5 << 1);
|
|
regmap_update_bits(priv->regmap, MT6358_ZCD_CON0,
|
|
0x1 << 0, 0x1 << 0);
|
|
} else {
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON11,
|
|
0x7, 0x4);
|
|
regmap_update_bits(priv->regmap, MT6358_ZCD_CON0,
|
|
0xffff, 0x0000);
|
|
}
|
|
}
|
|
|
|
static void hp_main_output_ramp(struct mt6358_priv *priv, bool up)
|
|
{
|
|
int i = 0, stage = 0;
|
|
int target = 7;
|
|
|
|
/* Enable/Reduce HPL/R main output stage step by step */
|
|
for (i = 0; i <= target; i++) {
|
|
stage = up ? i : target - i;
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x7 << 8, stage << 8);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x7 << 11, stage << 11);
|
|
usleep_range(100, 150);
|
|
}
|
|
}
|
|
|
|
static void hp_aux_feedback_loop_gain_ramp(struct mt6358_priv *priv, bool up)
|
|
{
|
|
int i = 0, stage = 0;
|
|
|
|
/* Reduce HP aux feedback loop gain step by step */
|
|
for (i = 0; i <= 0xf; i++) {
|
|
stage = up ? i : 0xf - i;
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xf << 12, stage << 12);
|
|
usleep_range(100, 150);
|
|
}
|
|
}
|
|
|
|
static void hp_pull_down(struct mt6358_priv *priv, bool enable)
|
|
{
|
|
int i;
|
|
|
|
if (enable) {
|
|
for (i = 0x0; i <= 0x6; i++) {
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4,
|
|
0x7, i);
|
|
usleep_range(600, 700);
|
|
}
|
|
} else {
|
|
for (i = 0x6; i >= 0x1; i--) {
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4,
|
|
0x7, i);
|
|
usleep_range(600, 700);
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool is_valid_hp_pga_idx(int reg_idx)
|
|
{
|
|
return (reg_idx >= DL_GAIN_8DB && reg_idx <= DL_GAIN_N_10DB) ||
|
|
reg_idx == DL_GAIN_N_40DB;
|
|
}
|
|
|
|
static void headset_volume_ramp(struct mt6358_priv *priv, int from, int to)
|
|
{
|
|
int offset = 0, count = 0, reg_idx;
|
|
|
|
if (!is_valid_hp_pga_idx(from) || !is_valid_hp_pga_idx(to))
|
|
dev_warn(priv->dev, "%s(), volume index is not valid, from %d, to %d\n",
|
|
__func__, from, to);
|
|
|
|
dev_info(priv->dev, "%s(), from %d, to %d\n",
|
|
__func__, from, to);
|
|
|
|
if (to > from)
|
|
offset = to - from;
|
|
else
|
|
offset = from - to;
|
|
|
|
while (offset >= 0) {
|
|
if (to > from)
|
|
reg_idx = from + count;
|
|
else
|
|
reg_idx = from - count;
|
|
|
|
if (is_valid_hp_pga_idx(reg_idx)) {
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_ZCD_CON2,
|
|
DL_GAIN_REG_MASK,
|
|
(reg_idx << 7) | reg_idx);
|
|
usleep_range(200, 300);
|
|
}
|
|
offset--;
|
|
count++;
|
|
}
|
|
}
|
|
|
|
static int mt6358_snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
|
struct soc_mixer_control *mc =
|
|
(struct soc_mixer_control *)kcontrol->private_value;
|
|
unsigned int reg = mc->reg;
|
|
unsigned int reg2 = mc->rreg;
|
|
unsigned int shift = mc->shift;
|
|
unsigned int rshift = mc->rshift;
|
|
int max = mc->max;
|
|
int min = mc->min;
|
|
unsigned int sign_bit = mc->sign_bit;
|
|
unsigned int mask = (1 << fls(max)) - 1;
|
|
unsigned int invert = mc->invert;
|
|
int err;
|
|
bool type_2r = false;
|
|
unsigned int val2 = 0;
|
|
unsigned int val, val_mask;
|
|
|
|
if (sign_bit)
|
|
mask = BIT(sign_bit + 1) - 1;
|
|
|
|
val = ucontrol->value.integer.value[0];
|
|
val = (val + min) & mask;
|
|
if (invert)
|
|
val = max - val;
|
|
val_mask = mask << shift;
|
|
val = val << shift;
|
|
if (snd_soc_volsw_is_stereo(mc)) {
|
|
val2 = ucontrol->value.integer.value[1];
|
|
val2 = (val2 + min) & mask;
|
|
if (invert)
|
|
val2 = max - val2;
|
|
if (reg == reg2) {
|
|
val_mask |= mask << rshift;
|
|
val |= val2 << rshift;
|
|
} else {
|
|
val2 = val2 << shift;
|
|
type_2r = true;
|
|
}
|
|
}
|
|
err = snd_soc_component_update_bits(component, reg, val_mask, val);
|
|
if (err < 0)
|
|
return err;
|
|
|
|
if (type_2r)
|
|
err = snd_soc_component_update_bits(component, reg2, val_mask, val2);
|
|
|
|
return err;
|
|
}
|
|
|
|
static int mt6358_put_volsw(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *component =
|
|
snd_soc_kcontrol_component(kcontrol);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(component);
|
|
struct soc_mixer_control *mc =
|
|
(struct soc_mixer_control *)kcontrol->private_value;
|
|
unsigned int reg;
|
|
int index = ucontrol->value.integer.value[0];
|
|
int ret;
|
|
|
|
ret = mt6358_snd_soc_put_volsw(kcontrol, ucontrol);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
switch (mc->reg) {
|
|
case MT6358_ZCD_CON2:
|
|
regmap_read(priv->regmap, MT6358_ZCD_CON2, ®);
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] =
|
|
(reg >> RG_AUDHPLGAIN_SFT) & RG_AUDHPLGAIN_MASK;
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] =
|
|
(reg >> RG_AUDHPRGAIN_SFT) & RG_AUDHPRGAIN_MASK;
|
|
break;
|
|
case MT6358_ZCD_CON1:
|
|
regmap_read(priv->regmap, MT6358_ZCD_CON1, ®);
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL] =
|
|
(reg >> RG_AUDLOLGAIN_SFT) & RG_AUDLOLGAIN_MASK;
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR] =
|
|
(reg >> RG_AUDLORGAIN_SFT) & RG_AUDLORGAIN_MASK;
|
|
break;
|
|
case MT6358_ZCD_CON3:
|
|
regmap_read(priv->regmap, MT6358_ZCD_CON3, ®);
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL] =
|
|
(reg >> RG_AUDHSGAIN_SFT) & RG_AUDHSGAIN_MASK;
|
|
break;
|
|
case MT6358_AUDENC_ANA_CON0:
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON0, ®);
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1] =
|
|
(reg >> RG_AUDPREAMPLGAIN_SFT) & RG_AUDPREAMPLGAIN_MASK;
|
|
case MT6358_AUDENC_ANA_CON1:
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON1, ®);
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2] =
|
|
(reg >> RG_AUDPREAMPRGAIN_SFT) & RG_AUDPREAMPRGAIN_MASK;
|
|
break;
|
|
}
|
|
|
|
dev_info(priv->dev, "%s(), name %s, reg(0x%x) = 0x%x, set index = %x\n",
|
|
__func__, kcontrol->id.name, mc->reg, reg, index);
|
|
return ret;
|
|
}
|
|
|
|
static void mt6358_restore_pga(struct mt6358_priv *priv);
|
|
|
|
/* VOW force phase2 for debug */
|
|
/* According to VOW programming guide.(analog part & digital part) */
|
|
static int mt6358_enable_vow_phase2(struct mt6358_priv *priv)
|
|
{
|
|
/* analog */
|
|
|
|
/* VOW: Enable audio global bias */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, (0x1 << 4), (0x0 << 4));
|
|
/* [13] xo_audio_en_m = 1 */
|
|
regmap_update_bits(priv->regmap, MT6358_DCXO_CW14, (0x1 << 13), (0x1 << 13));
|
|
/* AUDENC XO VOW enable */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON1, 0x0800);
|
|
mt6358_restore_pga(priv);
|
|
/* Enable XO VOW CK */
|
|
regmap_write(priv->regmap, MT6358_DCXO_CW13, 0x9929);
|
|
/* MIC Bias 0 Output voltage = 1.9v */
|
|
/* MIC Bias 0 LowPower enable */
|
|
/* MIC Bias 0 power on */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0025);
|
|
/* Digital microphone enable */
|
|
/* Digital microphone slew rate control = 2'b10 */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON8, 0x0005);
|
|
|
|
/* digital */
|
|
|
|
/* RG_VOW13M_CK_PDN = 1'b0 */
|
|
/* RG_VOW32K_CK_PDN = 1'b0 */
|
|
regmap_write(priv->regmap, MT6358_AUD_TOP_CKPDN_CON0, 0x0000);
|
|
/* AUD_DAT_MISO1 = 3'd4 */
|
|
/* AUD_DAT_MISO0 = 3'd4 */
|
|
regmap_write(priv->regmap, MT6358_GPIO_MODE3, 0x0120);
|
|
/* VOW AMPREF Setting */
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_CFG0, 0xffff);
|
|
/* VOW A,B timeout initial value */
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_CFG1, 0x0200);
|
|
/* VOW A,B value setting */
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_CFG2, 0x2424);
|
|
/* alhpa and beta K value setting */
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_CFG3, 0xdbac);
|
|
/* gamma K value and vow mtkaif tx setting */
|
|
/* VOW_TXIF_MONO = 1 */
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_CFG4, 0x029e);
|
|
/* N mini value setting */
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_CFG5, 0x0000);
|
|
/* vow posdiv and cic mode configure */
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_POSDIV_CFG0, 0x0000);
|
|
/* Latch S and N value when irq trigger */
|
|
/* rg_mtkaif_hpf_bypass = 1'b0 */
|
|
/* rg_sndrdet_hpf_bypass = 1'b0 */
|
|
/* rg_hpf_on = 1'b1 */
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_HPF_CFG0, 0x0451);
|
|
/* vow input rate select = 1.6m */
|
|
/* VOW_DIGMIC_ON */
|
|
/* VOW_CK_DIV_RST = 1'b1 , reset clock divider */
|
|
/* vow digital mic clock(800k/1.6k) */
|
|
/* Select SDM 3-level mode. (digital MIC data path) */
|
|
/* vow interrupt source select : no bias irq source */
|
|
/* vow interrupt flag for read out */
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_TOP, 0x68d1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* VOW force phase2 for debug */
|
|
/* According to VOW programming guide.(analog part & digital part) */
|
|
static int mt6358_disable_vow_phase2(struct mt6358_priv *priv)
|
|
{
|
|
/* digital */
|
|
|
|
/* power down VOW source clock */
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_TOP, 0xc000);
|
|
/* vow hpf filter off */
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_HPF_CFG0, 0x0450);
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_POSDIV_CFG0, 0x0c00);
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_CFG5, 0x0100);
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_CFG4, 0x006c);
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_CFG3, 0xa879);
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_CFG2, 0x2323);
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_CFG1, 0x0400);
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_CFG0, 0x0000);
|
|
regmap_write(priv->regmap, MT6358_GPIO_MODE3, 0x02d8);
|
|
regmap_write(priv->regmap, MT6358_AUD_TOP_CKPDN_CON0, 0x0000);
|
|
|
|
/* analog */
|
|
|
|
/* Digital microphone disable */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON8, 0x0004);
|
|
/* MIC Bias 0 Output voltage = 1.7v */
|
|
/* MIC Bias 0 LowPower disable */
|
|
/* MIC Bias 0 power down */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0000);
|
|
/* Disable XO VOW CK */
|
|
regmap_write(priv->regmap, MT6358_DCXO_CW13, 0x9829);
|
|
/* AUDENC XO VOW disable */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON1, 0x0000);
|
|
mt6358_restore_pga(priv);
|
|
/* [13] xo_audio_en_m = 0 */
|
|
regmap_update_bits(priv->regmap, MT6358_DCXO_CW14, (0x1 << 13), (0x0 << 13));
|
|
/* Disable audio global bias */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, (0x1 << 4), (0x1 << 4));
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* VOW force phase2 for debug */
|
|
static int mt6358_get_vow(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(c);
|
|
|
|
ucontrol->value.integer.value[0] = priv->vow_enable;
|
|
return 0;
|
|
}
|
|
|
|
/* VOW force phase2 for debug */
|
|
static int mt6358_put_vow(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(c);
|
|
int enabled = ucontrol->value.integer.value[0];
|
|
|
|
if (priv->vow_enable != enabled) {
|
|
if (enabled)
|
|
mt6358_enable_vow_phase2(priv);
|
|
else
|
|
mt6358_disable_vow_phase2(priv);
|
|
|
|
priv->vow_enable = enabled;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0);
|
|
static const DECLARE_TLV_DB_SCALE(capture_tlv, 0, 600, 0);
|
|
|
|
static const struct snd_kcontrol_new mt6358_snd_controls[] = {
|
|
/* dl pga gain */
|
|
SOC_DOUBLE_EXT_TLV("Headset Volume",
|
|
MT6358_ZCD_CON2, 0, 7, 0x12, 0,
|
|
snd_soc_get_volsw, mt6358_put_volsw, playback_tlv),
|
|
SOC_DOUBLE_EXT_TLV("Lineout Volume",
|
|
MT6358_ZCD_CON1, 0, 7, 0x12, 0,
|
|
snd_soc_get_volsw, mt6358_put_volsw, playback_tlv),
|
|
SOC_SINGLE_EXT_TLV("Handset Volume",
|
|
MT6358_ZCD_CON3, 0, 0x12, 0,
|
|
snd_soc_get_volsw, mt6358_put_volsw, playback_tlv),
|
|
|
|
/* ul pga gain */
|
|
SOC_SINGLE_EXT_TLV("PGA1 Volume",
|
|
MT6358_AUDENC_ANA_CON0, RG_AUDPREAMPLGAIN_SFT, 4, 0,
|
|
snd_soc_get_volsw, mt6358_put_volsw, capture_tlv),
|
|
SOC_SINGLE_EXT_TLV("PGA2 Volume",
|
|
MT6358_AUDENC_ANA_CON1, RG_AUDPREAMPRGAIN_SFT, 4, 0,
|
|
snd_soc_get_volsw, mt6358_put_volsw, capture_tlv),
|
|
|
|
/* VOW force phase2 for debug */
|
|
SOC_SINGLE_BOOL_EXT("VOW Phase2 Switch", 0,
|
|
mt6358_get_vow, mt6358_put_vow),
|
|
};
|
|
|
|
/* MUX */
|
|
/* LOL MUX */
|
|
static const char * const lo_in_mux_map[] = {
|
|
"Open", "Mute", "Playback", "Test Mode"
|
|
};
|
|
|
|
static int lo_in_mux_map_value[] = {
|
|
LOL_MUX_OPEN,
|
|
LOL_MUX_MUTE,
|
|
LOL_MUX_PLAYBACK,
|
|
LOL_MUX_TEST_MODE,
|
|
};
|
|
|
|
static SOC_VALUE_ENUM_SINGLE_DECL(lo_in_mux_map_enum,
|
|
SND_SOC_NOPM,
|
|
0,
|
|
LOL_MUX_MASK,
|
|
lo_in_mux_map,
|
|
lo_in_mux_map_value);
|
|
|
|
static const struct snd_kcontrol_new lo_in_mux_control =
|
|
SOC_DAPM_ENUM("In Select", lo_in_mux_map_enum);
|
|
|
|
static const char * const hp_in_mux_map[] = {
|
|
"Open",
|
|
"LoudSPK Playback",
|
|
"Audio Playback",
|
|
"Test Mode",
|
|
"HP Impedance",
|
|
"Loud DualSPK Playback",
|
|
"undefined2",
|
|
"undefined3",
|
|
};
|
|
|
|
static int hp_in_mux_map_value[] = {
|
|
HP_MUX_OPEN,
|
|
HP_MUX_HPSPK,
|
|
HP_MUX_HP,
|
|
HP_MUX_TEST_MODE,
|
|
HP_MUX_HP_IMPEDANCE,
|
|
HP_MUX_HP_DUALSPK,
|
|
HP_MUX_OPEN,
|
|
HP_MUX_OPEN,
|
|
};
|
|
|
|
static SOC_VALUE_ENUM_SINGLE_DECL(hpl_in_mux_map_enum,
|
|
SND_SOC_NOPM,
|
|
0,
|
|
HP_MUX_MASK,
|
|
hp_in_mux_map,
|
|
hp_in_mux_map_value);
|
|
|
|
static const struct snd_kcontrol_new hpl_in_mux_control =
|
|
SOC_DAPM_ENUM("HPL Select", hpl_in_mux_map_enum);
|
|
|
|
static SOC_VALUE_ENUM_SINGLE_DECL(hpr_in_mux_map_enum,
|
|
SND_SOC_NOPM,
|
|
0,
|
|
HP_MUX_MASK,
|
|
hp_in_mux_map,
|
|
hp_in_mux_map_value);
|
|
|
|
static const struct snd_kcontrol_new hpr_in_mux_control =
|
|
SOC_DAPM_ENUM("HPR Select", hpr_in_mux_map_enum);
|
|
|
|
static const char * const rcv_in_mux_map[] = {
|
|
"Open", "Mute", "Voice Playback", "Test Mode"
|
|
};
|
|
|
|
static int rcv_in_mux_map_value[] = {
|
|
RCV_MUX_OPEN,
|
|
RCV_MUX_MUTE,
|
|
RCV_MUX_VOICE_PLAYBACK,
|
|
RCV_MUX_TEST_MODE,
|
|
};
|
|
|
|
static SOC_VALUE_ENUM_SINGLE_DECL(rcv_in_mux_map_enum,
|
|
SND_SOC_NOPM,
|
|
0,
|
|
RCV_MUX_MASK,
|
|
rcv_in_mux_map,
|
|
rcv_in_mux_map_value);
|
|
|
|
static const struct snd_kcontrol_new rcv_in_mux_control =
|
|
SOC_DAPM_ENUM("RCV Select", rcv_in_mux_map_enum);
|
|
|
|
/* DAC In MUX */
|
|
static const char * const dac_in_mux_map[] = {
|
|
"Normal Path", "Sgen"
|
|
};
|
|
|
|
static int dac_in_mux_map_value[] = {
|
|
0x0, 0x1,
|
|
};
|
|
|
|
static SOC_VALUE_ENUM_SINGLE_DECL(dac_in_mux_map_enum,
|
|
MT6358_AFE_TOP_CON0,
|
|
DL_SINE_ON_SFT,
|
|
DL_SINE_ON_MASK,
|
|
dac_in_mux_map,
|
|
dac_in_mux_map_value);
|
|
|
|
static const struct snd_kcontrol_new dac_in_mux_control =
|
|
SOC_DAPM_ENUM("DAC Select", dac_in_mux_map_enum);
|
|
|
|
/* AIF Out MUX */
|
|
static SOC_VALUE_ENUM_SINGLE_DECL(aif_out_mux_map_enum,
|
|
MT6358_AFE_TOP_CON0,
|
|
UL_SINE_ON_SFT,
|
|
UL_SINE_ON_MASK,
|
|
dac_in_mux_map,
|
|
dac_in_mux_map_value);
|
|
|
|
static const struct snd_kcontrol_new aif_out_mux_control =
|
|
SOC_DAPM_ENUM("AIF Out Select", aif_out_mux_map_enum);
|
|
|
|
static const char * const mic_type_mux_map[] = {
|
|
"Idle",
|
|
"ACC",
|
|
"DMIC",
|
|
"DCC",
|
|
"DCC_ECM_DIFF",
|
|
"DCC_ECM_SINGLE",
|
|
};
|
|
|
|
static int mic_type_mux_map_value[] = {
|
|
MIC_TYPE_MUX_IDLE,
|
|
MIC_TYPE_MUX_ACC,
|
|
MIC_TYPE_MUX_DMIC,
|
|
MIC_TYPE_MUX_DCC,
|
|
MIC_TYPE_MUX_DCC_ECM_DIFF,
|
|
MIC_TYPE_MUX_DCC_ECM_SINGLE,
|
|
};
|
|
|
|
static SOC_VALUE_ENUM_SINGLE_DECL(mic_type_mux_map_enum,
|
|
SND_SOC_NOPM,
|
|
0,
|
|
MIC_TYPE_MUX_MASK,
|
|
mic_type_mux_map,
|
|
mic_type_mux_map_value);
|
|
|
|
static const struct snd_kcontrol_new mic_type_mux_control =
|
|
SOC_DAPM_ENUM("Mic Type Select", mic_type_mux_map_enum);
|
|
|
|
static const char * const adc_left_mux_map[] = {
|
|
"Idle", "AIN0", "Left Preamplifier", "Idle_1"
|
|
};
|
|
|
|
static int adc_mux_map_value[] = {
|
|
ADC_MUX_IDLE,
|
|
ADC_MUX_AIN0,
|
|
ADC_MUX_PREAMPLIFIER,
|
|
ADC_MUX_IDLE1,
|
|
};
|
|
|
|
static SOC_VALUE_ENUM_SINGLE_DECL(adc_left_mux_map_enum,
|
|
SND_SOC_NOPM,
|
|
0,
|
|
ADC_MUX_MASK,
|
|
adc_left_mux_map,
|
|
adc_mux_map_value);
|
|
|
|
static const struct snd_kcontrol_new adc_left_mux_control =
|
|
SOC_DAPM_ENUM("ADC L Select", adc_left_mux_map_enum);
|
|
|
|
/* ADC R MUX */
|
|
static const char * const adc_right_mux_map[] = {
|
|
"Idle", "AIN0", "Right Preamplifier", "Idle_1"
|
|
};
|
|
|
|
static SOC_VALUE_ENUM_SINGLE_DECL(adc_right_mux_map_enum,
|
|
SND_SOC_NOPM,
|
|
0,
|
|
ADC_MUX_MASK,
|
|
adc_right_mux_map,
|
|
adc_mux_map_value);
|
|
|
|
static const struct snd_kcontrol_new adc_right_mux_control =
|
|
SOC_DAPM_ENUM("ADC R Select", adc_right_mux_map_enum);
|
|
|
|
static const char * const pga_mux_map[] = {
|
|
"None", "AIN0", "AIN1", "AIN2"
|
|
};
|
|
|
|
static int pga_mux_map_value[] = {
|
|
PGA_MUX_NONE,
|
|
PGA_MUX_AIN0,
|
|
PGA_MUX_AIN1,
|
|
PGA_MUX_AIN2,
|
|
};
|
|
|
|
static SOC_VALUE_ENUM_SINGLE_DECL(pga_left_mux_map_enum,
|
|
SND_SOC_NOPM,
|
|
0,
|
|
PGA_MUX_MASK,
|
|
pga_mux_map,
|
|
pga_mux_map_value);
|
|
|
|
static const struct snd_kcontrol_new pga_left_mux_control =
|
|
SOC_DAPM_ENUM("PGA L Select", pga_left_mux_map_enum);
|
|
|
|
/* PGA R MUX */
|
|
static SOC_VALUE_ENUM_SINGLE_DECL(pga_right_mux_map_enum,
|
|
SND_SOC_NOPM,
|
|
0,
|
|
PGA_MUX_MASK,
|
|
pga_mux_map,
|
|
pga_mux_map_value);
|
|
|
|
static const struct snd_kcontrol_new pga_right_mux_control =
|
|
SOC_DAPM_ENUM("PGA R Select", pga_right_mux_map_enum);
|
|
|
|
static int mt_clksq_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* audio clk source from internal dcxo */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON6,
|
|
RG_CLKSQ_IN_SEL_TEST_MASK_SFT,
|
|
0x0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt_sgen_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* sdm audio fifo clock power on */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0006);
|
|
/* scrambler clock on enable */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xcba1);
|
|
/* sdm power on */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0003);
|
|
/* sdm fifo enable */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x000b);
|
|
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_SGEN_CFG0,
|
|
0xff3f,
|
|
0x0000);
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_SGEN_CFG1,
|
|
0xffff,
|
|
0x0001);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
/* DL scrambler disabling sequence */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0000);
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xcba0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt_aif_in_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
dev_info(priv->dev, "%s(), event 0x%x, rate %d\n",
|
|
__func__, event, priv->dl_rate);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
playback_gpio_set(priv);
|
|
|
|
/* sdm audio fifo clock power on */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0006);
|
|
/* scrambler clock on enable, invert left channel */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xcba1);
|
|
/* sdm power on */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0003);
|
|
/* sdm fifo enable */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x000B);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
/* DL scrambler disabling sequence */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0000);
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xcba0);
|
|
|
|
playback_gpio_reset(priv);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void set_hp_l_input_mux(struct mt6358_priv *priv, unsigned int mux)
|
|
{
|
|
dev_info(priv->dev, "%s(), mux = %d\n", __func__, mux);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
RG_AUDHPLMUXINPUTSEL_VAUDP15_MASK_SFT,
|
|
mux << RG_AUDHPLMUXINPUTSEL_VAUDP15_SFT);
|
|
}
|
|
|
|
static void enable_lo_buffer(struct mt6358_priv *priv, bool enable)
|
|
{
|
|
dev_info(priv->dev, "%s(), enable = %d\n", __func__, enable);
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON7, 0x0110);
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON7, 0x0112);
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON7, 0x0113);
|
|
}
|
|
|
|
static void set_speaker_gain(struct mt6358_priv *priv, int spk_gain)
|
|
{
|
|
dev_info(priv->dev, "%s(), spk_gain = %d\n", __func__, spk_gain);
|
|
regmap_update_bits(priv->regmap, MT6358_ZCD_CON1,
|
|
DL_GAIN_REG_MASK, (spk_gain << 7) | spk_gain);
|
|
}
|
|
|
|
static int mtk_hp_enable(struct mt6358_priv *priv)
|
|
{
|
|
#ifdef ANALOG_HPTRIM
|
|
unsigned int trim_setting = 0;
|
|
unsigned int reg_value = 0;
|
|
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), mic_vinp_mv = %d, Result AUDDEC_ELR_0 = 0x%x\n",
|
|
__func__, priv->dc_trim.mic_vinp_mv, reg_value);
|
|
|
|
if (priv->dc_trim.mic_vinp_mv > MIC_VINP_4POLE_THRES_MV &&
|
|
((priv->debug_flag & DBG_DCTRIM_BYPASS_4POLE) == 0)) {
|
|
trim_setting = priv->dc_trim.hp_4_pole_trim_setting;
|
|
dev_info(priv->dev, "%s(), set 4 pole mic_vinp_mv = %d\n",
|
|
__func__, priv->dc_trim.mic_vinp_mv);
|
|
} else {
|
|
trim_setting = priv->dc_trim.hp_3_pole_trim_setting;
|
|
}
|
|
|
|
dev_info(priv->dev, "%s(), trim_setting = %d",
|
|
__func__, trim_setting);
|
|
|
|
if (!priv->dc_trim.dc_compensation_disabled) {
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ELR_0, trim_setting);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), new AUDDEC_ELR_0 = 0x%x\n",
|
|
__func__, reg_value);
|
|
} else {
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ELR_0, 0x0);
|
|
dev_info(priv->dev, "%s(), priv->dc_trim.compensation_disabled = true\n",
|
|
__func__);
|
|
}
|
|
#endif
|
|
dev_info(priv->dev, "+%s()\n", __func__);
|
|
|
|
if (!priv->pull_down_stay_enable) {
|
|
/* Pull-down HPL/R to AVSS28_AUD */
|
|
hp_pull_down(priv, true);
|
|
}
|
|
/* release HP CMFB gate rstb */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4,
|
|
0x1 << 6, 0x1 << 6);
|
|
|
|
/* Disable headphone short-circuit protection */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x3000);
|
|
/* Reduce ESD resistance of AU_REFN */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0xc000);
|
|
/* Set HPR/HPL gain as minimum (~ -10dB) */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_10DB_REG);
|
|
|
|
/* Turn on DA_600K_NCP_VA18 */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON1, 0x0001);
|
|
/* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON2, 0x002c);
|
|
/* Toggle RG_DIVCKS_CHG */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON0, 0x0001);
|
|
/* Set NCP soft start mode as default mode: 150us */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON4, 0x0002);
|
|
/* Enable NCP */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x0000);
|
|
usleep_range(250, 270);
|
|
|
|
/* Enable cap-less LDOs (1.5V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x1055, 0x1055);
|
|
/* Enable NV regulator (-1.2V) */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x0001);
|
|
usleep_range(100, 120);
|
|
|
|
/* Enable AUD_ZCD */
|
|
zcd_enable(priv, true, DEVICE_HP);
|
|
|
|
/* Disable headphone short-circuit protection */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x3000);
|
|
|
|
/* Enable IBIST */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055);
|
|
|
|
/* Set HP DR bias current optimization, 010: 6uA */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON11,
|
|
0xff80, 0x4900);
|
|
/* Set HP & ZCD bias current optimization */
|
|
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055);
|
|
/* Set HPP/N STB enhance circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0xc033);
|
|
|
|
/* Enable HP aux output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x000c);
|
|
/* Enable HP aux feedback loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x003c);
|
|
/* Enable HP aux CMFB loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0c00);
|
|
/* Enable HP driver bias circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30c0);
|
|
/* Enable HP driver core circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30f0);
|
|
/* Short HP main output to HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x00ff, 0x00fc);
|
|
|
|
/* Enable HP main CMFB loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0e00);
|
|
/* Disable HP aux CMFB loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0200);
|
|
|
|
/* Select CMFB resistor bulk to AC mode */
|
|
/* Selec HS/LO cap size (6.5pF default) */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON10, 0x0000);
|
|
|
|
/* Enable HP main output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x00ff);
|
|
/* Enable HPR/L main output stage step by step */
|
|
hp_main_output_ramp(priv, true);
|
|
|
|
/* Reduce HP aux feedback loop gain */
|
|
hp_aux_feedback_loop_gain_ramp(priv, true);
|
|
/* Disable HP aux feedback loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fcf);
|
|
|
|
/* apply volume setting */
|
|
headset_volume_ramp(priv,
|
|
DL_GAIN_N_10DB,
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL]);
|
|
|
|
/* Disable HP aux output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fc3);
|
|
/* Unshort HP main output to HP aux output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3f03);
|
|
usleep_range(100, 120);
|
|
|
|
/* Enable AUD_CLK */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x1);
|
|
/* Enable Audio DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0xf, 0xf);
|
|
/* Enable low-noise mode of DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x1, 0x1);
|
|
usleep_range(100, 120);
|
|
|
|
/* Switch HPL MUX to audio DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x0f00, 0x0200);
|
|
/* Switch HPR MUX to audio DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x0f00, 0x0a00);
|
|
|
|
/* disable L ch invert: MT6358_AFUNC_AUC_CON0[10] = 0 */
|
|
regmap_update_bits(priv->regmap, MT6358_AFUNC_AUD_CON0,
|
|
0x0400, 0x0);
|
|
#ifndef ANALOG_HPTRIM
|
|
/* Apply digital DC compensation value to DAC */
|
|
apply_dc_compensation(priv, true);
|
|
#endif
|
|
|
|
/* Disable Pull-down HPL/R to AVSS28_AUD */
|
|
hp_pull_down(priv, false);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_hp_disable(struct mt6358_priv *priv)
|
|
{
|
|
dev_info(priv->dev, "+%s()\n", __func__);
|
|
|
|
/* Pull-down HPL/R to AVSS28_AUD */
|
|
hp_pull_down(priv, true);
|
|
|
|
#ifndef ANALOG_HPTRIM
|
|
apply_dc_compensation(priv, false);
|
|
#endif
|
|
|
|
/* HPR/HPL mux to open */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x0f00, 0x0000);
|
|
|
|
/* Disable low-noise mode of DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0x0001, 0x0000);
|
|
|
|
/* Disable Audio DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x000f, 0x0000);
|
|
|
|
/* Disable AUD_CLK */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x0);
|
|
|
|
/* Short HP main output to HP aux output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fc3);
|
|
/* Enable HP aux output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fcf);
|
|
|
|
/* decrease HPL/R gain to normal gain step by step */
|
|
headset_volume_ramp(priv,
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL],
|
|
DL_GAIN_N_10DB);
|
|
|
|
/* Enable HP aux feedback loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fff);
|
|
|
|
/* Reduce HP aux feedback loop gain */
|
|
hp_aux_feedback_loop_gain_ramp(priv, false);
|
|
|
|
/* decrease HPR/L main output stage step by step */
|
|
hp_main_output_ramp(priv, false);
|
|
|
|
/* Disable HP main output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3, 0x0);
|
|
|
|
/* Enable HP aux CMFB loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0e00);
|
|
|
|
/* Disable HP main CMFB loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0c00);
|
|
|
|
/* Unshort HP main output to HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x3 << 6, 0x0);
|
|
|
|
/* Disable HP driver core circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x3 << 4, 0x0);
|
|
|
|
/* Disable HP driver bias circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x3 << 6, 0x0);
|
|
|
|
/* Disable HP aux CMFB loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0000);
|
|
|
|
/* Disable HP aux feedback loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x3 << 4, 0x0);
|
|
|
|
/* Disable HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x3 << 2, 0x0);
|
|
|
|
/* Disable IBIST */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON12,
|
|
0x1 << 8, 0x1 << 8);
|
|
|
|
/* Disable AUD_ZCD */
|
|
zcd_enable(priv, false, DEVICE_HP);
|
|
|
|
/* Disable NV regulator (-1.2V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x1, 0x0);
|
|
/* Disable cap-less LDOs (1.5V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x1055, 0x0);
|
|
/* Disable NCP */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3,
|
|
0x1, 0x1);
|
|
|
|
/* Set HPL/HPR gain to mute */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_10DB_REG);
|
|
|
|
/* Increase ESD resistance of AU_REFN */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON2,
|
|
0x1 << 14, 0x0);
|
|
|
|
/* Set HP CMFB gate rstb */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4,
|
|
0x1 << 6, 0x0);
|
|
|
|
if (!priv->pull_down_stay_enable) {
|
|
/* disable Pull-down HPL/R to AVSS28_AUD */
|
|
hp_pull_down(priv, false);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_hp_spk_enable(struct mt6358_priv *priv)
|
|
{
|
|
unsigned int trim_setting = 0;
|
|
unsigned int reg_value = 0;
|
|
#ifdef ANALOG_HPTRIM
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), current AUDDEC_ELR_0 = 0x%x, mic_vinp_mv = %d\n",
|
|
__func__, reg_value, priv->dc_trim.mic_vinp_mv);
|
|
|
|
if (priv->dc_trim.mic_vinp_mv > MIC_VINP_4POLE_THRES_MV &&
|
|
((priv->debug_flag & DBG_DCTRIM_BYPASS_4POLE) == 0)) {
|
|
trim_setting = priv->dc_trim.spk_hp_4_pole_trim_setting;
|
|
} else {
|
|
trim_setting = priv->dc_trim.spk_hp_3_pole_trim_setting;
|
|
}
|
|
|
|
if (!priv->dc_trim.dc_compensation_disabled) {
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ELR_0, trim_setting);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), new AUDDEC_ELR_0 = 0x%x\n",
|
|
__func__, reg_value);
|
|
} else {
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ELR_0, 0x0);
|
|
dev_info(priv->dev, "%s(), priv->dc_trim.compensation_disabled = true\n",
|
|
__func__);
|
|
}
|
|
#endif
|
|
dev_info(priv->dev, "+%s()\n", __func__);
|
|
|
|
if (!priv->pull_down_stay_enable) {
|
|
/* Pull-down HPL/R to AVSS28_AUD */
|
|
hp_pull_down(priv, true);
|
|
}
|
|
/* release HP CMFB gate rstb */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4,
|
|
0x1 << 6, 0x1 << 6);
|
|
|
|
if (priv->apply_n12db_gain)
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0xff, 0x0004);
|
|
|
|
/* Audio left headphone input multiplexor selection : LOL */
|
|
set_hp_l_input_mux(priv, HP_INPUT_MUX_LOL);
|
|
|
|
/* Disable headphone short-circuit protection */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0xf0ff, 0x3000);
|
|
/* Disable lineout short-ckt protection */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1 << 4, 0x1 << 4);
|
|
|
|
/* Reduce ESD resistance of AU_REFN */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0xc000);
|
|
|
|
/* Set HPL/HPR gain to -10dB */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_10DB_REG);
|
|
/* Set LOLR/LOLL gain to -10dB */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON1, DL_GAIN_N_10DB_REG);
|
|
|
|
/* Turn on DA_600K_NCP_VA18 */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON1, 0x0001);
|
|
/* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON2, 0x002c);
|
|
/* Toggle RG_DIVCKS_CHG */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON0, 0x0001);
|
|
/* Set NCP soft start mode as default mode: 100us */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON4, 0x0002);
|
|
/* Enable NCP */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x0000);
|
|
usleep_range(250, 270);
|
|
|
|
/* Enable cap-less LDOs (1.5V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x1055, 0x1055);
|
|
/* Enable NV regulator (-1.2V) */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x0001);
|
|
usleep_range(100, 120);
|
|
|
|
/* Enable AUD_ZCD */
|
|
zcd_enable(priv, true, DEVICE_HP);
|
|
|
|
/* Enable IBIST */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055);
|
|
|
|
/* Set HP DR bias current optimization, 010: 6uA */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON11,
|
|
0xff80, 0x4900);
|
|
/* Set HP & ZCD bias current optimization */
|
|
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055);
|
|
/* Set HPP/N STB enhance circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0xc033);
|
|
|
|
if (priv->apply_n12db_gain) {
|
|
/* HP IVBUF (Vin path) de-gain enable: -12dB */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON10,
|
|
0xff, 0x04);
|
|
}
|
|
|
|
/* Set LO STB enhance circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1 << 8, 0x1 << 8);
|
|
/* Enable LO driver bias circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1 << 1, 0x1 << 1);
|
|
/* Enable LO driver core circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1, 0x1);
|
|
/* Set LOL gain to normal gain step by step */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON1, DL_GAIN_N_10DB_REG);
|
|
|
|
/* Switch HPL MUX to Line-out */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x3 << 8, 0x01 << 8);
|
|
/* Switch HPR MUX to DAC-R */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x3 << 10, 0x2 << 10);
|
|
/* Enable HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0xff, 0x0c);
|
|
/* Enable HP aux feedback loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0xff, 0x3c);
|
|
/* Enable HP aux CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xff00, 0x0c00);
|
|
/* Enable HP driver bias circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0xf0, 0xc0);
|
|
/* Enable HP driver core circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0xf0, 0xf0);
|
|
/* Short HP main output to HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0xff, 0xfc);
|
|
/* Enable HP main CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xff00, 0x0e00);
|
|
/* Disable HP aux CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xff00, 0x0200);
|
|
|
|
/* Select CMFB resistor bulk to AC mode */
|
|
/* Selec HS/LO cap size (6.5pF default) */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON10, 0x0000);
|
|
|
|
/* Enable HS driver bias circuits */
|
|
/* Disable HS main output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0010);
|
|
/* Enable LO driver bias circuits */
|
|
/* Disable LO main output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON7, 0x0010);
|
|
|
|
/* Enable LO main output stage */
|
|
enable_lo_buffer(priv, true);
|
|
set_speaker_gain(priv, priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL]);
|
|
|
|
/* Enable HP main output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x00ff, 0x00ff);
|
|
/* Enable HPR/L main output stage step by step */
|
|
hp_main_output_ramp(priv, true);
|
|
/* Reduce HP aux feedback loop gain step by step */
|
|
hp_aux_feedback_loop_gain_ramp(priv, true);
|
|
/* Disable HP aux feedback loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x00ff, 0x00cf);
|
|
/* apply volume setting */
|
|
headset_volume_ramp(priv,
|
|
DL_GAIN_N_10DB,
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL]);
|
|
/* Disable HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x00ff, 0x00c3);
|
|
/* Unshort HP main output to HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x00ff, 0x0003);
|
|
udelay(1000);
|
|
|
|
/* Enable AUD_CLK */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x1);
|
|
/* Enable Audio DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0xf, 0xf);
|
|
/* Enable low-noise mode of DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x1, 0x1);
|
|
udelay(100);
|
|
|
|
/* Switch LOL MUX to audio DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x3 << 2, 0x2 << 2);
|
|
|
|
/* Disable Pull-down HPL/R to AVSS28_AUD */
|
|
hp_pull_down(priv, false);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_hp_spk_disable(struct mt6358_priv *priv)
|
|
{
|
|
dev_info(priv->dev, "+%s()\n", __func__);
|
|
|
|
/* Pull-down HPL/R to AVSS28_AUD */
|
|
hp_pull_down(priv, true);
|
|
|
|
/* Disable low-noise mode of DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x1, 0x0);
|
|
|
|
/* Disable Audio DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x000f, 0x0000);
|
|
|
|
/* Disable AUD_CLK */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x0);
|
|
|
|
/* Short HP main output to HP aux output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fc3);
|
|
/* Enable HP aux output stage*/
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fcf);
|
|
|
|
/* decrease HPL/R gain to normal gain step by step */
|
|
headset_volume_ramp(priv,
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL],
|
|
DL_GAIN_N_10DB);
|
|
|
|
/* decrease LOL gain to minimum gain step by step */
|
|
regmap_update_bits(priv->regmap, MT6358_ZCD_CON1,
|
|
DL_GAIN_REG_MASK, DL_GAIN_N_10DB_REG);
|
|
|
|
/* set HP aux feedback loop gain to max */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xff00, 0xf200);
|
|
/* Enable HP aux feedback loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0xff, 0xff);
|
|
/* Reduce HP aux feedback loop gain */
|
|
hp_aux_feedback_loop_gain_ramp(priv, false);
|
|
|
|
/* decrease HPR/L main output stage step by step */
|
|
hp_main_output_ramp(priv, false);
|
|
|
|
/* HPR/HPL mux to open */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0xf << 8, 0x0 << 8);
|
|
/* LOL mux to open */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x3 << 2, 0x0 << 2);
|
|
|
|
/* Disable HP main output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3, 0x0);
|
|
/* Enable HP aux CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0x0f00, 0x0e00);
|
|
/* Disable HP main CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0x0f00, 0x0c00);
|
|
/* Unshort HP main output to HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x3 << 6, 0x0);
|
|
|
|
/* Disable HP driver core circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30c0);
|
|
/* Disable HP driver bias circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x3000);
|
|
/* Disable HP aux CMFB loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0);
|
|
/* Open HP aux feedback loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0xc);
|
|
/* Disable HP aux output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x0);
|
|
|
|
/* decrease LOL gain to minimum gain step by step */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON1, DL_GAIN_N_40DB_REG);
|
|
/* Disable LO driver core circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1, 0x0);
|
|
/* Disable LO driver bias circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1 << 1, 0x0 << 1);
|
|
|
|
/* Disable IBIST */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON12,
|
|
0x1 << 8, 0x1 << 8);
|
|
|
|
/* Disable AUD_ZCD */
|
|
zcd_enable(priv, false, DEVICE_HP);
|
|
|
|
/* Disable NV regulator (-1.2V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x1, 0x0);
|
|
/* Disable cap-less LDOs (1.5V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, 0x1055, 0x0);
|
|
/* Disable NCP */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x1, 0x1);
|
|
|
|
/* Set HPL/HPR gain to mute */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_40DB_REG);
|
|
/* Increase ESD resistance of AU_REFN */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON2,
|
|
0x1 << 14, 0x0);
|
|
|
|
/* Set HP CMFB gate rstb */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4,
|
|
0x1 << 6, 0x0);
|
|
|
|
if (!priv->pull_down_stay_enable) {
|
|
/* disable Pull-down HPL/R to AVSS28_AUD */
|
|
hp_pull_down(priv, false);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_hp_dual_spk_enable(struct mt6358_priv *priv)
|
|
{
|
|
unsigned int trim_setting = 0;
|
|
unsigned int reg_value = 0;
|
|
|
|
/* scrambler clock on enable, invert left channel */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xcfa1);
|
|
#ifdef ANALOG_HPTRIM
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), current AUDDEC_ELR_0 = 0x%x, mic_vinp_mv = %d\n",
|
|
__func__, reg_value, priv->dc_trim.mic_vinp_mv);
|
|
|
|
if (priv->dc_trim.mic_vinp_mv > MIC_VINP_4POLE_THRES_MV &&
|
|
((priv->debug_flag & DBG_DCTRIM_BYPASS_4POLE) == 0)) {
|
|
trim_setting = priv->dc_trim.spk_hp_4_pole_trim_setting;
|
|
} else {
|
|
trim_setting = priv->dc_trim.spk_hp_3_pole_trim_setting;
|
|
}
|
|
|
|
if (!priv->dc_trim.dc_compensation_disabled) {
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ELR_0, trim_setting);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), new AUDDEC_ELR_0 = 0x%x\n",
|
|
__func__, reg_value);
|
|
} else {
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ELR_0, 0x0);
|
|
dev_info(priv->dev, "%s(), priv->dc_trim.compensation_disabled = true\n",
|
|
__func__);
|
|
}
|
|
#endif
|
|
dev_info(priv->dev, "+%s()\n", __func__);
|
|
|
|
if (!priv->pull_down_stay_enable) {
|
|
/* Pull-down HPL/R to AVSS28_AUD */
|
|
hp_pull_down(priv, true);
|
|
}
|
|
|
|
/* release HP CMFB gate rstb */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4,
|
|
0x1 << 6, 0x1 << 6);
|
|
|
|
if (priv->apply_n12db_gain)
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0xff, 0x0004);
|
|
|
|
/* Audio left headphone input multiplexor selection : LOL */
|
|
set_hp_l_input_mux(priv, HP_INPUT_MUX_LOL);
|
|
|
|
/* Disable headphone short-circuit protection */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0xf0ff, 0x3000);
|
|
/* Disable lineout short-ckt protection */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1 << 4, 0x1 << 4);
|
|
|
|
/* Reduce ESD resistance of AU_REFN */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0xc000);
|
|
/* Set HPL/HPR gain to -10dB */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_10DB_REG);
|
|
/* Set LOLR/LOLL gain to -10dB */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON1, DL_GAIN_N_10DB_REG);
|
|
|
|
/* Turn on DA_600K_NCP_VA18 */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON1, 0x0001);
|
|
/* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON2, 0x002c);
|
|
/* Toggle RG_DIVCKS_CHG */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON0, 0x0001);
|
|
/* Set NCP soft start mode as default mode: 150us */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON4, 0x0002);
|
|
/* Enable NCP */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x0000);
|
|
usleep_range(250, 270);
|
|
|
|
/* Enable cap-less LDOs (1.5V), LCLDO local sense */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x1055, 0x1055);
|
|
/* Enable NV regulator (-1.2V) */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x0001);
|
|
usleep_range(100, 120);
|
|
|
|
/* Disable AUD_ZCD */
|
|
zcd_enable(priv, false, DEVICE_LO);
|
|
|
|
/* Enable IBIST */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055);
|
|
/* Set HP DR bias current optimization, 010: 6uA */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON11, 0x4900);
|
|
/* Set HP & ZCD bias current optimization */
|
|
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055);
|
|
/* Set HPP/N STB enhance circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0xc033);
|
|
|
|
if (priv->apply_n12db_gain) {
|
|
/* HP IVBUF (Vin path) de-gain enable: -12dB */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON10,
|
|
0xff, 0x04);
|
|
}
|
|
|
|
/* Set LO STB enhance circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1 << 8, 0x1 << 8);
|
|
/* Set HS STB enhance circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0090);
|
|
/* Enable LO driver bias circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1 << 1, 0x1 << 1);
|
|
/* Enable LO driver core circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1, 0x1);
|
|
/* Set LOL gain to normal gain step by step */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON1, DL_GAIN_N_10DB_REG);
|
|
|
|
/* Set HS output stage (3'b011 = 4x) for stereo lineout seneario */
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDDEC_ANA_CON10,
|
|
RG_ABIDEC_RSVD2_VAUDP15_MASK_SFT,
|
|
0x30 << RG_ABIDEC_RSVD2_VAUDP15_SFT);
|
|
|
|
/* Enable HS driver bias circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0092);
|
|
/* Enable HS driver core circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0093);
|
|
|
|
/* Set HS gain to normal gain step by step */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON3,
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL]);
|
|
|
|
/* Switch HPL MUX to Line-out */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x3 << 8, 0x03 << 8);
|
|
/* Switch HPR MUX to HS */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x3 << 10, 0x1 << 10);
|
|
/* Enable HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0xff, 0x0c);
|
|
/* Enable HP aux feedback loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0xff, 0x3c);
|
|
/* Enable HP aux CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xff00, 0x0c00);
|
|
/* Enable HP driver bias circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0xf0, 0xc0);
|
|
/* Enable HP driver core circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0xf0, 0xf0);
|
|
/* Short HP main output to HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0xff, 0xfc);
|
|
/* Enable HP main CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xff00, 0x0e00);
|
|
/* Disable HP aux CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xff00, 0x0200);
|
|
|
|
/* Select CMFB resistor bulk to AC mode */
|
|
/* Selec HS/LO cap size (6.5pF default) */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON10, 0x0000);
|
|
|
|
/* Enable LO main output stage */
|
|
enable_lo_buffer(priv, true);
|
|
set_speaker_gain(priv, priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL]);
|
|
|
|
/* Enable HP main output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x00ff, 0x00ff);
|
|
/* Enable HPR/L main output stage step by step */
|
|
hp_main_output_ramp(priv, true);
|
|
/* Reduce HP aux feedback loop gain step by step */
|
|
hp_aux_feedback_loop_gain_ramp(priv, true);
|
|
/* Disable HP aux feedback loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x00ff, 0x00cf);
|
|
/* apply volume setting */
|
|
headset_volume_ramp(priv,
|
|
DL_GAIN_N_10DB,
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL]);
|
|
/* Disable HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x00ff, 0x00c3);
|
|
/* Unshort HP main output to HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x00ff, 0x0003);
|
|
udelay(1000);
|
|
|
|
/* Enable AUD_CLK */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x1);
|
|
/* Enable Audio DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0xf, 0xf);
|
|
/* Enable low-noise mode of DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x1, 0x1);
|
|
udelay(100);
|
|
|
|
/* Switch LOL MUX to audio DAC R */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x3 << 2, 0x1 << 2);
|
|
/* Switch HS MUX to audio DAC L */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON6,
|
|
0x3 << 2, 0x2 << 2);
|
|
|
|
/* Disable Pull-down HPL/R to AVSS28_AUD */
|
|
hp_pull_down(priv, false);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_hp_dual_spk_disable(struct mt6358_priv *priv)
|
|
{
|
|
dev_info(priv->dev, "+%s()\n", __func__);
|
|
|
|
/* Pull-down HPL/R to AVSS28_AUD */
|
|
hp_pull_down(priv, true);
|
|
|
|
/* HPR/HPL mux to open */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0xf << 8, 0x0 << 8);
|
|
|
|
/* LOL mux to open */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x3 << 2, 0x0 << 2);
|
|
|
|
/* HS mux to open */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON6,
|
|
0x3 << 2, 0x0 << 2);
|
|
|
|
/* Disable low-noise mode of DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x1, 0x0);
|
|
|
|
/* Disable Audio DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0xf, 0x0);
|
|
|
|
/* Disable AUD_CLK */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x0);
|
|
|
|
/* Short HP main output to HP aux output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fc3);
|
|
/* Enable HP aux output stage*/
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fcf);
|
|
|
|
/* decrease HPL/R gain to normal gain step by step */
|
|
headset_volume_ramp(priv,
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL],
|
|
DL_GAIN_N_10DB);
|
|
/* decrease LOL gain to minimum gain step by step */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON1, DL_GAIN_N_10DB_REG);
|
|
|
|
/* set HP aux feedback loop gain to max */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xff00, 0xf200);
|
|
/* Enable HP aux feedback loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0xff, 0xff);
|
|
/* Reduce HP aux feedback loop gain */
|
|
hp_aux_feedback_loop_gain_ramp(priv, false);
|
|
|
|
/* decrease HPR/L main output stage step by step */
|
|
hp_main_output_ramp(priv, false);
|
|
|
|
/* Disable HP main output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3, 0x0);
|
|
/* Enable HP aux CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0x0f00, 0x0e00);
|
|
/* Disable HP main CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0x0f00, 0x0c00);
|
|
/* Unshort HP main output to HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x3 << 6, 0x0);
|
|
/* Disable HP driver core circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30c0);
|
|
/* Disable HP driver bias circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x3000);
|
|
/* Disable HP aux CMFB loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0);
|
|
/* Open HP aux feedback loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0xc);
|
|
/* Disable HP aux output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x0);
|
|
|
|
/* decrease LOL gain to minimum gain step by step */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON1, DL_GAIN_N_40DB_REG);
|
|
/* Disable LO driver core circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1, 0x0);
|
|
/* Disable LO driver bias circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1 << 1, 0x0 << 1);
|
|
|
|
/* Disable IBIST */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON12,
|
|
0x1 << 8, 0x1 << 8);
|
|
/* Disable NV regulator (-1.2V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x1, 0x0);
|
|
/* Disable cap-less LDOs (1.5V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, 0x1055, 0x0);
|
|
/* Disable NCP */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x1, 0x1);
|
|
|
|
/* Set HPL/HPR gain to mute */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_40DB_REG);
|
|
/* Increase ESD resistance of AU_REFN */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON2,
|
|
0x1 << 14, 0x0);
|
|
|
|
/* Set HP CMFB gate rstb */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4,
|
|
0x1 << 6, 0x0);
|
|
|
|
if (!priv->pull_down_stay_enable) {
|
|
/* disable Pull-down HPL/R to AVSS28_AUD */
|
|
hp_pull_down(priv, false);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_hp_impedance_enable(struct mt6358_priv *priv)
|
|
{
|
|
dev_info(priv->dev, "%s()\n", __func__);
|
|
|
|
/* release HP CMFB gate rstb */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4,
|
|
0x1 << 6, 0x1 << 6);
|
|
|
|
/* Disable headphone short-circuit protection */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x3000);
|
|
|
|
/* Reduce ESD resistance of AU_REFN */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4000);
|
|
|
|
/* Turn on DA_600K_NCP_VA18 */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON1, 0x0001);
|
|
/* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON2, 0x002c);
|
|
/* Toggle RG_DIVCKS_CHG */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON0, 0x0001);
|
|
/* Set NCP soft start mode as default mode: 150us */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON4, 0x0002);
|
|
/* Enable NCP */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x0000);
|
|
usleep_range(250, 270);
|
|
|
|
/* Enable cap-less LDOs (1.5V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x1055, 0x1055);
|
|
/* Enable NV regulator (-1.2V) */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x0001);
|
|
usleep_range(100, 120);
|
|
|
|
/* Enable AUD_ZCD */
|
|
zcd_enable(priv, true, DEVICE_HP);
|
|
|
|
/* Enable IBIST */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055);
|
|
/* Disable HPR/L STB enhance circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4000);
|
|
|
|
/* Disable Pull-down HPL/R to AVSS28_AUD */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON4, 0x0000);
|
|
|
|
/* Enable AUD_CLK */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x1);
|
|
/* Enable Audio L channel DAC */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x3009);
|
|
|
|
/* Enable Trim buffer VA28 reference */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0x00ff, 0x0002);
|
|
|
|
/* Enable HPDET circuit, */
|
|
/* select DACLP as HPDET input and HPR as HPDET output */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON8, 0x1900);
|
|
|
|
/* Enable TRIMBUF circuit, select HPR as TRIMBUF input */
|
|
/* Set TRIMBUF gain as 18dB */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON8, 0x1972);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_hp_impedance_disable(struct mt6358_priv *priv)
|
|
{
|
|
dev_info(priv->dev, "%s()\n", __func__);
|
|
|
|
/* disable HPDET circuit */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON8,
|
|
0xff00, 0x0000);
|
|
|
|
/* Disable Trim buffer VA28 reference */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0x00ff, 0x0000);
|
|
|
|
/* Disable Audio DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x000f, 0x0000);
|
|
|
|
/* Disable AUD_CLK */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x0);
|
|
|
|
/* Disable HP main output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3, 0x0);
|
|
|
|
/* Disable HP driver core circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x3 << 4, 0x0);
|
|
|
|
/* Disable HP driver bias circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x3 << 6, 0x0);
|
|
|
|
/* Disable HP aux CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xff << 8, 0x0);
|
|
|
|
/* Disable IBIST */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON12,
|
|
0x1 << 8, 0x1 << 8);
|
|
|
|
/* Disable AUD_ZCD */
|
|
zcd_enable(priv, false, DEVICE_HP);
|
|
|
|
/* Disable NV regulator (-1.2V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x1, 0x0);
|
|
/* Disable cap-less LDOs (1.5V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, 0x1055, 0x0);
|
|
/* Disable NCP */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x1, 0x1);
|
|
|
|
/* Set HPL/HPR gain to mute */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_10DB_REG);
|
|
|
|
/* Set HPP/N STB enhance circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0xff, 0x33);
|
|
|
|
/* Increase ESD resistance of AU_REFN */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON2,
|
|
0x1 << 14, 0x0);
|
|
|
|
/* Set HP CMFB gate rstb */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4,
|
|
0x1 << 6, 0x0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt_hp_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
|
|
int device = DEVICE_HP;
|
|
|
|
dev_info(priv->dev, "%s(), event 0x%x, dev_counter[DEV_HP] %d, mux %u\n",
|
|
__func__,
|
|
event,
|
|
priv->dev_counter[device],
|
|
mux);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
priv->dev_counter[device]++;
|
|
if (priv->dev_counter[device] > 1)
|
|
break; /* already enabled, do nothing */
|
|
else if (priv->dev_counter[device] <= 0)
|
|
dev_warn(priv->dev, "%s(), dev_counter[DEV_HP] %d <= 0\n",
|
|
__func__,
|
|
priv->dev_counter[device]);
|
|
|
|
priv->mux_select[MUX_HP_L] = mux;
|
|
|
|
if (mux == HP_MUX_HP)
|
|
mtk_hp_enable(priv);
|
|
else if (mux == HP_MUX_HPSPK)
|
|
mtk_hp_spk_enable(priv);
|
|
else if (mux == HP_MUX_HP_DUALSPK)
|
|
mtk_hp_dual_spk_enable(priv);
|
|
else if (mux == HP_MUX_HP_IMPEDANCE)
|
|
mtk_hp_impedance_enable(priv);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
priv->dev_counter[device]--;
|
|
if (priv->dev_counter[device] > 0) {
|
|
break; /* still being used, don't close */
|
|
} else if (priv->dev_counter[device] < 0) {
|
|
dev_warn(priv->dev, "%s(), dev_counter[DEV_HP] %d < 0\n",
|
|
__func__,
|
|
priv->dev_counter[device]);
|
|
priv->dev_counter[device] = 0;
|
|
break;
|
|
}
|
|
|
|
if (priv->mux_select[MUX_HP_L] == HP_MUX_HP)
|
|
mtk_hp_disable(priv);
|
|
else if (priv->mux_select[MUX_HP_L] == HP_MUX_HPSPK)
|
|
mtk_hp_spk_disable(priv);
|
|
else if (priv->mux_select[MUX_HP_L] == HP_MUX_HP_DUALSPK)
|
|
mtk_hp_dual_spk_disable(priv);
|
|
else if (priv->mux_select[MUX_HP_L] == HP_MUX_HP_IMPEDANCE)
|
|
mtk_hp_impedance_disable(priv);
|
|
|
|
priv->mux_select[MUX_HP_L] = mux;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt_lo_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
dev_info(priv->dev, "%s(), event 0x%x, mux %u\n",
|
|
__func__,
|
|
event,
|
|
dapm_kcontrol_get_value(w->kcontrols[0]));
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* Reduce ESD resistance of AU_REFN */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4000);
|
|
|
|
/* Turn on DA_600K_NCP_VA18 */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON1, 0x0001);
|
|
/* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON2, 0x002c);
|
|
/* Toggle RG_DIVCKS_CHG */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON0, 0x0001);
|
|
/* Set NCP soft start mode as default mode: 100us */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON4, 0x0003);
|
|
/* Enable NCP */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x0000);
|
|
usleep_range(250, 270);
|
|
|
|
/* Enable cap-less LDOs (1.5V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x1055, 0x1055);
|
|
/* Enable NV regulator (-1.2V) */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x0001);
|
|
usleep_range(100, 120);
|
|
|
|
/* Enable AUD_ZCD */
|
|
zcd_enable(priv, true, DEVICE_LO);
|
|
|
|
/* Disable lineout short-ckt protection */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1 << 4, 0x1 << 4);
|
|
|
|
/* Set LOLR/LOLL gain to -10dB */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON1, DL_GAIN_N_10DB_REG);
|
|
|
|
/* Enable IBIST */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055);
|
|
/* Set HP DR bias current optimization, 010: 6uA */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON11,
|
|
0xff80, 0x4900);
|
|
/* Set HP & ZCD bias current optimization */
|
|
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055);
|
|
/* Set LO STB enhance circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1 << 8, 0x1 << 8);
|
|
|
|
/* Disable HP main CMFB loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0000);
|
|
/* Select CMFB resistor bulk to AC mode */
|
|
/* Selec HS/LO cap size (6.5pF default) */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON10, 0x0000);
|
|
|
|
/* Enable LO driver bias circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1 << 1, 0x1 << 1);
|
|
/* Enable LO driver core circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1, 0x1);
|
|
|
|
/* Set LO gain to normal gain step by step */
|
|
set_speaker_gain(priv,
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL]);
|
|
|
|
/* Enable AUD_CLK */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13,
|
|
0x1, 0x1);
|
|
/* Enable Audio DAC R */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
RG_AUDDACRPWRUP_VAUDP15_MASK_SFT |
|
|
RG_AUD_DAC_PWR_UP_VA28_MASK_SFT, 0x0006);
|
|
|
|
/* Enable low-noise mode of DAC */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0001);
|
|
/* Switch LOL MUX to audio DAC R */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x3 << 2, 0x1 << 2);
|
|
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
/* Switch LOL MUX to open */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x3 << 2, 0x0 << 2);
|
|
/* Disable Audio DAC R */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
RG_AUDDACRPWRUP_VAUDP15_MASK_SFT |
|
|
RG_AUD_DAC_PWR_UP_VA28_MASK_SFT, 0x0000);
|
|
|
|
/* Disable AUD_CLK */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13,
|
|
0x1, 0x0);
|
|
|
|
/* decrease LO gain to minimum gain step by step */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON1,
|
|
DL_GAIN_N_40DB_REG);
|
|
|
|
/* Disable LO driver core circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1, 0x0);
|
|
|
|
/* Disable LO driver bias circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1 << 1, 0x0 << 1);
|
|
|
|
/* Disable HP aux CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xff << 8, 0x0);
|
|
|
|
/* Enable HP main CMFB Switch */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xff << 8, 0x2 << 8);
|
|
|
|
/* Disable IBIST */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON12,
|
|
0x1 << 8, 0x1 << 8);
|
|
|
|
/* Disable AUD_ZCD */
|
|
zcd_enable(priv, false, DEVICE_LO);
|
|
|
|
/* Disable NV regulator (-1.2V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON15,
|
|
0x1, 0x0);
|
|
/* Disable cap-less LDOs (1.5V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x1055, 0x0);
|
|
/* Disable NCP */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3,
|
|
0x1, 0x1);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt_rcv_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
dev_info(priv->dev, "%s(), event 0x%x, mux %u\n",
|
|
__func__,
|
|
event,
|
|
dapm_kcontrol_get_value(w->kcontrols[0]));
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* Reduce ESD resistance of AU_REFN */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4000);
|
|
|
|
/* Turn on DA_600K_NCP_VA18 */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON1, 0x0001);
|
|
/* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON2, 0x002c);
|
|
/* Toggle RG_DIVCKS_CHG */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON0, 0x0001);
|
|
/* Set NCP soft start mode as default mode: 100us */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON4, 0x0003);
|
|
/* Enable NCP */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x0000);
|
|
usleep_range(250, 270);
|
|
|
|
/* Enable cap-less LDOs (1.5V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x1055, 0x1055);
|
|
/* Enable NV regulator (-1.2V) */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x0001);
|
|
usleep_range(100, 120);
|
|
|
|
/* Enable AUD_ZCD */
|
|
zcd_enable(priv, true, DEVICE_RCV);
|
|
|
|
/* Disable handset short-circuit protection */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0010);
|
|
|
|
/* Enable IBIST */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055);
|
|
/* Set HP DR bias current optimization, 010: 6uA */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON11,
|
|
0xff80, 0x4900);
|
|
/* Set HP & ZCD bias current optimization */
|
|
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055);
|
|
/* Set HS STB enhance circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0090);
|
|
|
|
/* Disable HP main CMFB loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0000);
|
|
/* Select CMFB resistor bulk to AC mode */
|
|
/* Selec HS/LO cap size (6.5pF default) */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON10, 0x0000);
|
|
|
|
/* Enable HS driver bias circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0092);
|
|
/* Enable HS driver core circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0093);
|
|
|
|
/* Set HS gain to normal gain step by step */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON3,
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL]);
|
|
/* Enable AUD_CLK */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13,
|
|
0x1, 0x1);
|
|
|
|
/* Enable Audio DAC L */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
RG_AUDDACLPWRUP_VAUDP15_MASK_SFT |
|
|
RG_AUD_DAC_PWL_UP_VA28_MASK_SFT, 0x0009);
|
|
|
|
/* Enable low-noise mode of DAC */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0001);
|
|
/* Switch HS MUX to audio DAC L */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x009b);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
/* HS mux to open */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON6,
|
|
RG_AUDHSMUXINPUTSEL_VAUDP15_MASK_SFT,
|
|
RCV_MUX_OPEN);
|
|
|
|
/* Disable Audio DAC L */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
RG_AUDDACLPWRUP_VAUDP15_MASK_SFT |
|
|
RG_AUD_DAC_PWL_UP_VA28_MASK_SFT, 0x0000);
|
|
|
|
/* Disable AUD_CLK */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13,
|
|
0x1, 0x0);
|
|
|
|
/* decrease HS gain to minimum gain step by step */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON3, DL_GAIN_N_40DB);
|
|
|
|
/* Disable HS driver core circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON6,
|
|
0x1, 0x0);
|
|
|
|
/* Disable HS driver bias circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON6,
|
|
0x1 << 1, 0x0000);
|
|
|
|
/* Disable HP aux CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xff << 8, 0x0);
|
|
|
|
/* Enable HP main CMFB Switch */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xff << 8, 0x2 << 8);
|
|
|
|
/* Disable IBIST */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON12,
|
|
0x1 << 8, 0x1 << 8);
|
|
|
|
/* Disable AUD_ZCD */
|
|
zcd_enable(priv, false, DEVICE_RCV);
|
|
|
|
/* Disable NV regulator (-1.2V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON15,
|
|
0x1, 0x0);
|
|
/* Disable cap-less LDOs (1.5V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x1055, 0x0);
|
|
/* Disable NCP */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3,
|
|
0x1, 0x1);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt_aif_out_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
dev_dbg(priv->dev, "%s(), event 0x%x, rate %d\n",
|
|
__func__, event, priv->ul_rate);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
capture_gpio_set(priv);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
capture_gpio_reset(priv);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt_adc_supply_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
unsigned int mic_type = priv->mux_select[MUX_MIC_TYPE];
|
|
|
|
dev_info(priv->dev, "%s(), event 0x%x, vow_enable: %d\n",
|
|
__func__, event, priv->vow_enable);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* Enable audio ADC CLKGEN */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13,
|
|
0x1 << 5, 0x1 << 5);
|
|
if (IS_AMIC_BASE(mic_type) && priv->vow_enable) {
|
|
dev_info(priv->dev, "%s(), vow mode\n", __func__);
|
|
/* ADC CLK from CLKGEN: 3.25MHz clock in, 1.625MHz data out */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON3,
|
|
0x0009);
|
|
} else {
|
|
/* ADC CLK from CLKGEN (13MHz) */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON3,
|
|
0x0000);
|
|
}
|
|
/* Enable LCLDO_ENC 1P8V */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x2500, 0x0100);
|
|
/* LCLDO_ENC remote sense */
|
|
/* Enable LCLDO_ENC Ref. gen. */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x2500, 0x2500);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
/*LCLDO_ENC remote sense off */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x2500, 0x0100);
|
|
/* disable LCLDO_ENC 1P8V */
|
|
/* Disable LCLDO_ENC Ref. gen. */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x2500, 0x0000);
|
|
|
|
/* ADC CLK from CLKGEN (13MHz) */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON3, 0x0000);
|
|
/* disable audio ADC CLKGEN */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13,
|
|
0x1 << 5, 0x0 << 5);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt_vow_ldo_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
dev_info(priv->dev, "%s(), event 0x%x, MIC_TYPE %x\n",
|
|
__func__, event, priv->mux_select[MUX_MIC_TYPE]);
|
|
|
|
if (!(IS_AMIC_BASE(priv->mux_select[MUX_MIC_TYPE]))) {
|
|
dev_info(priv->dev, "%s(), no AMIC, return\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* Enable audio uplink LPW mode */
|
|
/* Enable Audio ADC 1st Stage LPW */
|
|
/* Enable Audio ADC 2nd & 3rd LPW */
|
|
/* Enable Audio ADC flash Audio ADC flash */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
RG_CLKSQ_EN_VOW_MASK_SFT,
|
|
0x1 << RG_CLKSQ_EN_VOW_SFT);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
/* Disable audio uplink LPW mode */
|
|
/* Disable Audio ADC 1st Stage LPW */
|
|
/* Disable Audio ADC 2nd & 3rd LPW */
|
|
/* Disable Audio ADC flash Audio ADC flash */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
RG_CLKSQ_EN_VOW_MASK_SFT,
|
|
0x0 << RG_CLKSQ_EN_VOW_SFT);
|
|
dev_info(priv->dev, "%s(), set vow disable at the last vow capture widget\n",
|
|
__func__);
|
|
priv->vow_enable = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt_vow_out_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
dev_info(priv->dev, "%s(), event 0x%x\n", __func__, event);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_WILL_PMU:
|
|
priv->vow_enable = 1;
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* vow gpio set */
|
|
regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3_CLR,
|
|
0xffff, 0xffff);
|
|
regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3_SET,
|
|
0xffff, 0x0120);
|
|
regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3,
|
|
0xffff, 0x0120);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
/* vow gpio clear */
|
|
regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3_CLR,
|
|
0xffff, 0xffff);
|
|
regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3,
|
|
0xffff, 0x0000);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt6358_vow_cfg_enable(struct mt6358_priv *priv)
|
|
{
|
|
unsigned int mic_type = priv->mux_select[MUX_MIC_TYPE];
|
|
|
|
dev_info(priv->dev, "%s(), mic_type: %d, vow_dmic_lp: %d\n", __func__,
|
|
mic_type, priv->vow_dmic_lp);
|
|
|
|
/* Enable vow cfg setting */
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_CFG0,
|
|
priv->reg_afe_vow_cfg0);
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_CFG1,
|
|
priv->reg_afe_vow_cfg1);
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_CFG2,
|
|
priv->reg_afe_vow_cfg2);
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_CFG3,
|
|
priv->reg_afe_vow_cfg3);
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_VOW_CFG4,
|
|
0x000f, priv->reg_afe_vow_cfg4);
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_CFG5,
|
|
priv->reg_afe_vow_cfg5);
|
|
|
|
if (mic_type == MIC_TYPE_MUX_DMIC) {
|
|
if (priv->vow_dmic_lp) {
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_VOW_CFG4,
|
|
0xfff0, 0x024e);
|
|
/* vow posdiv and cic mode configure*/
|
|
/* LP DMIC settings : 812.5k */
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_POSDIV_CFG0, 0x0c0a);
|
|
/* VOW_DIGMIC_ON */
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_VOW_TOP,
|
|
0x20c0, 0x20c0);
|
|
} else {
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_VOW_CFG4,
|
|
0xfff0, 0x029e);
|
|
/* vow posdiv and cic mode configure */
|
|
/* DMIC settings : 1600k */
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_POSDIV_CFG0, 0x0c00);
|
|
/* VOW_DIGMIC_ON */
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_VOW_TOP,
|
|
0x20c0, 0x20c0);
|
|
}
|
|
} else {
|
|
/* gamma K value and vow mtkaif tx setting */
|
|
/* VOW_TXIF_MONO = 1 */
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_VOW_CFG4,
|
|
0xfff0, 0x029e);
|
|
/* vow posdiv and cic mode configure */
|
|
/* AMIC settings : 1600k */
|
|
regmap_write(priv->regmap, MT6358_AFE_VOW_POSDIV_CFG0, 0x0c00);
|
|
/* VOW_DIGMIC_OFF */
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_VOW_TOP,
|
|
0x20c0, 0x0000);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void mt6358_vow_cfg_disable(struct mt6358_priv *priv)
|
|
{
|
|
unsigned int mic_type = priv->mux_select[MUX_MIC_TYPE];
|
|
|
|
dev_info(priv->dev, "%s(), mic_type 0x%x\n", __func__, mic_type);
|
|
|
|
/* VOW_DIGMIC_OFF */
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_VOW_TOP,
|
|
0x20c0, 0x0000);
|
|
}
|
|
|
|
static int mt6358_amic_enable(struct mt6358_priv *priv)
|
|
{
|
|
unsigned int mic_type = priv->mux_select[MUX_MIC_TYPE];
|
|
unsigned int mux_pga_l = priv->mux_select[MUX_PGA_L];
|
|
unsigned int mux_pga_r = priv->mux_select[MUX_PGA_R];
|
|
int mic_gain_l = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1];
|
|
int mic_gain_r = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2];
|
|
unsigned int reg_value = 0, rc_1 = 0, rc_2 = 0;
|
|
|
|
dev_info(priv->dev, "%s(), mux, mic %u, pga l %u, pga r %u, mic_gain l %d, r %d\n",
|
|
__func__, mic_type, mux_pga_l, mux_pga_r,
|
|
mic_gain_l, mic_gain_r);
|
|
|
|
if (IS_DCC_BASE(mic_type)) {
|
|
/* DCC 50k CLK (from 26M) */
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062);
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062);
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2060);
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2061);
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG1, 0x0100);
|
|
}
|
|
|
|
/* mic bias 0 */
|
|
if (mux_pga_l == PGA_MUX_AIN0 || mux_pga_l == PGA_MUX_AIN2 ||
|
|
mux_pga_r == PGA_MUX_AIN0 || mux_pga_r == PGA_MUX_AIN2) {
|
|
switch (mic_type) {
|
|
case MIC_TYPE_MUX_DCC_ECM_DIFF:
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON9,
|
|
0xff00, 0x7700);
|
|
break;
|
|
case MIC_TYPE_MUX_DCC_ECM_SINGLE:
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON9,
|
|
0xff00, 0x1100);
|
|
break;
|
|
default:
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON9,
|
|
0xff00, 0x0000);
|
|
break;
|
|
}
|
|
/* Enable MICBIAS0, MISBIAS0 = 1P9V */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON9,
|
|
0xff, 0x21);
|
|
}
|
|
|
|
/* mic bias 1 */
|
|
if (mux_pga_l == PGA_MUX_AIN1 || mux_pga_r == PGA_MUX_AIN1) {
|
|
/* Enable MICBIAS1, MISBIAS1 = 2P6V */
|
|
if (mic_type == MIC_TYPE_MUX_DCC_ECM_SINGLE)
|
|
regmap_write(priv->regmap,
|
|
MT6358_AUDENC_ANA_CON10, 0x0161);
|
|
else
|
|
regmap_write(priv->regmap,
|
|
MT6358_AUDENC_ANA_CON10, 0x0061);
|
|
}
|
|
|
|
/* set mic pga gain */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDPREAMPLGAIN_MASK_SFT,
|
|
mic_gain_l << RG_AUDPREAMPLGAIN_SFT);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
RG_AUDPREAMPRGAIN_MASK_SFT,
|
|
mic_gain_r << RG_AUDPREAMPRGAIN_SFT);
|
|
|
|
if (IS_DCC_BASE(mic_type)) {
|
|
/* Audio L/R preamplifier DCC precharge */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
0xf8fd, 0x0004);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
0xf8fd, 0x0004);
|
|
} else {
|
|
/* reset reg */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
0xf8fd, 0x0000);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
0xf8fd, 0x0000);
|
|
}
|
|
|
|
if (mux_pga_l != PGA_MUX_NONE) {
|
|
/* L preamplifier input sel */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDPREAMPLINPUTSEL_MASK_SFT,
|
|
mux_pga_l << RG_AUDPREAMPLINPUTSEL_SFT);
|
|
|
|
/* L preamplifier enable */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDPREAMPLON_MASK_SFT,
|
|
0x1 << RG_AUDPREAMPLON_SFT);
|
|
|
|
/* Audio L ADC input selection: Left Preamplifier */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDADCLINPUTSEL_MASK_SFT,
|
|
ADC_MUX_PREAMPLIFIER <<
|
|
RG_AUDADCLINPUTSEL_SFT);
|
|
|
|
usleep_range(1000, 1050);
|
|
/* Audio L ADC power on */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDADCLPWRUP_MASK_SFT,
|
|
0x1 << RG_AUDADCLPWRUP_SFT);
|
|
}
|
|
|
|
if (mux_pga_r != PGA_MUX_NONE) {
|
|
/* R preamplifier input sel */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
RG_AUDPREAMPRINPUTSEL_MASK_SFT,
|
|
mux_pga_r << RG_AUDPREAMPRINPUTSEL_SFT);
|
|
|
|
/* R preamplifier enable */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
RG_AUDPREAMPRON_MASK_SFT,
|
|
0x1 << RG_AUDPREAMPRON_SFT);
|
|
|
|
/* R ADC input sel : R PGA. Enable audio R ADC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
RG_AUDADCRINPUTSEL_MASK_SFT,
|
|
ADC_MUX_PREAMPLIFIER <<
|
|
RG_AUDADCRINPUTSEL_SFT);
|
|
usleep_range(1000, 1050);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
RG_AUDADCRPWRUP_MASK_SFT,
|
|
0x1 << RG_AUDADCRPWRUP_SFT);
|
|
}
|
|
|
|
if (IS_DCC_BASE(mic_type)) {
|
|
usleep_range(100, 150);
|
|
/* Audio L preamplifier DCC precharge off */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDPREAMPLDCPRECHARGE_MASK_SFT, 0x0);
|
|
/* Audio R preamplifier DCC precharge off */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
RG_AUDPREAMPRDCPRECHARGE_MASK_SFT, 0x0);
|
|
|
|
/* Short body to ground in PGA */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON3,
|
|
0x1 << 12, 0x0);
|
|
}
|
|
|
|
usleep_range(500, 520);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON12, ®_value);
|
|
rc_1 = reg_value & 0x1f;
|
|
rc_2 = (reg_value >> 8) & 0x1f;
|
|
dev_dbg(priv->dev, "%s(), 1: MT6358_AUDENC_CON12(rc2, rc1) = 0x%x(0x%x, 0x%x)\n",
|
|
__func__, reg_value, rc_2, rc_1);
|
|
if ((rc_2 == 0) || (rc_1 == 0) || (rc_1 == 0x1f) || (rc_2 == 0x1f)) {
|
|
/* Disable audio L ADC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDADCLPWRUP_MASK_SFT,
|
|
0x0 << RG_AUDADCLPWRUP_SFT);
|
|
/* Disable audio R ADC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
RG_AUDADCRPWRUP_MASK_SFT,
|
|
0x0 << RG_AUDADCRPWRUP_SFT);
|
|
/* Enable audio L ADC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDADCLPWRUP_MASK_SFT,
|
|
0x1 << RG_AUDADCLPWRUP_SFT);
|
|
/* Enable audio R ADC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
RG_AUDADCRPWRUP_MASK_SFT,
|
|
0x1 << RG_AUDADCRPWRUP_SFT);
|
|
}
|
|
|
|
usleep_range(500, 520);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON12, ®_value);
|
|
dev_dbg(priv->dev, "%s(), final: MT6358_AUDENC_CON12 = 0x%x\n",
|
|
__func__, reg_value);
|
|
|
|
/* here to set digital part */
|
|
mt6358_mtkaif_tx_enable(priv);
|
|
|
|
/* UL dmic setting off */
|
|
regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_H, 0x0000);
|
|
|
|
/* UL turn on */
|
|
regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_L, 0x0001);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void mt6358_amic_disable(struct mt6358_priv *priv)
|
|
{
|
|
unsigned int mic_type = priv->mux_select[MUX_MIC_TYPE];
|
|
unsigned int mux_pga_l = priv->mux_select[MUX_PGA_L];
|
|
unsigned int mux_pga_r = priv->mux_select[MUX_PGA_R];
|
|
|
|
dev_info(priv->dev, "%s(), mux, mic %u, pga l %u, pga r %u\n",
|
|
__func__, mic_type, mux_pga_l, mux_pga_r);
|
|
|
|
/* UL turn off */
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_UL_SRC_CON0_L,
|
|
0x0001, 0x0000);
|
|
|
|
/* disable aud_pad TX fifos */
|
|
mt6358_mtkaif_tx_disable(priv);
|
|
|
|
/* L ADC input sel : off, disable L ADC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
0xf000, 0x0000);
|
|
/* L preamplifier input sel : off, L PGA 0 dB gain */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
0x0ff9, 0x0000);
|
|
|
|
/* disable L preamplifier DCC precharge */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
0x1 << 2, 0x0);
|
|
|
|
/* R ADC input sel : off, disable R ADC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
0xf000, 0x0000);
|
|
/* R preamplifier input sel : off, R PGA 0 dB gain */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
0x0ff9, 0x0000);
|
|
|
|
/* disable R preamplifier DCC precharge */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
0x1 << 2, 0x0);
|
|
|
|
/* mic bias */
|
|
/* Disable MICBIAS0, MISBIAS0 = 1P7V */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0000);
|
|
|
|
/* Disable MICBIAS1 */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON10,
|
|
0x0001, 0x0000);
|
|
|
|
if (IS_DCC_BASE(mic_type)) {
|
|
/* dcclk_gen_on=1'b0 */
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2060);
|
|
/* dcclk_pdn=1'b1 */
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062);
|
|
/* dcclk_ref_ck_sel=2'b00 */
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062);
|
|
/* dcclk_div=11'b00100000011 */
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062);
|
|
}
|
|
}
|
|
|
|
static int mt6358_dmic_enable(struct mt6358_priv *priv)
|
|
{
|
|
dev_info(priv->dev, "%s()\n", __func__);
|
|
|
|
/* mic bias */
|
|
/* Enable MICBIAS0, MISBIAS0 = 1P9V */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0021);
|
|
|
|
/* RG_BANDGAPGEN=1'b0 */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON10,
|
|
0x1 << 12, 0x0);
|
|
|
|
/* DMIC enable */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON8, 0x0005);
|
|
|
|
/* here to set digital part */
|
|
mt6358_mtkaif_tx_enable(priv);
|
|
|
|
/* UL dmic setting */
|
|
if (priv->dmic_one_wire_mode)
|
|
regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_H, 0x0400);
|
|
else
|
|
regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_H, 0x0080);
|
|
|
|
/* UL turn on */
|
|
regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_L, 0x0003);
|
|
|
|
/* Prevent pop noise form dmic hw */
|
|
msleep(100);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void mt6358_dmic_disable(struct mt6358_priv *priv)
|
|
{
|
|
dev_info(priv->dev, "%s()\n", __func__);
|
|
|
|
/* UL turn off */
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_UL_SRC_CON0_L,
|
|
0x0003, 0x0000);
|
|
|
|
/* disable aud_pad TX fifos */
|
|
mt6358_mtkaif_tx_disable(priv);
|
|
|
|
/* DMIC disable */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON8, 0x0000);
|
|
|
|
/* mic bias */
|
|
/* MISBIAS0 = 1P7V */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0001);
|
|
|
|
/* RG_BANDGAPGEN=1'b0 */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON10,
|
|
0x1 << 12, 0x0);
|
|
|
|
/* MICBIA0 disable */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0000);
|
|
}
|
|
|
|
static int mt6358_vow_amic_enable(struct mt6358_priv *priv)
|
|
{
|
|
unsigned int mic_type = priv->mux_select[MUX_MIC_TYPE];
|
|
unsigned int mux_pga_l = priv->mux_select[MUX_PGA_L];
|
|
unsigned int rc_value = 0, rc_l = 0;
|
|
|
|
dev_info(priv->dev, "%s(), mux, mic %u, pga l %u\n",
|
|
__func__, mic_type, mux_pga_l);
|
|
|
|
if (IS_DCC_BASE(mic_type)) {
|
|
/* DCC 50k CLK (from 26M) */
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062);
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062);
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2060);
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2061);
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG1, 0x0100);
|
|
}
|
|
|
|
/* mic bias 0 */
|
|
if (mux_pga_l == PGA_MUX_AIN0) {
|
|
switch (mic_type) {
|
|
case MIC_TYPE_MUX_DCC_ECM_DIFF:
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDENC_ANA_CON9,
|
|
0xff00, 0x7700);
|
|
break;
|
|
case MIC_TYPE_MUX_DCC_ECM_SINGLE:
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDENC_ANA_CON9,
|
|
0xff00, 0x1100);
|
|
break;
|
|
default:
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDENC_ANA_CON9,
|
|
0xff00, 0x0000);
|
|
break;
|
|
}
|
|
/* Enable MICBIAS0, MISBIAS0 = 1P9V */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON9,
|
|
0xff, 0x25);
|
|
}
|
|
/* mic bias 1 */
|
|
if (mux_pga_l == PGA_MUX_AIN1) {
|
|
/* Enable MICBIAS1, MISBIAS1 = 2P6V */
|
|
if (mic_type == MIC_TYPE_MUX_DCC_ECM_SINGLE)
|
|
regmap_write(priv->regmap,
|
|
MT6358_AUDENC_ANA_CON10, 0x0161);
|
|
else
|
|
regmap_write(priv->regmap,
|
|
MT6358_AUDENC_ANA_CON10, 0x0061);
|
|
}
|
|
/* mic bias 0 */
|
|
if (mux_pga_l == PGA_MUX_AIN2) {
|
|
switch (mic_type) {
|
|
case MIC_TYPE_MUX_DCC_ECM_DIFF:
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDENC_ANA_CON9,
|
|
0xff00, 0x7700);
|
|
break;
|
|
case MIC_TYPE_MUX_DCC_ECM_SINGLE:
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDENC_ANA_CON9,
|
|
0xff00, 0x1100);
|
|
break;
|
|
default:
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDENC_ANA_CON9,
|
|
0xff00, 0x0000);
|
|
break;
|
|
}
|
|
/* Enable MICBIAS0, MISBIAS0 = 1P9V */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON9,
|
|
0xff, 0x25);
|
|
}
|
|
/* Audio L preamplifier gain adjust: 24db */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDPREAMPLGAIN_MASK_SFT,
|
|
0x04 << RG_AUDPREAMPLGAIN_SFT);
|
|
|
|
if (IS_DCC_BASE(mic_type)) {
|
|
/* Audio L preamplifier DCC precharge */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
0xf8fd, 0x0004);
|
|
} else {
|
|
/* reset reg */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
0xf8fd, 0x0000);
|
|
|
|
}
|
|
if (mux_pga_l != PGA_MUX_NONE) {
|
|
/* L preamplifier input sel */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDPREAMPLINPUTSEL_MASK_SFT,
|
|
mux_pga_l << RG_AUDPREAMPLINPUTSEL_SFT);
|
|
|
|
/* Audio L preamplifier enable */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDPREAMPLON_MASK_SFT,
|
|
0x1 << RG_AUDPREAMPLON_SFT);
|
|
|
|
/* Audio L ADC input selection: Left Preamplifier */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDADCLINPUTSEL_MASK_SFT,
|
|
ADC_MUX_PREAMPLIFIER <<
|
|
RG_AUDADCLINPUTSEL_SFT);
|
|
usleep_range(1000, 1050);
|
|
/* Audio L ADC power on */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDADCLPWRUP_MASK_SFT,
|
|
0x1 << RG_AUDADCLPWRUP_SFT);
|
|
/* Short body to ground in PGA */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON3,
|
|
0x1 << 12, 0x0);
|
|
}
|
|
|
|
usleep_range(500, 520);
|
|
/* adc reset mechanism */
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON12, &rc_value);
|
|
/* AUDENC_CON12[4:0] => RGS_AUDRCTUNELREAD */
|
|
rc_l = rc_value & 0x1f;
|
|
dev_dbg(priv->dev, "%s(), MT6358_AUDENC_ANA_CON12(rc_l) = 0x%x(0x%x)\n",
|
|
__func__, rc_value, rc_l);
|
|
if (rc_l == 0x0 || rc_l == 0x1f) {
|
|
dev_info(priv->dev, "%s(), calibration fail, resetting...\n",
|
|
__func__);
|
|
/* Disable audio L ADC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDADCLPWRUP_MASK_SFT,
|
|
0x0 << RG_AUDADCLPWRUP_SFT);
|
|
/* Enable audio L ADC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDADCLPWRUP_MASK_SFT,
|
|
0x1 << RG_AUDADCLPWRUP_SFT);
|
|
}
|
|
usleep_range(500, 520);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON12, &rc_value);
|
|
dev_dbg(priv->dev, "%s(), after reset: MT6358_AUDENC_ANA_CON12(rc_l) = 0x%x(0x%x)\n",
|
|
__func__, rc_value, rc_l);
|
|
|
|
if (IS_DCC_BASE(mic_type)) {
|
|
usleep_range(100, 150);
|
|
/* Audio L preamplifier DCC precharge off */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDPREAMPLDCPRECHARGE_MASK_SFT, 0x0);
|
|
/* Short body to ground in PGA */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON3,
|
|
0x1 << 12, 0x0);
|
|
}
|
|
usleep_range(1000, 1200);
|
|
/* Enable audio uplink LPW mode */
|
|
/* Enable Audio ADC 1st Stage LPW */
|
|
/* Enable Audio ADC 2nd & 3rd LPW */
|
|
/* Enable Audio ADC flash Audio ADC flash */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON2,
|
|
0x0039, 0x0039);
|
|
dev_info(priv->dev, "%s(), mt_vow_aud_lpw_enable 0x39\n",
|
|
__func__);
|
|
return 0;
|
|
}
|
|
|
|
static int mt6358_vow_amic_disable(struct mt6358_priv *priv)
|
|
{
|
|
unsigned int mic_type = priv->mux_select[MUX_MIC_TYPE];
|
|
unsigned int mux_pga_l = priv->mux_select[MUX_PGA_L];
|
|
|
|
dev_info(priv->dev, "%s(), mux, mic %u, pga l %u\n",
|
|
__func__, mic_type, mux_pga_l);
|
|
/* Disable audio uplink LPW mode */
|
|
/* Disable Audio ADC 1st Stage LPW */
|
|
/* Disable Audio ADC 2nd & 3rd LPW */
|
|
/* Disable Audio ADC flash Audio ADC flash */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON2,
|
|
0x0039, 0x0000);
|
|
dev_info(priv->dev, "%s(), mt_vow_aud_lpw_disable 0x0\n",
|
|
__func__);
|
|
/* L ADC input sel : off, disable L ADC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
0xf000, 0x0000);
|
|
|
|
/* L preamplifier input sel : off, L PGA 0 dB gain */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
0x0ff9, 0x0000);
|
|
|
|
/* disable L preamplifier DCC precharge */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
0x1 << 2, 0x0);
|
|
|
|
/* mic bias */
|
|
/* Disable MICBIAS0, MISBIAS0 = 1P7V */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0000);
|
|
/* Disable MICBIAS1, MISBIAS1 = 1P7V */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON10, 0x0000);
|
|
|
|
if (IS_DCC_BASE(mic_type)) {
|
|
/* dcclk_gen_on=1'b0 */
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2060);
|
|
/* dcclk_pdn=1'b1 */
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062);
|
|
/* dcclk_ref_ck_sel=2'b00 */
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062);
|
|
/* dcclk_div=11'b00100000011 */
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int mt6358_vow_dmic_enable(struct mt6358_priv *priv)
|
|
{
|
|
dev_info(priv->dev, "%s()\n", __func__);
|
|
/* mic bias */
|
|
/* Enable MICBIAS0, MISBIAS0 = 1P9V */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0025);
|
|
|
|
/* DMIC enable */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON8, 0x0005);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt6358_vow_dmic_disable(struct mt6358_priv *priv)
|
|
{
|
|
dev_info(priv->dev, "%s()\n", __func__);
|
|
/* DMIC disable */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON8, 0x0004);
|
|
|
|
/* mic bias */
|
|
/* MISBIAS0 = 1P7V */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0000);
|
|
return 0;
|
|
}
|
|
|
|
static void mt6358_restore_pga(struct mt6358_priv *priv)
|
|
{
|
|
unsigned int gain_l, gain_r;
|
|
|
|
gain_l = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1];
|
|
gain_r = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2];
|
|
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDPREAMPLGAIN_MASK_SFT,
|
|
gain_l << RG_AUDPREAMPLGAIN_SFT);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
RG_AUDPREAMPRGAIN_MASK_SFT,
|
|
gain_r << RG_AUDPREAMPRGAIN_SFT);
|
|
}
|
|
|
|
static int mt_mic_bias_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
unsigned int mux = priv->mux_select[MUX_MIC_TYPE];
|
|
unsigned int mux_pga_l = priv->mux_select[MUX_PGA_L];
|
|
unsigned int mux_pga_r = priv->mux_select[MUX_PGA_R];
|
|
|
|
dev_dbg(priv->dev, "%s(), event 0x%x, mux %u, vow_enable: %d\n",
|
|
__func__, event, mux, priv->vow_enable);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
if (priv->vow_enable) {
|
|
if ((mux == MIC_TYPE_MUX_DMIC) &&
|
|
!((mux_pga_l == PGA_MUX_AIN1 || mux_pga_r == PGA_MUX_AIN1))) {
|
|
mt6358_vow_dmic_enable(priv);
|
|
mt6358_vow_cfg_enable(priv);
|
|
} else {
|
|
mt6358_vow_amic_enable(priv);
|
|
mt6358_vow_cfg_enable(priv);
|
|
}
|
|
} else {
|
|
if ((mux == MIC_TYPE_MUX_DMIC) &&
|
|
!((mux_pga_l == PGA_MUX_AIN1 || mux_pga_r == PGA_MUX_AIN1)))
|
|
mt6358_dmic_enable(priv);
|
|
else
|
|
mt6358_amic_enable(priv);
|
|
}
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
if (priv->vow_enable) {
|
|
if ((mux == MIC_TYPE_MUX_DMIC) &&
|
|
!((mux_pga_l == PGA_MUX_AIN1 || mux_pga_r == PGA_MUX_AIN1))) {
|
|
mt6358_vow_cfg_disable(priv);
|
|
mt6358_vow_dmic_disable(priv);
|
|
} else {
|
|
mt6358_vow_cfg_disable(priv);
|
|
mt6358_vow_amic_disable(priv);
|
|
}
|
|
} else {
|
|
if ((mux == MIC_TYPE_MUX_DMIC) &&
|
|
!((mux_pga_l == PGA_MUX_AIN1 || mux_pga_r == PGA_MUX_AIN1)))
|
|
mt6358_dmic_disable(priv);
|
|
else
|
|
mt6358_amic_disable(priv);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt_mic_type_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
|
|
|
|
dev_dbg(priv->dev, "%s(), event 0x%x, mux %u\n",
|
|
__func__, event, mux);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_WILL_PMU:
|
|
priv->mux_select[MUX_MIC_TYPE] = mux;
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
switch (mux) {
|
|
case MIC_TYPE_MUX_DMIC:
|
|
mt6358_dmic_enable(priv);
|
|
break;
|
|
default:
|
|
mt6358_amic_enable(priv);
|
|
break;
|
|
}
|
|
mt6358_restore_pga(priv);
|
|
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
switch (priv->mux_select[MUX_MIC_TYPE]) {
|
|
case MIC_TYPE_MUX_DMIC:
|
|
mt6358_dmic_disable(priv);
|
|
break;
|
|
default:
|
|
mt6358_amic_disable(priv);
|
|
break;
|
|
}
|
|
|
|
priv->mux_select[MUX_MIC_TYPE] = mux;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt_adc_l_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
|
|
|
|
dev_dbg(priv->dev, "%s(), event = 0x%x, mux %u\n",
|
|
__func__, event, mux);
|
|
|
|
priv->mux_select[MUX_ADC_L] = mux;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt_adc_r_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
|
|
|
|
dev_dbg(priv->dev, "%s(), event = 0x%x, mux %u\n",
|
|
__func__, event, mux);
|
|
|
|
priv->mux_select[MUX_ADC_R] = mux;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt_pga_left_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
|
|
|
|
dev_dbg(priv->dev, "%s(), event = 0x%x, mux %u\n",
|
|
__func__, event, mux);
|
|
|
|
priv->mux_select[MUX_PGA_L] = mux;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt_pga_right_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
|
|
|
|
dev_dbg(priv->dev, "%s(), event = 0x%x, mux %u\n",
|
|
__func__, event, mux);
|
|
|
|
priv->mux_select[MUX_PGA_R] = mux;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt_delay_250_event(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol,
|
|
int event)
|
|
{
|
|
switch (event) {
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
usleep_range(250, 270);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
usleep_range(250, 270);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt_dmic_connect(struct snd_soc_dapm_widget *source,
|
|
struct snd_soc_dapm_widget *sink)
|
|
{
|
|
struct snd_soc_dapm_widget *w = sink;
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
return priv->mux_select[MUX_MIC_TYPE] == MIC_TYPE_MUX_DMIC ?
|
|
true : false;
|
|
}
|
|
|
|
static int mt_amic_connect(struct snd_soc_dapm_widget *source,
|
|
struct snd_soc_dapm_widget *sink)
|
|
{
|
|
struct snd_soc_dapm_widget *w = sink;
|
|
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
return priv->mux_select[MUX_MIC_TYPE] != MIC_TYPE_MUX_DMIC ?
|
|
true : false;
|
|
}
|
|
|
|
/* DAPM Widgets */
|
|
static const struct snd_soc_dapm_widget mt6358_dapm_widgets[] = {
|
|
/* Global Supply*/
|
|
SND_SOC_DAPM_REGULATOR_SUPPLY("vaud28", 0, 0),
|
|
SND_SOC_DAPM_SUPPLY_S("CLK_BUF", SUPPLY_SEQ_CLK_BUF,
|
|
MT6358_DCXO_CW14,
|
|
RG_XO_AUDIO_EN_M_SFT, 0, NULL, 0),
|
|
SND_SOC_DAPM_SUPPLY_S("AUDGLB", SUPPLY_SEQ_AUD_GLB,
|
|
MT6358_AUDDEC_ANA_CON13,
|
|
RG_AUDGLB_PWRDN_VA28_SFT, 1, NULL, 0),
|
|
SND_SOC_DAPM_SUPPLY_S("CLKSQ Audio", SUPPLY_SEQ_CLKSQ,
|
|
MT6358_AUDENC_ANA_CON6,
|
|
RG_CLKSQ_EN_SFT, 0,
|
|
mt_clksq_event,
|
|
SND_SOC_DAPM_PRE_PMU),
|
|
SND_SOC_DAPM_SUPPLY_S("AUDNCP_CK", SUPPLY_SEQ_TOP_CK,
|
|
MT6358_AUD_TOP_CKPDN_CON0,
|
|
RG_AUDNCP_CK_PDN_SFT, 1, NULL, 0),
|
|
SND_SOC_DAPM_SUPPLY_S("ZCD13M_CK", SUPPLY_SEQ_TOP_CK,
|
|
MT6358_AUD_TOP_CKPDN_CON0,
|
|
RG_ZCD13M_CK_PDN_SFT, 1, NULL, 0),
|
|
SND_SOC_DAPM_SUPPLY_S("AUD_CK", SUPPLY_SEQ_TOP_CK_LAST,
|
|
MT6358_AUD_TOP_CKPDN_CON0,
|
|
RG_AUD_CK_PDN_SFT, 1,
|
|
mt_delay_250_event,
|
|
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
|
|
SND_SOC_DAPM_SUPPLY_S("AUDIF_CK", SUPPLY_SEQ_TOP_CK,
|
|
MT6358_AUD_TOP_CKPDN_CON0,
|
|
RG_AUDIF_CK_PDN_SFT, 1, NULL, 0),
|
|
SND_SOC_DAPM_SUPPLY_S("MIC_BIAS", SUPPLY_SEQ_MIC_BIAS,
|
|
SND_SOC_NOPM, 0, 0,
|
|
mt_mic_bias_event,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
|
|
|
/* vow */
|
|
SND_SOC_DAPM_SUPPLY_S("AUD_VOW", SUPPLY_SEQ_AUD_VOW,
|
|
MT6358_AUDENC_ANA_CON1,
|
|
RG_AUDIO_VOW_EN_SFT, 0, NULL, 0),
|
|
SND_SOC_DAPM_SUPPLY_S("VOW_CLK", SUPPLY_SEQ_VOW_CLK,
|
|
MT6358_DCXO_CW13,
|
|
RG_XO_VOW_EN_SFT, 0, NULL, 0),
|
|
SND_SOC_DAPM_SUPPLY_S("VOW_LDO", SUPPLY_SEQ_VOW_LDO,
|
|
SND_SOC_NOPM, 0, 0,
|
|
mt_vow_ldo_event,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
|
|
|
/* Digital Clock */
|
|
SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_AFE_CTL", SUPPLY_SEQ_AUD_TOP_LAST,
|
|
MT6358_AUDIO_TOP_CON0,
|
|
PDN_AFE_CTL_SFT, 1,
|
|
mt_delay_250_event,
|
|
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
|
|
SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_DAC_CTL", SUPPLY_SEQ_AUD_TOP,
|
|
MT6358_AUDIO_TOP_CON0,
|
|
PDN_DAC_CTL_SFT, 1, NULL, 0),
|
|
SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_ADC_CTL", SUPPLY_SEQ_AUD_TOP,
|
|
MT6358_AUDIO_TOP_CON0,
|
|
PDN_ADC_CTL_SFT, 1, NULL, 0),
|
|
SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_I2S_DL", SUPPLY_SEQ_AUD_TOP,
|
|
MT6358_AUDIO_TOP_CON0,
|
|
PDN_I2S_DL_CTL_SFT, 1, NULL, 0),
|
|
SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PWR_CLK", SUPPLY_SEQ_AUD_TOP,
|
|
MT6358_AUDIO_TOP_CON0,
|
|
PWR_CLK_DIS_CTL_SFT, 1, NULL, 0),
|
|
SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_AFE_TESTMODEL", SUPPLY_SEQ_AUD_TOP,
|
|
MT6358_AUDIO_TOP_CON0,
|
|
PDN_AFE_TESTMODEL_CTL_SFT, 1, NULL, 0),
|
|
SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_RESERVED", SUPPLY_SEQ_AUD_TOP,
|
|
MT6358_AUDIO_TOP_CON0,
|
|
PDN_RESERVED_SFT, 1, NULL, 0),
|
|
|
|
SND_SOC_DAPM_SUPPLY("DL Digital Clock", SND_SOC_NOPM,
|
|
0, 0, NULL, 0),
|
|
|
|
/* AFE ON */
|
|
SND_SOC_DAPM_SUPPLY_S("AFE_ON", SUPPLY_SEQ_AFE,
|
|
MT6358_AFE_UL_DL_CON0, AFE_ON_SFT, 0,
|
|
NULL, 0),
|
|
|
|
/* AIF Rx*/
|
|
SND_SOC_DAPM_AIF_IN_E("AIF_RX", "AIF1 Playback", 0,
|
|
MT6358_AFE_DL_SRC2_CON0_L,
|
|
DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0,
|
|
mt_aif_in_event,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
|
|
|
/* DL Supply */
|
|
SND_SOC_DAPM_SUPPLY("DL Power Supply", SND_SOC_NOPM,
|
|
0, 0, NULL, 0),
|
|
|
|
/* DAC */
|
|
SND_SOC_DAPM_MUX("DAC In Mux", SND_SOC_NOPM, 0, 0, &dac_in_mux_control),
|
|
|
|
SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0),
|
|
|
|
SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0),
|
|
|
|
/* LOL */
|
|
SND_SOC_DAPM_MUX_E("LOL Mux", SND_SOC_NOPM, 0, 0,
|
|
&lo_in_mux_control,
|
|
mt_lo_event,
|
|
SND_SOC_DAPM_PRE_PMU |
|
|
SND_SOC_DAPM_PRE_PMD),
|
|
|
|
SND_SOC_DAPM_SUPPLY("LO Stability Enh", MT6358_AUDDEC_ANA_CON7,
|
|
RG_LOOUTPUTSTBENH_VAUDP15_SFT, 0, NULL, 0),
|
|
|
|
SND_SOC_DAPM_OUT_DRV("LOL Buffer", MT6358_AUDDEC_ANA_CON7,
|
|
RG_AUDLOLPWRUP_VAUDP15_SFT, 0, NULL, 0),
|
|
|
|
/* Headphone */
|
|
SND_SOC_DAPM_MUX_E("HPL Mux", SND_SOC_NOPM, 0, 0,
|
|
&hpl_in_mux_control,
|
|
mt_hp_event,
|
|
SND_SOC_DAPM_PRE_PMU |
|
|
SND_SOC_DAPM_PRE_PMD),
|
|
|
|
SND_SOC_DAPM_MUX_E("HPR Mux", SND_SOC_NOPM, 0, 0,
|
|
&hpr_in_mux_control,
|
|
mt_hp_event,
|
|
SND_SOC_DAPM_PRE_PMU |
|
|
SND_SOC_DAPM_PRE_PMD),
|
|
|
|
/* Receiver */
|
|
SND_SOC_DAPM_MUX_E("RCV Mux", SND_SOC_NOPM, 0, 0,
|
|
&rcv_in_mux_control,
|
|
mt_rcv_event,
|
|
SND_SOC_DAPM_PRE_PMU |
|
|
SND_SOC_DAPM_PRE_PMD),
|
|
|
|
/* Outputs */
|
|
SND_SOC_DAPM_OUTPUT("Receiver"),
|
|
SND_SOC_DAPM_OUTPUT("Headphone L"),
|
|
SND_SOC_DAPM_OUTPUT("Headphone R"),
|
|
SND_SOC_DAPM_OUTPUT("Headphone L Ext Spk Amp"),
|
|
SND_SOC_DAPM_OUTPUT("Headphone R Ext Spk Amp"),
|
|
SND_SOC_DAPM_OUTPUT("LINEOUT L"),
|
|
SND_SOC_DAPM_OUTPUT("LINEOUT L HSSPK"),
|
|
|
|
/* SGEN */
|
|
SND_SOC_DAPM_SUPPLY("SGEN DL Enable", MT6358_AFE_SGEN_CFG0,
|
|
SGEN_DAC_EN_CTL_SFT, 0, NULL, 0),
|
|
SND_SOC_DAPM_SUPPLY("SGEN MUTE", MT6358_AFE_SGEN_CFG0,
|
|
SGEN_MUTE_SW_CTL_SFT, 1,
|
|
mt_sgen_event,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
|
SND_SOC_DAPM_SUPPLY("SGEN DL SRC", MT6358_AFE_DL_SRC2_CON0_L,
|
|
DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, NULL, 0),
|
|
|
|
SND_SOC_DAPM_INPUT("SGEN DL"),
|
|
|
|
/* Uplinks */
|
|
SND_SOC_DAPM_AIF_OUT_E("AIF1TX", "AIF1 Capture", 0,
|
|
SND_SOC_NOPM, 0, 0,
|
|
mt_aif_out_event,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
|
|
|
SND_SOC_DAPM_SUPPLY_S("ADC Supply", SUPPLY_SEQ_ADC_SUPPLY,
|
|
SND_SOC_NOPM, 0, 0,
|
|
mt_adc_supply_event,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
|
|
|
/* Uplinks MUX */
|
|
SND_SOC_DAPM_MUX("AIF Out Mux", SND_SOC_NOPM, 0, 0,
|
|
&aif_out_mux_control),
|
|
|
|
SND_SOC_DAPM_MUX_E("Mic Type Mux", SND_SOC_NOPM, 0, 0,
|
|
&mic_type_mux_control,
|
|
mt_mic_type_event,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD |
|
|
SND_SOC_DAPM_WILL_PMU),
|
|
|
|
SND_SOC_DAPM_MUX_E("ADC L Mux", SND_SOC_NOPM, 0, 0,
|
|
&adc_left_mux_control,
|
|
mt_adc_l_event,
|
|
SND_SOC_DAPM_WILL_PMU),
|
|
SND_SOC_DAPM_MUX_E("ADC R Mux", SND_SOC_NOPM, 0, 0,
|
|
&adc_right_mux_control,
|
|
mt_adc_r_event,
|
|
SND_SOC_DAPM_WILL_PMU),
|
|
|
|
SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),
|
|
SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),
|
|
|
|
SND_SOC_DAPM_MUX_E("PGA L Mux", SND_SOC_NOPM, 0, 0,
|
|
&pga_left_mux_control,
|
|
mt_pga_left_event,
|
|
SND_SOC_DAPM_WILL_PMU),
|
|
SND_SOC_DAPM_MUX_E("PGA R Mux", SND_SOC_NOPM, 0, 0,
|
|
&pga_right_mux_control,
|
|
mt_pga_right_event,
|
|
SND_SOC_DAPM_WILL_PMU),
|
|
|
|
SND_SOC_DAPM_PGA("PGA L", SND_SOC_NOPM, 0, 0, NULL, 0),
|
|
SND_SOC_DAPM_PGA("PGA R", SND_SOC_NOPM, 0, 0, NULL, 0),
|
|
|
|
/* UL input */
|
|
SND_SOC_DAPM_INPUT("AIN0"),
|
|
SND_SOC_DAPM_INPUT("AIN1"),
|
|
SND_SOC_DAPM_INPUT("AIN2"),
|
|
|
|
SND_SOC_DAPM_INPUT("AIN0_DMIC"),
|
|
SND_SOC_DAPM_INPUT("AIN3_DMIC"),
|
|
|
|
/* DC trim : trigger dc trim flow because set the reg when init_reg */
|
|
/* this must be at the last widget */
|
|
SND_SOC_DAPM_SUPPLY("DC Trim", MT6358_AUDDEC_ANA_CON8,
|
|
RG_AUDTRIMBUF_EN_VAUDP15_SFT, 0,
|
|
mt_dc_trim_event, SND_SOC_DAPM_POST_PMD),
|
|
|
|
/* VOW */
|
|
SND_SOC_DAPM_AIF_OUT_E("VOW TX", "VOW Capture", 0,
|
|
SND_SOC_NOPM, 0, 0,
|
|
mt_vow_out_event,
|
|
SND_SOC_DAPM_WILL_PMU |
|
|
SND_SOC_DAPM_PRE_PMU |
|
|
SND_SOC_DAPM_POST_PMD),
|
|
};
|
|
|
|
static const struct snd_soc_dapm_route mt6358_dapm_routes[] = {
|
|
/* Capture */
|
|
{"AIF1TX", NULL, "AIF Out Mux"},
|
|
{"AIF1TX", NULL, "CLK_BUF"},
|
|
{"AIF1TX", NULL, "AUDGLB"},
|
|
{"AIF1TX", NULL, "CLKSQ Audio"},
|
|
{"AIF1TX", NULL, "vaud28"},
|
|
|
|
{"AIF1TX", NULL, "AUD_CK"},
|
|
{"AIF1TX", NULL, "AUDIF_CK"},
|
|
|
|
{"AIF1TX", NULL, "AUDIO_TOP_AFE_CTL"},
|
|
{"AIF1TX", NULL, "AUDIO_TOP_ADC_CTL"},
|
|
{"AIF1TX", NULL, "AUDIO_TOP_PWR_CLK"},
|
|
{"AIF1TX", NULL, "AUDIO_TOP_PDN_RESERVED"},
|
|
{"AIF1TX", NULL, "AUDIO_TOP_I2S_DL"},
|
|
|
|
{"AIF1TX", NULL, "AFE_ON"},
|
|
|
|
{"AIF Out Mux", NULL, "Mic Type Mux"},
|
|
{"AIF Out Mux", NULL, "AIN0_DMIC"},
|
|
{"AIF Out Mux", NULL, "ADC L"},
|
|
{"AIF Out Mux", NULL, "ADC R"},
|
|
|
|
{"ADC L", NULL, "ADC L Mux"},
|
|
{"ADC L", NULL, "ADC Supply"},
|
|
{"ADC R", NULL, "ADC R Mux"},
|
|
{"ADC R", NULL, "ADC Supply"},
|
|
|
|
{"ADC L Mux", "Left Preamplifier", "PGA L"},
|
|
{"ADC R Mux", "Right Preamplifier", "PGA R"},
|
|
|
|
{"PGA L", NULL, "PGA L Mux"},
|
|
{"PGA R", NULL, "PGA R Mux"},
|
|
|
|
{"PGA L Mux", "AIN0", "AIN0"},
|
|
{"PGA L Mux", "AIN1", "AIN1"},
|
|
{"PGA L Mux", "AIN2", "AIN2"},
|
|
|
|
{"PGA R Mux", "AIN0", "AIN0"},
|
|
{"PGA R Mux", "AIN1", "AIN1"},
|
|
{"PGA R Mux", "AIN2", "AIN2"},
|
|
|
|
/* DL Supply */
|
|
{"DL Power Supply", NULL, "CLK_BUF"},
|
|
{"DL Power Supply", NULL, "AUDGLB"},
|
|
{"DL Power Supply", NULL, "CLKSQ Audio"},
|
|
{"DL Power Supply", NULL, "AUDNCP_CK"},
|
|
{"DL Power Supply", NULL, "ZCD13M_CK"},
|
|
{"DL Power Supply", NULL, "AUD_CK"},
|
|
{"DL Power Supply", NULL, "AUDIF_CK"},
|
|
{"DL Power Supply", NULL, "vaud28"},
|
|
|
|
/* DL Digital Supply */
|
|
{"DL Digital Clock", NULL, "AUDIO_TOP_AFE_CTL"},
|
|
{"DL Digital Clock", NULL, "AUDIO_TOP_DAC_CTL"},
|
|
{"DL Digital Clock", NULL, "AUDIO_TOP_PWR_CLK"},
|
|
{"DL Digital Clock", NULL, "AFE_ON"},
|
|
|
|
{"AIF_RX", NULL, "DL Digital Clock"},
|
|
|
|
/* DL Path */
|
|
{"DAC In Mux", "Normal Path", "AIF_RX"},
|
|
{"DAC In Mux", "Sgen", "SGEN DL"},
|
|
|
|
{"SGEN DL", NULL, "SGEN DL SRC"},
|
|
{"SGEN DL", NULL, "SGEN MUTE"},
|
|
{"SGEN DL", NULL, "SGEN DL Enable"},
|
|
{"SGEN DL", NULL, "DL Digital Clock"},
|
|
{"SGEN DL", NULL, "AUDIO_TOP_PDN_AFE_TESTMODEL"},
|
|
|
|
{"DACL", NULL, "DAC In Mux"},
|
|
{"DACL", NULL, "DL Power Supply"},
|
|
|
|
{"DACR", NULL, "DAC In Mux"},
|
|
{"DACR", NULL, "DL Power Supply"},
|
|
|
|
/* Lineout Path */
|
|
{"LOL Mux", "Playback", "DACR"},
|
|
|
|
{"LOL Buffer", NULL, "LOL Mux"},
|
|
{"LOL Buffer", NULL, "LO Stability Enh"},
|
|
|
|
{"LINEOUT L", NULL, "LOL Buffer"},
|
|
|
|
/* Headphone Path */
|
|
{"HPL Mux", "Audio Playback", "DACL"},
|
|
{"HPR Mux", "Audio Playback", "DACR"},
|
|
{"HPL Mux", "HP Impedance", "DACL"},
|
|
{"HPR Mux", "HP Impedance", "DACR"},
|
|
{"HPL Mux", "LoudSPK Playback", "DACL"},
|
|
{"HPR Mux", "LoudSPK Playback", "DACR"},
|
|
{"HPL Mux", "Loud DualSPK Playback", "DACL"},
|
|
{"HPR Mux", "Loud DualSPK Playback", "DACR"},
|
|
|
|
{"Headphone L", NULL, "HPL Mux"},
|
|
{"Headphone R", NULL, "HPR Mux"},
|
|
{"Headphone L Ext Spk Amp", NULL, "HPL Mux"},
|
|
{"Headphone R Ext Spk Amp", NULL, "HPR Mux"},
|
|
{"LINEOUT L HSSPK", NULL, "HPL Mux"},
|
|
|
|
/* Receiver Path */
|
|
{"RCV Mux", "Voice Playback", "DACL"},
|
|
{"Receiver", NULL, "RCV Mux"},
|
|
|
|
/* VOW */
|
|
{"VOW TX", NULL, "Mic Type Mux"},
|
|
{"VOW TX", NULL, "CLK_BUF"},
|
|
{"VOW TX", NULL, "AUDGLB"},
|
|
{"VOW TX", NULL, "AUD_CK"},
|
|
{"VOW TX", NULL, "VOW_CLK"},
|
|
{"VOW TX", NULL, "AUD_VOW"},
|
|
{"VOW TX", NULL, "VOW_LDO"},
|
|
{"VOW TX", NULL, "ADC L"},
|
|
{"VOW TX", NULL, "AIN0_DMIC"},
|
|
{"VOW TX", NULL, "vaud28"},
|
|
|
|
/* mic bias */
|
|
{"AIN0", NULL, "MIC_BIAS", mt_amic_connect},
|
|
{"AIN1", NULL, "MIC_BIAS"},
|
|
{"AIN2", NULL, "MIC_BIAS", mt_amic_connect},
|
|
{"AIN0_DMIC", NULL, "MIC_BIAS", mt_dmic_connect},
|
|
};
|
|
|
|
static int mt6358_codec_dai_hw_params(struct snd_pcm_substream *substream,
|
|
struct snd_pcm_hw_params *params,
|
|
struct snd_soc_dai *dai)
|
|
{
|
|
struct snd_soc_component *cmpnt = dai->component;
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
unsigned int rate = params_rate(params);
|
|
|
|
dev_info(priv->dev, "%s(), substream->stream %d, rate %d, number %d\n",
|
|
__func__,
|
|
substream->stream,
|
|
rate,
|
|
substream->number);
|
|
|
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
|
priv->dl_rate = rate;
|
|
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
|
priv->ul_rate = rate;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct snd_soc_dai_ops mt6358_codec_dai_ops = {
|
|
.hw_params = mt6358_codec_dai_hw_params,
|
|
};
|
|
|
|
#define MT6358_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\
|
|
SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |\
|
|
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\
|
|
SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE |\
|
|
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\
|
|
SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE)
|
|
|
|
static struct snd_soc_dai_driver mt6358_dai_driver[] = {
|
|
{
|
|
.name = "mt6358-snd-codec-aif1",
|
|
.playback = {
|
|
.stream_name = "AIF1 Playback",
|
|
.channels_min = 1,
|
|
.channels_max = 2,
|
|
.rates = SNDRV_PCM_RATE_8000_48000 |
|
|
SNDRV_PCM_RATE_96000 |
|
|
SNDRV_PCM_RATE_192000,
|
|
.formats = MT6358_FORMATS,
|
|
},
|
|
.capture = {
|
|
.stream_name = "AIF1 Capture",
|
|
.channels_min = 1,
|
|
.channels_max = 2,
|
|
.rates = SNDRV_PCM_RATE_8000 |
|
|
SNDRV_PCM_RATE_16000 |
|
|
SNDRV_PCM_RATE_32000 |
|
|
SNDRV_PCM_RATE_48000,
|
|
.formats = MT6358_FORMATS,
|
|
},
|
|
.ops = &mt6358_codec_dai_ops,
|
|
},
|
|
{
|
|
.name = "mt6358-snd-codec-vow",
|
|
.capture = {
|
|
.stream_name = "VOW Capture",
|
|
.channels_min = 1,
|
|
.channels_max = 2,
|
|
.rates = SNDRV_PCM_RATE_16000,
|
|
.formats = MT6358_FORMATS,
|
|
},
|
|
},
|
|
};
|
|
|
|
static void set_trim_buf_in_mux(struct mt6358_priv *priv, int mux)
|
|
{
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON8,
|
|
RG_AUDTRIMBUF_INPUTMUXSEL_VAUDP15_MASK,
|
|
mux);
|
|
}
|
|
|
|
static void set_trim_buf_gain(struct mt6358_priv *priv, unsigned int gain)
|
|
{
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON8,
|
|
RG_AUDTRIMBUF_GAINSEL_VAUDP15_MASK_SFT,
|
|
gain << RG_AUDTRIMBUF_GAINSEL_VAUDP15_SFT);
|
|
}
|
|
|
|
static void enable_trim_buf(struct mt6358_priv *priv, bool enable)
|
|
{
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON8,
|
|
RG_AUDTRIMBUF_EN_VAUDP15_MASK_SFT,
|
|
(enable ? 1 : 0) << RG_AUDTRIMBUF_EN_VAUDP15_SFT);
|
|
}
|
|
|
|
/* 1 / (10 ^ (dB / 20)) * db_denominator */
|
|
static const int db_denominator = 8192;
|
|
static const int db_numerator[32] = {
|
|
3261, 3659, 4106, 4607,
|
|
5169, 5799, 6507, 7301,
|
|
8192, 9192, 10313, 11572,
|
|
12983, 14568, 16345, 18340,
|
|
20577, 23088, 25905, 819200,
|
|
819200, 819200, 819200, 819200,
|
|
819200, 819200, 819200, 819200,
|
|
819200, 819200, 819200, 819200,
|
|
};
|
|
|
|
#ifndef ANALOG_HPTRIM
|
|
static int get_mic_bias_mv(struct mt6358_priv *priv)
|
|
{
|
|
unsigned int mic_bias;
|
|
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON10, &mic_bias);
|
|
mic_bias = (mic_bias >> 4) & 0x7;
|
|
|
|
switch (mic_bias) {
|
|
case MIC_BIAS_1P7:
|
|
return 1700;
|
|
case MIC_BIAS_1P8:
|
|
return 1800;
|
|
case MIC_BIAS_1P9:
|
|
return 1900;
|
|
case MIC_BIAS_2P0:
|
|
return 2000;
|
|
case MIC_BIAS_2P1:
|
|
return 2100;
|
|
case MIC_BIAS_2P5:
|
|
return 2500;
|
|
case MIC_BIAS_2P6:
|
|
return 2600;
|
|
case MIC_BIAS_2P7:
|
|
return 2700;
|
|
default:
|
|
dev_warn(priv->dev, "%s(), invalid mic_bias %d\n",
|
|
__func__, mic_bias);
|
|
return 2600;
|
|
};
|
|
}
|
|
|
|
static int convert_offset_to_comp(struct mt6358_priv *priv,
|
|
int offset, int vol_type)
|
|
{
|
|
int gain = priv->ana_gain[vol_type];
|
|
int mic_vinp_mv = priv->dc_trim.mic_vinp_mv;
|
|
int real_mic_vinp_mv;
|
|
int mic_bias_mv;
|
|
int offset_scale = DIV_ROUND_CLOSEST(offset * db_numerator[gain],
|
|
db_denominator);
|
|
|
|
if (mic_vinp_mv > MIC_VINP_4POLE_THRES_MV &&
|
|
((priv->debug_flag & DBG_DCTRIM_BYPASS_4POLE) == 0)) {
|
|
int v_diff_bias_vinp;
|
|
int v_diff_bias_vinp_scale;
|
|
|
|
/* refine mic bias influence on 4 pole headset */
|
|
mic_bias_mv = get_mic_bias_mv(priv);
|
|
real_mic_vinp_mv = DIV_ROUND_CLOSEST(mic_vinp_mv * mic_bias_mv,
|
|
VINP_NORMALIZED_TO_MV);
|
|
|
|
v_diff_bias_vinp = mic_bias_mv - real_mic_vinp_mv;
|
|
v_diff_bias_vinp_scale = DIV_ROUND_CLOSEST((v_diff_bias_vinp) *
|
|
db_numerator[gain],
|
|
db_denominator);
|
|
|
|
if ((priv->debug_flag & DBG_DCTRIM_4POLE_LOG) != 0) {
|
|
dev_info(priv->dev, "%s(), mic_bias_mv %d, mic_vinp_mv %d, real_mic_vinp_mv %d\n",
|
|
__func__,
|
|
mic_bias_mv, mic_vinp_mv, real_mic_vinp_mv);
|
|
|
|
dev_info(priv->dev, "%s(), a %d, b %d\n", __func__,
|
|
DIV_ROUND_CLOSEST(offset_scale * 2804225,
|
|
32768),
|
|
DIV_ROUND_CLOSEST(v_diff_bias_vinp_scale *
|
|
1782,
|
|
1800));
|
|
}
|
|
|
|
return DIV_ROUND_CLOSEST(offset_scale * 2804225, 32768) -
|
|
DIV_ROUND_CLOSEST(v_diff_bias_vinp_scale * 1782, 1800);
|
|
} else {
|
|
/* The formula is from DE programming guide */
|
|
/* should be mantain by pmic owner */
|
|
return DIV_ROUND_CLOSEST(offset_scale * 2804225, 32768);
|
|
}
|
|
}
|
|
|
|
static int get_dc_ramp_step(int gain)
|
|
{
|
|
/* each step should be smaller than 100uV */
|
|
/* 1 pcm of dc compensation = 0.0808uV HP buffer voltage @ 0dB*/
|
|
/* 80uV / 0.0808uV(0dB) = 990.099 */
|
|
int step_0db = 990;
|
|
|
|
/* scale for specific gain */
|
|
return step_0db * db_numerator[gain] / db_denominator;
|
|
}
|
|
|
|
static int apply_dc_compensation(struct mt6358_priv *priv, bool enable)
|
|
{
|
|
struct mt6358_codec_ops *ops = &priv->ops;
|
|
struct dc_trim_data *dc_trim = &priv->dc_trim;
|
|
|
|
int lch_value = 0, rch_value = 0, tmp_ramp = 0;
|
|
int times = 0, i = 0;
|
|
int sign_lch = 0, sign_rch = 0;
|
|
int abs_lch = 0, abs_rch = 0;
|
|
int diff_lch = 0, diff_rch = 0, ramp_l = 0, ramp_r = 0;
|
|
int index_lgain = priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL];
|
|
int ramp_step = get_dc_ramp_step(index_lgain);
|
|
int *pre_lch_comp = &dc_trim->pre_comp_value[CH_L];
|
|
int *pre_rch_comp = &dc_trim->pre_comp_value[CH_R];
|
|
|
|
if (ops->enable_dc_compensation == NULL ||
|
|
ops->set_lch_dc_compensation == NULL ||
|
|
ops->set_rch_dc_compensation == NULL) {
|
|
dev_warn(priv->dev, "%s(), function not ready, enable %p, lch %p, rch %p\n",
|
|
__func__,
|
|
ops->enable_dc_compensation,
|
|
ops->set_lch_dc_compensation,
|
|
ops->set_rch_dc_compensation);
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (enable && index_lgain == DL_GAIN_N_40DB) {
|
|
dev_info(priv->dev, "%s(), -40dB skip dc compensation\n",
|
|
__func__);
|
|
return 0;
|
|
}
|
|
|
|
lch_value = convert_offset_to_comp(priv, dc_trim->hp_offset[CH_L],
|
|
AUDIO_ANALOG_VOLUME_HPOUTL);
|
|
rch_value = convert_offset_to_comp(priv, dc_trim->hp_offset[CH_R],
|
|
AUDIO_ANALOG_VOLUME_HPOUTR);
|
|
|
|
diff_lch = enable ? lch_value - *pre_lch_comp : lch_value;
|
|
diff_rch = enable ? rch_value - *pre_rch_comp : rch_value;
|
|
sign_lch = diff_lch < 0 ? -1 : 1;
|
|
sign_rch = diff_rch < 0 ? -1 : 1;
|
|
abs_lch = sign_lch * diff_lch;
|
|
abs_rch = sign_rch * diff_rch;
|
|
times = abs_lch > abs_rch ?
|
|
(abs_lch / ramp_step) : (abs_rch / ramp_step);
|
|
|
|
dev_info(priv->dev, "%s(), enable = %d, index_gain = %d, times = %d, lch_value = %d -> %d, rch_value = %d -> %d, ramp_step %d, mic_vinp_mv %d\n",
|
|
__func__, enable, index_lgain, times,
|
|
*pre_lch_comp, lch_value,
|
|
*pre_rch_comp, rch_value, ramp_step, dc_trim->mic_vinp_mv);
|
|
|
|
if (enable) {
|
|
ops->enable_dc_compensation(true);
|
|
for (i = 1; i <= times; i++) {
|
|
tmp_ramp = i * ramp_step;
|
|
if (tmp_ramp < abs_lch) {
|
|
ramp_l = *pre_lch_comp + sign_lch * tmp_ramp;
|
|
ops->set_lch_dc_compensation(ramp_l << 8);
|
|
}
|
|
if (tmp_ramp < abs_rch) {
|
|
ramp_r = *pre_rch_comp + sign_rch * tmp_ramp;
|
|
ops->set_rch_dc_compensation(ramp_r << 8);
|
|
}
|
|
udelay(600);
|
|
}
|
|
ops->set_lch_dc_compensation(lch_value << 8);
|
|
ops->set_rch_dc_compensation(rch_value << 8);
|
|
*pre_lch_comp = lch_value;
|
|
*pre_rch_comp = rch_value;
|
|
} else {
|
|
for (i = times; i >= 0; i--) {
|
|
tmp_ramp = i * ramp_step;
|
|
if (tmp_ramp < abs_lch) {
|
|
ramp_l = sign_lch * tmp_ramp;
|
|
ops->set_lch_dc_compensation(ramp_l << 8);
|
|
}
|
|
|
|
if (tmp_ramp < abs_rch) {
|
|
ramp_r = sign_rch * tmp_ramp;
|
|
ops->set_rch_dc_compensation(ramp_r << 8);
|
|
}
|
|
udelay(600);
|
|
}
|
|
ops->set_lch_dc_compensation(0);
|
|
ops->set_rch_dc_compensation(0);
|
|
ops->enable_dc_compensation(false);
|
|
*pre_lch_comp = 0;
|
|
*pre_rch_comp = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(SKIP_SB) && !defined(CONFIG_FPGA_EARLY_PORTING)
|
|
static void enable_trim_circuit(struct mt6358_priv *priv, bool enable)
|
|
{
|
|
int status = 0;
|
|
unsigned int value = 0;
|
|
|
|
if (enable) {
|
|
if (!IS_ERR(priv->reg_vaud28)) {
|
|
status = regulator_enable(priv->reg_vaud28);
|
|
if (status)
|
|
dev_info(priv->dev, "%s() failed to enable vaud28(%d)\n",
|
|
__func__, status);
|
|
}
|
|
} else {
|
|
if (!IS_ERR(priv->reg_vaud28)) {
|
|
status = regulator_disable(priv->reg_vaud28);
|
|
if (status)
|
|
dev_info(priv->dev, "%s() failed to disable vaud28(%d)\n",
|
|
__func__, status);
|
|
}
|
|
}
|
|
|
|
regmap_read(priv->regmap, MT6358_LDO_VAUD28_CON0, &value);
|
|
dev_dbg(priv->dev, "%s(), enable(%d), 0x%x MT6358_LDO_VAUD28_CON0 = 0x%x\n",
|
|
__func__, enable, MT6358_LDO_VAUD28_CON0, value);
|
|
}
|
|
|
|
static int calculate_trim_result(struct mt6358_priv *priv,
|
|
int *on_value, int *off_value,
|
|
int trim_times, int discard_num, int useful_num)
|
|
{
|
|
int i = 0, j = 0, tmp = 0, offset = 0;
|
|
/* sort */
|
|
for (i = 0; i < trim_times - 1; i++) {
|
|
for (j = 0; j < trim_times - 1 - i; j++) {
|
|
if (on_value[j] > on_value[j + 1]) {
|
|
tmp = on_value[j + 1];
|
|
on_value[j + 1] = on_value[j];
|
|
on_value[j] = tmp;
|
|
}
|
|
if (off_value[j] > off_value[j + 1]) {
|
|
tmp = off_value[j + 1];
|
|
off_value[j + 1] = off_value[j];
|
|
off_value[j] = tmp;
|
|
}
|
|
}
|
|
}
|
|
/* calculate result */
|
|
for (i = discard_num; i < trim_times - discard_num; i++) {
|
|
offset += on_value[i] - off_value[i];
|
|
dev_info(priv->dev, "%s(), offset diff = %d, on = %d, off = %d\n",
|
|
__func__,
|
|
on_value[i] - off_value[i], on_value[i], off_value[i]);
|
|
}
|
|
return DIV_ROUND_CLOSEST(offset, useful_num);
|
|
}
|
|
|
|
static void start_trim_hardware(struct mt6358_priv *priv, bool buffer_on)
|
|
{
|
|
dev_info(priv->dev, "%s(), ++\n", __func__);
|
|
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON10,
|
|
0xff, 0xa0);
|
|
|
|
/* Set playback gpio (mosi/clk/sync) */
|
|
playback_gpio_set(priv);
|
|
|
|
/* Enable AUDGLB */
|
|
mt6358_set_aud_global_bias(priv, true);
|
|
|
|
if (!priv->pull_down_stay_enable) {
|
|
/* Pull-down HPL/R to AVSS30_AUD */
|
|
hp_pull_down(priv, true);
|
|
}
|
|
|
|
/* release HP CMFB gate rstb */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4,
|
|
0x1 << 6, 0x1 << 6);
|
|
|
|
/* enable clk buf */
|
|
mt6358_set_dcxo(priv, true);
|
|
|
|
/* Enable CLKSQ 26MHz */
|
|
mt6358_set_clksq(priv, true);
|
|
|
|
/* Enable ZCD13M_CK, AUD_CK, AUDIF_CK, AUDNCP_CK*/
|
|
mt6358_set_topck(priv, true);
|
|
usleep_range(250, 270);
|
|
|
|
regmap_update_bits(priv->regmap, MT6358_AUDIO_TOP_CON0, 0x00c4, 0x0);
|
|
usleep_range(250, 270);
|
|
|
|
/* sdm audio fifo clock power on */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0006);
|
|
/* scrambler clock on enable */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xcba1);
|
|
/* sdm power on */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0003);
|
|
/* sdm fifo enable */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x000B);
|
|
|
|
/* afe enable */
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_UL_DL_CON0,
|
|
AFE_ON_MASK_SFT, 0x1);
|
|
/* turn on dl */
|
|
regmap_write(priv->regmap, MT6358_AFE_DL_SRC2_CON0_L, 0x1);
|
|
/* set DL in normal path, not from sine gen table */
|
|
regmap_write(priv->regmap, MT6358_AFE_TOP_CON0, 0x0);
|
|
|
|
/* sdm output mute enable */
|
|
/* regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON1, 0x0000); */
|
|
/* regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xcbad); */
|
|
|
|
/* The above is turning on DAC */
|
|
|
|
/* Disable headphone short-circuit protection */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x3000);
|
|
/* Disable handset short-circuit protection */
|
|
/* regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0010); */
|
|
/* Disable linout short-circuit protection */
|
|
/* regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON7, 0x0010); */
|
|
/* Reduce ESD resistance of AU_REFN */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0xc000);
|
|
/* Set HPL/HPR gain to -10dB*/
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_10DB_REG);
|
|
|
|
/* Turn on DA_600K_NCP_VA18 */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON1, 0x0001);
|
|
/* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON2, 0x002c);
|
|
/* Toggle RG_DIVCKS_CHG */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON0, 0x0001);
|
|
/* Set NCP soft start mode as default mode: 150us */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON4, 0x0002);
|
|
/* Enable NCP */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x0000);
|
|
usleep_range(250, 270);
|
|
|
|
/* Enable cap-less LDOs (1.5V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x1055, 0x1055);
|
|
/* Enable NV regulator (-1.2V) */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x0001);
|
|
usleep_range(100, 120);
|
|
|
|
/* Enable AUD_ZCD */
|
|
zcd_enable(priv, true, DEVICE_HP);
|
|
|
|
/* Enable IBIST */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055);
|
|
/* Set HP DR bias current optimization, 010: 6uA */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON11,
|
|
0xff80, 0x4900);
|
|
/* Set HP & ZCD bias current optimization */
|
|
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055);
|
|
/* Set HPP/N STB enhance circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0xc033);
|
|
if (buffer_on) {
|
|
/* Enable HP aux output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x000c);
|
|
/* Enable HP aux feedback loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x003c);
|
|
/* Enable HP aux CMFB loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0c80);
|
|
|
|
/* Enable HP driver bias circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30c0);
|
|
/* Enable HP driver core circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30f0);
|
|
/* Short HP main output to HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x00ff, 0x00fc);
|
|
/* Enable HP main CMFB loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0e80);
|
|
/* Disable HP aux CMFB loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0280);
|
|
|
|
/* Select CMFB resistor bulk to AC mode */
|
|
/* Selec HS/LO cap size (6.5pF default) */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON10, 0x0000);
|
|
|
|
/* Enable HS driver bias circuits */
|
|
/* Disable HS main output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0010);
|
|
/* Enable LO driver bias circuits */
|
|
/* Disable LO main output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON7, 0x0010);
|
|
|
|
/* Enable HP main output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x00ff, 0x00ff);
|
|
/* Enable HPR/L main output stage step by step */
|
|
hp_main_output_ramp(priv, true);
|
|
/* Reduce HP aux feedback loop gain step by step */
|
|
hp_aux_feedback_loop_gain_ramp(priv, true);
|
|
/* Disable HP aux feedback loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fcf);
|
|
/* Increase HPL/HPR gain to normal gain step by step */
|
|
headset_volume_ramp(priv,
|
|
DL_GAIN_N_10DB,
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL]);
|
|
/* Disable HP aux output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fc3);
|
|
/* Unshort HP main output to HP aux output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3f03);
|
|
udelay(1000);
|
|
|
|
/* Disable AUD_CLK */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13,
|
|
0x1, 0x0);
|
|
/* Disable Audio DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0xf, 0x0);
|
|
/* Disable low-noise mode of DAC*/
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x1, 0x0);
|
|
|
|
/* Switch HPL/HPR MUX to open */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x0f00, 0x0000);
|
|
|
|
/* Disable Pull-down HPL/R to AVSS28_AUD*/
|
|
hp_pull_down(priv, false);
|
|
|
|
/* Enable Trim buffer VA28 reference */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0x1 << 1, 0x1 << 1);
|
|
} else {
|
|
/* Enable HP driver bias circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30c0);
|
|
/* Disable HP main output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x0000);
|
|
/* Enable HS driver bias circuits */
|
|
/* Disable HS main output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0012);
|
|
/* Enable LO driver bias circuits */
|
|
/* Disable LO main output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON7, 0x0012);
|
|
}
|
|
udelay(100);
|
|
|
|
dev_info(priv->dev, "%s(), --\n", __func__);
|
|
}
|
|
|
|
static void stop_trim_hardware(struct mt6358_priv *priv)
|
|
{
|
|
dev_info(priv->dev, "%s(), ++\n", __func__);
|
|
|
|
hp_pull_down(priv, true);
|
|
|
|
/* HPR/HPL mux to open */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x0f00, 0x0000);
|
|
/* Disable low-noise mode of DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0x1, 0x0);
|
|
|
|
/* Disable Audio DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x000f, 0x0000);
|
|
/* Disable AUD_CLK */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x0);
|
|
|
|
/* Short HP main output to HP aux output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fc3);
|
|
/* Enable HP aux output stage*/
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fcf);
|
|
|
|
/* decrease HPL/R gain to normal gain step by step */
|
|
headset_volume_ramp(priv,
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL],
|
|
DL_GAIN_N_10DB);
|
|
|
|
/* Enable HP aux feedback loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fff);
|
|
/* set HP aux feedback loop gain to max step by step */
|
|
hp_aux_feedback_loop_gain_ramp(priv, false);
|
|
/* decrease HPR/L main output stage step by step */
|
|
hp_main_output_ramp(priv, false);
|
|
/* Disable HP main output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3, 0x0);
|
|
|
|
/* Enable HP aux CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0x0f00, 0x0e00);
|
|
/* Disable HP main CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0x0f00, 0x0c00);
|
|
/* Unshort HP main output to HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x3 << 6, 0x0);
|
|
/* Disable HP driver core circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30c0);
|
|
/* Disable HP driver bias circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x3000);
|
|
/* Disable HP aux CMFB loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0);
|
|
/* Open HP aux feedback loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0xc);
|
|
/* Disable HP aux output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x0);
|
|
|
|
/* Disable IBIST */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON12,
|
|
0x1 << 8, 0x1 << 8);
|
|
|
|
/* Disable AUD_ZCD */
|
|
zcd_enable(priv, false, DEVICE_HP);
|
|
|
|
/* Disable NV regulator (-1.2V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x1, 0x0);
|
|
/* Disable cap-less LDOs (1.5V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, 0x1055, 0x0);
|
|
/* Disable NCP */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x1, 0x1);
|
|
|
|
/* Set HPL/HPR gain to mute */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_40DB_REG);
|
|
/* Increase ESD resistance of AU_REFN */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON2,
|
|
0x1 << 14, 0x0);
|
|
|
|
/* The below is turning off DAC */
|
|
|
|
/* Turn off down-link */
|
|
regmap_write(priv->regmap, MT6358_AFE_DL_SRC2_CON0_L, 0x0);
|
|
|
|
/* DL scrambler disabling sequence */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0);
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xcba0);
|
|
|
|
/* turn off afe */
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_UL_DL_CON0,
|
|
AFE_ON_MASK_SFT, 0x0);
|
|
/* all power down */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDIO_TOP_CON0,
|
|
0x00ff, 0x00ff);
|
|
usleep_range(250, 270);
|
|
|
|
/* disable ZCD13M_CK, AUD_CK, AUDIF_CK, AUDNCP_CK*/
|
|
mt6358_set_topck(priv, false);
|
|
/* disable CLKSQ 26MHz */
|
|
mt6358_set_clksq(priv, false);
|
|
|
|
/* Set HP CMFB gate rstb */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4,
|
|
0x1 << 6, 0x0);
|
|
|
|
if (!priv->pull_down_stay_enable) {
|
|
/* Disable Pull-down HPL/R to AVSS30_AUD */
|
|
hp_pull_down(priv, false);
|
|
}
|
|
|
|
/* disable AUDGLB */
|
|
mt6358_set_aud_global_bias(priv, false);
|
|
|
|
/* disable clk buf */
|
|
mt6358_set_dcxo(priv, false);
|
|
|
|
/* Reset playback gpio (mosi/clk/sync) */
|
|
playback_gpio_reset(priv);
|
|
|
|
dev_info(priv->dev, "%s(), --\n", __func__);
|
|
}
|
|
|
|
static void start_trim_hardware_with_lo(struct mt6358_priv *priv,
|
|
bool buffer_on)
|
|
{
|
|
/* Set playback gpio (mosi/clk/sync) */
|
|
playback_gpio_set(priv);
|
|
|
|
/* Enable AUDGLB */
|
|
mt6358_set_aud_global_bias(priv, true);
|
|
|
|
if (!priv->pull_down_stay_enable) {
|
|
/* Pull-down HPL/R to AVSS30_AUD */
|
|
hp_pull_down(priv, true);
|
|
}
|
|
|
|
/* release HP CMFB gate rstb */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4,
|
|
0x1 << 6, 0x1 << 6);
|
|
|
|
/* enable clk buf */
|
|
mt6358_set_dcxo(priv, true);
|
|
|
|
/* Enable CLKSQ 26MHz */
|
|
mt6358_set_clksq(priv, true);
|
|
|
|
/* Enable ZCD13M_CK, AUD_CK, AUDIF_CK, AUDNCP_CK*/
|
|
mt6358_set_topck(priv, true);
|
|
usleep_range(250, 270);
|
|
|
|
regmap_update_bits(priv->regmap, MT6358_AUDIO_TOP_CON0, 0x00c4, 0x0);
|
|
usleep_range(250, 270);
|
|
|
|
/* sdm audio fifo clock power on */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0006);
|
|
/* scrambler clock on enable */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xcba1);
|
|
/* sdm power on */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0003);
|
|
/* sdm fifo enable */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x000B);
|
|
|
|
/* afe enable */
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_UL_DL_CON0,
|
|
AFE_ON_MASK_SFT, 0x1);
|
|
/* turn on dl */
|
|
regmap_write(priv->regmap, MT6358_AFE_DL_SRC2_CON0_L, 0x1);
|
|
/* set DL in normal path, not from sine gen table */
|
|
regmap_write(priv->regmap, MT6358_AFE_TOP_CON0, 0x0);
|
|
|
|
/* The above is turning on DAC */
|
|
|
|
/* HP IVBUF (Vin path) de-gain enable: -12dB */
|
|
if (priv->apply_n12db_gain)
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDDEC_ANA_CON7,
|
|
0xff, 0x0004);
|
|
|
|
/* Audio left headphone input multiplexor selection : LOL*/
|
|
set_hp_l_input_mux(priv, HP_INPUT_MUX_LOL);
|
|
|
|
/* Disable headphone short-circuit protection */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0xf0ff, 0x3000);
|
|
/* Disable lineout short-ckt protection */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1 << 4, 0x1 << 4);
|
|
|
|
/* Reduce ESD resistance of AU_REFN */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON2,
|
|
0xffff, 0xc000);
|
|
|
|
/* Set HPL/HPR gain to -10dB*/
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_10DB_REG);
|
|
/* Set LOLR/LOLL gain to -10dB */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON1, DL_GAIN_N_10DB_REG);
|
|
|
|
/* Turn on DA_600K_NCP_VA18 */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON1, 0x0001);
|
|
/* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON2, 0x002c);
|
|
/* Toggle RG_DIVCKS_CHG */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON0, 0x0001);
|
|
/* Set NCP soft start mode as default mode: 150us */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON4, 0x0002);
|
|
/* Enable NCP */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x0000);
|
|
udelay(250);
|
|
|
|
/* Enable cap-less LDOs (1.5V), LCLDO local sense */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x1055, 0x1055);
|
|
/* Enable NV regulator (-1.2V) */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x0001);
|
|
udelay(100);
|
|
|
|
/* Enable AUD_ZCD */
|
|
zcd_enable(priv, true, DEVICE_HP);
|
|
|
|
/* Enable IBIST */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055);
|
|
|
|
/* Set HP DR bias current optimization, 010: 6uA */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON11,
|
|
0xff80, 0x4900);
|
|
/* Set HP & ZCD bias current optimization */
|
|
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055);
|
|
/* Set HPP/N STB enhance circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0xc033);
|
|
|
|
if (buffer_on) {
|
|
if (priv->apply_n12db_gain) {
|
|
/* HP IVBUF (Vin path) de-gain enable: -12dB */
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDDEC_ANA_CON10,
|
|
0xff, 0x04);
|
|
}
|
|
/* Set LO STB enhance circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1 << 8, 0x1 << 8);
|
|
/* Enable LO driver bias circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1 << 1, 0x1 << 1);
|
|
/* Enable LO driver core circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1, 0x1);
|
|
/* Set LOL gain to normal gain step by step */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON1, DL_GAIN_N_10DB_REG);
|
|
|
|
/* Switch HPL MUX to Line-out */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0x3 << 8, 0x01 << 8);
|
|
/* Switch HPR MUX to Line-out */
|
|
/* Ana_Set_Reg(AUDDEC_ANA_CON0, 0x01 << 10, 0x3 << 10); */
|
|
/* Enable HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0xff, 0x0c);
|
|
/* Enable HP aux feedback loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0xff, 0x3c);
|
|
/* Enable HP aux CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xff00, 0x0c00);
|
|
/* Enable HP driver bias circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0xf0, 0xc0);
|
|
/* Enable HP driver core circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0xf0, 0xf0);
|
|
/* Short HP main output to HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0xff, 0xfc);
|
|
/* Enable HP main CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xff00, 0x0e00);
|
|
/* Disable HP aux CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xff00, 0x0200);
|
|
|
|
/* Select CMFB resistor bulk to AC mode */
|
|
/* Selec HS/LO cap size (6.5pF default) */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON10, 0x0000);
|
|
|
|
/* Enable HS driver bias circuits */
|
|
/* Disable HS main output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0010);
|
|
/* Enable LO driver bias circuits */
|
|
/* Disable LO main output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON7, 0x0010);
|
|
|
|
/* Enable LO main output stage */
|
|
enable_lo_buffer(priv, true);
|
|
set_speaker_gain(priv, DL_GAIN_0DB);
|
|
|
|
/* Enable HP main output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x00ff, 0x00ff);
|
|
/* Enable HPR/L main output stage step by step */
|
|
hp_main_output_ramp(priv, true);
|
|
/* Reduce HP aux feedback loop gain step by step */
|
|
hp_aux_feedback_loop_gain_ramp(priv, true);
|
|
/* Disable HP aux feedback loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x00ff, 0x00cf);
|
|
|
|
/* Increase HPL/HPR gain to normal gain step by step */
|
|
headset_volume_ramp(priv,
|
|
DL_GAIN_N_10DB,
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL]);
|
|
|
|
/* Disable HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x00ff, 0x00c3);
|
|
/* Unshort HP main output to HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x00ff, 0x0003);
|
|
udelay(1000);
|
|
|
|
}
|
|
/* Enable AUD_CLK */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x1);
|
|
/* Enable low-noise mode of DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x1, 0x1);
|
|
udelay(100);
|
|
|
|
/* Switch LOL MUX to audio DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x3 << 2, 0x2 << 2);
|
|
/* Disable Pull-down HPL/R to AVSS28_AUD */
|
|
hp_pull_down(priv, false);
|
|
|
|
/* Enable Trim buffer VA28 reference */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0x1 << 1, 0x1 << 1);
|
|
}
|
|
|
|
static void stop_trim_hardware_with_lo(struct mt6358_priv *priv)
|
|
{
|
|
/* Pull-down HPL/R to AVSS28_AUD */
|
|
hp_pull_down(priv, true);
|
|
|
|
/* Disable low-noise mode of DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x1, 0x0);
|
|
/* Disable Audio DAC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0xf, 0x0);
|
|
/* Disable AUD_CLK */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x0);
|
|
|
|
/* Short HP main output to HP aux output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fc3);
|
|
/* Enable HP aux output stage*/
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fcf);
|
|
|
|
/* decrease HPL/R gain to normal gain step by step */
|
|
headset_volume_ramp(priv,
|
|
priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL],
|
|
DL_GAIN_N_10DB);
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON1, DL_GAIN_N_10DB_REG);
|
|
|
|
/* set HP aux feedback loop gain to max */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0xff00, 0xf200);
|
|
|
|
/* Enable HP aux feedback loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0xff, 0xff);
|
|
|
|
/* Reduce HP aux feedback loop gain */
|
|
hp_aux_feedback_loop_gain_ramp(priv, false);
|
|
|
|
/* decrease HPR/L main output stage step by step */
|
|
hp_main_output_ramp(priv, false);
|
|
|
|
/* Switch HPL/HPR MUX to open */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
0xf << 8, 0x0 << 8);
|
|
/* Switch LOL MUX to open */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x3 << 2, 0x0 << 2);
|
|
|
|
/* Disable HP main output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3, 0x0);
|
|
/* Enable HP aux CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0x0f00, 0x0e00);
|
|
/* Disable HP main CMFB loop */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9,
|
|
0x0f00, 0x0c00);
|
|
/* Unshort HP main output to HP aux output stage */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1,
|
|
0x3 << 6, 0x0);
|
|
/* Disable HP driver core circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30c0);
|
|
/* Disable HP driver bias circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x3000);
|
|
/* Disable HP aux CMFB loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0);
|
|
/* Open HP aux feedback loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0xc);
|
|
/* Disable HP aux output stage */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x0);
|
|
|
|
/* decrease LOL gain to minimum gain step by step */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON1, DL_GAIN_N_40DB_REG);
|
|
/* Disable LO driver core circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7, 0x1, 0x0);
|
|
/* Disable LO driver bias circuits */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
0x1 << 1, 0x0 << 1);
|
|
|
|
/* Disable IBIST */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON12,
|
|
0x1 << 8, 0x1 << 8);
|
|
|
|
/* Disable AUD_ZCD */
|
|
zcd_enable(priv, false, DEVICE_HP);
|
|
|
|
/* Disable NV regulator (-1.2V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x1, 0x0);
|
|
/* Disable cap-less LDOs (1.5V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x1055, 0x0);
|
|
/* Disable NCP */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x1, 0x1);
|
|
|
|
/* Set HPL/HPR gain to mute */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_40DB_REG);
|
|
|
|
/* Increase ESD resistance of AU_REFN */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON2,
|
|
0x1 << 14, 0x0);
|
|
|
|
/* The below is turning off DAC */
|
|
|
|
/* Turn off down-link */
|
|
regmap_write(priv->regmap, MT6358_AFE_DL_SRC2_CON0_L, 0x0);
|
|
|
|
/* DL scrambler disabling sequence */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0);
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xcba0);
|
|
|
|
/* turn off afe */
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_UL_DL_CON0,
|
|
AFE_ON_MASK_SFT, 0x0);
|
|
/* all power down */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDIO_TOP_CON0,
|
|
0x00ff, 0x00ff);
|
|
usleep_range(250, 270);
|
|
|
|
/* disable ZCD13M_CK, AUD_CK, AUDIF_CK, AUDNCP_CK*/
|
|
mt6358_set_topck(priv, false);
|
|
/* disable CLKSQ 26MHz */
|
|
mt6358_set_clksq(priv, false);
|
|
|
|
/* Set HP CMFB gate rstb */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4,
|
|
0x1 << 6, 0x0);
|
|
|
|
if (!priv->pull_down_stay_enable) {
|
|
/* Disable Pull-down HPL/R to AVSS30_AUD */
|
|
hp_pull_down(priv, false);
|
|
}
|
|
/* disable AUDGLB */
|
|
mt6358_set_aud_global_bias(priv, false);
|
|
|
|
/* disable clk buf */
|
|
mt6358_set_dcxo(priv, false);
|
|
|
|
/* Reset playback gpio (mosi/clk/sync) */
|
|
playback_gpio_reset(priv);
|
|
}
|
|
|
|
static void hp_trim_offset(struct mt6358_priv *priv)
|
|
{
|
|
int on_value_l[TRIM_TIMES], on_value_r[TRIM_TIMES];
|
|
int off_value_l[TRIM_TIMES], off_value_r[TRIM_TIMES];
|
|
int i;
|
|
|
|
regmap_update_bits(priv->regmap, MT6358_AUXADC_CON10,
|
|
0x7, AUXADC_AVG_256);
|
|
|
|
/* Step1. turn on buffer */
|
|
start_trim_hardware(priv, true);
|
|
|
|
/* L Channel */
|
|
|
|
/* Step2. Enable TRIMBUF circuit */
|
|
/* select HPL as TRIMBUF input and set TRIMBUF gain as 18dB */
|
|
set_trim_buf_in_mux(priv, TRIM_BUF_MUX_HPL);
|
|
set_trim_buf_gain(priv, TRIM_BUF_GAIN_18DB);
|
|
enable_trim_buf(priv, true);
|
|
|
|
/* Step3. Request AuxADC to get HP on dc value */
|
|
usleep_range(1 * 1000, 10 * 1000);
|
|
for (i = 0; i < TRIM_TIMES; i++)
|
|
on_value_l[i] = mt6358_get_hpofs_auxadc(priv);
|
|
|
|
/* Step4. select AUDREFN as TRIMBUF input */
|
|
set_trim_buf_in_mux(priv, TRIM_MUX_AU_REFN);
|
|
|
|
/* Step5. Request AuxADC to get HP off dc value */
|
|
usleep_range(1 * 1000, 10 * 1000);
|
|
for (i = 0; i < TRIM_TIMES; i++)
|
|
off_value_l[i] = mt6358_get_hpofs_auxadc(priv);
|
|
|
|
/* Step6. Enable TRIMBUF circuit */
|
|
/* select HPR as TRIMBUF input and set TRIMBUF gain as 18dB */
|
|
|
|
/* R Channel */
|
|
set_trim_buf_in_mux(priv, TRIM_BUF_MUX_HPR);
|
|
|
|
/* Step7. Request AuxADC to get HP on dc value */
|
|
usleep_range(1 * 1000, 10 * 1000);
|
|
for (i = 0; i < TRIM_TIMES; i++)
|
|
on_value_r[i] = mt6358_get_hpofs_auxadc(priv);
|
|
|
|
/* Step8. select AUDREFN as TRIMBUF input */
|
|
set_trim_buf_in_mux(priv, TRIM_MUX_AU_REFN);
|
|
|
|
/* Step9. Request AuxADC to get HP off dc value */
|
|
usleep_range(1 * 1000, 10 * 1000);
|
|
for (i = 0; i < TRIM_TIMES; i++)
|
|
off_value_r[i] = mt6358_get_hpofs_auxadc(priv);
|
|
|
|
/* Step10. turn off buffer */
|
|
enable_trim_buf(priv, false);
|
|
stop_trim_hardware(priv);
|
|
priv->dc_trim.hp_trim_offset[CH_L] =
|
|
calculate_trim_result(priv, on_value_l, off_value_l,
|
|
TRIM_TIMES, TRIM_DISCARD_NUM, TRIM_USEFUL_NUM);
|
|
priv->dc_trim.hp_trim_offset[CH_R] =
|
|
calculate_trim_result(priv, on_value_r, off_value_r,
|
|
TRIM_TIMES, TRIM_DISCARD_NUM, TRIM_USEFUL_NUM);
|
|
dev_info(priv->dev, "%s(), trim offset L = %d, trim offset R = %d\n",
|
|
__func__,
|
|
priv->dc_trim.hp_trim_offset[CH_L],
|
|
priv->dc_trim.hp_trim_offset[CH_R]);
|
|
}
|
|
|
|
static int spk_trim_offset(struct mt6358_priv *priv, int channel)
|
|
{
|
|
int offset = 0;
|
|
int on_value[TRIM_TIMES];
|
|
int off_value[TRIM_TIMES];
|
|
int i;
|
|
|
|
regmap_update_bits(priv->regmap, MT6358_AUXADC_CON10,
|
|
0x7, AUXADC_AVG_256);
|
|
|
|
/* Step1. turn on buffer */
|
|
start_trim_hardware_with_lo(priv, true);
|
|
|
|
/* Step2. Enable TRIMBUF circuit and set TRIMBUF gain as 18dB */
|
|
set_trim_buf_in_mux(priv, channel);
|
|
set_trim_buf_gain(priv, TRIM_BUF_GAIN_18DB);
|
|
enable_trim_buf(priv, true);
|
|
|
|
/* Step3. Request AuxADC to get HP on dc value */
|
|
usleep_range(1 * 1000, 10 * 1000);
|
|
for (i = 0; i < TRIM_TIMES; i++)
|
|
on_value[i] = mt6358_get_hpofs_auxadc(priv);
|
|
|
|
/* Step4. select AUDREFN as TRIMBUF input */
|
|
set_trim_buf_in_mux(priv, TRIM_MUX_AU_REFN);
|
|
|
|
/* Step5. Request AuxADC to get HP off dc value */
|
|
usleep_range(1 * 1000, 10 * 1000);
|
|
for (i = 0; i < TRIM_TIMES; i++)
|
|
off_value[i] = mt6358_get_hpofs_auxadc(priv);
|
|
|
|
/* Step6. turn off buffer */
|
|
enable_trim_buf(priv, false);
|
|
stop_trim_hardware_with_lo(priv);
|
|
|
|
offset = calculate_trim_result(priv, on_value, off_value,
|
|
TRIM_TIMES, TRIM_DISCARD_NUM, TRIM_USEFUL_NUM);
|
|
dev_info(priv->dev, "%s(), channel = %d, offset = %d\n",
|
|
__func__, channel, offset);
|
|
return offset;
|
|
}
|
|
|
|
#ifdef ANALOG_HPTRIM
|
|
static int pick_hp_finetrim(int offset_base,
|
|
int offset_finetrim_1,
|
|
int offset_finetrim_3)
|
|
{
|
|
if (abs(offset_base) < abs(offset_finetrim_1)) {
|
|
if (abs(offset_base) < abs(offset_finetrim_3))
|
|
return 0x0;
|
|
else
|
|
return 0x3;
|
|
} else {
|
|
if (abs(offset_finetrim_1) < abs(offset_finetrim_3))
|
|
return 0x1;
|
|
else
|
|
return 0x3;
|
|
}
|
|
}
|
|
|
|
static int pick_spk_finetrim(int offset_base,
|
|
int offset_finetrim_2,
|
|
int offset_finetrim_3)
|
|
{
|
|
if (abs(offset_base) < abs(offset_finetrim_2)) {
|
|
if (abs(offset_base) < abs(offset_finetrim_3))
|
|
return 0x0;
|
|
else
|
|
return 0x3;
|
|
} else {
|
|
if (abs(offset_finetrim_2) < abs(offset_finetrim_3))
|
|
return 0x2;
|
|
else
|
|
return 0x3;
|
|
}
|
|
}
|
|
|
|
static void set_lr_trim_code(struct mt6358_priv *priv)
|
|
{
|
|
int hpl_base = 0, hpr_base = 0;
|
|
int hpl_min = 0, hpr_min = 0;
|
|
int hpl_ceiling = 0, hpr_ceiling = 0;
|
|
int hpl_floor = 0, hpr_floor = 0;
|
|
int hpl_finetrim_1 = 0, hpr_finetrim_1 = 0;
|
|
int hpl_finetrim_3 = 0, hpr_finetrim_3 = 0;
|
|
int trimcodel = 0, trimcoder = 0;
|
|
int trimcodel_ceiling = 0, trimcoder_ceiling = 0;
|
|
int trimcodel_floor = 0, trimcoder_floor = 0;
|
|
int finetriml = 0, finetrimr = 0;
|
|
int trimcode_tmpl = 0, trimcode_tmpr = 0;
|
|
int tmp = 0;
|
|
unsigned int hp_3_pole_trim_setting = 0;
|
|
unsigned int hp_4_pole_trim_setting = 0;
|
|
bool code_change = false;
|
|
unsigned int reg_value = 0;
|
|
struct ana_offset *offset_3_pole = NULL;
|
|
struct ana_offset *offset_4_pole = NULL;
|
|
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), Start DCtrim Calibrating, AUDDEC_ELR_0 = 0x%x\n",
|
|
__func__, reg_value);
|
|
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_EN_MASK, 0x1 << HPTRIM_EN_SHIFT);
|
|
priv->dc_trim.hp_3_pole_ana_offset.enable = 1;
|
|
priv->dc_trim.hp_4_pole_ana_offset.enable = 1;
|
|
/* channel L */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_L_MASK, 0x0 << HPTRIM_L_SHIFT);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPFINETRIM_L_MASK, 0x0 << HPFINETRIM_L_SHIFT);
|
|
/* channel R */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_R_MASK, 0x0 << HPTRIM_R_SHIFT);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPFINETRIM_R_MASK, 0x0 << HPFINETRIM_R_SHIFT);
|
|
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), AUDDEC_ELR_0 = 0x%x\n", __func__, reg_value);
|
|
hp_trim_offset(priv);
|
|
hpl_base = priv->dc_trim.hp_trim_offset[CH_L];
|
|
hpr_base = priv->dc_trim.hp_trim_offset[CH_R];
|
|
mdelay(10);
|
|
|
|
/* Step1: get trim code */
|
|
if (hpl_base == 0)
|
|
goto EXIT;
|
|
if (hpr_base == 0)
|
|
goto EXIT;
|
|
if (hpl_base > 0 || hpr_base > 0) {
|
|
if (hpl_base > 0) {
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_L_MASK, 0x2 << HPTRIM_L_SHIFT);
|
|
code_change = true;
|
|
}
|
|
if (hpr_base > 0) {
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_R_MASK, 0x2 << HPTRIM_R_SHIFT);
|
|
code_change = true;
|
|
}
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step1 > 0 set 4 level AUDDEC_ELR_0 = 0x%x, trimcode(L/R) = %d / %d\n",
|
|
__func__, reg_value, trimcodel, trimcoder);
|
|
if (code_change) {
|
|
hp_trim_offset(priv);
|
|
code_change = false;
|
|
hpl_min = priv->dc_trim.hp_trim_offset[CH_L];
|
|
hpr_min = priv->dc_trim.hp_trim_offset[CH_R];
|
|
if (hpl_base == hpl_min || hpr_base == hpr_min)
|
|
goto EXIT;
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_L_MASK, 0x0 << HPTRIM_L_SHIFT);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_R_MASK, 0x0 << HPTRIM_R_SHIFT);
|
|
mdelay(10);
|
|
|
|
/* Check floor & ceiling to avoid rounding error */
|
|
if (hpl_base > 0) {
|
|
trimcodel_floor =
|
|
(abs(hpl_base) * 3) / (abs(hpl_base - hpl_min));
|
|
trimcodel_ceiling = trimcodel_floor + 1;
|
|
}
|
|
if (hpr_base > 0) {
|
|
trimcoder_floor =
|
|
(abs(hpr_base) * 3) / (abs(hpr_base - hpr_min));
|
|
trimcoder_ceiling = trimcoder_floor + 1;
|
|
}
|
|
}
|
|
}
|
|
if (hpl_base < 0 || hpr_base < 0) {
|
|
if (hpl_base < 0) {
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_L_MASK, 0xa << HPTRIM_L_SHIFT);
|
|
code_change = true;
|
|
}
|
|
if (hpr_base < 0) {
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_R_MASK, 0xa << HPTRIM_R_SHIFT);
|
|
code_change = true;
|
|
}
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step1 < 0, set 4 level AUDDEC_ELR_0 = 0x%x, trimcode(L/R) = %d / %d\n",
|
|
__func__, reg_value, trimcodel, trimcoder);
|
|
if (code_change) {
|
|
hp_trim_offset(priv);
|
|
code_change = false;
|
|
hpl_min = priv->dc_trim.hp_trim_offset[CH_L];
|
|
hpr_min = priv->dc_trim.hp_trim_offset[CH_R];
|
|
if (hpl_base == hpl_min || hpr_base == hpr_min)
|
|
goto EXIT;
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_L_MASK, 0x0 << HPTRIM_L_SHIFT);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_R_MASK, 0x0 << HPTRIM_R_SHIFT);
|
|
mdelay(10);
|
|
/* Check floor & ceiling to avoid rounding error */
|
|
if (hpl_base < 0) {
|
|
trimcodel_floor =
|
|
(abs(hpl_base) * 3) / (abs(hpl_base - hpl_min)) + 8;
|
|
trimcodel_ceiling = trimcodel_floor + 1;
|
|
}
|
|
if (hpr_base < 0) {
|
|
trimcoder_floor =
|
|
(abs(hpr_base) * 3) / (abs(hpr_base - hpr_min)) + 8;
|
|
trimcoder_ceiling = trimcoder_floor + 1;
|
|
}
|
|
}
|
|
}
|
|
/* Get the best trim code from floor and ceiling value */
|
|
/* Get floor trim code */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_L_MASK, trimcodel_floor << HPTRIM_L_SHIFT);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_R_MASK, trimcoder_floor << HPTRIM_R_SHIFT);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step1 floor AUDDEC_ELR_0 = 0x%x, trimcode(L/R) = %d / %d\n",
|
|
__func__, reg_value,
|
|
trimcodel_floor, trimcoder_floor);
|
|
|
|
hp_trim_offset(priv);
|
|
hpl_floor = priv->dc_trim.hp_trim_offset[CH_L];
|
|
hpr_floor = priv->dc_trim.hp_trim_offset[CH_R];
|
|
mdelay(10);
|
|
/* Get ceiling trim code */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_L_MASK, trimcodel_ceiling << HPTRIM_L_SHIFT);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_R_MASK, trimcoder_ceiling << HPTRIM_R_SHIFT);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step1 ceiling AUDDEC_ELR_0 = 0x%x, trimcode(L/R) = %d / %d\n",
|
|
__func__, reg_value,
|
|
trimcodel_ceiling, trimcoder_ceiling);
|
|
|
|
hp_trim_offset(priv);
|
|
hpl_ceiling = priv->dc_trim.hp_trim_offset[CH_L];
|
|
hpr_ceiling = priv->dc_trim.hp_trim_offset[CH_R];
|
|
mdelay(10);
|
|
/* Choose the best */
|
|
if (abs(hpl_ceiling) < abs(hpl_floor)) {
|
|
hpl_base = hpl_ceiling;
|
|
trimcodel = trimcodel_ceiling;
|
|
} else {
|
|
hpl_base = hpl_floor;
|
|
trimcodel = trimcodel_floor;
|
|
}
|
|
if (abs(hpr_ceiling) < abs(hpr_floor)) {
|
|
hpr_base = hpr_ceiling;
|
|
trimcoder = trimcoder_ceiling;
|
|
} else {
|
|
hpr_base = hpr_floor;
|
|
trimcoder = trimcoder_floor;
|
|
}
|
|
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_L_MASK, trimcodel << HPTRIM_L_SHIFT);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_R_MASK, trimcoder << HPTRIM_R_SHIFT);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step1 result: AUDDEC_ELR_0 = 0x%x, hp_base(L/R) = %d / %d, trimcode(L/R) = %d / %d\n",
|
|
__func__, reg_value,
|
|
hpl_base, hpr_base, trimcodel, trimcoder);
|
|
|
|
/* Step2: Trim code refine +1/0/-1 */
|
|
trimcode_tmpl = trimcodel;
|
|
trimcode_tmpr = trimcoder;
|
|
mdelay(10);
|
|
if (hpl_base == 0)
|
|
goto EXIT;
|
|
if (hpr_base == 0)
|
|
goto EXIT;
|
|
if (hpl_base > 0 || hpr_base > 0) {
|
|
if ((hpl_base > 0) &&
|
|
(trimcodel != 0x7) && (trimcodel != 0x8)) {
|
|
tmp = trimcodel + ((trimcodel > 7) ? -1 : 1);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_L_MASK, tmp << HPTRIM_L_SHIFT);
|
|
code_change = true;
|
|
}
|
|
if ((hpr_base > 0) &&
|
|
(trimcoder != 0x7) && (trimcoder != 0x8)) {
|
|
tmp = trimcoder + ((trimcoder > 7) ? -1 : 1);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_R_MASK, tmp << HPTRIM_R_SHIFT);
|
|
code_change = true;
|
|
}
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step2 > 0, AUDDEC_ELR_0 = 0x%x, trimcode_tmp = %d\n",
|
|
__func__, reg_value, tmp);
|
|
if (code_change) {
|
|
hp_trim_offset(priv);
|
|
code_change = false;
|
|
hpl_min = priv->dc_trim.hp_trim_offset[CH_L];
|
|
hpr_min = priv->dc_trim.hp_trim_offset[CH_R];
|
|
mdelay(10);
|
|
if ((hpl_base > 0) &&
|
|
(hpl_min >= 0 || abs(hpl_min) < abs(hpl_base))) {
|
|
if ((trimcodel != 0x7) && (trimcodel != 0x8)) {
|
|
trimcode_tmpl =
|
|
trimcodel +
|
|
((trimcodel > 7) ? -1 : 1);
|
|
} else {
|
|
trimcode_tmpl = trimcodel;
|
|
dev_info(priv->dev, "%s(), [Step2][L > 0, bit-overflow!!], don't refine, trimcodel = %d\n",
|
|
__func__, trimcodel);
|
|
}
|
|
}
|
|
if ((hpr_base > 0) &&
|
|
(hpr_min >= 0 || abs(hpr_min) < abs(hpr_base))) {
|
|
if ((trimcoder != 0x7) && (trimcoder != 0x8)) {
|
|
trimcode_tmpr =
|
|
trimcoder +
|
|
((trimcoder > 7) ? -1 : 1);
|
|
} else {
|
|
trimcode_tmpr = trimcoder;
|
|
dev_info(priv->dev, "%s(), [Step2][R > 0, bit-overflow!!], don't refine, trimcoder = %d\n",
|
|
__func__, trimcoder);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_L_MASK, trimcodel << HPTRIM_L_SHIFT);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_R_MASK, trimcoder << HPTRIM_R_SHIFT);
|
|
if (hpl_base < 0 || hpr_base < 0) {
|
|
if ((hpl_base < 0) && (trimcodel != 0) && (trimcodel != 0xf)) {
|
|
tmp = trimcodel - ((trimcodel > 7) ? -1 : 1);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_L_MASK, tmp << HPTRIM_L_SHIFT);
|
|
code_change = true;
|
|
}
|
|
if ((hpr_base < 0) && (trimcoder != 0) && (trimcoder != 0xf)) {
|
|
tmp = trimcoder - ((trimcoder > 7) ? -1 : 1);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_R_MASK, tmp << HPTRIM_R_SHIFT);
|
|
code_change = true;
|
|
}
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step2 < 0 AUDDEC_ELR_0 = 0x%x, trimcode_tmp(L/R) = %d / %d\n",
|
|
__func__,
|
|
reg_value, trimcode_tmpl, trimcode_tmpr);
|
|
if (code_change) {
|
|
hp_trim_offset(priv);
|
|
code_change = false;
|
|
hpl_min = priv->dc_trim.hp_trim_offset[CH_L];
|
|
hpr_min = priv->dc_trim.hp_trim_offset[CH_R];
|
|
mdelay(10);
|
|
if ((hpl_base < 0) &&
|
|
(hpl_min <= 0 || abs(hpl_min) < abs(hpl_base))) {
|
|
if ((trimcodel != 0) && (trimcodel != 0xf)) {
|
|
trimcode_tmpl =
|
|
trimcodel -
|
|
((trimcodel > 7) ? -1 : 1);
|
|
} else {
|
|
trimcode_tmpl = trimcodel;
|
|
pr_debug("%s(), [Step2][L < 0, bit-overflow!!], don't refine, trimcodel = %d\n",
|
|
__func__, trimcodel);
|
|
}
|
|
}
|
|
if ((hpr_base < 0) &&
|
|
(hpr_min <= 0 || abs(hpr_min) < abs(hpr_base))) {
|
|
if ((trimcoder != 0) && (trimcoder != 0xf)) {
|
|
trimcode_tmpr =
|
|
trimcoder -
|
|
((trimcoder > 7) ? -1 : 1);
|
|
} else {
|
|
trimcode_tmpr = trimcoder;
|
|
pr_debug("%s(), [Step2][R < 0, bit-overflow!!], don't refine, trimcoder = %d\n",
|
|
__func__, trimcoder);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
trimcodel = trimcode_tmpl;
|
|
trimcoder = trimcode_tmpr;
|
|
/* channel L */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_L_MASK, trimcodel << HPTRIM_L_SHIFT);
|
|
/* channel R */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_R_MASK, trimcoder << HPTRIM_R_SHIFT);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step2 result AUDDEC_ELR_0 = 0x%x, trimcode(L/R) = %d / %d\n",
|
|
__func__, reg_value, trimcode_tmpl, trimcode_tmpr);
|
|
|
|
/*Step3: Trim code fine tune*/
|
|
hp_trim_offset(priv);
|
|
hpl_base = priv->dc_trim.hp_trim_offset[CH_L];
|
|
hpr_base = priv->dc_trim.hp_trim_offset[CH_R];
|
|
mdelay(10);
|
|
if (hpl_base == 0)
|
|
goto EXIT;
|
|
if (hpr_base == 0)
|
|
goto EXIT;
|
|
if (hpl_base > 0 || hpr_base > 0) {
|
|
if (hpl_base > 0) {
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPFINETRIM_L_MASK,
|
|
0x1 << HPFINETRIM_L_SHIFT);
|
|
code_change = true;
|
|
}
|
|
if (hpr_base > 0) {
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPFINETRIM_R_MASK,
|
|
0x1 << HPFINETRIM_R_SHIFT);
|
|
code_change = true;
|
|
}
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step3 > 0, AUDDEC_ELR_0 = 0x%x, hp_base(L/R) = %d / %d\n",
|
|
__func__, reg_value, hpl_base, hpr_base);
|
|
if (code_change) {
|
|
hp_trim_offset(priv);
|
|
code_change = false;
|
|
/* HP finetrim=3 compensates negative DC value */
|
|
/* Choose the best fine trim */
|
|
hpl_finetrim_1 = priv->dc_trim.hp_trim_offset[CH_L];
|
|
hpr_finetrim_1 = priv->dc_trim.hp_trim_offset[CH_R];
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPFINETRIM_L_MASK,
|
|
0x0 << HPFINETRIM_L_SHIFT);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPFINETRIM_R_MASK,
|
|
0x0 << HPFINETRIM_R_SHIFT);
|
|
mdelay(10);
|
|
if ((hpl_base > 0) &&
|
|
((hpl_finetrim_1 >= 0) &&
|
|
(abs(hpl_finetrim_1) < abs(hpl_base))))
|
|
finetriml = 0x1;
|
|
if ((hpr_base > 0) &&
|
|
((hpr_finetrim_1 >= 0) &&
|
|
(abs(hpr_finetrim_1) < abs(hpr_base))))
|
|
finetrimr = 0x1;
|
|
if (hpl_finetrim_1 < 0 || hpr_finetrim_1 < 0) {
|
|
/* base and finetrim=1 across zero. */
|
|
/* Choose base, finetrim=1, and finetrim=3 */
|
|
if (hpl_finetrim_1 < 0 && hpl_base > 0) {
|
|
/* channel L */
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDDEC_ELR_0,
|
|
HPFINETRIM_L_MASK,
|
|
0x3 << HPFINETRIM_L_SHIFT);
|
|
code_change = true;
|
|
}
|
|
if (hpr_finetrim_1 < 0 && hpr_base > 0) {
|
|
/* channel R */
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDDEC_ELR_0,
|
|
HPFINETRIM_R_MASK,
|
|
0x3 << HPFINETRIM_R_SHIFT);
|
|
code_change = true;
|
|
}
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
®_value);
|
|
dev_info(priv->dev, "%s(), step3_2 > 0, AUDDEC_ELR_0 = 0x%x, code_change = %d\n",
|
|
__func__,
|
|
reg_value, code_change);
|
|
if (code_change) {
|
|
hp_trim_offset(priv);
|
|
code_change = false;
|
|
hpl_finetrim_3 =
|
|
priv->dc_trim.hp_trim_offset
|
|
[CH_L];
|
|
hpr_finetrim_3 =
|
|
priv->dc_trim.hp_trim_offset
|
|
[CH_R];
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDDEC_ELR_0,
|
|
HPFINETRIM_L_MASK,
|
|
0x0 << HPFINETRIM_L_SHIFT);
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDDEC_ELR_0,
|
|
HPFINETRIM_R_MASK,
|
|
0x0 << HPFINETRIM_R_SHIFT);
|
|
mdelay(10);
|
|
|
|
if (hpl_base > 0) {
|
|
finetriml =
|
|
pick_hp_finetrim(hpl_base,
|
|
hpl_finetrim_1,
|
|
hpl_finetrim_3);
|
|
dev_info(priv->dev, "%s(), [Step3] refine finetriml = %d\n",
|
|
__func__, finetriml);
|
|
}
|
|
if (hpr_base > 0) {
|
|
finetrimr =
|
|
pick_hp_finetrim(hpr_base,
|
|
hpr_finetrim_1,
|
|
hpr_finetrim_3);
|
|
dev_info(priv->dev, "%s(), [Step3] refine finetrimr = %d\n",
|
|
__func__, finetrimr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (hpl_base < 0 || hpr_base < 0) {
|
|
if (hpl_base < 0) {
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDDEC_ELR_0,
|
|
HPFINETRIM_L_MASK, 0x2 << HPFINETRIM_L_SHIFT);
|
|
code_change = true;
|
|
}
|
|
if (hpr_base < 0) {
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDDEC_ELR_0,
|
|
HPFINETRIM_R_MASK, 0x2 << HPFINETRIM_R_SHIFT);
|
|
code_change = true;
|
|
}
|
|
regmap_read(priv->regmap,
|
|
MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step3 < 0, AUDDEC_ELR_0 = 0x%x\n",
|
|
__func__, reg_value);
|
|
if (code_change) {
|
|
hp_trim_offset(priv);
|
|
code_change = false;
|
|
hpl_min =
|
|
priv->dc_trim.hp_trim_offset
|
|
[CH_L];
|
|
hpr_min =
|
|
priv->dc_trim.hp_trim_offset
|
|
[CH_R];
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPFINETRIM_L_MASK,
|
|
0x0 << HPFINETRIM_L_SHIFT);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPFINETRIM_R_MASK,
|
|
0x0 << HPFINETRIM_R_SHIFT);
|
|
mdelay(10);
|
|
if ((hpl_base < 0) &&
|
|
(hpl_min <= 0 || abs(hpl_min) < abs(hpl_base)))
|
|
finetriml = 0x2;
|
|
if ((hpr_base < 0) &&
|
|
(hpr_min <= 0 || abs(hpr_min) < abs(hpr_base)))
|
|
finetrimr = 0x2;
|
|
}
|
|
}
|
|
/* channel L */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPFINETRIM_L_MASK, finetriml << HPFINETRIM_L_SHIFT);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPFINETRIM_R_MASK, finetrimr << HPFINETRIM_R_SHIFT);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step3 result AUDDEC_ELR_0 = 0x%x\n",
|
|
__func__, reg_value);
|
|
EXIT:
|
|
/* 4 pole fine trim */
|
|
hp_trim_offset(priv);
|
|
hpl_min = priv->dc_trim.hp_trim_offset[CH_L];
|
|
hpr_min = priv->dc_trim.hp_trim_offset[CH_R];
|
|
mdelay(10);
|
|
priv->dc_trim.hp_3_pole_ana_offset.hp_trim_code[CH_L] = trimcodel;
|
|
priv->dc_trim.hp_3_pole_ana_offset.hp_fine_trim[CH_L] = finetriml;
|
|
priv->dc_trim.hp_3_pole_ana_offset.hp_trim_code[CH_R] = trimcoder;
|
|
priv->dc_trim.hp_3_pole_ana_offset.hp_fine_trim[CH_R] = finetrimr;
|
|
|
|
/* check trimcode is valid */
|
|
if ((trimcodel < 0 || trimcodel > 0xf) ||
|
|
(finetriml < 0 || finetriml > 0x3) ||
|
|
(trimcoder < 0 || trimcoder > 0xf) ||
|
|
(finetrimr < 0 || finetrimr > 0x3))
|
|
dev_info(priv->dev, "%s(), [Warning], invalid trimcode(3 pole), trimcodel = %d, finetriml = %d, trimcoder = %d, finetrimr = %d\n",
|
|
__func__, trimcodel, finetriml, trimcoder, finetrimr);
|
|
|
|
if ((hpl_min < 0) && (finetriml == 0x0)) {
|
|
finetriml = 0x2;
|
|
} else if ((hpl_min < 0) && (finetriml == 0x2)) {
|
|
if ((trimcodel != 0) && (trimcodel != 0xf)) {
|
|
finetriml = 0x0;
|
|
trimcodel = trimcodel - ((trimcodel > 7) ? -1 : 1);
|
|
} else {
|
|
dev_info(priv->dev, "%s(), [Step4][bit-overflow!!], don't refine, trimcodel = %d, finetriml = %d\n",
|
|
__func__, trimcodel, finetriml);
|
|
}
|
|
}
|
|
if ((hpr_min < 0) && (finetrimr == 0x0)) {
|
|
finetrimr = 0x2;
|
|
} else if ((hpr_min < 0) && (finetrimr == 0x2)) {
|
|
if ((trimcoder != 0) && (trimcoder != 0xf)) {
|
|
finetrimr = 0x0;
|
|
trimcoder = trimcoder - ((trimcoder > 7) ? -1 : 1);
|
|
} else {
|
|
dev_info(priv->dev, "%s(), [Step4][bit-overflow!!], don't refine, trimcoder = %d, finetrimr = %d\n",
|
|
__func__, trimcoder, finetrimr);
|
|
}
|
|
}
|
|
priv->dc_trim.hp_4_pole_ana_offset.hp_trim_code[CH_L] = trimcodel;
|
|
priv->dc_trim.hp_4_pole_ana_offset.hp_fine_trim[CH_L] = finetriml;
|
|
priv->dc_trim.hp_4_pole_ana_offset.hp_trim_code[CH_R] = trimcoder;
|
|
priv->dc_trim.hp_4_pole_ana_offset.hp_fine_trim[CH_R] = finetrimr;
|
|
|
|
/* check trimcode is valid */
|
|
if ((trimcodel < 0 || trimcodel > 0xf) ||
|
|
(finetriml < 0 || finetriml > 0x3) ||
|
|
(trimcoder < 0 || trimcoder > 0xf) ||
|
|
(finetrimr < 0 || finetrimr > 0x3))
|
|
dev_info(priv->dev, "%s(), [Warning], invalid trimcode(4 pole), trimcodel = %d, finetriml = %d, trimcoder = %d, finetrimr = %d\n",
|
|
__func__, trimcodel, finetriml, trimcoder, finetrimr);
|
|
|
|
offset_3_pole = &(priv->dc_trim.hp_3_pole_ana_offset);
|
|
offset_4_pole = &(priv->dc_trim.hp_4_pole_ana_offset);
|
|
hp_3_pole_trim_setting =
|
|
(offset_3_pole->enable << HPTRIM_EN_SHIFT) |
|
|
(offset_3_pole->hp_fine_trim[CH_R] << HPFINETRIM_R_SHIFT) |
|
|
(offset_3_pole->hp_fine_trim[CH_L] << HPFINETRIM_L_SHIFT) |
|
|
(offset_3_pole->hp_trim_code[CH_R] << HPTRIM_R_SHIFT) |
|
|
(offset_3_pole->hp_trim_code[CH_L] << HPTRIM_L_SHIFT);
|
|
hp_4_pole_trim_setting =
|
|
(offset_4_pole->enable << HPTRIM_EN_SHIFT) |
|
|
(offset_4_pole->hp_fine_trim[CH_R] << HPFINETRIM_R_SHIFT) |
|
|
(offset_4_pole->hp_fine_trim[CH_L] << HPFINETRIM_L_SHIFT) |
|
|
(offset_4_pole->hp_trim_code[CH_R] << HPTRIM_R_SHIFT) |
|
|
(offset_4_pole->hp_trim_code[CH_L] << HPTRIM_L_SHIFT);
|
|
priv->dc_trim.hp_3_pole_trim_setting = hp_3_pole_trim_setting;
|
|
priv->dc_trim.hp_4_pole_trim_setting = hp_4_pole_trim_setting;
|
|
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), Final result AUDDEC_ELR_0 = 0x%x, hp_3_pole_trim_setting = 0x%x, hp_4_pole_trim_setting = 0x%x\n",
|
|
__func__,
|
|
reg_value,
|
|
hp_3_pole_trim_setting, hp_4_pole_trim_setting);
|
|
dev_info(priv->dev, "%s(), get hp offset L = %d, R = %d\n",
|
|
__func__,
|
|
priv->dc_trim.hp_trim_offset[CH_L],
|
|
priv->dc_trim.hp_trim_offset[CH_R]);
|
|
}
|
|
|
|
static void set_lr_trim_code_spk(struct mt6358_priv *priv, int channel)
|
|
{
|
|
int hpl_base = 0;
|
|
int hpl_min = 0;
|
|
int hpl_ceiling = 0;
|
|
int hpl_floor = 0;
|
|
int hpl_finetrim_2 = 0;
|
|
int hpl_finetrim_3 = 0;
|
|
int trimcode = 0;
|
|
int trimcode_ceiling = 0;
|
|
int trimcode_floor = 0;
|
|
int finetrim = 0;
|
|
int trimcode_tmp = 0;
|
|
unsigned int spk_hp_3_pole_trim_setting = 0;
|
|
unsigned int spk_hp_4_pole_trim_setting = 0;
|
|
int trim_shift = 0, trim_mask = 0;
|
|
int fine_shift = 0, fine_mask = 0;
|
|
struct ana_offset *offset_3_pole = NULL;
|
|
struct ana_offset *offset_4_pole = NULL;
|
|
unsigned int reg_value = 0;
|
|
|
|
if (channel == TRIM_BUF_MUX_HPL) {
|
|
trim_shift = HPTRIM_L_SHIFT;
|
|
trim_mask = HPTRIM_L_MASK;
|
|
fine_shift = HPFINETRIM_L_SHIFT;
|
|
fine_mask = HPFINETRIM_L_MASK;
|
|
} else if (channel == TRIM_BUF_MUX_HPR) {
|
|
trim_shift = HPTRIM_R_SHIFT;
|
|
trim_mask = HPTRIM_R_MASK;
|
|
fine_shift = HPFINETRIM_R_SHIFT;
|
|
fine_mask = HPFINETRIM_R_MASK;
|
|
}
|
|
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), Start DCtrim Calibrating, channel = %d, AUDDEC_ELR_0 = 0x%x\n",
|
|
__func__, channel, reg_value);
|
|
|
|
/* Step1: get trim code */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
HPTRIM_EN_MASK, 0x1 << HPTRIM_EN_SHIFT);
|
|
priv->dc_trim.spk_3_pole_ana_offset.enable = 0x1;
|
|
priv->dc_trim.spk_4_pole_ana_offset.enable = 0x1;
|
|
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
trim_mask, 0x0 << trim_shift);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
fine_mask, 0x0 << fine_shift);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), AUDDEC_ELR_0 = 0x%x\n", __func__, reg_value);
|
|
hpl_base = spk_trim_offset(priv, channel);
|
|
mdelay(10);
|
|
|
|
if (hpl_base == 0)
|
|
goto EXIT;
|
|
|
|
if (hpl_base > 0) {
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
trim_mask, 0x2 << trim_shift);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step1 > 0, AUDDEC_ELR_0 = 0x%x, trimcode = %d\n",
|
|
__func__, reg_value, trimcode);
|
|
hpl_min = spk_trim_offset(priv, channel);
|
|
if (hpl_base == hpl_min)
|
|
goto EXIT;
|
|
mdelay(10);
|
|
/* Check floor and ceiling value to avoid rounding error */
|
|
trimcode_floor = (abs(hpl_base) * 3) / abs(hpl_base - hpl_min);
|
|
trimcode_ceiling = trimcode_floor + 1;
|
|
dev_info(priv->dev, "%s(), step1 > 0, get trim level trimcode_floor = %d, trimcode_ceiling = %d\n",
|
|
__func__, trimcode_floor, trimcode_ceiling);
|
|
} else {
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
trim_mask, 0xa << trim_shift);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step1 < 0, AUDDEC_ELR_0 = 0x%x, trimcode = %d\n",
|
|
__func__, reg_value, trimcode);
|
|
hpl_min = spk_trim_offset(priv, channel);
|
|
if (hpl_base == hpl_min)
|
|
goto EXIT;
|
|
mdelay(10);
|
|
/* Check floor and ceiling value to avoid rounding error */
|
|
trimcode_floor = (abs(hpl_base) * 3) / abs(hpl_base - hpl_min) + 8;
|
|
trimcode_ceiling = trimcode_floor + 1;
|
|
dev_info(priv->dev, "%s(), step1 < 0, get trim level trimcode_floor = %d, trimcode_ceiling = %d\n",
|
|
__func__, trimcode_floor, trimcode_ceiling);
|
|
}
|
|
/* Get the best trim code from floor and ceiling value */
|
|
/* Get floor trim code */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
trim_mask, trimcode_floor << trim_shift);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step1 floor AUDDEC_ELR_0 = 0x%x, trimcode_floor = %d\n",
|
|
__func__, reg_value, trimcode_floor);
|
|
hpl_floor = spk_trim_offset(priv, channel);
|
|
mdelay(10);
|
|
/* Get ceiling trim code */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
trim_mask, trimcode_ceiling << trim_shift);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step1 ceiling AUDDEC_ELR_0 = 0x%x, trimcode_ceiling = %d\n",
|
|
__func__, reg_value, trimcode_ceiling);
|
|
hpl_ceiling = spk_trim_offset(priv, channel);
|
|
mdelay(10);
|
|
/* Choose the best */
|
|
if (abs(hpl_ceiling) < abs(hpl_floor)) {
|
|
hpl_base = hpl_ceiling;
|
|
trimcode = trimcode_ceiling;
|
|
} else {
|
|
hpl_base = hpl_floor;
|
|
trimcode = trimcode_floor;
|
|
}
|
|
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
trim_mask, trimcode << trim_shift);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step1 result: AUDDEC_ELR_0 = 0x%x, hp_base = %d, trimcode = %d\n",
|
|
__func__, reg_value, hpl_base, trimcode);
|
|
|
|
/* Step2: Trim code refine +1/0/-1 */
|
|
hpl_base = spk_trim_offset(priv, channel);
|
|
mdelay(10);
|
|
|
|
if (hpl_base == 0)
|
|
goto EXIT;
|
|
|
|
if (hpl_base > 0) {
|
|
if ((trimcode != 0x7) && (trimcode != 0x8)) {
|
|
trimcode_tmp = trimcode + ((trimcode > 7) ? -1 : 1);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
trim_mask,
|
|
trimcode_tmp << trim_shift);
|
|
regmap_read(priv->regmap,
|
|
MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step2 > 0, AUDDEC_ELR_0 = 0x%x, trimcode_tmp = %d\n",
|
|
__func__, reg_value, trimcode_tmp);
|
|
hpl_min = spk_trim_offset(priv, channel);
|
|
mdelay(10);
|
|
if (hpl_min >= 0 || abs(hpl_min) < abs(hpl_base)) {
|
|
trimcode = trimcode_tmp;
|
|
hpl_base = hpl_min;
|
|
}
|
|
}
|
|
} else {
|
|
if ((trimcode != 0) && (trimcode != 0xf)) {
|
|
trimcode_tmp = trimcode - ((trimcode > 7) ? -1 : 1);
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDDEC_ELR_0,
|
|
trim_mask, trimcode_tmp << trim_shift);
|
|
regmap_read(priv->regmap,
|
|
MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step2 < 0, AUDDEC_ELR_0 = 0x%x, trimcode_tmp = %d\n",
|
|
__func__, reg_value, trimcode_tmp);
|
|
hpl_min = spk_trim_offset(priv, channel);
|
|
mdelay(10);
|
|
if (hpl_min <= 0 || abs(hpl_min) < abs(hpl_base)) {
|
|
trimcode = trimcode_tmp;
|
|
hpl_base = hpl_min;
|
|
}
|
|
}
|
|
}
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDDEC_ELR_0,
|
|
trim_mask, trimcode << trim_shift);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step2 result AUDDEC_ELR_0 = 0x%x, trimcode = %d\n",
|
|
__func__, reg_value, trimcode);
|
|
|
|
/* Step3: Trim code fine tune */
|
|
mdelay(10);
|
|
|
|
if (hpl_base == 0)
|
|
goto EXIT;
|
|
if (hpl_base > 0) {
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDDEC_ELR_0,
|
|
fine_mask, 0x1 << fine_shift);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step3 > 0, AUDDEC_ELR_0 = 0x%x\n",
|
|
__func__, reg_value);
|
|
hpl_min = spk_trim_offset(priv, channel);
|
|
mdelay(10);
|
|
|
|
if (hpl_min >= 0 ||
|
|
abs(hpl_min) < abs(hpl_base)) {
|
|
finetrim = 0x1;
|
|
hpl_base = hpl_min;
|
|
} else {
|
|
regmap_update_bits(priv->regmap,
|
|
MT6358_AUDDEC_ELR_0,
|
|
fine_mask, 0x3 << fine_shift);
|
|
regmap_read(priv->regmap,
|
|
MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step3_2 > 0, AUDDEC_ELR_0 = 0x%x\n ",
|
|
__func__, reg_value);
|
|
hpl_min = spk_trim_offset(priv, channel);
|
|
mdelay(10);
|
|
if (hpl_min >= 0 && abs(hpl_min) < abs(hpl_base)) {
|
|
finetrim = 0x3;
|
|
hpl_base = hpl_min;
|
|
}
|
|
}
|
|
} else {
|
|
/* SPK+HP finetrim=3 compensates positive DC value */
|
|
/* choose the best fine trim */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
fine_mask, 0x2 << fine_shift);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step3 < 0, AUDDEC_ELR_0 = 0x%x\n",
|
|
__func__, reg_value);
|
|
hpl_finetrim_2 = spk_trim_offset(priv, channel);
|
|
mdelay(10);
|
|
if ((hpl_finetrim_2 <= 0) &&
|
|
(abs(hpl_finetrim_2) < abs(hpl_base))) {
|
|
finetrim = 0x2;
|
|
hpl_base = hpl_finetrim_2;
|
|
} else {
|
|
/* base and finetrim=2 across zero */
|
|
/* Choose best from base, finetrim=2, and finetrim=3 */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
fine_mask, 0x3 << fine_shift);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
®_value);
|
|
dev_info(priv->dev, "%s(), step3_2 < 0, AUDDEC_ELR_0 = 0x%x\n",
|
|
__func__, reg_value);
|
|
hpl_finetrim_3 = spk_trim_offset(priv, channel);
|
|
mdelay(10);
|
|
|
|
finetrim = pick_spk_finetrim(hpl_base,
|
|
hpl_finetrim_2,
|
|
hpl_finetrim_3);
|
|
if (finetrim == 0x2)
|
|
hpl_base = hpl_finetrim_2;
|
|
else if (finetrim == 0x3)
|
|
hpl_base = hpl_finetrim_3;
|
|
}
|
|
}
|
|
|
|
dev_info(priv->dev, "%s(), refine finetrim = %d\n",
|
|
__func__, finetrim);
|
|
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ELR_0,
|
|
fine_mask, finetrim << fine_shift);
|
|
EXIT:
|
|
priv->dc_trim.spk_3_pole_ana_offset.hp_trim_code[CH_L] = trimcode;
|
|
priv->dc_trim.spk_3_pole_ana_offset.hp_fine_trim[CH_L] = finetrim;
|
|
priv->dc_trim.spk_3_pole_ana_offset.hp_trim_code[CH_R] =
|
|
priv->dc_trim.hp_3_pole_ana_offset.hp_trim_code[CH_R];
|
|
priv->dc_trim.spk_3_pole_ana_offset.hp_fine_trim[CH_R] =
|
|
priv->dc_trim.hp_3_pole_ana_offset.hp_fine_trim[CH_R];
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), step3 result AUDDEC_ELR_0 = 0x%x\n",
|
|
__func__, reg_value);
|
|
|
|
/* check trimcode is valid */
|
|
if ((trimcode < 0 || trimcode > 0xf) ||
|
|
(finetrim < 0 || finetrim > 0x3))
|
|
dev_info(priv->dev, "%s(), [Warning], invalid trimcode(3pole), trimcode = %d, finetrim = %d\n",
|
|
__func__, trimcode, finetrim);
|
|
|
|
/* 4 pole fine trim */
|
|
hpl_base = spk_trim_offset(priv, channel);
|
|
mdelay(10);
|
|
|
|
if ((hpl_base < 0) && (finetrim == 0x0)) {
|
|
finetrim = 0x2;
|
|
} else if ((hpl_base < 0) && (finetrim == 0x2)) {
|
|
if ((trimcode != 0) && (trimcode != 0xf)) {
|
|
finetrim = 0x0;
|
|
trimcode = trimcode - ((trimcode > 7) ? -1 : 1);
|
|
}
|
|
}
|
|
|
|
priv->dc_trim.spk_4_pole_ana_offset.hp_trim_code[CH_L] = trimcode;
|
|
priv->dc_trim.spk_4_pole_ana_offset.hp_fine_trim[CH_L] = finetrim;
|
|
priv->dc_trim.spk_4_pole_ana_offset.hp_trim_code[CH_R] =
|
|
priv->dc_trim.hp_4_pole_ana_offset.hp_trim_code[CH_R];
|
|
priv->dc_trim.spk_4_pole_ana_offset.hp_fine_trim[CH_R] =
|
|
priv->dc_trim.hp_4_pole_ana_offset.hp_fine_trim[CH_R];
|
|
|
|
/* check trimcode is valid */
|
|
if ((trimcode < 0 || trimcode > 0xf) ||
|
|
(finetrim < 0 || finetrim > 0x3))
|
|
dev_info(priv->dev, "%s(), [Warning], invalid trimcode(4 pole), trimcode = %d, finetrim = %d\n",
|
|
__func__, trimcode, finetrim);
|
|
|
|
offset_3_pole = &(priv->dc_trim.spk_3_pole_ana_offset);
|
|
offset_4_pole = &(priv->dc_trim.spk_4_pole_ana_offset);
|
|
spk_hp_3_pole_trim_setting =
|
|
(offset_3_pole->enable << HPTRIM_EN_SHIFT) |
|
|
(offset_3_pole->hp_fine_trim[CH_R] << HPFINETRIM_R_SHIFT) |
|
|
(offset_3_pole->hp_fine_trim[CH_L] << HPFINETRIM_L_SHIFT) |
|
|
(offset_3_pole->hp_trim_code[CH_R] << HPTRIM_R_SHIFT) |
|
|
(offset_3_pole->hp_trim_code[CH_L] << HPTRIM_L_SHIFT);
|
|
spk_hp_4_pole_trim_setting =
|
|
(offset_4_pole->enable << HPTRIM_EN_SHIFT) |
|
|
(offset_4_pole->hp_fine_trim[CH_R] << HPFINETRIM_R_SHIFT) |
|
|
(offset_4_pole->hp_fine_trim[CH_L] << HPFINETRIM_L_SHIFT) |
|
|
(offset_4_pole->hp_trim_code[CH_R]) |
|
|
(offset_4_pole->hp_trim_code[CH_L] << HPTRIM_L_SHIFT);
|
|
priv->dc_trim.spk_hp_3_pole_trim_setting = spk_hp_3_pole_trim_setting;
|
|
priv->dc_trim.spk_hp_4_pole_trim_setting = spk_hp_4_pole_trim_setting;
|
|
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, ®_value);
|
|
dev_info(priv->dev, "%s(), Final result AUDDEC_ELR_0 = 0x%x, spk_hp_3_pole_trim_setting = 0x%x, spk_hp_4_pole_trim_setting = 0x%x\n",
|
|
__func__,
|
|
reg_value,
|
|
spk_hp_3_pole_trim_setting, spk_hp_4_pole_trim_setting);
|
|
dev_info(priv->dev, "%s(), get spkl offset = %d, channel = %d\n",
|
|
__func__, spk_trim_offset(priv, channel), channel);
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|
|
static void get_hp_trim_offset(struct mt6358_priv *priv, bool force)
|
|
{
|
|
struct dc_trim_data *dc_trim = &priv->dc_trim;
|
|
|
|
if (dc_trim->calibrated && !force)
|
|
return;
|
|
|
|
dev_info(priv->dev, "%s(), Start DCtrim Calibrating", __func__);
|
|
#if !defined(SKIP_SB) && !defined(CONFIG_FPGA_EARLY_PORTING)
|
|
enable_trim_circuit(priv, true);
|
|
#ifdef ANALOG_HPTRIM
|
|
set_lr_trim_code(priv);
|
|
priv->dc_trim.hp_offset[CH_L] = priv->dc_trim.hp_trim_offset[CH_L];
|
|
priv->dc_trim.hp_offset[CH_R] = priv->dc_trim.hp_trim_offset[CH_R];
|
|
dev_info(priv->dev, "%s(), priv->dc_trim.hp_offset[CH_L]: %d, priv->dc_trim.hp_offset[CH_R]: %d\n",
|
|
__func__,
|
|
priv->dc_trim.hp_offset[CH_L],
|
|
priv->dc_trim.hp_offset[CH_R]);
|
|
|
|
set_lr_trim_code_spk(priv, TRIM_BUF_MUX_HPL);
|
|
priv->dc_trim.spk_l_offset = spk_trim_offset(priv, TRIM_BUF_MUX_HPL);
|
|
dev_info(priv->dev, "%s(), priv->spkl_dc_offset: %d\n", __func__,
|
|
priv->dc_trim.spk_l_offset);
|
|
#else
|
|
dc_trim->hp_offset[CH_L] = hp_trim_offset(priv, TRIM_BUF_MUX_HPL);
|
|
dc_trim->hp_offset[CH_R] = hp_trim_offset(priv, TRIM_BUF_MUX_HPR);
|
|
#endif
|
|
enable_trim_circuit(priv, false);
|
|
udelay(1000);
|
|
#endif
|
|
dc_trim->calibrated = true;
|
|
dev_info(priv->dev, "%s(), End DCtrim Calibrating, L: %d, R: %d",
|
|
__func__,
|
|
dc_trim->hp_offset[CH_L], dc_trim->hp_offset[CH_R]);
|
|
}
|
|
|
|
static void mic_type_default_init(struct mt6358_priv *priv)
|
|
{
|
|
if (IS_DCC_BASE(priv->mux_select[MUX_MIC_TYPE])) {
|
|
/* L preamplifier DCCEN */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDPREAMPLDCCEN_MASK_SFT,
|
|
0x1 << RG_AUDPREAMPLDCCEN_SFT);
|
|
/* R preamplifier DCCEN */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
RG_AUDPREAMPRDCCEN_MASK_SFT,
|
|
0x1 << RG_AUDPREAMPRDCCEN_SFT);
|
|
}
|
|
}
|
|
|
|
static int dc_trim_thread(void *arg)
|
|
{
|
|
struct mt6358_priv *priv = arg;
|
|
|
|
if (priv->pull_down_stay_enable)
|
|
hp_pull_down(priv, true);
|
|
|
|
get_hp_trim_offset(priv, false);
|
|
#if IS_ENABLED(CONFIG_SND_SOC_MT6366_ACCDET) || IS_ENABLED(CONFIG_SND_SOC_MT6358_ACCDET)
|
|
mt6358_accdet_late_init(0);
|
|
#endif
|
|
do_exit(0);
|
|
return 0;
|
|
}
|
|
|
|
/* Headphone Impedance Detection */
|
|
static int mtk_calculate_impedance_formula(int pcm_offset, int aux_diff)
|
|
{
|
|
/* The formula is from DE programming guide */
|
|
/* should be mantain by pmic owner */
|
|
/* R = V /I */
|
|
/* V = auxDiff * (1800mv /auxResolution) /TrimBufGain */
|
|
/* I = pcmOffset * DAC_constant * Gsdm * Gibuf */
|
|
|
|
return DIV_ROUND_CLOSEST(3600000 / pcm_offset * aux_diff, 7832);
|
|
}
|
|
|
|
static int calculate_impedance(struct mt6358_priv *priv,
|
|
int dc_init, int dc_input,
|
|
short pcm_offset,
|
|
const unsigned int detect_times)
|
|
{
|
|
int dc_value;
|
|
int r_tmp = 0;
|
|
|
|
if (dc_input < dc_init) {
|
|
dev_warn(priv->dev, "%s(), Wrong[%d] : dc_input(%d) < dc_init(%d)\n",
|
|
__func__, pcm_offset, dc_input, dc_init);
|
|
return 0;
|
|
}
|
|
|
|
dc_value = dc_input - dc_init;
|
|
r_tmp = mtk_calculate_impedance_formula(pcm_offset, dc_value);
|
|
r_tmp = DIV_ROUND_CLOSEST(r_tmp, detect_times);
|
|
|
|
/* Efuse calibration */
|
|
if ((priv->hp_current_calibrate_val != 0) && (r_tmp != 0)) {
|
|
dev_info(priv->dev, "%s(), Before Calibration from EFUSE: %d, R: %d\n",
|
|
__func__, priv->hp_current_calibrate_val, r_tmp);
|
|
r_tmp = DIV_ROUND_CLOSEST(
|
|
r_tmp * 128 + priv->hp_current_calibrate_val,
|
|
128);
|
|
}
|
|
|
|
dev_info(priv->dev, "%s(), pcm_offset %d dcoffset %d detected resistor is %d\n",
|
|
__func__, pcm_offset, dc_value, r_tmp);
|
|
|
|
return r_tmp;
|
|
}
|
|
|
|
#define PARALLEL_OHM 0
|
|
static int detect_impedance(struct mt6358_priv *priv)
|
|
{
|
|
const unsigned int num_detect = 8;
|
|
int i;
|
|
int dc_sum = 0, detect_sum = 0;
|
|
int pick_impedance = 0, impedance = 0, phase_flag = 0;
|
|
int cur_dc = 0;
|
|
unsigned int value;
|
|
|
|
/* params by chip */
|
|
int auxcable_impedance = 5000;
|
|
/* should little lower than auxadc max resolution */
|
|
int auxadc_upper_bound = 32630;
|
|
/* Dc ramp up and ramp down step */
|
|
int dc_step = 96;
|
|
/* Phase 0 : high impedance with worst resolution */
|
|
int dc_phase0 = 288;
|
|
/* Phase 1 : median impedance with normal resolution */
|
|
int dc_phase1 = 1440;
|
|
/* Phase 2 : low impedance with better resolution */
|
|
int dc_phase2 = 6048;
|
|
/* Resistance Threshold of phase 2 and phase 1 */
|
|
int resistance_1st_threshold = 250;
|
|
/* Resistance Threshold of phase 1 and phase 0 */
|
|
int resistance_2nd_threshold = 1000;
|
|
|
|
if (priv->ops.adda_dl_gain_control) {
|
|
priv->ops.adda_dl_gain_control(true);
|
|
} else {
|
|
dev_warn(priv->dev, "%s(), adda_dl_gain_control ops not ready\n",
|
|
__func__);
|
|
return 0;
|
|
}
|
|
|
|
if (priv->ops.enable_dc_compensation &&
|
|
priv->ops.set_lch_dc_compensation &&
|
|
priv->ops.set_rch_dc_compensation) {
|
|
priv->ops.set_lch_dc_compensation(0);
|
|
priv->ops.set_rch_dc_compensation(0);
|
|
priv->ops.enable_dc_compensation(true);
|
|
} else {
|
|
dev_warn(priv->dev, "%s(), dc compensation ops not ready\n",
|
|
__func__);
|
|
return 0;
|
|
}
|
|
|
|
regmap_update_bits(priv->regmap, MT6358_AUXADC_CON10,
|
|
0x7, AUXADC_AVG_64);
|
|
|
|
set_trim_buf_in_mux(priv, TRIM_BUF_MUX_HPR);
|
|
set_trim_buf_gain(priv, TRIM_BUF_GAIN_18DB);
|
|
enable_trim_buf(priv, true);
|
|
|
|
/* set hp gain 0dB */
|
|
regmap_update_bits(priv->regmap, MT6358_ZCD_CON2,
|
|
RG_AUDHPRGAIN_MASK_SFT,
|
|
DL_GAIN_0DB << RG_AUDHPRGAIN_SFT);
|
|
regmap_update_bits(priv->regmap, MT6358_ZCD_CON2,
|
|
RG_AUDHPLGAIN_MASK_SFT, DL_GAIN_0DB);
|
|
|
|
for (cur_dc = 0; cur_dc <= dc_phase2; cur_dc += dc_step) {
|
|
/* apply dc by dc compensation: 16bit MSB and negative value */
|
|
priv->ops.set_lch_dc_compensation(-cur_dc << 16);
|
|
priv->ops.set_rch_dc_compensation(-cur_dc << 16);
|
|
|
|
/* save for DC = 0 offset */
|
|
if (cur_dc == 0) {
|
|
usleep_range(1 * 1000, 1 * 1000);
|
|
dc_sum = 0;
|
|
for (i = 0; i < num_detect; i++)
|
|
dc_sum += mt6358_get_hpofs_auxadc(priv);
|
|
|
|
if ((dc_sum / num_detect) > auxadc_upper_bound) {
|
|
dev_info(priv->dev, "%s(), cur_dc == 0, auxadc value %d > auxadc_upper_bound %d\n",
|
|
__func__,
|
|
dc_sum / num_detect,
|
|
auxadc_upper_bound);
|
|
impedance = auxcable_impedance;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* start checking */
|
|
if (cur_dc == dc_phase0) {
|
|
usleep_range(1 * 1000, 1 * 1000);
|
|
detect_sum = 0;
|
|
detect_sum = mt6358_get_hpofs_auxadc(priv);
|
|
|
|
if ((dc_sum / num_detect) == detect_sum) {
|
|
dev_info(priv->dev, "%s(), dc_sum / num_detect %d == detect_sum %d\n",
|
|
__func__,
|
|
dc_sum / num_detect, detect_sum);
|
|
impedance = auxcable_impedance;
|
|
break;
|
|
}
|
|
|
|
pick_impedance = calculate_impedance(
|
|
priv,
|
|
dc_sum / num_detect,
|
|
detect_sum, cur_dc, 1);
|
|
|
|
if (pick_impedance < resistance_1st_threshold) {
|
|
phase_flag = 2;
|
|
continue;
|
|
} else if (pick_impedance < resistance_2nd_threshold) {
|
|
phase_flag = 1;
|
|
continue;
|
|
}
|
|
|
|
/* Phase 0 : detect range 1kohm to 5kohm impedance */
|
|
for (i = 1; i < num_detect; i++)
|
|
detect_sum += mt6358_get_hpofs_auxadc(priv);
|
|
|
|
/* if auxadc > 32630 , the hpImpedance is over 5k ohm */
|
|
if ((detect_sum / num_detect) > auxadc_upper_bound)
|
|
impedance = auxcable_impedance;
|
|
else
|
|
impedance = calculate_impedance(priv,
|
|
dc_sum,
|
|
detect_sum,
|
|
cur_dc,
|
|
num_detect);
|
|
break;
|
|
}
|
|
|
|
/* Phase 1 : detect range 250ohm to 1000ohm impedance */
|
|
if (phase_flag == 1 && cur_dc == dc_phase1) {
|
|
usleep_range(1 * 1000, 1 * 1000);
|
|
detect_sum = 0;
|
|
for (i = 0; i < num_detect; i++)
|
|
detect_sum += mt6358_get_hpofs_auxadc(priv);
|
|
|
|
impedance = calculate_impedance(priv,
|
|
dc_sum, detect_sum,
|
|
cur_dc, num_detect);
|
|
break;
|
|
}
|
|
|
|
/* Phase 2 : detect under 250ohm impedance */
|
|
if (phase_flag == 2 && cur_dc == dc_phase2) {
|
|
usleep_range(1 * 1000, 1 * 1000);
|
|
detect_sum = 0;
|
|
for (i = 0; i < num_detect; i++)
|
|
detect_sum += mt6358_get_hpofs_auxadc(priv);
|
|
|
|
impedance = calculate_impedance(priv,
|
|
dc_sum, detect_sum,
|
|
cur_dc, num_detect);
|
|
break;
|
|
}
|
|
usleep_range(1 * 200, 1 * 200);
|
|
}
|
|
|
|
if (PARALLEL_OHM != 0) {
|
|
if (impedance < PARALLEL_OHM) {
|
|
impedance = DIV_ROUND_CLOSEST(impedance * PARALLEL_OHM,
|
|
PARALLEL_OHM - impedance);
|
|
} else {
|
|
dev_warn(priv->dev, "%s(), PARALLEL_OHM %d <= impedance %d\n",
|
|
__func__, PARALLEL_OHM, impedance);
|
|
}
|
|
}
|
|
|
|
regmap_read(priv->regmap, MT6358_AUXADC_CON10, &value);
|
|
dev_info(priv->dev, "%s(), phase %d [dc,detect]Sum %d times [%d,%d], hp_impedance %d, pick_impedance %d, AUXADC_CON10 0x%x\n",
|
|
__func__, phase_flag, num_detect, dc_sum, detect_sum,
|
|
impedance, pick_impedance, value);
|
|
|
|
/* Ramp-Down */
|
|
while (cur_dc > 0) {
|
|
cur_dc -= dc_step;
|
|
/* apply dc by dc compensation: 16bit MSB and negative value */
|
|
priv->ops.set_lch_dc_compensation(-cur_dc << 16);
|
|
priv->ops.set_rch_dc_compensation(-cur_dc << 16);
|
|
usleep_range(1 * 200, 1 * 200);
|
|
}
|
|
|
|
priv->ops.set_lch_dc_compensation(0);
|
|
priv->ops.set_rch_dc_compensation(0);
|
|
priv->ops.enable_dc_compensation(false);
|
|
priv->ops.adda_dl_gain_control(false);
|
|
|
|
set_trim_buf_in_mux(priv, TRIM_BUF_MUX_GROUND);
|
|
enable_trim_buf(priv, false);
|
|
|
|
return impedance;
|
|
}
|
|
|
|
static int hp_impedance_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
if (priv->dev_counter[DEVICE_HP] <= 0 ||
|
|
priv->mux_select[MUX_HP_L] != HP_MUX_HP_IMPEDANCE) {
|
|
dev_warn(priv->dev, "%s(), counter %d <= 0 || mux_select[MUX_HP_L] %d != HP_MUX_HP_IMPEDANCE\n",
|
|
__func__,
|
|
priv->dev_counter[DEVICE_HP],
|
|
priv->mux_select[MUX_HP_L]);
|
|
ucontrol->value.integer.value[0] = priv->hp_impedance;
|
|
return 0;
|
|
}
|
|
|
|
priv->hp_impedance = detect_impedance(priv);
|
|
|
|
ucontrol->value.integer.value[0] = priv->hp_impedance;
|
|
|
|
dev_info(priv->dev, "%s(), hp_impedance = %d, efuse = %d\n",
|
|
__func__, priv->hp_impedance, priv->hp_current_calibrate_val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* vow control */
|
|
static int *get_vow_coeff_by_name(struct mt6358_priv *priv,
|
|
const char *name)
|
|
{
|
|
if (strcmp(name, "Audio VOWCFG0 Data") == 0)
|
|
return &(priv->reg_afe_vow_cfg0);
|
|
else if (strcmp(name, "Audio VOWCFG1 Data") == 0)
|
|
return &(priv->reg_afe_vow_cfg1);
|
|
else if (strcmp(name, "Audio VOWCFG2 Data") == 0)
|
|
return &(priv->reg_afe_vow_cfg2);
|
|
else if (strcmp(name, "Audio VOWCFG3 Data") == 0)
|
|
return &(priv->reg_afe_vow_cfg3);
|
|
else if (strcmp(name, "Audio VOWCFG4 Data") == 0)
|
|
return &(priv->reg_afe_vow_cfg4);
|
|
else if (strcmp(name, "Audio VOWCFG5 Data") == 0)
|
|
return &(priv->reg_afe_vow_cfg5);
|
|
else if (strcmp(name, "Audio_VOW_Periodic") == 0)
|
|
return &(priv->reg_afe_vow_periodic);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
static int audio_vow_cfg_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
int *vow_cfg;
|
|
|
|
vow_cfg = get_vow_coeff_by_name(priv, kcontrol->id.name);
|
|
if (!vow_cfg) {
|
|
dev_err(priv->dev, "%s(), vow_cfg == NULL\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
dev_info(priv->dev, "%s(), %s = %d\n",
|
|
__func__, kcontrol->id.name, *vow_cfg);
|
|
|
|
ucontrol->value.integer.value[0] = *vow_cfg;
|
|
return 0;
|
|
}
|
|
|
|
static int audio_vow_cfg_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
int index = ucontrol->value.integer.value[0];
|
|
int *vow_cfg;
|
|
|
|
vow_cfg = get_vow_coeff_by_name(priv, kcontrol->id.name);
|
|
if (!vow_cfg) {
|
|
dev_err(priv->dev, "%s(), vow_cfg == NULL\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
dev_info(priv->dev, "%s(), %s = %d\n",
|
|
__func__, kcontrol->id.name, index);
|
|
|
|
*vow_cfg = index;
|
|
return 0;
|
|
}
|
|
|
|
/* misc control */
|
|
static const char *const off_on_function[] = {"Off", "On"};
|
|
|
|
static int hp_plugged_in_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
ucontrol->value.integer.value[0] = priv->hp_plugged;
|
|
return 0;
|
|
}
|
|
|
|
static int hp_plugged_in_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(off_on_function)) {
|
|
dev_warn(priv->dev, "%s(), return -EINVAL\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (ucontrol->value.integer.value[0] == 1) {
|
|
priv->dc_trim.mic_vinp_mv = mt6358_get_hpofs_auxadc(priv);
|
|
dev_info(priv->dev, "%s(), mic_vinp_mv = %d\n",
|
|
__func__, priv->dc_trim.mic_vinp_mv);
|
|
}
|
|
|
|
priv->hp_plugged = ucontrol->value.integer.value[0];
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef ANALOG_HPTRIM
|
|
static int disable_analog_dc_compensation_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
ucontrol->value.integer.value[0] =
|
|
priv->dc_trim.dc_compensation_disabled;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int disable_analog_dc_compensation_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
if (ucontrol->value.enumerated.item[0] > ARRAY_SIZE(off_on_function)) {
|
|
dev_warn(priv->dev, "%s(), return -EINVAL\n",
|
|
__func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
priv->dc_trim.dc_compensation_disabled =
|
|
ucontrol->value.integer.value[0];
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int mt6358_rcv_mic_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
int rcv_mic_type = ucontrol->value.integer.value[0];
|
|
int status;
|
|
|
|
dev_info(priv->dev, "%s(), rcv_mic_type = %d\n",
|
|
__func__, rcv_mic_type);
|
|
|
|
if (!IS_ERR(priv->reg_vaud28)) {
|
|
status = regulator_enable(priv->reg_vaud28);
|
|
if (status)
|
|
dev_info(priv->dev, "%s() failed to enable vaud28(%d)\n",
|
|
__func__, status);
|
|
}
|
|
|
|
/* receiver downlink */
|
|
playback_gpio_set(priv);
|
|
/* Disable audio globe bias */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13,
|
|
0x1 << 4, 0x0);
|
|
if (!priv->pull_down_stay_enable) {
|
|
/* Pull-down HPL/R to AVSS28_AUD */
|
|
hp_pull_down(priv, true);
|
|
}
|
|
/* release HP CMFB gate rstb */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4,
|
|
0x1 << 6, 0x1 << 6);
|
|
/* XO_AUDIO_EN_M Enable */
|
|
regmap_update_bits(priv->regmap, MT6358_DCXO_CW14,
|
|
0x1 << 13, 0x1 << 13);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON6,
|
|
0x0003, 0x0001);
|
|
regmap_update_bits(priv->regmap, MT6358_AUD_TOP_CKPDN_CON0,
|
|
0x66, 0x0);
|
|
usleep_range(250, 270);
|
|
/* Audio system digital clock power down release */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDIO_TOP_CON0,
|
|
0x00c5, 0x0000);
|
|
usleep_range(250, 270);
|
|
|
|
/* sdm audio fifo clock power on */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0006);
|
|
/* scrambler clock on enable */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xcba1);
|
|
/* sdm power on */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0003);
|
|
/* sdm fifo enable */
|
|
regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x000B);
|
|
|
|
/* afe enable, dl_lr_swap = 0 */
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_UL_DL_CON0,
|
|
0x4001, 0x0001);
|
|
|
|
/* turn on dl */
|
|
regmap_write(priv->regmap, MT6358_AFE_DL_SRC2_CON0_L, 0x0001);
|
|
|
|
/* set DL in normal path, not from sine gen table */
|
|
regmap_write(priv->regmap, MT6358_AFE_TOP_CON0, 0x0000);
|
|
|
|
/* Reduce ESD resistance of AU_REFN */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4000);
|
|
|
|
/* Turn on DA_600K_NCP_VA18 */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON1, 0x0001);
|
|
/* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON2, 0x002c);
|
|
/* Toggle RG_DIVCKS_CHG */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON0, 0x0001);
|
|
/* Set NCP soft start mode as default mode: 100us */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON4, 0x0003);
|
|
/* Enable NCP */
|
|
regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x0000);
|
|
usleep_range(250, 270);
|
|
|
|
/* Enable cap-less LDOs (1.5V) */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x1055, 0x1055);
|
|
/* Enable NV regulator (-1.2V) */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x0001);
|
|
usleep_range(100, 120);
|
|
|
|
/* Enable AUD_ZCD */
|
|
zcd_enable(priv, true, DEVICE_RCV);
|
|
|
|
/* Disable handset short-circuit protection */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0010);
|
|
/* Enable IBIST */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055);
|
|
/* Set HP DR bias current optimization, 010: 6uA */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON11,
|
|
0xff80, 0x4900);
|
|
/* Set HP & ZCD bias current optimization */
|
|
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055);
|
|
/* Set HS STB enhance circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0090);
|
|
|
|
/* Disable HP main CMFB loop */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0000);
|
|
/* Select CMFB resistor bulk to AC mode */
|
|
/* Selec HS/LO cap size (6.5pF default) */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON10, 0x0000);
|
|
|
|
/* Enable HS driver bias circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0092);
|
|
/* Enable HS driver core circuits */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0093);
|
|
|
|
/* Set HS gain to normal gain step by step */
|
|
regmap_write(priv->regmap, MT6358_ZCD_CON3, 0x0);
|
|
|
|
/* Enable AUD_CLK */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x1);
|
|
/* Enable Audio DAC */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x0009);
|
|
/* Enable low-noise mode of DAC */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0001);
|
|
/* Switch HS MUX to audio DAC */
|
|
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x009b);
|
|
|
|
/* phone mic */
|
|
|
|
/* Enable audio ADC CLKGEN */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13,
|
|
0x1 << 5, 0x1 << 5);
|
|
/* ADC CLK from CLKGEN (13MHz) */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON3, 0x0000);
|
|
/* Enable LCLDO_ENC 1P8V */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x2500, 0x0100);
|
|
/* LCLDO_ENC remote sense */
|
|
/* Enable LCLDO_ENC Ref. gen. */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14,
|
|
0x2500, 0x2500);
|
|
|
|
if (rcv_mic_type == RCV_MIC_DCC) {
|
|
/* DCC 50k CLK (from 26M) */
|
|
regmap_write(priv->regmap, MT6358_AUD_TOP_CKPDN_CON0, 0x0000);
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062);
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2060);
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2061);
|
|
regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG1, 0x0100);
|
|
}
|
|
|
|
/* Enable MICBIAS0, MISBIAS0 = 1P9V */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0021);
|
|
|
|
if (rcv_mic_type == RCV_MIC_DCC) {
|
|
/* Audio L preamplifier DCC precharge */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
0x1 << 2, 0x1 << 2);
|
|
/* Audio R preamplifier DCC precharge */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
0x1 << 2, 0x1 << 2);
|
|
}
|
|
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
0x0700, 0x4 << 8);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
0x0700, 0x4 << 8);
|
|
|
|
/* "ADC1", main_mic */
|
|
/* Audio L preamplifier input sel : AIN0. Enable audio L PGA */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
0xf0c1, 0x0041);
|
|
if (rcv_mic_type == RCV_MIC_DCC) {
|
|
/* Audio L preamplifier DCCEN */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
0x1 << 1, 0x1 << 1);
|
|
}
|
|
/* Audio L ADC input sel : L PGA. Enable audio L ADC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
0xf000, 0x5000);
|
|
|
|
usleep_range(100, 150);
|
|
|
|
/* ref mic */
|
|
/* Audio R preamplifier input sel : AIN2. Enable audio R PGA */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
0xf0c1, 0x00c1);
|
|
if (rcv_mic_type == RCV_MIC_DCC) {
|
|
/* Audio R preamplifier DCCEN */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
0x1 << 1, 0x1 << 1);
|
|
}
|
|
/* Audio R ADC input sel : R PGA. Enable audio R ADC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
0xf000, 0x5000);
|
|
|
|
if (rcv_mic_type == RCV_MIC_DCC) {
|
|
/* Short body to ground in PGA */
|
|
regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON3, 0x0000);
|
|
}
|
|
|
|
usleep_range(100, 150);
|
|
|
|
if (rcv_mic_type == RCV_MIC_DCC) {
|
|
/* Audio L ADC input sel : L PGA. Enable audio L ADC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
|
|
RG_AUDPREAMPLDCPRECHARGE_MASK_SFT, 0x0);
|
|
/* Audio R ADC input sel : R PGA. Enable audio R ADC */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
|
|
RG_AUDPREAMPLDCPRECHARGE_MASK_SFT, 0x0);
|
|
}
|
|
|
|
/* here to set digital part */
|
|
|
|
/* set gpio miso mode */
|
|
capture_gpio_set(priv);
|
|
|
|
/* power on clock */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDIO_TOP_CON0,
|
|
0x00bf, 0x0000);
|
|
|
|
/* configure ADC setting */
|
|
regmap_write(priv->regmap, MT6358_AFE_TOP_CON0, 0x0000);
|
|
|
|
/* [0] afe enable */
|
|
regmap_update_bits(priv->regmap, MT6358_AFE_UL_DL_CON0,
|
|
0x0001, 0x0001);
|
|
|
|
mt6358_mtkaif_tx_enable(priv);
|
|
|
|
/* UL dmic setting */
|
|
regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_H, 0x0000);
|
|
|
|
/* UL turn on */
|
|
regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_L, 0x0001);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt6358_rcv_mic_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* vow control */
|
|
static const struct snd_kcontrol_new mt6358_snd_vow_controls[] = {
|
|
SOC_SINGLE_EXT("Audio VOWCFG0 Data",
|
|
SND_SOC_NOPM, 0, 0x80000, 0,
|
|
audio_vow_cfg_get, audio_vow_cfg_set),
|
|
SOC_SINGLE_EXT("Audio VOWCFG1 Data",
|
|
SND_SOC_NOPM, 0, 0x80000, 0,
|
|
audio_vow_cfg_get, audio_vow_cfg_set),
|
|
SOC_SINGLE_EXT("Audio VOWCFG2 Data",
|
|
SND_SOC_NOPM, 0, 0x80000, 0,
|
|
audio_vow_cfg_get, audio_vow_cfg_set),
|
|
SOC_SINGLE_EXT("Audio VOWCFG3 Data",
|
|
SND_SOC_NOPM, 0, 0x80000, 0,
|
|
audio_vow_cfg_get, audio_vow_cfg_set),
|
|
SOC_SINGLE_EXT("Audio VOWCFG4 Data",
|
|
SND_SOC_NOPM, 0, 0x80000, 0,
|
|
audio_vow_cfg_get, audio_vow_cfg_set),
|
|
SOC_SINGLE_EXT("Audio VOWCFG5 Data",
|
|
SND_SOC_NOPM, 0, 0x80000, 0,
|
|
audio_vow_cfg_get, audio_vow_cfg_set),
|
|
SOC_SINGLE_EXT("Audio_VOW_Periodic",
|
|
SND_SOC_NOPM, 0, 0x80000, 0,
|
|
audio_vow_cfg_get, audio_vow_cfg_set),
|
|
};
|
|
|
|
static int dmic_used_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
|
|
ucontrol->value.integer.value[0] =
|
|
priv->mux_select[MUX_MIC_TYPE] == MIC_TYPE_MUX_DMIC;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct soc_enum misc_control_enum[] = {
|
|
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(off_on_function), off_on_function),
|
|
};
|
|
|
|
static const char *const rcv_mic_function[] = {"Off", "ACC", "DCC"};
|
|
|
|
static const struct soc_enum rcv_mic_enum[] = {
|
|
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rcv_mic_function), rcv_mic_function),
|
|
};
|
|
|
|
static const struct snd_kcontrol_new mt6358_snd_misc_controls[] = {
|
|
SOC_ENUM_EXT("Headphone Plugged In", misc_control_enum[0],
|
|
hp_plugged_in_get, hp_plugged_in_set),
|
|
SOC_SINGLE_EXT("Audio HP ImpeDance Setting",
|
|
SND_SOC_NOPM, 0, 0x10000, 0,
|
|
hp_impedance_get, NULL),
|
|
#ifdef ANALOG_HPTRIM
|
|
SOC_ENUM_EXT("Disable Analog DC Compensation", misc_control_enum[0],
|
|
disable_analog_dc_compensation_get,
|
|
disable_analog_dc_compensation_set),
|
|
#endif
|
|
// SOC_ENUM_EXT("Audio_Codec_Debug_Setting", misc_control_enum[0],
|
|
// mt6358_codec_debug_get, mt6358_codec_debug_set),
|
|
SOC_ENUM_EXT("PMIC_REG_CLEAR", rcv_mic_enum[0],
|
|
mt6358_rcv_mic_get, mt6358_rcv_mic_set),
|
|
SOC_ENUM_EXT("DMic Used", misc_control_enum[0], dmic_used_get, NULL),
|
|
};
|
|
|
|
static void mt6358_set_gpio_smt(struct mt6358_priv *priv)
|
|
{
|
|
/* set gpio SMT mode */
|
|
regmap_update_bits(priv->regmap, MT6358_SMT_CON1, 0xff0, 0xff0);
|
|
}
|
|
|
|
static void mt6358_codec_init_reg(struct mt6358_priv *priv)
|
|
{
|
|
/* enable clk buf */
|
|
regmap_update_bits(priv->regmap, MT6358_DCXO_CW14,
|
|
0x1 << RG_XO_AUDIO_EN_M_SFT,
|
|
0x1 << RG_XO_AUDIO_EN_M_SFT);
|
|
|
|
/* set those not controlled by dapm widget */
|
|
|
|
/* audio clk source from internal dcxo */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON6,
|
|
RG_CLKSQ_IN_SEL_TEST_MASK_SFT,
|
|
0x0);
|
|
|
|
/* Disable HeadphoneL/HeadphoneR short circuit protection */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
RG_AUDHPLSCDISABLE_VAUDP15_MASK_SFT,
|
|
0x1 << RG_AUDHPLSCDISABLE_VAUDP15_SFT);
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
|
RG_AUDHPRSCDISABLE_VAUDP15_MASK_SFT,
|
|
0x1 << RG_AUDHPRSCDISABLE_VAUDP15_SFT);
|
|
/* Disable voice short circuit protection */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON6,
|
|
RG_AUDHSSCDISABLE_VAUDP15_MASK_SFT,
|
|
0x1 << RG_AUDHSSCDISABLE_VAUDP15_SFT);
|
|
/* disable LO buffer left short circuit protection */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7,
|
|
RG_AUDLOLSCDISABLE_VAUDP15_MASK_SFT,
|
|
0x1 << RG_AUDLOLSCDISABLE_VAUDP15_SFT);
|
|
|
|
/* Set HP_EINT trigger level to 2.0v */
|
|
regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON11,
|
|
RG_EINTCOMPVTH_MASK_SFT,
|
|
0x1 << RG_EINTCOMPVTH_SFT);
|
|
|
|
/* set gpio */
|
|
playback_gpio_reset(priv);
|
|
capture_gpio_reset(priv);
|
|
|
|
mt6358_set_gpio_smt(priv);
|
|
/* mic type setting */
|
|
mic_type_default_init(priv);
|
|
|
|
/* disable clk buf */
|
|
regmap_update_bits(priv->regmap, MT6358_DCXO_CW14,
|
|
0x1 << RG_XO_AUDIO_EN_M_SFT,
|
|
0x0);
|
|
|
|
/* this will trigger dctrim widgat power down event */
|
|
enable_trim_buf(priv, true);
|
|
}
|
|
|
|
#if !defined(SKIP_SB) && !defined(CONFIG_FPGA_EARLY_PORTING)
|
|
static int get_hp_current_calibrate_val(struct mt6358_priv *priv)
|
|
{
|
|
int ret = 0;
|
|
unsigned short efuse_val = 0;
|
|
int value, sign;
|
|
|
|
#if defined(CONFIG_SND_SOC_MT6366)
|
|
/* 3. set EFUSE addr */
|
|
/* HPDET_COMP[6:0] @ efuse bit 1880 ~ 1886 */
|
|
/* HPDET_COMP_SIGN @ efuse bit 1887 */
|
|
/* 1880 / 8 = 235 --> 0xeb */
|
|
ret = nvmem_device_read(priv->hp_efuse, 0xeb, 2, &efuse_val);
|
|
#else
|
|
/* 3. set EFUSE addr */
|
|
/* HPDET_COMP[6:0] @ efuse bit 1696 ~ 1702 */
|
|
/* HPDET_COMP_SIGN @ efuse bit 1703 */
|
|
/* 1696 / 8 = 212 --> 0xd4 */
|
|
regmap_update_bits(priv->regmap, MT6358_OTP_CON0, 0xff, 0xd4);
|
|
#endif
|
|
|
|
if (ret < 0) {
|
|
dev_err(priv->dev, "%s(), efuse read fail: %d\n", __func__,
|
|
ret);
|
|
efuse_val = 0;
|
|
}
|
|
|
|
/* extract value and signed from HPDET_COMP[6:0] & HPDET_COMP_SIGN */
|
|
sign = (efuse_val >> 7) & 0x1;
|
|
value = efuse_val & 0x7f;
|
|
value = sign ? -value : value;
|
|
|
|
dev_info(priv->dev, "%s(), efuse: %d\n", __func__, value);
|
|
|
|
return value;
|
|
}
|
|
#endif
|
|
|
|
static int mt6358_codec_probe(struct snd_soc_component *cmpnt)
|
|
{
|
|
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
|
|
struct snd_soc_card *sndcard = cmpnt->card;
|
|
struct snd_card *card = sndcard->snd_card;
|
|
int ret = 0;
|
|
|
|
dev_info(priv->dev, "%s()\n", __func__);
|
|
|
|
codec_dev_attr_reg.private = priv;
|
|
ret = snd_card_add_dev_attr(card, &codec_bin_attr_group);
|
|
if (ret)
|
|
pr_info("%s snd_card_add_dev_attr fail\n", __func__);
|
|
|
|
snd_soc_component_init_regmap(cmpnt, priv->regmap);
|
|
|
|
/* add codec controls */
|
|
snd_soc_add_component_controls(cmpnt,
|
|
mt6358_snd_misc_controls,
|
|
ARRAY_SIZE(mt6358_snd_misc_controls));
|
|
snd_soc_add_component_controls(cmpnt,
|
|
mt6358_snd_vow_controls,
|
|
ARRAY_SIZE(mt6358_snd_vow_controls));
|
|
mt6358_codec_init_reg(priv);
|
|
|
|
#if !defined(SKIP_SB) && !defined(CONFIG_FPGA_EARLY_PORTING)
|
|
priv->hp_current_calibrate_val = get_hp_current_calibrate_val(priv);
|
|
#else
|
|
priv->hp_current_calibrate_val = 0;
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void codec_write_reg(struct mt6358_priv *priv, void *arg)
|
|
{
|
|
char *token1 = NULL;
|
|
char *token2 = NULL;
|
|
char *temp = arg;
|
|
char delim[] = " ,";
|
|
unsigned int reg_addr = 0;
|
|
unsigned int reg_value = 0;
|
|
int ret = 0;
|
|
|
|
token1 = strsep(&temp, delim);
|
|
token2 = strsep(&temp, delim);
|
|
dev_info(priv->dev, "%s(), token1 = %s, token2 = %s, temp = %s\n",
|
|
__func__, token1, token2, temp);
|
|
|
|
if ((token1 != NULL) && (token2 != NULL)) {
|
|
ret = kstrtouint(token1, 16, ®_addr);
|
|
ret = kstrtouint(token2, 16, ®_value);
|
|
dev_info(priv->dev, "%s(), reg_addr = 0x%x, reg_value = 0x%x\n",
|
|
__func__,
|
|
reg_addr, reg_value);
|
|
regmap_write(priv->regmap, reg_addr, reg_value);
|
|
regmap_read(priv->regmap, reg_addr, ®_value);
|
|
dev_info(priv->dev, "%s(), reg_addr = 0x%x, reg_value = 0x%x\n",
|
|
__func__,
|
|
reg_addr, reg_value);
|
|
} else {
|
|
dev_err(priv->dev, "token1 or token2 is NULL!\n");
|
|
}
|
|
}
|
|
|
|
static void debug_write_reg(struct file *file, void *arg)
|
|
{
|
|
struct mt6358_priv *priv = file->private_data;
|
|
|
|
return codec_write_reg(priv, arg);
|
|
}
|
|
|
|
static void debug_re_trim_offset(struct file *file,
|
|
void *arg __attribute__((unused)))
|
|
{
|
|
struct mt6358_priv *priv = file->private_data;
|
|
|
|
dev_info(priv->dev, "start %s\n", __func__);
|
|
get_hp_trim_offset(priv, true);
|
|
dev_info(priv->dev, "end %s\n", __func__);
|
|
}
|
|
|
|
static void debug_set_debug_flag(struct file *file, void *arg)
|
|
{
|
|
struct mt6358_priv *priv = file->private_data;
|
|
char *token1 = NULL;
|
|
char *temp = arg;
|
|
char delim[] = " ,";
|
|
int ret = 0;
|
|
unsigned int value;
|
|
|
|
token1 = strsep(&temp, delim);
|
|
dev_info(priv->dev, "%s(), token1 = %s, temp = %s\n",
|
|
__func__, token1, temp);
|
|
|
|
if (token1 != NULL) {
|
|
ret = kstrtouint(token1, 16, &value);
|
|
priv->debug_flag = value;
|
|
} else {
|
|
dev_warn(priv->dev, "%s(), token1 is NULL!\n", __func__);
|
|
}
|
|
}
|
|
|
|
struct command_function {
|
|
const char *cmd;
|
|
void (*fn)(struct file *file, void *arg);
|
|
};
|
|
|
|
#define CMD_FN(_cmd, _fn) { \
|
|
.cmd = _cmd, \
|
|
.fn = _fn, \
|
|
}
|
|
|
|
static u32 copy_from_buffer_request(void *dest, size_t destsize, const void *src,
|
|
size_t srcsize, u32 offset, size_t request)
|
|
{
|
|
/* if request == -1, offset == 0, copy full srcsize */
|
|
if (offset + request > srcsize)
|
|
request = srcsize - offset;
|
|
|
|
/* if destsize == -1, don't check the request size */
|
|
if (!dest || destsize < request) {
|
|
pr_info("%s, buffer null or not enough space", __func__);
|
|
return 0;
|
|
}
|
|
|
|
memcpy(dest, src + offset, request);
|
|
|
|
return request;
|
|
}
|
|
|
|
static const struct command_function debug_cmds[] = {
|
|
CMD_FN("write_reg", debug_write_reg),
|
|
CMD_FN("re_trim_offset", debug_re_trim_offset),
|
|
CMD_FN("set_debug_flag", debug_set_debug_flag),
|
|
{}
|
|
};
|
|
|
|
static int mt6358_debugfs_open(struct inode *inode, struct file *file)
|
|
{
|
|
file->private_data = inode->i_private;
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t mt6358_codec_read(struct mt6358_priv *priv, char *buffer, size_t size)
|
|
{
|
|
int n = 0;
|
|
unsigned int value = 0;
|
|
|
|
if (!buffer)
|
|
return -ENOMEM;
|
|
|
|
n += scnprintf(buffer + n, size - n, "mtkaif_protocol = %d\n",
|
|
priv->mtkaif_protocol);
|
|
n += scnprintf(buffer + n, size - n, "dc_trim_data:\n");
|
|
n += scnprintf(buffer + n, size - n, "\tcalibrated = %d\n",
|
|
priv->dc_trim.calibrated);
|
|
n += scnprintf(buffer + n, size - n, "\toffset_L = %d, offset_R = %d\n",
|
|
priv->dc_trim.hp_offset[CH_L],
|
|
priv->dc_trim.hp_offset[CH_R]);
|
|
n += scnprintf(buffer + n, size - n, "\tmic_vinp_mv = %d\n",
|
|
priv->dc_trim.mic_vinp_mv);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"\thp_3_pole_trim_setting = 0x%x, hp_4_pole_trim_setting = 0x%x\n",
|
|
priv->dc_trim.hp_3_pole_trim_setting,
|
|
priv->dc_trim.hp_4_pole_trim_setting);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"\tspk_hp_3_pole_trim_setting = 0x%x, spk_hp_4_pole_trim_setting = 0x%x\n",
|
|
priv->dc_trim.spk_hp_3_pole_trim_setting,
|
|
priv->dc_trim.spk_hp_4_pole_trim_setting);
|
|
|
|
n += scnprintf(buffer + n, size - n, "codec_ops:\n");
|
|
n += scnprintf(buffer + n, size - n, "\tenable_dc_compensation = %p\n",
|
|
priv->ops.enable_dc_compensation);
|
|
n += scnprintf(buffer + n, size - n, "\tset_lch_dc_compensation = %p\n",
|
|
priv->ops.set_lch_dc_compensation);
|
|
n += scnprintf(buffer + n, size - n, "\tset_rch_dc_compensation = %p\n",
|
|
priv->ops.set_rch_dc_compensation);
|
|
|
|
n += scnprintf(buffer + n, size - n, "debug_flag = 0x%x\n",
|
|
priv->debug_flag);
|
|
|
|
n += scnprintf(buffer + n, size - n, "hp_impedance = %d\n",
|
|
priv->hp_impedance);
|
|
n += scnprintf(buffer + n, size - n, "hp_current_calibrate_val = %d\n",
|
|
priv->hp_current_calibrate_val);
|
|
regmap_read(priv->regmap, MT6358_SMT_CON1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_SMT_CON1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_DRV_CON2, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_DRV_CON2 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_DRV_CON3, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_DRV_CON3 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_GPIO_DIR0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_GPIO_DIR0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_GPIO_MODE2, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_GPIO_MODE2 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_GPIO_MODE3, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_GPIO_MODE3 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_TOP_CKPDN_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_TOP_CKPDN_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_TOP_CKHWEN_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_TOP_CKHWEN_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_DCXO_CW13, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_DCXO_CW13 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_DCXO_CW14, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_DCXO_CW14 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUXADC_CON10, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUXADC_CON10 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_LDO_VAUD28_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_LDO_VAUD28_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_ID, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_ID = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_REV0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_REV0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_DBI, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_DBI = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_DXI, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_DXI = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_CKPDN_TPM0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_CKPDN_TPM0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_CKPDN_TPM1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_CKPDN_TPM1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_CKPDN_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_CKPDN_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_CKPDN_CON0_SET, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_CKPDN_CON0_SET = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_CKPDN_CON0_CLR, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_CKPDN_CON0_CLR = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_CKSEL_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_CKSEL_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_CKSEL_CON0_SET, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_CKSEL_CON0_SET = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_CKSEL_CON0_CLR, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_CKSEL_CON0_CLR = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_CKTST_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_CKTST_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_CLK_HWEN_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_CLK_HWEN_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_CLK_HWEN_CON0_SET, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_CLK_HWEN_CON0_SET = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_CLK_HWEN_CON0_CLR, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_CLK_HWEN_CON0_CLR = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_RST_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_RST_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_RST_CON0_SET, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_RST_CON0_SET = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_RST_CON0_CLR, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_RST_CON0_CLR = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_RST_BANK_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_RST_BANK_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_INT_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_INT_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_INT_CON0_SET, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_INT_CON0_SET = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_INT_CON0_CLR, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_INT_CON0_CLR = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_INT_MASK_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_INT_MASK_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_INT_MASK_CON0_SET, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_INT_MASK_CON0_SET = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_INT_MASK_CON0_CLR, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_INT_MASK_CON0_CLR = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_INT_STATUS0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_INT_STATUS0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_INT_RAW_STATUS0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_INT_RAW_STATUS0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_INT_MISC_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_INT_MISC_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDNCP_CLKDIV_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDNCP_CLKDIV_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDNCP_CLKDIV_CON1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDNCP_CLKDIV_CON1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDNCP_CLKDIV_CON2, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDNCP_CLKDIV_CON2 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDNCP_CLKDIV_CON3 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDNCP_CLKDIV_CON4, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDNCP_CLKDIV_CON4 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUD_TOP_MON_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUD_TOP_MON_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDIO_DIG_DSN_ID, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDIO_DIG_DSN_ID = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDIO_DIG_DSN_REV0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDIO_DIG_DSN_REV0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDIO_DIG_DSN_DBI, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDIO_DIG_DSN_DBI = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDIO_DIG_DSN_DXI, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDIO_DIG_DSN_DXI = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_UL_DL_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_UL_DL_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_DL_SRC2_CON0_L, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_DL_SRC2_CON0_L = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_UL_SRC_CON0_H, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_UL_SRC_CON0_H = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_UL_SRC_CON0_L, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_UL_SRC_CON0_L = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_TOP_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_TOP_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDIO_TOP_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDIO_TOP_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_MON_DEBUG0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_MON_DEBUG0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFUNC_AUD_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFUNC_AUD_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFUNC_AUD_CON1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFUNC_AUD_CON1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFUNC_AUD_CON2, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFUNC_AUD_CON2 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFUNC_AUD_CON3, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFUNC_AUD_CON3 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFUNC_AUD_CON4, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFUNC_AUD_CON4 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFUNC_AUD_CON5, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFUNC_AUD_CON5 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFUNC_AUD_CON6, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFUNC_AUD_CON6 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFUNC_AUD_MON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFUNC_AUD_MON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDRC_TUNE_MON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDRC_TUNE_MON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_ADDA_MTKAIF_FIFO_CFG0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_ADDA_MTKAIF_FIFO_CFG0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_ADDA_MTKAIF_FIFO_LOG_MON1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_ADDA_MTKAIF_FIFO_LOG_MON1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_ADDA_MTKAIF_MON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_ADDA_MTKAIF_MON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_ADDA_MTKAIF_MON1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_ADDA_MTKAIF_MON1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_ADDA_MTKAIF_MON2, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_ADDA_MTKAIF_MON2 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_ADDA_MTKAIF_MON3, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_ADDA_MTKAIF_MON3 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_ADDA_MTKAIF_CFG0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_ADDA_MTKAIF_CFG0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_ADDA_MTKAIF_RX_CFG0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_ADDA_MTKAIF_RX_CFG0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_ADDA_MTKAIF_RX_CFG1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_ADDA_MTKAIF_RX_CFG1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_ADDA_MTKAIF_RX_CFG2, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_ADDA_MTKAIF_RX_CFG2 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_ADDA_MTKAIF_RX_CFG3, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_ADDA_MTKAIF_RX_CFG3 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_ADDA_MTKAIF_TX_CFG1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_ADDA_MTKAIF_TX_CFG1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_SGEN_CFG0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_SGEN_CFG0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_SGEN_CFG1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_SGEN_CFG1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_ADC_ASYNC_FIFO_CFG, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_ADC_ASYNC_FIFO_CFG = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_DCCLK_CFG0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_DCCLK_CFG0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_DCCLK_CFG1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_DCCLK_CFG1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDIO_DIG_CFG, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDIO_DIG_CFG = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_AUD_PAD_TOP, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_AUD_PAD_TOP = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_AUD_PAD_TOP_MON, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_AUD_PAD_TOP_MON = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_AUD_PAD_TOP_MON1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_AUD_PAD_TOP_MON1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_DL_NLE_CFG, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_DL_NLE_CFG = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_DL_NLE_MON, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_DL_NLE_MON = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_CG_EN_MON, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_CG_EN_MON = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDIO_DIG_2ND_DSN_ID, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDIO_DIG_2ND_DSN_ID = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDIO_DIG_2ND_DSN_REV0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDIO_DIG_2ND_DSN_REV0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDIO_DIG_2ND_DSN_DBI, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDIO_DIG_2ND_DSN_DBI = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDIO_DIG_2ND_DSN_DXI, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDIO_DIG_2ND_DSN_DXI = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_PMIC_NEWIF_CFG3, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_PMIC_NEWIF_CFG3 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_TOP, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_TOP = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_CFG0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_CFG0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_CFG1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_CFG1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_CFG2, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_CFG2 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_CFG3, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_CFG3 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_CFG4, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_CFG4 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_CFG5, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_CFG5 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_CFG6, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_CFG6 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_MON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_MON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_MON1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_MON1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_MON2, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_MON2 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_MON3, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_MON3 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_MON4, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_MON4 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_MON5, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_MON5 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_SN_INI_CFG, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_SN_INI_CFG = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_TGEN_CFG0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_TGEN_CFG0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_POSDIV_CFG0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_POSDIV_CFG0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_HPF_CFG0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_HPF_CFG0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG2, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG2 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG3, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG3 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG4, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG4 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG5, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG5 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG6, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG6 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG7, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG7 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG8, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG8 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG9, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG9 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG10, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG10 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG11, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG11 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG12, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG12 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG13, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG13 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG14, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG14 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG15, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG15 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG16, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG16 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG17, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG17 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG18, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG18 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG19, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG19 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG20, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG20 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG21, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG21 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG22, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG22 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_CFG23, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_CFG23 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_MON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_MON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AFE_VOW_PERIODIC_MON1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AFE_VOW_PERIODIC_MON1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_DSN_ID, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDENC_DSN_ID = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_DSN_REV0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDENC_DSN_REV0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_DSN_DBI, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDENC_DSN_DBI = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_DSN_FPI, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDENC_DSN_FPI = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDENC_ANA_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDENC_ANA_CON1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON2, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDENC_ANA_CON2 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON3, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDENC_ANA_CON3 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON4, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDENC_ANA_CON4 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON5, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDENC_ANA_CON5 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON6, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDENC_ANA_CON6 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON7, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDENC_ANA_CON7 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON8, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDENC_ANA_CON8 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON9, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDENC_ANA_CON9 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON10, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDENC_ANA_CON10 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON11, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDENC_ANA_CON11 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON12, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDENC_ANA_CON12 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_DSN_ID, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_DSN_ID = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_DSN_REV0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_DSN_REV0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_DSN_DBI, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_DSN_DBI = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_DSN_FPI, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_DSN_FPI = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ANA_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ANA_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ANA_CON1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ANA_CON1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ANA_CON2, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ANA_CON2 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ANA_CON3, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ANA_CON3 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ANA_CON4, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ANA_CON4 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ANA_CON5, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ANA_CON5 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ANA_CON6, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ANA_CON6 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ANA_CON7, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ANA_CON7 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ANA_CON8, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ANA_CON8 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ANA_CON9, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ANA_CON9 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ANA_CON10, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ANA_CON10 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ANA_CON11, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ANA_CON11 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ANA_CON12, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ANA_CON12 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ANA_CON13, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ANA_CON13 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ANA_CON14, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ANA_CON14 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ANA_CON15, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ANA_CON15 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_NUM, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ELR_NUM = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDDEC_ELR_0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDDEC_ELR_0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDZCD_DSN_ID, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDZCD_DSN_ID = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDZCD_DSN_REV0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDZCD_DSN_REV0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDZCD_DSN_DBI, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDZCD_DSN_DBI = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_AUDZCD_DSN_FPI, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_AUDZCD_DSN_FPI = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_ZCD_CON0, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_ZCD_CON0 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_ZCD_CON1, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_ZCD_CON1 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_ZCD_CON2, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_ZCD_CON2 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_ZCD_CON3, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_ZCD_CON3 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_ZCD_CON4, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_ZCD_CON4 = 0x%x\n", value);
|
|
regmap_read(priv->regmap, MT6358_ZCD_CON5, &value);
|
|
n += scnprintf(buffer + n, size - n,
|
|
"MT6358_ZCD_CON5 = 0x%x\n", value);
|
|
|
|
return n;
|
|
}
|
|
|
|
static ssize_t mt6358_debugfs_read(struct file *file, char __user *buf,
|
|
size_t count, loff_t *pos)
|
|
{
|
|
struct mt6358_priv *priv = file->private_data;
|
|
const int size = 12288;
|
|
char *buffer = NULL; /* for reduce kernel stack */
|
|
int n = 0;
|
|
int ret = 0;
|
|
|
|
buffer = kmalloc(size, GFP_KERNEL);
|
|
if (!buffer)
|
|
return -ENOMEM;
|
|
|
|
n = mt6358_codec_read(priv, buffer, size);
|
|
|
|
ret = simple_read_from_buffer(buf, count, pos, buffer, n);
|
|
kfree(buffer);
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t mt6358_debugfs_write(struct file *f, const char __user *buf,
|
|
size_t count, loff_t *offset)
|
|
{
|
|
#define MAX_DEBUG_WRITE_INPUT 256
|
|
struct mt6358_priv *priv = f->private_data;
|
|
char input[MAX_DEBUG_WRITE_INPUT];
|
|
char *temp = NULL;
|
|
char *command = NULL;
|
|
char *str_begin = NULL;
|
|
char delim[] = " ,";
|
|
const struct command_function *cf = NULL;
|
|
|
|
if (!count) {
|
|
dev_info(priv->dev, "%s(), count is 0, return directly\n",
|
|
__func__);
|
|
goto exit;
|
|
}
|
|
|
|
if (count > MAX_DEBUG_WRITE_INPUT)
|
|
count = MAX_DEBUG_WRITE_INPUT;
|
|
|
|
memset((void *)input, 0, MAX_DEBUG_WRITE_INPUT);
|
|
|
|
if (copy_from_user(input, buf, count))
|
|
dev_warn(priv->dev, "%s(), copy_from_user fail, count = %zu\n",
|
|
__func__, count);
|
|
|
|
str_begin = kstrndup(input, MAX_DEBUG_WRITE_INPUT - 1,
|
|
GFP_KERNEL);
|
|
if (!str_begin) {
|
|
dev_info(priv->dev, "%s(), kstrdup fail\n", __func__);
|
|
goto exit;
|
|
}
|
|
temp = str_begin;
|
|
|
|
command = strsep(&temp, delim);
|
|
|
|
dev_info(priv->dev, "%s(), command %s, content %s\n",
|
|
__func__, command, temp);
|
|
|
|
for (cf = debug_cmds; cf->cmd; cf++) {
|
|
if (strcmp(cf->cmd, command) == 0) {
|
|
cf->fn(f, temp);
|
|
break;
|
|
}
|
|
}
|
|
|
|
kfree(str_begin);
|
|
exit:
|
|
return count;
|
|
}
|
|
|
|
/*
|
|
* sysfs bin_attribute node
|
|
*/
|
|
static ssize_t mt6358_codec_sysfs_read(struct file *filep, struct kobject *kobj,
|
|
struct bin_attribute *attr,
|
|
char *buf, loff_t offset, size_t size)
|
|
{
|
|
size_t read_size, ceil_size, page_mask;
|
|
ssize_t ret;
|
|
|
|
struct mt6358_priv *priv = (struct mt6358_priv *)attr->private;
|
|
char *buffer = NULL; /* for reduce kernel stack */
|
|
|
|
buffer = kzalloc(CODEC_SYS_DEBUG_SIZE, GFP_KERNEL);
|
|
if (!buffer)
|
|
return -ENOMEM;
|
|
|
|
/* here read size may be different because of reg return may different */
|
|
read_size = mt6358_codec_read(priv, buffer, CODEC_SYS_DEBUG_SIZE);
|
|
page_mask = ~(PAGE_SIZE - 1);
|
|
ceil_size = (read_size & page_mask) + PAGE_SIZE;
|
|
|
|
pr_info("%s buf[%p] offset = %lld size = %zu read_size[%zu]\n",
|
|
__func__, buf, offset, size, read_size);
|
|
|
|
ret = copy_from_buffer_request(buf, -1, buffer, ceil_size, offset, size);
|
|
if (ret < 0)
|
|
ret = 0;
|
|
|
|
kfree(buffer);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t mt6358_codec_sysfs_write(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *bin_attr,
|
|
char *buf, loff_t off, size_t count)
|
|
{
|
|
struct mt6358_priv *priv = (struct mt6358_priv *)bin_attr->private;
|
|
|
|
char input[MAX_DEBUG_WRITE_INPUT];
|
|
char *temp, *command, *str_begin;
|
|
char delim[] = " ,";
|
|
|
|
if (!count) {
|
|
dev_info(priv->dev, "%s(), count is 0, return directly\n",
|
|
__func__);
|
|
goto exit;
|
|
}
|
|
|
|
if (count > MAX_DEBUG_WRITE_INPUT)
|
|
count = MAX_DEBUG_WRITE_INPUT;
|
|
|
|
memset((void *)input, 0, MAX_DEBUG_WRITE_INPUT);
|
|
memcpy(input, buf, count);
|
|
|
|
str_begin = kstrndup(input, MAX_DEBUG_WRITE_INPUT - 1,
|
|
GFP_KERNEL);
|
|
if (!str_begin) {
|
|
dev_info(priv->dev, "%s(), kstrdup fail\n", __func__);
|
|
goto exit;
|
|
}
|
|
temp = str_begin;
|
|
command = strsep(&temp, delim);
|
|
dev_info(priv->dev, "%s(), temp=%s, command = %s\n",
|
|
__func__, temp, command);
|
|
|
|
if (strcmp("write_reg", command) == 0)
|
|
codec_write_reg(priv, temp);
|
|
exit:
|
|
return count;
|
|
}
|
|
|
|
static const struct file_operations mt6358_debugfs_ops = {
|
|
.open = mt6358_debugfs_open,
|
|
.write = mt6358_debugfs_write,
|
|
.read = mt6358_debugfs_read,
|
|
};
|
|
|
|
static const struct snd_soc_component_driver mt6358_soc_component_driver = {
|
|
.name = CODEC_MT6358_NAME,
|
|
.probe = mt6358_codec_probe,
|
|
.controls = mt6358_snd_controls,
|
|
.num_controls = ARRAY_SIZE(mt6358_snd_controls),
|
|
.dapm_widgets = mt6358_dapm_widgets,
|
|
.num_dapm_widgets = ARRAY_SIZE(mt6358_dapm_widgets),
|
|
.dapm_routes = mt6358_dapm_routes,
|
|
.num_dapm_routes = ARRAY_SIZE(mt6358_dapm_routes),
|
|
};
|
|
|
|
static int mt6358_parse_dt(struct mt6358_priv *priv)
|
|
{
|
|
int ret;
|
|
struct device *dev = priv->dev;
|
|
struct device_node *np;
|
|
|
|
np = of_get_child_by_name(dev->parent->of_node, "mt6358codec");
|
|
if (!np)
|
|
return -EINVAL;
|
|
|
|
/* get mic type */
|
|
ret = of_property_read_u32(np, "mediatek,dmic-mode",
|
|
&priv->dmic_one_wire_mode);
|
|
if (ret) {
|
|
dev_info(dev, "%s() failed to read dmic-mode, default 2 wire\n",
|
|
__func__);
|
|
priv->dmic_one_wire_mode = 0;
|
|
}
|
|
|
|
ret = of_property_read_u32(dev->of_node, "mediatek,mic-type",
|
|
&priv->mux_select[MUX_MIC_TYPE]);
|
|
if (ret) {
|
|
dev_info(dev, "%s() failed to read mic-type, default ACC\n",
|
|
__func__);
|
|
priv->mux_select[MUX_MIC_TYPE] = MIC_TYPE_MUX_ACC;
|
|
}
|
|
|
|
ret = of_property_read_bool(dev->of_node, "vow_dmic_lp");
|
|
if (ret) {
|
|
priv->vow_dmic_lp = 1;
|
|
} else {
|
|
dev_info(dev, "%s() vow_dmic_lp node not exist, default off.\n",
|
|
__func__);
|
|
priv->vow_dmic_lp = 0;
|
|
}
|
|
|
|
/* get auxadc channel */
|
|
priv->hpofs_cal_auxadc = devm_iio_channel_get(dev,
|
|
"pmic_hpofs_cal");
|
|
|
|
ret = PTR_ERR_OR_ZERO(priv->hpofs_cal_auxadc);
|
|
if (ret) {
|
|
if (ret != -EPROBE_DEFER) //EPROBE_DEFER:517
|
|
dev_info(dev,
|
|
"%s() Get pmic_hpofs_cal iio ch failed (%d)\n",
|
|
__func__, ret);
|
|
else
|
|
dev_info(dev,
|
|
"%s() Get pmic_hpofs_cal iio ch failed (%d), will retry ...\n",
|
|
__func__, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if !defined(CONFIG_FPGA_EARLY_PORTING) && !defined(SKIP_SB)
|
|
/* get pmic efuse handler */
|
|
priv->hp_efuse = devm_nvmem_device_get(dev, "pmic-hp-efuse");
|
|
ret = PTR_ERR_OR_ZERO(priv->hp_efuse);
|
|
if (ret) {
|
|
if (ret != -EPROBE_DEFER)
|
|
dev_info(dev, "%s() Get efuse failed (%d)\n",
|
|
__func__, ret);
|
|
else
|
|
dev_info(dev, "%s() Get efuse failed (%d), will retry ...\n",
|
|
__func__, ret);
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
/* get pmic regulator handler */
|
|
priv->reg_vaud28 = devm_regulator_get_optional(dev, "reg_vaud28");
|
|
ret = IS_ERR(priv->reg_vaud28);
|
|
if (ret) {
|
|
ret = PTR_ERR(priv->reg_vaud28);
|
|
if (ret != -EPROBE_DEFER)
|
|
dev_info(dev, "%s() Get regulator failed (%d)\n",
|
|
__func__, ret);
|
|
else
|
|
dev_info(dev, "%s() Get regulator failed (%d), will retry ...\n",
|
|
__func__, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* get priv->pull_down_stay_enable flag */
|
|
ret = of_property_read_u32(dev->of_node,
|
|
"mtk_pull_down_stay_enable",
|
|
&priv->pull_down_stay_enable);
|
|
if (ret) {
|
|
priv->pull_down_stay_enable = 0;
|
|
dev_info(dev,
|
|
"%s(), get pull_down_stay_enable fail, default 0\n",
|
|
__func__);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt6358_platform_driver_probe(struct platform_device *pdev)
|
|
{
|
|
struct mt6358_priv *priv;
|
|
struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
|
|
int ret;
|
|
|
|
priv = devm_kzalloc(&pdev->dev,
|
|
sizeof(struct mt6358_priv),
|
|
GFP_KERNEL);
|
|
if (!priv)
|
|
return -ENOMEM;
|
|
|
|
dev_set_drvdata(&pdev->dev, priv);
|
|
|
|
priv->dev = &pdev->dev;
|
|
|
|
priv->regmap = mt6397->regmap;
|
|
if (IS_ERR(priv->regmap))
|
|
return PTR_ERR(priv->regmap);
|
|
|
|
/* create debugfs file */
|
|
priv->debugfs = debugfs_create_file("mtksocanaaudio",
|
|
S_IFREG | 0444, NULL,
|
|
priv, &mt6358_debugfs_ops);
|
|
|
|
ret = mt6358_parse_dt(priv);
|
|
if (ret) {
|
|
dev_warn(&pdev->dev,
|
|
"%s() fail to parse dts: %d\n", __func__, ret);
|
|
return ret;
|
|
}
|
|
|
|
dev_info(priv->dev, "%s(), dev name %s\n",
|
|
__func__, dev_name(&pdev->dev));
|
|
|
|
return devm_snd_soc_register_component(&pdev->dev,
|
|
&mt6358_soc_component_driver,
|
|
mt6358_dai_driver,
|
|
ARRAY_SIZE(mt6358_dai_driver));
|
|
}
|
|
|
|
static const struct of_device_id mt6358_of_match[] = {
|
|
{.compatible = "mediatek,mt6358-sound",},
|
|
{.compatible = "mediatek,mt6366-sound",},
|
|
{}
|
|
};
|
|
MODULE_DEVICE_TABLE(of, mt6358_of_match);
|
|
|
|
static struct platform_driver mt6358_platform_driver = {
|
|
.driver = {
|
|
.name = DEVICE_MT6358_NAME,
|
|
.of_match_table = mt6358_of_match,
|
|
},
|
|
.probe = mt6358_platform_driver_probe,
|
|
};
|
|
|
|
module_platform_driver(mt6358_platform_driver)
|
|
|
|
/* Module information */
|
|
MODULE_DESCRIPTION("MT6358 ALSA SoC codec driver");
|
|
MODULE_AUTHOR("KaiChieh Chuang <kaichieh.chuang@mediatek.com>");
|
|
MODULE_LICENSE("GPL v2");
|