AndroidVibrator(1)在lk如何啓動vibrator

vibrator簡單介紹

現在市場上所使用的vibrator一共有兩種,他們是LRA與EMB。

  • LRA 線性振盪器
  • EMB 離心振盪器

這次主要爲大家介紹的是LRA

LRA是在單個軸上產生振盪力的振動電機,與直流偏心旋轉質量電機(EMB)不同,LRA依靠交流電壓來驅動壓靠與彈簧連接的移動質量塊的音圈。當音圈在彈簧的共振頻率下被驅動時,整個傳動器以可感知的力振動。雖可通過改變交流輸入來調節LRA的頻率和振幅,但傳動器必須在其諧振頻率下被驅動以產生大電流有意義的力

在產生振動,壓靠移動質量塊時,音圈在裝置內部保持靜止。通過相對於彈簧向上和向下驅動磁體,LRA作爲整體發生移位,產生振動。基礎機制類似於揚聲器產生聲音。在揚聲器中,通過將交流電頻率和振幅轉變爲振動頻率和振幅使空氣通過錐體並且以不同的頻率發生位移。

從高通的spec上可以看到可以LRA是被方波或者正弦波所驅動的。

一般來講在手機中,vibrator是被PMI芯片所驅動的,通過HAP_OUT_P/HAP_OUT_N驅動。

高通指出了它就是User Interface中的haptic.

lk的啓動流程圖

流程圖如下:

簡單說明:target_init函數調用vib_timed_turn_on進入函數pm_vib_turn_on,配置相關寄存器,設置定時器,啓動vib_timer_func,定時器結束回調vib_turn_off

具體分析

#if PON_VIB_SUPPORT
#include <vibrator.h>
#define VIBRATE_TIME 250
#endif

在init.c中會引用vibrator.h

#if PON_VIB_SUPPORT
	vib_timed_turn_on(VIBRATE_TIME);
#endif

target_init(void)中會調用vibrator.h的vib_timed_turn_on函數

在lk/dev/vib/vibrator.c中

/*
 * Function to turn on vibrator.
 * vibrate_time - the time of phone vibrate.
 */
