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