codec.c 16.9 KB
Newer Older
B
bernard.xiong 已提交
1 2 3
#include <rthw.h>
#include <rtthread.h>
#include "stm32f10x.h"
4
#include "board.h"
5
#include "codec.h"
B
bernard.xiong 已提交
6

7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
#if CODEC_USE_SPI3

#define CODEC_I2S_PORT		SPI3
#define CODEC_I2S_IRQ		SPI3_IRQn
#define CODEC_I2S_DMA		DMA2_Channel2
#define CODEC_I2S_DMA_IRQ	DMA2_Channel2_IRQn
#define CODEC_I2S_RCC_APB1	RCC_APB1Periph_SPI3
#define CODEC_I2S_RCC_AHB	RCC_AHBPeriph_DMA2

// I2S3_WS -> PA15
#define CODEC_I2S_WS_PIN	GPIO_Pin_15
#define CODEC_I2S_WS_PORT	GPIOA
// I2S3_CK -> PB3
#define CODEC_I2S_CK_PIN	GPIO_Pin_3
#define CODEC_I2S_CK_PORT	GPIOB
// I2S3_SD -> PB5
#define CODEC_I2S_SD_PIN	GPIO_Pin_5
#define CODEC_I2S_SD_PORT	GPIOB

#else

#define CODEC_I2S_PORT		SPI2
#define CODEC_I2S_IRQ		SPI2_IRQn
#define CODEC_I2S_DMA		DMA1_Channel5
#define CODEC_I2S_DMA_IRQ	DMA1_Channel5_IRQn
#define CODEC_I2S_RCC_APB1	RCC_APB1Periph_SPI2
#define CODEC_I2S_RCC_AHB	RCC_AHBPeriph_DMA1

// I2S2_WS -> PB12
#define CODEC_I2S_WS_PIN	GPIO_Pin_12
#define CODEC_I2S_WS_PORT	GPIOB
// I2S2_CK -> PB13
#define CODEC_I2S_CK_PIN	GPIO_Pin_13
#define CODEC_I2S_CK_PORT	GPIOB
// I2S2_SD -> PB15
#define CODEC_I2S_SD_PIN	GPIO_Pin_15
#define CODEC_I2S_SD_PORT	GPIOB

#endif	// #if CODEC_USE_SPI3
46

B
bernard.xiong 已提交
47 48
/*
SCLK  PA5  SPI1_SCK
wuyangyong's avatar
wuyangyong 已提交
49
SDIN  PA7  SPI1_MOSI
B
bernard.xiong 已提交
50 51
CSB   PC5
*/
52 53 54 55 56 57
#define CODEC_CSB_PORT		GPIOC
#define CODEC_CSB_PIN		GPIO_Pin_5
#define codec_set_csb()		do { CODEC_CSB_PORT->BSRR = CODEC_CSB_PIN; } while (0)
#define codec_reset_csb()	do { CODEC_CSB_PORT->BRR = CODEC_CSB_PIN; } while (0)

void vol(uint16_t v);
58
static void codec_send(rt_uint16_t s_data);
B
bernard.xiong 已提交
59 60 61

#define DATA_NODE_MAX 5
/* data node for Tx Mode */
62
struct codec_data_node
B
bernard.xiong 已提交
63 64 65 66 67
{
    rt_uint16_t *data_ptr;
    rt_size_t  data_size;
};

68
struct codec_device
B
bernard.xiong 已提交
69 70 71 72 73
{
    /* inherit from rt_device */
    struct rt_device parent;

    /* pcm data list */
74
    struct codec_data_node data_list[DATA_NODE_MAX];
B
bernard.xiong 已提交
75 76 77 78 79
    rt_uint16_t read_index, put_index;

    /* transmitted offset of current data node */
    rt_size_t offset;
};
80 81
struct codec_device codec;

82
static uint16_t r06 = REG_CLOCK_GEN | CLKSEL_PLL | MCLK_DIV2 | BCLK_DIV8;
B
bernard.xiong 已提交
83 84 85 86 87

static void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;

88 89
    /* DMA IRQ Channel configuration */
    NVIC_InitStructure.NVIC_IRQChannel = CODEC_I2S_DMA_IRQ;
B
bernard.xiong 已提交
90 91 92 93 94 95 96 97 98 99
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

static void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

