#define EXT6_AGC_LEVEL_MASK (3)
#define EXT6_AGC_LEVEL(x) (x)
#define UDA1341_L3ADDR 5 //即UDA1341的设备地址,见 uda1341 datasheet p.11.
#define UDA1341_DATA0_ADDR ((UDA1341_L3ADDR << 2) | 0)
#define UDA1341_DATA1_ADDR ((UDA1341_L3ADDR << 2) | 1)
#define UDA1341_STATUS_ADDR ((UDA1341_L3ADDR << 2) | 2)
/* UDA1341 registers */
#define UDA1341_DATA00 0
#define UDA1341_DATA01 1
#define UDA1341_DATA10 2
#define UDA1341_EA000 3
#define UDA1341_EA001 4
#define UDA1341_EA010 5
#define UDA1341_EA100 6
#define UDA1341_EA101 7
#define UDA1341_EA110 8
#define UDA1341_DATA1 9
#define UDA1341_STATUS0 10
#define UDA1341_STATUS1 11
#define UDA1341_REG_NUM 12
#define UDA1341_EXTADDR_PREFIX 0xC0
#define UDA1341_EXTDATA_PREFIX 0xE0
/* 所有寄存器的默认值 */
static const char uda1341_reg[UDA1341_REG_NUM] = {
/* DATA0 */
0x00, 0x40, 0x80,
/* Extended address registers */
0x04, 0x04, 0x04, 0x00, 0x00, 0x00,
/* data1 */
0x00,
/* status regs */
0x00, 0x83,
};
static const char uda1341_reg_addr[UDA1341_REG_NUM] = {
UDA1341_DATA0_ADDR, UDA1341_DATA0_ADDR, UDA1341_DATA0_ADDR,
0, 1, 2, 4, 5, 6, //扩展寄存器的地址EA2,EA1,EA0,见:UDA1341 datasheet “7.21 programming the sound processing and other features”.
UDA1341_DATA1_ADDR,
UDA1341_STATUS_ADDR, UDA1341_STATUS_ADDR
};
static const char uda1341_data_bit[UDA1341_REG_NUM] = {
0 /* VC */, (1<<6)/* BB,TR */, (1<<7)/* PP,DE,MT,M */,
0, 0, 0, 0, 0, 0,//6个扩展寄存器不使用uda1341_data_bit,而是在发送数据时,直接| UDA1341_EXTDATA_PREFIX
0, //data1 用于读数据,用不着
0/* status0 */, (1<<7)/* status1 */,
};
static volatile unsigned int *gpbdat;
static volatile unsigned int *gpbcon;
static int uda1341_soc_probe(struct snd_soc_codec *codec)
{
int ret;
uda1341_init_regs(codec);
return ret;
}
/*
* The codec has no support for reading its registers except for peak level...
*/
static inline unsigned int uda1341_read_reg_cache(struct snd_soc_codec *codec, unsigned int reg)
{
u8 *cache = codec->reg_cache;
if (reg >= UDA1341_REG_NUM)
return -1;
return cache[reg];
}
/*以下有关用GPIO模拟L3接口的函数,参考裸板程序的set_mod、set_clk、set_dat、sendbyte、l3_write */
static void set_mod(int val)
{
if (val)
{
*gpbdat |= (1<<2);
}
else
{
*gpbdat &= ~(1<<2);
}
}
static void set_clk(int val)
{
if (val)
{
*gpbdat |= (1<<4);
}
else
{
*gpbdat &= ~(1<<4);
}
}
static void set_dat(int val)
{
if (val)
{
*gpbdat |= (1<<3);
}
else
{
*gpbdat &= ~(1<<3);
}
}
static void sendbyte(unsigned int byte)
{
int i;
for (i = 0; i < 8; i++) {
set_clk(0);
udelay(1);
set_dat(byte & 1);
udelay(1);
set_clk(1);
udelay(1);
byte >>= 1;
}
}
static void l3_write(u8 addr, u8 data)
{
set_clk(1);
set_dat(1);
set_mod(1);
udelay(1);
set_mod(0);
udelay(1);
sendbyte(addr);
udelay(1);
set_mod(1);
sendbyte(data);
set_clk(1);
set_dat(1);
set_mod(1);
}
static int uda1341_write_reg(struct snd_soc_codec *codec, unsigned int reg, unsigned int value)
{
u8 *cache = codec->reg_cache;
/* 先保存 */
if (reg >= UDA1341_REG_NUM)
return -1;
cache[reg] = value;
/* 再写入硬件 */
/* 对于EA,需要调用2次l3_write */
if ((reg >= UDA1341_EA000) && (reg <= UDA1341_EA110))
{
l3_write(UDA1341_DATA0_ADDR, uda1341_reg_addr[reg] | UDA1341_EXTADDR_PREFIX);
l3_write(UDA1341_DATA0_ADDR, value | UDA1341_EXTDATA_PREFIX);
}
else
{
l3_write(uda1341_reg_addr[reg], value | uda1341_data_bit[reg]);
}
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_uda1341 = {
.probe = uda134x_soc_probe,
// .remove = uda134x_soc_remove,
// .suspend = uda134x_soc_suspend,
// .resume = uda134x_soc_resume,
/* UDA1341的寄存器不支持读操作
* 要知道某个寄存器的当前值,
* 只能在写入时保存起来
*/
.reg_cache_size = sizeof(uda134x_reg),
.reg_word_size = sizeof(u8),
.reg_cache_default = uda134x_reg,
.reg_cache_step = 1,
.read = uda134x_read_reg_cache,
.write = uda134x_write,
// .set_bias_level = uda134x_set_bias_level,
};
//参考: 裸板程序uda1341_init
static void uda1341_init_regs(struct snd_soc_codec *codec)
{
/* GPB 4: L3CLOCK */
/* GPB 3: L3DATA */
/* GPB 2: L3MODE */
*gpbcon &= ~((3<<4) | (3<<6) | (3<<8));
*gpbcon |= ((1<<4) | (1<<6) | (1<<8));
/*
bit[6] : reset
bit[5:4] : system clk frequency, 1:384fs
bit[3~1] : input data format, 0:iis
bit[0] : DC filter, 1:yes
*/
uda1341_write_reg(codec, UDA1341_STATUS0, 0x40 | STAT0_SC_384FS | STAT0_DC_FILTER); // reset uda1341
uda1341_write_reg(codec, UDA1341_STATUS1, STAT1_ADC_ON | STAT1_DAC_ON); //打开ADC和DAC通道
uda1341_write_reg(codec, UDA1341_DATA00, DATA0_VOLUME(0x0)); // maximum volume
uda1341_write_reg(codec, UDA1341_DATA01, DATA1_BASS(0)| DATA1_TREBLE(0));
uda1341_write_reg(codec, UDA1341_DATA10, 0); // not mute
}
static int uda1341_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
/* 根据params的值,设置UDA1341的寄存器
* 比如时钟设置,格式
*/
/* 为了简单, 在uda1341_init_regs里就设置好时钟、格式等参数 */
return 0;
}
四、参考资料
1. 韦东山 嵌入式Linux视频教程_3期项目实战之ALSA声卡:第2课第1.1_17节_ALSA声卡09_从零编写之参数设置
2. DroidPhone 《Linux ALSA 声卡驱动》
3. gliethttp 在uda1341的i2s中256fs,384fs和512fs表示的实际意义和如何auto智能选择
上一篇:韦东山嵌入式Linux_3期之USB摄像头监控_手机App增加录像功能(二)
下一篇:ALSA声卡_从零编写之框架(基于优龙FS2410开发板,UDA1341声卡)
推荐阅读最新更新时间:2024-11-01 22:13
设计资源 培训 开发板 精华推荐
- LT8609EMSE 3.3V 降压型稳压器的典型应用电路
- TCR5SB34U、200mA、3.4V输出电压CMOS低压降稳压器的典型应用
- NCP-NCV51561D2PAK7LGEVB:隔离式双通道栅极驱动器NCP/NCV51561 EVB OPN
- DC1830A-B,用于 LTC4000EUFD 电池充电器控制器的演示板(无 PowerPath 管理器)
- 无线输电钢铁侠卡片
- 使用 ON Semiconductor 的 LV4900H 的参考设计
- LT8570EDD-1 1.5MHz、5 至 12V 输出升压转换器的典型应用
- DC1505A,演示板 LTC4360 过压保护控制器
- EVAL-ADM1175EBZ,用于中心局交换机 ADM1175 热插拔控制器的评估套件
- EVAL-ADF7012DB3,ADF7012 ISM 频段发射器评估板,单芯片低功耗 UHF 发射器