in touchscreen/cyttsp4_core.c [1077:1246]
static irqreturn_t cyttsp4_irq(int irq, void *handle)
{
struct cyttsp4 *cd = handle;
struct device *dev = cd->dev;
enum cyttsp4_mode cur_mode;
u8 cmd_ofs = cd->sysinfo.si_ofs.cmd_ofs;
u8 mode[3];
int rc;
/*
* Check whether this IRQ should be ignored (external)
* This should be the very first thing to check since
* ignore_irq may be set for a very short period of time
*/
if (atomic_read(&cd->ignore_irq)) {
dev_vdbg(dev, "%s: Ignoring IRQ\n", __func__);
return IRQ_HANDLED;
}
dev_dbg(dev, "%s int:0x%x\n", __func__, cd->int_status);
mutex_lock(&cd->system_lock);
/* Just to debug */
if (cd->sleep_state == SS_SLEEP_ON || cd->sleep_state == SS_SLEEPING)
dev_vdbg(dev, "%s: Received IRQ while in sleep\n", __func__);
rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), mode);
if (rc) {
dev_err(cd->dev, "%s: Fail read adapter r=%d\n", __func__, rc);
goto cyttsp4_irq_exit;
}
dev_vdbg(dev, "%s mode[0-2]:0x%X 0x%X 0x%X\n", __func__,
mode[0], mode[1], mode[2]);
if (IS_BOOTLOADER(mode[0], mode[1])) {
cur_mode = CY_MODE_BOOTLOADER;
dev_vdbg(dev, "%s: bl running\n", __func__);
if (cd->mode == CY_MODE_BOOTLOADER) {
/* Signal bootloader heartbeat heard */
wake_up(&cd->wait_q);
goto cyttsp4_irq_exit;
}
/* switch to bootloader */
dev_dbg(dev, "%s: restart switch to bl m=%d -> m=%d\n",
__func__, cd->mode, cur_mode);
/* catch operation->bl glitch */
if (cd->mode != CY_MODE_UNKNOWN) {
/* Incase startup_state do not let startup_() */
cd->mode = CY_MODE_UNKNOWN;
cyttsp4_queue_startup_(cd);
goto cyttsp4_irq_exit;
}
/*
* do not wake thread on this switch since
* it is possible to get an early heartbeat
* prior to performing the reset
*/
cd->mode = cur_mode;
goto cyttsp4_irq_exit;
}
switch (mode[0] & CY_HST_MODE) {
case CY_HST_OPERATE:
cur_mode = CY_MODE_OPERATIONAL;
dev_vdbg(dev, "%s: operational\n", __func__);
break;
case CY_HST_CAT:
cur_mode = CY_MODE_CAT;
dev_vdbg(dev, "%s: CaT\n", __func__);
break;
case CY_HST_SYSINFO:
cur_mode = CY_MODE_SYSINFO;
dev_vdbg(dev, "%s: sysinfo\n", __func__);
break;
default:
cur_mode = CY_MODE_UNKNOWN;
dev_err(dev, "%s: unknown HST mode 0x%02X\n", __func__,
mode[0]);
break;
}
/* Check whether this IRQ should be ignored (internal) */
if (cd->int_status & CY_INT_IGNORE) {
dev_vdbg(dev, "%s: Ignoring IRQ\n", __func__);
goto cyttsp4_irq_exit;
}
/* Check for wake up interrupt */
if (cd->int_status & CY_INT_AWAKE) {
cd->int_status &= ~CY_INT_AWAKE;
wake_up(&cd->wait_q);
dev_vdbg(dev, "%s: Received wake up interrupt\n", __func__);
goto cyttsp4_irq_handshake;
}
/* Expecting mode change interrupt */
if ((cd->int_status & CY_INT_MODE_CHANGE)
&& (mode[0] & CY_HST_MODE_CHANGE) == 0) {
cd->int_status &= ~CY_INT_MODE_CHANGE;
dev_dbg(dev, "%s: finish mode switch m=%d -> m=%d\n",
__func__, cd->mode, cur_mode);
cd->mode = cur_mode;
wake_up(&cd->wait_q);
goto cyttsp4_irq_handshake;
}
/* compare current core mode to current device mode */
dev_vdbg(dev, "%s: cd->mode=%d cur_mode=%d\n",
__func__, cd->mode, cur_mode);
if ((mode[0] & CY_HST_MODE_CHANGE) == 0 && cd->mode != cur_mode) {
/* Unexpected mode change occurred */
dev_err(dev, "%s %d->%d 0x%x\n", __func__, cd->mode,
cur_mode, cd->int_status);
dev_dbg(dev, "%s: Unexpected mode change, startup\n",
__func__);
cyttsp4_queue_startup_(cd);
goto cyttsp4_irq_exit;
}
/* Expecting command complete interrupt */
dev_vdbg(dev, "%s: command byte:0x%x\n", __func__, mode[cmd_ofs]);
if ((cd->int_status & CY_INT_EXEC_CMD)
&& mode[cmd_ofs] & CY_CMD_COMPLETE) {
cd->int_status &= ~CY_INT_EXEC_CMD;
dev_vdbg(dev, "%s: Received command complete interrupt\n",
__func__);
wake_up(&cd->wait_q);
/*
* It is possible to receive a single interrupt for
* command complete and touch/button status report.
* Continue processing for a possible status report.
*/
}
/* This should be status report, read status regs */
if (cd->mode == CY_MODE_OPERATIONAL) {
dev_vdbg(dev, "%s: Read status registers\n", __func__);
rc = cyttsp4_load_status_regs(cd);
if (rc < 0)
dev_err(dev, "%s: fail read mode regs r=%d\n",
__func__, rc);
}
cyttsp4_mt_attention(cd);
cyttsp4_irq_handshake:
/* handshake the event */
dev_vdbg(dev, "%s: Handshake mode=0x%02X r=%d\n",
__func__, mode[0], rc);
rc = cyttsp4_handshake(cd, mode[0]);
if (rc < 0)
dev_err(dev, "%s: Fail handshake mode=0x%02X r=%d\n",
__func__, mode[0], rc);
/*
* a non-zero udelay period is required for using
* IRQF_TRIGGER_LOW in order to delay until the
* device completes isr deassert
*/
udelay(cd->cpdata->level_irq_udelay);
cyttsp4_irq_exit:
mutex_unlock(&cd->system_lock);
return IRQ_HANDLED;
}