1 /*
2 * Copyright 2021 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "fsl_pcm186x.h"
8
9 /*******************************************************************************
10 * Definitions
11 ******************************************************************************/
12
13 /*******************************************************************************
14 * Prototypes
15 ******************************************************************************/
16
17 /*******************************************************************************
18 * Variables
19 ******************************************************************************/
20
21 /*******************************************************************************
22 * Code
23 ******************************************************************************/
PCM186x_WriteReg(pcm186x_handle_t * handle,uint8_t reg,uint8_t val)24 status_t PCM186x_WriteReg(pcm186x_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
PCM186x_ReadReg(pcm186x_handle_t * handle,uint8_t reg,uint8_t * val)31 status_t PCM186x_ReadReg(pcm186x_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
PCM186x_ModifyReg(pcm186x_handle_t * handle,uint8_t reg,uint8_t mask,uint8_t val)38 status_t PCM186x_ModifyReg(pcm186x_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 (PCM186x_ReadReg(handle, reg, &old) != kStatus_Success) {
45 return kStatus_Fail;
46 }
47
48 new = (old & (~mask)) | (val & mask);
49
50 return PCM186x_WriteReg(handle, reg, new);
51 }
52
53
dac_pcm186x_set_gpio_val(pcm186x_handle_t * handle,int gpio_nr,int val)54 static status_t dac_pcm186x_set_gpio_val(pcm186x_handle_t *handle, int gpio_nr, int val)
55 {
56 status_t ret = kStatus_Success;
57
58 switch (gpio_nr) {
59 case 0:
60 /* Set muxmode to gpio */
61 ret = PCM186x_ModifyReg(handle,
62 PCM186X_GPIO1_0_CTRL,
63 PCM186X_GPIO0_FUNC,
64 0);
65 if (ret != kStatus_Success) goto end;
66
67 /* Set gpio as output */
68 ret = PCM186x_ModifyReg(handle,
69 PCM186X_GPIO1_0_DIR_CTRL,
70 PCM186X_GPIO0_DIR,
71 0);
72 if (ret != kStatus_Success) goto end;
73
74 break;
75 case 1:
76 /* Set muxmode to gpio */
77 ret = PCM186x_ModifyReg(handle,
78 PCM186X_GPIO1_0_CTRL,
79 PCM186X_GPIO1_FUNC,
80 0);
81 if (ret != kStatus_Success) goto end;
82
83 /* Set gpio as output */
84 ret = PCM186x_ModifyReg(handle,
85 PCM186X_GPIO1_0_DIR_CTRL,
86 PCM186X_GPIO1_DIR,
87 4 << 4);
88 if (ret != kStatus_Success) goto end;
89
90 break;
91 case 2:
92 /* Set muxmode to gpio */
93 ret = PCM186x_ModifyReg(handle,
94 PCM186X_GPIO3_2_CTRL,
95 PCM186X_GPIO2_FUNC,
96 0);
97 if (ret != kStatus_Success) goto end;
98
99 /* Set gpio as output */
100 ret = PCM186x_ModifyReg(handle,
101 PCM186X_GPIO3_2_DIR_CTRL,
102 PCM186X_GPIO2_DIR,
103 4);
104 if (ret != kStatus_Success) goto end;
105
106 break;
107 case 3:
108 /* Set muxmode to gpio */
109 ret = PCM186x_ModifyReg(handle,
110 PCM186X_GPIO3_2_CTRL,
111 PCM186X_GPIO3_FUNC,
112 0);
113 if (ret != kStatus_Success) goto end;
114
115 /* Set gpio as output */
116 ret = PCM186x_ModifyReg(handle,
117 PCM186X_GPIO3_2_DIR_CTRL,
118 PCM186X_GPIO3_DIR,
119 4 << 4);
120 if (ret != kStatus_Success) goto end;
121
122 break;
123 default:
124 ret = kStatus_InvalidArgument;
125 goto end;
126 }
127
128 /* Set / clear gpio */
129 ret = PCM186x_ModifyReg(handle,
130 PCM186X_GPIO_IN_OUT,
131 1 << (gpio_nr + 4),
132 val ? 1 << (gpio_nr + 4) : 0);
133
134 end:
135 return ret;
136 }
137
dac_pcm186x_set_gpio(pcm186x_handle_t * handle,int gpio_nr)138 static status_t dac_pcm186x_set_gpio(pcm186x_handle_t *handle, int gpio_nr)
139 {
140 return dac_pcm186x_set_gpio_val(handle, gpio_nr, 1);
141 }
142
dac_pcm186x_clear_gpio(pcm186x_handle_t * handle,int gpio_nr)143 static status_t dac_pcm186x_clear_gpio(pcm186x_handle_t *handle, int gpio_nr)
144 {
145 return dac_pcm186x_set_gpio_val(handle, gpio_nr, 0);
146 }
147
PCM186x_SetFormat(pcm186x_handle_t * handle,uint32_t mclk,uint32_t sampleRate,uint32_t bitWidth)148 status_t PCM186x_SetFormat(pcm186x_handle_t *handle, uint32_t mclk, uint32_t sampleRate, uint32_t bitWidth)
149 {
150 status_t ret = kStatus_Success;
151 uint8_t fmt, wlen;
152
153 fmt = PCM186X_FMT_I2S;
154
155 switch (bitWidth) {
156 case kPCM186x_AudioBitWidth16bit:
157 wlen = PCM186X_WLEN_16;
158 break;
159 case kPCM186x_AudioBitWidth24bit:
160 wlen = PCM186X_WLEN_24;
161 break;
162 case kPCM186x_AudioBitWidth32bit:
163 wlen = PCM186X_WLEN_32;
164 break;
165 default:
166 ret = kStatus_InvalidArgument;
167 goto end;
168 }
169
170 /* Set slave mode */
171 ret = PCM186x_ModifyReg(handle,
172 PCM186X_CLK_CTRL,
173 PCM186X_MST_MODE,
174 0);
175 if (ret != kStatus_Success) goto end;
176
177 /* TODO: probably useless as we are not in DSP format */
178 ret = PCM186x_WriteReg(handle, PCM186X_TDM_TX_OFFSET, 0);
179 if (ret != kStatus_Success) goto end;
180
181 /* Set format */
182 ret = PCM186x_ModifyReg(handle,
183 PCM186X_PCM_CFG,
184 PCM186X_FMT,
185 fmt);
186 if (ret != kStatus_Success) goto end;
187
188 /* Set word length */
189 ret = PCM186x_ModifyReg(handle,
190 PCM186X_PCM_CFG,
191 PCM186X_RX_WLEN | PCM186X_TX_WLEN,
192 (wlen << 6) | (wlen << 2));
193 if (ret != kStatus_Success) goto end;
194
195 /* Power up analog */
196 ret = PCM186x_ModifyReg(handle,
197 PCM186X_POWER_CTRL,
198 PCM186X_PWRDN,
199 0);
200
201 end:
202 return ret;
203 }
204
PCM186x_Init(pcm186x_handle_t * handle,const pcm186x_config_t * config)205 status_t PCM186x_Init(pcm186x_handle_t *handle, const pcm186x_config_t *config)
206 {
207 status_t ret = kStatus_Success;
208
209 handle->config = config;
210
211 /* i2c bus initialization */
212 if (CODEC_I2C_Init(handle->i2cHandle, config->i2cConfig.codecI2CInstance, PCM186X_I2C_BAUDRATE,
213 config->i2cConfig.codecI2CSourceClock) != (status_t)kStatus_HAL_I2cSuccess)
214 {
215 return kStatus_Fail;
216 }
217
218 /* Reset ADC */
219 ret = PCM186x_WriteReg(handle, PCM186X_REG_00, PCM186X_RESET);
220 if (ret != kStatus_Success) goto end;
221
222 /* Turn PCM1863 LED GPIO ON */
223 ret = dac_pcm186x_set_gpio(handle, config->gpio_led);
224
225 end:
226 return ret;
227 }
228
PCM186x_Deinit(pcm186x_handle_t * handle)229 status_t PCM186x_Deinit(pcm186x_handle_t *handle)
230 {
231 status_t ret;
232
233 /* Reinit I2C in case it has been stopped by concurrent codec driver */
234 if (CODEC_I2C_Init(handle->i2cHandle, handle->config->i2cConfig.codecI2CInstance, PCM186X_I2C_BAUDRATE,
235 handle->config->i2cConfig.codecI2CSourceClock) != (status_t)kStatus_HAL_I2cSuccess)
236 return kStatus_Fail;
237
238 /* Power down analog */
239 ret = PCM186x_ModifyReg(handle,
240 PCM186X_POWER_CTRL,
241 PCM186X_PWRDN,
242 1);
243 if (ret != kStatus_Success) goto end;
244
245 /* Turn PCM1863 LED GPIO OFF */
246 ret = dac_pcm186x_clear_gpio(handle, handle->config->gpio_led);
247 if (ret != kStatus_Success) goto end;
248
249 ret = CODEC_I2C_Deinit(handle->i2cHandle);
250
251 end:
252 return ret;
253 }
254