493 lines
13 KiB
C
493 lines
13 KiB
C
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
#ifndef __WCD9XXX_MBHC_H__
|
|
#define __WCD9XXX_MBHC_H__
|
|
|
|
#include "wcd9xxx-resmgr.h"
|
|
#include "wcdcal-hwdep.h"
|
|
|
|
#define WCD9XXX_CFILT_FAST_MODE 0x00
|
|
#define WCD9XXX_CFILT_SLOW_MODE 0x40
|
|
#define WCD9XXX_CFILT_EXT_PRCHG_EN 0x30
|
|
#define WCD9XXX_CFILT_EXT_PRCHG_DSBL 0x00
|
|
|
|
#define WCD9XXX_USLEEP_RANGE_MARGIN_US 100
|
|
|
|
struct mbhc_micbias_regs {
|
|
u16 cfilt_val;
|
|
u16 cfilt_ctl;
|
|
u16 mbhc_reg;
|
|
u16 int_rbias;
|
|
u16 ctl_reg;
|
|
u8 cfilt_sel;
|
|
};
|
|
|
|
enum mbhc_v_index {
|
|
MBHC_V_IDX_CFILT,
|
|
MBHC_V_IDX_VDDIO,
|
|
MBHC_V_IDX_NUM,
|
|
};
|
|
|
|
enum mbhc_cal_type {
|
|
MBHC_CAL_MCLK,
|
|
MBHC_CAL_RCO,
|
|
MBHC_CAL_NUM,
|
|
};
|
|
|
|
enum mbhc_impedance_detect_stages {
|
|
MBHC_ZDET_PRE_MEASURE,
|
|
MBHC_ZDET_POST_MEASURE,
|
|
MBHC_ZDET_GAIN_0,
|
|
MBHC_ZDET_GAIN_1,
|
|
MBHC_ZDET_GAIN_2,
|
|
MBHC_ZDET_HPHR_RAMP_DISABLE,
|
|
MBHC_ZDET_HPHL_RAMP_DISABLE,
|
|
MBHC_ZDET_RAMP_DISABLE,
|
|
MBHC_ZDET_HPHR_PA_DISABLE,
|
|
MBHC_ZDET_PA_DISABLE,
|
|
MBHC_ZDET_GAIN_UPDATE_1X,
|
|
};
|
|
|
|
/* Zone assignments used in WCD9330 for Zdet */
|
|
enum mbhc_zdet_zones {
|
|
ZL_ZONE1__ZR_ZONE1,
|
|
ZL_ZONE2__ZR_ZONE2,
|
|
ZL_ZONE3__ZR_ZONE3,
|
|
ZL_ZONE2__ZR_ZONE1,
|
|
ZL_ZONE3__ZR_ZONE1,
|
|
ZL_ZONE1__ZR_ZONE2,
|
|
ZL_ZONE1__ZR_ZONE3,
|
|
ZL_ZR_NOT_IN_ZONE1,
|
|
};
|
|
|
|
/* Data used by MBHC */
|
|
struct mbhc_internal_cal_data {
|
|
u16 dce_z;
|
|
u16 dce_nsc_cs_z;
|
|
u16 dce_mb;
|
|
u16 sta_z;
|
|
u16 sta_mb;
|
|
u32 t_sta_dce;
|
|
u32 t_dce;
|
|
u32 t_sta;
|
|
u32 micb_mv;
|
|
u16 v_ins_hu[MBHC_V_IDX_NUM];
|
|
u16 v_ins_h[MBHC_V_IDX_NUM];
|
|
u16 v_b1_hu[MBHC_V_IDX_NUM];
|
|
u16 v_b1_h[MBHC_V_IDX_NUM];
|
|
u16 v_brh[MBHC_V_IDX_NUM];
|
|
u16 v_brl;
|
|
u16 v_no_mic;
|
|
s16 v_inval_ins_low;
|
|
s16 v_inval_ins_high;
|
|
u16 v_cs_ins_h;
|
|
};
|
|
|
|
enum wcd9xxx_mbhc_plug_type {
|
|
PLUG_TYPE_INVALID = -1,
|
|
PLUG_TYPE_NONE,
|
|
PLUG_TYPE_HEADSET,
|
|
PLUG_TYPE_HEADPHONE,
|
|
PLUG_TYPE_HIGH_HPH,
|
|
PLUG_TYPE_GND_MIC_SWAP,
|
|
PLUG_TYPE_ANC_HEADPHONE,
|
|
};
|
|
|
|
enum wcd9xxx_mbhc_micbias_type {
|
|
MBHC_PRIMARY_MIC_MB,
|
|
MBHC_ANC_MIC_MB,
|
|
};
|
|
|
|
enum wcd9xxx_micbias_num {
|
|
MBHC_MICBIAS_INVALID = -1,
|
|
MBHC_MICBIAS1,
|
|
MBHC_MICBIAS2,
|
|
MBHC_MICBIAS3,
|
|
MBHC_MICBIAS4,
|
|
};
|
|
|
|
enum hw_jack_type {
|
|
FOUR_POLE_JACK = 0,
|
|
FIVE_POLE_JACK,
|
|
SIX_POLE_JACK,
|
|
};
|
|
|
|
enum wcd9xx_mbhc_micbias_enable_bits {
|
|
MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET,
|
|
MBHC_MICBIAS_ENABLE_REGULAR_HEADSET,
|
|
};
|
|
|
|
enum wcd9xx_mbhc_cs_enable_bits {
|
|
MBHC_CS_ENABLE_POLLING,
|
|
MBHC_CS_ENABLE_INSERTION,
|
|
MBHC_CS_ENABLE_REMOVAL,
|
|
MBHC_CS_ENABLE_DET_ANC,
|
|
};
|
|
|
|
enum wcd9xxx_mbhc_state {
|
|
MBHC_STATE_NONE = -1,
|
|
MBHC_STATE_POTENTIAL,
|
|
MBHC_STATE_POTENTIAL_RECOVERY,
|
|
MBHC_STATE_RELEASE,
|
|
};
|
|
|
|
enum wcd9xxx_mbhc_btn_det_mem {
|
|
MBHC_BTN_DET_V_BTN_LOW,
|
|
MBHC_BTN_DET_V_BTN_HIGH,
|
|
MBHC_BTN_DET_N_READY,
|
|
MBHC_BTN_DET_N_CIC,
|
|
MBHC_BTN_DET_GAIN
|
|
};
|
|
|
|
enum wcd9xxx_mbhc_clk_freq {
|
|
TAIKO_MCLK_12P2MHZ = 0,
|
|
TAIKO_MCLK_9P6MHZ,
|
|
TAIKO_NUM_CLK_FREQS,
|
|
};
|
|
|
|
enum wcd9xxx_mbhc_event_state {
|
|
MBHC_EVENT_PA_HPHL,
|
|
MBHC_EVENT_PA_HPHR,
|
|
MBHC_EVENT_PRE_TX_3_ON,
|
|
MBHC_EVENT_POST_TX_3_OFF,
|
|
};
|
|
|
|
enum mbhc_hph_type {
|
|
MBHC_HPH_NONE = 0,
|
|
MBHC_HPH_MONO,
|
|
MBHC_HPH_STEREO,
|
|
};
|
|
|
|
struct wcd9xxx_mbhc_general_cfg {
|
|
u8 t_ldoh;
|
|
u8 t_bg_fast_settle;
|
|
u8 t_shutdown_plug_rem;
|
|
u8 mbhc_nsa;
|
|
u8 mbhc_navg;
|
|
u8 v_micbias_l;
|
|
u8 v_micbias;
|
|
u8 mbhc_reserved;
|
|
u16 settle_wait;
|
|
u16 t_micbias_rampup;
|
|
u16 t_micbias_rampdown;
|
|
u16 t_supply_bringup;
|
|
} __packed;
|
|
|
|
struct wcd9xxx_mbhc_plug_detect_cfg {
|
|
u32 mic_current;
|
|
u32 hph_current;
|
|
u16 t_mic_pid;
|
|
u16 t_ins_complete;
|
|
u16 t_ins_retry;
|
|
u16 v_removal_delta;
|
|
u8 micbias_slow_ramp;
|
|
u8 reserved0;
|
|
u8 reserved1;
|
|
u8 reserved2;
|
|
} __packed;
|
|
|
|
struct wcd9xxx_mbhc_plug_type_cfg {
|
|
u8 av_detect;
|
|
u8 mono_detect;
|
|
u8 num_ins_tries;
|
|
u8 reserved0;
|
|
s16 v_no_mic;
|
|
s16 v_av_min;
|
|
s16 v_av_max;
|
|
s16 v_hs_min;
|
|
s16 v_hs_max;
|
|
u16 reserved1;
|
|
} __packed;
|
|
|
|
struct wcd9xxx_mbhc_btn_detect_cfg {
|
|
s8 c[8];
|
|
u8 nc;
|
|
u8 n_meas;
|
|
u8 mbhc_nsc;
|
|
u8 n_btn_meas;
|
|
u8 n_btn_con;
|
|
u8 num_btn;
|
|
u8 reserved0;
|
|
u8 reserved1;
|
|
u16 t_poll;
|
|
u16 t_bounce_wait;
|
|
u16 t_rel_timeout;
|
|
s16 v_btn_press_delta_sta;
|
|
s16 v_btn_press_delta_cic;
|
|
u16 t_btn0_timeout;
|
|
s16 _v_btn_low[0]; /* v_btn_low[num_btn] */
|
|
s16 _v_btn_high[0]; /* v_btn_high[num_btn] */
|
|
u8 _n_ready[TAIKO_NUM_CLK_FREQS];
|
|
u8 _n_cic[TAIKO_NUM_CLK_FREQS];
|
|
u8 _gain[TAIKO_NUM_CLK_FREQS];
|
|
} __packed;
|
|
|
|
struct wcd9xxx_mbhc_imped_detect_cfg {
|
|
u8 _hs_imped_detect;
|
|
u8 _n_rload;
|
|
u8 _hph_keep_on;
|
|
u8 _repeat_rload_calc;
|
|
u16 _t_dac_ramp_time;
|
|
u16 _rhph_high;
|
|
u16 _rhph_low;
|
|
u16 _rload[0]; /* rload[n_rload] */
|
|
u16 _alpha[0]; /* alpha[n_rload] */
|
|
u16 _beta[3];
|
|
} __packed;
|
|
|
|
struct wcd9xxx_mbhc_config {
|
|
bool read_fw_bin;
|
|
/*
|
|
* void* calibration contains:
|
|
* struct wcd9xxx_mbhc_general_cfg generic;
|
|
* struct wcd9xxx_mbhc_plug_detect_cfg plug_det;
|
|
* struct wcd9xxx_mbhc_plug_type_cfg plug_type;
|
|
* struct wcd9xxx_mbhc_btn_detect_cfg btn_det;
|
|
* struct wcd9xxx_mbhc_imped_detect_cfg imped_det;
|
|
* Note: various size depends on btn_det->num_btn
|
|
*/
|
|
void *calibration;
|
|
enum wcd9xxx_micbias_num micbias;
|
|
enum wcd9xxx_micbias_num anc_micbias;
|
|
int (*mclk_cb_fn) (struct snd_soc_codec*, int, bool);
|
|
unsigned int mclk_rate;
|
|
unsigned int gpio;
|
|
unsigned int gpio_irq;
|
|
int gpio_level_insert;
|
|
bool insert_detect; /* codec has own MBHC_INSERT_DETECT */
|
|
bool detect_extn_cable;
|
|
/* bit mask of enum wcd9xx_mbhc_micbias_enable_bits */
|
|
unsigned long micbias_enable_flags;
|
|
/* swap_gnd_mic returns true if extern GND/MIC swap switch toggled */
|
|
bool (*swap_gnd_mic) (struct snd_soc_codec *);
|
|
unsigned long cs_enable_flags;
|
|
bool use_int_rbias;
|
|
bool do_recalibration;
|
|
bool use_vddio_meas;
|
|
bool enable_anc_mic_detect;
|
|
enum hw_jack_type hw_jack_type;
|
|
int key_code[8];
|
|
};
|
|
|
|
struct wcd9xxx_cfilt_mode {
|
|
u8 reg_mode_val;
|
|
u8 cur_mode_val;
|
|
u8 reg_mask;
|
|
};
|
|
|
|
struct wcd9xxx_mbhc_intr {
|
|
int poll_plug_rem;
|
|
int shortavg_complete;
|
|
int potential_button_press;
|
|
int button_release;
|
|
int dce_est_complete;
|
|
int insertion;
|
|
int hph_left_ocp;
|
|
int hph_right_ocp;
|
|
int hs_jack_switch;
|
|
};
|
|
|
|
struct wcd9xxx_mbhc_cb {
|
|
void (*enable_mux_bias_block) (struct snd_soc_codec *);
|
|
void (*cfilt_fast_mode) (struct snd_soc_codec *, struct wcd9xxx_mbhc *);
|
|
void (*codec_specific_cal) (struct snd_soc_codec *,
|
|
struct wcd9xxx_mbhc *);
|
|
struct wcd9xxx_cfilt_mode (*switch_cfilt_mode) (struct wcd9xxx_mbhc *,
|
|
bool);
|
|
void (*select_cfilt) (struct snd_soc_codec *, struct wcd9xxx_mbhc *);
|
|
enum wcd9xxx_cdc_type (*get_cdc_type) (void);
|
|
void (*enable_clock_gate) (struct snd_soc_codec *, bool);
|
|
int (*setup_zdet) (struct wcd9xxx_mbhc *,
|
|
enum mbhc_impedance_detect_stages stage);
|
|
void (*compute_impedance) (struct wcd9xxx_mbhc *, s16 *, s16 *,
|
|
uint32_t *, uint32_t *);
|
|
void (*zdet_error_approx) (struct wcd9xxx_mbhc *, uint32_t *,
|
|
uint32_t *);
|
|
void (*enable_mbhc_txfe) (struct snd_soc_codec *, bool);
|
|
int (*enable_mb_source) (struct snd_soc_codec *, bool, bool);
|
|
void (*setup_int_rbias) (struct snd_soc_codec *, bool);
|
|
void (*pull_mb_to_vddio) (struct snd_soc_codec *, bool);
|
|
bool (*insert_rem_status) (struct snd_soc_codec *);
|
|
void (*micbias_pulldown_ctrl) (struct wcd9xxx_mbhc *, bool);
|
|
int (*codec_rco_ctrl) (struct snd_soc_codec *, bool);
|
|
void (*hph_auto_pulldown_ctrl) (struct snd_soc_codec *, bool);
|
|
struct firmware_cal * (*get_hwdep_fw_cal) (struct snd_soc_codec *,
|
|
enum wcd_cal_type);
|
|
};
|
|
|
|
struct wcd9xxx_mbhc {
|
|
bool polling_active;
|
|
/* Delayed work to report long button press */
|
|
struct delayed_work mbhc_btn_dwork;
|
|
int buttons_pressed;
|
|
enum wcd9xxx_mbhc_state mbhc_state;
|
|
struct wcd9xxx_mbhc_config *mbhc_cfg;
|
|
const struct wcd9xxx_mbhc_cb *mbhc_cb;
|
|
|
|
struct mbhc_internal_cal_data mbhc_data;
|
|
|
|
struct mbhc_micbias_regs mbhc_bias_regs;
|
|
struct mbhc_micbias_regs mbhc_anc_bias_regs;
|
|
|
|
bool mbhc_micbias_switched;
|
|
|
|
u32 hph_status; /* track headhpone status */
|
|
u8 hphlocp_cnt; /* headphone left ocp retry */
|
|
u8 hphrocp_cnt; /* headphone right ocp retry */
|
|
|
|
/* Work to perform MBHC Firmware Read */
|
|
struct delayed_work mbhc_firmware_dwork;
|
|
const struct firmware *mbhc_fw;
|
|
struct firmware_cal *mbhc_cal;
|
|
|
|
struct delayed_work mbhc_insert_dwork;
|
|
|
|
u8 current_plug;
|
|
struct work_struct correct_plug_swch;
|
|
/*
|
|
* Work to perform polling on microphone voltage
|
|
* in order to correct plug type once plug type
|
|
* is detected as headphone
|
|
*/
|
|
struct work_struct correct_plug_noswch;
|
|
bool hs_detect_work_stop;
|
|
|
|
bool lpi_enabled; /* low power insertion detection */
|
|
bool in_swch_irq_handler;
|
|
|
|
struct wcd9xxx_resmgr *resmgr;
|
|
struct snd_soc_codec *codec;
|
|
|
|
bool no_mic_headset_override;
|
|
|
|
/* track PA/DAC state to sync with userspace */
|
|
unsigned long hph_pa_dac_state;
|
|
/*
|
|
* save codec's state with resmgr event notification
|
|
* bit flags of enum wcd9xxx_mbhc_event_state
|
|
*/
|
|
unsigned long event_state;
|
|
|
|
unsigned long mbhc_last_resume; /* in jiffies */
|
|
|
|
bool insert_detect_level_insert;
|
|
|
|
struct snd_soc_jack headset_jack;
|
|
struct snd_soc_jack button_jack;
|
|
|
|
struct notifier_block nblock;
|
|
|
|
bool micbias_enable;
|
|
int (*micbias_enable_cb) (struct snd_soc_codec*, bool,
|
|
enum wcd9xxx_micbias_num);
|
|
|
|
bool impedance_detect;
|
|
/* impedance of hphl and hphr */
|
|
uint32_t zl, zr;
|
|
|
|
u32 rco_clk_rate;
|
|
|
|
bool update_z;
|
|
|
|
u8 scaling_mux_in;
|
|
/* Holds codec specific interrupt mapping */
|
|
const struct wcd9xxx_mbhc_intr *intr_ids;
|
|
|
|
/* Indicates status of current source switch */
|
|
bool is_cs_enabled;
|
|
|
|
/* Holds type of Headset - Mono/Stereo */
|
|
enum mbhc_hph_type hph_type;
|
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
struct dentry *debugfs_poke;
|
|
struct dentry *debugfs_mbhc;
|
|
#endif
|
|
|
|
struct mutex mbhc_lock;
|
|
};
|
|
|
|
#define WCD9XXX_MBHC_CAL_SIZE(buttons, rload) ( \
|
|
sizeof(enum wcd9xxx_micbias_num) + \
|
|
sizeof(struct wcd9xxx_mbhc_general_cfg) + \
|
|
sizeof(struct wcd9xxx_mbhc_plug_detect_cfg) + \
|
|
((sizeof(s16) + sizeof(s16)) * buttons) + \
|
|
sizeof(struct wcd9xxx_mbhc_plug_type_cfg) + \
|
|
sizeof(struct wcd9xxx_mbhc_btn_detect_cfg) + \
|
|
sizeof(struct wcd9xxx_mbhc_imped_detect_cfg) + \
|
|
((sizeof(u16) + sizeof(u16)) * rload) \
|
|
)
|
|
|
|
#define WCD9XXX_MBHC_CAL_GENERAL_PTR(cali) ( \
|
|
(struct wcd9xxx_mbhc_general_cfg *) cali)
|
|
#define WCD9XXX_MBHC_CAL_PLUG_DET_PTR(cali) ( \
|
|
(struct wcd9xxx_mbhc_plug_detect_cfg *) \
|
|
&(WCD9XXX_MBHC_CAL_GENERAL_PTR(cali)[1]))
|
|
#define WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(cali) ( \
|
|
(struct wcd9xxx_mbhc_plug_type_cfg *) \
|
|
&(WCD9XXX_MBHC_CAL_PLUG_DET_PTR(cali)[1]))
|
|
#define WCD9XXX_MBHC_CAL_BTN_DET_PTR(cali) ( \
|
|
(struct wcd9xxx_mbhc_btn_detect_cfg *) \
|
|
&(WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(cali)[1]))
|
|
#define WCD9XXX_MBHC_CAL_IMPED_DET_PTR(cali) ( \
|
|
(struct wcd9xxx_mbhc_imped_detect_cfg *) \
|
|
(((void *)&WCD9XXX_MBHC_CAL_BTN_DET_PTR(cali)[1]) + \
|
|
(WCD9XXX_MBHC_CAL_BTN_DET_PTR(cali)->num_btn * \
|
|
(sizeof(WCD9XXX_MBHC_CAL_BTN_DET_PTR(cali)->_v_btn_low[0]) + \
|
|
sizeof(WCD9XXX_MBHC_CAL_BTN_DET_PTR(cali)->_v_btn_high[0])))) \
|
|
)
|
|
|
|
/* minimum size of calibration data assuming there is only one button and
|
|
* one rload.
|
|
*/
|
|
#define WCD9XXX_MBHC_CAL_MIN_SIZE ( \
|
|
sizeof(struct wcd9xxx_mbhc_general_cfg) + \
|
|
sizeof(struct wcd9xxx_mbhc_plug_detect_cfg) + \
|
|
sizeof(struct wcd9xxx_mbhc_plug_type_cfg) + \
|
|
sizeof(struct wcd9xxx_mbhc_btn_detect_cfg) + \
|
|
sizeof(struct wcd9xxx_mbhc_imped_detect_cfg) + \
|
|
(sizeof(u16) * 2) \
|
|
)
|
|
|
|
#define WCD9XXX_MBHC_CAL_BTN_SZ(cfg_ptr) ( \
|
|
sizeof(struct wcd9xxx_mbhc_btn_detect_cfg) + \
|
|
(cfg_ptr->num_btn * (sizeof(cfg_ptr->_v_btn_low[0]) + \
|
|
sizeof(cfg_ptr->_v_btn_high[0]))))
|
|
|
|
#define WCD9XXX_MBHC_CAL_IMPED_MIN_SZ ( \
|
|
sizeof(struct wcd9xxx_mbhc_imped_detect_cfg) + sizeof(u16) * 2)
|
|
|
|
#define WCD9XXX_MBHC_CAL_IMPED_SZ(cfg_ptr) ( \
|
|
sizeof(struct wcd9xxx_mbhc_imped_detect_cfg) + \
|
|
(cfg_ptr->_n_rload * \
|
|
(sizeof(cfg_ptr->_rload[0]) + sizeof(cfg_ptr->_alpha[0]))))
|
|
|
|
int wcd9xxx_mbhc_set_keycode(struct wcd9xxx_mbhc *mbhc);
|
|
int wcd9xxx_mbhc_start(struct wcd9xxx_mbhc *mbhc,
|
|
struct wcd9xxx_mbhc_config *mbhc_cfg);
|
|
void wcd9xxx_mbhc_stop(struct wcd9xxx_mbhc *mbhc);
|
|
int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
|
|
struct snd_soc_codec *codec,
|
|
int (*micbias_enable_cb) (struct snd_soc_codec*, bool,
|
|
enum wcd9xxx_micbias_num),
|
|
const struct wcd9xxx_mbhc_cb *mbhc_cb,
|
|
const struct wcd9xxx_mbhc_intr *mbhc_cdc_intr_ids,
|
|
int rco_clk_rate,
|
|
bool impedance_det_en);
|
|
void wcd9xxx_mbhc_deinit(struct wcd9xxx_mbhc *mbhc);
|
|
void *wcd9xxx_mbhc_cal_btn_det_mp(
|
|
const struct wcd9xxx_mbhc_btn_detect_cfg *btn_det,
|
|
const enum wcd9xxx_mbhc_btn_det_mem mem);
|
|
int wcd9xxx_mbhc_get_impedance(struct wcd9xxx_mbhc *mbhc, uint32_t *zl,
|
|
uint32_t *zr);
|
|
#endif /* __WCD9XXX_MBHC_H__ */
|