Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a1c44fd5 authored by Abinaya P's avatar Abinaya P Committed by Mohan Pallaka
Browse files

msm: qpnp-haptic: disable haptics during permanent short circuit



sc_irq is fired when short circuit happens. It is considered to be
a permanent short circut when it lasts more than 5 secs. Hence,
if the sc_irq is fired continuously for more than 5 secs, then
disable the haptics driver permanently.

Change-Id: I38b2de58acb75755dd4a024cfbf626f886f4d91e
Signed-off-by: default avatarAbinaya P <abinayap@codeaurora.org>
parent 1e05de9d
Loading
Loading
Loading
Loading
+58 −7
Original line number Original line Diff line number Diff line
@@ -47,6 +47,7 @@
#define QPNP_HAP_EXT_PWM_REG(b)		(b + 0x57)
#define QPNP_HAP_EXT_PWM_REG(b)		(b + 0x57)
#define QPNP_HAP_PWM_CAP_REG(b)		(b + 0x58)
#define QPNP_HAP_PWM_CAP_REG(b)		(b + 0x58)
#define QPNP_HAP_SC_CLR_REG(b)		(b + 0x59)
#define QPNP_HAP_SC_CLR_REG(b)		(b + 0x59)
#define QPNP_HAP_SC_IRQ_STATUS_DELAY   msecs_to_jiffies(1000)
#define QPNP_HAP_BRAKE_REG(b)		(b + 0x5C)
#define QPNP_HAP_BRAKE_REG(b)		(b + 0x5C)
#define QPNP_HAP_WAV_REP_REG(b)		(b + 0x5E)
#define QPNP_HAP_WAV_REP_REG(b)		(b + 0x5E)
#define QPNP_HAP_WAV_S_REG_BASE(b)	(b + 0x60)
#define QPNP_HAP_WAV_S_REG_BASE(b)	(b + 0x60)
@@ -128,6 +129,8 @@
#define AUTO_RES_ENABLE			0x80
#define AUTO_RES_ENABLE			0x80
#define AUTO_RES_DISABLE		0x00
#define AUTO_RES_DISABLE		0x00
#define AUTO_RES_ERR_BIT		0x10
#define AUTO_RES_ERR_BIT		0x10
#define SC_FOUND_BIT			0x08
#define SC_MAX_DURATION			5


