You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

264 lines
4.2 KiB

#include <stdio.h>
#include <stdlib.h>
#include "stm32f4xx.h"
#include "cmd.h"
#include "gpio.h"
#include "iic.h"
#include "i2c.h"
#define WM8978_ADDR (0x1A)
#define WADDR (0x34)
static union {
iic_t iic;
i2c_t i2c;
void *raw;
} _i2c;
static int (*_write)(uint8_t reg, uint8_t val);
static uint16_t __regs[58]= {
0X0000,0X0000,0X0000,0X0000,0X0050,0X0000,0X0140,0X0000,
0X0000,0X0000,0X0000,0X00FF,0X00FF,0X0000,0X0100,0X00FF,
0X00FF,0X0000,0X012C,0X002C,0X002C,0X002C,0X002C,0X0000,
0X0032,0X0000,0X0000,0X0000,0X0000,0X0000,0X0000,0X0000,
0X0038,0X000B,0X0032,0X0000,0X0008,0X000C,0X0093,0X00E9,
0X0000,0X0000,0X0000,0X0000,0X0003,0X0010,0X0010,0X0100,
0X0100,0X0002,0X0001,0X0001,0X0039,0X0039,0X0039,0X0039,
0X0001,0X0001
};
uint16_t wm8978_read(uint8_t reg)
{
return __regs[reg];
}
static int _iic_write(uint8_t regr, uint8_t regv)
{
if (iic_start(_i2c.iic)) {
printf("start\r\n");
return -1;
}
if (iic_send_slave_address(_i2c.iic, WADDR)) {
printf("slave\r\n");
return -2;
}
if (iic_send_byte(_i2c.iic, regr)) {
printf("byte 1\r\n");
return -3;
}
if (iic_send_byte(_i2c.iic, regv)) {
printf("byte 2\r\n");
return -4;
}
iic_stop(_i2c.raw);
return 0;
}
static int _i2c_write(uint8_t regr, uint8_t regv)
{
if (i2c_start(_i2c.i2c)) {
printf("start\r\n");
return -1;
}
i2c_send_byte(_i2c.i2c, WADDR);
if (i2c_wait_ack(_i2c.i2c)) { /* NACK */
printf("address not response\r\n");
return -2;
}
i2c_send_byte(_i2c.i2c, regr);
i2c_wait_ack(_i2c.i2c);
i2c_send_byte(_i2c.i2c, regv);
i2c_wait_ack(_i2c.i2c);
i2c_stop(_i2c.i2c);
return 0;
}
int wm8978_write(uint8_t reg, uint16_t val)
{
uint8_t regr, regv;
if (_write) {
regr = ((reg << 1) & 0xfe) | ((val >> 8) & 0x01);
regv = val & 0xff;
if (!_write(regr, regv)) {
__regs[reg] = val;
return 0;
}
}
return -1;
}
static void aux_gain(uint8_t gain)
{
uint16_t regval;
gain &=0x07;
regval = wm8978_read(47);
regval &= ~(7<<0);
wm8978_write(47,regval|gain<<0);
regval = wm8978_read(48);
regval &=~(7<<0);
wm8978_write(48, regval|gain<<0);
}
static void linein_gain(uint8_t gain)
{
uint16_t regval;
gain &= 0x07;
regval = wm8978_read(47);
regval &=~(7<<4);
wm8978_write(47,regval|gain<<4);
regval = wm8978_read(48);
regval&=~(7<<4);
wm8978_write(48,regval|gain<<4);
}
static void input_cfg(uint8_t micen,uint8_t lineinen,uint8_t auxen)
{
uint16_t regval;
regval = wm8978_read(2);
if(micen)
regval|=3<<2;
else
regval&=~(3<<2);
wm8978_write(2,regval);
regval = wm8978_read(44);
if(micen)
regval|=3<<4|3<<0;
else
regval&=~(3<<4|3<<0);
wm8978_write(44,regval);
if(lineinen)
linein_gain(5);
else
linein_gain(0);
if (auxen)
aux_gain(7);
else
aux_gain(0);
}
static void enable_ad_da(uint8_t dac, uint8_t adc)
{
uint16_t regv;
regv = wm8978_read(3);
if (dac) {
regv |= 3;
} else {
regv &= ~3;
}
wm8978_write(3, regv);
regv = wm8978_read(2);
if (adc) {
regv |= 3;
} else {
regv &= ~3;
}
wm8978_write(2, regv);
}
static void output_cfg(uint8_t dacen,uint8_t bpsen)
{
uint16_t regval=0;
if(dacen)
regval|=1<<0;
if(bpsen) {
regval|=1<<1;
regval|=5<<2;
}
wm8978_write(50, regval);
wm8978_write(51, regval);
}
static void hp_vol_set(uint8_t voll,uint8_t volr)
{
voll&=0x3F;
volr&=0x3F;
if(voll==0)voll|=1<<6;
if(volr==0)volr|=1<<6;
wm8978_write(52,voll);
wm8978_write(53,volr|(1<<8));
}
static void spk_vol_set(uint8_t volx)
{
volx &= 0x3F;
if(volx==0)volx|=1<<6;
wm8978_write(54, volx);
wm8978_write(55, volx|(1<<8));
}
static int do_init()
{
if (wm8978_write(0, 0)) {
return -1;
}
wm8978_write(1, 0x1b);
wm8978_write(2, 0x1b0);
wm8978_write(3, 0x6c);
wm8978_write(6, 0);
wm8978_write(43, 1 << 4);
wm8978_write(47, 1 << 8);
wm8978_write(48, 1 << 8);
wm8978_write(49, 1 << 1);
wm8978_write(10, 1 << 3);
wm8978_write(14, 1 << 3);
/* i2s cfg */
wm8978_write(4, (0x2 << 3) | (0x00 << 5));
/* ad da */
enable_ad_da(1, 0);
input_cfg(0, 0, 0);
output_cfg(1, 0);
hp_vol_set(63, 63);
spk_vol_set(63);
return 0;
}
int wm8978_init_with_iic(iic_t i2c)
{
_i2c.iic = i2c;
_write = _iic_write;
return do_init();
}
int wm8978_init_with_i2c(i2c_t i2c)
{
_i2c.i2c = i2c;
_write = _i2c_write;
return do_init();
}