void vib_timed_turn_on(const uint32_t vibrate_time)
{
	if(!vib_timeout){
		dprintf(CRITICAL,"vibrator already turn on\n");
		return;
	}
	vib_turn_on();
	vib_timeout = 0;
#if !USE_VIB_THREAD
	timer_initialize(&vib_timer);
	timer_set_oneshot(&vib_timer, vibrate_time, vib_timer_func, NULL);
#else
	vib_time = (vibrate_time/CHECK_VIB_TIMER_FREQUENCY)+1;
	thread_resume(thread_create("vibrator_thread", &vibrator_thread,
			NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
#endif
}

當vibrator的傳進來的時間不爲0時會啓動vibrator.c中vib_turn_on()函數

/* Function to turn on vibrator */
void vib_turn_on()
{
	pm_vib_turn_on();
}

調用lk/dev/vib/qpnp_haptic.c

#define HAPTIC_BASE (PMI_SECOND_SLAVE_ADDR_BASE+ 0xC000)
#define QPNP_HAP_EN_CTL_REG (HAPTIC_BASE + 0x46)
#define QPNP_HAP_EN_CTL2_REG (HAPTIC_BASE + 0x48)
#define QPNP_HAP_ACT_TYPE_REG (HAPTIC_BASE + 0x4C)
#define QPNP_HAP_WAV_SHAPE_REG (HAPTIC_BASE + 0x4D)
#define QPNP_HAP_PLAY_MODE_REG (HAPTIC_BASE + 0x4E)
#define QPNP_HAP_LRA_AUTO_RES_REG (HAPTIC_BASE + 0x4F)
#define QPNP_HAP_VMAX_REG (HAPTIC_BASE + 0x51)
#define QPNP_HAP_ILIM_REG (HAPTIC_BASE + 0x52)
#define QPNP_HAP_SC_DEB_REG (HAPTIC_BASE + 0x53)
#define QPNP_HAP_RATE_CFG1_REG (HAPTIC_BASE + 0x54)
#define QPNP_HAP_RATE_CFG2_REG (HAPTIC_BASE + 0x55)
#define QPNP_HAP_INT_PWM_REG (HAPTIC_BASE + 0x56)
#define QPNP_HAP_PWM_CAP_REG (HAPTIC_BASE + 0x58)
#define QPNP_HAP_BRAKE_REG (HAPTIC_BASE + 0x5C)
#define QPNP_HAP_PLAY_REG (HAPTIC_BASE + 0x70)
#define QPNP_HAP_ACT_TYPE_MASK 0x01
#define QPNP_HAP_PLAY_MODE_MASK 0x3F
#define QPNP_HAP_DIRECT 0x0
#define QPNP_HAP_VMAX_MASK 0x3F
#define QPNP_HAP_VMAX 0x14
#define QPNP_HAP_ILIM_MASK 0x01
#define QPNP_HAP_ILIM 0x01
#define QPNP_HAP_SC_DEB_MASK 0x07
#define QPNP_HAP_SC_DEB_8CLK 0x01
#define QPNP_HAP_INT_PWM_MASK 0x03
#define QPNP_HAP_INT_PWM_505KHZ 0x01
#define QPNP_HAP_WAV_SHAPE_MASK 0x01
#define QPNP_HAP_WAV_SHAPE_SQUARE 0x01
#define QPNP_HAP_PWM_CAP_MASK 0x03
#define QPNP_HAP_PWM_CAP_13PF 0x01
#define QPNP_HAP_RATE_CFG1_MASK 0xFF
#define QPNP_HAP_RATE_CFG2_MASK 0x0F
#define QPNP_HAP_EN_BRAKE_EN_MASK 0x01
#define QPNP_HAP_EN_BRAKING_EN 0x01
#define QPNP_HAP_BRAKE_VMAX_MASK 0xFF
#define QPNP_HAP_BRAKE_VMAX 0xF
#define QPNP_HAP_ERM 0x1
#define QPNP_HAP_LRA 0x0
#define QPNP_HAP_PLAY_MASK 0x80
#define QPNP_HAP_PLAY_EN 0x80
#define QPNP_HAP_MASK 0x80
#define QPNP_HAP_EN 0x80
#define QPNP_HAP_PLAY_DIS 0x00
#define QPNP_HAP_DIS 0x00
#define QPNP_HAP_BRAKE_MASK 0xFE
#define QPNP_HAP_LRA_AUTO_DISABLE 0x00
#define QPNP_HAP_LRA_AUTO_MASK 0x70
/* Turn on vibrator */
void pm_vib_turn_on(void)
{
	struct qpnp_hap vib_config = {0};
	get_vibration_type(&vib_config);
	/* Configure the ACTUATOR TYPE register as ERM*/
	pmic_spmi_reg_mask_write(QPNP_HAP_ACT_TYPE_REG,
					QPNP_HAP_ACT_TYPE_MASK,
					VIB_ERM_TYPE == vib_config.vib_type ? QPNP_HAP_ERM
					: QPNP_HAP_LRA);
	/* Disable auto resonance for ERM */
	pmic_spmi_reg_mask_write(QPNP_HAP_LRA_AUTO_RES_REG,
					QPNP_HAP_LRA_AUTO_MASK,
					QPNP_HAP_LRA_AUTO_DISABLE);
	/* Configure the PLAY MODE register as direct*/
	pmic_spmi_reg_mask_write(QPNP_HAP_PLAY_MODE_REG,
					QPNP_HAP_PLAY_MODE_MASK,
					QPNP_HAP_DIRECT);
	/* Configure the VMAX register */
	pmic_spmi_reg_mask_write(QPNP_HAP_VMAX_REG,
					QPNP_HAP_VMAX_MASK, QPNP_HAP_VMAX);
	/* Sets current limit to 800mA*/
	pmic_spmi_reg_mask_write(QPNP_HAP_ILIM_REG,
					QPNP_HAP_ILIM_MASK, QPNP_HAP_ILIM);
	/* Configure the short circuit debounce register as DEB_8CLK*/
	pmic_spmi_reg_mask_write(QPNP_HAP_SC_DEB_REG,
					QPNP_HAP_SC_DEB_MASK, QPNP_HAP_SC_DEB_8CLK);
	/* Configure the INTERNAL_PWM register as 505KHZ and 13PF*/
	pmic_spmi_reg_mask_write(QPNP_HAP_INT_PWM_REG,
					QPNP_HAP_INT_PWM_MASK, QPNP_HAP_INT_PWM_505KHZ);
	pmic_spmi_reg_mask_write(QPNP_HAP_PWM_CAP_REG,
					QPNP_HAP_PWM_CAP_MASK, QPNP_HAP_PWM_CAP_13PF);
	/* Configure the WAVE SHAPE register as SQUARE*/
	pmic_spmi_reg_mask_write(QPNP_HAP_WAV_SHAPE_REG,
					QPNP_HAP_WAV_SHAPE_MASK, QPNP_HAP_WAV_SHAPE_SQUARE);
	/* Configure RATE_CFG1 and RATE_CFG2 registers for haptic rate. */
	pmic_spmi_reg_mask_write(QPNP_HAP_RATE_CFG1_REG,
					QPNP_HAP_RATE_CFG1_MASK, vib_config.hap_rate_cfg1);
	pmic_spmi_reg_mask_write(QPNP_HAP_RATE_CFG2_REG,
					QPNP_HAP_RATE_CFG2_MASK, vib_config.hap_rate_cfg2);
	/* Configure BRAKE register, PATTERN1 & PATTERN2 as VMAX. */
	pmic_spmi_reg_mask_write(QPNP_HAP_EN_CTL2_REG,
					QPNP_HAP_EN_BRAKE_EN_MASK, QPNP_HAP_EN_BRAKING_EN);
	pmic_spmi_reg_mask_write(QPNP_HAP_BRAKE_REG,
					QPNP_HAP_BRAKE_VMAX_MASK, QPNP_HAP_BRAKE_VMAX);
	/* Enable control register */
	pmic_spmi_reg_mask_write(QPNP_HAP_EN_CTL_REG,
					QPNP_HAP_PLAY_MASK, QPNP_HAP_PLAY_EN);
	/* Enable play register */
	pmic_spmi_reg_mask_write(QPNP_HAP_PLAY_REG, QPNP_HAP_MASK, QPNP_HAP_EN);
}

確認vib的類型調用lk/target/init.c 中的 void get_vibration_type(struct qpnp_hap *config)

#if PON_VIB_SUPPORT
void get_vibration_type(struct qpnp_hap *config)
{
	uint32_t hw_id = board_hardware_id();
	uint32_t platform = board_platform_id();
	
	config->vib_type = VIB_ERM_TYPE;
	config->hap_rate_cfg1 = QPNP_HAP_RATE_CFG1_1c;
	config->hap_rate_cfg2 = QPNP_HAP_RATE_CFG2_04;
	switch(hw_id){
	case HW_PLATFORM_MTP:
		switch(platform){
		case MSM8952:
			config->vib_type = VIB_ERM_TYPE;
			break;
		case MSM8976:
		case MSM8956:
		case APQ8056:
			config->vib_type = VIB_LRA_TYPE;
			break;
		case MSM8937:
		case APQ8037:
		case MSM8917:
		case MSM8217:
		case MSM8617:
		case APQ8017:
		case MSM8953:
		case APQ8053:
			config->vib_type = VIB_LRA_TYPE;
			config->hap_rate_cfg1 = QPNP_HAP_RATE_CFG1_41;
			config->hap_rate_cfg2 = QPNP_HAP_RATE_CFG2_03;
			break;
		default:
			dprintf(CRITICAL,"Unsupported platform id\n");
			break;
		}
		break;
	case HW_PLATFORM_QRD:
		config->vib_type = VIB_ERM_TYPE;
		break;
	default:
		dprintf(CRITICAL,"Unsupported hardware id\n");
		break;
	}
}
#endif

然後可以看到設置一個定時器,告訴定時器時間到時的回調函數
vibrate_time之後纔回調vib_timer_func

/* Function to turn off vibrator when the vib_timer is expired. */
static enum handler_return vib_timer_func(struct timer *v_timer, time_t t, void *arg)
{
	timer_cancel(&vib_timer);
	if(!vib_timeout){
		vib_turn_off();
		vib_timeout = 1;
	}
	return INT_RESCHEDULE;
}

然後調用 vib_turn_off

/* Turn off vibrator */
void pm_vib_turn_off(void)
{
	/* Disable control register */
	pmic_spmi_reg_mask_write(QPNP_HAP_EN_CTL_REG,
					QPNP_HAP_PLAY_MASK, QPNP_HAP_PLAY_DIS);
	/* Disable play register */
	pmic_spmi_reg_mask_write(QPNP_HAP_PLAY_REG, QPNP_HAP_MASK, QPNP_HAP_DIS);
}

至此整個流程就已經通了

至於具體的配置寄存器,在此也列出了一張表,當然各個人可以對此表進行修改各類數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章