Files
2026-08-24 10:03:24 +08:00

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
}