100 101 102 103 104 105 106 107 108
	/* Disable the JTAG interface and enable the SWJ interface */
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

	/* PC5 CODEC CS */
	GPIO_InitStructure.GPIO_Pin = CODEC_CSB_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(CODEC_CSB_PORT, &GPIO_InitStructure);

109 110
	// WS
	GPIO_InitStructure.GPIO_Pin = CODEC_I2S_WS_PIN;
111
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
112
#if CODEC_MASTER_MODE
113
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
114 115 116 117
#else
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
#endif
	GPIO_Init(CODEC_I2S_WS_PORT, &GPIO_InitStructure);
118

119 120
	// CK
	GPIO_InitStructure.GPIO_Pin = CODEC_I2S_CK_PIN;
121
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
122 123
#if CODEC_MASTER_MODE
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
124
#else
125
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
126
#endif
127 128 129 130 131 132 133
	GPIO_Init(CODEC_I2S_CK_PORT, &GPIO_InitStructure);

	// SD
	GPIO_InitStructure.GPIO_Pin = CODEC_I2S_SD_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(CODEC_I2S_SD_PORT, &GPIO_InitStructure);
134 135 136 137 138 139 140 141 142

#ifdef CODEC_USE_MCO
	/*    MCO    configure */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);

	RCC_MCOConfig(RCC_MCO_HSE);
B
bernard.xiong 已提交
143 144 145 146 147
#endif
}

static void DMA_Configuration(rt_uint32_t addr, rt_size_t size)
{
148 149
    DMA_InitTypeDef DMA_InitStructure;

150 151 152
	/* DMA Channel configuration ----------------------------------------------*/
	DMA_Cmd(CODEC_I2S_DMA, DISABLE);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(CODEC_I2S_PORT->DR));
153 154 155 156 157 158 159
	DMA_InitStructure.DMA_MemoryBaseAddr = (u32) addr;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
	DMA_InitStructure.DMA_BufferSize = size;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
160
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
161 162
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
163
	DMA_Init(CODEC_I2S_DMA, &DMA_InitStructure);
164

165 166
	/* Enable SPI DMA Tx request */
	SPI_I2S_DMACmd(CODEC_I2S_PORT, SPI_I2S_DMAReq_Tx, ENABLE);
167

168 169
	DMA_ITConfig(CODEC_I2S_DMA, DMA_IT_TC, ENABLE);
	DMA_Cmd(CODEC_I2S_DMA, ENABLE);
B
bernard.xiong 已提交
170 171 172 173
}

static void I2S_Configuration(void)
{
174 175 176 177
	I2S_InitTypeDef I2S_InitStructure;

	/* I2S peripheral configuration */
	I2S_InitStructure.I2S_Standard = I2S_Standard_Phillips;
178
	I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;
179 180
	I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Disable;
	I2S_InitStructure.I2S_AudioFreq = I2S_AudioFreq_44k;
181
	I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;
182 183

	/* I2S2 configuration */
184 185 186 187 188
#if CODEC_MASTER_MODE
	I2S_InitStructure.I2S_Mode = I2S_Mode_SlaveTx;
#else
	I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;
#endif
189
	I2S_Init(CODEC_I2S_PORT, &I2S_InitStructure);
B
bernard.xiong 已提交
190 191
}

192
uint8_t SPI_WriteByte(unsigned char data)
B
bernard.xiong 已提交
193
{
194 195 196 197 198 199 200 201 202 203 204 205 206
	//Wait until the transmit buffer is empty
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
	// Send the byte
	SPI_I2S_SendData(SPI1, data);

	//Wait until a data is received
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
	// Get the received data
	data = SPI_I2S_ReceiveData(SPI1);

	// Return the shifted data
	return data;
}
wuyangyong's avatar
wuyangyong 已提交
207

208 209 210 211 212 213 214
static void codec_send(rt_uint16_t s_data)
{
	codec_reset_csb();
	SPI_WriteByte((s_data >> 8) & 0xFF);
	SPI_WriteByte(s_data & 0xFF);
	codec_set_csb();
}
wuyangyong's avatar
wuyangyong 已提交
215

