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