1 /*
2 * Copyright (c) 2023 Centralp
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ti_tas6422dac
8
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/gpio.h>
11 #include <zephyr/drivers/i2c.h>
12 #include <zephyr/audio/codec.h>
13
14 #include "tas6422dac.h"
15
16 #define LOG_LEVEL CONFIG_AUDIO_CODEC_LOG_LEVEL
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(tas6422dac);
19
20 #define TAS6422DAC_MUTE_GPIO_SUPPORT DT_ANY_INST_HAS_PROP_STATUS_OKAY(mute_gpios)
21
22 #define CODEC_OUTPUT_VOLUME_MAX (24 * 2)
23 #define CODEC_OUTPUT_VOLUME_MIN (-100 * 2)
24
25 struct codec_driver_config {
26 struct i2c_dt_spec bus;
27 #if TAS6422DAC_MUTE_GPIO_SUPPORT
28 struct gpio_dt_spec mute_gpio;
29 #endif /* TAS6422DAC_MUTE_GPIO_SUPPORT */
30 };
31
32 struct codec_driver_data {
33 };
34
35 enum tas6422dac_channel_t {
36 TAS6422DAC_CHANNEL_1,
37 TAS6422DAC_CHANNEL_2,
38 TAS6422DAC_CHANNEL_ALL,
39 TAS6422DAC_CHANNEL_UNKNOWN,
40 };
41
42 static enum tas6422dac_channel_t audio_to_tas6422dac_channel[] = {
43 [AUDIO_CHANNEL_FRONT_LEFT] = TAS6422DAC_CHANNEL_1,
44 [AUDIO_CHANNEL_FRONT_RIGHT] = TAS6422DAC_CHANNEL_2,
45 [AUDIO_CHANNEL_LFE] = TAS6422DAC_CHANNEL_UNKNOWN,
46 [AUDIO_CHANNEL_FRONT_CENTER] = TAS6422DAC_CHANNEL_UNKNOWN,
47 [AUDIO_CHANNEL_REAR_LEFT] = TAS6422DAC_CHANNEL_1,
48 [AUDIO_CHANNEL_REAR_RIGHT] = TAS6422DAC_CHANNEL_2,
49 [AUDIO_CHANNEL_REAR_CENTER] = TAS6422DAC_CHANNEL_UNKNOWN,
50 [AUDIO_CHANNEL_SIDE_LEFT] = TAS6422DAC_CHANNEL_1,
51 [AUDIO_CHANNEL_SIDE_RIGHT] = TAS6422DAC_CHANNEL_2,
52 [AUDIO_CHANNEL_ALL] = TAS6422DAC_CHANNEL_ALL,
53 };
54
55 static void codec_mute_output(const struct device *dev, enum tas6422dac_channel_t channel);
56 static void codec_unmute_output(const struct device *dev, enum tas6422dac_channel_t channel);
57 static void codec_write_reg(const struct device *dev, uint8_t reg, uint8_t val);
58 static void codec_read_reg(const struct device *dev, uint8_t reg, uint8_t *val);
59 static void codec_soft_reset(const struct device *dev);
60 static int codec_configure_dai(const struct device *dev, audio_dai_cfg_t *cfg);
61 static void codec_configure_output(const struct device *dev);
62 static int codec_set_output_volume(const struct device *dev, enum tas6422dac_channel_t channel,
63 int vol);
64
65 #if (LOG_LEVEL >= LOG_LEVEL_DEBUG)
66 static void codec_read_all_regs(const struct device *dev);
67 #define CODEC_DUMP_REGS(dev) codec_read_all_regs((dev))
68 #else
69 #define CODEC_DUMP_REGS(dev)
70 #endif
71
codec_initialize(const struct device * dev)72 static int codec_initialize(const struct device *dev)
73 {
74 const struct codec_driver_config *const dev_cfg = dev->config;
75
76 if (!device_is_ready(dev_cfg->bus.bus)) {
77 LOG_ERR("I2C device not ready");
78 return -ENODEV;
79 }
80
81 #if TAS6422DAC_MUTE_GPIO_SUPPORT
82 if (!device_is_ready(dev_cfg->mute_gpio.port)) {
83 LOG_ERR("GPIO device not ready");
84 return -ENODEV;
85 }
86 #endif /* TAS6422DAC_MUTE_GPIO_SUPPORT */
87
88 return 0;
89 }
90
codec_configure(const struct device * dev,struct audio_codec_cfg * cfg)91 static int codec_configure(const struct device *dev, struct audio_codec_cfg *cfg)
92 {
93 int ret;
94
95 if (cfg->dai_type != AUDIO_DAI_TYPE_I2S) {
96 LOG_ERR("dai_type must be AUDIO_DAI_TYPE_I2S");
97 return -EINVAL;
98 }
99
100 codec_soft_reset(dev);
101 ret = codec_configure_dai(dev, &cfg->dai_cfg);
102 codec_configure_output(dev);
103
104 return ret;
105 }
106
codec_start_output(const struct device * dev)107 static void codec_start_output(const struct device *dev)
108 {
109 codec_unmute_output(dev, TAS6422DAC_CHANNEL_ALL);
110
111 CODEC_DUMP_REGS(dev);
112 }
113
codec_stop_output(const struct device * dev)114 static void codec_stop_output(const struct device *dev)
115 {
116 codec_mute_output(dev, TAS6422DAC_CHANNEL_ALL);
117 }
118
codec_mute_output(const struct device * dev,enum tas6422dac_channel_t channel)119 static void codec_mute_output(const struct device *dev, enum tas6422dac_channel_t channel)
120 {
121 uint8_t val;
122
123 #if TAS6422DAC_MUTE_GPIO_SUPPORT
124 const struct codec_driver_config *const dev_cfg = dev->config;
125
126 gpio_pin_configure_dt(&dev_cfg->mute_gpio, GPIO_OUTPUT_ACTIVE);
127 #endif
128
129 codec_read_reg(dev, CH_STATE_CTRL_ADDR, &val);
130 switch (channel) {
131 case TAS6422DAC_CHANNEL_1:
132 val &= ~CH_STATE_CTRL_CH1_STATE_CTRL_MASK;
133 val |= CH_STATE_CTRL_CH1_STATE_CTRL(CH_STATE_CTRL_MUTE);
134 break;
135 case TAS6422DAC_CHANNEL_2:
136 val &= ~CH_STATE_CTRL_CH2_STATE_CTRL_MASK;
137 val |= CH_STATE_CTRL_CH2_STATE_CTRL(CH_STATE_CTRL_MUTE);
138 break;
139 case TAS6422DAC_CHANNEL_ALL:
140 val &= ~(CH_STATE_CTRL_CH1_STATE_CTRL_MASK | CH_STATE_CTRL_CH2_STATE_CTRL_MASK);
141 val |= CH_STATE_CTRL_CH1_STATE_CTRL(CH_STATE_CTRL_MUTE) |
142 CH_STATE_CTRL_CH2_STATE_CTRL(CH_STATE_CTRL_MUTE);
143 break;
144 case TAS6422DAC_CHANNEL_UNKNOWN:
145 default:
146 LOG_ERR("Invalid codec channel %u", channel);
147 return;
148 }
149 codec_write_reg(dev, CH_STATE_CTRL_ADDR, val);
150 }
151
codec_unmute_output(const struct device * dev,enum tas6422dac_channel_t channel)152 static void codec_unmute_output(const struct device *dev, enum tas6422dac_channel_t channel)
153 {
154 uint8_t val;
155
156 #if TAS6422DAC_MUTE_GPIO_SUPPORT
157 const struct codec_driver_config *const dev_cfg = dev->config;
158
159 gpio_pin_configure_dt(&dev_cfg->mute_gpio, GPIO_OUTPUT_INACTIVE);
160 #endif
161
162 codec_read_reg(dev, CH_STATE_CTRL_ADDR, &val);
163 switch (channel) {
164 case TAS6422DAC_CHANNEL_1:
165 val &= ~CH_STATE_CTRL_CH1_STATE_CTRL_MASK;
166 val |= CH_STATE_CTRL_CH1_STATE_CTRL(CH_STATE_CTRL_PLAY);
167 break;
168 case TAS6422DAC_CHANNEL_2:
169 val &= ~CH_STATE_CTRL_CH2_STATE_CTRL_MASK;
170 val |= CH_STATE_CTRL_CH2_STATE_CTRL(CH_STATE_CTRL_PLAY);
171 break;
172 case TAS6422DAC_CHANNEL_ALL:
173 val &= ~(CH_STATE_CTRL_CH1_STATE_CTRL_MASK | CH_STATE_CTRL_CH2_STATE_CTRL_MASK);
174 val |= CH_STATE_CTRL_CH1_STATE_CTRL(CH_STATE_CTRL_PLAY) |
175 CH_STATE_CTRL_CH2_STATE_CTRL(CH_STATE_CTRL_PLAY);
176 break;
177 case TAS6422DAC_CHANNEL_UNKNOWN:
178 default:
179 LOG_ERR("Invalid codec channel %u", channel);
180 return;
181 }
182 codec_write_reg(dev, CH_STATE_CTRL_ADDR, val);
183 }
184
codec_set_property(const struct device * dev,audio_property_t property,audio_channel_t channel,audio_property_value_t val)185 static int codec_set_property(const struct device *dev, audio_property_t property,
186 audio_channel_t channel, audio_property_value_t val)
187 {
188 enum tas6422dac_channel_t codec_channel = audio_to_tas6422dac_channel[channel];
189
190 if (codec_channel == TAS6422DAC_CHANNEL_UNKNOWN) {
191 LOG_ERR("Invalid channel %u", channel);
192 return -EINVAL;
193 }
194
195 switch (property) {
196 case AUDIO_PROPERTY_OUTPUT_VOLUME:
197 return codec_set_output_volume(dev, codec_channel, val.vol);
198
199 case AUDIO_PROPERTY_OUTPUT_MUTE:
200 if (val.mute) {
201 codec_mute_output(dev, codec_channel);
202 } else {
203 codec_unmute_output(dev, codec_channel);
204 }
205 return 0;
206
207 default:
208 break;
209 }
210
211 return -EINVAL;
212 }
213
codec_apply_properties(const struct device * dev)214 static int codec_apply_properties(const struct device *dev)
215 {
216 /* nothing to do because there is nothing cached */
217 return 0;
218 }
219
codec_write_reg(const struct device * dev,uint8_t reg,uint8_t val)220 static void codec_write_reg(const struct device *dev, uint8_t reg, uint8_t val)
221 {
222 const struct codec_driver_config *const dev_cfg = dev->config;
223
224 i2c_reg_write_byte_dt(&dev_cfg->bus, reg, val);
225 LOG_DBG("%s WR REG:0x%02x VAL:0x%02x", dev->name, reg, val);
226 }
227
codec_read_reg(const struct device * dev,uint8_t reg,uint8_t * val)228 static void codec_read_reg(const struct device *dev, uint8_t reg, uint8_t *val)
229 {
230 const struct codec_driver_config *const dev_cfg = dev->config;
231
232 i2c_reg_read_byte_dt(&dev_cfg->bus, reg, val);
233 LOG_DBG("%s RD REG:0x%02x VAL:0x%02x", dev->name, reg, *val);
234 }
235
codec_soft_reset(const struct device * dev)236 static void codec_soft_reset(const struct device *dev)
237 {
238 uint8_t val;
239
240 codec_read_reg(dev, MODE_CTRL_ADDR, &val);
241 val |= MODE_CTRL_RESET;
242 codec_write_reg(dev, MODE_CTRL_ADDR, val);
243 }
244
codec_configure_dai(const struct device * dev,audio_dai_cfg_t * cfg)245 static int codec_configure_dai(const struct device *dev, audio_dai_cfg_t *cfg)
246 {
247 uint8_t val;
248
249 codec_read_reg(dev, SAP_CTRL_ADDR, &val);
250
251 /* I2S mode */
252 val &= ~SAP_CTRL_INPUT_FORMAT_MASK;
253 val |= SAP_CTRL_INPUT_FORMAT(SAP_CTRL_INPUT_FORMAT_I2S);
254
255 /* Input sampling rate */
256 val &= ~SAP_CTRL_INPUT_SAMPLING_RATE_MASK;
257 switch (cfg->i2s.frame_clk_freq) {
258 case AUDIO_PCM_RATE_44P1K:
259 val |= SAP_CTRL_INPUT_SAMPLING_RATE(SAP_CTRL_INPUT_SAMPLING_RATE_44_1_KHZ);
260 break;
261 case AUDIO_PCM_RATE_48K:
262 val |= SAP_CTRL_INPUT_SAMPLING_RATE(SAP_CTRL_INPUT_SAMPLING_RATE_48_KHZ);
263 break;
264 case AUDIO_PCM_RATE_96K:
265 val |= SAP_CTRL_INPUT_SAMPLING_RATE(SAP_CTRL_INPUT_SAMPLING_RATE_96_KHZ);
266 break;
267 default:
268 LOG_ERR("Invalid sampling rate %zu", cfg->i2s.frame_clk_freq);
269 return -EINVAL;
270 }
271
272 codec_write_reg(dev, SAP_CTRL_ADDR, val);
273
274 return 0;
275 }
276
codec_configure_output(const struct device * dev)277 static void codec_configure_output(const struct device *dev)
278 {
279 uint8_t val;
280
281 /* Overcurrent level = 1 */
282 codec_read_reg(dev, MISC_CTRL_1_ADDR, &val);
283 val &= ~MISC_CTRL_1_OC_CONTROL_MASK;
284 codec_write_reg(dev, MISC_CTRL_1_ADDR, val);
285
286 /*
287 * PWM frequency = 10 fs
288 * Reduce PWM frequency to prevent component overtemperature
289 */
290 codec_read_reg(dev, MISC_CTRL_2_ADDR, &val);
291 val &= ~MISC_CTRL_2_PWM_FREQUENCY_MASK;
292 val |= MISC_CTRL_2_PWM_FREQUENCY(MISC_CTRL_2_PWM_FREQUENCY_10_FS);
293 codec_write_reg(dev, MISC_CTRL_2_ADDR, val);
294 }
295
codec_set_output_volume(const struct device * dev,enum tas6422dac_channel_t channel,int vol)296 static int codec_set_output_volume(const struct device *dev, enum tas6422dac_channel_t channel,
297 int vol)
298 {
299 uint8_t vol_val;
300
301 if ((vol > CODEC_OUTPUT_VOLUME_MAX) || (vol < CODEC_OUTPUT_VOLUME_MIN)) {
302 LOG_ERR("Invalid volume %d.%d dB", vol >> 1, ((uint32_t)vol & 1) ? 5 : 0);
303 return -EINVAL;
304 }
305
306 vol_val = vol + 0xcf;
307 switch (channel) {
308 case TAS6422DAC_CHANNEL_1:
309 codec_write_reg(dev, CH1_VOLUME_CTRL_ADDR, CH_VOLUME_CTRL_VOLUME(vol_val));
310 break;
311 case TAS6422DAC_CHANNEL_2:
312 codec_write_reg(dev, CH2_VOLUME_CTRL_ADDR, CH_VOLUME_CTRL_VOLUME(vol_val));
313 break;
314 case TAS6422DAC_CHANNEL_ALL:
315 codec_write_reg(dev, CH1_VOLUME_CTRL_ADDR, CH_VOLUME_CTRL_VOLUME(vol_val));
316 codec_write_reg(dev, CH2_VOLUME_CTRL_ADDR, CH_VOLUME_CTRL_VOLUME(vol_val));
317 break;
318 case TAS6422DAC_CHANNEL_UNKNOWN:
319 default:
320 LOG_ERR("Invalid codec channel %u", channel);
321 return -EINVAL;
322 }
323
324 return 0;
325 }
326
327 #if (LOG_LEVEL >= LOG_LEVEL_DEBUG)
codec_read_all_regs(const struct device * dev)328 static void codec_read_all_regs(const struct device *dev)
329 {
330 uint8_t val;
331
332 codec_read_reg(dev, MODE_CTRL_ADDR, &val);
333 codec_read_reg(dev, MISC_CTRL_1_ADDR, &val);
334 codec_read_reg(dev, MISC_CTRL_2_ADDR, &val);
335 codec_read_reg(dev, SAP_CTRL_ADDR, &val);
336 codec_read_reg(dev, CH_STATE_CTRL_ADDR, &val);
337 codec_read_reg(dev, CH1_VOLUME_CTRL_ADDR, &val);
338 codec_read_reg(dev, CH2_VOLUME_CTRL_ADDR, &val);
339 codec_read_reg(dev, DC_LDG_CTRL_1_ADDR, &val);
340 codec_read_reg(dev, DC_LDG_CTRL_2_ADDR, &val);
341 codec_read_reg(dev, DC_LDG_REPORT_1_ADDR, &val);
342 codec_read_reg(dev, DC_LDG_REPORT_3_ADDR, &val);
343 codec_read_reg(dev, CH_FAULTS_ADDR, &val);
344 codec_read_reg(dev, GLOBAL_FAULTS_1_ADDR, &val);
345 codec_read_reg(dev, GLOBAL_FAULTS_2_ADDR, &val);
346 codec_read_reg(dev, WARNINGS_ADDR, &val);
347 codec_read_reg(dev, PIN_CTRL_ADDR, &val);
348 codec_read_reg(dev, MISC_CTRL_3_ADDR, &val);
349 codec_read_reg(dev, ILIMIT_STATUS_ADDR, &val);
350 codec_read_reg(dev, MISC_CTRL_4_ADDR, &val);
351 codec_read_reg(dev, MISC_CTRL_5_ADDR, &val);
352 }
353 #endif
354
355 static const struct audio_codec_api codec_driver_api = {
356 .configure = codec_configure,
357 .start_output = codec_start_output,
358 .stop_output = codec_stop_output,
359 .set_property = codec_set_property,
360 .apply_properties = codec_apply_properties,
361 };
362
363 #if TAS6422DAC_MUTE_GPIO_SUPPORT
364 #define TAS6422DAC_MUTE_GPIO_INIT(n) .mute_gpio = GPIO_DT_SPEC_INST_GET(n, mute_gpios)
365 #else
366 #define TAS6422DAC_MUTE_GPIO_INIT(n)
367 #endif /* TAS6422DAC_MUTE_GPIO_SUPPORT */
368
369 #define TAS6422DAC_INIT(n) \
370 static struct codec_driver_data codec_device_data_##n; \
371 \
372 static struct codec_driver_config codec_device_config_##n = { \
373 .bus = I2C_DT_SPEC_INST_GET(n), TAS6422DAC_MUTE_GPIO_INIT(n)}; \
374 \
375 DEVICE_DT_INST_DEFINE(n, codec_initialize, NULL, &codec_device_data_##n, \
376 &codec_device_config_##n, POST_KERNEL, \
377 CONFIG_AUDIO_CODEC_INIT_PRIORITY, &codec_driver_api);
378
379 DT_INST_FOREACH_STATUS_OKAY(TAS6422DAC_INIT)
380