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