// SPDX-License-Identifier: GPL-2.0 /* * Sysfs APIs for Google Pixel devices. * * Copyright 2022 Google LLC. */ #include "touch_mf_mode.h" /* Update a state machine used to toggle control of the touch IC's motion * filter. */ int touch_mf_update_state(struct touch_mf *tmf, u8 touches) { /* Motion filter timeout, in milliseconds */ const u32 mf_timeout_ms = 500; u8 next_state = TOUCH_MF_STATE_UNFILTERED; mutex_lock(&tmf->update_mutex); tmf->touches = touches; if (tmf->mode == TOUCH_MF_MODE_UNFILTERED) { next_state = TOUCH_MF_STATE_UNFILTERED; } else if (tmf->mode == TOUCH_MF_MODE_DYNAMIC) { /* Determine the next filter state. The motion filter is enabled * by default and it is disabled while a single finger is * touching the screen. If another finger is touched down or if * a timeout expires, the motion filter is reenabled and remains * enabled until all fingers are lifted. */ next_state = tmf->state; switch (tmf->state) { case TOUCH_MF_STATE_FILTERED: if (touches == 1) { next_state = TOUCH_MF_STATE_UNFILTERED; tmf->downtime = ktime_get(); } break; case TOUCH_MF_STATE_UNFILTERED: if (touches == 0) { next_state = TOUCH_MF_STATE_FILTERED; } else if (touches > 1 || ktime_after(ktime_get(), ktime_add_ms(tmf->downtime, mf_timeout_ms))) { next_state = TOUCH_MF_STATE_LOCKED; } break; case TOUCH_MF_STATE_LOCKED: if (touches == 0) { next_state = TOUCH_MF_STATE_FILTERED; } break; } } else if (tmf->mode == TOUCH_MF_MODE_FILTERED) { next_state = TOUCH_MF_STATE_FILTERED; } else if (tmf->mode == TOUCH_MF_MODE_AUTO_REPORT) { next_state = TOUCH_MF_STATE_UNFILTERED; } /* Update continuously report switch if needed */ if ((next_state == TOUCH_MF_STATE_UNFILTERED) != (tmf->state == TOUCH_MF_STATE_UNFILTERED)) { if (tmf->set_continuously_report_enabled != NULL) { tmf->set_continuously_report_enabled(&tmf->pdev->dev, next_state == TOUCH_MF_STATE_UNFILTERED); } } tmf->state = next_state; mutex_unlock(&tmf->update_mutex); return 0; } int touch_mf_set_mode(struct touch_mf *tmf, enum touch_mf_mode mode) { int ret = 0; if ((mode < TOUCH_MF_MODE_UNFILTERED) || (mode > TOUCH_MF_MODE_AUTO_REPORT)) { ret = -EINVAL; } else { tmf->mode = mode; touch_mf_update_state(tmf, tmf->touches); } return ret; } int touch_mf_init(struct touch_mf *tmf) { /* init motion filter mode */ tmf->mode = TOUCH_MF_MODE_DYNAMIC; tmf->touches = 0; mutex_init(&tmf->update_mutex); return 0; }