216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
static rt_err_t codec_init(rt_device_t dev)
{
	codec_send(REG_SOFTWARE_RESET);

	// 1.5x boost power up sequence.
	// Mute all outputs.
	codec_send(REG_LOUT1_VOL | LOUT1MUTE);
	codec_send(REG_ROUT1_VOL | ROUT1MUTE);
	codec_send(REG_LOUT2_VOL | LOUT2MUTE);
	codec_send(REG_ROUT2_VOL | ROUT2MUTE);
	// Enable unused output chosen from L/ROUT2, OUT3 or OUT4.
	codec_send(REG_POWER_MANAGEMENT3 | OUT4EN);
	// Set BUFDCOPEN=1 and BUFIOEN=1 in register R1
	codec_send(REG_POWER_MANAGEMENT1 | BUFDCOPEN | BUFIOEN);
	// Set SPKBOOST=1 in register R49.
	codec_send(REG_OUTPUT | SPKBOOST);
	// Set VMIDSEL[1:0] to required value in register R1.
	codec_send(REG_POWER_MANAGEMENT1 | BUFDCOPEN | BUFIOEN | VMIDSEL_75K);
	// Set L/RMIXEN=1 and DACENL/R=1 in register R3.
	codec_send(REG_POWER_MANAGEMENT3 | LMIXEN | RMIXEN | DACENL | DACENR);
	// Set BIASEN=1 in register R1.
	codec_send(REG_POWER_MANAGEMENT1 | BUFDCOPEN | BUFIOEN | VMIDSEL_75K | BIASEN);
	// Set L/ROUT2EN=1 in register R3.
	codec_send(REG_POWER_MANAGEMENT3 | LMIXEN | RMIXEN | DACENL | DACENR | LOUT2EN | ROUT2EN);
	// Enable other mixers as required.
	// Enable other outputs as required.
	codec_send(REG_POWER_MANAGEMENT2 | LOUT1EN | ROUT1EN | BOOSTENL | BOOSTENR | INPPGAENL | INPPGAENR);

	// Digital inferface setup.
	codec_send(REG_AUDIO_INTERFACE | BCP_NORMAL | LRP_NORMAL | WL_16BITS | FMT_I2S);

	// PLL setup.
248
	// fs = 44.1KHz * 256fs = 11.2896MHz
249 250 251
	// F_PLL = 11.2896MHz * 4 * 2 = 90.3168MHz
	// R = 90.3168MHz / 12.288MHz = 7.35
	// PLL_N = 7
252
	// PLL_K = 0x59999A (0x5A5A5A for STM32's 44.117KHz fs generated from 72MHz clock)
253
	codec_send(REG_PLL_N | 7);
254 255 256 257 258
#if CODEC_MASTER_MODE
	codec_send(REG_PLL_K1 | 0x16);
	codec_send(REG_PLL_K2 | 0xCC);
	codec_send(REG_PLL_K3 | 0x19A);
#else
259
	codec_send(REG_PLL_K1 | 0x16);
260 261
	codec_send(REG_PLL_K2 | 0x12D);
	codec_send(REG_PLL_K3 | 0x5A);
262
#endif
263
	codec_send(REG_POWER_MANAGEMENT1 | BUFDCOPEN | BUFIOEN | VMIDSEL_75K | BIASEN | PLLEN);
264
	codec_send(r06);
265 266 267 268 269 270 271

	// Enable DAC 128x oversampling.
	codec_send(REG_DAC | DACOSR128);

	// Set LOUT2/ROUT2 in BTL operation.
	codec_send(REG_BEEP | INVROUT2);

272
	// Set output volume.
273
	vol(40);
274 275 276 277 278 279

	return RT_EOK;
}

// Exported functions
#include <finsh.h>
wuyangyong's avatar
wuyangyong 已提交
280

281 282 283 284 285 286 287
void vol(uint16_t v)
{
	v = (v & VOL_MASK) << VOL_POS;
	codec_send(REG_LOUT1_VOL | v);
	codec_send(REG_ROUT1_VOL | HPVU | v);
	codec_send(REG_LOUT2_VOL | v);
	codec_send(REG_ROUT2_VOL | SPKVU | v);
B
bernard.xiong 已提交
288 289
}

