x86: more apic debugging
[sfrench/cifs-2.6.git] / drivers / media / video / cx18 / cx18-av-audio.c
1 /*
2  *  cx18 ADEC audio functions
3  *
4  *  Derived from cx25840-audio.c
5  *
6  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
7  *
8  *  This program is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU General Public License
10  *  as published by the Free Software Foundation; either version 2
11  *  of the License, or (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  *  02110-1301, USA.
22  */
23
24 #include "cx18-driver.h"
25
26 static int set_audclk_freq(struct cx18 *cx, u32 freq)
27 {
28         struct cx18_av_state *state = &cx->av_state;
29
30         if (freq != 32000 && freq != 44100 && freq != 48000)
31                 return -EINVAL;
32
33         /* common for all inputs and rates */
34         /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
35         cx18_av_write(cx, 0x127, 0x50);
36
37         if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
38                 switch (freq) {
39                 case 32000:
40                         /* VID_PLL and AUX_PLL */
41                         cx18_av_write4(cx, 0x108, 0x1006040f);
42
43                         /* AUX_PLL_FRAC */
44                         cx18_av_write4(cx, 0x110, 0x01bb39ee);
45
46                         /* src3/4/6_ctl = 0x0801f77f */
47                         cx18_av_write4(cx, 0x900, 0x0801f77f);
48                         cx18_av_write4(cx, 0x904, 0x0801f77f);
49                         cx18_av_write4(cx, 0x90c, 0x0801f77f);
50                         break;
51
52                 case 44100:
53                         /* VID_PLL and AUX_PLL */
54                         cx18_av_write4(cx, 0x108, 0x1009040f);
55
56                         /* AUX_PLL_FRAC */
57                         cx18_av_write4(cx, 0x110, 0x00ec6bd6);
58
59                         /* src3/4/6_ctl = 0x08016d59 */
60                         cx18_av_write4(cx, 0x900, 0x08016d59);
61                         cx18_av_write4(cx, 0x904, 0x08016d59);
62                         cx18_av_write4(cx, 0x90c, 0x08016d59);
63                         break;
64
65                 case 48000:
66                         /* VID_PLL and AUX_PLL */
67                         cx18_av_write4(cx, 0x108, 0x100a040f);
68
69                         /* AUX_PLL_FRAC */
70                         cx18_av_write4(cx, 0x110, 0x0098d6e5);
71
72                         /* src3/4/6_ctl = 0x08014faa */
73                         cx18_av_write4(cx, 0x900, 0x08014faa);
74                         cx18_av_write4(cx, 0x904, 0x08014faa);
75                         cx18_av_write4(cx, 0x90c, 0x08014faa);
76                         break;
77                 }
78         } else {
79                 switch (freq) {
80                 case 32000:
81                         /* VID_PLL and AUX_PLL */
82                         cx18_av_write4(cx, 0x108, 0x1e08040f);
83
84                         /* AUX_PLL_FRAC */
85                         cx18_av_write4(cx, 0x110, 0x012a0869);
86
87                         /* src1_ctl = 0x08010000 */
88                         cx18_av_write4(cx, 0x8f8, 0x08010000);
89
90                         /* src3/4/6_ctl = 0x08020000 */
91                         cx18_av_write4(cx, 0x900, 0x08020000);
92                         cx18_av_write4(cx, 0x904, 0x08020000);
93                         cx18_av_write4(cx, 0x90c, 0x08020000);
94
95                         /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
96                         cx18_av_write(cx, 0x127, 0x54);
97                         break;
98
99                 case 44100:
100                         /* VID_PLL and AUX_PLL */
101                         cx18_av_write4(cx, 0x108, 0x1809040f);
102
103                         /* AUX_PLL_FRAC */
104                         cx18_av_write4(cx, 0x110, 0x00ec6bd6);
105
106                         /* src1_ctl = 0x08010000 */
107                         cx18_av_write4(cx, 0x8f8, 0x080160cd);
108
109                         /* src3/4/6_ctl = 0x08020000 */
110                         cx18_av_write4(cx, 0x900, 0x08017385);
111                         cx18_av_write4(cx, 0x904, 0x08017385);
112                         cx18_av_write4(cx, 0x90c, 0x08017385);
113                         break;
114
115                 case 48000:
116                         /* VID_PLL and AUX_PLL */
117                         cx18_av_write4(cx, 0x108, 0x180a040f);
118
119                         /* AUX_PLL_FRAC */
120                         cx18_av_write4(cx, 0x110, 0x0098d6e5);
121
122                         /* src1_ctl = 0x08010000 */
123                         cx18_av_write4(cx, 0x8f8, 0x08018000);
124
125                         /* src3/4/6_ctl = 0x08020000 */
126                         cx18_av_write4(cx, 0x900, 0x08015555);
127                         cx18_av_write4(cx, 0x904, 0x08015555);
128                         cx18_av_write4(cx, 0x90c, 0x08015555);
129                         break;
130                 }
131         }
132
133         state->audclk_freq = freq;
134
135         return 0;
136 }
137
138 void cx18_av_audio_set_path(struct cx18 *cx)
139 {
140         struct cx18_av_state *state = &cx->av_state;
141
142         /* stop microcontroller */
143         cx18_av_and_or(cx, 0x803, ~0x10, 0);
144
145         /* assert soft reset */
146         cx18_av_and_or(cx, 0x810, ~0x1, 0x01);
147
148         /* Mute everything to prevent the PFFT! */
149         cx18_av_write(cx, 0x8d3, 0x1f);
150
151         if (state->aud_input == CX18_AV_AUDIO_SERIAL) {
152                 /* Set Path1 to Serial Audio Input */
153                 cx18_av_write4(cx, 0x8d0, 0x01011012);
154
155                 /* The microcontroller should not be started for the
156                  * non-tuner inputs: autodetection is specific for
157                  * TV audio. */
158         } else {
159                 /* Set Path1 to Analog Demod Main Channel */
160                 cx18_av_write4(cx, 0x8d0, 0x1f063870);
161         }
162
163         set_audclk_freq(cx, state->audclk_freq);
164
165         /* deassert soft reset */
166         cx18_av_and_or(cx, 0x810, ~0x1, 0x00);
167
168         if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
169                 /* When the microcontroller detects the
170                  * audio format, it will unmute the lines */
171                 cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
172         }
173 }
174
175 static int get_volume(struct cx18 *cx)
176 {
177         /* Volume runs +18dB to -96dB in 1/2dB steps
178          * change to fit the msp3400 -114dB to +12dB range */
179
180         /* check PATH1_VOLUME */
181         int vol = 228 - cx18_av_read(cx, 0x8d4);
182         vol = (vol / 2) + 23;
183         return vol << 9;
184 }
185
186 static void set_volume(struct cx18 *cx, int volume)
187 {
188         /* First convert the volume to msp3400 values (0-127) */
189         int vol = volume >> 9;
190         /* now scale it up to cx18_av values
191          * -114dB to -96dB maps to 0
192          * this should be 19, but in my testing that was 4dB too loud */
193         if (vol <= 23)
194                 vol = 0;
195         else
196                 vol -= 23;
197
198         /* PATH1_VOLUME */
199         cx18_av_write(cx, 0x8d4, 228 - (vol * 2));
200 }
201
202 static int get_bass(struct cx18 *cx)
203 {
204         /* bass is 49 steps +12dB to -12dB */
205
206         /* check PATH1_EQ_BASS_VOL */
207         int bass = cx18_av_read(cx, 0x8d9) & 0x3f;
208         bass = (((48 - bass) * 0xffff) + 47) / 48;
209         return bass;
210 }
211
212 static void set_bass(struct cx18 *cx, int bass)
213 {
214         /* PATH1_EQ_BASS_VOL */
215         cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
216 }
217
218 static int get_treble(struct cx18 *cx)
219 {
220         /* treble is 49 steps +12dB to -12dB */
221
222         /* check PATH1_EQ_TREBLE_VOL */
223         int treble = cx18_av_read(cx, 0x8db) & 0x3f;
224         treble = (((48 - treble) * 0xffff) + 47) / 48;
225         return treble;
226 }
227
228 static void set_treble(struct cx18 *cx, int treble)
229 {
230         /* PATH1_EQ_TREBLE_VOL */
231         cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
232 }
233
234 static int get_balance(struct cx18 *cx)
235 {
236         /* balance is 7 bit, 0 to -96dB */
237
238         /* check PATH1_BAL_LEVEL */
239         int balance = cx18_av_read(cx, 0x8d5) & 0x7f;
240         /* check PATH1_BAL_LEFT */
241         if ((cx18_av_read(cx, 0x8d5) & 0x80) == 0)
242                 balance = 0x80 - balance;
243         else
244                 balance = 0x80 + balance;
245         return balance << 8;
246 }
247
248 static void set_balance(struct cx18 *cx, int balance)
249 {
250         int bal = balance >> 8;
251         if (bal > 0x80) {
252                 /* PATH1_BAL_LEFT */
253                 cx18_av_and_or(cx, 0x8d5, 0x7f, 0x80);
254                 /* PATH1_BAL_LEVEL */
255                 cx18_av_and_or(cx, 0x8d5, ~0x7f, bal & 0x7f);
256         } else {
257                 /* PATH1_BAL_LEFT */
258                 cx18_av_and_or(cx, 0x8d5, 0x7f, 0x00);
259                 /* PATH1_BAL_LEVEL */
260                 cx18_av_and_or(cx, 0x8d5, ~0x7f, 0x80 - bal);
261         }
262 }
263
264 static int get_mute(struct cx18 *cx)
265 {
266         /* check SRC1_MUTE_EN */
267         return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0;
268 }
269
270 static void set_mute(struct cx18 *cx, int mute)
271 {
272         struct cx18_av_state *state = &cx->av_state;
273
274         if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
275                 /* Must turn off microcontroller in order to mute sound.
276                  * Not sure if this is the best method, but it does work.
277                  * If the microcontroller is running, then it will undo any
278                  * changes to the mute register. */
279                 if (mute) {
280                         /* disable microcontroller */
281                         cx18_av_and_or(cx, 0x803, ~0x10, 0x00);
282                         cx18_av_write(cx, 0x8d3, 0x1f);
283                 } else {
284                         /* enable microcontroller */
285                         cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
286                 }
287         } else {
288                 /* SRC1_MUTE_EN */
289                 cx18_av_and_or(cx, 0x8d3, ~0x2, mute ? 0x02 : 0x00);
290         }
291 }
292
293 int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg)
294 {
295         struct cx18_av_state *state = &cx->av_state;
296         struct v4l2_control *ctrl = arg;
297         int retval;
298
299         switch (cmd) {
300         case VIDIOC_INT_AUDIO_CLOCK_FREQ:
301                 if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
302                         cx18_av_and_or(cx, 0x803, ~0x10, 0);
303                         cx18_av_write(cx, 0x8d3, 0x1f);
304                 }
305                 cx18_av_and_or(cx, 0x810, ~0x1, 1);
306                 retval = set_audclk_freq(cx, *(u32 *)arg);
307                 cx18_av_and_or(cx, 0x810, ~0x1, 0);
308                 if (state->aud_input != CX18_AV_AUDIO_SERIAL)
309                         cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
310                 return retval;
311
312         case VIDIOC_G_CTRL:
313                 switch (ctrl->id) {
314                 case V4L2_CID_AUDIO_VOLUME:
315                         ctrl->value = get_volume(cx);
316                         break;
317                 case V4L2_CID_AUDIO_BASS:
318                         ctrl->value = get_bass(cx);
319                         break;
320                 case V4L2_CID_AUDIO_TREBLE:
321                         ctrl->value = get_treble(cx);
322                         break;
323                 case V4L2_CID_AUDIO_BALANCE:
324                         ctrl->value = get_balance(cx);
325                         break;
326                 case V4L2_CID_AUDIO_MUTE:
327                         ctrl->value = get_mute(cx);
328                         break;
329                 default:
330                         return -EINVAL;
331                 }
332                 break;
333
334         case VIDIOC_S_CTRL:
335                 switch (ctrl->id) {
336                 case V4L2_CID_AUDIO_VOLUME:
337                         set_volume(cx, ctrl->value);
338                         break;
339                 case V4L2_CID_AUDIO_BASS:
340                         set_bass(cx, ctrl->value);
341                         break;
342                 case V4L2_CID_AUDIO_TREBLE:
343                         set_treble(cx, ctrl->value);
344                         break;
345                 case V4L2_CID_AUDIO_BALANCE:
346                         set_balance(cx, ctrl->value);
347                         break;
348                 case V4L2_CID_AUDIO_MUTE:
349                         set_mute(cx, ctrl->value);
350                         break;
351                 default:
352                         return -EINVAL;
353                 }
354                 break;
355
356         default:
357                 return -EINVAL;
358         }
359
360         return 0;
361 }