387 lines
8.9 KiB
C
387 lines
8.9 KiB
C
/*
|
|
* Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include "FreeRTOS.h"
|
|
#include "gpio.h"
|
|
#include "projdefs.h"
|
|
#include "portmacro.h"
|
|
#include "string.h"
|
|
|
|
#include <unistd.h>
|
|
#include "n200_func.h"
|
|
#include "common.h"
|
|
#include "ir.h"
|
|
#include "mailbox-api.h"
|
|
#include "stick_mem.h"
|
|
|
|
#include "ir_drv.h"
|
|
#include "drv_errno.h"
|
|
|
|
static struct IRPowerKey prvDefWakeupList[MAX_KEY_NUM];
|
|
static uint8_t ucDefWakeupNum;
|
|
static uint16_t usDefWorkMode;
|
|
|
|
#define ERR_IR(errno) (DRV_ERRNO_IR_BASE | errno)
|
|
#define IR_PRT_ENABLE 0
|
|
|
|
static uint8_t ucIsDebugEnable;
|
|
#define IRDebug(fmt, x...) \
|
|
do { \
|
|
if (ucIsDebugEnable) \
|
|
printf("%s " fmt, DRIVE_NAME, ##x); \
|
|
} while (0)
|
|
|
|
#if (IR_PRT_ENABLE)
|
|
#define IRError(fmt, x...) printf("%s " fmt, DRIVE_NAME, ##x)
|
|
#else
|
|
#define IRError(fmt, x...)
|
|
#endif
|
|
|
|
static inline void prvIRRegWrite(uint8_t ucCTL, uint8_t ucAddr, uint32_t ulval)
|
|
{
|
|
uint32_t ulRegBase = 0;
|
|
|
|
if (!IR_BASE_ADDR || !IR_BASE_ADDR_OLD) {
|
|
IRError("IR_BASE_ADDR not found!\n");
|
|
return;
|
|
}
|
|
|
|
ulRegBase = IS_LEGACY_CTRL(ucCTL);
|
|
|
|
REG32((unsigned long)(ulRegBase + ucAddr)) = ulval;
|
|
}
|
|
|
|
static inline uint32_t prvIRRegRead(uint8_t ucCTL, uint8_t ucAddr)
|
|
{
|
|
uint32_t ulRegBase = 0;
|
|
|
|
if (!IR_BASE_ADDR || !IR_BASE_ADDR_OLD) {
|
|
IRError("IR_BASE_ADDR not found!\n");
|
|
return ERR_IR(DRV_ERROR_PARAMETER);
|
|
}
|
|
|
|
ulRegBase = IS_LEGACY_CTRL(ucCTL);
|
|
|
|
return REG32(ulRegBase + ucAddr);
|
|
}
|
|
|
|
static inline void prvIRRegUpdateBit(uint8_t ucCTL, uint8_t ucAddr, uint32_t ulMask, uint32_t ulVal)
|
|
{
|
|
uint32_t ulRegBase = 0;
|
|
|
|
if (!IR_BASE_ADDR || !IR_BASE_ADDR_OLD) {
|
|
IRError("IR_BASE_ADDR not found!\n");
|
|
return;
|
|
}
|
|
|
|
ulRegBase = IS_LEGACY_CTRL(ucCTL);
|
|
|
|
REG32_UPDATE_BITS(ulRegBase + ucAddr, ulMask, ulVal);
|
|
}
|
|
|
|
static void vSetIRWorkMode(uint16_t usWorkMode, uint8_t ucWorkCTL)
|
|
{
|
|
uint8_t ucRegSize = 0;
|
|
uint8_t i = 0;
|
|
uint32_t ulValue = 0;
|
|
const struct xRegProtocolMethod **xProData;
|
|
|
|
xProData = pGetSupportProtocol();
|
|
|
|
for (; (*xProData) != NULL;) {
|
|
if ((*xProData)->ucProtocol == usWorkMode)
|
|
break;
|
|
xProData++;
|
|
}
|
|
|
|
if (!*xProData) {
|
|
IRError("Not support this type Protocol!\n");
|
|
return;
|
|
}
|
|
|
|
/*clear status and disable ir decoder */
|
|
prvIRRegRead(ucWorkCTL, REG_FRAME);
|
|
prvIRRegWrite(ucWorkCTL, REG_REG1, 0x01);
|
|
|
|
ucRegSize = (*xProData)->ucRegNum;
|
|
|
|
for (; i < ucRegSize; i++)
|
|
prvIRRegWrite(ucWorkCTL, (*xProData)->RegList[i].ucReg,
|
|
(*xProData)->RegList[i].ulVal);
|
|
|
|
/*reset IR decoder when reinstall */
|
|
ulValue = prvIRRegRead(ucWorkCTL, REG_REG1);
|
|
ulValue |= 1;
|
|
prvIRRegWrite(ucWorkCTL, REG_REG1, ulValue);
|
|
ulValue &= ~0x01;
|
|
prvIRRegWrite(ucWorkCTL, REG_REG1, ulValue);
|
|
}
|
|
|
|
void vInitIRWorkMode(uint16_t usWorkMode)
|
|
{
|
|
if (ENABLE_LEGACY_CTL(usWorkMode))
|
|
vSetIRWorkMode(LEGACY_IR_CTL_MASK(usWorkMode), LEGACY_CTL);
|
|
else
|
|
prvIRRegWrite(LEGACY_CTL, REG_REG1, 0);
|
|
|
|
IRDebug("mode: 0x%x\n", usWorkMode);
|
|
if (MULTI_IR_CTL_MASK(usWorkMode))
|
|
vSetIRWorkMode(MULTI_IR_CTL_MASK(usWorkMode), MULTI_CTL);
|
|
}
|
|
|
|
static int8_t prvCheckPowerKey(struct IRPowerKey *list, uint8_t num)
|
|
{
|
|
struct xIRDrvData *xDrvData;
|
|
struct IRPowerKey *ulPowerKeyList = list;
|
|
uint8_t ucIndex = 0;
|
|
|
|
xDrvData = pGetIRDrvData();
|
|
if (!xDrvData->ulFrameCode || !num)
|
|
return 1;
|
|
|
|
/* search power key list */
|
|
for (; ucIndex < num; ucIndex++) {
|
|
IRDebug("chk: 0x%x\n", ulPowerKeyList[ucIndex].code);
|
|
if (ulPowerKeyList[ucIndex].code == xDrvData->ulFrameCode) {
|
|
xDrvData->ulLastPowerKey = xDrvData->ulFrameCode;
|
|
#ifndef CONFIG_STICK_MEM
|
|
xDrvData->ulLastWakeupKey = xDrvData->ulFrameCode;
|
|
#endif
|
|
printf("[ir] key:0x%x\n", xDrvData->ulFrameCode);
|
|
if (xDrvData->vIRHandler) {
|
|
xDrvData->vIRHandler(&ulPowerKeyList[ucIndex]);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void vIRIntteruptHandler(void)
|
|
{
|
|
uint32_t ulDecodeStatus = 0;
|
|
uint8_t ucIndex = 0;
|
|
uint16_t ucCurWorkMode;
|
|
struct xIRDrvData *xDrvData;
|
|
|
|
xDrvData = pGetIRDrvData();
|
|
ucCurWorkMode = xDrvData->ucCurWorkMode;
|
|
|
|
/*choose controller */
|
|
for (; ucIndex < (ENABLE_LEGACY_CTL(ucCurWorkMode) ? 2 : 1); ucIndex++) {
|
|
ulDecodeStatus = prvIRRegRead(ucIndex, REG_STATUS);
|
|
if (ulDecodeStatus & 0x08) {
|
|
xDrvData->ucWorkCTL = ucIndex;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ucIndex == ERROR_CTL) {
|
|
IRError("error interrupt !\n");
|
|
return;
|
|
}
|
|
|
|
ulDecodeStatus = prvIRRegRead(xDrvData->ucWorkCTL, REG_STATUS);
|
|
|
|
xDrvData->ucIRStatus = STATUS_NORMAL;
|
|
if (ulDecodeStatus & 0x01)
|
|
xDrvData->ucIRStatus = STATUS_REPEAT;
|
|
|
|
xDrvData->ulFrameCode = prvIRRegRead(xDrvData->ucWorkCTL, REG_FRAME);
|
|
IRDebug("rec: 0x%x\n", xDrvData->ulFrameCode);
|
|
|
|
if (prvCheckPowerKey(prvDefWakeupList, ucDefWakeupNum))
|
|
prvCheckPowerKey(xDrvData->ulPowerKeyList,
|
|
xDrvData->ucPowerKeyNum);
|
|
}
|
|
|
|
int8_t ucIsIRInit(void)
|
|
{
|
|
struct xIRDrvData *xDrvData;
|
|
|
|
xDrvData = pGetIRDrvData();
|
|
return xDrvData->ucIsInit;
|
|
}
|
|
|
|
uint32_t vIRInit(uint16_t usWorkMode, uint16_t usGpio, enum PinMuxType func,
|
|
struct IRPowerKey *ulPowerKeyList, uint8_t ucPowerKeyNum,
|
|
void (*vIRHandler)(struct IRPowerKey *pkey))
|
|
{
|
|
struct xIRDrvData *xDrvData;
|
|
|
|
if (ucIsIRInit()) {
|
|
IRError("all ready init\n");
|
|
return ERR_IR(DRV_ERROR_BUSY);
|
|
}
|
|
|
|
if (!IR_INTERRUPT_NUM || !IRQ_NUM_IRIN) {
|
|
IRError("ir irq number not found, ir init failed\n");
|
|
return ERR_IR(DRV_ERROR_IRQ);
|
|
}
|
|
|
|
if (!ucDefWakeupNum &&
|
|
(ulPowerKeyList == NULL || !ucPowerKeyNum)) {
|
|
IRError("not set power key list, ir init failed\n");
|
|
return ERR_IR(DRV_ERROR_SIZE);
|
|
}
|
|
|
|
xPinmuxSet(usGpio, func);
|
|
|
|
xDrvData = pGetIRDrvData();
|
|
xDrvData->ulPowerKeyList = ulPowerKeyList;
|
|
xDrvData->ucPowerKeyNum = ucPowerKeyNum;
|
|
|
|
if (usDefWorkMode)
|
|
xDrvData->ucCurWorkMode = usDefWorkMode;
|
|
else
|
|
xDrvData->ucCurWorkMode = usWorkMode;
|
|
xDrvData->vIRHandler = vIRHandler;
|
|
xDrvData->ulLastPowerKey = 0;
|
|
vInitIRWorkMode(xDrvData->ucCurWorkMode);
|
|
|
|
RegisterIrq(IRQ_NUM_IRIN, 2, vIRIntteruptHandler);
|
|
EnableIrq(IRQ_NUM_IRIN);
|
|
#if defined(IRQ_NUM_IRIN_EXT)
|
|
RegisterIrq(IRQ_NUM_IRIN_EXT, 2, vIRIntteruptHandler);
|
|
EnableIrq(IRQ_NUM_IRIN_EXT);
|
|
#endif
|
|
|
|
xDrvData->ucIsInit = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void vIRDeint(void)
|
|
{
|
|
struct xIRDrvData *xDrvData;
|
|
|
|
if (!ucIsIRInit())
|
|
return;
|
|
|
|
xDrvData = pGetIRDrvData();
|
|
|
|
xDrvData->ucIsInit = 0;
|
|
xDrvData->vIRHandler = NULL;
|
|
|
|
DisableIrq(IRQ_NUM_IRIN);
|
|
UnRegisterIrq(IRQ_NUM_IRIN);
|
|
#if defined(IRQ_NUM_IRIN_EXT)
|
|
DisableIrq(IRQ_NUM_IRIN_EXT);
|
|
UnRegisterIrq(IRQ_NUM_IRIN_EXT);
|
|
#endif
|
|
}
|
|
|
|
static int8_t prvIRCheckPowerKeyExist(uint32_t framecode)
|
|
{
|
|
uint8_t ucIndex;
|
|
struct xIRDrvData *xDrvData = pGetIRDrvData();
|
|
|
|
for (ucIndex = 0; ucIndex < ucDefWakeupNum; ucIndex++)
|
|
if (prvDefWakeupList[ucIndex].code == framecode)
|
|
return 1;
|
|
|
|
for (ucIndex = 0; ucIndex < xDrvData->ucPowerKeyNum; ucIndex++)
|
|
if (xDrvData->ulPowerKeyList[ucIndex].code == framecode)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void *prvIRGetInfo(void *msg)
|
|
{
|
|
uint8_t i, j;
|
|
//uint16_t gpio = 0, pinmux = PIN_FUNC_INVALID;
|
|
uint32_t cmd = *(uint32_t *)msg;
|
|
uint32_t *data = (uint32_t *)msg + 1;
|
|
struct xIRDrvData *xDrvData = pGetIRDrvData();
|
|
|
|
switch (cmd) {
|
|
case IR_MBOX_CMD_SET_DEBUG_LOG:
|
|
ucIsDebugEnable = data[0];
|
|
break;
|
|
case IR_MBOX_CMD_SET_WAKEUP_LIST:
|
|
for (i = ucDefWakeupNum, j = 0;
|
|
j < data[0] && i < MAX_KEY_NUM; j++) {
|
|
if (!prvIRCheckPowerKeyExist(data[j + 2])) {
|
|
prvDefWakeupList[i].type = (data[1] >> j) & 0x1;
|
|
prvDefWakeupList[i].code = data[j + 2];
|
|
i++;
|
|
}
|
|
}
|
|
ucDefWakeupNum = i;
|
|
break;
|
|
case IR_MBOX_CMD_GET_WAKEUP_KEY:
|
|
memset(msg, 0, MBOX_BUF_LEN);
|
|
#ifdef CONFIG_STICK_MEM
|
|
stick_mem_read(STICK_IR_WAKEUP_KEY, msg);
|
|
stick_mem_write(STICK_IR_WAKEUP_KEY, 0);
|
|
#else
|
|
*(uint32_t *)msg = xDrvData->ulLastWakeupKey;
|
|
xDrvData->ulLastWakeupKey = 0;
|
|
#endif
|
|
break;
|
|
case IR_MBOX_CMD_SET_STATUS:
|
|
//if (data[2]) {
|
|
// gpio = data[2];
|
|
// pinmux = data[3];
|
|
//}
|
|
if (data[0] == 1)
|
|
vIRInit(MODE_HARD_NEC, 0, PIN_FUNC_INVALID, NULL, 0,
|
|
NULL);
|
|
//vIRInit(MODE_HARD_NEC, gpio, pinmux, NULL, 0, NULL);
|
|
else if (data[0] == 0)
|
|
vIRDeint();
|
|
else if (data[0] == 2)
|
|
usDefWorkMode = data[1];
|
|
break;
|
|
case IR_MBOX_CMD_GET_PREBOOT_KEY:
|
|
memset(msg, 0, MBOX_BUF_LEN);
|
|
*(uint32_t *)msg = xDrvData->ulLastPowerKey;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
uint32_t vIRMailboxEnable(void)
|
|
{
|
|
int32_t ret;
|
|
|
|
ret = xInstallRemoteMessageCallbackFeedBack(REE2AO_CHANNEL, MBX_CMD_GET_IR_INFO,
|
|
prvIRGetInfo, 1);
|
|
if (ret == MBOX_CALL_MAX) {
|
|
return ERR_IR(DRV_ERROR_UNSUPPORTED);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void vIR32KInit(uint32_t ulFrame0, uint32_t ulFrame1)
|
|
{
|
|
#ifdef RTCCTRL_REG_CTRL9
|
|
REG32(RTCCTRL_REG_CTRL3) = ulFrame0;
|
|
REG32(RTCCTRL_REG_CTRL4) = ulFrame1;
|
|
|
|
if (ulFrame0)
|
|
REG32(RTCCTRL_REG_CTRL5) = 0xffffffff;
|
|
else
|
|
REG32(RTCCTRL_REG_CTRL5) = 0x00;
|
|
|
|
if (ulFrame1)
|
|
REG32(RTCCTRL_REG_CTRL6) = 0xffffffff;
|
|
else
|
|
REG32(RTCCTRL_REG_CTRL6) = 0x0;
|
|
|
|
REG32(RTCCTRL_REG_CTRL9) = (1 << 12);
|
|
REG32(RTCCTRL_REG_CTRL9) = (1 << 4);
|
|
#else
|
|
(void)ulFrame0;
|
|
(void)ulFrame1;
|
|
#endif
|
|
}
|