Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions Documentation/devicetree/bindings/sound/qcom,pm4125-codec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,24 @@ properties:
minimum: 1800000
maximum: 2850000

qcom,hphl-jack-type-normally-closed:
description: Indicates that HPHL jack switch type is normally closed
type: boolean

qcom,ground-jack-type-normally-closed:
description: Indicates that Headset Ground switch type is normally closed
type: boolean

qcom,mbhc-headset-vthreshold-microvolt:
description: Voltage threshold value for headset detection
minimum: 0
maximum: 2850000

qcom,mbhc-headphone-vthreshold-microvolt:
description: Voltage threshold value for headphone detection
minimum: 0
maximum: 2850000

qcom,mbhc-buttons-vthreshold-microvolt:
description:
Array of 8 Voltage threshold values corresponding to headset
Expand Down
220 changes: 214 additions & 6 deletions sound/soc/codecs/pm4125.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
Expand Down Expand Up @@ -74,6 +75,8 @@ struct pm4125_priv {
struct regmap_irq_chip_data *irq_chip;
struct snd_soc_jack *jack;
unsigned long status_mask;
/* Protects micbias voltage adjustment against concurrent requests */
struct mutex micb_lock;
s32 micb_ref[PM4125_MAX_MICBIAS];
s32 pullup_ref[PM4125_MAX_MICBIAS];
u32 micb1_mv;
Expand Down Expand Up @@ -230,7 +233,7 @@ static int pm4125_global_mbias_disable(struct snd_soc_component *component)
{
struct pm4125_priv *pm4125 = snd_soc_component_get_drvdata(component);

if (atomic_dec_and_test(&pm4125->gloal_mbias_cnt)) {
if (atomic_dec_if_positive(&pm4125->gloal_mbias_cnt) == 0) {

snd_soc_component_write_field(component, PM4125_ANA_MBIAS_EN,
PM4125_ANA_MBIAS_EN_V2I_MASK,
Expand Down Expand Up @@ -783,8 +786,18 @@ static int pm4125_micbias_control(struct snd_soc_component *component, int micb_
}
break;
case MICB_DISABLE:
if (pm4125->micb_ref[micb_index] > 0)
pm4125->micb_ref[micb_index]--;
/*
* Ignore a release that has no matching request. The MBHC
* framework releases MIC_BIAS_2 once when the plug type
* correction work ends and again when it turns the bias off,
* and honouring the second one would drop a reference on the
* shared global mbias that was never taken, switching the
* analog master bias off under an active stream.
*/
if (!pm4125->micb_ref[micb_index])
break;

pm4125->micb_ref[micb_index]--;
if ((pm4125->micb_ref[micb_index] == 0) &&
(pm4125->pullup_ref[micb_index] > 0)) {
snd_soc_component_update_bits(component, micb_reg,
Expand Down Expand Up @@ -969,6 +982,12 @@ static int pm4125_set_swr_port(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
return 1;
}

static void pm4125_mbhc_clk_setup(struct snd_soc_component *component, bool enable)
{
snd_soc_component_write_field(component, PM4125_ANA_MBHC_CTL_1,
PM4125_ANA_MBHC_CTL_RCO_EN_MASK, enable);
}

static void pm4125_mbhc_bias_control(struct snd_soc_component *component, bool enable)
{
snd_soc_component_write_field(component, PM4125_ANA_MBHC_ELECT,
Expand All @@ -992,13 +1011,191 @@ static void pm4125_mbhc_program_btn_thr(struct snd_soc_component *component,
for (i = 0; i < num_btn; i++) {
vth = ((btn_high[i] * 2) / 25) & 0x3F;
snd_soc_component_write_field(component, PM4125_ANA_MBHC_BTN0_ZDET_VREF1 + i,
PM4125_ANA_MBHC_BTN0_THRESHOLD_MASK, vth << 2);
PM4125_ANA_MBHC_BTN0_THRESHOLD_MASK, vth);
}
}

static bool pm4125_mbhc_micb_en_status(struct snd_soc_component *component, int micb_num)
{
if (micb_num != MIC_BIAS_2)
return false;

return snd_soc_component_read_field(component, PM4125_ANA_MICBIAS_MICB_1_2_EN,
PM4125_ANA_MICBIAS_MICB2_EN_MASK) == 1;
}

static void pm4125_mbhc_hph_l_pull_up_control(struct snd_soc_component *component,
enum mbhc_hs_pullup_iref pull_up_cur)
{
/* Default pull up current to 3uA */
if (pull_up_cur < I_OFF || pull_up_cur > I_3P0_UA || pull_up_cur == I_DEFAULT)
pull_up_cur = I_3P0_UA;

snd_soc_component_write_field(component, PM4125_ANA_MBHC_PLUG_DETECT_CTL,
PM4125_ANA_MBHC_HSDET_PULLUP_C_MASK, pull_up_cur);
}

static int pm4125_mbhc_request_micbias(struct snd_soc_component *component,
int micb_num, int req)
{
return pm4125_micbias_control(component, micb_num, req, false);
}

static void pm4125_mbhc_micb_ramp_control(struct snd_soc_component *component, bool enable)
{
if (enable) {
snd_soc_component_write_field(component, PM4125_ANA_MBHC_MICB2_RAMP,
PM4125_ANA_MBHC_MICB2_RAMP_SHIFT_MASK,
PM4125_ANA_MBHC_MICB2_RAMP_SHIFT_CTRL);
snd_soc_component_write_field(component, PM4125_ANA_MBHC_MICB2_RAMP,
PM4125_ANA_MBHC_MICB2_RAMP_EN_MASK, 1);
} else {
snd_soc_component_write_field(component, PM4125_ANA_MBHC_MICB2_RAMP,
PM4125_ANA_MBHC_MICB2_RAMP_EN_MASK, 0);
snd_soc_component_write_field(component, PM4125_ANA_MBHC_MICB2_RAMP,
PM4125_ANA_MBHC_MICB2_RAMP_SHIFT_MASK, 0);
}
}

static int pm4125_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
int req_volt, int micb_num)
{
struct pm4125_priv *pm4125 = snd_soc_component_get_drvdata(component);
int cur_vout_ctl, req_vout_ctl, micb_en, ret = 0;
unsigned int pullup_mask, en_mask;

switch (micb_num) {
case MIC_BIAS_1:
pullup_mask = PM4125_ANA_MICBIAS_MICB1_PULL_UP_MASK;
en_mask = PM4125_ANA_MICBIAS_MICB1_EN_MASK;
break;
case MIC_BIAS_2:
pullup_mask = PM4125_ANA_MICBIAS_MICB2_PULL_UP_MASK;
en_mask = PM4125_ANA_MICBIAS_MICB2_EN_MASK;
break;
default:
return -EINVAL;
}

mutex_lock(&pm4125->micb_lock);

/*
* If requested micbias voltage is same as current micbias voltage,
* then just return. Otherwise, adjust voltage as per requested value.
* If micbias is already enabled, then to avoid slow micbias ramp-up
* or down enable pull-up momentarily, change the micbias value and
* then re-enable micbias.
*/
micb_en = snd_soc_component_read_field(component, PM4125_ANA_MICBIAS_MICB_1_2_EN,
en_mask);
cur_vout_ctl = snd_soc_component_read_field(component, PM4125_ANA_MICBIAS_LDO_1_SETTING,
PM4125_ANA_MICBIAS_MICB_OUT_VAL_MASK);

req_vout_ctl = pm4125_get_micb_vout_ctl_val(component->dev, req_volt);
if (req_vout_ctl < 0) {
ret = -EINVAL;
goto exit;
}

if (cur_vout_ctl == req_vout_ctl)
goto exit;

if (micb_en == 1)
snd_soc_component_write_field(component, PM4125_ANA_MICBIAS_MICB_1_2_EN,
pullup_mask,
PM4125_ANA_MICBIAS_MICB_PULL_ENABLE);

snd_soc_component_write_field(component, PM4125_ANA_MICBIAS_LDO_1_SETTING,
PM4125_ANA_MICBIAS_MICB_OUT_VAL_MASK, req_vout_ctl);

if (micb_en == 1) {
snd_soc_component_write_field(component, PM4125_ANA_MICBIAS_MICB_1_2_EN,
pullup_mask,
PM4125_ANA_MICBIAS_MICB_PULL_DISABLE);
/* Add 2ms delay as per HW requirement after enabling micbias */
usleep_range(2000, 2100);
}
exit:
mutex_unlock(&pm4125->micb_lock);

return ret;
}

static int pm4125_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component,
int micb_num, bool req_en)
{
struct pm4125_priv *pm4125 = snd_soc_component_get_drvdata(component);
int micb_mv;

if (micb_num != MIC_BIAS_2)
return -EINVAL;

/*
* If device tree micbias level is already above the minimum voltage
* needed to detect threshold microphone, then do not change the
* micbias, just return.
*/
if (pm4125->micb2_mv >= WCD_MBHC_THR_HS_MICB_MV)
return 0;

micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : pm4125->micb2_mv;

return pm4125_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2);
}

static void pm4125_mbhc_get_micbias_val(struct snd_soc_component *component, int *mb)
{
u8 vout_ctl;

/* Read MBHC Micbias (Mic Bias2) voltage */
vout_ctl = snd_soc_component_read_field(component, PM4125_ANA_MICBIAS_LDO_1_SETTING,
PM4125_ANA_MICBIAS_MICB_OUT_VAL_MASK);

/*
* Formula for getting micbias from vout:
* micbias = 1.6V + VOUT_CTL * 50mV
*/
*mb = 1600 + (vout_ctl * 50);
}

static void pm4125_mbhc_gnd_det_ctrl(struct snd_soc_component *component, bool enable)
{
if (enable) {
snd_soc_component_write_field(component, PM4125_ANA_MBHC_MECH,
PM4125_ANA_MBHC_HSG_PULLUP_COMP_EN_MASK, 1);
snd_soc_component_write_field(component, PM4125_ANA_MBHC_MECH,
PM4125_ANA_MBHC_GND_DET_EN_MASK, 1);
} else {
snd_soc_component_write_field(component, PM4125_ANA_MBHC_MECH,
PM4125_ANA_MBHC_GND_DET_EN_MASK, 0);
snd_soc_component_write_field(component, PM4125_ANA_MBHC_MECH,
PM4125_ANA_MBHC_HSG_PULLUP_COMP_EN_MASK, 0);
}
}

static void pm4125_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component, bool enable)
{
u8 val = enable ? PM4125_ANA_HPHPA_CNP_GND_PULL_DOWN :
PM4125_ANA_HPHPA_CNP_GND_PULL_NONE;

snd_soc_component_write_field(component, PM4125_ANA_HPHPA_CNP_CTL_2,
PM4125_ANA_HPHPA_CNP_GND_L_MASK, val);
snd_soc_component_write_field(component, PM4125_ANA_HPHPA_CNP_CTL_2,
PM4125_ANA_HPHPA_CNP_GND_R_MASK, val);
}

static const struct wcd_mbhc_cb mbhc_cb = {
.clk_setup = pm4125_mbhc_clk_setup,
.mbhc_bias = pm4125_mbhc_bias_control,
.set_btn_thr = pm4125_mbhc_program_btn_thr,
.micbias_enable_status = pm4125_mbhc_micb_en_status,
.hph_pull_up_control = pm4125_mbhc_hph_l_pull_up_control,
.mbhc_micbias_control = pm4125_mbhc_request_micbias,
.mbhc_micb_ramp_control = pm4125_mbhc_micb_ramp_control,
.mbhc_micb_ctrl_thr_mic = pm4125_mbhc_micb_ctrl_threshold_mic,
.get_micbias_val = pm4125_mbhc_get_micbias_val,
.mbhc_gnd_det_ctrl = pm4125_mbhc_gnd_det_ctrl,
.hph_pull_down_ctrl = pm4125_mbhc_hph_pull_down_ctrl,
};

static int pm4125_mbhc_init(struct snd_soc_component *component)
Expand Down Expand Up @@ -1742,6 +1939,7 @@ static int pm4125_probe(struct platform_device *pdev)

pm4125_dt_parse_micbias_info(dev, pm4125);
atomic_set(&pm4125->gloal_mbias_cnt, 0);
mutex_init(&pm4125->micb_lock);

cfg = &pm4125->mbhc_cfg;
cfg->mbhc_micbias = MIC_BIAS_2;
Expand All @@ -1750,10 +1948,20 @@ static int pm4125_probe(struct platform_device *pdev)
cfg->num_btn = PM4125_MBHC_MAX_BUTTONS;
cfg->micb_mv = pm4125->micb2_mv;
cfg->linein_th = 5000;
cfg->hs_thr = 1700;
cfg->hph_thr = 50;

wcd_dt_parse_mbhc_data(dev, &pm4125->mbhc_cfg);
cfg->hphl_swh = false;
cfg->gnd_swh = false;
cfg->hs_thr = 1700;
cfg->hph_thr = 50;
cfg->btn_high[0] = 75;
cfg->btn_high[1] = 150;
cfg->btn_high[2] = 237;
cfg->btn_high[3] = 500;
cfg->btn_high[4] = 500;
cfg->btn_high[5] = 500;
cfg->btn_high[6] = 500;
cfg->btn_high[7] = 500;

ret = pm4125_add_slave_components(pm4125, dev, &match);
if (ret)
Expand Down
13 changes: 13 additions & 0 deletions sound/soc/codecs/pm4125.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
#define PM4125_DIG_BASE_ADDR 0x3400

#define PM4125_ANA_MICBIAS_MICB_1_2_EN (PM4125_ANA_BASE_ADDR+0x040)
#define PM4125_ANA_MICBIAS_MICB1_EN_MASK BIT(6)
#define PM4125_ANA_MICBIAS_MICB1_PULL_UP_MASK BIT(5)
#define PM4125_ANA_MICBIAS_MICB2_EN_MASK BIT(2)
#define PM4125_ANA_MICBIAS_MICB2_PULL_UP_MASK BIT(1)
#define PM4125_ANA_MICBIAS_MICB2_PULL_DN_MASK BIT(0)
#define PM4125_ANA_MICBIAS_MICB_PULL_ENABLE 1
Expand All @@ -24,6 +26,8 @@
#define PM4125_ANA_TX_AMIC1 (PM4125_ANA_BASE_ADDR+0x047)
#define PM4125_ANA_TX_AMIC2 (PM4125_ANA_BASE_ADDR+0x048)
#define PM4125_ANA_MBHC_MECH (PM4125_ANA_BASE_ADDR+0x05A)
#define PM4125_ANA_MBHC_GND_DET_EN_MASK BIT(6)
#define PM4125_ANA_MBHC_HSG_PULLUP_COMP_EN_MASK BIT(1)
#define PM4125_ANA_MBHC_ELECT (PM4125_ANA_BASE_ADDR+0x05B)
#define PM4125_ANA_MBHC_ELECT_BIAS_EN_MASK BIT(0)
#define PM4125_ANA_MBHC_ELECT_BIAS_ENABLE 1
Expand All @@ -39,9 +43,14 @@
#define PM4125_ANA_MBHC_BTN3_ZDET_DBG_400 (PM4125_ANA_BASE_ADDR+0x063)
#define PM4125_ANA_MBHC_BTN4_ZDET_DBG_1400 (PM4125_ANA_BASE_ADDR+0x064)
#define PM4125_ANA_MBHC_MICB2_RAMP (PM4125_ANA_BASE_ADDR+0x065)
#define PM4125_ANA_MBHC_MICB2_RAMP_EN_MASK BIT(7)
#define PM4125_ANA_MBHC_MICB2_RAMP_SHIFT_MASK GENMASK(4, 2)
#define PM4125_ANA_MBHC_MICB2_RAMP_SHIFT_CTRL 3
#define PM4125_ANA_MBHC_CTL_1 (PM4125_ANA_BASE_ADDR+0x066)
#define PM4125_ANA_MBHC_CTL_RCO_EN_MASK BIT(7)
#define PM4125_ANA_MBHC_CTL_2 (PM4125_ANA_BASE_ADDR+0x067)
#define PM4125_ANA_MBHC_PLUG_DETECT_CTL (PM4125_ANA_BASE_ADDR+0x068)
#define PM4125_ANA_MBHC_HSDET_PULLUP_C_MASK GENMASK(7, 6)
#define PM4125_ANA_MBHC_ZDET_ANA_CTL (PM4125_ANA_BASE_ADDR+0x069)
#define PM4125_ANA_MBHC_ZDET_RAMP_CTL (PM4125_ANA_BASE_ADDR+0x06A)
#define PM4125_ANA_MBHC_FSM_STATUS (PM4125_ANA_BASE_ADDR+0x06B)
Expand All @@ -57,6 +66,10 @@
#define PM4125_ANA_HPHPA_CNP_CTL_1_EN_MASK BIT(1)
#define PM4125_ANA_HPHPA_CNP_CTL_1_EN 1
#define PM4125_ANA_HPHPA_CNP_CTL_2 (PM4125_ANA_BASE_ADDR+0x084)
#define PM4125_ANA_HPHPA_CNP_GND_L_MASK GENMASK(5, 4)
#define PM4125_ANA_HPHPA_CNP_GND_R_MASK GENMASK(3, 2)
#define PM4125_ANA_HPHPA_CNP_GND_PULL_DOWN 2
#define PM4125_ANA_HPHPA_CNP_GND_PULL_NONE 0
#define PM4125_ANA_HPHPA_CNP_OCP_EN_L_MASK BIT(1)
#define PM4125_ANA_HPHPA_CNP_OCP_EN_R_MASK BIT(0)
#define PM4125_ANA_HPHPA_CNP_OCP_ENABLE 1
Expand Down
1 change: 1 addition & 0 deletions sound/soc/qcom/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
case TX_CODEC_DMA_TX_1:
case TX_CODEC_DMA_TX_2:
case TX_CODEC_DMA_TX_3:
case VA_CODEC_DMA_TX_1:
for_each_rtd_codec_dais(rtd, i, codec_dai) {
rval = snd_soc_component_set_jack(codec_dai->component,
jack, NULL);
Expand Down
Loading