2023-08-30 16:21:18 +08:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2022-2023, ArtInChip Technology Co., Ltd
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
*
|
|
|
|
|
* Authors: Li Siyao <siyao.li@artinchip.com>
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "aic_core.h"
|
|
|
|
|
#include "hal_psadc.h"
|
2024-04-03 16:40:57 +08:00
|
|
|
#include <string.h>
|
2023-08-30 16:21:18 +08:00
|
|
|
|
|
|
|
|
/* Register definition of PSADC Controller */
|
|
|
|
|
#define PSADC_MCR 0x000
|
|
|
|
|
#define PSADC_TCR 0x004
|
|
|
|
|
#define PSADC_NODE1 0x008
|
|
|
|
|
#define PSADC_NODE2 0x00C
|
|
|
|
|
#define PSADC_MSR 0x010
|
|
|
|
|
#define PSADC_CALCSR 0x014
|
|
|
|
|
#define PSADC_FILTER 0x01C
|
|
|
|
|
#define PSADC_Q1FCR 0x020
|
|
|
|
|
#define PSADC_Q2FCR 0x024
|
|
|
|
|
#define PSADC_Q1FDR 0x040
|
|
|
|
|
#define PSADC_Q2FDR 0x080
|
|
|
|
|
#define PSADC_VERSION 0xFFC
|
|
|
|
|
|
|
|
|
|
#define PSADC_MCR_Q1_TRIGS BIT(22)
|
|
|
|
|
#define PSADC_MCR_Q1_INTE BIT(18)
|
|
|
|
|
#define PSADC_MCR_QUE_COMB BIT(1)
|
|
|
|
|
#define PSADC_MCR_EN BIT(0)
|
|
|
|
|
|
2024-04-03 16:40:57 +08:00
|
|
|
#define PSADC_TCR_Q2_TRIG_CNT_SHIFT 4
|
|
|
|
|
#define PSADC_QX_NODE_MASK 4
|
|
|
|
|
|
|
|
|
|
#define PSADC_MSR_QX_CNT_MASK GENMASK(27, 24)
|
|
|
|
|
#define PSADC_MSR_Q2_FERR BIT(6)
|
|
|
|
|
#define PSADC_MSR_Q2_INT BIT(4)
|
2023-08-30 16:21:18 +08:00
|
|
|
#define PSADC_MSR_Q1_FERR BIT(2)
|
|
|
|
|
#define PSADC_MSR_Q1_INT BIT(0)
|
|
|
|
|
|
|
|
|
|
#define PSADC_Q1FCR_FIFO_DRTH_SHIFT 11
|
|
|
|
|
#define PSADC_Q1FCR_UF_STS BIT(17)
|
|
|
|
|
#define PSADC_Q1FCR_OF_STS BIT(16)
|
|
|
|
|
#define PSADC_Q1FCR_FIFO_ERRIE BIT(3)
|
|
|
|
|
#define PSADC_Q1FCR_FIFO_FLUSH BIT(0)
|
|
|
|
|
|
2024-04-03 16:40:57 +08:00
|
|
|
#define PSADC_Q2FCR_FIFO_DRTH_SHIFT 11
|
|
|
|
|
#define PSADC_Q2FCR_UF_STS BIT(17)
|
|
|
|
|
#define PSADC_Q2FCR_OF_STS BIT(16)
|
|
|
|
|
#define PSADC_Q2FCR_FIFO_ERRIE BIT(3)
|
|
|
|
|
#define PSADC_Q2FCR_FIFO_FLUSH BIT(0)
|
|
|
|
|
|
2023-08-30 16:21:18 +08:00
|
|
|
#define PSADC_Q1FDR_CHNUM_SHIFT 12
|
2024-04-03 16:40:57 +08:00
|
|
|
#define PSADC_Q1FDR_CHNUM_MASK GENMASK(15, 12)
|
2023-08-30 16:21:18 +08:00
|
|
|
#define PSADC_Q1FDR_DATA_MASK GENMASK(11, 0)
|
|
|
|
|
#define PSADC_Q1FDR_DATA BIT(0)
|
|
|
|
|
|
2024-04-03 16:40:57 +08:00
|
|
|
#define PSADC_Q2FDR_CHNUM_SHIFT 12
|
|
|
|
|
#define PSADC_Q2FDR_CHNUM_MASK GENMASK(15, 12)
|
|
|
|
|
#define PSADC_Q2FDR_DATA_MASK GENMASK(11, 0)
|
|
|
|
|
#define PSADC_Q2FDR_DATA BIT(0)
|
|
|
|
|
|
2023-08-30 16:21:18 +08:00
|
|
|
extern struct aic_psadc_ch aic_psadc_chs[];
|
2024-04-03 16:40:57 +08:00
|
|
|
extern struct aic_psadc_queue aic_psadc_queues[];
|
2023-08-30 16:21:18 +08:00
|
|
|
static u32 aic_psadc_ch_num = 0; // the number of available channel
|
2024-04-03 16:40:57 +08:00
|
|
|
static u32 aic_psadc_ch_data[AIC_PSADC_CH_NUM];
|
2023-08-30 16:21:18 +08:00
|
|
|
|
|
|
|
|
static inline void psadc_writel(u32 val, int reg)
|
|
|
|
|
{
|
|
|
|
|
writel(val, PSADC_BASE + reg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline u32 psadc_readl(int reg)
|
|
|
|
|
{
|
|
|
|
|
return readl(PSADC_BASE + reg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void psadc_reg_enable(int offset, int bit, int enable)
|
|
|
|
|
{
|
|
|
|
|
int tmp = psadc_readl(offset);
|
|
|
|
|
|
|
|
|
|
if (enable)
|
|
|
|
|
tmp |= bit;
|
|
|
|
|
else
|
|
|
|
|
tmp &= ~bit;
|
|
|
|
|
|
|
|
|
|
psadc_writel(tmp, offset);
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-27 08:47:24 +08:00
|
|
|
void hal_psadc_enable(int enable)
|
2023-08-30 16:21:18 +08:00
|
|
|
{
|
|
|
|
|
psadc_reg_enable(PSADC_MCR, PSADC_MCR_EN, enable);
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-27 08:47:24 +08:00
|
|
|
void hal_psadc_single_queue_mode(int enable)
|
2023-08-30 16:21:18 +08:00
|
|
|
{
|
|
|
|
|
psadc_reg_enable(PSADC_MCR, PSADC_MCR_QUE_COMB, enable);
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-27 08:47:24 +08:00
|
|
|
void hal_psadc_qc_irq_enable(int enable)
|
2023-08-30 16:21:18 +08:00
|
|
|
{
|
|
|
|
|
psadc_reg_enable(PSADC_MCR, PSADC_MCR_Q1_INTE, enable);
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-03 16:40:57 +08:00
|
|
|
static void psadc_fifo1_flush()
|
2023-08-30 16:21:18 +08:00
|
|
|
{
|
|
|
|
|
u32 val = psadc_readl(PSADC_Q1FCR);
|
|
|
|
|
|
|
|
|
|
if (val & PSADC_Q1FCR_UF_STS)
|
2024-04-03 16:40:57 +08:00
|
|
|
pr_err("FIFO is Underflow!%#x\n", val);
|
2023-08-30 16:21:18 +08:00
|
|
|
if (val & PSADC_Q1FCR_OF_STS)
|
2024-04-03 16:40:57 +08:00
|
|
|
pr_err("FIFO is Overflow!%#x\n", val);
|
2023-08-30 16:21:18 +08:00
|
|
|
|
|
|
|
|
psadc_writel(val | PSADC_Q1FCR_FIFO_FLUSH, PSADC_Q1FCR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void psadc_fifo_init(void)
|
|
|
|
|
{
|
|
|
|
|
u32 val = 0;
|
|
|
|
|
|
|
|
|
|
val = 1 << PSADC_Q1FCR_FIFO_DRTH_SHIFT;
|
|
|
|
|
psadc_writel(val, PSADC_Q1FCR);
|
|
|
|
|
psadc_writel(val, PSADC_Q2FCR);
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-03 16:40:57 +08:00
|
|
|
int hal_psadc_set_queue_node(int queue, int ch, int node_ordinal)
|
2023-08-30 16:21:18 +08:00
|
|
|
{
|
2024-04-03 16:40:57 +08:00
|
|
|
int val;
|
|
|
|
|
int node_chan = 0;
|
|
|
|
|
u32 node_regs = 0;
|
|
|
|
|
|
|
|
|
|
if (queue == AIC_PSADC_Q1)
|
|
|
|
|
node_regs = PSADC_NODE1;
|
|
|
|
|
if (queue == AIC_PSADC_Q2)
|
|
|
|
|
node_regs = PSADC_NODE2;
|
|
|
|
|
|
|
|
|
|
node_chan = ch << (node_ordinal * PSADC_QX_NODE_MASK);
|
|
|
|
|
val = psadc_readl(node_regs);
|
|
|
|
|
val |= node_chan;
|
|
|
|
|
psadc_writel(val, node_regs);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int hal_psadc_ch_init()
|
|
|
|
|
{
|
|
|
|
|
int val = 0;
|
|
|
|
|
struct aic_psadc_queue *queue = &aic_psadc_queues[0];
|
|
|
|
|
|
2023-08-30 16:21:18 +08:00
|
|
|
psadc_fifo_init();
|
2024-04-03 16:40:57 +08:00
|
|
|
if (queue->type == AIC_PSADC_QC) {
|
|
|
|
|
val = queue->nodes_num;
|
|
|
|
|
psadc_writel(val, PSADC_TCR);
|
|
|
|
|
}
|
2023-08-30 16:21:18 +08:00
|
|
|
|
|
|
|
|
psadc_reg_enable(PSADC_MCR, PSADC_MCR_Q1_INTE, 1);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-03 16:40:57 +08:00
|
|
|
void aich_psadc_status_show(void)
|
2023-08-30 16:21:18 +08:00
|
|
|
{
|
|
|
|
|
int version = psadc_readl(PSADC_VERSION);
|
|
|
|
|
|
2024-04-03 16:40:57 +08:00
|
|
|
printf("In PSADC V%d.%02d\n"
|
2024-06-04 19:00:30 +08:00
|
|
|
"enabled %d channels: ",
|
2024-04-03 16:40:57 +08:00
|
|
|
version >> 8, version & 0xff,
|
|
|
|
|
aic_psadc_ch_num);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < aic_psadc_ch_num; i++) {
|
|
|
|
|
if (aic_psadc_chs[i].available)
|
|
|
|
|
printf("[%d] ", aic_psadc_chs[i].id);
|
|
|
|
|
}
|
|
|
|
|
printf("\n");
|
|
|
|
|
return;
|
2023-08-30 16:21:18 +08:00
|
|
|
}
|
|
|
|
|
|
2024-04-03 16:40:57 +08:00
|
|
|
static void psadc_read_ch(int cnt)
|
2023-08-30 16:21:18 +08:00
|
|
|
{
|
2024-04-03 16:40:57 +08:00
|
|
|
u32 data;
|
|
|
|
|
int val;
|
|
|
|
|
|
|
|
|
|
val = psadc_readl(PSADC_Q1FDR);
|
|
|
|
|
data = val & PSADC_Q1FDR_DATA_MASK;
|
|
|
|
|
aic_psadc_ch_data[cnt] = data;
|
|
|
|
|
pr_debug("val %#x\n", val);
|
2023-08-30 16:21:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct aic_psadc_ch *hal_psadc_ch_is_valid(u32 ch)
|
|
|
|
|
{
|
|
|
|
|
s32 i;
|
|
|
|
|
if (ch >= AIC_PSADC_CH_NUM) {
|
|
|
|
|
pr_err("Invalid channel %d\n", ch);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < aic_psadc_ch_num; i++) {
|
|
|
|
|
if (aic_psadc_chs[i].id != ch)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (aic_psadc_chs[i].available)
|
|
|
|
|
return &aic_psadc_chs[i];
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-04-03 16:40:57 +08:00
|
|
|
pr_debug("Ch%d is unavailable!\n", ch);
|
2023-08-30 16:21:18 +08:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-03 16:40:57 +08:00
|
|
|
int hal_psadc_read(u32 *val, u32 timeout)
|
2023-08-30 16:21:18 +08:00
|
|
|
{
|
|
|
|
|
int ret = 0;
|
2024-04-03 16:40:57 +08:00
|
|
|
struct aic_psadc_queue *queue = &aic_psadc_queues[AIC_PSADC_QC];
|
2023-08-30 16:21:18 +08:00
|
|
|
|
2024-04-03 16:40:57 +08:00
|
|
|
psadc_fifo1_flush();
|
|
|
|
|
psadc_reg_enable(PSADC_MCR, PSADC_MCR_Q1_TRIGS, 1);
|
|
|
|
|
ret = aicos_sem_take(queue->complete, timeout);
|
2023-08-30 16:21:18 +08:00
|
|
|
if (ret < 0) {
|
2024-06-04 19:00:30 +08:00
|
|
|
hal_log_err("Queue%d read timeout!\n", queue->id);
|
2024-01-27 08:47:24 +08:00
|
|
|
hal_psadc_qc_irq_enable(0);
|
2024-04-03 16:40:57 +08:00
|
|
|
|
2023-08-30 16:21:18 +08:00
|
|
|
return -ETIMEDOUT;
|
|
|
|
|
}
|
2024-04-03 16:40:57 +08:00
|
|
|
if (val)
|
|
|
|
|
memcpy(val, aic_psadc_ch_data, sizeof(aic_psadc_ch_data));
|
|
|
|
|
|
2024-06-04 19:00:30 +08:00
|
|
|
return 0;
|
2024-04-03 16:40:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int hal_psadc_read_poll(u32 *val, u32 timeout)
|
|
|
|
|
{
|
|
|
|
|
u32 q_flag = 0;
|
|
|
|
|
int get_data_flag = 0;
|
|
|
|
|
int time_count = 0;
|
|
|
|
|
struct aic_psadc_queue *queue = &aic_psadc_queues[AIC_PSADC_QC];
|
|
|
|
|
|
|
|
|
|
psadc_fifo1_flush();
|
|
|
|
|
psadc_reg_enable(PSADC_MCR, PSADC_MCR_Q1_TRIGS, 1);
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
time_count++;
|
|
|
|
|
q_flag = psadc_readl(PSADC_MSR);
|
|
|
|
|
psadc_writel(q_flag, PSADC_MSR);
|
|
|
|
|
|
|
|
|
|
if (q_flag & PSADC_MSR_Q1_INT) {
|
|
|
|
|
get_data_flag++;
|
|
|
|
|
for(int i = 0; i < queue->nodes_num; i++)
|
|
|
|
|
psadc_read_ch(i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (q_flag & PSADC_MSR_Q1_FERR)
|
|
|
|
|
psadc_fifo1_flush();
|
|
|
|
|
if (get_data_flag)
|
|
|
|
|
break;
|
|
|
|
|
if (time_count > timeout) {
|
|
|
|
|
hal_psadc_qc_irq_enable(0);
|
|
|
|
|
return -ETIMEDOUT;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-08-30 16:21:18 +08:00
|
|
|
|
|
|
|
|
if (val)
|
2024-04-03 16:40:57 +08:00
|
|
|
memcpy(val, aic_psadc_ch_data,
|
|
|
|
|
sizeof(aic_psadc_ch_data[0]) * queue->nodes_num);
|
2023-08-30 16:21:18 +08:00
|
|
|
|
2024-06-04 19:00:30 +08:00
|
|
|
return 0;
|
2023-08-30 16:21:18 +08:00
|
|
|
}
|
|
|
|
|
|
2024-01-27 08:47:24 +08:00
|
|
|
irqreturn_t hal_psadc_isr(int irq, void *arg)
|
2023-08-30 16:21:18 +08:00
|
|
|
{
|
|
|
|
|
u32 q_flag = 0;
|
2024-04-03 16:40:57 +08:00
|
|
|
struct aic_psadc_queue *queue = &aic_psadc_queues[AIC_PSADC_QC];
|
|
|
|
|
|
2023-08-30 16:21:18 +08:00
|
|
|
q_flag = psadc_readl(PSADC_MSR);
|
|
|
|
|
psadc_writel(q_flag, PSADC_MSR);
|
2024-04-03 16:40:57 +08:00
|
|
|
if (q_flag & PSADC_MSR_Q1_INT) {
|
|
|
|
|
for(int i = 0; i < queue->nodes_num; i++)
|
|
|
|
|
psadc_read_ch(i);
|
|
|
|
|
aicos_sem_give(queue->complete);
|
|
|
|
|
}
|
2023-08-30 16:21:18 +08:00
|
|
|
|
2024-04-03 16:40:57 +08:00
|
|
|
if (q_flag & PSADC_MSR_Q1_FERR)
|
|
|
|
|
psadc_fifo1_flush();
|
2023-08-30 16:21:18 +08:00
|
|
|
|
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void hal_psadc_set_ch_num(u32 num)
|
|
|
|
|
{
|
|
|
|
|
aic_psadc_ch_num = num;
|
|
|
|
|
}
|