Files

131 lines
3.7 KiB
C

/*
* Copyright (c) 2021-2026 Amlogic, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*/
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include "pdd.h"
#include "n200_func.h"
#include "common.h"
#define DRV_NAME_PREFIX "PDD: "
#define PDD_CLK_DIV_MASK GENMASK(7, 0)
#define PDD_CLK_DIV_SHIFT (0)
#define PDD_CLK_GATE BIT(8)
#define PDD_CLK_MUX_MASK GENMASK(10, 9)
#define FLT_TICK_BIT_WIDTH 2
#define FLT_CNT_BIT_WIDTH 3
#define FLT_TICK_MASK(OFFSET) ((BIT(FLT_TICK_BIT_WIDTH) - 1) << (OFFSET))
#define FLT_CNT_MASK(OFFSET) ((BIT(FLT_CNT_BIT_WIDTH) - 1) << (OFFSET))
#define DET_TRIM_BIT_WIDTH 6
#define DET_CTRL_BIT_WIDTH 2
#define DET_TRIM_MASK(OFFSET) ((BIT(DET_TRIM_BIT_WIDTH) - 1) << (OFFSET))
#define DET_CTRL_MASK(OFFSET) ((BIT(DET_CTRL_BIT_WIDTH) - 1) << (OFFSET))
static uint32_t PddRegBackup[7];
static void (*handler)(void);
static void prvPddIrqHandler(void)
{
if (REG32(PDD_REG_BASE + PDD_IRQ_OUT_REG_OFFS) & BIT(PDD_IRQ_OUT_BIT_OFFS))
handler();
/* Clear PDD IRQ */
REG32_UPDATE_BITS(PDD_REG_BASE + PDD_IRQ_CLR_REG_OFFS,
BIT(PDD_IRQ_CLR_BIT_OFFS),
BIT(PDD_IRQ_CLR_BIT_OFFS));
}
void vPddInit(enum PddTriggerLevel level, void (*callback)(void))
{
uint32_t mask;
uint32_t value;
handler = callback;
/* Clock Init: 3M=24M/(0x7 + 1) */
PddRegBackup[0] = REG32(PDD_CLK_BASE);
REG32_UPDATE_BITS(PDD_CLK_BASE, PDD_CLK_DIV_MASK, 0x7 << PDD_CLK_DIV_SHIFT);
REG32_UPDATE_BITS(PDD_CLK_BASE, PDD_CLK_GATE, PDD_CLK_GATE);
/* Sys Clock Enable */
PddRegBackup[1] = REG32(PDD_SYS_CLK_EN_BASE);
REG32(PDD_SYS_CLK_EN_BASE) |= BIT(PDD_SYS_CLK_EN_BIT);
/* Set Trigger Level */
PddRegBackup[2] = REG32(PDD_REG_BASE + PDD_DET_CTRL_REG_OFFS);
mask = DET_CTRL_MASK(PDD_DET_CTRL_BIT_OFFS);
value = (uint32_t)level << PDD_DET_CTRL_BIT_OFFS;
REG32_UPDATE_BITS(PDD_REG_BASE + PDD_DET_CTRL_REG_OFFS, mask, value);
/*
* filter_tick_sel:
* 2'b00: 1us/tick
* 2'b01: 10us/tick
* 2'b10: 100us/tick
* 2'b11: 1ms/tick
*/
PddRegBackup[3] = REG32(PDD_REG_BASE + PDD_FLT_TICK_REG_OFFS);
mask = FLT_TICK_MASK(PDD_FLT_TICK_BIT_OFFS);
value = 1 << PDD_FLT_TICK_BIT_OFFS; /* Select 10us/tick */
REG32_UPDATE_BITS(PDD_REG_BASE + PDD_FLT_TICK_REG_OFFS, mask, value);
/*
* filter_cnt_sel:
* 3'b000: 0 tick (no filter)
* 3'b001: 1x3 tick
* 3'b010: 2x3 tick
* ...
*/
PddRegBackup[4] = REG32(PDD_REG_BASE + PDD_FLT_CNT_REG_OFFS);
mask = FLT_CNT_MASK(PDD_FLT_CNT_BIT_OFFS);
value = 0x7 << PDD_FLT_CNT_BIT_OFFS; /* Select 7x3 tick */
REG32_UPDATE_BITS(PDD_REG_BASE + PDD_FLT_CNT_REG_OFFS, mask, value);
/* Enable Detection */
PddRegBackup[5] = REG32(PDD_REG_BASE + PDD_DET_EN_REG_OFFS);
REG32_UPDATE_BITS(PDD_REG_BASE + PDD_DET_EN_REG_OFFS,
BIT(PDD_DET_EN_BIT_OFFS),
BIT(PDD_DET_EN_BIT_OFFS));
/* Clear PDD IRQ */
REG32_UPDATE_BITS(PDD_REG_BASE + PDD_IRQ_CLR_REG_OFFS,
BIT(PDD_IRQ_CLR_BIT_OFFS),
BIT(PDD_IRQ_CLR_BIT_OFFS));
/* Enable PDD IRQ */
PddRegBackup[6] = REG32(PDD_REG_BASE + PDD_IRQ_EN_REG_OFFS);
REG32_UPDATE_BITS(PDD_REG_BASE + PDD_IRQ_EN_REG_OFFS,
BIT(PDD_IRQ_EN_BIT_OFFS),
BIT(PDD_IRQ_EN_BIT_OFFS));
/* Interrupt Init */
RegisterIrq(PDD_INTERRUPT_NUM, 1, prvPddIrqHandler);
EnableIrq(PDD_INTERRUPT_NUM);
printf(DRV_NAME_PREFIX "EN\n");
}
void vPddDeinit(void)
{
DisableIrq(PDD_INTERRUPT_NUM);
UnRegisterIrq(PDD_INTERRUPT_NUM);
REG32(PDD_REG_BASE + PDD_IRQ_EN_REG_OFFS) = PddRegBackup[6];
REG32(PDD_REG_BASE + PDD_DET_EN_REG_OFFS) = PddRegBackup[5];
REG32(PDD_REG_BASE + PDD_FLT_CNT_REG_OFFS) = PddRegBackup[4];
REG32(PDD_REG_BASE + PDD_FLT_TICK_REG_OFFS) = PddRegBackup[3];
REG32(PDD_REG_BASE + PDD_DET_CTRL_REG_OFFS) = PddRegBackup[2];
REG32(PDD_SYS_CLK_EN_BASE) = PddRegBackup[1];
REG32(PDD_CLK_BASE) = PddRegBackup[0];
printf(DRV_NAME_PREFIX "DIS\n");
}