1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * cx18 audio-related functions |
4 | * |
5 | * Derived from ivtv-audio.c |
6 | * |
7 | * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> |
8 | */ |
9 | |
10 | #include "cx18-driver.h" |
11 | #include "cx18-io.h" |
12 | #include "cx18-cards.h" |
13 | #include "cx18-audio.h" |
14 | |
15 | #define CX18_AUDIO_ENABLE 0xc72014 |
16 | #define CX18_AI1_MUX_MASK 0x30 |
17 | #define CX18_AI1_MUX_I2S1 0x00 |
18 | #define CX18_AI1_MUX_I2S2 0x10 |
19 | #define CX18_AI1_MUX_843_I2S 0x20 |
20 | |
21 | /* Selects the audio input and output according to the current |
22 | settings. */ |
23 | int cx18_audio_set_io(struct cx18 *cx) |
24 | { |
25 | const struct cx18_card_audio_input *in; |
26 | u32 u, v; |
27 | int err; |
28 | |
29 | /* Determine which input to use */ |
30 | if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) |
31 | in = &cx->card->radio_input; |
32 | else |
33 | in = &cx->card->audio_inputs[cx->audio_input]; |
34 | |
35 | /* handle muxer chips */ |
36 | v4l2_subdev_call(cx->sd_extmux, audio, s_routing, |
37 | (u32) in->muxer_input, 0, 0); |
38 | |
39 | err = cx18_call_hw_err(cx, cx->card->hw_audio_ctrl, |
40 | audio, s_routing, in->audio_input, 0, 0); |
41 | if (err) |
42 | return err; |
43 | |
44 | /* FIXME - this internal mux should be abstracted to a subdev */ |
45 | u = cx18_read_reg(cx, CX18_AUDIO_ENABLE); |
46 | v = u & ~CX18_AI1_MUX_MASK; |
47 | switch (in->audio_input) { |
48 | case CX18_AV_AUDIO_SERIAL1: |
49 | v |= CX18_AI1_MUX_I2S1; |
50 | break; |
51 | case CX18_AV_AUDIO_SERIAL2: |
52 | v |= CX18_AI1_MUX_I2S2; |
53 | break; |
54 | default: |
55 | v |= CX18_AI1_MUX_843_I2S; |
56 | break; |
57 | } |
58 | if (v == u) { |
59 | /* force a toggle of some AI1 MUX control bits */ |
60 | u &= ~CX18_AI1_MUX_MASK; |
61 | switch (in->audio_input) { |
62 | case CX18_AV_AUDIO_SERIAL1: |
63 | u |= CX18_AI1_MUX_843_I2S; |
64 | break; |
65 | case CX18_AV_AUDIO_SERIAL2: |
66 | u |= CX18_AI1_MUX_843_I2S; |
67 | break; |
68 | default: |
69 | u |= CX18_AI1_MUX_I2S1; |
70 | break; |
71 | } |
72 | cx18_write_reg_expect(cx, val: u | 0xb00, CX18_AUDIO_ENABLE, |
73 | eval: u, CX18_AI1_MUX_MASK); |
74 | } |
75 | cx18_write_reg_expect(cx, val: v | 0xb00, CX18_AUDIO_ENABLE, |
76 | eval: v, CX18_AI1_MUX_MASK); |
77 | return 0; |
78 | } |
79 | |