Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /* cx25840 audio functions
  2  *
  3  * This program is free software; you can redistribute it and/or
  4  * modify it under the terms of the GNU General Public License
  5  * as published by the Free Software Foundation; either version 2
  6  * of the License, or (at your option) any later version.
  7  *
  8  * This program is distributed in the hope that it will be useful,
  9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 11  * GNU General Public License for more details.
 12  *
 13  * You should have received a copy of the GNU General Public License
 14  * along with this program; if not, write to the Free Software
 15  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 16  */
 17 
 18 
 19 #include <linux/videodev2.h>
 20 #include <linux/i2c.h>
 21 #include <media/v4l2-common.h>
 22 #include <media/cx25840.h>
 23 
 24 #include "cx25840-core.h"
 25 
 26 static int set_audclk_freq(struct i2c_client *client, u32 freq)
 27 {
 28         struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 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         if (!state->is_cx23885 && !state->is_cx231xx)
 36                 cx25840_write(client, 0x127, 0x50);
 37 
 38         if (state->aud_input != CX25840_AUDIO_SERIAL) {
 39                 switch (freq) {
 40                 case 32000:
 41                         if (state->is_cx23885) {
 42                                 /* We don't have register values
 43                                  * so avoid destroying registers. */
 44                                 break;
 45                         }
 46 
 47                         if (!state->is_cx231xx) {
 48                                 /* VID_PLL and AUX_PLL */
 49                                 cx25840_write4(client, 0x108, 0x1006040f);
 50 
 51                                 /* AUX_PLL_FRAC */
 52                                 cx25840_write4(client, 0x110, 0x01bb39ee);
 53                         }
 54 
 55                         if (state->is_cx25836)
 56                                 break;
 57 
 58                         /* src3/4/6_ctl = 0x0801f77f */
 59                         cx25840_write4(client, 0x900, 0x0801f77f);
 60                         cx25840_write4(client, 0x904, 0x0801f77f);
 61                         cx25840_write4(client, 0x90c, 0x0801f77f);
 62                         break;
 63 
 64                 case 44100:
 65                         if (state->is_cx23885) {
 66                                 /* We don't have register values
 67                                  * so avoid destroying registers. */
 68                                 break;
 69                         }
 70 
 71                         if (!state->is_cx231xx) {
 72                                 /* VID_PLL and AUX_PLL */
 73                                 cx25840_write4(client, 0x108, 0x1009040f);
 74 
 75                                 /* AUX_PLL_FRAC */
 76                                 cx25840_write4(client, 0x110, 0x00ec6bd6);
 77                         }
 78 
 79                         if (state->is_cx25836)
 80                                 break;
 81 
 82                         /* src3/4/6_ctl = 0x08016d59 */
 83                         cx25840_write4(client, 0x900, 0x08016d59);
 84                         cx25840_write4(client, 0x904, 0x08016d59);
 85                         cx25840_write4(client, 0x90c, 0x08016d59);
 86                         break;
 87 
 88                 case 48000:
 89                         if (state->is_cx23885) {
 90                                 /* We don't have register values
 91                                  * so avoid destroying registers. */
 92                                 break;
 93                         }
 94 
 95                         if (!state->is_cx231xx) {
 96                                 /* VID_PLL and AUX_PLL */
 97                                 cx25840_write4(client, 0x108, 0x100a040f);
 98 
 99                                 /* AUX_PLL_FRAC */
100                                 cx25840_write4(client, 0x110, 0x0098d6e5);
101                         }
102 
103                         if (state->is_cx25836)
104                                 break;
105 
106                         /* src3/4/6_ctl = 0x08014faa */
107                         cx25840_write4(client, 0x900, 0x08014faa);
108                         cx25840_write4(client, 0x904, 0x08014faa);
109                         cx25840_write4(client, 0x90c, 0x08014faa);
110                         break;
111                 }
112         } else {
113                 switch (freq) {
114                 case 32000:
115                         if (state->is_cx23885) {
116                                 /* We don't have register values
117                                  * so avoid destroying registers. */
118                                 break;
119                         }
120 
121                         if (!state->is_cx231xx) {
122                                 /* VID_PLL and AUX_PLL */
123                                 cx25840_write4(client, 0x108, 0x1e08040f);
124 
125                                 /* AUX_PLL_FRAC */
126                                 cx25840_write4(client, 0x110, 0x012a0869);
127                         }
128 
129                         if (state->is_cx25836)
130                                 break;
131 
132                         /* src1_ctl = 0x08010000 */
133                         cx25840_write4(client, 0x8f8, 0x08010000);
134 
135                         /* src3/4/6_ctl = 0x08020000 */
136                         cx25840_write4(client, 0x900, 0x08020000);
137                         cx25840_write4(client, 0x904, 0x08020000);
138                         cx25840_write4(client, 0x90c, 0x08020000);
139 
140                         /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
141                         cx25840_write(client, 0x127, 0x54);
142                         break;
143 
144                 case 44100:
145                         if (state->is_cx23885) {
146                                 /* We don't have register values
147                                  * so avoid destroying registers. */
148                                 break;
149                         }
150 
151 
152                         if (!state->is_cx231xx) {
153                                 /* VID_PLL and AUX_PLL */
154                                 cx25840_write4(client, 0x108, 0x1809040f);
155 
156                                 /* AUX_PLL_FRAC */
157                                 cx25840_write4(client, 0x110, 0x00ec6bd6);
158                         }
159 
160                         if (state->is_cx25836)
161                                 break;
162 
163                         /* src1_ctl = 0x08010000 */
164                         cx25840_write4(client, 0x8f8, 0x080160cd);
165 
166                         /* src3/4/6_ctl = 0x08020000 */
167                         cx25840_write4(client, 0x900, 0x08017385);
168                         cx25840_write4(client, 0x904, 0x08017385);
169                         cx25840_write4(client, 0x90c, 0x08017385);
170                         break;
171 
172                 case 48000:
173                         if (!state->is_cx23885 && !state->is_cx231xx) {
174                                 /* VID_PLL and AUX_PLL */
175                                 cx25840_write4(client, 0x108, 0x180a040f);
176 
177                                 /* AUX_PLL_FRAC */
178                                 cx25840_write4(client, 0x110, 0x0098d6e5);
179                         }
180 
181                         if (state->is_cx25836)
182                                 break;
183 
184                         if (!state->is_cx23885 && !state->is_cx231xx) {
185                                 /* src1_ctl */
186                                 cx25840_write4(client, 0x8f8, 0x08018000);
187 
188                                 /* src3/4/6_ctl */
189                                 cx25840_write4(client, 0x900, 0x08015555);
190                                 cx25840_write4(client, 0x904, 0x08015555);
191                                 cx25840_write4(client, 0x90c, 0x08015555);
192                         } else {
193 
194                                 cx25840_write4(client, 0x8f8, 0x0801867c);
195 
196                                 cx25840_write4(client, 0x900, 0x08014faa);
197                                 cx25840_write4(client, 0x904, 0x08014faa);
198                                 cx25840_write4(client, 0x90c, 0x08014faa);
199                         }
200                         break;
201                 }
202         }
203 
204         state->audclk_freq = freq;
205 
206         return 0;
207 }
208 
209 void cx25840_audio_set_path(struct i2c_client *client)
210 {
211         struct cx25840_state *state = to_state(i2c_get_clientdata(client));
212 
213         /* assert soft reset */
214         cx25840_and_or(client, 0x810, ~0x1, 0x01);
215 
216         /* stop microcontroller */
217         cx25840_and_or(client, 0x803, ~0x10, 0);
218 
219         /* Mute everything to prevent the PFFT! */
220         cx25840_write(client, 0x8d3, 0x1f);
221 
222         if (state->aud_input == CX25840_AUDIO_SERIAL) {
223                 /* Set Path1 to Serial Audio Input */
224                 cx25840_write4(client, 0x8d0, 0x01011012);
225 
226                 /* The microcontroller should not be started for the
227                  * non-tuner inputs: autodetection is specific for
228                  * TV audio. */
229         } else {
230                 /* Set Path1 to Analog Demod Main Channel */
231                 cx25840_write4(client, 0x8d0, 0x1f063870);
232         }
233 
234         set_audclk_freq(client, state->audclk_freq);
235 
236         if (state->aud_input != CX25840_AUDIO_SERIAL) {
237                 /* When the microcontroller detects the
238                  * audio format, it will unmute the lines */
239                 cx25840_and_or(client, 0x803, ~0x10, 0x10);
240         }
241 
242         /* deassert soft reset */
243         cx25840_and_or(client, 0x810, ~0x1, 0x00);
244 
245         /* Ensure the controller is running when we exit */
246         if (state->is_cx23885 || state->is_cx231xx)
247                 cx25840_and_or(client, 0x803, ~0x10, 0x10);
248 }
249 
250 static int get_volume(struct i2c_client *client)
251 {
252         struct cx25840_state *state = to_state(i2c_get_clientdata(client));
253         int vol;
254 
255         if (state->unmute_volume >= 0)
256                 return state->unmute_volume;
257 
258         /* Volume runs +18dB to -96dB in 1/2dB steps
259          * change to fit the msp3400 -114dB to +12dB range */
260 
261         /* check PATH1_VOLUME */
262         vol = 228 - cx25840_read(client, 0x8d4);
263         vol = (vol / 2) + 23;
264         return vol << 9;
265 }
266 
267 static void set_volume(struct i2c_client *client, int volume)
268 {
269         struct cx25840_state *state = to_state(i2c_get_clientdata(client));
270         int vol;
271 
272         if (state->unmute_volume >= 0) {
273                 state->unmute_volume = volume;
274                 return;
275         }
276 
277         /* Convert the volume to msp3400 values (0-127) */
278         vol = volume >> 9;
279 
280         /* now scale it up to cx25840 values
281          * -114dB to -96dB maps to 0
282          * this should be 19, but in my testing that was 4dB too loud */
283         if (vol <= 23) {
284                 vol = 0;
285         } else {
286                 vol -= 23;
287         }
288 
289         /* PATH1_VOLUME */
290         cx25840_write(client, 0x8d4, 228 - (vol * 2));
291 }
292 
293 static int get_bass(struct i2c_client *client)
294 {
295         /* bass is 49 steps +12dB to -12dB */
296 
297         /* check PATH1_EQ_BASS_VOL */
298         int bass = cx25840_read(client, 0x8d9) & 0x3f;
299         bass = (((48 - bass) * 0xffff) + 47) / 48;
300         return bass;
301 }
302 
303 static void set_bass(struct i2c_client *client, int bass)
304 {
305         /* PATH1_EQ_BASS_VOL */
306         cx25840_and_or(client, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
307 }
308 
309 static int get_treble(struct i2c_client *client)
310 {
311         /* treble is 49 steps +12dB to -12dB */
312 
313         /* check PATH1_EQ_TREBLE_VOL */
314         int treble = cx25840_read(client, 0x8db) & 0x3f;
315         treble = (((48 - treble) * 0xffff) + 47) / 48;
316         return treble;
317 }
318 
319 static void set_treble(struct i2c_client *client, int treble)
320 {
321         /* PATH1_EQ_TREBLE_VOL */
322         cx25840_and_or(client, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
323 }
324 
325 static int get_balance(struct i2c_client *client)
326 {
327         /* balance is 7 bit, 0 to -96dB */
328 
329         /* check PATH1_BAL_LEVEL */
330         int balance = cx25840_read(client, 0x8d5) & 0x7f;
331         /* check PATH1_BAL_LEFT */
332         if ((cx25840_read(client, 0x8d5) & 0x80) == 0)
333                 balance = 0x80 - balance;
334         else
335                 balance = 0x80 + balance;
336         return balance << 8;
337 }
338 
339 static void set_balance(struct i2c_client *client, int balance)
340 {
341         int bal = balance >> 8;
342         if (bal > 0x80) {
343                 /* PATH1_BAL_LEFT */
344                 cx25840_and_or(client, 0x8d5, 0x7f, 0x80);
345                 /* PATH1_BAL_LEVEL */
346                 cx25840_and_or(client, 0x8d5, ~0x7f, bal & 0x7f);
347         } else {
348                 /* PATH1_BAL_LEFT */
349                 cx25840_and_or(client, 0x8d5, 0x7f, 0x00);
350                 /* PATH1_BAL_LEVEL */
351                 cx25840_and_or(client, 0x8d5, ~0x7f, 0x80 - bal);
352         }
353 }
354 
355 static int get_mute(struct i2c_client *client)
356 {
357         struct cx25840_state *state = to_state(i2c_get_clientdata(client));
358 
359         return state->unmute_volume >= 0;
360 }
361 
362 static void set_mute(struct i2c_client *client, int mute)
363 {
364         struct cx25840_state *state = to_state(i2c_get_clientdata(client));
365 
366         if (mute && state->unmute_volume == -1) {
367                 int vol = get_volume(client);
368 
369                 set_volume(client, 0);
370                 state->unmute_volume = vol;
371         }
372         else if (!mute && state->unmute_volume != -1) {
373                 int vol = state->unmute_volume;
374 
375                 state->unmute_volume = -1;
376                 set_volume(client, vol);
377         }
378 }
379 
380 int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
381 {
382         struct i2c_client *client = v4l2_get_subdevdata(sd);
383         struct cx25840_state *state = to_state(sd);
384         int retval;
385 
386         if (!state->is_cx25836)
387                 cx25840_and_or(client, 0x810, ~0x1, 1);
388         if (state->aud_input != CX25840_AUDIO_SERIAL) {
389                 cx25840_and_or(client, 0x803, ~0x10, 0);
390                 cx25840_write(client, 0x8d3, 0x1f);
391         }
392         retval = set_audclk_freq(client, freq);
393         if (state->aud_input != CX25840_AUDIO_SERIAL)
394                 cx25840_and_or(client, 0x803, ~0x10, 0x10);
395         if (!state->is_cx25836)
396                 cx25840_and_or(client, 0x810, ~0x1, 0);
397         return retval;
398 }
399 
400 int cx25840_audio_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
401 {
402         struct i2c_client *client = v4l2_get_subdevdata(sd);
403 
404         switch (ctrl->id) {
405         case V4L2_CID_AUDIO_VOLUME:
406                 ctrl->value = get_volume(client);
407                 break;
408         case V4L2_CID_AUDIO_BASS:
409                 ctrl->value = get_bass(client);
410                 break;
411         case V4L2_CID_AUDIO_TREBLE:
412                 ctrl->value = get_treble(client);
413                 break;
414         case V4L2_CID_AUDIO_BALANCE:
415                 ctrl->value = get_balance(client);
416                 break;
417         case V4L2_CID_AUDIO_MUTE:
418                 ctrl->value = get_mute(client);
419                 break;
420         default:
421                 return -EINVAL;
422         }
423         return 0;
424 }
425 
426 int cx25840_audio_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
427 {
428         struct i2c_client *client = v4l2_get_subdevdata(sd);
429 
430         switch (ctrl->id) {
431         case V4L2_CID_AUDIO_VOLUME:
432                 set_volume(client, ctrl->value);
433                 break;
434         case V4L2_CID_AUDIO_BASS:
435                 set_bass(client, ctrl->value);
436                 break;
437         case V4L2_CID_AUDIO_TREBLE:
438                 set_treble(client, ctrl->value);
439                 break;
440         case V4L2_CID_AUDIO_BALANCE:
441                 set_balance(client, ctrl->value);
442                 break;
443         case V4L2_CID_AUDIO_MUTE:
444                 set_mute(client, ctrl->value);
445                 break;
446         default:
447                 return -EINVAL;
448         }
449         return 0;
450 }
451 
  This page was automatically generated by the LXR engine.