コード例 #1
0
ファイル: qpnp-haptic.c プロジェクト: auras76/aur-kernel-XZxx
/* configuration api for buffer mode */
static int qpnp_hap_buffer_config(struct qpnp_hap *hap)
{
	u8 reg = 0;
	int rc, i, temp;

	/* Configure the WAVE_REPEAT register */
	if (hap->wave_rep_cnt < QPNP_HAP_WAV_REP_MIN)
		hap->wave_rep_cnt = QPNP_HAP_WAV_REP_MIN;
	else if (hap->wave_rep_cnt > QPNP_HAP_WAV_REP_MAX)
		hap->wave_rep_cnt = QPNP_HAP_WAV_REP_MAX;

	if (hap->wave_s_rep_cnt < QPNP_HAP_WAV_S_REP_MIN)
		hap->wave_s_rep_cnt = QPNP_HAP_WAV_S_REP_MIN;
	else if (hap->wave_s_rep_cnt > QPNP_HAP_WAV_S_REP_MAX)
		hap->wave_s_rep_cnt = QPNP_HAP_WAV_S_REP_MAX;

	rc = qpnp_hap_read_reg(hap, &reg,
			QPNP_HAP_WAV_REP_REG(hap->base));
	if (rc < 0)
		return rc;
	reg &= QPNP_HAP_WAV_REP_MASK;
	temp = fls(hap->wave_rep_cnt) - 1;
	reg |= (temp << QPNP_HAP_WAV_REP_SHFT);
	reg &= QPNP_HAP_WAV_S_REP_MASK;
	temp = fls(hap->wave_s_rep_cnt) - 1;
	reg |= temp;
	rc = qpnp_hap_write_reg(hap, &reg,
			QPNP_HAP_WAV_REP_REG(hap->base));
	if (rc)
		return rc;

	/* Configure WAVE_SAMPLE1 to WAVE_SAMPLE8 register */
	for (i = 0, reg = 0; i < QPNP_HAP_WAV_SAMP_LEN; i++) {
		reg = hap->wave_samp[i];
		rc = qpnp_hap_write_reg(hap, &reg,
			QPNP_HAP_WAV_S_REG_BASE(hap->base) + i);
		if (rc)
			return rc;
	}

	/* setup play irq */
	if (hap->use_play_irq) {
		rc = devm_request_threaded_irq(&hap->spmi->dev, hap->play_irq,
			NULL, qpnp_hap_play_irq,
			QPNP_IRQ_FLAGS,
			"qpnp_play_irq", hap);
		if (rc < 0) {
			dev_err(&hap->spmi->dev,
				"Unable to request play(%d) IRQ(err:%d)\n",
				hap->play_irq, rc);
			return rc;
		}
	}

	hap->buffer_cfg_state = true;
	return 0;
}
コード例 #2
0
ファイル: qpnp-haptic.c プロジェクト: auras76/aur-kernel-XZxx
/* sysfs store for wave samples repeat */
static ssize_t qpnp_hap_wf_s_rep_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	struct timed_output_dev *timed_dev = dev_get_drvdata(dev);
	struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap,
					 timed_dev);
	int data, rc, temp;
	u8 reg;

	if (sscanf(buf, "%d", &data) != 1)
		return -EINVAL;

	if (data < QPNP_HAP_WAV_S_REP_MIN)
		data = QPNP_HAP_WAV_S_REP_MIN;
	else if (data > QPNP_HAP_WAV_S_REP_MAX)
		data = QPNP_HAP_WAV_S_REP_MAX;

	rc = qpnp_hap_read_reg(hap, &reg,
			QPNP_HAP_WAV_REP_REG(hap->base));
	if (rc < 0)
		return rc;
	reg &= QPNP_HAP_WAV_S_REP_MASK;
	temp = fls(data) - 1;
	reg |= temp;
	rc = qpnp_hap_write_reg(hap, &reg,
			QPNP_HAP_WAV_REP_REG(hap->base));
	if (rc)
		return rc;

	hap->wave_s_rep_cnt = data;

	return count;
}
コード例 #3
0
ファイル: qpnp-haptic.c プロジェクト: auras76/aur-kernel-XZxx
/* sysfs store for max volatge */
static ssize_t qpnp_hap_max_volatge_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	struct timed_output_dev *timed_dev = dev_get_drvdata(dev);
	struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap,
					 timed_dev);
	int data, rc, temp;
	u8 reg;

	if (sscanf(buf, "%d", &data) != 1)
		return -EINVAL;

	if (data < QPNP_HAP_VMAX_MIN_MV)
		data = QPNP_HAP_VMAX_MIN_MV;
	else if (data > QPNP_HAP_VMAX_MAX_MV)
		data = QPNP_HAP_VMAX_MAX_MV;

	rc = qpnp_hap_read_reg(hap, &reg, QPNP_HAP_VMAX_REG(hap->base));
	if (rc < 0)
		return rc;
	reg &= QPNP_HAP_VMAX_MASK;
	temp = data / QPNP_HAP_VMAX_MIN_MV;
	reg |= (temp << QPNP_HAP_VMAX_SHIFT);
	rc = qpnp_hap_write_reg(hap, &reg, QPNP_HAP_VMAX_REG(hap->base));
	if (rc)
		return rc;

	hap->vmax_mv = data;

	return count;
}
コード例 #4
0
/* configuration api for max volatge */
static int qpnp_hap_vmax_config(struct qpnp_hap *hap , int odrb)
{
	u8 reg = 0;
	int rc, temp;

	if (hap->vmax_mv < QPNP_HAP_VMAX_MIN_MV)
		hap->vmax_mv = QPNP_HAP_VMAX_MIN_MV;
	else if (hap->vmax_mv > QPNP_HAP_VMAX_MAX_MV)
	{
	/*                           */
	/* When Over drive or Reverse braking occur , odrb = 1 */
	 if(odrb)
		hap->vmax_mv = QPNP_HAP_OV_RB_MV;
	 else
		hap->vmax_mv = QPNP_HAP_VMAX_MAX_MV;
	}

	rc = qpnp_hap_read_reg(hap, &reg, QPNP_HAP_VMAX_REG(hap->base));
	if (rc < 0)
		return rc;
	reg &= QPNP_HAP_VMAX_MASK;
	temp = hap->vmax_mv / QPNP_HAP_VMAX_MIN_MV;
	reg |= (temp << QPNP_HAP_VMAX_SHIFT);
	rc = qpnp_hap_write_reg(hap, &reg, QPNP_HAP_VMAX_REG(hap->base));
	if (rc)
		return rc;

	return 0;
}
コード例 #5
0
static int qpnp_hap_play(struct qpnp_hap *hap, int on)
{
	u8 val;
	int rc;

	val = hap->reg_play;
	if (on)
		val |= QPNP_HAP_PLAY_EN;
	else
		val &= ~QPNP_HAP_PLAY_EN;
	if (hap->play_mode == QPNP_HAP_DIRECT) {
		if (!on) {

			/*                        */
#if 0
			/* 2 x VMAX reverse braking */
			hap->vmax_mv = hap->vmax_mv_orig * 2;
#endif
			/*                                         */
			hap->vmax_mv = QPNP_HAP_OV_RB_MV;
			qpnp_hap_vmax_config(hap,1);
		}
	}

	rc = qpnp_hap_write_reg(hap, &val,
			QPNP_HAP_PLAY_REG(hap->base));
	if (rc < 0)
		return rc;
	pr_info("[LGE VIBRATOR] qpnp_hap_play play : %d voltage : %d \n", on  , hap->vmax_mv);
	hap->reg_play = val;

	return 0;
}
コード例 #6
0
ファイル: qpnp-haptic.c プロジェクト: auras76/aur-kernel-XZxx
/* short circuit irq handler */
static irqreturn_t qpnp_hap_sc_irq(int irq, void *_hap)
{
	struct qpnp_hap *hap = _hap;
	u8 reg;

	/* clear short circuit register */
	dev_dbg(&hap->spmi->dev, "Short circuit detected\n");
	reg = QPNP_HAP_SC_CLR;
	qpnp_hap_write_reg(hap, &reg, QPNP_HAP_SC_CLR_REG(hap->base));

	return IRQ_HANDLED;
}
コード例 #7
0
ファイル: qpnp-haptic.c プロジェクト: auras76/aur-kernel-XZxx
/* configuration api for pwm */
static int qpnp_hap_pwm_config(struct qpnp_hap *hap)
{
	u8 reg = 0;
	int rc, temp;

	/* Configure the EXTERNAL_PWM register */
	if (hap->ext_pwm_freq_khz <= QPNP_HAP_EXT_PWM_FREQ_25_KHZ) {
		hap->ext_pwm_freq_khz = QPNP_HAP_EXT_PWM_FREQ_25_KHZ;
		temp = 0;
	} else if (hap->ext_pwm_freq_khz <=
				QPNP_HAP_EXT_PWM_FREQ_50_KHZ) {
		hap->ext_pwm_freq_khz = QPNP_HAP_EXT_PWM_FREQ_50_KHZ;
		temp = 1;
	} else if (hap->ext_pwm_freq_khz <=
				QPNP_HAP_EXT_PWM_FREQ_75_KHZ) {
		hap->ext_pwm_freq_khz = QPNP_HAP_EXT_PWM_FREQ_75_KHZ;
		temp = 2;
	} else {
		hap->ext_pwm_freq_khz = QPNP_HAP_EXT_PWM_FREQ_100_KHZ;
		temp = 3;
	}

	rc = qpnp_hap_read_reg(hap, &reg,
			QPNP_HAP_EXT_PWM_REG(hap->base));
	if (rc < 0)
		return rc;
	reg &= QPNP_HAP_EXT_PWM_MASK;
	reg |= temp;
	rc = qpnp_hap_write_reg(hap, &reg,
			QPNP_HAP_EXT_PWM_REG(hap->base));
	if (rc)
		return rc;

	hap->pwm_info.pwm_dev = pwm_request(hap->pwm_info.pwm_channel,
							 "qpnp-hap");
	if (IS_ERR_OR_NULL(hap->pwm_info.pwm_dev)) {
		dev_err(&hap->spmi->dev, "hap pwm request failed\n");
		return -ENODEV;
	}

	rc = pwm_config(hap->pwm_info.pwm_dev, hap->pwm_info.duty_us,
					hap->pwm_info.period_us);
	if (rc < 0) {
		dev_err(&hap->spmi->dev, "hap pwm config failed\n");
		pwm_free(hap->pwm_info.pwm_dev);
		return -ENODEV;
	}

	hap->pwm_cfg_state = true;

	return 0;
}
コード例 #8
0
ファイル: qpnp-haptic.c プロジェクト: auras76/aur-kernel-XZxx
/* configuration api for play mode */
static int qpnp_hap_play_mode_config(struct qpnp_hap *hap)
{
	u8 reg = 0;
	int rc, temp;

	rc = qpnp_hap_read_reg(hap, &reg, QPNP_HAP_PLAY_MODE_REG(hap->base));
	if (rc < 0)
		return rc;
	reg &= QPNP_HAP_PLAY_MODE_MASK;
	temp = hap->play_mode << QPNP_HAP_PLAY_MODE_SHFT;
	reg |= temp;
	rc = qpnp_hap_write_reg(hap, &reg, QPNP_HAP_PLAY_MODE_REG(hap->base));
	if (rc)
		return rc;
	return 0;
}
コード例 #9
0
ファイル: qpnp-haptic.c プロジェクト: auras76/aur-kernel-XZxx
static int qpnp_hap_play(struct qpnp_hap *hap, int on)
{
	u8 val;
	int rc;

	val = hap->reg_play;
	if (on)
		val |= QPNP_HAP_PLAY_EN;
	else
		val &= ~QPNP_HAP_PLAY_EN;

	rc = qpnp_hap_write_reg(hap, &val,
			QPNP_HAP_PLAY_REG(hap->base));
	if (rc < 0)
		return rc;

	hap->reg_play = val;

	return 0;
}
コード例 #10
0
ファイル: qpnp-haptic.c プロジェクト: Skin1980/bass-MM
static int qpnp_hap_mod_enable(struct qpnp_hap *hap, int on)
{
	u8 val;
	int rc;

	val = hap->reg_en_ctl;
	if (on)
		val |= QPNP_HAP_EN;
	else
		val &= ~QPNP_HAP_EN;

	rc = qpnp_hap_write_reg(hap, &val,
			QPNP_HAP_EN_CTL_REG(hap->base));
	if (rc < 0)
		return rc;

	hap->reg_en_ctl = val;

	return 0;
}
コード例 #11
0
/* sysfs store for amp */
static ssize_t qpnp_hap_amp_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	struct timed_output_dev *timed_dev = dev_get_drvdata(dev);
	struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap,
					 timed_dev);
	u8 reg = 0;
	int temp, ret, value;

	if (sscanf(buf, "%d", &value) != 1)
		return -EINVAL;

	if (value < QPNP_HAP_VMAX_MIN_MV)
		value = QPNP_HAP_VMAX_MIN_MV;
	else if (value > QPNP_HAP_VMAX_MAX_MV)
		value = QPNP_HAP_VMAX_MAX_MV;

	ret = qpnp_hap_read_reg(hap, &reg, QPNP_HAP_VMAX_REG(hap->base));

	if (ret < 0) {
			dev_err(&hap->spmi->dev, "Error reading address: %X\n",
					QPNP_HAP_VMAX_REG(hap->base));
	}

	reg &= QPNP_HAP_VMAX_MASK;
	/* Vmax Controlled by 116mV step. So we divide our input Voltage by 116 */
	temp = value / QPNP_HAP_VMAX_MIN_MV;
	/* Changed Vmax have to save to hap->vmax_mv and hap->vmax_mv_orig to
						recover vmax that changed here */
	hap->vmax_mv = hap->vmax_mv_orig = temp * QPNP_HAP_VMAX_MIN_MV;
	reg |= (temp << QPNP_HAP_VMAX_SHIFT);

	ret = qpnp_hap_write_reg(hap, &reg, QPNP_HAP_VMAX_REG(hap->base));
	if (ret < 0) {
			dev_err(&hap->spmi->dev,
					"Error writing address: %X\n",
					QPNP_HAP_VMAX_REG(hap->base));
	}

	return count;
}
コード例 #12
0
ファイル: qpnp-haptic.c プロジェクト: auras76/aur-kernel-XZxx
static int qpnp_hap_mod_enable(struct qpnp_hap *hap, int on)
{
	u8 val;
	int rc, i;

	val = hap->reg_en_ctl;
	if (on) {
		val |= QPNP_HAP_EN;
	} else {
		for (i = 0; i < QPNP_HAP_MAX_RETRIES; i++) {
			rc = qpnp_hap_read_reg(hap, &val,
				QPNP_HAP_STATUS(hap->base));

			dev_dbg(&hap->spmi->dev, "HAP_STATUS=0x%x\n", val);

			/* wait for QPNP_HAP_CYCLS cycles of play rate */
			if (val & QPNP_HAP_STATUS_BUSY) {
				usleep(QPNP_HAP_CYCLS * hap->wave_play_rate_us);
				if (hap->play_mode == QPNP_HAP_DIRECT)
					break;
			} else
				break;
		}

		if (i >= QPNP_HAP_MAX_RETRIES)
			dev_dbg(&hap->spmi->dev,
				"Haptics Busy. Force disable\n");

		val &= ~QPNP_HAP_EN;
	}

	rc = qpnp_hap_write_reg(hap, &val,
			QPNP_HAP_EN_CTL_REG(hap->base));
	if (rc < 0)
		return rc;

	hap->reg_en_ctl = val;

	return 0;
}
コード例 #13
0
ファイル: qpnp-haptic.c プロジェクト: auras76/aur-kernel-XZxx
/* configuration api for max volatge */
static int qpnp_hap_vmax_config(struct qpnp_hap *hap)
{
	u8 reg = 0;
	int rc, temp;

	if (hap->vmax_mv < QPNP_HAP_VMAX_MIN_MV)
		hap->vmax_mv = QPNP_HAP_VMAX_MIN_MV;
	else if (hap->vmax_mv > QPNP_HAP_VMAX_MAX_MV)
		hap->vmax_mv = QPNP_HAP_VMAX_MAX_MV;

	rc = qpnp_hap_read_reg(hap, &reg, QPNP_HAP_VMAX_REG(hap->base));
	if (rc < 0)
		return rc;
	reg &= QPNP_HAP_VMAX_MASK;
	temp = hap->vmax_mv / QPNP_HAP_VMAX_MIN_MV;
	reg |= (temp << QPNP_HAP_VMAX_SHIFT);
	rc = qpnp_hap_write_reg(hap, &reg, QPNP_HAP_VMAX_REG(hap->base));
	if (rc)
		return rc;

	return 0;
}
コード例 #14
0
ファイル: qpnp-haptic.c プロジェクト: auras76/aur-kernel-XZxx
/* play irq handler */
static irqreturn_t qpnp_hap_play_irq(int irq, void *_hap)
{
	struct qpnp_hap *hap = _hap;
	int i, rc;
	u8 reg;

	mutex_lock(&hap->wf_lock);

	/* Configure WAVE_SAMPLE1 to WAVE_SAMPLE8 register */
	for (i = 0; i < QPNP_HAP_WAV_SAMP_LEN && hap->wf_update; i++) {
		reg = hap->wave_samp[i] = hap->shadow_wave_samp[i];
		rc = qpnp_hap_write_reg(hap, &reg,
			QPNP_HAP_WAV_S_REG_BASE(hap->base) + i);
		if (rc)
			goto unlock;
	}
	hap->wf_update = false;

unlock:
	mutex_unlock(&hap->wf_lock);

	return IRQ_HANDLED;
}
コード例 #15
0
ファイル: qpnp-haptic.c プロジェクト: auras76/aur-kernel-XZxx
/* configuration api for short circuit debounce */
static int qpnp_hap_sc_deb_config(struct qpnp_hap *hap)
{
	u8 reg = 0;
	int rc, temp;

	if (hap->sc_deb_cycles < QPNP_HAP_SC_DEB_CYCLES_MIN)
		hap->sc_deb_cycles = QPNP_HAP_SC_DEB_CYCLES_MIN;
	else if (hap->sc_deb_cycles > QPNP_HAP_SC_DEB_CYCLES_MAX)
		hap->sc_deb_cycles = QPNP_HAP_SC_DEB_CYCLES_MAX;

	rc = qpnp_hap_read_reg(hap, &reg, QPNP_HAP_SC_DEB_REG(hap->base));
	if (rc < 0)
		return rc;
	reg &= QPNP_HAP_SC_DEB_MASK;
	if (hap->sc_deb_cycles) {
		temp = fls(hap->sc_deb_cycles) - 1;
		reg |= temp - QPNP_HAP_SC_DEB_SUB;
	}
	rc = qpnp_hap_write_reg(hap, &reg, QPNP_HAP_SC_DEB_REG(hap->base));
	if (rc)
		return rc;

	return 0;
}
コード例 #16
0
ファイル: qpnp-haptic.c プロジェクト: auras76/aur-kernel-XZxx
/* Configuration api for haptics registers */
static int qpnp_hap_config(struct qpnp_hap *hap)
{
	u8 reg = 0;
	int rc, i, temp;

	/* Configure the ACTUATOR TYPE register */
	rc = qpnp_hap_read_reg(hap, &reg, QPNP_HAP_ACT_TYPE_REG(hap->base));
	if (rc < 0)
		return rc;
	reg &= QPNP_HAP_ACT_TYPE_MASK;
	reg |= hap->act_type;
	rc = qpnp_hap_write_reg(hap, &reg, QPNP_HAP_ACT_TYPE_REG(hap->base));
	if (rc)
		return rc;

	/* Configure auto resonance parameters */
	if (hap->act_type == QPNP_HAP_LRA) {
		if (hap->lra_res_cal_period < QPNP_HAP_RES_CAL_PERIOD_MIN)
			hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MIN;
		else if (hap->lra_res_cal_period > QPNP_HAP_RES_CAL_PERIOD_MAX)
			hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MAX;

		rc = qpnp_hap_read_reg(hap, &reg,
					QPNP_HAP_LRA_AUTO_RES_REG(hap->base));
		if (rc < 0)
			return rc;
		reg &= QPNP_HAP_AUTO_RES_MODE_MASK;
		reg |= (hap->auto_res_mode << QPNP_HAP_AUTO_RES_MODE_SHIFT);
		reg &= QPNP_HAP_LRA_HIGH_Z_MASK;
		reg |= (hap->lra_high_z << QPNP_HAP_LRA_HIGH_Z_SHIFT);
		reg &= QPNP_HAP_LRA_RES_CAL_PER_MASK;
		temp = fls(hap->lra_res_cal_period) - 1;
		reg |= (temp - 2);
		rc = qpnp_hap_write_reg(hap, &reg,
					QPNP_HAP_LRA_AUTO_RES_REG(hap->base));
		if (rc)
			return rc;
	} else {
		/* disable auto resonance for ERM */
		reg = 0x00;

		rc = qpnp_hap_write_reg(hap, &reg,
					QPNP_HAP_LRA_AUTO_RES_REG(hap->base));
		if (rc)
			return rc;
	}

	/* Configure the PLAY MODE register */
	rc = qpnp_hap_play_mode_config(hap);
	if (rc)
		return rc;

	/* Configure the VMAX register */
	rc = qpnp_hap_vmax_config(hap);
	if (rc)
		return rc;

	/* Configure the ILIM register */
	if (hap->ilim_ma < QPNP_HAP_ILIM_MIN_MA)
		hap->ilim_ma = QPNP_HAP_ILIM_MIN_MA;
	else if (hap->ilim_ma > QPNP_HAP_ILIM_MAX_MA)
		hap->ilim_ma = QPNP_HAP_ILIM_MAX_MA;

	rc = qpnp_hap_read_reg(hap, &reg, QPNP_HAP_ILIM_REG(hap->base));
	if (rc < 0)
		return rc;
	reg &= QPNP_HAP_ILIM_MASK;
	temp = (hap->ilim_ma / QPNP_HAP_ILIM_MIN_MA) >> 1;
	reg |= temp;
	rc = qpnp_hap_write_reg(hap, &reg, QPNP_HAP_ILIM_REG(hap->base));
	if (rc)
		return rc;

	/* Configure the short circuit debounce register */
	rc = qpnp_hap_sc_deb_config(hap);
	if (rc)
		return rc;

	/* Configure the INTERNAL_PWM register */
	if (hap->int_pwm_freq_khz <= QPNP_HAP_INT_PWM_FREQ_253_KHZ) {
		hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_253_KHZ;
		temp = 0;
	} else if (hap->int_pwm_freq_khz <= QPNP_HAP_INT_PWM_FREQ_505_KHZ) {
		hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_505_KHZ;
		temp = 1;
	} else if (hap->int_pwm_freq_khz <= QPNP_HAP_INT_PWM_FREQ_739_KHZ) {
		hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_739_KHZ;
		temp = 2;
	} else {
		hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_1076_KHZ;
		temp = 3;
	}

	rc = qpnp_hap_read_reg(hap, &reg, QPNP_HAP_INT_PWM_REG(hap->base));
	if (rc < 0)
		return rc;
	reg &= QPNP_HAP_INT_PWM_MASK;
	reg |= temp;
	rc = qpnp_hap_write_reg(hap, &reg, QPNP_HAP_INT_PWM_REG(hap->base));
	if (rc)
		return rc;

	rc = qpnp_hap_read_reg(hap, &reg, QPNP_HAP_PWM_CAP_REG(hap->base));
	if (rc < 0)
		return rc;
	reg &= QPNP_HAP_INT_PWM_MASK;
	reg |= temp;
	rc = qpnp_hap_write_reg(hap, &reg, QPNP_HAP_PWM_CAP_REG(hap->base));
	if (rc)
		return rc;

	/* Configure the WAVE SHAPE register */
	rc = qpnp_hap_read_reg(hap, &reg,
			QPNP_HAP_WAV_SHAPE_REG(hap->base));
	if (rc < 0)
		return rc;
	reg &= QPNP_HAP_WAV_SHAPE_MASK;
	reg |= hap->wave_shape;
	rc = qpnp_hap_write_reg(hap, &reg,
			QPNP_HAP_WAV_SHAPE_REG(hap->base));
	if (rc)
		return rc;

	/* Configure RATE_CFG1 and RATE_CFG2 registers */
	/* Note: For ERM these registers act as play rate and
	   for LRA these represent resonance period */
	if (hap->wave_play_rate_us < QPNP_HAP_WAV_PLAY_RATE_US_MIN)
		hap->wave_play_rate_us = QPNP_HAP_WAV_PLAY_RATE_US_MIN;
	else if (hap->wave_play_rate_us > QPNP_HAP_WAV_PLAY_RATE_US_MAX)
		hap->wave_play_rate_us = QPNP_HAP_WAV_PLAY_RATE_US_MAX;

	temp = hap->wave_play_rate_us / QPNP_HAP_RATE_CFG_STEP_US;
	reg = temp & QPNP_HAP_RATE_CFG1_MASK;
	rc = qpnp_hap_write_reg(hap, &reg,
			QPNP_HAP_RATE_CFG1_REG(hap->base));
	if (rc)
		return rc;

	rc = qpnp_hap_read_reg(hap, &reg,
			QPNP_HAP_RATE_CFG2_REG(hap->base));
	if (rc < 0)
		return rc;
	reg &= QPNP_HAP_RATE_CFG2_MASK;
	temp = temp >> QPNP_HAP_RATE_CFG2_SHFT;
	reg |= temp;
	rc = qpnp_hap_write_reg(hap, &reg,
			QPNP_HAP_RATE_CFG2_REG(hap->base));
	if (rc)
		return rc;

	/* Configure BRAKE register */
	rc = qpnp_hap_read_reg(hap, &reg, QPNP_HAP_EN_CTL2_REG(hap->base));
	if (rc < 0)
		return rc;
	reg &= QPNP_HAP_BRAKE_MASK;
	reg |= hap->en_brake;
	rc = qpnp_hap_write_reg(hap, &reg, QPNP_HAP_EN_CTL2_REG(hap->base));
	if (rc)
		return rc;

	if (hap->en_brake && hap->sup_brake_pat) {
		for (i = QPNP_HAP_BRAKE_PAT_LEN - 1, reg = 0; i >= 0; i--) {
			hap->brake_pat[i] &= QPNP_HAP_BRAKE_PAT_MASK;
			temp = i << 1;
			reg |= hap->brake_pat[i] << temp;
		}
		rc = qpnp_hap_write_reg(hap, &reg,
					QPNP_HAP_BRAKE_REG(hap->base));
		if (rc)
			return rc;
	}

	/* Cache enable control register */
	rc = qpnp_hap_read_reg(hap, &reg, QPNP_HAP_EN_CTL_REG(hap->base));
	if (rc < 0)
		return rc;
	hap->reg_en_ctl = reg;

	/* Cache play register */
	rc = qpnp_hap_read_reg(hap, &reg, QPNP_HAP_PLAY_REG(hap->base));
	if (rc < 0)
		return rc;
	hap->reg_play = reg;

	if (hap->play_mode == QPNP_HAP_BUFFER)
		rc = qpnp_hap_buffer_config(hap);
	else if (hap->play_mode == QPNP_HAP_PWM)
		rc = qpnp_hap_pwm_config(hap);
	else if (hap->play_mode == QPNP_HAP_AUDIO)
		rc = qpnp_hap_mod_enable(hap, true);

	if (rc)
		return rc;

	/* setup short circuit irq */
	if (hap->use_sc_irq) {
		rc = devm_request_threaded_irq(&hap->spmi->dev, hap->sc_irq,
			NULL, qpnp_hap_sc_irq,
			QPNP_IRQ_FLAGS,
			"qpnp_sc_irq", hap);
		if (rc < 0) {
			dev_err(&hap->spmi->dev,
				"Unable to request sc(%d) IRQ(err:%d)\n",
				hap->sc_irq, rc);
			return rc;
		}
	}

	return rc;
}