1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /* cx25840 audio functions
3*4882a593Smuzhiyun */
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <linux/videodev2.h>
7*4882a593Smuzhiyun #include <linux/i2c.h>
8*4882a593Smuzhiyun #include <media/v4l2-common.h>
9*4882a593Smuzhiyun #include <media/drv-intf/cx25840.h>
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include "cx25840-core.h"
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun /*
14*4882a593Smuzhiyun * Note: The PLL and SRC parameters are based on a reference frequency that
15*4882a593Smuzhiyun * would ideally be:
16*4882a593Smuzhiyun *
17*4882a593Smuzhiyun * NTSC Color subcarrier freq * 8 = 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
18*4882a593Smuzhiyun *
19*4882a593Smuzhiyun * However, it's not the exact reference frequency that matters, only that the
20*4882a593Smuzhiyun * firmware and modules that comprise the driver for a particular board all
21*4882a593Smuzhiyun * use the same value (close to the ideal value).
22*4882a593Smuzhiyun *
23*4882a593Smuzhiyun * Comments below will note which reference frequency is assumed for various
24*4882a593Smuzhiyun * parameters. They will usually be one of
25*4882a593Smuzhiyun *
26*4882a593Smuzhiyun * ref_freq = 28.636360 MHz
27*4882a593Smuzhiyun * or
28*4882a593Smuzhiyun * ref_freq = 28.636363 MHz
29*4882a593Smuzhiyun */
30*4882a593Smuzhiyun
cx25840_set_audclk_freq(struct i2c_client * client,u32 freq)31*4882a593Smuzhiyun static int cx25840_set_audclk_freq(struct i2c_client *client, u32 freq)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun struct cx25840_state *state = to_state(i2c_get_clientdata(client));
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun if (state->aud_input != CX25840_AUDIO_SERIAL) {
36*4882a593Smuzhiyun switch (freq) {
37*4882a593Smuzhiyun case 32000:
38*4882a593Smuzhiyun /*
39*4882a593Smuzhiyun * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
40*4882a593Smuzhiyun * AUX_PLL Integer = 0x06, AUX PLL Post Divider = 0x10
41*4882a593Smuzhiyun */
42*4882a593Smuzhiyun cx25840_write4(client, 0x108, 0x1006040f);
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun /*
45*4882a593Smuzhiyun * VID_PLL Fraction (register 0x10c) = 0x2be2fe
46*4882a593Smuzhiyun * 28636360 * 0xf.15f17f0/4 = 108 MHz
47*4882a593Smuzhiyun * 432 MHz pre-postdivide
48*4882a593Smuzhiyun */
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun /*
51*4882a593Smuzhiyun * AUX_PLL Fraction = 0x1bb39ee
52*4882a593Smuzhiyun * 28636363 * 0x6.dd9cf70/0x10 = 32000 * 384
53*4882a593Smuzhiyun * 196.6 MHz pre-postdivide
54*4882a593Smuzhiyun * FIXME < 200 MHz is out of specified valid range
55*4882a593Smuzhiyun * FIXME 28636363 ref_freq doesn't match VID PLL ref
56*4882a593Smuzhiyun */
57*4882a593Smuzhiyun cx25840_write4(client, 0x110, 0x01bb39ee);
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /*
60*4882a593Smuzhiyun * SA_MCLK_SEL = 1
61*4882a593Smuzhiyun * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
62*4882a593Smuzhiyun */
63*4882a593Smuzhiyun cx25840_write(client, 0x127, 0x50);
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun if (is_cx2583x(state))
66*4882a593Smuzhiyun break;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun /* src3/4/6_ctl */
69*4882a593Smuzhiyun /* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */
70*4882a593Smuzhiyun cx25840_write4(client, 0x900, 0x0801f77f);
71*4882a593Smuzhiyun cx25840_write4(client, 0x904, 0x0801f77f);
72*4882a593Smuzhiyun cx25840_write4(client, 0x90c, 0x0801f77f);
73*4882a593Smuzhiyun break;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun case 44100:
76*4882a593Smuzhiyun /*
77*4882a593Smuzhiyun * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
78*4882a593Smuzhiyun * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x10
79*4882a593Smuzhiyun */
80*4882a593Smuzhiyun cx25840_write4(client, 0x108, 0x1009040f);
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun /*
83*4882a593Smuzhiyun * VID_PLL Fraction (register 0x10c) = 0x2be2fe
84*4882a593Smuzhiyun * 28636360 * 0xf.15f17f0/4 = 108 MHz
85*4882a593Smuzhiyun * 432 MHz pre-postdivide
86*4882a593Smuzhiyun */
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /*
89*4882a593Smuzhiyun * AUX_PLL Fraction = 0x0ec6bd6
90*4882a593Smuzhiyun * 28636363 * 0x9.7635eb0/0x10 = 44100 * 384
91*4882a593Smuzhiyun * 271 MHz pre-postdivide
92*4882a593Smuzhiyun * FIXME 28636363 ref_freq doesn't match VID PLL ref
93*4882a593Smuzhiyun */
94*4882a593Smuzhiyun cx25840_write4(client, 0x110, 0x00ec6bd6);
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun /*
97*4882a593Smuzhiyun * SA_MCLK_SEL = 1
98*4882a593Smuzhiyun * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
99*4882a593Smuzhiyun */
100*4882a593Smuzhiyun cx25840_write(client, 0x127, 0x50);
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun if (is_cx2583x(state))
103*4882a593Smuzhiyun break;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun /* src3/4/6_ctl */
106*4882a593Smuzhiyun /* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */
107*4882a593Smuzhiyun cx25840_write4(client, 0x900, 0x08016d59);
108*4882a593Smuzhiyun cx25840_write4(client, 0x904, 0x08016d59);
109*4882a593Smuzhiyun cx25840_write4(client, 0x90c, 0x08016d59);
110*4882a593Smuzhiyun break;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun case 48000:
113*4882a593Smuzhiyun /*
114*4882a593Smuzhiyun * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
115*4882a593Smuzhiyun * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x10
116*4882a593Smuzhiyun */
117*4882a593Smuzhiyun cx25840_write4(client, 0x108, 0x100a040f);
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun /*
120*4882a593Smuzhiyun * VID_PLL Fraction (register 0x10c) = 0x2be2fe
121*4882a593Smuzhiyun * 28636360 * 0xf.15f17f0/4 = 108 MHz
122*4882a593Smuzhiyun * 432 MHz pre-postdivide
123*4882a593Smuzhiyun */
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun /*
126*4882a593Smuzhiyun * AUX_PLL Fraction = 0x098d6e5
127*4882a593Smuzhiyun * 28636363 * 0xa.4c6b728/0x10 = 48000 * 384
128*4882a593Smuzhiyun * 295 MHz pre-postdivide
129*4882a593Smuzhiyun * FIXME 28636363 ref_freq doesn't match VID PLL ref
130*4882a593Smuzhiyun */
131*4882a593Smuzhiyun cx25840_write4(client, 0x110, 0x0098d6e5);
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun /*
134*4882a593Smuzhiyun * SA_MCLK_SEL = 1
135*4882a593Smuzhiyun * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
136*4882a593Smuzhiyun */
137*4882a593Smuzhiyun cx25840_write(client, 0x127, 0x50);
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun if (is_cx2583x(state))
140*4882a593Smuzhiyun break;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun /* src3/4/6_ctl */
143*4882a593Smuzhiyun /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
144*4882a593Smuzhiyun cx25840_write4(client, 0x900, 0x08014faa);
145*4882a593Smuzhiyun cx25840_write4(client, 0x904, 0x08014faa);
146*4882a593Smuzhiyun cx25840_write4(client, 0x90c, 0x08014faa);
147*4882a593Smuzhiyun break;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun } else {
150*4882a593Smuzhiyun switch (freq) {
151*4882a593Smuzhiyun case 32000:
152*4882a593Smuzhiyun /*
153*4882a593Smuzhiyun * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
154*4882a593Smuzhiyun * AUX_PLL Integer = 0x08, AUX PLL Post Divider = 0x1e
155*4882a593Smuzhiyun */
156*4882a593Smuzhiyun cx25840_write4(client, 0x108, 0x1e08040f);
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun /*
159*4882a593Smuzhiyun * VID_PLL Fraction (register 0x10c) = 0x2be2fe
160*4882a593Smuzhiyun * 28636360 * 0xf.15f17f0/4 = 108 MHz
161*4882a593Smuzhiyun * 432 MHz pre-postdivide
162*4882a593Smuzhiyun */
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun /*
165*4882a593Smuzhiyun * AUX_PLL Fraction = 0x12a0869
166*4882a593Smuzhiyun * 28636363 * 0x8.9504348/0x1e = 32000 * 256
167*4882a593Smuzhiyun * 246 MHz pre-postdivide
168*4882a593Smuzhiyun * FIXME 28636363 ref_freq doesn't match VID PLL ref
169*4882a593Smuzhiyun */
170*4882a593Smuzhiyun cx25840_write4(client, 0x110, 0x012a0869);
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /*
173*4882a593Smuzhiyun * SA_MCLK_SEL = 1
174*4882a593Smuzhiyun * SA_MCLK_DIV = 0x14 = 256/384 * AUX_PLL post dvivider
175*4882a593Smuzhiyun */
176*4882a593Smuzhiyun cx25840_write(client, 0x127, 0x54);
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun if (is_cx2583x(state))
179*4882a593Smuzhiyun break;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun /* src1_ctl */
182*4882a593Smuzhiyun /* 0x1.0000 = 32000/32000 */
183*4882a593Smuzhiyun cx25840_write4(client, 0x8f8, 0x08010000);
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun /* src3/4/6_ctl */
186*4882a593Smuzhiyun /* 0x2.0000 = 2 * (32000/32000) */
187*4882a593Smuzhiyun cx25840_write4(client, 0x900, 0x08020000);
188*4882a593Smuzhiyun cx25840_write4(client, 0x904, 0x08020000);
189*4882a593Smuzhiyun cx25840_write4(client, 0x90c, 0x08020000);
190*4882a593Smuzhiyun break;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun case 44100:
193*4882a593Smuzhiyun /*
194*4882a593Smuzhiyun * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
195*4882a593Smuzhiyun * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x18
196*4882a593Smuzhiyun */
197*4882a593Smuzhiyun cx25840_write4(client, 0x108, 0x1809040f);
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun /*
200*4882a593Smuzhiyun * VID_PLL Fraction (register 0x10c) = 0x2be2fe
201*4882a593Smuzhiyun * 28636360 * 0xf.15f17f0/4 = 108 MHz
202*4882a593Smuzhiyun * 432 MHz pre-postdivide
203*4882a593Smuzhiyun */
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun /*
206*4882a593Smuzhiyun * AUX_PLL Fraction = 0x0ec6bd6
207*4882a593Smuzhiyun * 28636363 * 0x9.7635eb0/0x18 = 44100 * 256
208*4882a593Smuzhiyun * 271 MHz pre-postdivide
209*4882a593Smuzhiyun * FIXME 28636363 ref_freq doesn't match VID PLL ref
210*4882a593Smuzhiyun */
211*4882a593Smuzhiyun cx25840_write4(client, 0x110, 0x00ec6bd6);
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun /*
214*4882a593Smuzhiyun * SA_MCLK_SEL = 1
215*4882a593Smuzhiyun * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
216*4882a593Smuzhiyun */
217*4882a593Smuzhiyun cx25840_write(client, 0x127, 0x50);
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun if (is_cx2583x(state))
220*4882a593Smuzhiyun break;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun /* src1_ctl */
223*4882a593Smuzhiyun /* 0x1.60cd = 44100/32000 */
224*4882a593Smuzhiyun cx25840_write4(client, 0x8f8, 0x080160cd);
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun /* src3/4/6_ctl */
227*4882a593Smuzhiyun /* 0x1.7385 = 2 * (32000/44100) */
228*4882a593Smuzhiyun cx25840_write4(client, 0x900, 0x08017385);
229*4882a593Smuzhiyun cx25840_write4(client, 0x904, 0x08017385);
230*4882a593Smuzhiyun cx25840_write4(client, 0x90c, 0x08017385);
231*4882a593Smuzhiyun break;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun case 48000:
234*4882a593Smuzhiyun /*
235*4882a593Smuzhiyun * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
236*4882a593Smuzhiyun * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x18
237*4882a593Smuzhiyun */
238*4882a593Smuzhiyun cx25840_write4(client, 0x108, 0x180a040f);
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun /*
241*4882a593Smuzhiyun * VID_PLL Fraction (register 0x10c) = 0x2be2fe
242*4882a593Smuzhiyun * 28636360 * 0xf.15f17f0/4 = 108 MHz
243*4882a593Smuzhiyun * 432 MHz pre-postdivide
244*4882a593Smuzhiyun */
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /*
247*4882a593Smuzhiyun * AUX_PLL Fraction = 0x098d6e5
248*4882a593Smuzhiyun * 28636363 * 0xa.4c6b728/0x18 = 48000 * 256
249*4882a593Smuzhiyun * 295 MHz pre-postdivide
250*4882a593Smuzhiyun * FIXME 28636363 ref_freq doesn't match VID PLL ref
251*4882a593Smuzhiyun */
252*4882a593Smuzhiyun cx25840_write4(client, 0x110, 0x0098d6e5);
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun /*
255*4882a593Smuzhiyun * SA_MCLK_SEL = 1
256*4882a593Smuzhiyun * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
257*4882a593Smuzhiyun */
258*4882a593Smuzhiyun cx25840_write(client, 0x127, 0x50);
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun if (is_cx2583x(state))
261*4882a593Smuzhiyun break;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun /* src1_ctl */
264*4882a593Smuzhiyun /* 0x1.8000 = 48000/32000 */
265*4882a593Smuzhiyun cx25840_write4(client, 0x8f8, 0x08018000);
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun /* src3/4/6_ctl */
268*4882a593Smuzhiyun /* 0x1.5555 = 2 * (32000/48000) */
269*4882a593Smuzhiyun cx25840_write4(client, 0x900, 0x08015555);
270*4882a593Smuzhiyun cx25840_write4(client, 0x904, 0x08015555);
271*4882a593Smuzhiyun cx25840_write4(client, 0x90c, 0x08015555);
272*4882a593Smuzhiyun break;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun state->audclk_freq = freq;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun return 0;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
cx25836_set_audclk_freq(struct i2c_client * client,u32 freq)281*4882a593Smuzhiyun static inline int cx25836_set_audclk_freq(struct i2c_client *client, u32 freq)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun return cx25840_set_audclk_freq(client, freq);
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
cx23885_set_audclk_freq(struct i2c_client * client,u32 freq)286*4882a593Smuzhiyun static int cx23885_set_audclk_freq(struct i2c_client *client, u32 freq)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun struct cx25840_state *state = to_state(i2c_get_clientdata(client));
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun if (state->aud_input != CX25840_AUDIO_SERIAL) {
291*4882a593Smuzhiyun switch (freq) {
292*4882a593Smuzhiyun case 32000:
293*4882a593Smuzhiyun case 44100:
294*4882a593Smuzhiyun case 48000:
295*4882a593Smuzhiyun /* We don't have register values
296*4882a593Smuzhiyun * so avoid destroying registers. */
297*4882a593Smuzhiyun /* FIXME return -EINVAL; */
298*4882a593Smuzhiyun break;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun } else {
301*4882a593Smuzhiyun switch (freq) {
302*4882a593Smuzhiyun case 32000:
303*4882a593Smuzhiyun case 44100:
304*4882a593Smuzhiyun /* We don't have register values
305*4882a593Smuzhiyun * so avoid destroying registers. */
306*4882a593Smuzhiyun /* FIXME return -EINVAL; */
307*4882a593Smuzhiyun break;
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun case 48000:
310*4882a593Smuzhiyun /* src1_ctl */
311*4882a593Smuzhiyun /* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
312*4882a593Smuzhiyun cx25840_write4(client, 0x8f8, 0x0801867c);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun /* src3/4/6_ctl */
315*4882a593Smuzhiyun /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
316*4882a593Smuzhiyun cx25840_write4(client, 0x900, 0x08014faa);
317*4882a593Smuzhiyun cx25840_write4(client, 0x904, 0x08014faa);
318*4882a593Smuzhiyun cx25840_write4(client, 0x90c, 0x08014faa);
319*4882a593Smuzhiyun break;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun state->audclk_freq = freq;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun return 0;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun
cx231xx_set_audclk_freq(struct i2c_client * client,u32 freq)328*4882a593Smuzhiyun static int cx231xx_set_audclk_freq(struct i2c_client *client, u32 freq)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun struct cx25840_state *state = to_state(i2c_get_clientdata(client));
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun if (state->aud_input != CX25840_AUDIO_SERIAL) {
333*4882a593Smuzhiyun switch (freq) {
334*4882a593Smuzhiyun case 32000:
335*4882a593Smuzhiyun /* src3/4/6_ctl */
336*4882a593Smuzhiyun /* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */
337*4882a593Smuzhiyun cx25840_write4(client, 0x900, 0x0801f77f);
338*4882a593Smuzhiyun cx25840_write4(client, 0x904, 0x0801f77f);
339*4882a593Smuzhiyun cx25840_write4(client, 0x90c, 0x0801f77f);
340*4882a593Smuzhiyun break;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun case 44100:
343*4882a593Smuzhiyun /* src3/4/6_ctl */
344*4882a593Smuzhiyun /* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */
345*4882a593Smuzhiyun cx25840_write4(client, 0x900, 0x08016d59);
346*4882a593Smuzhiyun cx25840_write4(client, 0x904, 0x08016d59);
347*4882a593Smuzhiyun cx25840_write4(client, 0x90c, 0x08016d59);
348*4882a593Smuzhiyun break;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun case 48000:
351*4882a593Smuzhiyun /* src3/4/6_ctl */
352*4882a593Smuzhiyun /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
353*4882a593Smuzhiyun cx25840_write4(client, 0x900, 0x08014faa);
354*4882a593Smuzhiyun cx25840_write4(client, 0x904, 0x08014faa);
355*4882a593Smuzhiyun cx25840_write4(client, 0x90c, 0x08014faa);
356*4882a593Smuzhiyun break;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun } else {
359*4882a593Smuzhiyun switch (freq) {
360*4882a593Smuzhiyun /* FIXME These cases make different assumptions about audclk */
361*4882a593Smuzhiyun case 32000:
362*4882a593Smuzhiyun /* src1_ctl */
363*4882a593Smuzhiyun /* 0x1.0000 = 32000/32000 */
364*4882a593Smuzhiyun cx25840_write4(client, 0x8f8, 0x08010000);
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun /* src3/4/6_ctl */
367*4882a593Smuzhiyun /* 0x2.0000 = 2 * (32000/32000) */
368*4882a593Smuzhiyun cx25840_write4(client, 0x900, 0x08020000);
369*4882a593Smuzhiyun cx25840_write4(client, 0x904, 0x08020000);
370*4882a593Smuzhiyun cx25840_write4(client, 0x90c, 0x08020000);
371*4882a593Smuzhiyun break;
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun case 44100:
374*4882a593Smuzhiyun /* src1_ctl */
375*4882a593Smuzhiyun /* 0x1.60cd = 44100/32000 */
376*4882a593Smuzhiyun cx25840_write4(client, 0x8f8, 0x080160cd);
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun /* src3/4/6_ctl */
379*4882a593Smuzhiyun /* 0x1.7385 = 2 * (32000/44100) */
380*4882a593Smuzhiyun cx25840_write4(client, 0x900, 0x08017385);
381*4882a593Smuzhiyun cx25840_write4(client, 0x904, 0x08017385);
382*4882a593Smuzhiyun cx25840_write4(client, 0x90c, 0x08017385);
383*4882a593Smuzhiyun break;
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun case 48000:
386*4882a593Smuzhiyun /* src1_ctl */
387*4882a593Smuzhiyun /* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
388*4882a593Smuzhiyun cx25840_write4(client, 0x8f8, 0x0801867c);
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun /* src3/4/6_ctl */
391*4882a593Smuzhiyun /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
392*4882a593Smuzhiyun cx25840_write4(client, 0x900, 0x08014faa);
393*4882a593Smuzhiyun cx25840_write4(client, 0x904, 0x08014faa);
394*4882a593Smuzhiyun cx25840_write4(client, 0x90c, 0x08014faa);
395*4882a593Smuzhiyun break;
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun state->audclk_freq = freq;
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun return 0;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
set_audclk_freq(struct i2c_client * client,u32 freq)404*4882a593Smuzhiyun static int set_audclk_freq(struct i2c_client *client, u32 freq)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun struct cx25840_state *state = to_state(i2c_get_clientdata(client));
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun if (freq != 32000 && freq != 44100 && freq != 48000)
409*4882a593Smuzhiyun return -EINVAL;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun if (is_cx231xx(state))
412*4882a593Smuzhiyun return cx231xx_set_audclk_freq(client, freq);
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun if (is_cx2388x(state))
415*4882a593Smuzhiyun return cx23885_set_audclk_freq(client, freq);
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun if (is_cx2583x(state))
418*4882a593Smuzhiyun return cx25836_set_audclk_freq(client, freq);
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun return cx25840_set_audclk_freq(client, freq);
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun
cx25840_audio_set_path(struct i2c_client * client)423*4882a593Smuzhiyun void cx25840_audio_set_path(struct i2c_client *client)
424*4882a593Smuzhiyun {
425*4882a593Smuzhiyun struct cx25840_state *state = to_state(i2c_get_clientdata(client));
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun if (!is_cx2583x(state)) {
428*4882a593Smuzhiyun /* assert soft reset */
429*4882a593Smuzhiyun cx25840_and_or(client, 0x810, ~0x1, 0x01);
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun /* stop microcontroller */
432*4882a593Smuzhiyun cx25840_and_or(client, 0x803, ~0x10, 0);
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun /* Mute everything to prevent the PFFT! */
435*4882a593Smuzhiyun cx25840_write(client, 0x8d3, 0x1f);
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun if (state->aud_input == CX25840_AUDIO_SERIAL) {
438*4882a593Smuzhiyun /* Set Path1 to Serial Audio Input */
439*4882a593Smuzhiyun cx25840_write4(client, 0x8d0, 0x01011012);
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun /* The microcontroller should not be started for the
442*4882a593Smuzhiyun * non-tuner inputs: autodetection is specific for
443*4882a593Smuzhiyun * TV audio. */
444*4882a593Smuzhiyun } else {
445*4882a593Smuzhiyun /* Set Path1 to Analog Demod Main Channel */
446*4882a593Smuzhiyun cx25840_write4(client, 0x8d0, 0x1f063870);
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun set_audclk_freq(client, state->audclk_freq);
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun if (!is_cx2583x(state)) {
453*4882a593Smuzhiyun if (state->aud_input != CX25840_AUDIO_SERIAL) {
454*4882a593Smuzhiyun /* When the microcontroller detects the
455*4882a593Smuzhiyun * audio format, it will unmute the lines */
456*4882a593Smuzhiyun cx25840_and_or(client, 0x803, ~0x10, 0x10);
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun /* deassert soft reset */
460*4882a593Smuzhiyun cx25840_and_or(client, 0x810, ~0x1, 0x00);
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun /* Ensure the controller is running when we exit */
463*4882a593Smuzhiyun if (is_cx2388x(state) || is_cx231xx(state))
464*4882a593Smuzhiyun cx25840_and_or(client, 0x803, ~0x10, 0x10);
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun
set_volume(struct i2c_client * client,int volume)468*4882a593Smuzhiyun static void set_volume(struct i2c_client *client, int volume)
469*4882a593Smuzhiyun {
470*4882a593Smuzhiyun int vol;
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun /* Convert the volume to msp3400 values (0-127) */
473*4882a593Smuzhiyun vol = volume >> 9;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun /* now scale it up to cx25840 values
476*4882a593Smuzhiyun * -114dB to -96dB maps to 0
477*4882a593Smuzhiyun * this should be 19, but in my testing that was 4dB too loud */
478*4882a593Smuzhiyun if (vol <= 23) {
479*4882a593Smuzhiyun vol = 0;
480*4882a593Smuzhiyun } else {
481*4882a593Smuzhiyun vol -= 23;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun /* PATH1_VOLUME */
485*4882a593Smuzhiyun cx25840_write(client, 0x8d4, 228 - (vol * 2));
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun
set_balance(struct i2c_client * client,int balance)488*4882a593Smuzhiyun static void set_balance(struct i2c_client *client, int balance)
489*4882a593Smuzhiyun {
490*4882a593Smuzhiyun int bal = balance >> 8;
491*4882a593Smuzhiyun if (bal > 0x80) {
492*4882a593Smuzhiyun /* PATH1_BAL_LEFT */
493*4882a593Smuzhiyun cx25840_and_or(client, 0x8d5, 0x7f, 0x80);
494*4882a593Smuzhiyun /* PATH1_BAL_LEVEL */
495*4882a593Smuzhiyun cx25840_and_or(client, 0x8d5, ~0x7f, bal & 0x7f);
496*4882a593Smuzhiyun } else {
497*4882a593Smuzhiyun /* PATH1_BAL_LEFT */
498*4882a593Smuzhiyun cx25840_and_or(client, 0x8d5, 0x7f, 0x00);
499*4882a593Smuzhiyun /* PATH1_BAL_LEVEL */
500*4882a593Smuzhiyun cx25840_and_or(client, 0x8d5, ~0x7f, 0x80 - bal);
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun
cx25840_s_clock_freq(struct v4l2_subdev * sd,u32 freq)504*4882a593Smuzhiyun int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
505*4882a593Smuzhiyun {
506*4882a593Smuzhiyun struct i2c_client *client = v4l2_get_subdevdata(sd);
507*4882a593Smuzhiyun struct cx25840_state *state = to_state(sd);
508*4882a593Smuzhiyun int retval;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun if (!is_cx2583x(state))
511*4882a593Smuzhiyun cx25840_and_or(client, 0x810, ~0x1, 1);
512*4882a593Smuzhiyun if (state->aud_input != CX25840_AUDIO_SERIAL) {
513*4882a593Smuzhiyun cx25840_and_or(client, 0x803, ~0x10, 0);
514*4882a593Smuzhiyun cx25840_write(client, 0x8d3, 0x1f);
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun retval = set_audclk_freq(client, freq);
517*4882a593Smuzhiyun if (state->aud_input != CX25840_AUDIO_SERIAL)
518*4882a593Smuzhiyun cx25840_and_or(client, 0x803, ~0x10, 0x10);
519*4882a593Smuzhiyun if (!is_cx2583x(state))
520*4882a593Smuzhiyun cx25840_and_or(client, 0x810, ~0x1, 0);
521*4882a593Smuzhiyun return retval;
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun
cx25840_audio_s_ctrl(struct v4l2_ctrl * ctrl)524*4882a593Smuzhiyun static int cx25840_audio_s_ctrl(struct v4l2_ctrl *ctrl)
525*4882a593Smuzhiyun {
526*4882a593Smuzhiyun struct v4l2_subdev *sd = to_sd(ctrl);
527*4882a593Smuzhiyun struct cx25840_state *state = to_state(sd);
528*4882a593Smuzhiyun struct i2c_client *client = v4l2_get_subdevdata(sd);
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun switch (ctrl->id) {
531*4882a593Smuzhiyun case V4L2_CID_AUDIO_VOLUME:
532*4882a593Smuzhiyun if (state->mute->val)
533*4882a593Smuzhiyun set_volume(client, 0);
534*4882a593Smuzhiyun else
535*4882a593Smuzhiyun set_volume(client, state->volume->val);
536*4882a593Smuzhiyun break;
537*4882a593Smuzhiyun case V4L2_CID_AUDIO_BASS:
538*4882a593Smuzhiyun /* PATH1_EQ_BASS_VOL */
539*4882a593Smuzhiyun cx25840_and_or(client, 0x8d9, ~0x3f,
540*4882a593Smuzhiyun 48 - (ctrl->val * 48 / 0xffff));
541*4882a593Smuzhiyun break;
542*4882a593Smuzhiyun case V4L2_CID_AUDIO_TREBLE:
543*4882a593Smuzhiyun /* PATH1_EQ_TREBLE_VOL */
544*4882a593Smuzhiyun cx25840_and_or(client, 0x8db, ~0x3f,
545*4882a593Smuzhiyun 48 - (ctrl->val * 48 / 0xffff));
546*4882a593Smuzhiyun break;
547*4882a593Smuzhiyun case V4L2_CID_AUDIO_BALANCE:
548*4882a593Smuzhiyun set_balance(client, ctrl->val);
549*4882a593Smuzhiyun break;
550*4882a593Smuzhiyun default:
551*4882a593Smuzhiyun return -EINVAL;
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun return 0;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun const struct v4l2_ctrl_ops cx25840_audio_ctrl_ops = {
557*4882a593Smuzhiyun .s_ctrl = cx25840_audio_s_ctrl,
558*4882a593Smuzhiyun };
559