290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
void eq(codec_eq_args_t args)
{
	switch (args->channel)
	{
	case 1:
		codec_send(REG_EQ1 | ((args->frequency & EQC_MASK) << EQC_POS) | ((args->gain & EQG_MASK) << EQG_POS) | (args->mode_bandwidth ? EQ3DMODE_DAC : EQ3DMODE_ADC));
		break;

	case 2:
		codec_send(REG_EQ2 | ((args->frequency & EQC_MASK) << EQC_POS) | ((args->gain & EQG_MASK) << EQG_POS) | (args->mode_bandwidth ? EQ2BW_WIDE : EQ2BW_NARROW));
		break;

	case 3:
		codec_send(REG_EQ3 | ((args->frequency & EQC_MASK) << EQC_POS) | ((args->gain & EQG_MASK) << EQG_POS) | (args->mode_bandwidth ? EQ3BW_WIDE : EQ3BW_NARROW));
		break;

	case 4:
		codec_send(REG_EQ4 | ((args->frequency & EQC_MASK) << EQC_POS) | ((args->gain & EQG_MASK) << EQG_POS) | (args->mode_bandwidth ? EQ4BW_WIDE : EQ4BW_NARROW));
		break;

	case 5:
		codec_send(REG_EQ5 | ((args->frequency & EQC_MASK) << EQC_POS) | ((args->gain & EQG_MASK) << EQG_POS));
		break;
	}
}

// TODO eq1() ~ eq5() are just for testing. To be removed.
317
void eq1(uint8_t freq, uint8_t gain, uint8_t mode)
B
bernard.xiong 已提交
318
{
319
	codec_send(REG_EQ1 | ((freq & EQC_MASK) << EQC_POS) | ((gain & EQG_MASK) << EQG_POS) | (mode ? EQ3DMODE_DAC : EQ3DMODE_ADC));
B
bernard.xiong 已提交
320 321
}

322
void eq2(uint8_t freq, uint8_t gain, uint8_t bw)
B
bernard.xiong 已提交
323
{
324 325
	codec_send(REG_EQ2 | ((freq & EQC_MASK) << EQC_POS) | ((gain & EQG_MASK) << EQG_POS) | (bw ? EQ2BW_WIDE : EQ2BW_NARROW));
}
wuyangyong's avatar
wuyangyong 已提交
326

327 328 329
void eq3(uint8_t freq, uint8_t gain, uint8_t bw)
{
	codec_send(REG_EQ3 | ((freq & EQC_MASK) << EQC_POS) | ((gain & EQG_MASK) << EQG_POS) | (bw ? EQ3BW_WIDE : EQ3BW_NARROW));
B
bernard.xiong 已提交
330 331
}

332
void eq4(uint8_t freq, uint8_t gain, uint8_t bw)
B
bernard.xiong 已提交
333
{
334
	codec_send(REG_EQ4 | ((freq & EQC_MASK) << EQC_POS) | ((gain & EQG_MASK) << EQG_POS) | (bw ? EQ4BW_WIDE : EQ4BW_NARROW));
B
bernard.xiong 已提交
335 336
}

337
void eq5(uint8_t freq, uint8_t gain)
B
bernard.xiong 已提交
338
{
339 340
	codec_send(REG_EQ2 | ((freq & EQC_MASK) << EQC_POS) | ((gain & EQG_MASK) << EQG_POS));
}
B
bernard.xiong 已提交
341

342 343 344
void eq3d(uint8_t depth)
{
	codec_send(REG_3D | ((depth & DEPTH3D_MASK) << DEPTH3D_POS));
B
bernard.xiong 已提交
345 346
}

347
rt_err_t sample_rate(int sr)
B
bernard.xiong 已提交
348
{
349 350 351
	uint16_t r07 = REG_ADDITIONAL;

	switch (sr)
352
	{
353 354
	case 8000:
		r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV6 | BCLK_DIV8 | (r06 & MS);
355 356 357
		r07 |= SR_8KHZ;
		break;

358 359
	case 11025:
		r06 = REG_CLOCK_GEN | CLKSEL_PLL | MCLK_DIV8 | BCLK_DIV8 | (r06 & MS);
360 361 362 363
		r07 |= SR_12KHZ;
		break;

#if CODEC_MASTER_MODE
364 365
	case 12000:
		r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV4 | BCLK_DIV8 | (r06 & MS);
366 367 368 369
		r07 |= SR_12KHZ;
		break;
#endif

370 371
	case 16000:
		r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV3 | BCLK_DIV8 | (r06 & MS);
372 373 374
		r07 |= SR_16KHZ;
		break;

375 376
	case 22050:
		r06 = REG_CLOCK_GEN | CLKSEL_PLL | MCLK_DIV4 | BCLK_DIV8 | (r06 & MS);
377 378 379 380
		r07 |= SR_24KHZ;
		break;

#if CODEC_MASTER_MODE
381 382
	case 24000:
		r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV2 | BCLK_DIV8 | (r06 & MS);
383 384 385 386
		r07 |= SR_24KHZ;
		break;
#endif

387 388
	case 32000:
		r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV1_5 | BCLK_DIV8 | (r06 & MS);
389 390 391
		r07 |= SR_32KHZ;
		break;

392 393
	case 44100:
		r06 = REG_CLOCK_GEN | CLKSEL_PLL | MCLK_DIV2 | BCLK_DIV8 | (r06 & MS);
394 395 396
		r07 |= SR_48KHZ;
		break;

397 398
	case 48000:
		r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV1 | BCLK_DIV8 | (r06 & MS);
399 400 401 402 403
		r07 |= SR_48KHZ;
		break;

	default:
		return RT_ERROR;
404
	}
405 406 407
	codec_send(r06);
	codec_send(r07);
	return RT_EOK;
408 409 410 411 412 413 414 415 416 417
}

