909 lines
22 KiB
C
909 lines
22 KiB
C
/**
|
|
* @file hgi2s_v0.c
|
|
* @author bxd
|
|
* @brief iis
|
|
* @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/string.h"
|
|
#include "osal/semaphore.h"
|
|
#include "osal/mutex.h"
|
|
#include "hal/i2s.h"
|
|
#include "dev/i2s/hgi2s_v0.h"
|
|
#include "hgi2s_v0_hw.h"
|
|
|
|
|
|
#define __OVER_SAMPPLE_RATE (512)
|
|
|
|
struct __iis_cfg {
|
|
uint32 mclk_div;
|
|
uint32 baud_div;
|
|
uint32 wscon_div;
|
|
};
|
|
|
|
const struct __iis_cfg iis_cfg_8k[] = {
|
|
|
|
/*!
|
|
* over_sample: 512.000
|
|
* sample_rate: 8000.000
|
|
* 8 bit
|
|
*/
|
|
//mclk_rate:4.103MHz, bclk_rate:128.205KHz, sample_rate:8012.821Hz, error_rate:1602.56ppm,mclk = 116, baud = 15, wscon = 7
|
|
{
|
|
.mclk_div = 116,
|
|
.baud_div = 15,
|
|
.wscon_div = 7,
|
|
},
|
|
|
|
/*!
|
|
* over_sample: 512.000
|
|
* sample_rate: 8000.000
|
|
* 16 bit
|
|
*/
|
|
//mclk_rate:4.103MHz, bclk_rate:256.410KHz, sample_rate:8012.821Hz, error_rate:1602.56ppm,mclk = 116, baud = 7, wscon = 15
|
|
{
|
|
.mclk_div = 116,
|
|
.baud_div = 7,
|
|
.wscon_div = 15,
|
|
},
|
|
|
|
/*!
|
|
* over_sample: 768.000
|
|
* sample_rate: 8000.000
|
|
* 24 bit
|
|
*/
|
|
//mclk_rate:6.154MHz, bclk_rate:384.615KHz, sample_rate:8012.821Hz, error_rate:1602.56ppm,mclk = 77, baud = 7, wscon = 23
|
|
{
|
|
.mclk_div = 77,
|
|
.baud_div = 7,
|
|
.wscon_div = 23,
|
|
}
|
|
};
|
|
|
|
const struct __iis_cfg iis_cfg_16k[] = {
|
|
|
|
/*!
|
|
* over_sample: 256.000
|
|
* sample_rate: 16000.000
|
|
* 8 bit
|
|
*/
|
|
//mclk_rate:4.103MHz, bclk_rate:256.410KHz, sample_rate:16025.641Hz, error_rate:1602.56ppm,mclk = 116, baud = 7, wscon = 7
|
|
{
|
|
.mclk_div = 116,
|
|
.baud_div = 7,
|
|
.wscon_div = 7,
|
|
},
|
|
|
|
/*!
|
|
* over_sample: 256.000
|
|
* sample_rate: 16000.000
|
|
* 16 bit
|
|
*/
|
|
//mclk_rate:4.103MHz, bclk_rate:512.821KHz, sample_rate:16025.641Hz, error_rate:1602.56ppm,mclk = 116, baud = 3, wscon = 15
|
|
{
|
|
.mclk_div = 116,
|
|
.baud_div = 3,
|
|
.wscon_div = 15,
|
|
},
|
|
|
|
/*!
|
|
* over_sample: 384.000
|
|
* sample_rate: 16000.000
|
|
* 24 bit
|
|
*/
|
|
//mclk_rate:6.154MHz, bclk_rate:769.231KHz, sample_rate:16025.641Hz, error_rate:1602.56ppm,mclk = 77, baud = 3, wscon = 23
|
|
{
|
|
.mclk_div = 77,
|
|
.baud_div = 3,
|
|
.wscon_div = 23,
|
|
}
|
|
|
|
};
|
|
|
|
const struct __iis_cfg iis_cfg_44_1k[] = {
|
|
|
|
/*!
|
|
* over_sample: 128.000
|
|
* sample_rate: 44100.000
|
|
* 16 bit
|
|
*/
|
|
//mclk_rate:5.647MHz, bclk_rate:705.882KHz, sample_rate:44117.647Hz, error_rate:400.16ppm,mclk = 84, baud = 3, wscon = 7
|
|
{
|
|
.mclk_div = 84,
|
|
.baud_div = 3,
|
|
.wscon_div = 7,
|
|
},
|
|
|
|
/*!
|
|
* over_sample: 128.000
|
|
* sample_rate: 44100.000
|
|
* 16 bit
|
|
*/
|
|
//mclk_rate:5.647MHz, bclk_rate:1411.765KHz, sample_rate:44117.647Hz, error_rate:400.16ppm,mclk = 84, baud = 1, wscon = 15
|
|
{
|
|
.mclk_div = 84,
|
|
.baud_div = 1,
|
|
.wscon_div = 15,
|
|
},
|
|
|
|
/*!
|
|
* over_sample: 128.000
|
|
* sample_rate: 44100.000
|
|
* 24 bit
|
|
*/
|
|
//no support
|
|
|
|
};
|
|
|
|
const struct __iis_cfg iis_cfg_48k[] = {
|
|
|
|
/*!
|
|
* over_sample: 256.000
|
|
* sample_rate: 48000.000
|
|
* 8 bit
|
|
*/
|
|
//mclk_rate:12.308MHz, bclk_rate:769.231KHz, sample_rate:48076.923Hz, error_rate:1602.56ppm,mclk = 38, baud = 7, wscon = 7
|
|
{
|
|
.mclk_div = 38,
|
|
.baud_div = 7,
|
|
.wscon_div = 7,
|
|
},
|
|
|
|
|
|
/*!
|
|
* over_sample: 768.000
|
|
* sample_rate: 48000.000
|
|
* 16 bit
|
|
*/
|
|
//mclk_rate:36.923MHz, bclk_rate:1538.462KHz, sample_rate:48076.923Hz, error_rate:1602.56ppm,mclk = 12, baud = 11, wscon = 15
|
|
{
|
|
.mclk_div = 12,
|
|
.baud_div = 11,
|
|
.wscon_div = 15,
|
|
},
|
|
|
|
/*!
|
|
* over_sample: 768.000
|
|
* sample_rate: 48000.000
|
|
* 16 bit
|
|
*/
|
|
//mclk_rate:36.923MHz, bclk_rate:2307.692KHz, sample_rate:48076.923Hz, error_rate:1602.56ppm,mclk = 12, baud = 7, wscon = 23
|
|
{
|
|
.mclk_div = 12,
|
|
.baud_div = 7,
|
|
.wscon_div = 23,
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**********************************************************************************/
|
|
/* I2S LOW LAYER FUNCTION */
|
|
/**********************************************************************************/
|
|
static int32 hgi2s_v0_switch_hal_i2s_mode(enum i2s_mode mode) {
|
|
|
|
switch (mode) {
|
|
case (I2S_MODE_MASTER ):
|
|
return 0;
|
|
break;
|
|
case (I2S_MODE_SLAVE ):
|
|
return 1;
|
|
break;
|
|
default:
|
|
return -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int32 hgi2s_v0_switch_hal_i2s_channel(enum i2s_channel channel) {
|
|
|
|
switch (channel) {
|
|
case (I2S_CHANNEL_MONO ):
|
|
return 1;
|
|
break;
|
|
case (I2S_CHANNEL_STEREO):
|
|
return 0;
|
|
break;
|
|
default:
|
|
return -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int32 hgi2s_v0_switch_hal_i2s_sample_bits(enum i2s_sample_bits bits) {
|
|
|
|
switch (bits) {
|
|
case (I2S_SAMPLE_BITS_8BITS ):
|
|
return 8;
|
|
break;
|
|
case (I2S_SAMPLE_BITS_16BITS):
|
|
return 16;
|
|
break;
|
|
case (I2S_SAMPLE_BITS_24BITS):
|
|
return 24;
|
|
break;
|
|
default:
|
|
return -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int32 hgi2s_v0_switch_hal_i2s_data_fmt(enum i2s_data_fmt data_fmt) {
|
|
|
|
switch (data_fmt) {
|
|
case (I2S_DATA_FMT_I2S):
|
|
return 0;
|
|
break;
|
|
case (I2S_DATA_FMT_LSB):
|
|
return 1;
|
|
break;
|
|
case (I2S_DATA_FMT_MSB):
|
|
return 2;
|
|
break;
|
|
case (I2S_DATA_FMT_PCM):
|
|
return 3;
|
|
break;
|
|
default:
|
|
return -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static const struct __iis_cfg* hgi2s_v0_switch_hal_i2s_sample_freq(enum i2s_sample_freq frequency, enum i2s_sample_bits bits)
|
|
{
|
|
const struct __iis_cfg *p_iis_cfg = NULL;
|
|
int8 index = -1;
|
|
|
|
if (I2S_SAMPLE_BITS_8BITS ==bits) {index=0;}
|
|
if (I2S_SAMPLE_BITS_16BITS==bits) {index=1;}
|
|
if (I2S_SAMPLE_BITS_24BITS==bits) {index=2;}
|
|
|
|
switch (frequency) {
|
|
case (I2S_SAMPLE_FREQ_8K):
|
|
p_iis_cfg = iis_cfg_8k;
|
|
break;
|
|
case (I2S_SAMPLE_FREQ_16K):
|
|
p_iis_cfg = iis_cfg_16k;
|
|
break;
|
|
case (I2S_SAMPLE_FREQ_44_1K):
|
|
p_iis_cfg = iis_cfg_44_1k;
|
|
if (I2S_SAMPLE_BITS_24BITS==bits) {
|
|
index=-1; p_iis_cfg=NULL;
|
|
os_printf("iis info: no support 44.1k, 24bit\r\n");
|
|
}
|
|
break;
|
|
case (I2S_SAMPLE_FREQ_48K ):
|
|
p_iis_cfg = iis_cfg_48k;
|
|
break;
|
|
default:
|
|
return NULL;
|
|
break;
|
|
}
|
|
|
|
if ((index==-1) || (p_iis_cfg==NULL)) {
|
|
return NULL;
|
|
} else {
|
|
return &p_iis_cfg[index];
|
|
}
|
|
|
|
}
|
|
|
|
static inline void hgi2s_v0_set_mclk(struct hgi2s_v0_hw *p_i2s, uint32 mclk_div) {
|
|
//uint32 mclk_div = 0;
|
|
|
|
//IIS0
|
|
if (IIS0_BASE == (uint32)p_i2s) {
|
|
SYSCTRL_REG_OPT(
|
|
SYSCTRL->SYS_CON3 = (SYSCTRL->SYS_CON3 & ~(0x01 << 28)) | (0 << 28);
|
|
);
|
|
|
|
#if 0
|
|
/* i2s module clk use pll0 & pll1 */
|
|
os_printf("iis0 pll clk:%d\r\n", peripheral_clock_get(HG_APB0_PT_IIS0));
|
|
os_printf("iis1 pll clk:%d\r\n", peripheral_clock_get(HG_APB0_PT_IIS0));
|
|
mclk_div = ((peripheral_clock_get(HG_APB0_PT_IIS0)+((freq*__OVER_SAMPPLE_RATE)/2)) / (freq*__OVER_SAMPPLE_RATE));
|
|
#endif
|
|
|
|
#if 0
|
|
/* FPGA: 96MHz */
|
|
mclk_div = (96000000 / (freq*256));
|
|
#endif
|
|
|
|
SYSCTRL_REG_OPT(
|
|
SYSCTRL->CLK_CON0 = (SYSCTRL->CLK_CON0 & ~(0x7f << 16)) | ((mclk_div) << 16);
|
|
);
|
|
}
|
|
//IIS1
|
|
else if(IIS1_BASE == (uint32)p_i2s){
|
|
SYSCTRL_REG_OPT(
|
|
SYSCTRL->SYS_CON3 = (SYSCTRL->SYS_CON3 & ~(0x01 << 29)) | (0 << 29);
|
|
);
|
|
|
|
#if 0
|
|
/* i2s module clk use pll0 & pll1 */
|
|
mclk_div = (peripheral_clock_get(HG_APB0_PT_IIS1) / (freq*256));
|
|
#endif
|
|
|
|
#if 0
|
|
/* FPGA: 96MHz */
|
|
mclk_div = (96000000 / (freq*256));
|
|
#endif
|
|
|
|
SYSCTRL_REG_OPT(
|
|
SYSCTRL->CLK_CON0 = (SYSCTRL->CLK_CON0 & ~(0x7f << 23)) | ((mclk_div) << 23);
|
|
);
|
|
}
|
|
}
|
|
|
|
static inline void hgi2s_v0_enable(struct hgi2s_v0_hw *p_i2s) {
|
|
p_i2s->CON |= LL_I2S_CON_ENABLE(1);
|
|
}
|
|
|
|
static inline void hgi2s_v0_disable(struct hgi2s_v0_hw *p_i2s) {
|
|
p_i2s->CON &= ~ LL_I2S_CON_ENABLE(1);
|
|
}
|
|
|
|
static inline void hgi2s_v0_set_tx(struct hgi2s_v0_hw *p_i2s) {
|
|
p_i2s->CON |= LL_I2S_CON_WORKMODE(1);
|
|
}
|
|
|
|
static inline void hgi2s_v0_set_rx(struct hgi2s_v0_hw *p_i2s) {
|
|
p_i2s->CON &= ~ LL_I2S_CON_WORKMODE(1);
|
|
}
|
|
|
|
static int32 hgi2s_v0_set_wsclk_pol(struct hgi2s_v0_hw *p_i2s, uint32 value) {
|
|
|
|
hgi2s_v0_disable(p_i2s);
|
|
|
|
if (value) {
|
|
p_i2s->CON |= LL_I2S_CON_WSPOL(1);
|
|
} else {
|
|
p_i2s->CON &= ~ LL_I2S_CON_WSPOL(1);
|
|
}
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
static int32 hgi2s_v0_set_sample_bits(struct hgi2s_v0_hw *p_i2s, enum i2s_sample_bits bits) {
|
|
|
|
int32 i2s_sample_bits_to_reg = 0;
|
|
|
|
i2s_sample_bits_to_reg = hgi2s_v0_switch_hal_i2s_sample_bits(bits);
|
|
|
|
if ((-1) == i2s_sample_bits_to_reg) {
|
|
return RET_ERR;
|
|
}
|
|
|
|
hgi2s_v0_disable(p_i2s);
|
|
|
|
p_i2s->BIT_SET = i2s_sample_bits_to_reg;
|
|
p_i2s->WS_CON = i2s_sample_bits_to_reg;
|
|
p_i2s->BAUD = (64 / i2s_sample_bits_to_reg) - 1;
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
static int32 hgi2s_v0_set_channel(struct hgi2s_v0_hw *p_i2s, enum i2s_channel channel) {
|
|
|
|
int32 i2s_channel_to_reg = 0;
|
|
|
|
i2s_channel_to_reg = hgi2s_v0_switch_hal_i2s_channel(channel);
|
|
|
|
if ((-1) == i2s_channel_to_reg) {
|
|
return RET_ERR;
|
|
}
|
|
|
|
hgi2s_v0_disable(p_i2s);
|
|
|
|
p_i2s->CON = (p_i2s->CON &~ LL_I2S_CON_MONO(0x3)) | LL_I2S_CON_MONO(i2s_channel_to_reg);
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
static int32 hgi2s_v0_set_data_fmt(struct hgi2s_v0_hw *p_i2s, enum i2s_data_fmt data_fmt) {
|
|
|
|
int32 i2s_data_fmt_to_reg = 0;
|
|
|
|
i2s_data_fmt_to_reg = hgi2s_v0_switch_hal_i2s_data_fmt(data_fmt);
|
|
|
|
if ((-1) == i2s_data_fmt_to_reg) {
|
|
return RET_ERR;
|
|
}
|
|
|
|
hgi2s_v0_disable(p_i2s);
|
|
|
|
p_i2s->CON = (p_i2s->CON &~ LL_I2S_CON_FRMT(0x3)) | LL_I2S_CON_FRMT(i2s_data_fmt_to_reg);
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
static int32 hgi2s_v0_set_debounce(struct hgi2s_v0_hw *p_i2s, uint32 enable) {
|
|
|
|
hgi2s_v0_disable(p_i2s);
|
|
|
|
if (!enable) {
|
|
p_i2s->CON |= LL_I2S_CON_BCLKDBSBPS(1) | LL_I2S_CON_RXDBSBPS(1) | LL_I2S_CON_WSCLKDBSBPS(1);
|
|
} else {
|
|
p_i2s->CON &= ~(LL_I2S_CON_BCLKDBSBPS(1) | LL_I2S_CON_RXDBSBPS(1) | LL_I2S_CON_WSCLKDBSBPS(1));
|
|
}
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
static int32 hgi2s_v0_set_duplex(struct hgi2s_v0 *dev, uint32 enable) {
|
|
|
|
if (enable) {
|
|
dev->duplex_en = 1;
|
|
} else {
|
|
dev->duplex_en = 0;
|
|
}
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
/**********************************************************************************/
|
|
/* I2S ATTCH FUNCTION */
|
|
/**********************************************************************************/
|
|
int32 hgi2s_v0_open(struct i2s_device *i2s, enum i2s_mode mode, enum i2s_sample_freq frequency, enum i2s_sample_bits bits)
|
|
{
|
|
|
|
struct hgi2s_v0 *dev = (struct hgi2s_v0*)i2s;
|
|
struct hgi2s_v0_hw *hw = (struct hgi2s_v0_hw *)dev->hw;
|
|
const struct __iis_cfg *p_iis_cfg = NULL;
|
|
uint32 i2s_reg_con = 0;
|
|
int32 i2s_mode_to_reg = 0;
|
|
int32 i2s_channel_to_reg = 0;
|
|
int32 i2s_sample_bits_to_reg = 0;
|
|
int32 i2s_data_fmt_to_reg = 0;
|
|
//int32 i2s_sample_freq_to_reg = 0;
|
|
|
|
if (dev->opened) {
|
|
if (!dev->dsleep) {
|
|
return -EBUSY;
|
|
}
|
|
}
|
|
|
|
/* hal enum */
|
|
i2s_mode_to_reg = hgi2s_v0_switch_hal_i2s_mode(mode );
|
|
i2s_channel_to_reg = hgi2s_v0_switch_hal_i2s_channel(I2S_CHANNEL_STEREO);
|
|
i2s_data_fmt_to_reg = hgi2s_v0_switch_hal_i2s_data_fmt(I2S_DATA_FMT_I2S );
|
|
i2s_sample_bits_to_reg = hgi2s_v0_switch_hal_i2s_sample_bits(bits );
|
|
p_iis_cfg = hgi2s_v0_switch_hal_i2s_sample_freq(frequency,bits);
|
|
|
|
if (((-1) == i2s_mode_to_reg ) || \
|
|
((-1) == i2s_channel_to_reg ) || \
|
|
((-1) == i2s_data_fmt_to_reg ) || \
|
|
((-1) == i2s_sample_bits_to_reg) || \
|
|
((NULL) == p_iis_cfg)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
#if 0
|
|
/* make sure the sys_clk */
|
|
if (0 != ((peripheral_clock_get(HG_APB0_PT_IIS0)*2) % (i2s_sample_freq_to_reg * 256))) {
|
|
return RET_ERR;
|
|
}
|
|
#endif
|
|
|
|
/* pin config */
|
|
if (pin_func(dev->dev.dev.dev_id , 1) != RET_OK) {
|
|
return RET_ERR;
|
|
}
|
|
|
|
/*
|
|
* open I2S clk
|
|
*/
|
|
if (IIS0_BASE == (uint32)hw) {
|
|
sysctrl_iis0_clk_open();
|
|
} else if (IIS1_BASE == (uint32)hw) {
|
|
sysctrl_iis1_clk_open();
|
|
}
|
|
|
|
/*
|
|
* clear the regs
|
|
*/
|
|
hw->BAUD = 0;
|
|
hw->BIT_SET = 0;
|
|
hw->CON = 0;
|
|
hw->DMA_LEN = 0;
|
|
hw->DMA_STADR = 0;
|
|
hw->WS_CON = 0;
|
|
hw->STA = 0xFFFF;
|
|
|
|
/* reg config */
|
|
i2s_reg_con = hw->CON;
|
|
|
|
i2s_reg_con = LL_I2S_CON_MODE(i2s_mode_to_reg ) |
|
|
LL_I2S_CON_MONO(i2s_channel_to_reg ) |
|
|
LL_I2S_CON_MCLK_OE(1 ) | /* open mclk to io */
|
|
LL_I2S_CON_WSPOL(0 ) |
|
|
LL_I2S_CON_BCKPOL(0 ) |
|
|
LL_I2S_CON_FRMT(i2s_data_fmt_to_reg) ;
|
|
|
|
if (mode == I2S_MODE_SLAVE) {
|
|
i2s_reg_con |= (LL_I2S_CON_BCLKDBSBPS(0) | LL_I2S_CON_RXDBSBPS(0) | LL_I2S_CON_WSCLKDBSBPS(0));
|
|
} else {
|
|
//close debounce
|
|
i2s_reg_con |= (LL_I2S_CON_BCLKDBSBPS(1) | LL_I2S_CON_RXDBSBPS(1) | LL_I2S_CON_WSCLKDBSBPS(1));
|
|
}
|
|
|
|
hw->CON = i2s_reg_con;
|
|
hw->WS_CON = p_iis_cfg->wscon_div;
|
|
hw->BAUD = p_iis_cfg->baud_div;
|
|
hw->BIT_SET = i2s_sample_bits_to_reg - 1;
|
|
|
|
if (mode == I2S_MODE_SLAVE) {
|
|
hgi2s_v0_set_mclk(hw, 5);
|
|
} else {
|
|
hgi2s_v0_set_mclk(hw, p_iis_cfg->mclk_div);
|
|
}
|
|
|
|
|
|
dev->opened = 1;
|
|
dev->duplex_en = 0;
|
|
dev->dsleep = 0;
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
int32 hgi2s_v0_close(struct i2s_device *i2s) {
|
|
|
|
struct hgi2s_v0 *dev = (struct hgi2s_v0*)i2s;
|
|
struct hgi2s_v0_hw *hw = (struct hgi2s_v0_hw *)dev->hw;
|
|
|
|
if (!dev->opened) {
|
|
return RET_OK;
|
|
}
|
|
|
|
/*
|
|
* close IIS clk
|
|
*/
|
|
if (IIS0_BASE == (uint32)hw) {
|
|
sysctrl_iis0_clk_close();
|
|
} else if (IIS1_BASE == (uint32)hw) {
|
|
sysctrl_iis1_clk_close();
|
|
}
|
|
|
|
|
|
irq_disable(dev->irq_num );
|
|
pin_func(dev->dev.dev.dev_id, 0);
|
|
hgi2s_v0_disable(hw );
|
|
|
|
dev->opened = 0;
|
|
dev->duplex_en = 0;
|
|
dev->dsleep = 0;
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
int32 hgi2s_v0_write(struct i2s_device *i2s, const void* buf, uint32 len) {
|
|
|
|
struct hgi2s_v0 *dev = (struct hgi2s_v0*)i2s;
|
|
struct hgi2s_v0_hw *hw = (struct hgi2s_v0_hw *)dev->hw;
|
|
uint32 len_to_reg = 0;
|
|
|
|
if ((!dev->opened) || (dev->dsleep)) {
|
|
return RET_ERR;
|
|
}
|
|
|
|
len_to_reg = len;
|
|
|
|
hw->DMA_STADR = (uint32)buf;
|
|
hw->DMA_LEN = len_to_reg;
|
|
|
|
hgi2s_v0_set_tx(hw);
|
|
|
|
if (!dev->duplex_en) {
|
|
hgi2s_v0_enable(hw);
|
|
}
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
int32 hgi2s_v0_read(struct i2s_device *i2s, void* buf, uint32 len) {
|
|
|
|
struct hgi2s_v0 *dev = (struct hgi2s_v0*)i2s;
|
|
struct hgi2s_v0_hw *hw = (struct hgi2s_v0_hw *)dev->hw;
|
|
uint32 len_to_reg = 0;
|
|
|
|
if ((!dev->opened) || (dev->dsleep)) {
|
|
return RET_ERR;
|
|
}
|
|
|
|
len_to_reg = len;
|
|
|
|
hw->DMA_STADR = (uint32)buf;
|
|
hw->DMA_LEN = len_to_reg;
|
|
|
|
hgi2s_v0_set_rx(hw);
|
|
|
|
if (!dev->duplex_en) {
|
|
hgi2s_v0_enable(hw);
|
|
}
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
int32 hgi2s_v0_ioctl(struct i2s_device *i2s, uint32 cmd, uint32 param) {
|
|
|
|
int32 ret_val = RET_OK;
|
|
struct hgi2s_v0 *dev = (struct hgi2s_v0*)i2s;
|
|
struct hgi2s_v0_hw *hw = (struct hgi2s_v0_hw *)dev->hw;
|
|
|
|
if ((!dev->opened) || (dev->dsleep)) {
|
|
return RET_ERR;
|
|
}
|
|
|
|
switch(cmd) {
|
|
case (I2S_IOCTL_CMD_SET_WSCLK_POL):
|
|
ret_val = hgi2s_v0_set_wsclk_pol(hw , param);
|
|
break;
|
|
case (I2S_IOCTL_CMD_SET_SAMPLE_BITS):
|
|
ret_val = hgi2s_v0_set_sample_bits(hw, param);
|
|
break;
|
|
case (I2S_IOCTL_CMD_SET_CHANNEL):
|
|
ret_val = hgi2s_v0_set_channel(hw , param);
|
|
break;
|
|
case (I2S_IOCTL_CMD_SET_DATA_FMT):
|
|
ret_val = hgi2s_v0_set_data_fmt(hw , param);
|
|
break;
|
|
case (I2S_IOCTL_CMD_SET_DEBOUNCE):
|
|
ret_val = hgi2s_v0_set_debounce(hw , param);
|
|
break;
|
|
case (I2S_IOCTL_CMD_SET_DUPLEX):
|
|
ret_val = hgi2s_v0_set_duplex(dev , param);
|
|
break;
|
|
default:
|
|
ret_val = -ENOTSUPP;
|
|
break;
|
|
}
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
#ifdef CONFIG_SLEEP
|
|
static int32 hgi2s_v0_suspend(struct dev_obj *obj)
|
|
{
|
|
struct hgi2s_v0 *dev = (struct hgi2s_v0*)obj;
|
|
struct hgi2s_v0_hw *hw = (struct hgi2s_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 IIS
|
|
*/
|
|
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.bit_set = hw->BIT_SET;
|
|
dev->bp_regs.baud = hw->BAUD;
|
|
dev->bp_regs.ws_con = hw->WS_CON;
|
|
dev->bp_regs.dma_stadr = hw->DMA_STADR;
|
|
dev->bp_regs.dma_len = hw->DMA_LEN;
|
|
|
|
/*
|
|
* save the irq_hdl created by user
|
|
*/
|
|
dev->bp_irq_hdl = dev->irq_hdl;
|
|
dev->bp_irq_data = dev->irq_data;
|
|
|
|
/*
|
|
* close IIS clk
|
|
*/
|
|
if (IIS0_BASE == (uint32)hw) {
|
|
sysctrl_iis0_clk_close();
|
|
} else if (IIS1_BASE == (uint32)hw) {
|
|
sysctrl_iis1_clk_close();
|
|
}
|
|
|
|
dev->dsleep = 1;
|
|
|
|
os_mutex_unlock(&dev->bp_suspend_lock);
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
static int32 hgi2s_v0_resume(struct dev_obj *obj)
|
|
{
|
|
struct hgi2s_v0 *dev = (struct hgi2s_v0*)obj;
|
|
struct hgi2s_v0_hw *hw = (struct hgi2s_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;
|
|
}
|
|
|
|
|
|
/*
|
|
* open I2S clk
|
|
*/
|
|
if (IIS0_BASE == (uint32)hw) {
|
|
sysctrl_iis0_clk_open();
|
|
} else if (IIS1_BASE == (uint32)hw) {
|
|
sysctrl_iis1_clk_open();
|
|
}
|
|
|
|
|
|
/*
|
|
* recovery the reglist from sram
|
|
*/
|
|
hw->BIT_SET = dev->bp_regs.bit_set;
|
|
hw->BAUD = dev->bp_regs.baud;
|
|
hw->WS_CON = dev->bp_regs.ws_con;
|
|
hw->DMA_STADR = dev->bp_regs.dma_stadr;
|
|
hw->DMA_LEN = dev->bp_regs.dma_len;
|
|
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 IIS
|
|
*/
|
|
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
|
|
|
|
/* interrupt handler */
|
|
static void hgi2s_v0_irq_handler(void *data) {
|
|
|
|
struct hgi2s_v0 *dev = (struct hgi2s_v0 *)data;
|
|
struct hgi2s_v0_hw *hw = (struct hgi2s_v0_hw *)dev->hw;
|
|
|
|
if ((hw->CON & LL_I2S_CON_HF_PEND_IE(1)) && (hw->STA & LL_I2S_STA_DMA_HF_PENGING(1))) {
|
|
hw->STA = LL_I2S_STA_DMA_HF_PENGING(1);
|
|
if (dev->irq_hdl) {
|
|
dev->irq_hdl(I2S_IRQ_FLAG_HALF, dev->irq_data);
|
|
}
|
|
}
|
|
|
|
if ((hw->CON & LL_I2S_CON_OV_PEND_IE(1)) && (hw->STA & LL_I2S_STA_DMA_OV_PENGING(1))) {
|
|
hw->STA = LL_I2S_STA_DMA_OV_PENGING(1);
|
|
if (dev->irq_hdl) {
|
|
dev->irq_hdl(I2S_IRQ_FLAG_FULL, dev->irq_data);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* request interrupt */
|
|
int32 hgi2s_v0_request_irq(struct i2s_device *i2s, uint32 irq_flag, i2s_irq_hdl irqhdl, uint32 irq_data) {
|
|
|
|
struct hgi2s_v0 *dev = (struct hgi2s_v0 *)i2s;
|
|
struct hgi2s_v0_hw *hw = (struct hgi2s_v0_hw *)dev->hw;
|
|
|
|
if ((!dev->opened) || (dev->dsleep)) {
|
|
return RET_ERR;
|
|
}
|
|
|
|
dev->irq_hdl = irqhdl;
|
|
dev->irq_data = irq_data;
|
|
request_irq(dev->irq_num, hgi2s_v0_irq_handler, dev);
|
|
|
|
|
|
if (irq_flag & I2S_IRQ_FLAG_HALF) {
|
|
hw->CON |= LL_I2S_CON_HF_PEND_IE(1);
|
|
}
|
|
|
|
if (irq_flag & I2S_IRQ_FLAG_FULL) {
|
|
hw->CON |= LL_I2S_CON_OV_PEND_IE(1);
|
|
}
|
|
|
|
irq_enable(dev->irq_num);
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
int32 hgi2s_v0_release_irq(struct i2s_device *i2s, uint32 irq_flag) {
|
|
|
|
struct hgi2s_v0 *dev = (struct hgi2s_v0 *)i2s;
|
|
struct hgi2s_v0_hw *hw = (struct hgi2s_v0_hw *)dev->hw;
|
|
|
|
if ((!dev->opened) || (dev->dsleep)) {
|
|
return RET_ERR;
|
|
}
|
|
|
|
if (irq_flag & I2S_IRQ_FLAG_HALF) {
|
|
hw->CON &= ~ LL_I2S_CON_HF_PEND_IE(1);
|
|
}
|
|
|
|
if (irq_flag & I2S_IRQ_FLAG_FULL) {
|
|
hw->CON &= ~ LL_I2S_CON_OV_PEND_IE(1);
|
|
}
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
static const struct i2s_hal_ops i2s_v0_ops = {
|
|
.open = hgi2s_v0_open,
|
|
.close = hgi2s_v0_close,
|
|
.write = hgi2s_v0_write,
|
|
.read = hgi2s_v0_read,
|
|
.request_irq = hgi2s_v0_request_irq,
|
|
.release_irq = hgi2s_v0_release_irq,
|
|
.ioctl = hgi2s_v0_ioctl,
|
|
#ifdef CONFIG_SLEEP
|
|
.ops.suspend = hgi2s_v0_suspend,
|
|
.ops.resume = hgi2s_v0_resume,
|
|
#endif
|
|
};
|
|
|
|
int32 hgi2s_v0_attach(uint32 dev_id, struct hgi2s_v0 *i2s) {
|
|
i2s->opened = 0;
|
|
i2s->dsleep = 0;
|
|
i2s->irq_hdl = NULL;
|
|
i2s->irq_data = 0;
|
|
i2s->duplex_en = 0;
|
|
i2s->dev.dev.ops = (const struct devobj_ops *)&i2s_v0_ops;
|
|
#ifdef CONFIG_SLEEP
|
|
os_mutex_init(&i2s->bp_suspend_lock);
|
|
os_mutex_init(&i2s->bp_resume_lock);
|
|
#endif
|
|
irq_disable(i2s->irq_num);
|
|
dev_register(dev_id, (struct dev_obj *)i2s);
|
|
return RET_OK;
|
|
}
|
|
|
|
|