1 /*
2 * Copyright 2021-2022 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "fsl_pcm512x.h"
8
9 /*******************************************************************************
10 * Definitions
11 ******************************************************************************/
12
13 /*******************************************************************************
14 * Prototypes
15 ******************************************************************************/
16
17 /*******************************************************************************
18 * Variables
19 ******************************************************************************/
20
21 /*******************************************************************************
22 * Code
23 ******************************************************************************/
PCM512x_WriteReg(pcm512x_handle_t * handle,uint8_t reg,uint8_t val)24 status_t PCM512x_WriteReg(pcm512x_handle_t *handle, uint8_t reg, uint8_t val)
25 {
26 assert(handle->config != NULL);
27
28 return CODEC_I2C_Send(handle->i2cHandle, handle->config->slaveAddress, reg, 1U, &val, 1U);
29 }
30
PCM512x_ReadReg(pcm512x_handle_t * handle,uint8_t reg,uint8_t * val)31 status_t PCM512x_ReadReg(pcm512x_handle_t *handle, uint8_t reg, uint8_t *val)
32 {
33 assert(handle->config != NULL);
34
35 return CODEC_I2C_Receive(handle->i2cHandle, handle->config->slaveAddress, reg, 1U, val, 1U);
36 }
37
PCM512x_ModifyReg(pcm512x_handle_t * handle,uint8_t reg,uint8_t mask,uint8_t val)38 status_t PCM512x_ModifyReg(pcm512x_handle_t *handle, uint8_t reg, uint8_t mask, uint8_t val)
39 {
40 uint8_t old, new;
41
42 assert(handle->config != NULL);
43
44 if (PCM512x_ReadReg(handle, reg, &old) != kStatus_Success) {
45 return kStatus_Fail;
46 }
47
48 new = (old & (~mask)) | (val & mask);
49
50 return PCM512x_WriteReg(handle, reg, new);
51 }
52
53
dac_pcm512x_set_gpio_val(pcm512x_handle_t * handle,int gpio_nr,int val)54 static status_t dac_pcm512x_set_gpio_val(pcm512x_handle_t *handle, int gpio_nr, int val)
55 {
56 status_t ret = kStatus_Success;
57 uint8_t gpio_bit = 1 << (gpio_nr - 1);
58 uint8_t gpio_output_reg;
59
60 switch (gpio_nr) {
61 case 3:
62 gpio_output_reg = PCM512x_GPIO_OUTPUT_3;
63 break;
64 case 4:
65 gpio_output_reg = PCM512x_GPIO_OUTPUT_4;
66 break;
67 case 6:
68 gpio_output_reg = PCM512x_GPIO_OUTPUT_6;
69 break;
70 default:
71 ret = kStatus_InvalidArgument;
72 goto end;
73 }
74
75 /* Enable gpio */
76 ret = PCM512x_ModifyReg(handle, PCM512x_GPIO_EN, gpio_bit, gpio_bit);
77 if (ret != kStatus_Success) goto end;
78
79 /* Set pinmux to gpio */
80 ret = PCM512x_ModifyReg(handle, gpio_output_reg, 0xf, 2);
81 if (ret != kStatus_Success) goto end;
82
83 /* Set gpio value */
84 ret = PCM512x_ModifyReg(handle, PCM512x_GPIO_CONTROL_1, gpio_bit, val ? gpio_bit : 0);
85 if (ret != kStatus_Success) goto end;
86
87 end:
88 return ret;
89 }
90
dac_pcm512x_set_gpio(pcm512x_handle_t * handle,int gpio_nr)91 static status_t dac_pcm512x_set_gpio(pcm512x_handle_t *handle, int gpio_nr)
92 {
93 return dac_pcm512x_set_gpio_val(handle, gpio_nr, 1);
94 }
95
dac_pcm512x_clear_gpio(pcm512x_handle_t * handle,int gpio_nr)96 static status_t dac_pcm512x_clear_gpio(pcm512x_handle_t *handle, int gpio_nr)
97 {
98 return dac_pcm512x_set_gpio_val(handle, gpio_nr, 0);
99 }
100
101 #define CLK_48000 (48000 * 512)
102 #define CLK_44100 (44100 * 512)
103
dac_pcm512x_get_dac_rate(int sample_rate)104 static int dac_pcm512x_get_dac_rate(int sample_rate)
105 {
106 int dr;
107
108 switch (sample_rate) {
109 case kPCM512x_AudioSampleRate44100Hz:
110 case kPCM512x_AudioSampleRate88200Hz:
111 case kPCM512x_AudioSampleRate176400Hz:
112 dr = 5644800;
113 break;
114 case kPCM512x_AudioSampleRate48KHz:
115 case kPCM512x_AudioSampleRate96KHz:
116 case kPCM512x_AudioSampleRate192KHz:
117 dr = 6144000;
118 break;
119 default:
120 dr = -1;
121 break;
122 }
123
124 return dr;
125 }
126
dac_pcm512x_get_dac_div(int sample_rate)127 static uint8_t dac_pcm512x_get_dac_div(int sample_rate)
128 {
129 int dd;
130 int u, d;
131
132 switch (sample_rate) {
133 case kPCM512x_AudioSampleRate44100Hz:
134 case kPCM512x_AudioSampleRate88200Hz:
135 case kPCM512x_AudioSampleRate176400Hz:
136 u = CLK_44100;
137 break;
138 case kPCM512x_AudioSampleRate48KHz:
139 case kPCM512x_AudioSampleRate96KHz:
140 case kPCM512x_AudioSampleRate192KHz:
141 u = CLK_48000;
142 break;
143 default:
144 dd = -1;
145 goto end;
146 };
147
148 d = dac_pcm512x_get_dac_rate(sample_rate);
149 dd = (u + d / 2) / d;
150
151 end:
152 return dd;
153 }
154
dac_pcm512x_get_idac(int sample_rate,uint8_t dsp_div)155 static int dac_pcm512x_get_idac(int sample_rate, uint8_t dsp_div)
156 {
157 int idac;
158 int u;
159
160 switch (sample_rate) {
161 case kPCM512x_AudioSampleRate44100Hz:
162 case kPCM512x_AudioSampleRate88200Hz:
163 case kPCM512x_AudioSampleRate176400Hz:
164 u = CLK_44100;
165 break;
166 case kPCM512x_AudioSampleRate48KHz:
167 case kPCM512x_AudioSampleRate96KHz:
168 case kPCM512x_AudioSampleRate192KHz:
169 u = CLK_48000;
170 break;
171 default:
172 idac = -1;
173 goto end;
174 }
175
176 idac = u / (sample_rate * dsp_div);
177
178 end:
179 return idac;
180 }
181
dac_pcm512x_get_bclk_div(int sample_rate,uint8_t lrclk_div)182 static uint8_t dac_pcm512x_get_bclk_div(int sample_rate, uint8_t lrclk_div)
183 {
184 uint8_t bclk_div;
185 int u;
186
187 switch (sample_rate) {
188 case kPCM512x_AudioSampleRate44100Hz:
189 case kPCM512x_AudioSampleRate88200Hz:
190 case kPCM512x_AudioSampleRate176400Hz:
191 u = CLK_44100;
192 break;
193 case kPCM512x_AudioSampleRate48KHz:
194 case kPCM512x_AudioSampleRate96KHz:
195 case kPCM512x_AudioSampleRate192KHz:
196 u = CLK_48000;
197 break;
198 default:
199 bclk_div = 0;
200 goto end;
201 }
202
203 bclk_div = (uint8_t )(u / (sample_rate * lrclk_div));
204
205 end:
206 return bclk_div;
207 }
208
dac_pcm512x_get_fssp(int sample_rate)209 static uint8_t dac_pcm512x_get_fssp(int sample_rate)
210 {
211 uint8_t fssp;
212
213 switch (sample_rate) {
214 case kPCM512x_AudioSampleRate44100Hz:
215 case kPCM512x_AudioSampleRate48KHz:
216 fssp = PCM512x_FSSP_48KHZ;
217 break;
218 case kPCM512x_AudioSampleRate88200Hz:
219 case kPCM512x_AudioSampleRate96KHz:
220 fssp = PCM512x_FSSP_96KHZ;
221 break;
222 case kPCM512x_AudioSampleRate176400Hz:
223 case kPCM512x_AudioSampleRate192KHz:
224 fssp = PCM512x_FSSP_192KHZ;
225 break;
226 default:
227 fssp = 0;
228 goto end;
229 }
230
231 end:
232 return fssp;
233 }
234
PCM512x_SetFormat(pcm512x_handle_t * handle,uint32_t mclk,uint32_t sampleRate,uint32_t bitWidth)235 status_t PCM512x_SetFormat(pcm512x_handle_t *handle, uint32_t mclk, uint32_t sampleRate, uint32_t bitWidth)
236 {
237 status_t ret = kStatus_Success;
238 uint8_t alen, lrclk_div, bclk_div, dsp_div, dac_div, ncp_div, osr_div, fssp;
239 int dac_rate, idac;
240
241 if ((sampleRate != kPCM512x_AudioSampleRate44100Hz) &&
242 (sampleRate != kPCM512x_AudioSampleRate88200Hz) &&
243 (sampleRate != kPCM512x_AudioSampleRate176400Hz) &&
244 (sampleRate != kPCM512x_AudioSampleRate48KHz) &&
245 (sampleRate != kPCM512x_AudioSampleRate96KHz) &&
246 (sampleRate != kPCM512x_AudioSampleRate192KHz)) {
247 ret = kStatus_InvalidArgument;
248 goto end;
249 }
250
251 /* Turn DAC on */
252 ret = PCM512x_ModifyReg(handle,
253 PCM512x_POWER,
254 PCM512x_RQPD,
255 0);
256
257 /* Enable 44.1kHz or 48kHz oscillator depending on sampling rate */
258 if (sampleRate % 8000) {
259 /* Enable 44.1kHz oscillator on Hifiberry card */
260 ret = dac_pcm512x_set_gpio(handle, handle->config->gpio_osc44);
261 /* Clear 48kHz oscillator on Hifiberry card */
262 ret = dac_pcm512x_clear_gpio(handle, handle->config->gpio_osc48);
263 }
264 else {
265 /* Enable 48kHz oscillator on Hifiberry card */
266 ret = dac_pcm512x_set_gpio(handle, handle->config->gpio_osc48);
267 /* Clear 44.1kHz oscillator on Hifiberry card */
268 ret = dac_pcm512x_clear_gpio(handle, handle->config->gpio_osc44);
269 }
270 if (ret != kStatus_Success) goto end;
271
272 switch (bitWidth) {
273 case kPCM512x_AudioBitWidth16bit:
274 alen = PCM512x_ALEN_16;
275 break;
276 case kPCM512x_AudioBitWidth24bit:
277 alen = PCM512x_ALEN_24;
278 break;
279 case kPCM512x_AudioBitWidth32bit:
280 alen = PCM512x_ALEN_32;
281 break;
282 default:
283 ret = kStatus_InvalidArgument;
284 goto end;
285 }
286
287 ret = PCM512x_ModifyReg(handle,
288 PCM512x_I2S_1,
289 PCM512x_ALEN,
290 alen);
291
292 ret = PCM512x_ModifyReg(handle,
293 PCM512x_ERROR_DETECT,
294 PCM512x_IDFS | PCM512x_IDBK | PCM512x_IDSK | PCM512x_IDCH
295 | PCM512x_IDCM | PCM512x_DCAS | PCM512x_IPLK,
296 PCM512x_IDFS | PCM512x_IDBK | PCM512x_IDSK | PCM512x_IDCH
297 | PCM512x_DCAS | PCM512x_IPLK);
298 if (ret != kStatus_Success) goto end;
299
300 ret = PCM512x_ModifyReg(handle,
301 PCM512x_PLL_EN,
302 PCM512x_PLLE,
303 0);
304 if (ret != kStatus_Success) goto end;
305
306 ret= PCM512x_ModifyReg(handle,
307 PCM512x_DAC_REF,
308 PCM512x_SDAC,
309 PCM512x_SDAC_SCK);
310 if (ret != kStatus_Success) goto end;
311
312 dsp_div = 1; /* mclk < 50Mhz, so no need to divide DSP clk */
313 ret = PCM512x_WriteReg(handle, PCM512x_DSP_CLKDIV, dsp_div - 1);
314 if (ret != kStatus_Success) goto end;
315
316 dac_rate = dac_pcm512x_get_dac_rate(sampleRate);
317 dac_div = dac_pcm512x_get_dac_div(sampleRate);
318 ret = PCM512x_WriteReg(handle, PCM512x_DAC_CLKDIV, dac_div - 1);
319 if (ret != kStatus_Success) goto end;
320
321 ncp_div = (uint8_t)((dac_rate + 768000) / 1536000);
322 ret = PCM512x_WriteReg(handle, PCM512x_NCP_CLKDIV, ncp_div - 1);
323 if (ret != kStatus_Success) goto end;
324
325 osr_div = (uint8_t)(dac_rate / (sampleRate * 16));
326 ret = PCM512x_WriteReg(handle, PCM512x_OSR_CLKDIV, osr_div - 1);
327 if (ret != kStatus_Success) goto end;
328
329 lrclk_div = bitWidth * 2;
330 bclk_div = dac_pcm512x_get_bclk_div(sampleRate, lrclk_div);
331 ret = PCM512x_WriteReg(handle, PCM512x_MASTER_CLKDIV_1, bclk_div - 1);
332 if (ret != kStatus_Success) goto end;
333 ret = PCM512x_WriteReg(handle, PCM512x_MASTER_CLKDIV_2, lrclk_div - 1);
334 if (ret != kStatus_Success) goto end;
335
336 idac = dac_pcm512x_get_idac(sampleRate, dsp_div);
337 ret = PCM512x_WriteReg(handle, PCM512x_IDAC_1, idac >> 8);
338 if (ret != kStatus_Success) goto end;
339 ret = PCM512x_WriteReg(handle, PCM512x_IDAC_2, idac & 0xff);
340 if (ret != kStatus_Success) goto end;
341
342 fssp = dac_pcm512x_get_fssp(sampleRate);
343 ret = PCM512x_ModifyReg(handle,
344 PCM512x_FS_SPEED_MODE,
345 PCM512x_FSSP,
346 fssp);
347 if (ret != kStatus_Success) goto end;
348
349 ret = PCM512x_ModifyReg(handle,
350 PCM512x_BCLK_LRCLK_CFG,
351 PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO,
352 PCM512x_BCKO | PCM512x_LRKO);
353 if (ret != kStatus_Success) goto end;
354
355 ret = PCM512x_ModifyReg(handle,
356 PCM512x_MASTER_MODE,
357 PCM512x_RLRK | PCM512x_RBCK,
358 PCM512x_RLRK | PCM512x_RBCK);
359 if (ret != kStatus_Success) goto end;
360
361 ret = PCM512x_ModifyReg(handle,
362 PCM512x_SYNCHRONIZE,
363 PCM512x_RQSY,
364 PCM512x_RQSY_HALT);
365 if (ret != kStatus_Success) goto end;
366
367 ret = PCM512x_ModifyReg(handle,
368 PCM512x_SYNCHRONIZE,
369 PCM512x_RQSY,
370 PCM512x_RQSY_RESUME);
371 if (ret != kStatus_Success) goto end;
372
373 /* Normal operation mode */
374 ret = PCM512x_ModifyReg(handle,
375 PCM512x_POWER,
376 PCM512x_RQST,
377 0);
378 if (ret != kStatus_Success) goto end;
379
380 /* Unmute codec */
381 ret = PCM512x_SetMute(handle, false);
382 if (ret != kStatus_Success) goto end;
383
384 end:
385 return ret;
386 }
387
PCM512x_SetMute(pcm512x_handle_t * handle,bool isEnabled)388 status_t PCM512x_SetMute(pcm512x_handle_t *handle, bool isEnabled)
389 {
390 status_t ret = kStatus_Success;
391
392 if (isEnabled) {
393 ret = PCM512x_ModifyReg(handle,
394 PCM512x_MUTE,
395 PCM512x_RQML | PCM512x_RQMR,
396 PCM512x_RQML | PCM512x_RQMR);
397 }
398 else {
399 ret = PCM512x_ModifyReg(handle,
400 PCM512x_MUTE,
401 PCM512x_RQML | PCM512x_RQMR,
402 0);
403 }
404
405 return ret;
406 }
407
PCM512x_Init(pcm512x_handle_t * handle,const pcm512x_config_t * config)408 status_t PCM512x_Init(pcm512x_handle_t *handle, const pcm512x_config_t *config)
409 {
410 status_t ret = kStatus_Success;
411
412 handle->config = config;
413
414 /* i2c bus initialization */
415 if (CODEC_I2C_Init(handle->i2cHandle, config->i2cConfig.codecI2CInstance, PCM512X_I2C_BAUDRATE,
416 config->i2cConfig.codecI2CSourceClock) != (status_t)kStatus_HAL_I2cSuccess)
417 {
418 return kStatus_Fail;
419 }
420
421 /* Mute codec */
422 ret = PCM512x_SetMute(handle, true);
423 if (ret != kStatus_Success) goto end;
424
425 /* Reset codec */
426 ret = PCM512x_WriteReg(handle,
427 PCM512x_RESET,
428 PCM512x_RSTM | PCM512x_RSTR);
429 if (ret != kStatus_Success) goto end;
430 ret = PCM512x_WriteReg(handle,
431 PCM512x_RESET,
432 0);
433 if (ret != kStatus_Success) goto end;
434
435 /* Default to standby mode */
436 ret = PCM512x_ModifyReg(handle,
437 PCM512x_POWER,
438 PCM512x_RQST,
439 PCM512x_RQST);
440 if (ret != kStatus_Success) goto end;
441
442 /* Turn PCM5122 LED GPIO ON */
443 ret = dac_pcm512x_set_gpio(handle, config->gpio_led);
444
445 end:
446 return ret;
447 }
448
PCM512x_Deinit(pcm512x_handle_t * handle)449 status_t PCM512x_Deinit(pcm512x_handle_t *handle)
450 {
451 status_t ret;
452
453 /* Reinit I2C in case it has been stopped by concurrent codec driver */
454 if (CODEC_I2C_Init(handle->i2cHandle, handle->config->i2cConfig.codecI2CInstance, PCM512X_I2C_BAUDRATE,
455 handle->config->i2cConfig.codecI2CSourceClock) != (status_t)kStatus_HAL_I2cSuccess)
456 return kStatus_Fail;
457
458 /* Mute codec */
459 ret = PCM512x_SetMute(handle, true);
460 if (ret != kStatus_Success) goto end;
461
462 /* Turn PCM5122 LED GPIO OFF */
463 ret = dac_pcm512x_clear_gpio(handle, handle->config->gpio_led);
464 if (ret != kStatus_Success) goto end;
465
466 ret = CODEC_I2C_Deinit(handle->i2cHandle);
467
468 end:
469 return ret;
470 }
471