188 lines
4.8 KiB
C
188 lines
4.8 KiB
C
/**
|
|
* @file analog_control.c
|
|
* @brief Implementation of disabling analog mux of a channel/device/chip,
|
|
* and enabling an analog mux of a channle.
|
|
*
|
|
* @copyright Copyright (c) 2025 Semidrive Semiconductor.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
|
|
#include <regs_base.h>
|
|
#define ADC1_BASE APB_ADC1_BASE
|
|
#define ADC2_BASE APB_ADC2_BASE
|
|
#define ADC3_BASE APB_ADC3_BASE
|
|
#define ACMP1_BASE APB_ACMP1_BASE
|
|
#define ACMP2_BASE APB_ACMP2_BASE
|
|
#define SCR_BASE APB_SCR_SF_BASE
|
|
#include <scr_hw.h>
|
|
#include <analog_control.h>
|
|
|
|
|
|
#define SCR_AMUX_DISABLE 1
|
|
#define SCR_AMUX_ENABLE 0
|
|
#define AMUX_CHNL_MIN 4 /* channel 0~3 has no mux on chip */
|
|
#define CHNL_MASK(chnl) ((chnl) & 0x7u)
|
|
#define CHNL_2_POS(chnl) CHNL_MASK((chnl) >> 3)
|
|
#define CHNL_2_NEG(chnl) CHNL_MASK(chnl)
|
|
|
|
|
|
static struct chip_amux_scr *amux_scr_head = NULL;
|
|
|
|
|
|
/*
|
|
* Register a chip with its analog mux table to the chip list.
|
|
*/
|
|
void analog_chip_amux_register(struct chip_amux_scr *amux_scr)
|
|
{
|
|
struct chip_amux_scr **temp = &amux_scr_head;
|
|
|
|
while (*temp) {
|
|
if (*temp == amux_scr) {
|
|
/* It is already registered. */
|
|
return;
|
|
}
|
|
temp = &(*temp)->next;
|
|
}
|
|
|
|
*temp = amux_scr;
|
|
}
|
|
|
|
/*
|
|
* Disable all analog mux of a chip.
|
|
*/
|
|
void analog_chip_amux_init(struct chip_amux_scr *amux_scr)
|
|
{
|
|
sdrv_scr_t scr_ctrl;
|
|
const struct channel_amux_scr *scr_array = NULL;
|
|
uint32_t scr_len = 0;
|
|
int i;
|
|
int j;
|
|
|
|
if (!amux_scr || !amux_scr->dev_amux) {
|
|
return;
|
|
}
|
|
|
|
scr_ctrl.base = amux_scr->scr_base;
|
|
for (i = 0; i < amux_scr->dev_amux_cnt; i++) {
|
|
scr_array = amux_scr->dev_amux[i].chnl_amux;
|
|
scr_len = amux_scr->dev_amux[i].chnl_amux_cnt;
|
|
for (j = 0; j < scr_len; j++) {
|
|
scr_set(&scr_ctrl, &scr_array[j].scr_sig, SCR_AMUX_DISABLE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Look for analog mux table and scr address of the specified device.
|
|
*/
|
|
static const struct device_amux_scr * analog_seek_dev_amux(uintptr_t ana_dev_base, sdrv_scr_t *scr_ctrl)
|
|
{
|
|
struct chip_amux_scr *chip = amux_scr_head;
|
|
int i;
|
|
|
|
while (chip) {
|
|
for (i = 0; i < chip->dev_amux_cnt; i++) {
|
|
if (chip->dev_amux[i].base == ana_dev_base) {
|
|
scr_ctrl->base = chip->scr_base;
|
|
return &chip->dev_amux[i];
|
|
}
|
|
}
|
|
chip = chip->next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Disable all analog mux of the specified device.
|
|
*/
|
|
void analog_dev_amux_init(uintptr_t ana_dev_base)
|
|
{
|
|
sdrv_scr_t scr_ctrl;
|
|
const struct device_amux_scr *dev_amux;
|
|
int i;
|
|
|
|
dev_amux = analog_seek_dev_amux(ana_dev_base, &scr_ctrl);
|
|
if (!dev_amux || !dev_amux->chnl_amux) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < dev_amux->chnl_amux_cnt; i++) {
|
|
scr_set(&scr_ctrl, &dev_amux->chnl_amux[i].scr_sig, SCR_AMUX_DISABLE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Look for scr signal address of the specified channel.
|
|
*/
|
|
static const scr_signal_t * analog_seek_amux_scr(const struct device_amux_scr *dev_amux, uint16_t chnl)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < dev_amux->chnl_amux_cnt; i++) {
|
|
if (dev_amux->chnl_amux[i].chnl == chnl) {
|
|
return &dev_amux->chnl_amux[i].scr_sig;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Enable or disable the analog mux which the channel belongs to.
|
|
*/
|
|
void analog_dev_chnl_amux_cfg(uintptr_t ana_dev_base, uint16_t chnl, bool enable)
|
|
{
|
|
sdrv_scr_t scr_ctrl;
|
|
const struct device_amux_scr *dev_amux;
|
|
const scr_signal_t *amux_scr;
|
|
uint16_t chnl_pos = CHNL_2_POS(chnl);
|
|
uint16_t chnl_neg = CHNL_2_NEG(chnl);
|
|
uint32_t scr_val;
|
|
|
|
if ((chnl_pos < AMUX_CHNL_MIN) && (chnl_neg < AMUX_CHNL_MIN)) {
|
|
return;
|
|
}
|
|
|
|
dev_amux = analog_seek_dev_amux(ana_dev_base, &scr_ctrl);
|
|
if (!dev_amux || !dev_amux->chnl_amux) {
|
|
return;
|
|
}
|
|
|
|
scr_val = enable ? SCR_AMUX_ENABLE : SCR_AMUX_DISABLE;
|
|
if (chnl_neg >= AMUX_CHNL_MIN) {
|
|
/* Note: consider 6b'001xxx as a single positive channel. */
|
|
if (chnl_pos == SINGLE_CHNL_POSITIVE) {
|
|
chnl_neg = ADC_ACMP_POS_CHNL(chnl_neg);
|
|
}
|
|
amux_scr = analog_seek_amux_scr(dev_amux, chnl_neg);
|
|
if (amux_scr) {
|
|
if (scr_get(&scr_ctrl, amux_scr) != scr_val) {
|
|
scr_set(&scr_ctrl, amux_scr, scr_val);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (chnl_pos >= AMUX_CHNL_MIN) {
|
|
amux_scr = analog_seek_amux_scr(dev_amux, ADC_ACMP_POS_CHNL(chnl_pos));
|
|
if (amux_scr) {
|
|
if (scr_get(&scr_ctrl, amux_scr) != scr_val) {
|
|
scr_set(&scr_ctrl, amux_scr, scr_val);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Disable all analog mux of ADC/ACMP device.
|
|
* And register their scr signals to the chip list.
|
|
*/
|
|
analog_init_func_def(analog_init)
|
|
|
|
/*
|
|
* Register all scr signals of a chip to the chip list.
|
|
*/
|
|
amux_register_func_def(analog_mux_register)
|
|
|