blob: e43e7c1a6075395bf3911af0dbce8ee5a57ac523 [file] [log] [blame]
/*
* drivers/amlogic/atv_demod/atv_demod_isr.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include "atv_demod_isr.h"
#include "atvdemod_func.h"
#include "atv_demod_access.h"
#include "atv_demod_debug.h"
static DEFINE_MUTEX(isr_mutex);
bool atvdemod_isr_en;
static void atv_demod_reset_irq(void)
{
atv_dmd_wr_long(APB_BLOCK_ADDR_INTERPT_MGT, 0x10, 0x3);
atv_dmd_wr_long(APB_BLOCK_ADDR_INTERPT_MGT, 0x10, 0x0);
}
static void atv_demod_set_irq(bool enable)
{
if (enable)
atv_dmd_wr_long(APB_BLOCK_ADDR_INTERPT_MGT, 0x14, 0x0);
else
atv_dmd_wr_long(APB_BLOCK_ADDR_INTERPT_MGT, 0x14, 0xf);
}
static int atv_demod_get_irq_status(void)
{
return atv_dmd_rd_long(APB_BLOCK_ADDR_INTERPT_MGT, 0x18);
}
static irqreturn_t atv_demod_isr_handler(int irq, void *dev)
{
int status = atv_demod_get_irq_status();
pr_isr("irq status: 0x%x.\n", status);
pr_isr("line_unlock: %s.\n",
(status & 0x80) ? "unlocked" : "locked");
pr_isr("line_strong_unlock: %s.\n",
(status & 0x40) ? "unlocked" : "locked");
pr_isr("field_unlock: %s.\n",
(status & 0x20) ? "unlocked" : "locked");
pr_isr("pll_unlock: %s.\n",
(status & 0x10) ? "unlocked" : "locked");
pr_isr("line_lock: %s.\n",
(status & 0x08) ? "locked" : "unlocked");
pr_isr("line_strong_lock: %s.\n",
(status & 0x04) ? "locked" : "unlocked");
pr_isr("field_lock: %s.\n",
(status & 0x02) ? "locked" : "unlocked");
pr_isr("pll_lock: %s.\n\n",
(status & 0x01) ? "locked" : "unlocked");
atv_demod_reset_irq();
return IRQ_HANDLED;
}
static void atv_demod_isr_disable(struct atv_demod_isr *isr)
{
mutex_lock(&isr->mtx);
if (atvdemod_isr_en && isr->init && isr->state == true) {
atv_demod_set_irq(false);
disable_irq(isr->irq);
isr->state = false;
}
mutex_unlock(&isr->mtx);
pr_isr("%s: state: %d.\n", __func__, isr->state);
}
static void atv_demod_isr_enable(struct atv_demod_isr *isr)
{
mutex_lock(&isr->mtx);
if (atvdemod_isr_en && isr->init && isr->state == false) {
atv_demod_reset_irq();
atv_demod_set_irq(true);
enable_irq(isr->irq);
isr->state = true;
}
mutex_unlock(&isr->mtx);
pr_isr("%s: state: %d.\n", __func__, isr->state);
}
void atv_demod_isr_init(struct atv_demod_isr *isr)
{
int ret = 0;
mutex_lock(&isr_mutex);
mutex_init(&isr->mtx);
isr->state = false;
isr->disable = atv_demod_isr_disable;
isr->enable = atv_demod_isr_enable;
isr->handler = atv_demod_isr_handler;
ret = request_irq(isr->irq, isr->handler, IRQF_SHARED,
"atv_demod_irq", (void *) isr);
if (ret != 0) {
isr->init = false;
pr_err("atv_demod_isr request irq error: %d.\n", ret);
} else {
isr->init = true;
disable_irq_nosync(isr->irq);
}
mutex_unlock(&isr_mutex);
}
void atv_demod_isr_uninit(struct atv_demod_isr *isr)
{
mutex_lock(&isr_mutex);
if (isr->init) {
free_irq(isr->irq, (void *) isr);
isr->init = false;
isr->state = false;
}
mutex_unlock(&isr_mutex);
}