#define QPNP_HAP_TIMEOUT_MS_MAX		15000
#define QPNP_HAP_TIMEOUT_MS_MAX		15000
#define QPNP_HAP_STR_SIZE		20
#define QPNP_HAP_STR_SIZE		20
@@ -236,6 +239,7 @@ struct qpnp_pwm_info {
 *  @ timed_dev - timed output device
 *  @ timed_dev - timed output device
 *  @ work - worker
 *  @ work - worker
 *  @ auto_res_err_work - correct auto resonance error
 *  @ auto_res_err_work - correct auto resonance error
 *  @ sc_work - worker to handle short circuit condition
 *  @ pwm_info - pwm info
 *  @ pwm_info - pwm info
 *  @ lock - mutex lock
 *  @ lock - mutex lock
 *  @ wf_lock - mutex lock for waveform
 *  @ wf_lock - mutex lock for waveform
@@ -262,6 +266,7 @@ struct qpnp_pwm_info {
 *  @ reg_en_ctl - enable control register
 *  @ reg_en_ctl - enable control register
 *  @ reg_play - play register
 *  @ reg_play - play register
 *  @ lra_res_cal_period - period for resonance calibration
 *  @ lra_res_cal_period - period for resonance calibration
 *  @ sc_duration - counter to determine the duration of short circuit condition
 *  @ state - current state of haptics
 *  @ state - current state of haptics
 *  @ use_play_irq - play irq usage state
 *  @ use_play_irq - play irq usage state
 *  @ use_sc_irq - short circuit irq usage state
 *  @ use_sc_irq - short circuit irq usage state
@@ -280,6 +285,7 @@ struct qpnp_hap {
	struct timed_output_dev timed_dev;
	struct timed_output_dev timed_dev;
	struct work_struct work;
	struct work_struct work;
	struct work_struct auto_res_err_work;
	struct work_struct auto_res_err_work;
	struct delayed_work sc_work;
	struct hrtimer hap_test_timer;
	struct hrtimer hap_test_timer;
	struct work_struct test_work;
	struct work_struct test_work;
	struct qpnp_pwm_info pwm_info;
	struct qpnp_pwm_info pwm_info;
@@ -309,6 +315,7 @@ struct qpnp_hap {
	u8 reg_en_ctl;
	u8 reg_en_ctl;
	u8 reg_play;
	u8 reg_play;
	u8 lra_res_cal_period;
	u8 lra_res_cal_period;
	u8 sc_duration;
	u8 ext_pwm_dtest_line;
	u8 ext_pwm_dtest_line;
	bool state;
	bool state;
	bool use_play_irq;
	bool use_play_irq;
@@ -367,6 +374,21 @@ static int qpnp_hap_sec_access(struct qpnp_hap *hap)
	return 0;
	return 0;
}
}


static void qpnp_handle_sc_irq(struct work_struct *work)
{
	struct qpnp_hap *hap = container_of(work,
				struct qpnp_hap, sc_work.work);
	u8 val, reg;

	qpnp_hap_read_reg(hap, &val, QPNP_HAP_STATUS(hap->base));

	/* clear short circuit register */
	if (val & SC_FOUND_BIT) {
		hap->sc_duration++;
		reg = QPNP_HAP_SC_CLR;
		qpnp_hap_write_reg(hap, &reg, QPNP_HAP_SC_CLR_REG(hap->base));
	}
}


static int qpnp_hap_mod_enable(struct qpnp_hap *hap, int on)
static int qpnp_hap_mod_enable(struct qpnp_hap *hap, int on)
{
{
@@ -488,12 +510,28 @@ unlock:
static irqreturn_t qpnp_hap_sc_irq(int irq, void *_hap)
static irqreturn_t qpnp_hap_sc_irq(int irq, void *_hap)
{
{
	struct qpnp_hap *hap = _hap;
	struct qpnp_hap *hap = _hap;
	u8 reg;
	int rc;
	u8 disable_haptics = 0x00;
	u8 val;


	/* clear short circuit register */
	dev_dbg(&hap->spmi->dev, "Short circuit detected\n");
	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));
	if (hap->sc_duration < SC_MAX_DURATION) {
		qpnp_hap_read_reg(hap, &val, QPNP_HAP_STATUS(hap->base));
		if (val & SC_FOUND_BIT)
			schedule_delayed_work(&hap->sc_work,
					QPNP_HAP_SC_IRQ_STATUS_DELAY);
		else
			hap->sc_duration = 0;
	} else {
		/* Disable haptics module if the duration of short circuit
		 * exceeds the maximum limit (5 secs).
		 */
		rc = qpnp_hap_write_reg(hap, &disable_haptics,
					QPNP_HAP_EN_CTL_REG(hap->base));
		dev_err(&hap->spmi->dev,
			"Haptics disabled permanently due to short circuit\n");
	}


	return IRQ_HANDLED;
	return IRQ_HANDLED;
}
}
@@ -1587,11 +1625,21 @@ static void qpnp_hap_worker(struct work_struct *work)
{
{
	struct qpnp_hap *hap = container_of(work, struct qpnp_hap,
	struct qpnp_hap *hap = container_of(work, struct qpnp_hap,
					 work);
					 work);
	u8 val = 0x00;
	int rc;


	/* Disable haptics module if the duration of short circuit
	 * exceeds the maximum limit (5 secs).
	 */
	if (hap->sc_duration == SC_MAX_DURATION) {
		rc = qpnp_hap_write_reg(hap, &val,
				QPNP_HAP_EN_CTL_REG(hap->base));
	} else {
		if (hap->play_mode == QPNP_HAP_PWM)
		if (hap->play_mode == QPNP_HAP_PWM)
			qpnp_hap_mod_enable(hap, hap->state);
			qpnp_hap_mod_enable(hap, hap->state);
		qpnp_hap_set(hap, hap->state);
		qpnp_hap_set(hap, hap->state);
	}
	}
}


/* get time api to know the remaining time */
/* get time api to know the remaining time */
static int qpnp_hap_get_time(struct timed_output_dev *dev)
static int qpnp_hap_get_time(struct timed_output_dev *dev)
@@ -1886,6 +1934,8 @@ static int qpnp_hap_config(struct qpnp_hap *hap)
		}
		}
	}
	}


	hap->sc_duration = 0;

	return rc;
	return rc;
}
}


@@ -2143,6 +2193,7 @@ static int qpnp_haptic_probe(struct spmi_device *spmi)
	mutex_init(&hap->lock);
	mutex_init(&hap->lock);
	mutex_init(&hap->wf_lock);
	mutex_init(&hap->wf_lock);
	INIT_WORK(&hap->work, qpnp_hap_worker);
	INIT_WORK(&hap->work, qpnp_hap_worker);
	INIT_DELAYED_WORK(&hap->sc_work, qpnp_handle_sc_irq);
	init_completion(&hap->completion);
	init_completion(&hap->completion);


	hrtimer_init(&hap->hap_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	hrtimer_init(&hap->hap_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);