1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016-2021 NXP
4  * Copyright (c) 2022 HPMicro
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  */
9 
10 #ifndef _HPM_WM8960_H_
11 #define _HPM_WM8960_H_
12 
13 //#include "hpm_i2c_drv.h"
14 //#include "hpm_common.h"
15 #include <rtthread.h>
16 #include <rtdevice.h>
17 #include "rtt_board.h"
18 #include "drivers/i2c.h"
19 #include "hpm_wm8960_regs.h"
20 
21 #define WM8960_I2C_ADDR 0x1A
22 
23 typedef enum wm8960_module {
24     wm8960_module_adc            = 0, /* ADC module in WM8960 */
25     wm8960_module_dac            = 1, /* DAC module in WM8960 */
26     wm8960_module_vref           = 2, /* VREF module */
27     wm8960_module_headphone      = 3, /* Headphone */
28     wm8960_module_micbais        = 4, /* Mic bias */
29     wm8960_module_ana_in         = 6, /* Analog in PGA  */
30     wm8960_module_lineout        = 7, /* Line out module */
31     wm8960_module_speaker        = 8, /* Speaker module */
32     wm8960_module_output_mixer   = 9, /* Output mixer */
33 } wm8960_module_t;
34 
35 /* wm8960 play source for output mixer */
36 typedef enum wm8960_play_source {
37     wm8960_play_source_input_mixer   = 1, /* Input Boost Mixer to Output Mixer */
38     wm8960_play_source_input3        = 2, /* L/RINPUT3 to Output Mixer */
39     wm8960_play_source_dac           = 4, /* DAC to Output Mixer */
40 } wm8960_play_source_t;
41 
42 /* WM8960 data route */
43 typedef enum wm8960_route {
44     wm8960_route_bypass            = 0, /* ANA_IN->Headphone. */
45     wm8960_route_playback          = 1, /*  I2SIN->DAC->Headphone. */
46     wm8960_route_playback_and_record = 2, /* I2SIN->DAC->Headphone, ANA_IN->ADC->I2SOUT. */
47     wm8960_route_record            = 5  /* ANA_IN->ADC->I2SOUT. */
48 } wm8960_route_t;
49 
50 /* The audio data transfer protocol choice */
51 typedef enum wm8960_protocol {
52     wm8960_bus_i2s             = 2,           /* I2S type */
53     wm8960_bus_left_justified  = 1,           /* Left justified mode */
54     wm8960_bus_right_justified = 0,           /* Right justified mode */
55     wm8960_bus_pcma            = 3,           /* PCM A mode */
56     wm8960_bus_pcmb            = 3 | (1 << 4) /* PCM B mode */
57 } wm8960_protocol_t;
58 
59 /* wm8960 input source */
60 typedef enum wm8960_input {
61     wm8960_input_closed                  = 0, /* Input device is closed */
62     wm8960_input_single_ended_mic        = 1, /* Input as single ended mic, only use L/RINPUT1 */
63     wm8960_input_differential_mic_input2 = 2, /* Input as differential mic, use L/RINPUT1 and L/RINPUT2 */
64     wm8960_input_differential_mic_input3 = 3, /* Input as differential mic, use L/RINPUT1 and L/RINPUT3*/
65     wm8960_input_line_input2             = 4, /* Input as line input, only use L/RINPUT2 */
66     wm8960_input_line_input3             = 5  /* Input as line input, only use L/RINPUT3 */
67 } wm8960_input_t;
68 
69 /* wm8960 audio format */
70 typedef struct wm8960_audio_format {
71     uint32_t mclk_hz;     /* master clock frequency */
72     uint32_t sample_rate; /* sample rate */
73     uint32_t bit_width;   /* bit width */
74 } wm8960_audio_format_t;
75 
76 /* configure structure of WM8960 */
77 typedef struct wm8960_config {
78     wm8960_route_t route;                      /* Audio data route.*/
79     wm8960_protocol_t bus;                     /* Audio transfer protocol */
80     bool enable_speaker;                       /* True means enable class D speaker as output, false means no */
81     wm8960_input_t left_input;                 /* Left input source for WM8960 */
82     wm8960_input_t right_input;                /* Right input source for wm8960 */
83     wm8960_play_source_t play_source;          /* play source */
84     wm8960_audio_format_t format;              /* Audio format */
85 } wm8960_config_t;
86 
87 typedef struct {
88     struct rt_i2c_bus_device *i2c_bus;  /* I2C bus device */
89     uint8_t slave_address;             /* code device address */
90 } wm8960_control_t;
91 
92 
93 #if defined(__cplusplus)
94 extern "C" {
95 #endif
96 
97 /**
98  * @brief WM8960 initialize function.
99  *
100  * @param control WM8960 control structure.
101  * @param config WM8960 configuration structure.
102  */
103 hpm_stat_t wm8960_init(wm8960_control_t *control, wm8960_config_t *config);
104 
105 /**
106  * @brief Deinit the WM8960 codec.
107  *
108  * This function close all modules in WM8960 to save power.
109  *
110  * @param control WM8960 control structure pointer.
111  */
112 hpm_stat_t wm8960_deinit(wm8960_control_t *control);
113 
114 /**
115  * @brief Set audio data route in WM8960.
116  *
117  * This function would set the data route according to route.
118  *
119  * @param control WM8960 control structure.
120  * @param config Audio configure structure in WM8960.
121  */
122 hpm_stat_t wm8960_set_data_route(wm8960_control_t *control, wm8960_config_t *config);
123 
124 /**
125  * @brief Set left audio input source in WM8960.
126  *
127  * @param control WM8960 control structure.
128  * @param input Audio input source.
129  */
130 hpm_stat_t wm8960_set_left_input(wm8960_control_t *control, wm8960_input_t input);
131 
132 /**
133  * @brief Set right audio input source in WM8960.
134  *
135  * @param control WM8960 control structure.
136  * @param input Audio input source.
137  */
138 hpm_stat_t wm8960_set_right_input(wm8960_control_t *control, wm8960_input_t input);
139 
140 /**
141  * @brief Set the audio transfer protocol.
142  *
143  * @param control WM8960 control structure.
144  * @param protocol Audio data transfer protocol.
145  */
146 hpm_stat_t wm8960_set_protocol(wm8960_control_t *control, wm8960_protocol_t protocol);
147 
148 /**
149  * @brief Set the volume of different modules in WM8960.
150  *
151  * This function would set the volume of WM8960 modules. Uses need to appoint the module.
152  * The function assume that left channel and right channel has the same volume.
153  *
154  * Module:wm8960_module_adc, volume range value: 0 is mute, 1-255 is -97db to 30db
155  * Module:wm8960_module_dac, volume range value: 0 is mute, 1-255 is -127db to 0db
156  * Module:wm8960_module_headphone, volume range value: 0 - 2F is mute, 0x30 - 0x7F is -73db to 6db
157  * Module:wm8960_module_ana_in, volume range value: 0 - 0x3F is -17.25db to 30db
158  * Module:wm8960_module_speaker, volume range value: 0 - 2F is mute, 0x30 - 0x7F is -73db to 6db
159  *
160  *
161  * @param control WM8960 control structure.
162  * @param module Module to set volume, it can be ADC, DAC, Headphone and so on.
163  * @param volume Volume value need to be set.
164  */
165 hpm_stat_t wm8960_set_volume(wm8960_control_t *control, wm8960_module_t module, uint32_t volume);
166 
167 /**
168  * @brief Enable/disable expected module.
169  *
170  * @param control WM8960 control structure.
171  * @param module Module expected to enable.
172  * @param enable Enable or disable moudles.
173  */
174 hpm_stat_t wm8960_set_module(wm8960_control_t *control, wm8960_module_t module, bool enable);
175 
176 /**
177  * @brief SET the WM8960 play source.
178  *
179  * @param control WM8960 control structure.
180  * @param play_source play source
181  *
182  * @return kStatus_WM8904_Success if successful, different code otherwise..
183  */
184 hpm_stat_t wm8960_config_input_to_output_mixer(wm8960_control_t *control, uint32_t play_source);
185 
186 /**
187  * @brief Configure the data format of audio data.
188  *
189  * This function would configure the registers about the sample rate, bit depths.
190  *
191  * @param control WM8960 control structure pointer.
192  * @param sysclk system clock of the codec which can be generated by MCLK or PLL output.
193  * @param sample_rate Sample rate of audio file running in WM8960. WM8960 now
194  * supports 8k, 11.025k, 12k, 16k, 22.05k, 24k, 32k, 44.1k, 48k and 96k sample rate.
195  * @param bits Bit depth of audio file (WM8960 only supports 16bit, 20bit, 24bit
196  * and 32 bit in HW).
197  */
198 hpm_stat_t wm8960_set_data_format(wm8960_control_t *control, uint32_t sysclk, uint32_t sample_rate, uint32_t bits);
199 
200 
201 /**
202  * @brief Write register to WM8960 using I2C.
203  *
204  * @param control WM8960 control structure.
205  * @param reg The register address in WM8960.
206  * @param val Value needs to write into the register.
207  */
208 hpm_stat_t wm8960_write_reg(wm8960_control_t *control, uint8_t reg, uint16_t val);
209 
210 /**
211  * @brief Read register from WM8960 using I2C.
212  * @param reg The register address in WM8960.
213  * @param val Value written to.
214  */
215 hpm_stat_t wm8960_read_reg(uint8_t reg, uint16_t *val);
216 
217 /**
218  * @brief Modify some bits in the register using I2C.
219  * @param control WM8960 control structure.
220  * @param reg The register address in WM8960.
221  * @param mask The mask code for the bits want to write. The bit you want to write should be 0.
222  * @param val Value needs to write into the register.
223  */
224 hpm_stat_t wm8960_modify_reg(wm8960_control_t *control, uint8_t reg, uint16_t mask, uint16_t val);
225 
226 
227 #endif /* _HPM_WM8960_H_ */
228