1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  * Copyright (c) 2025 Croxel Inc
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/kernel.h>
9 #include "codec.h"
10 #include <zephyr/sys/printk.h>
11 #include <zephyr/drivers/i2c.h>
12 
13 #if DT_ON_BUS(WM8731_NODE, i2c)
14 
15 #define WM8731_I2C_NODE DT_BUS(WM8731_NODE)
16 #define WM8731_I2C_ADDR DT_REG_ADDR(WM8731_NODE)
17 
init_wm8731_i2c(void)18 bool init_wm8731_i2c(void)
19 {
20 	const struct device *const i2c_dev = DEVICE_DT_GET(WM8731_I2C_NODE);
21 
22 	/* Initialization data for WM8731 registers. */
23 	static const uint8_t init[][2] = {
24 		/*
25 		 * Reset Register:
26 		 * [8:0] RESET = 0 (reset device)
27 		 */
28 		{ 0x1E, 0x00 },
29 		/*
30 		 * Power Down Control:
31 		 *   [7] POWEROFF = 0 (Disable POWEROFF)
32 		 *   [6] CLKOUTPD = 1 (Enable Power Down)
33 		 *   [5] OSCPDD = 0 (Disable Power Down)
34 		 *   [4] OUTPD = 1 (Enable Power Down)
35 		 *   [3] DACPD = 0 (Disable Power Down)
36 		 *   [2] ADCPD = 0 (Disable Power Down)
37 		 *   [1] MICPD = 1 (Enable Power Down)
38 		 *   [0] LINEINPD = 0 (Disable Power Down)
39 		 */
40 		{ 0x0C, 0x52 },
41 		/*
42 		 * Left Line In:
43 		 *   [8] LRINBOTH = 1 (Enable Simultaneous Load)
44 		 *   [7] LINMUTE = 0 (Disable Mute)
45 		 * [4:0] LINVOL = 0x07 (-24 dB)
46 		 */
47 		{ 0x01, 0x07 },
48 		/*
49 		 * Left Headphone Out:
50 		 *   [8] LRHPBOTH = 1 (Enable Simultaneous Load)
51 		 *   [7] LZCEN = 0 (Disable)
52 		 * [6:0] LHPVOL = 0x79 (0 dB)
53 		 */
54 		{ 0x05, 0x79 },
55 		/*
56 		 * Analogue Audio Path Control:
57 		 * [7:6] SIDEATT = 0 (-6 dB)
58 		 *   [5] SIDETONE = 0 (Disable Side Tone)
59 		 *   [4] DACSEL = 1 (Select DAC)
60 		 *   [3] BYPASS = 0 (Disable Bypass)
61 		 *   [2] INSEL = 0 (Line Input Select to ADC)
62 		 *   [1] MUTEMIC = 1 (Enable Mute)
63 		 *   [0] MICBOOST = 0 (Disable Boost)
64 		 */
65 		{ 0x08, 0x12 },
66 		/*
67 		 * Digital Audio Path Control:
68 		 *   [4] HPOR = 0 (clear offset)
69 		 *   [3] DACMU = 0 (Disable soft mute)
70 		 * [2:1] DEEMP = 0 (Disable)
71 		 *   [0] ADCHPD = 1 (Disable High Pass Filter)
72 		 */
73 		{ 0x0A, 0x01 },
74 		/*
75 		 * Digital Audio Interface Format:
76 		 *   [7] BCLKINV = 0 (Don't invert BCLK)
77 		 *   [6] MS = 0 (Enable Slave Mode)
78 		 *   [5] LRSWAP = 0 (Right Channel DAC Data Right)
79 		 *   [4] LRP = 1 (Right Channel DAC data when DACLRC high)
80 		 * [3:2] IWL = 0 (16 bits)
81 		 * [1:0] FORMAT = 2 (I2S Format)
82 		 */
83 		{ 0x0E, 0x12 },
84 		/*
85 		 * Sampling Control:
86 		 *   [7] CLKODIV2 = 0 (CLOCKOUT is Core Clock)
87 		 *   [6] CLKIDIV2 = 0 (Core Clock is MCLK)
88 		 * [5:2] SR = 0x8 (44.1 kHz)
89 		 *   [1] BOSR = 0 (256fs)
90 		 *   [0] USB/NORMAL = 0 (Normal mode)
91 		 */
92 		{ 0x10, 0x20 },
93 		/*
94 		 * Active Control:
95 		 * [0] ACTIVE = 1 (Active)
96 		 */
97 		{ 0x12, 0x01 },
98 		/*
99 		 * As recommended in WAN_0111, set the OUTPD bit in the Power
100 		 * Down Control register to 0 at the very end of the power-on
101 		 * sequence.
102 		 */
103 		{ 0x0C, 0x42 }
104 	};
105 
106 	if (!device_is_ready(i2c_dev)) {
107 		printk("%s is not ready\n", i2c_dev->name);
108 		return false;
109 	}
110 
111 	for (int i = 0; i < ARRAY_SIZE(init); ++i) {
112 		const uint8_t *entry = init[i];
113 		int ret;
114 
115 		ret = i2c_reg_write_byte(i2c_dev, WM8731_I2C_ADDR,
116 					 entry[0], entry[1]);
117 		if (ret < 0) {
118 			printk("Initialization step %d failed\n", i);
119 			return false;
120 		}
121 	}
122 
123 	return true;
124 }
125 
126 #endif /* DT_ON_BUS(WM8731_NODE, i2c) */
127 
128 #if DT_ON_BUS(MAX9867_NODE, i2c)
129 
130 #define MAX9867_I2C_NODE             DT_BUS(MAX9867_NODE)
131 #define MAX9867_I2C_ADDR             DT_REG_ADDR(MAX9867_NODE)
132 /* Register addresses */
133 #define MAX9867_00_STATUS            0x00
134 #define MAX9867_01_JACKSENSE         0x01
135 #define MAX9867_02_AUX_HIGH          0x02
136 #define MAX9867_03_AUX_LOW           0x03
137 #define MAX9867_04_INT_EN            0x04
138 #define MAX9867_05_SYS_CLK           0x05
139 #define MAX9867_06_CLK_HIGH          0x06
140 #define MAX9867_07_CLK_LOW           0x07
141 #define MAX9867_08_DAI_FORMAT        0x08
142 #define MAX9867_09_DAI_CLOCK         0x09
143 #define MAX9867_0A_DIG_FILTER        0x0A
144 #define MAX9867_0B_SIDETONE          0x0B
145 #define MAX9867_0C_LVL_DAC           0x0C
146 #define MAX9867_0D_LVL_ADC           0x0D
147 #define MAX9867_0E_LVL_LINE_IN_LEFT  0x0E
148 #define MAX9867_0F_LVL_LINE_IN_RIGHT 0x0F
149 #define MAX9867_10_VOL_LEFT          0x10
150 #define MAX9867_11_VOL_RIGHT         0x11
151 #define MAX9867_12_MIC_GAIN_LEFT     0x12
152 #define MAX9867_13_MIC_GAIN_RIGHT    0x13
153 #define MAX9867_14_ADC_INPUT         0x14
154 #define MAX9867_15_MIC               0x15
155 #define MAX9867_16_MODE              0x16
156 #define MAX9867_17_PWR_SYS           0x17
157 #define MAX9867_FF_REV_ID            0xFF
158 
159 /* MAX9867_04_INT_EN */
160 #define MAX9867_ICLD   (1 << 7)
161 #define MAX9867_SDODLY (1 << 2)
162 
163 /* MAX9867_05_SYS_CLK */
164 #define MAX9867_PSCLK_POS 4
165 
166 /* MAX9867_06_CLK_HIGH */
167 #define MAX9867_PLL              (1 << 7)
168 #define MAX9867_NI_UPPER_8KHZ    0x10
169 #define MAX9867_NI_UPPER_16KHZ   0x20
170 #define MAX9867_NI_UPPER_24KHZ   0x30
171 #define MAX9867_NI_UPPER_32KHZ   0x40
172 #define MAX9867_NI_UPPER_44p1KHZ 0x58
173 #define MAX9867_NI_UPPER_48KHZ   0x60
174 
175 /* MAX9867_07_CLK_LOW */
176 #define MAX9867_NI_LOWER_OTHER   0x00
177 #define MAX9867_NI_LOWER_44p1KHZ 0x33
178 
179 /* MAX9867_08_DAI_FORMAT */
180 #define MAX9867_MAS    (1 << 7)
181 #define MAX9867_WCI    (1 << 6)
182 #define MAX9867_BCI    (1 << 5)
183 #define MAX9867_DLY    (1 << 4)
184 #define MAX9867_HIZOFF (1 << 3)
185 #define MAX9867_TDM    (1 << 2)
186 
187 /* MAX9867_09_DAI_CLOCK */
188 #define MAX9867_BSEL_PCLK_DIV8 0x06
189 
190 /* MAX9867_0D_LVL_ADC */
191 #define MAX9867_AVL_POS 4
192 #define MAX9867_AVR_POS 0
193 
194 /*
195  * MAX9867_0E_LVL_LINE_IN_LEFT
196  * MAX9867_0F_LVL_LINE_IN_RIGHT
197  */
198 #define MAX9867_LI_MUTE     (1 << 6)
199 #define MAX9867_LI_GAIN_POS 0
200 
201 /*
202  * MAX9867_10_VOL_LEFT
203  * MAX9867_11_VOL_RIGHT
204  */
205 #define MAX9867_VOL_POS 0
206 
207 /* MAX9867_14_ADC_INPUT */
208 #define MAX9867_MXINL_POS       6
209 #define MAX9867_MXINR_POS       4
210 #define MAX9867_MXIN_DIS        0
211 #define MAX9867_MXIN_ANALOG_MIC 1
212 #define MAX9867_MXIN_LINE       2
213 
214 /* MAX9867_15_MIC */
215 #define MAX9867_MICCLK_POS  6
216 #define MAX9867_DIGMICL_POS 5
217 #define MAX9867_DIGMICR_POS 4
218 
219 /* MAX9867_16_MODE */
220 #define MAX9867_HPMODE_POS          0
221 #define MAX9867_STEREO_SE_CLICKLESS 4
222 #define MAX9867_MONO_SE_CLICKLESS   5
223 
224 /* MAX9867_17_PWR_SYS */
225 #define MAX9867_SHDN  (1 << 7)
226 #define MAX9867_LNLEN (1 << 6)
227 #define MAX9867_LNREN (1 << 5)
228 #define MAX9867_DALEN (1 << 3)
229 #define MAX9867_DAREN (1 << 2)
230 #define MAX9867_ADLEN (1 << 1)
231 #define MAX9867_ADREN (1 << 0)
232 
init_max9867_i2c(void)233 bool init_max9867_i2c(void)
234 {
235 	const struct device *const i2c_dev = DEVICE_DT_GET(MAX9867_I2C_NODE);
236 
237 	/* Initialization data for MAX9867 registers. */
238 	static const uint8_t init[][2] = {
239 		/* Shutdown MAX9867 during configuration */
240 		{MAX9867_17_PWR_SYS, 0x00},
241 		/*
242 		 * Clear all regs to POR state. The MAX9867 does not not have an external
243 		 * reset signal. So manually writing 0, from (0x04 - 0x17)
244 		 */
245 		{MAX9867_04_INT_EN, 0x00},
246 		{MAX9867_05_SYS_CLK, 0x00},
247 		{MAX9867_06_CLK_HIGH, 0x00},
248 		{MAX9867_07_CLK_LOW, 0x00},
249 		{MAX9867_08_DAI_FORMAT, 0x00},
250 		{MAX9867_09_DAI_CLOCK, 0x00},
251 		{MAX9867_0A_DIG_FILTER, 0x00},
252 		{MAX9867_0B_SIDETONE, 0x00},
253 		{MAX9867_0C_LVL_DAC, 0x00},
254 		{MAX9867_0D_LVL_ADC, 0x00},
255 		{MAX9867_0E_LVL_LINE_IN_LEFT, 0x00},
256 		{MAX9867_0F_LVL_LINE_IN_RIGHT, 0x00},
257 		{MAX9867_10_VOL_LEFT, 0x00},
258 		{MAX9867_11_VOL_RIGHT, 0x00},
259 		{MAX9867_12_MIC_GAIN_LEFT, 0x00},
260 		{MAX9867_13_MIC_GAIN_RIGHT, 0x00},
261 		{MAX9867_14_ADC_INPUT, 0x00},
262 		{MAX9867_15_MIC, 0x00},
263 		{MAX9867_16_MODE, 0x00},
264 		{MAX9867_17_PWR_SYS, 0x00},
265 		/*
266 		 * Select MCLK prescaler. PSCLK divides MCLK to generate a PCLK between 10MHz and
267 		 * 20MHz. Set prescaler, FREQ field is 0 for Normal or PLL mode, < 20MHz.
268 		 */
269 		{MAX9867_05_SYS_CLK, 0x01 << MAX9867_PSCLK_POS},
270 		/* Configure codec to generate 48kHz sampling frequency in master mode */
271 		{MAX9867_06_CLK_HIGH, MAX9867_NI_UPPER_44p1KHZ},
272 		{MAX9867_07_CLK_LOW, MAX9867_NI_LOWER_44p1KHZ},
273 		{MAX9867_09_DAI_CLOCK, MAX9867_BSEL_PCLK_DIV8},
274 		/* I2S format */
275 		{MAX9867_08_DAI_FORMAT, MAX9867_MAS | MAX9867_DLY | MAX9867_HIZOFF},
276 		/* */
277 		{MAX9867_0A_DIG_FILTER, 0xA2},
278 		/* Select Digital microphone input */
279 		{MAX9867_15_MIC, ((0x1 << MAX9867_DIGMICR_POS))},
280 		/* ADC level */
281 		{MAX9867_0D_LVL_ADC, (3 << MAX9867_AVL_POS) | (3 << MAX9867_AVR_POS)},
282 		/*Set line-in level, disconnect line input from playback amplifiers */
283 		{MAX9867_0E_LVL_LINE_IN_LEFT, (0x0C << MAX9867_LI_GAIN_POS) | MAX9867_LI_MUTE},
284 		{MAX9867_0F_LVL_LINE_IN_RIGHT, (0x0C << MAX9867_LI_GAIN_POS) | MAX9867_LI_MUTE},
285 		/* Headphone mode */
286 		{MAX9867_16_MODE, MAX9867_STEREO_SE_CLICKLESS << MAX9867_HPMODE_POS},
287 		/* Set playback volume */
288 		{MAX9867_10_VOL_LEFT, 0x04 << MAX9867_VOL_POS},
289 		{MAX9867_11_VOL_RIGHT, 0x04 << MAX9867_VOL_POS},
290 		/* Enable */
291 		{MAX9867_17_PWR_SYS, MAX9867_SHDN | MAX9867_DALEN | MAX9867_DAREN | MAX9867_ADLEN},
292 	};
293 
294 	if (!device_is_ready(i2c_dev)) {
295 		printk("%s is not ready\n", i2c_dev->name);
296 		return false;
297 	}
298 
299 	for (int i = 0; i < ARRAY_SIZE(init); ++i) {
300 		const uint8_t *entry = init[i];
301 		int ret;
302 
303 		ret = i2c_reg_write_byte(i2c_dev, MAX9867_I2C_ADDR, entry[0], entry[1]);
304 		if (ret < 0) {
305 			printk("Initialization step %d failed with %d\n", i, ret);
306 			return false;
307 		}
308 	}
309 
310 	return true;
311 }
312 
313 #endif /* DT_ON_BUS(MAX9867_NODE, i2c) */
314