FINSH_FUNCTION_EXPORT(vol, Set volume);
FINSH_FUNCTION_EXPORT(eq1, Set EQ1(Cut-off, Gain, Mode));
FINSH_FUNCTION_EXPORT(eq2, Set EQ2(Center, Gain, Bandwidth));
FINSH_FUNCTION_EXPORT(eq3, Set EQ3(Center, Gain, Bandwidth));
FINSH_FUNCTION_EXPORT(eq4, Set EQ4(Center, Gain, Bandwidth));
FINSH_FUNCTION_EXPORT(eq5, Set EQ5(Cut-off, Gain));
FINSH_FUNCTION_EXPORT(eq3d, Set 3D(Depth));
FINSH_FUNCTION_EXPORT(sample_rate, Set sample rate);
B
bernard.xiong 已提交
418

419 420
static rt_err_t codec_open(rt_device_t dev, rt_uint16_t oflag)
{
421
#if !CODEC_MASTER_MODE
422
	/* enable I2S */
423
	I2S_Cmd(CODEC_I2S_PORT, ENABLE);
424 425
#endif

426
	return RT_EOK;
B
bernard.xiong 已提交
427 428
}

429
static rt_err_t codec_close(rt_device_t dev)
B
bernard.xiong 已提交
430
{
431
#if CODEC_MASTER_MODE
432
	if (r06 & MS)
433
	{
434 435 436 437
		CODEC_I2S_DMA->CCR &= ~DMA_CCR1_EN;
		while ((CODEC_I2S_PORT->SR & SPI_I2S_FLAG_TXE) == 0);
		while ((CODEC_I2S_PORT->SR & SPI_I2S_FLAG_BSY) != 0);
		CODEC_I2S_PORT->I2SCFGR &= ~SPI_I2SCFGR_I2SE;
438 439 440

		r06 &= ~MS;
		codec_send(r06);
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459

		/* remove all data node */
		if (codec.parent.tx_complete != RT_NULL)
		{
			rt_base_t level = rt_hw_interrupt_disable();

			do
			{
				codec.parent.tx_complete(&codec.parent, codec.data_list[codec.read_index].data_ptr);
				codec.read_index++;
				if (codec.read_index >= DATA_NODE_MAX)
				{
					codec.read_index = 0;
				}
			}
			while (codec.read_index != codec.put_index);

			rt_hw_interrupt_enable(level);
		}
460 461
	}
#endif
462 463

	return RT_EOK;
B
bernard.xiong 已提交
464 465
}

466
static rt_err_t codec_control(rt_device_t dev, rt_uint8_t cmd, void *args)
B
bernard.xiong 已提交
467
{
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
	switch (cmd)
	{
	case CODEC_CMD_RESET:
		codec_init(dev);
		break;

	case CODEC_CMD_VOLUME:
		vol(*((uint16_t*) args));
		break;

	case CODEC_CMD_SAMPLERATE:
		sample_rate(*((int*) args));
		break;

	case CODEC_CMD_EQ:
		eq((codec_eq_args_t) args);
		break;

	case CODEC_CMD_3D:
		eq3d(*((uint8_t*) args));
		break;

	default:
		return RT_ERROR;
	}
493
	return RT_EOK;
B
bernard.xiong 已提交
494 495
}

496 497
static rt_size_t codec_write(rt_device_t dev, rt_off_t pos,
		const void* buffer, rt_size_t size)
