1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2018-12-05     zylx         The first version for STM32F4xx
9  * 2019-4-25      misonyo      port to IMXRT
10  */
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 
14 #include "bsp_wm8960.h"
15 #include <stdlib.h>
16 #include <drv_log.h>
17 #include <rthw.h>
18 static rt_uint16_t wm8960_regval_tbl[56] = {
19     0x0097, 0x0097, 0x0000, 0x0000, 0x0000, 0x0008, 0x0000, 0x000a, 0x01c0, 0x0000, 0x00ff, 0x00ff, 0x0000, 0x0000,
20     0x0000, 0x0000, 0x0000, 0x007b, 0x0100, 0x0032, 0x0000, 0x00c3, 0x00c3, 0x01c0, 0x0000, 0x0000, 0x0000, 0x0000,
21     0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0100, 0x0050, 0x0050, 0x0050, 0x0050, 0x0000, 0x0000, 0x0000, 0x0000,
22     0x0040, 0x0000, 0x0000, 0x0050, 0x0050, 0x0000, 0x0002, 0x0037, 0x004d, 0x0080, 0x0008, 0x0031, 0x0026, 0x00e9,
23 };
24 static rt_uint16_t reg_cache[WM8960_CACHEREGNUM];
wm8960_write_reg(struct rt_i2c_bus_device * dev,rt_uint8_t reg,rt_uint16_t val)25 static void wm8960_write_reg(struct rt_i2c_bus_device *dev,  rt_uint8_t reg, rt_uint16_t val)
26 {
27     struct rt_i2c_msg msg;
28     rt_uint8_t send_buffer[2];
29     RT_ASSERT(dev != RT_NULL);
30     /* store temp */
31     rt_uint16_t buff = val;
32     reg_cache[reg] = buff;
33     send_buffer[0] = (reg << 1) | ((val >> 8U) & 0x0001U);
34     send_buffer[1] = (rt_uint8_t)(val & 0xFF);
35     msg.addr = 0x1A;////WM8960_I2C_ADDR 0x1A
36     msg.flags = RT_I2C_WR;
37     msg.len = 2;
38     msg.buf = send_buffer;
39     rt_i2c_transfer(dev, &msg, 1);
40 }
wm8960_read_reg(struct rt_i2c_bus_device * dev,rt_uint8_t reg,rt_uint16_t * val)41 static void wm8960_read_reg(struct rt_i2c_bus_device *dev, rt_uint8_t reg, rt_uint16_t *val)
42 {
43     *val = reg_cache[reg];
44 }
45 
wm8960_modify_reg(struct rt_i2c_bus_device * dev,rt_uint8_t reg,rt_uint16_t mask,rt_uint16_t val)46 static void wm8960_modify_reg(struct rt_i2c_bus_device *dev, rt_uint8_t reg, rt_uint16_t mask, rt_uint16_t val)
47 {
48     uint16_t reg_val = 0;
49     wm8960_read_reg(dev, reg, &reg_val);
50     reg_val &= (rt_uint16_t)~mask;
51     reg_val |= val;
52 
53     wm8960_write_reg(dev, reg, reg_val);
54 }
WM8960_SetMasterSlave(struct rt_i2c_bus_device * dev,rt_bool_t master)55 void WM8960_SetMasterSlave(struct rt_i2c_bus_device *dev, rt_bool_t master)
56 {
57     if (master == 1)
58     {
59         wm8960_modify_reg(dev, WM8960_IFACE1, WM8960_IFACE1_MS_MASK, WM8960_IFACE1_MS(WM8960_IFACE1_MASTER));
60     }
61     else
62     {
63         wm8960_modify_reg(dev, WM8960_IFACE1, WM8960_IFACE1_MS_MASK, WM8960_IFACE1_MS(WM8960_IFACE1_SLAVE));
64     }
65 }
66 
WM8960_SetModule(struct rt_i2c_bus_device * dev,wm8960_module_t module,rt_bool_t isEnabled)67 void WM8960_SetModule(struct rt_i2c_bus_device *dev, wm8960_module_t module, rt_bool_t isEnabled)
68 {
69     switch (module)
70     {
71     case kWM8960_ModuleADC:
72         wm8960_modify_reg(dev, WM8960_POWER1, WM8960_POWER1_ADCL_MASK,
73                           ((uint16_t)isEnabled << WM8960_POWER1_ADCL_SHIFT));
74         wm8960_modify_reg(dev, WM8960_POWER1, WM8960_POWER1_ADCR_MASK,
75                           ((uint16_t)isEnabled << WM8960_POWER1_ADCR_SHIFT));
76         break;
77     case kWM8960_ModuleDAC:
78         wm8960_modify_reg(dev, WM8960_POWER2, WM8960_POWER2_DACL_MASK,
79                           ((uint16_t)isEnabled << WM8960_POWER2_DACL_SHIFT));
80         wm8960_modify_reg(dev, WM8960_POWER2, WM8960_POWER2_DACR_MASK,
81                           ((uint16_t)isEnabled << WM8960_POWER2_DACR_SHIFT));
82         break;
83     case kWM8960_ModuleVREF:
84         wm8960_modify_reg(dev, WM8960_POWER1, WM8960_POWER1_VREF_MASK,
85                           ((uint16_t)isEnabled << WM8960_POWER1_VREF_SHIFT));
86         break;
87     case kWM8960_ModuleLineIn:
88         wm8960_modify_reg(dev, WM8960_POWER1, WM8960_POWER1_AINL_MASK,
89                           ((uint16_t)isEnabled << WM8960_POWER1_AINL_SHIFT));
90         wm8960_modify_reg(dev, WM8960_POWER1, WM8960_POWER1_AINR_MASK,
91                           ((uint16_t)isEnabled << WM8960_POWER1_AINR_SHIFT));
92         break;
93     case kWM8960_ModuleLineOut:
94         wm8960_modify_reg(dev, WM8960_POWER2, WM8960_POWER2_LOUT1_MASK,
95                           ((uint16_t)isEnabled << WM8960_POWER2_LOUT1_SHIFT));
96         wm8960_modify_reg(dev, WM8960_POWER2, WM8960_POWER2_ROUT1_MASK,
97                           ((uint16_t)isEnabled << WM8960_POWER2_ROUT1_SHIFT));
98         break;
99     case kWM8960_ModuleMICB:
100         wm8960_modify_reg(dev, WM8960_POWER1, WM8960_POWER1_MICB_MASK,
101                           ((uint16_t)isEnabled << WM8960_POWER1_MICB_SHIFT));
102         break;
103     case kWM8960_ModuleSpeaker:
104         wm8960_modify_reg(dev, WM8960_POWER2, WM8960_POWER2_SPKL_MASK,
105                           ((uint16_t)isEnabled << WM8960_POWER2_SPKL_SHIFT));
106         wm8960_modify_reg(dev, WM8960_POWER2, WM8960_POWER2_SPKR_MASK,
107                           ((uint16_t)isEnabled << WM8960_POWER2_SPKR_SHIFT));
108         wm8960_write_reg(dev, WM8960_CLASSD1, 0xF7);
109         break;
110     case kWM8960_ModuleMIC:
111         wm8960_modify_reg(dev, WM8960_POWER3, WM8960_POWER3_LMIC_MASK,
112                           ((uint16_t)isEnabled << WM8960_POWER3_LMIC_SHIFT));
113         wm8960_modify_reg(dev, WM8960_POWER3, WM8960_POWER3_RMIC_MASK,
114                           ((uint16_t)isEnabled << WM8960_POWER3_RMIC_SHIFT));
115         break;
116     case kWM8960_ModuleOMIX:
117         wm8960_modify_reg(dev, WM8960_POWER3, WM8960_POWER3_LOMIX_MASK,
118                           ((uint16_t)isEnabled << WM8960_POWER3_LOMIX_SHIFT));
119         wm8960_modify_reg(dev, WM8960_POWER3, WM8960_POWER3_ROMIX_MASK,
120                           ((uint16_t)isEnabled << WM8960_POWER3_ROMIX_SHIFT));
121         break;
122     default:
123         break;
124     }
125 }
126 
WM8960_SetDataRoute(struct rt_i2c_bus_device * dev,wm8960_route_t route)127 void WM8960_SetDataRoute(struct rt_i2c_bus_device *dev, wm8960_route_t route)
128 {
129     switch (route)
130     {
131     case kWM8960_RouteBypass:
132         /* Bypass means from line-in to HP*/
133         /*
134          * Left LINPUT3 to left output mixer, LINPUT3 left output mixer volume = 0dB
135          */
136         wm8960_write_reg(dev, WM8960_LOUTMIX, 0x80);
137 
138         /*
139          * Right RINPUT3 to right output mixer, RINPUT3 right output mixer volume = 0dB
140          */
141         wm8960_write_reg(dev, WM8960_ROUTMIX, 0x80);
142         break;
143     case kWM8960_RoutePlayback:
144         /* Data route I2S_IN-> DAC-> HP */
145         /*
146          * Left DAC to left output mixer, LINPUT3 left output mixer volume = 0dB
147          */
148         wm8960_write_reg(dev, WM8960_LOUTMIX, 0x100);
149 
150         /*
151          * Right DAC to right output mixer, RINPUT3 right output mixer volume = 0dB
152          */
153         wm8960_write_reg(dev, WM8960_ROUTMIX, 0x100);
154         wm8960_write_reg(dev, WM8960_POWER3, 0x0C);
155         /* Set power for DAC */
156         WM8960_SetModule(dev, kWM8960_ModuleDAC, RT_TRUE);
157         WM8960_SetModule(dev, kWM8960_ModuleOMIX, RT_TRUE);
158         WM8960_SetModule(dev, kWM8960_ModuleLineOut, RT_TRUE);
159         break;
160     case kWM8960_RoutePlaybackandRecord:
161         /*
162          * Left DAC to left output mixer, LINPUT3 left output mixer volume = 0dB
163          */
164         wm8960_write_reg(dev, WM8960_LOUTMIX, 0x100);
165 
166         /*
167          * Right DAC to right output mixer, RINPUT3 right output mixer volume = 0dB
168          */
169         wm8960_write_reg(dev, WM8960_ROUTMIX, 0x100);
170         wm8960_write_reg(dev, WM8960_POWER3, 0x3C);
171         WM8960_SetModule(dev, kWM8960_ModuleDAC, RT_TRUE);
172         WM8960_SetModule(dev, kWM8960_ModuleADC, RT_TRUE);
173         WM8960_SetModule(dev, kWM8960_ModuleLineIn, RT_TRUE);
174         WM8960_SetModule(dev, kWM8960_ModuleOMIX, RT_TRUE);
175         WM8960_SetModule(dev, kWM8960_ModuleLineOut, RT_TRUE);
176         break;
177     case kWM8960_RouteRecord:
178         /* LINE_IN->ADC->I2S_OUT */
179         /*
180          * Left and right input boost, LIN3BOOST and RIN3BOOST = 0dB
181          */
182         wm8960_write_reg(dev, WM8960_POWER3, 0x30);
183         /* Power up ADC and AIN */
184         WM8960_SetModule(dev, kWM8960_ModuleLineIn, RT_TRUE);
185         WM8960_SetModule(dev, kWM8960_ModuleADC, RT_TRUE);
186         break;
187     default:
188         break;
189     }
190 }
191 
WM8960_SetLeftInput(struct rt_i2c_bus_device * dev,wm8960_input_t input)192 void WM8960_SetLeftInput(struct rt_i2c_bus_device *dev, wm8960_input_t input)
193 {
194     uint16_t val = 0;
195 
196     switch (input)
197     {
198     case kWM8960_InputSingleEndedMic:
199         /* Only LMN1 enabled, LMICBOOST to 13db, LMIC2B enabled */
200         wm8960_read_reg(dev,WM8960_POWER1, &val);
201         val |= (WM8960_POWER1_AINL_MASK | WM8960_POWER1_ADCL_MASK | WM8960_POWER1_MICB_MASK);
202         wm8960_write_reg(dev, WM8960_POWER1, val);
203         wm8960_write_reg(dev, WM8960_LINPATH, 0x138);
204         wm8960_write_reg(dev, WM8960_LINVOL, 0x117);
205         break;
206     case kWM8960_InputDifferentialMicInput2:
207         wm8960_read_reg(dev,WM8960_POWER1, &val);
208         val |= (WM8960_POWER1_AINL_MASK | WM8960_POWER1_ADCL_MASK | WM8960_POWER1_MICB_MASK);
209         wm8960_write_reg(dev, WM8960_POWER1, val);
210         wm8960_write_reg(dev, WM8960_LINPATH, 0x178);
211         wm8960_write_reg(dev, WM8960_LINVOL, 0x117);
212         break;
213     case kWM8960_InputDifferentialMicInput3:
214         wm8960_read_reg(dev,WM8960_POWER1, &val);
215         val |= (WM8960_POWER1_AINL_MASK | WM8960_POWER1_ADCL_MASK | WM8960_POWER1_MICB_MASK);
216         wm8960_write_reg(dev, WM8960_POWER1, val);
217         wm8960_write_reg(dev, WM8960_LINPATH, 0x1B8);
218         wm8960_write_reg(dev, WM8960_LINVOL, 0x117);
219         break;
220     case kWM8960_InputLineINPUT2:
221         wm8960_read_reg(dev,WM8960_POWER1, &val);
222         val |= (WM8960_POWER1_AINL_MASK | WM8960_POWER1_ADCL_MASK);
223         wm8960_write_reg(dev, WM8960_POWER1, val);
224         wm8960_read_reg(dev,WM8960_INBMIX1, &val);
225         val |= 0xE;
226         wm8960_write_reg(dev, WM8960_INBMIX1, val);
227         break;
228     case kWM8960_InputLineINPUT3:
229         wm8960_read_reg(dev,WM8960_POWER1, &val);
230         val |= (WM8960_POWER1_AINL_MASK | WM8960_POWER1_ADCL_MASK);
231         wm8960_write_reg(dev, WM8960_POWER1, val);
232         wm8960_read_reg(dev,WM8960_INBMIX1, &val);
233         val |= 0x70;
234         wm8960_write_reg(dev, WM8960_INBMIX1, val);
235         break;
236     default:
237         break;
238     }
239 }
240 
WM8960_SetRightInput(struct rt_i2c_bus_device * dev,wm8960_input_t input)241 void WM8960_SetRightInput(struct rt_i2c_bus_device *dev, wm8960_input_t input)
242 {
243     uint16_t val = 0;
244 
245     switch (input)
246     {
247     case kWM8960_InputSingleEndedMic:
248         /* Only LMN1 enabled, LMICBOOST to 13db, LMIC2B enabled */
249         wm8960_read_reg(dev,WM8960_POWER1, &val);
250         val |= (WM8960_POWER1_AINR_MASK | WM8960_POWER1_ADCR_MASK | WM8960_POWER1_MICB_MASK);
251         wm8960_write_reg(dev, WM8960_POWER1, val);
252         wm8960_write_reg(dev, WM8960_RINPATH, 0x138);
253         wm8960_write_reg(dev, WM8960_RINVOL, 0x117);
254         break;
255     case kWM8960_InputDifferentialMicInput2:
256         wm8960_read_reg(dev,WM8960_POWER1, &val);
257         val |= (WM8960_POWER1_AINR_MASK | WM8960_POWER1_ADCR_MASK | WM8960_POWER1_MICB_MASK);
258         wm8960_write_reg(dev, WM8960_POWER1, val);
259         wm8960_write_reg(dev, WM8960_RINPATH, 0x178);
260         wm8960_write_reg(dev, WM8960_RINVOL, 0x117);
261         break;
262     case kWM8960_InputDifferentialMicInput3:
263         wm8960_read_reg(dev,WM8960_POWER1, &val);
264         val |= (WM8960_POWER1_AINR_MASK | WM8960_POWER1_ADCR_MASK | WM8960_POWER1_MICB_MASK);
265         wm8960_write_reg(dev, WM8960_POWER1, val);
266         wm8960_write_reg(dev, WM8960_RINPATH, 0x1B8);
267         wm8960_write_reg(dev, WM8960_RINVOL, 0x117);
268         break;
269     case kWM8960_InputLineINPUT2:
270         wm8960_read_reg(dev,WM8960_POWER1, &val);
271         val |= (WM8960_POWER1_AINR_MASK | WM8960_POWER1_ADCR_MASK);
272         wm8960_write_reg(dev, WM8960_POWER1, val);
273         wm8960_read_reg(dev,WM8960_INBMIX2, &val);
274         val |= 0xE;
275         wm8960_write_reg(dev, WM8960_INBMIX2, val);
276         break;
277     case kWM8960_InputLineINPUT3:
278         wm8960_read_reg(dev,WM8960_POWER1, &val);
279         val |= (WM8960_POWER1_AINR_MASK | WM8960_POWER1_ADCR_MASK);
280         wm8960_write_reg(dev, WM8960_POWER1, val);
281         wm8960_read_reg(dev,WM8960_INBMIX2, &val);
282         val |= 0x70;
283         wm8960_write_reg(dev, WM8960_INBMIX2, val);
284         break;
285     default:
286         break;
287     }
288 }
289 
WM8960_SetProtocol(struct rt_i2c_bus_device * dev,wm8960_protocol_t protocol)290 void WM8960_SetProtocol(struct rt_i2c_bus_device *dev, wm8960_protocol_t protocol)
291 {
292     wm8960_modify_reg(dev, WM8960_IFACE1, WM8960_IFACE1_FORMAT_MASK | WM8960_IFACE1_LRP_MASK, protocol);
293 }
294 
WM8960_SetVolume(struct rt_i2c_bus_device * dev,wm8960_module_t module,rt_uint32_t volume)295 void WM8960_SetVolume(struct rt_i2c_bus_device *dev, wm8960_module_t module, rt_uint32_t volume)
296 {
297     uint16_t vol = 0;
298     switch (module)
299     {
300     case kWM8960_ModuleADC:
301         vol = volume;
302         wm8960_write_reg(dev, WM8960_LADC, vol);
303         wm8960_write_reg(dev, WM8960_RADC, vol);
304         /* Update volume */
305         vol = 0x100 | volume;
306         wm8960_write_reg(dev, WM8960_LADC, vol);
307         wm8960_write_reg(dev, WM8960_RADC, vol);
308         break;
309     case kWM8960_ModuleDAC:
310         vol = volume;
311         wm8960_write_reg(dev, WM8960_LDAC, vol);
312         wm8960_write_reg(dev, WM8960_RDAC, vol);
313         vol = 0x100 | volume;
314         wm8960_write_reg(dev, WM8960_LDAC, vol);
315         wm8960_write_reg(dev, WM8960_RDAC, vol);
316         break;
317     case kWM8960_ModuleHP:
318         vol = volume;
319         wm8960_write_reg(dev, WM8960_LOUT1, vol);
320         wm8960_write_reg(dev, WM8960_ROUT1, vol);
321         vol = 0x100 | volume;
322         wm8960_write_reg(dev, WM8960_LOUT1, vol);
323         wm8960_write_reg(dev, WM8960_ROUT1, vol);
324         break;
325     case kWM8960_ModuleLineIn:
326         vol = volume;
327         wm8960_write_reg(dev, WM8960_LINVOL, vol);
328         wm8960_write_reg(dev, WM8960_RINVOL, vol);
329         vol = 0x100 | volume;
330         wm8960_write_reg(dev, WM8960_LINVOL, vol);
331         wm8960_write_reg(dev, WM8960_RINVOL, vol);
332         break;
333     case kWM8960_ModuleSpeaker:
334         vol = volume;
335         wm8960_write_reg(dev, WM8960_LOUT2, vol);
336         wm8960_write_reg(dev, WM8960_ROUT2, vol);
337         vol = 0x100 | volume;
338         wm8960_write_reg(dev, WM8960_LOUT2, vol);
339         wm8960_write_reg(dev, WM8960_ROUT2, vol);
340         break;
341     default:
342         break;
343     }
344 }
345 
WM8960_GetVolume(struct rt_i2c_bus_device * dev,wm8960_module_t module)346 rt_uint32_t WM8960_GetVolume(struct rt_i2c_bus_device *dev, wm8960_module_t module)
347 {
348     uint16_t vol = 0;
349     switch (module)
350     {
351     case kWM8960_ModuleADC:
352         wm8960_read_reg(dev,WM8960_LADC, &vol);
353         vol &= 0xFF;
354         break;
355     case kWM8960_ModuleDAC:
356         wm8960_read_reg(dev,WM8960_LDAC, &vol);
357         vol &= 0xFF;
358         break;
359     case kWM8960_ModuleHP:
360         wm8960_read_reg(dev,WM8960_LOUT1, &vol);
361         vol &= 0x7F;
362         break;
363     case kWM8960_ModuleLineOut:
364         wm8960_read_reg(dev,WM8960_LINVOL, &vol);
365         vol &= 0x3F;
366         break;
367     default:
368         vol = 0;
369         break;
370     }
371     return vol;
372 }
373 
WM8960_SetMute(struct rt_i2c_bus_device * dev,wm8960_module_t module,rt_bool_t isEnabled)374 void WM8960_SetMute(struct rt_i2c_bus_device *dev, wm8960_module_t module, rt_bool_t isEnabled)
375 {
376     switch (module)
377     {
378     case kWM8960_ModuleADC:
379         /*
380          * Digital Mute
381          */
382         if (isEnabled)
383         {
384             wm8960_write_reg(dev, WM8960_LADC, 0x100);
385             wm8960_write_reg(dev, WM8960_RADC, 0x100);
386         }
387         else
388         {
389             wm8960_write_reg(dev, WM8960_LADC, 0x1C3);
390             wm8960_write_reg(dev, WM8960_RADC, 0x1C3);
391         }
392         break;
393     case kWM8960_ModuleDAC:
394         /*
395          * Digital mute
396          */
397         if (isEnabled)
398         {
399             wm8960_write_reg(dev, WM8960_LDAC, 0x100);
400             wm8960_write_reg(dev, WM8960_RDAC, 0x100);
401         }
402         else
403         {
404             wm8960_write_reg(dev, WM8960_LDAC, 0x1FF);
405             wm8960_write_reg(dev, WM8960_RDAC, 0x1FF);
406         }
407         break;
408     case kWM8960_ModuleHP:
409         /*
410          * Analog mute
411          */
412         if (isEnabled)
413         {
414             wm8960_write_reg(dev, WM8960_LOUT1, 0x100);
415             wm8960_write_reg(dev, WM8960_ROUT1, 0x100);
416         }
417         else
418         {
419             wm8960_write_reg(dev, WM8960_LOUT1, 0x16F);
420             wm8960_write_reg(dev, WM8960_ROUT1, 0x16F);
421         }
422         break;
423 
424     case kWM8960_ModuleSpeaker:
425         if (isEnabled)
426         {
427             wm8960_write_reg(dev, WM8960_LOUT2, 0x100);
428             wm8960_write_reg(dev, WM8960_ROUT2, 0x100);
429         }
430         else
431         {
432             wm8960_write_reg(dev, WM8960_LOUT2, 0x16F);
433             wm8960_write_reg(dev, WM8960_ROUT2, 0x16f);
434         }
435         break;
436 
437     case kWM8960_ModuleLineOut:
438         break;
439     default:
440         break;
441     }
442 }
443 
WM8960_ConfigDataFormat(struct rt_i2c_bus_device * dev,rt_uint32_t sysclk,rt_uint32_t sample_rate,rt_uint32_t bits)444 void WM8960_ConfigDataFormat(struct rt_i2c_bus_device *dev, rt_uint32_t sysclk, rt_uint32_t sample_rate, rt_uint32_t bits)
445 {
446     uint32_t divider = 0;
447     uint16_t val     = 0;
448 
449     /* Compute sample rate divider, dac and adc are the same sample rate */
450     divider = sysclk / sample_rate;
451     if (divider == 256)
452     {
453         val = 0;
454     }
455     if (divider > 256)
456     {
457         val = (((divider / 256U) << 6U) | ((divider / 256U) << 3U));
458     }
459 
460     wm8960_write_reg(dev, WM8960_CLOCK1, val);
461 
462     /* Compute bclk divider */
463     divider /= bits * 2;
464     switch (divider)
465     {
466     case 4:
467     case 5:
468     case 6:
469         val = (0x1C0 | divider);
470         break;
471     case 8:
472         val = 0x1C7;
473         break;
474     case 11:
475         val = 0x1C8;
476         break;
477     case 12:
478         val = 0x1C9;
479         break;
480     case 16:
481         val = 0x1CA;
482         break;
483     case 22:
484         val = 0x1CB;
485         break;
486     case 24:
487         val = 0x1CC;
488         break;
489     case 32:
490         val = 0x1CF;
491         break;
492     default:
493         break;
494 
495     }
496 
497     wm8960_write_reg(dev, WM8960_CLOCK2, val);
498     /*
499      * Slave mode (MS = 0), LRP = 0, 32bit WL, left justified (FORMAT[1:0]=0b01)
500      */
501     switch (bits)
502     {
503     case 16:
504         wm8960_modify_reg(dev, WM8960_IFACE1, WM8960_IFACE1_WL_MASK,
505                           WM8960_IFACE1_WL(WM8960_IFACE1_WL_16BITS));
506         break;
507     case 20:
508         wm8960_modify_reg(dev, WM8960_IFACE1, WM8960_IFACE1_WL_MASK,
509                           WM8960_IFACE1_WL(WM8960_IFACE1_WL_20BITS));
510         break;
511     case 24:
512         wm8960_modify_reg(dev, WM8960_IFACE1, WM8960_IFACE1_WL_MASK,
513                           WM8960_IFACE1_WL(WM8960_IFACE1_WL_24BITS));
514         break;
515     case 32:
516         wm8960_modify_reg(dev, WM8960_IFACE1, WM8960_IFACE1_WL_MASK,
517                           WM8960_IFACE1_WL(WM8960_IFACE1_WL_32BITS));
518         break;
519     default:
520         break;
521     }
522 }
523 
WM8960_Deinit(struct rt_i2c_bus_device * dev)524 void WM8960_Deinit(struct rt_i2c_bus_device *dev)
525 {
526     WM8960_SetModule(dev, kWM8960_ModuleADC, RT_FALSE);
527     WM8960_SetModule(dev, kWM8960_ModuleDAC, RT_FALSE);
528     WM8960_SetModule(dev, kWM8960_ModuleVREF, RT_FALSE);
529     WM8960_SetModule(dev, kWM8960_ModuleLineIn, RT_FALSE);
530     WM8960_SetModule(dev, kWM8960_ModuleLineOut, RT_FALSE);
531     WM8960_SetModule(dev, kWM8960_ModuleSpeaker, RT_FALSE);
532 }
533 
WM8960_init(struct rt_i2c_bus_device * dev,wm8960_config_t * wm8960Config)534 void WM8960_init(struct rt_i2c_bus_device *dev, wm8960_config_t *wm8960Config)
535 {
536     wm8960_config_t *config = wm8960Config;
537     rt_memcpy(reg_cache, wm8960_regval_tbl, sizeof(wm8960_regval_tbl));
538     /* Reset the codec */
539     wm8960_write_reg(dev, WM8960_RESET, 0x00);
540     /*
541      * VMID=50K, Enable VREF, AINL, AINR, ADCL and ADCR
542      * I2S_IN (bit 0), I2S_OUT (bit 1), DAP (bit 4), DAC (bit 5), ADC (bit 6) are powered on
543      */
544     wm8960_write_reg(dev, WM8960_POWER1, 0xFE);
545     /*
546      * Enable DACL, DACR, LOUT1, ROUT1, PLL down
547      */
548     wm8960_write_reg(dev, WM8960_POWER2, 0x1E0);
549     /*
550      * Enable left and right channel input PGA, left and right output mixer
551      */
552     wm8960_write_reg(dev, WM8960_POWER3, 0x3C);
553     /* ADC and DAC uses same clock */
554     wm8960_write_reg(dev, WM8960_IFACE2, 0x40);
555     /* set data route */
556     WM8960_SetDataRoute(dev, config->route);
557     /* set data protocol */
558     WM8960_SetProtocol(dev, config->bus);
559     /* set master or slave */
560     WM8960_SetMasterSlave(dev, config->master_slave);
561     /* select left input */
562     WM8960_SetLeftInput(dev, config->leftInputSource);
563     /* select right input */
564     WM8960_SetRightInput(dev, config->rightInputSource);
565     /* speaker power */
566     if (config->enableSpeaker)
567     {
568         WM8960_SetModule(dev, kWM8960_ModuleSpeaker, RT_TRUE);
569     }
570     wm8960_write_reg(dev, WM8960_ADDCTL1, 0x0C0);
571     wm8960_write_reg(dev, WM8960_ADDCTL4, 0x40);
572 
573     wm8960_write_reg(dev, WM8960_BYPASS1, 0x0);
574     wm8960_write_reg(dev, WM8960_BYPASS2, 0x0);
575     /*
576      * ADC volume, 0dB
577      */
578     wm8960_write_reg(dev, WM8960_LADC, 0x1C3);
579     wm8960_write_reg(dev, WM8960_RADC, 0x1C3);
580 
581     /*
582      * Digital DAC volume, 0dB
583      */
584     wm8960_write_reg(dev, WM8960_LDAC, 0x1E0);
585     wm8960_write_reg(dev, WM8960_RDAC, 0x1E0);
586 
587     /*
588      * Headphone volume, LOUT1 and ROUT1, 0dB
589      */
590     wm8960_write_reg(dev, WM8960_LOUT1, 0x16F);
591     wm8960_write_reg(dev, WM8960_ROUT1, 0x16F);
592 
593     /* Unmute DAC. */
594     wm8960_write_reg(dev, WM8960_DACCTL1, 0x0000);
595     wm8960_write_reg(dev, WM8960_LINVOL, 0x117);
596     wm8960_write_reg(dev, WM8960_RINVOL, 0x117);
597 
598     WM8960_ConfigDataFormat(dev, config->format.mclk_HZ, config->format.sampleRate, config->format.bitWidth);
599 }
WM8960_SetPlay(struct rt_i2c_bus_device * dev,uint32_t playSource)600 void WM8960_SetPlay(struct rt_i2c_bus_device *dev, uint32_t playSource)
601 {
602     if (kWM8960_PlaySourcePGA & playSource)
603     {
604         wm8960_modify_reg(dev, WM8960_BYPASS1, 0x80U, 0x80U);
605         wm8960_modify_reg(dev, WM8960_BYPASS2, 0x80U, 0x80U);
606         wm8960_modify_reg(dev, WM8960_LOUTMIX, 0x180U, 0U);
607         wm8960_modify_reg(dev, WM8960_ROUTMIX, 0x180U, 0U);
608     }
609 
610     if (playSource & kWM8960_PlaySourceDAC)
611     {
612         wm8960_modify_reg(dev, WM8960_BYPASS1, 0x80U, 0x00U);
613         wm8960_modify_reg(dev, WM8960_BYPASS2, 0x80U, 0x00U);
614         wm8960_modify_reg(dev, WM8960_LOUTMIX, 0x180U, 0x100U);
615         wm8960_modify_reg(dev, WM8960_ROUTMIX, 0x180U, 0x100U);
616     }
617 
618     if (playSource & kWM8960_PlaySourceInput)
619     {
620         wm8960_modify_reg(dev, WM8960_BYPASS1, 0x80U, 0x0U);
621         wm8960_modify_reg(dev, WM8960_BYPASS2, 0x80U, 0x0U);
622         wm8960_modify_reg(dev, WM8960_LOUTMIX, 0x180U, 0x80U);
623         wm8960_modify_reg(dev, WM8960_ROUTMIX, 0x180U, 0x80U);
624     }
625 }
626