pure sdk for main
This commit is contained in:
@@ -0,0 +1,477 @@
|
||||
/**
|
||||
* @file hgpdm_v0.c
|
||||
* @author bxd
|
||||
* @brief pdm
|
||||
* @version
|
||||
* TXW80X; TXW81X
|
||||
* @date 2023-08-02
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
#include "typesdef.h"
|
||||
#include "list.h"
|
||||
#include "errno.h"
|
||||
#include "dev.h"
|
||||
#include "osal/irq.h"
|
||||
#include "osal/semaphore.h"
|
||||
#include "osal/mutex.h"
|
||||
#include "osal/string.h"
|
||||
#include "hal/pdm.h"
|
||||
#include "dev/pdm/hgpdm_v0.h"
|
||||
#include "hgpdm_v0_hw.h"
|
||||
|
||||
/**********************************************************************************/
|
||||
/* LOW LAYER FUNCTION */
|
||||
/**********************************************************************************/
|
||||
|
||||
static int32 hgpdm_v0_switch_hal_pdm_sample_freq(enum pdm_sample_freq param) {
|
||||
|
||||
switch (param) {
|
||||
#ifdef TXW80X
|
||||
case (PDM_SAMPLE_FREQ_8K):
|
||||
return 8000;
|
||||
break;
|
||||
#endif
|
||||
case (PDM_SAMPLE_FREQ_16K):
|
||||
return 16000;
|
||||
break;
|
||||
case (PDM_SAMPLE_FREQ_32K):
|
||||
return 32000;
|
||||
break;
|
||||
case (PDM_SAMPLE_FREQ_48K):
|
||||
return 48000;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int32 hgpdm_v0_switch_hal_pdm_channel(enum pdm_channel param) {
|
||||
|
||||
switch (param) {
|
||||
case (PDM_CHANNEL_LEFT):
|
||||
return 0;
|
||||
break;
|
||||
case (PDM_CHANNEL_RIGHT):
|
||||
return 1;
|
||||
break;
|
||||
case (PDM_CHANNEL_STEREO):
|
||||
return 2;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void hgpdm_v0_set_mclk(int32 freq) {
|
||||
|
||||
uint32 temp;
|
||||
volatile uint32 div;
|
||||
|
||||
sysctrl_unlock();
|
||||
SYSCTRL->SYS_CON2 |= 1<<18; //choose pll0
|
||||
|
||||
#ifdef TXW80X
|
||||
#ifndef FPGA_SUPPORT
|
||||
div = (peripheral_clock_get(HG_APB0_PT_PDM)/ (freq*64*8));
|
||||
#else
|
||||
float div_f;
|
||||
div_f = (96000000.0 / (freq*64*8));
|
||||
div = (uint32_t)(div_f+0.5);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef TXW81X
|
||||
#ifndef FPGA_SUPPORT
|
||||
div = (peripheral_clock_get(HG_APB0_PT_PDM)/ (freq*100*4));
|
||||
#else
|
||||
float div_f;
|
||||
div_f = (96000000.0 / (freq*64*8));
|
||||
div = (uint32_t)(div_f+0.5);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
temp = SYSCTRL->SYS_CON2;
|
||||
temp &= ~0x07F00000;
|
||||
temp |= (div-1)<<20; //select div
|
||||
|
||||
SYSCTRL->SYS_CON2 = temp;
|
||||
sysctrl_lock();
|
||||
}
|
||||
|
||||
static int32 hgpdm_v0_lr_channel_interchange(struct hgpdm_v0_hw *p_pdm, uint32 enable) {
|
||||
|
||||
if (enable) {
|
||||
p_pdm->CON |= LL_PDM_CON_LRSW(1);
|
||||
} else {
|
||||
p_pdm->CON &= ~ LL_PDM_CON_LRSW(1);
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static void hgpdm_v0_enable(struct hgpdm_v0_hw *p_pdm) {
|
||||
|
||||
p_pdm->CON |= LL_PDM_CON_ENABLE(1);
|
||||
}
|
||||
|
||||
static void hgpdm_v0_disable(struct hgpdm_v0_hw *p_pdm) {
|
||||
|
||||
p_pdm->CON &= ~ LL_PDM_CON_ENABLE(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**********************************************************************************/
|
||||
/* ATTCH FUNCTION */
|
||||
/**********************************************************************************/
|
||||
|
||||
static int32 hgpdm_v0_open(struct pdm_device *pdm, enum pdm_sample_freq freq, enum pdm_channel channel) {
|
||||
|
||||
struct hgpdm_v0 *dev = (struct hgpdm_v0 *)pdm;
|
||||
struct hgpdm_v0_hw *hw = (struct hgpdm_v0_hw *)dev->hw;
|
||||
int32 freq_to_reg = 0;
|
||||
int32 channel_to_reg = 0;
|
||||
|
||||
if (dev->opened) {
|
||||
if (!dev->dsleep) {
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
/* hal enum */
|
||||
freq_to_reg = hgpdm_v0_switch_hal_pdm_sample_freq(freq);
|
||||
channel_to_reg = hgpdm_v0_switch_hal_pdm_channel(channel);
|
||||
|
||||
if ((-1) == freq_to_reg ||
|
||||
(-1) == channel_to_reg) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* make sure the clk */
|
||||
#if 0
|
||||
if (0 != ((peripheral_clock_get(HG_APB0_PT_PDM)) % (freq_to_reg*512))) {
|
||||
return RET_ERR;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* pin config */
|
||||
if (pin_func(dev->dev.dev.dev_id , 1) != RET_OK) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/*
|
||||
* open PDM clk
|
||||
*/
|
||||
sysctrl_pdm_clk_open();
|
||||
/*
|
||||
* clear the regs
|
||||
*/
|
||||
hw->CON = 0;
|
||||
hw->DMACON = 0;
|
||||
hw->DMALEN = 0;
|
||||
hw->DMASTADR = 0;
|
||||
hw->STA = 0xFFFF;
|
||||
|
||||
/* reg config */
|
||||
hgpdm_v0_set_mclk(freq_to_reg);
|
||||
#ifdef TXW80X
|
||||
hw->CON = LL_PDM_CON_WORKMODE(channel_to_reg) | LL_PDM_CON_DECIM(0);
|
||||
#endif
|
||||
#ifdef TXW81X
|
||||
hw->CON = LL_PDM_CON_WORKMODE(channel_to_reg) | LL_PDM_CON_DECIM(1);
|
||||
#endif
|
||||
hw->STA = 3;
|
||||
|
||||
dev->opened = 1;
|
||||
dev->dsleep = 0;
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static int32 hgpdm_v0_read(struct pdm_device *pdm, void* buf, uint32 len) {
|
||||
|
||||
struct hgpdm_v0 *dev = (struct hgpdm_v0 *)pdm;
|
||||
struct hgpdm_v0_hw *hw = (struct hgpdm_v0_hw *)dev->hw;
|
||||
|
||||
if ((!dev->opened) || (dev->dsleep)) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
if(!buf || len == 0)
|
||||
{
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
hw->DMASTADR = (uint32)buf;
|
||||
hw->DMALEN = len;
|
||||
|
||||
hgpdm_v0_enable(hw);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static int32 hgpdm_v0_close(struct pdm_device *pdm) {
|
||||
|
||||
struct hgpdm_v0 *dev = (struct hgpdm_v0 *)pdm;
|
||||
struct hgpdm_v0_hw *hw = (struct hgpdm_v0_hw *)dev->hw;
|
||||
|
||||
if (!dev->opened) {
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* close PDM clk
|
||||
*/
|
||||
sysctrl_pdm_clk_close();
|
||||
|
||||
hgpdm_v0_disable(hw );
|
||||
irq_disable(dev->irq_num );
|
||||
pin_func(dev->dev.dev.dev_id, 0);
|
||||
|
||||
dev->opened = 0;
|
||||
dev->dsleep = 0;
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SLEEP
|
||||
static int32 hgpdm_v0_suspend(struct dev_obj *obj)
|
||||
{
|
||||
struct hgpdm_v0 *dev = (struct hgpdm_v0 *)obj;
|
||||
struct hgpdm_v0_hw *hw = (struct hgpdm_v0_hw *)dev->hw;
|
||||
|
||||
if ((!dev->opened) || (dev->dsleep)) {
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
if (0 > os_mutex_lock(&dev->bp_suspend_lock, 10000)) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Close the PDM
|
||||
*/
|
||||
hw->CON &= ~ BIT(0);
|
||||
|
||||
pin_func(dev->dev.dev.dev_id, 0);
|
||||
|
||||
|
||||
/*
|
||||
* close irq
|
||||
*/
|
||||
irq_disable(dev->irq_num);
|
||||
|
||||
/*
|
||||
* clear pending
|
||||
*/
|
||||
hw->STA = 0xFFFFFFFF;
|
||||
|
||||
os_memset((void *)&dev->bp_regs, 0, sizeof(dev->bp_regs));
|
||||
|
||||
/*
|
||||
* save the reglist
|
||||
*/
|
||||
dev->bp_regs.con = hw->CON;
|
||||
dev->bp_regs.dmastadr = hw->DMASTADR;
|
||||
dev->bp_regs.dmalen = hw->DMALEN;
|
||||
dev->bp_regs.dmacon = hw->DMACON;
|
||||
|
||||
/*
|
||||
* save the irq_hdl created by user
|
||||
*/
|
||||
dev->bp_irq_hdl = dev->irq_hdl;
|
||||
dev->bp_irq_data = dev->irq_data;
|
||||
|
||||
sysctrl_pdm_clk_close();
|
||||
|
||||
dev->dsleep = 1;
|
||||
|
||||
os_mutex_unlock(&dev->bp_suspend_lock);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static int32 hgpdm_v0_resume(struct dev_obj *obj)
|
||||
{
|
||||
struct hgpdm_v0 *dev = (struct hgpdm_v0 *)obj;
|
||||
struct hgpdm_v0_hw *hw = (struct hgpdm_v0_hw *)dev->hw;
|
||||
|
||||
if ((!dev->opened) || (!dev->dsleep)) {
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
if (0 > os_mutex_lock(&dev->bp_resume_lock, 10000)) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* pin config */
|
||||
if (pin_func(dev->dev.dev.dev_id , 1) != RET_OK) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* recovery the PDM clk
|
||||
*/
|
||||
sysctrl_pdm_clk_open();
|
||||
|
||||
|
||||
/*
|
||||
* recovery the reglist from sram
|
||||
*/
|
||||
hw->DMASTADR = dev->bp_regs.dmastadr;
|
||||
hw->DMALEN = dev->bp_regs.dmalen;
|
||||
hw->DMACON = dev->bp_regs.dmacon;
|
||||
hw->CON = dev->bp_regs.con;
|
||||
|
||||
|
||||
/*
|
||||
* recovery the irq handle and data
|
||||
*/
|
||||
dev->irq_hdl = dev->bp_irq_hdl;
|
||||
dev->irq_data = dev->bp_irq_data;
|
||||
|
||||
os_memset((void *)&dev->bp_regs, 0, sizeof(dev->bp_regs));
|
||||
|
||||
/*!
|
||||
* Open the PDM
|
||||
*/
|
||||
hw->CON |= BIT(0);
|
||||
|
||||
/*
|
||||
* open irq
|
||||
*/
|
||||
irq_enable(dev->irq_num);
|
||||
|
||||
dev->dsleep = 0;
|
||||
|
||||
os_mutex_unlock(&dev->bp_resume_lock);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void hgpdm_v0_irq_handler(void *data) {
|
||||
|
||||
struct hgpdm_v0 *dev = (struct hgpdm_v0 *)data;
|
||||
struct hgpdm_v0_hw *hw = (struct hgpdm_v0_hw *)dev->hw;
|
||||
if ((hw->DMACON & LL_PDM_DMACON_HF_IE_EN(1)) &&
|
||||
(hw->STA & LL_PDM_STA_HF_PENDING(1))) {
|
||||
hw->STA |= LL_PDM_STA_HF_PENDING(1);
|
||||
if (dev->irq_hdl) {
|
||||
dev->irq_hdl(PDM_IRQ_FLAG_DMA_HF, dev->irq_data);
|
||||
}
|
||||
}
|
||||
|
||||
if ((hw->DMACON & LL_PDM_DMACON_OV_IE_EN(1)) &&
|
||||
(hw->STA & LL_PDM_STA_OV_PENDING(1))) {
|
||||
hw->STA |= LL_PDM_STA_OV_PENDING(1);
|
||||
if (dev->irq_hdl) {
|
||||
dev->irq_hdl(PDM_IRQ_FLAG_DMA_OV, dev->irq_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int32 hgpdm_v0_request_irq(struct pdm_device *pdm, enum pdm_irq_flag irq_flag, pdm_irq_hdl irq_hdl, uint32 data) {
|
||||
|
||||
struct hgpdm_v0 *dev = (struct hgpdm_v0 *)pdm;
|
||||
struct hgpdm_v0_hw *hw = (struct hgpdm_v0_hw *)dev->hw;
|
||||
|
||||
if ((!dev->opened) || (dev->dsleep)) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
dev->irq_hdl = irq_hdl;
|
||||
dev->irq_data = data;
|
||||
|
||||
request_irq(dev->irq_num, hgpdm_v0_irq_handler, dev);
|
||||
|
||||
if (irq_flag & PDM_IRQ_FLAG_DMA_HF) {
|
||||
hw->DMACON |= LL_PDM_DMACON_HF_IE_EN(1);
|
||||
}
|
||||
|
||||
if (irq_flag & PDM_IRQ_FLAG_DMA_OV) {
|
||||
hw->DMACON |= LL_PDM_DMACON_OV_IE_EN(1);
|
||||
}
|
||||
|
||||
irq_enable(dev->irq_num);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static int32 hgpdm_v0_release_irq(struct pdm_device *pdm, enum pdm_irq_flag irq_flag) {
|
||||
|
||||
struct hgpdm_v0 *dev = (struct hgpdm_v0 *)pdm;
|
||||
struct hgpdm_v0_hw *hw = (struct hgpdm_v0_hw *)dev->hw;
|
||||
|
||||
if ((!dev->opened) || (dev->dsleep)) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
if (irq_flag & PDM_IRQ_FLAG_DMA_HF) {
|
||||
hw->DMACON &= ~ LL_PDM_DMACON_HF_IE_EN(1);
|
||||
}
|
||||
|
||||
if (irq_flag & PDM_IRQ_FLAG_DMA_OV) {
|
||||
hw->DMACON &= ~ LL_PDM_DMACON_OV_IE_EN(1);
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static int32 hgpdm_v0_ioctl(struct pdm_device *pdm, enum pdm_ioctl_cmd ioctl_cmd, uint32 param) {
|
||||
|
||||
int32 ret_val = RET_OK;
|
||||
struct hgpdm_v0 *dev = (struct hgpdm_v0 *)pdm;
|
||||
struct hgpdm_v0_hw *hw = (struct hgpdm_v0_hw *)dev->hw;
|
||||
|
||||
if ((!dev->opened) || (dev->dsleep)) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
switch (ioctl_cmd) {
|
||||
case (PDM_IOCTL_CMD_LR_CHANNEL_INTERCHANGE):
|
||||
ret_val = hgpdm_v0_lr_channel_interchange(hw, param);
|
||||
break;
|
||||
default:
|
||||
ret_val = -ENOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static const struct pdm_hal_ops pdm_ops = {
|
||||
.open = hgpdm_v0_open,
|
||||
.read = hgpdm_v0_read,
|
||||
.close = hgpdm_v0_close,
|
||||
.ioctl = hgpdm_v0_ioctl,
|
||||
.request_irq = hgpdm_v0_request_irq,
|
||||
.release_irq = hgpdm_v0_release_irq,
|
||||
#ifdef CONFIG_SLEEP
|
||||
.ops.suspend = hgpdm_v0_suspend,
|
||||
.ops.resume = hgpdm_v0_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
int32 hgpdm_v0_attach(uint32 dev_id, struct hgpdm_v0 *pdm) {
|
||||
|
||||
pdm->opened = 0;
|
||||
pdm->dsleep = 0;
|
||||
pdm->irq_hdl = NULL;
|
||||
pdm->irq_data = 0;
|
||||
pdm->dev.dev.ops =(const struct devobj_ops *)&pdm_ops;
|
||||
#ifdef CONFIG_SLEEP
|
||||
os_mutex_init(&pdm->bp_suspend_lock);
|
||||
os_mutex_init(&pdm->bp_resume_lock);
|
||||
#endif
|
||||
irq_disable(pdm->irq_num);
|
||||
dev_register(dev_id, (struct dev_obj *)pdm);
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#ifndef _HGPDM_V0_HW_H
|
||||
#define _HGPDM_V0_HW_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***** CON *****/
|
||||
#define LL_PDM_CON_LRSW(n) ((n) << 4)
|
||||
#define LL_PDM_CON_DECIM(n) ((n) << 3)
|
||||
#define LL_PDM_CON_WORKMODE(n) ((n) << 1)
|
||||
#define LL_PDM_CON_ENABLE(n) ((n) << 0)
|
||||
|
||||
/***** DMACON *****/
|
||||
#define LL_PDM_DMACON_OV_IE_EN(n) ((n) << 1)
|
||||
#define LL_PDM_DMACON_HF_IE_EN(n) ((n) << 0)
|
||||
|
||||
/***** STA *****/
|
||||
#define LL_PDM_STA_OV_PENDING(n) ((n) << 1)
|
||||
#define LL_PDM_STA_HF_PENDING(n) ((n) << 0)
|
||||
|
||||
|
||||
struct hgpdm_v0_hw {
|
||||
__IO uint32 CON;
|
||||
__IO uint32 DMACON;
|
||||
__IO uint32 DMASTADR;
|
||||
__IO uint32 RESERVE;
|
||||
__IO uint32 DMALEN;
|
||||
__IO uint32 DMACNT;
|
||||
__IO uint32 STA;
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HGPDM_V0_HW_H */␍
|
||||
Reference in New Issue
Block a user