B
bernard.xiong 已提交
498
{
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
	struct codec_device* device;
	struct codec_data_node* node;
	rt_uint32_t level;
	rt_uint16_t next_index;

	device = (struct codec_device*) dev;
	RT_ASSERT(device != RT_NULL);

	next_index = device->put_index + 1;
	if (next_index >= DATA_NODE_MAX)
		next_index = 0;

	/* check data_list full */
	if (next_index == device->read_index)
	{
		rt_set_errno(-RT_EFULL);
		return 0;
	}

	level = rt_hw_interrupt_disable();
	node = &device->data_list[device->put_index];
	device->put_index = next_index;

	/* set node attribute */
	node->data_ptr = (rt_uint16_t*) buffer;
	node->data_size = size >> 1; /* size is byte unit, convert to half word unit */

	next_index = device->read_index + 1;
	if (next_index >= DATA_NODE_MAX)
		next_index = 0;

	/* check data list whether is empty */
	if (next_index == device->put_index)
	{
533
		DMA_Configuration((rt_uint32_t) node->data_ptr, node->data_size);
534 535 536 537

#if CODEC_MASTER_MODE
		if ((r06 & MS) == 0)
		{
538
			CODEC_I2S_PORT->I2SCFGR |= SPI_I2SCFGR_I2SE;
539 540 541 542
			r06 |= MS;
			codec_send(r06);
		}
#endif
543 544 545 546
	}
	rt_hw_interrupt_enable(level);

	return size;
B
bernard.xiong 已提交
547 548
}

549
rt_err_t codec_hw_init(void)
B
bernard.xiong 已提交
550
{
551 552
	rt_device_t dev;

553 554 555
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE);
	RCC_APB1PeriphClockCmd(CODEC_I2S_RCC_APB1, ENABLE);
	RCC_AHBPeriphClockCmd(CODEC_I2S_RCC_AHB, ENABLE);
556 557 558 559 560 561

	NVIC_Configuration();
	GPIO_Configuration();
	I2S_Configuration();

	dev = (rt_device_t) &codec;
562
	dev->type = RT_Device_Class_Sound;
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
	dev->rx_indicate = RT_NULL;
	dev->tx_complete = RT_NULL;
	dev->init = codec_init;
	dev->open = codec_open;
	dev->close = codec_close;
	dev->read = RT_NULL;
	dev->write = codec_write;
	dev->control = codec_control;
	dev->private = RT_NULL;

	/* set read_index and put index to 0 */
	codec.read_index = 0;
	codec.put_index = 0;

	/* unselect */
	codec_set_csb();

	/* register the device */
	return rt_device_register(&codec.parent, "snd", RT_DEVICE_FLAG_WRONLY | RT_DEVICE_FLAG_DMA_TX);
B
bernard.xiong 已提交
582 583
}

584
void codec_dma_isr(void)
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
{
	/* switch to next buffer */
	rt_uint16_t next_index;
	void* data_ptr;

	next_index = codec.read_index + 1;
	if (next_index >= DATA_NODE_MAX)
		next_index = 0;

	/* save current data pointer */
	data_ptr = codec.data_list[codec.read_index].data_ptr;

	codec.read_index = next_index;
	if (next_index != codec.put_index)
	{
		/* enable next dma request */
		DMA_Configuration((rt_uint32_t) codec.data_list[codec.read_index].data_ptr, codec.data_list[codec.read_index].data_size);
602 603 604 605

#if CODEC_MASTER_MODE
		if ((r06 & MS) == 0)
		{
606
			CODEC_I2S_PORT->I2SCFGR |= SPI_I2SCFGR_I2SE;
607 608 609 610
			r06 |= MS;
			codec_send(r06);
		}
#endif
611 612 613
	}
	else
	{
614
#if CODEC_MASTER_MODE
615 616
		if (r06 & MS)
		{
617 618 619 620
			CODEC_I2S_DMA->CCR &= ~DMA_CCR1_EN;
			while ((CODEC_I2S_PORT->SR & SPI_I2S_FLAG_TXE) == 0);
			while ((CODEC_I2S_PORT->SR & SPI_I2S_FLAG_BSY) != 0);
			CODEC_I2S_PORT->I2SCFGR &= ~SPI_I2SCFGR_I2SE;
621

622 623 624
			r06 &= ~MS;
			codec_send(r06);
		}
625 626
#endif

627 628 629 630 631 632 633 634 635
		rt_kprintf("*\n");
	}

	/* notify transmitted complete. */
	if (codec.parent.tx_complete != RT_NULL)
	{
		codec.parent.tx_complete(&codec.parent, data_ptr);
	}
}