Files
luban-lite-t3e-pro/bsp/artinchip/hal/cir/hal_cir.c

240 lines
7.7 KiB
C
Raw Normal View History

2023-08-30 16:21:18 +08:00
/*
2024-09-30 17:06:01 +08:00
* Copyright (c) 2022-2024, ArtInChip Technology Co., Ltd
2023-08-30 16:21:18 +08:00
*
* SPDX-License-Identifier: Apache-2.0
* Authors: dwj <weijie.ding@artinchip.com>
*/
#include "hal_cir.h"
#include "aic_hal_clk.h"
#define USEC_PER_SEC (1000000)
#define gen_reg(val) (volatile void *)(val)
int hal_cir_init(aic_cir_ctrl_t *aic_cir_ctrl)
{
int ret = 0;
uint32_t reg_val;
aic_cir_ctrl->cir_base = CIR_BASE;
aic_cir_ctrl->irq_num = CIR_IRQn;
aic_cir_ctrl->clk_idx = CLK_CIR;
ret = hal_clk_enable_deassertrst(aic_cir_ctrl->clk_idx);
/* Set noise thresholld */
reg_val = readl(gen_reg(aic_cir_ctrl->cir_base + CIR_RX_CFG_REG));
reg_val &= ~(0xffff << CIR_RX_CFG_NOISE);
reg_val |= CIR_RX_CFG_NOISE_LEVEL(0x1770);
writel(reg_val, gen_reg(aic_cir_ctrl->cir_base + CIR_RX_CFG_REG));
/* Set rx active threshold and idle threshold */
writel((CIR_RX_THRES_ACTIVE_LEVEL(0x10) |
CIR_RX_THRES_IDLE_LEVEL(0x1C0)),
gen_reg(aic_cir_ctrl->cir_base + CIR_RX_THRES_REG));
/* Flush TX and RX FIFO */
writel((CIR_MCR_RXFIFO_CLR | CIR_MCR_TXFIFO_CLR),
gen_reg(aic_cir_ctrl->cir_base + CIR_MCR_REG));
/* Set TX and RX FIFO level */
writel((CIR_INTEN_TXB_EMPTY_LEVEL(0x40) |
CIR_INTEN_RXB_AVL_LEVEL(0x20)),
gen_reg(aic_cir_ctrl->cir_base + CIR_INTEN_REG));
/* Clear pending interrupt flags */
writel(0xff, gen_reg(aic_cir_ctrl->cir_base + CIR_INTR_REG));
/* Enable RX interrupt */
reg_val = readl(gen_reg(aic_cir_ctrl->cir_base + CIR_INTEN_REG));
reg_val |= CIR_INTEN_RX_INT_EN;
writel(reg_val, gen_reg(aic_cir_ctrl->cir_base + CIR_INTEN_REG));
return ret;
}
void hal_cir_uninit(aic_cir_ctrl_t *aic_cir_ctrl)
{
hal_clk_disable_assertrst(aic_cir_ctrl->clk_idx);
}
int hal_cir_set_tx_carrier(aic_cir_ctrl_t * aic_cir_ctrl,
uint8_t protocol, uint32_t tx_duty)
{
uint32_t mod_clk, clk_div, carrier_high, carrier_low, val;
mod_clk = hal_clk_get_freq(CLK_CIR);
if (protocol == 1) {
/* RC5 protocol */
clk_div = DIV_ROUND_UP(mod_clk, 36000);
carrier_high = clk_div * tx_duty / 100;
carrier_low = clk_div - carrier_high;
} else {
/* NEC protocol */
clk_div = DIV_ROUND_UP(mod_clk, 38000);
carrier_high = clk_div * tx_duty / 100;
carrier_low = clk_div - carrier_high;
}
val = ((carrier_high - 1) << 16) | (carrier_low - 1);
writel(val, gen_reg(aic_cir_ctrl->cir_base + CIR_CARR_CFG_REG));
return 0;
}
void hal_cir_set_rx_sample_clock(aic_cir_ctrl_t * aic_cir_ctrl,
uint8_t protocol)
{
uint32_t mod_clk, clk_div;
mod_clk = hal_clk_get_freq(CLK_CIR);
if (protocol == 1) {
/* RC5 protocol */
clk_div = DIV_ROUND_UP(mod_clk, 36000);
} else {
/* NEC protocol */
clk_div = DIV_ROUND_UP(mod_clk, 38000);
}
writel(clk_div - 1, gen_reg(aic_cir_ctrl->cir_base + CIR_RXCLK_REG));
}
void hal_cir_set_rx_level(aic_cir_ctrl_t * aic_cir_ctrl, uint32_t rx_level)
{
uint32_t reg_val;
aic_cir_ctrl->rx_level = rx_level;
reg_val = readl(gen_reg(aic_cir_ctrl->cir_base + CIR_RX_CFG_REG));
reg_val &= ~CIR_RX_CFG_RX_LEVEL;
reg_val |= (rx_level << 1);
writel(reg_val, gen_reg(aic_cir_ctrl->cir_base + CIR_RX_CFG_REG));
}
void hal_cir_send_data(aic_cir_ctrl_t * aic_cir_ctrl,
uint8_t * tx_data, uint32_t size)
{
int i;
uint32_t reg_val;
for (i = 0; i < size; i++)
writel(tx_data[i], gen_reg(aic_cir_ctrl->cir_base + CIR_TXFIFO_REG));
/* Start to transfer */
reg_val = readl(gen_reg(aic_cir_ctrl->cir_base + CIR_MCR_REG));
reg_val |= CIR_MCR_TX_START;
writel(reg_val, gen_reg(aic_cir_ctrl->cir_base + CIR_MCR_REG));
}
void hal_cir_enable_transmitter(aic_cir_ctrl_t * aic_cir_ctrl)
{
uint32_t reg_val;
reg_val = readl(gen_reg(aic_cir_ctrl->cir_base + CIR_MCR_REG));
reg_val |= CIR_MCR_TX_EN;
writel(reg_val, gen_reg(aic_cir_ctrl->cir_base + CIR_MCR_REG));
}
void hal_cir_disable_transmitter(aic_cir_ctrl_t * aic_cir_ctrl)
{
uint32_t reg_val;
reg_val = readl(gen_reg(aic_cir_ctrl->cir_base + CIR_MCR_REG));
reg_val &= ~CIR_MCR_TX_EN;
writel(reg_val, gen_reg(aic_cir_ctrl->cir_base + CIR_MCR_REG));
}
void hal_cir_enable_receiver(aic_cir_ctrl_t * aic_cir_ctrl)
{
uint32_t reg_val;
reg_val = readl(gen_reg(aic_cir_ctrl->cir_base + CIR_MCR_REG));
reg_val |= CIR_MCR_RX_EN;
writel(reg_val, gen_reg(aic_cir_ctrl->cir_base + CIR_MCR_REG));
}
void hal_cir_disable_receiver(aic_cir_ctrl_t * aic_cir_ctrl)
{
uint32_t reg_val;
reg_val = readl(gen_reg(aic_cir_ctrl->cir_base + CIR_MCR_REG));
reg_val &= ~CIR_MCR_RX_EN;
writel(reg_val, gen_reg(aic_cir_ctrl->cir_base + CIR_MCR_REG));
}
2024-09-30 17:06:01 +08:00
void hal_cir_flush_rx_fifo(aic_cir_ctrl_t * aic_cir_ctrl)
{
uint32_t reg_val;
reg_val = readl(gen_reg(aic_cir_ctrl->cir_base + CIR_MCR_REG));
reg_val |= CIR_MCR_RXFIFO_CLR;
writel(reg_val, gen_reg(aic_cir_ctrl->cir_base + CIR_MCR_REG));
}
2023-08-30 16:21:18 +08:00
irqreturn_t hal_cir_irq(int irq_num, void *arg)
{
2024-09-30 17:06:01 +08:00
unsigned int int_status, rx_status;
unsigned int i, count = 0, free_space;
2023-08-30 16:21:18 +08:00
aic_cir_ctrl_t *aic_cir_ctrl = (aic_cir_ctrl_t *)arg;
uint8_t *rx_data = &aic_cir_ctrl->rx_data[aic_cir_ctrl->rx_idx];
uint8_t need_inverse;
int_status = readl(gen_reg(aic_cir_ctrl->cir_base + CIR_INTR_REG)) & 7;
rx_status = readl(gen_reg(aic_cir_ctrl->cir_base + CIR_RXSTAT_REG));
2024-09-30 17:06:01 +08:00
/* Calculate how much free space is left in rx_data */
free_space = sizeof(aic_cir_ctrl->rx_data) - aic_cir_ctrl->rx_idx;
2023-08-30 16:21:18 +08:00
/* clear all pending status */
/* RX Available interrupt is pulse interrupt */
writel(0xff, gen_reg(aic_cir_ctrl->cir_base + CIR_INTR_REG));
/* Handle Receive data */
if (int_status & (CIR_INTR_RXB_AVL_INT | CIR_INTR_RX_END_INT)) {
/* Get the number of data in RXFIFO */
count = rx_status & 0x3f;
2024-09-30 17:06:01 +08:00
count = (count <= free_space) ? count : free_space;
2023-08-30 16:21:18 +08:00
/* Confirm if RXFIFO has data */
if (!(rx_status & (0x1 << 8))) {
for (i = 0; i < count; i++) {
rx_data[i] = readl(gen_reg(aic_cir_ctrl->cir_base +
CIR_RXFIFO_REG));
need_inverse = (rx_data[i] >> 7) ^ aic_cir_ctrl->rx_level;
rx_data[i] = (need_inverse << 7) | (rx_data[i] & 0x7f);
aic_cir_ctrl->rx_idx++;
}
aic_cir_ctrl->rx_flag = 1;
}
}
2024-09-30 17:06:01 +08:00
/* If count == free_space, means that there maybe still have some data
* in RXFIFO, then flush RXFIFO, because there is no space to store them.
*/
if (count == free_space)
hal_cir_flush_rx_fifo(aic_cir_ctrl);
2023-08-30 16:21:18 +08:00
if (int_status & CIR_INTR_RX_OVF_INT) {
aic_cir_ctrl->rx_flag = 0;
2024-09-30 17:06:01 +08:00
hal_cir_flush_rx_fifo(aic_cir_ctrl);
2023-08-30 16:21:18 +08:00
if (aic_cir_ctrl->callback)
aic_cir_ctrl->callback(aic_cir_ctrl, CIR_EVENT_ERROR,
aic_cir_ctrl->arg);
} else if ((int_status & CIR_INTR_RX_END_INT) && aic_cir_ctrl->rx_flag) {
aic_cir_ctrl->rx_flag = 0;
if (aic_cir_ctrl->callback)
aic_cir_ctrl->callback(aic_cir_ctrl, CIR_EVENT_RECEIVE_COMPLETE,
aic_cir_ctrl->arg);
}
return IRQ_HANDLED;
}
void hal_cir_attach_callback(aic_cir_ctrl_t * aic_cir_ctrl,
void *callback, void *arg)
{
aic_cir_ctrl->callback = callback;
aic_cir_ctrl->arg = arg;
}
2024-09-30 17:06:01 +08:00
void hal_cir_detach_callback(aic_cir_ctrl_t * aic_cir_ctrl)
{
aic_cir_ctrl->callback = NULL;
aic_cir_ctrl->arg = NULL;
}
2023-08-30 16:21:18 +08:00
void hal_cir_rx_reset_status(aic_cir_ctrl_t * aic_cir_ctrl)
{
2024-09-30 17:06:01 +08:00
memset((void *)aic_cir_ctrl->rx_data, 0, sizeof(aic_cir_ctrl->rx_data));
2023-08-30 16:21:18 +08:00
aic_cir_ctrl->rx_idx = 0;
}