Merge tag 'printk-for-4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/pmladek...
[sfrench/cifs-2.6.git] / drivers / media / radio / radio-tea5777.c
1 /*
2  *   v4l2 driver for TEA5777 Philips AM/FM radio tuner chips
3  *
4  *      Copyright (c) 2012 Hans de Goede <hdegoede@redhat.com>
5  *
6  *   Based on the ALSA driver for TEA5757/5759 Philips AM/FM radio tuner chips:
7  *
8  *      Copyright (c) 2004 Jaroslav Kysela <perex@perex.cz>
9  *
10  *   This program is free software; you can redistribute it and/or modify
11  *   it under the terms of the GNU General Public License as published by
12  *   the Free Software Foundation; either version 2 of the License, or
13  *   (at your option) any later version.
14  *
15  *   This program is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  */
21
22 #include <linux/delay.h>
23 #include <linux/init.h>
24 #include <linux/module.h>
25 #include <linux/sched.h>
26 #include <linux/slab.h>
27 #include <media/v4l2-device.h>
28 #include <media/v4l2-dev.h>
29 #include <media/v4l2-fh.h>
30 #include <media/v4l2-ioctl.h>
31 #include <media/v4l2-event.h>
32 #include "radio-tea5777.h"
33
34 MODULE_AUTHOR("Hans de Goede <perex@perex.cz>");
35 MODULE_DESCRIPTION("Routines for control of TEA5777 Philips AM/FM radio tuner chips");
36 MODULE_LICENSE("GPL");
37
38 #define TEA5777_FM_IF                   150 /* kHz */
39 #define TEA5777_FM_FREQ_STEP            50  /* kHz */
40
41 #define TEA5777_AM_IF                   21  /* kHz */
42 #define TEA5777_AM_FREQ_STEP            1   /* kHz */
43
44 /* Write reg, common bits */
45 #define TEA5777_W_MUTE_MASK             (1LL << 47)
46 #define TEA5777_W_MUTE_SHIFT            47
47 #define TEA5777_W_AM_FM_MASK            (1LL << 46)
48 #define TEA5777_W_AM_FM_SHIFT           46
49 #define TEA5777_W_STB_MASK              (1LL << 45)
50 #define TEA5777_W_STB_SHIFT             45
51
52 #define TEA5777_W_IFCE_MASK             (1LL << 29)
53 #define TEA5777_W_IFCE_SHIFT            29
54 #define TEA5777_W_IFW_MASK              (1LL << 28)
55 #define TEA5777_W_IFW_SHIFT             28
56 #define TEA5777_W_HILO_MASK             (1LL << 27)
57 #define TEA5777_W_HILO_SHIFT            27
58 #define TEA5777_W_DBUS_MASK             (1LL << 26)
59 #define TEA5777_W_DBUS_SHIFT            26
60
61 #define TEA5777_W_INTEXT_MASK           (1LL << 24)
62 #define TEA5777_W_INTEXT_SHIFT          24
63 #define TEA5777_W_P1_MASK               (1LL << 23)
64 #define TEA5777_W_P1_SHIFT              23
65 #define TEA5777_W_P0_MASK               (1LL << 22)
66 #define TEA5777_W_P0_SHIFT              22
67 #define TEA5777_W_PEN1_MASK             (1LL << 21)
68 #define TEA5777_W_PEN1_SHIFT            21
69 #define TEA5777_W_PEN0_MASK             (1LL << 20)
70 #define TEA5777_W_PEN0_SHIFT            20
71
72 #define TEA5777_W_CHP0_MASK             (1LL << 18)
73 #define TEA5777_W_CHP0_SHIFT            18
74 #define TEA5777_W_DEEM_MASK             (1LL << 17)
75 #define TEA5777_W_DEEM_SHIFT            17
76
77 #define TEA5777_W_SEARCH_MASK           (1LL << 7)
78 #define TEA5777_W_SEARCH_SHIFT          7
79 #define TEA5777_W_PROGBLIM_MASK         (1LL << 6)
80 #define TEA5777_W_PROGBLIM_SHIFT        6
81 #define TEA5777_W_UPDWN_MASK            (1LL << 5)
82 #define TEA5777_W_UPDWN_SHIFT           5
83 #define TEA5777_W_SLEV_MASK             (3LL << 3)
84 #define TEA5777_W_SLEV_SHIFT            3
85
86 /* Write reg, FM specific bits */
87 #define TEA5777_W_FM_PLL_MASK           (0x1fffLL << 32)
88 #define TEA5777_W_FM_PLL_SHIFT          32
89 #define TEA5777_W_FM_FREF_MASK          (0x03LL << 30)
90 #define TEA5777_W_FM_FREF_SHIFT         30
91 #define TEA5777_W_FM_FREF_VALUE         0LL /* 50k steps, 150k IF */
92
93 #define TEA5777_W_FM_FORCEMONO_MASK     (1LL << 15)
94 #define TEA5777_W_FM_FORCEMONO_SHIFT    15
95 #define TEA5777_W_FM_SDSOFF_MASK        (1LL << 14)
96 #define TEA5777_W_FM_SDSOFF_SHIFT       14
97 #define TEA5777_W_FM_DOFF_MASK          (1LL << 13)
98 #define TEA5777_W_FM_DOFF_SHIFT         13
99
100 #define TEA5777_W_FM_STEP_MASK          (3LL << 1)
101 #define TEA5777_W_FM_STEP_SHIFT         1
102
103 /* Write reg, AM specific bits */
104 #define TEA5777_W_AM_PLL_MASK           (0x7ffLL << 34)
105 #define TEA5777_W_AM_PLL_SHIFT          34
106 #define TEA5777_W_AM_AGCRF_MASK         (1LL << 33)
107 #define TEA5777_W_AM_AGCRF_SHIFT        33
108 #define TEA5777_W_AM_AGCIF_MASK         (1LL << 32)
109 #define TEA5777_W_AM_AGCIF_SHIFT        32
110 #define TEA5777_W_AM_MWLW_MASK          (1LL << 31)
111 #define TEA5777_W_AM_MWLW_SHIFT         31
112 #define TEA5777_W_AM_LW                 0LL
113 #define TEA5777_W_AM_MW                 1LL
114 #define TEA5777_W_AM_LNA_MASK           (1LL << 30)
115 #define TEA5777_W_AM_LNA_SHIFT          30
116
117 #define TEA5777_W_AM_PEAK_MASK          (1LL << 25)
118 #define TEA5777_W_AM_PEAK_SHIFT         25
119
120 #define TEA5777_W_AM_RFB_MASK           (1LL << 16)
121 #define TEA5777_W_AM_RFB_SHIFT          16
122 #define TEA5777_W_AM_CALLIGN_MASK       (1LL << 15)
123 #define TEA5777_W_AM_CALLIGN_SHIFT      15
124 #define TEA5777_W_AM_CBANK_MASK         (0x7fLL << 8)
125 #define TEA5777_W_AM_CBANK_SHIFT        8
126
127 #define TEA5777_W_AM_DELAY_MASK         (1LL << 2)
128 #define TEA5777_W_AM_DELAY_SHIFT        2
129 #define TEA5777_W_AM_STEP_MASK          (1LL << 1)
130 #define TEA5777_W_AM_STEP_SHIFT         1
131
132 /* Read reg, common bits */
133 #define TEA5777_R_LEVEL_MASK            (0x0f << 17)
134 #define TEA5777_R_LEVEL_SHIFT           17
135 #define TEA5777_R_SFOUND_MASK           (0x01 << 16)
136 #define TEA5777_R_SFOUND_SHIFT          16
137 #define TEA5777_R_BLIM_MASK             (0x01 << 15)
138 #define TEA5777_R_BLIM_SHIFT            15
139
140 /* Read reg, FM specific bits */
141 #define TEA5777_R_FM_STEREO_MASK        (0x01 << 21)
142 #define TEA5777_R_FM_STEREO_SHIFT       21
143 #define TEA5777_R_FM_PLL_MASK           0x1fff
144 #define TEA5777_R_FM_PLL_SHIFT          0
145
146 enum { BAND_FM, BAND_AM };
147
148 static const struct v4l2_frequency_band bands[] = {
149         {
150                 .type = V4L2_TUNER_RADIO,
151                 .index = 0,
152                 .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
153                               V4L2_TUNER_CAP_FREQ_BANDS |
154                               V4L2_TUNER_CAP_HWSEEK_BOUNDED |
155                               V4L2_TUNER_CAP_HWSEEK_PROG_LIM,
156                 .rangelow   =  76000 * 16,
157                 .rangehigh  = 108000 * 16,
158                 .modulation = V4L2_BAND_MODULATION_FM,
159         },
160         {
161                 .type = V4L2_TUNER_RADIO,
162                 .index = 1,
163                 .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS |
164                               V4L2_TUNER_CAP_HWSEEK_BOUNDED |
165                               V4L2_TUNER_CAP_HWSEEK_PROG_LIM,
166                 .rangelow   =  530 * 16,
167                 .rangehigh  = 1710 * 16,
168                 .modulation = V4L2_BAND_MODULATION_AM,
169         },
170 };
171
172 static u32 tea5777_freq_to_v4l2_freq(struct radio_tea5777 *tea, u32 freq)
173 {
174         switch (tea->band) {
175         case BAND_FM:
176                 return (freq * TEA5777_FM_FREQ_STEP + TEA5777_FM_IF) * 16;
177         case BAND_AM:
178                 return (freq * TEA5777_AM_FREQ_STEP + TEA5777_AM_IF) * 16;
179         }
180         return 0; /* Never reached */
181 }
182
183 int radio_tea5777_set_freq(struct radio_tea5777 *tea)
184 {
185         u32 freq;
186         int res;
187
188         freq = clamp(tea->freq, bands[tea->band].rangelow,
189                                 bands[tea->band].rangehigh);
190         freq = (freq + 8) / 16; /* to kHz */
191
192         switch (tea->band) {
193         case BAND_FM:
194                 tea->write_reg &= ~TEA5777_W_AM_FM_MASK;
195                 freq = (freq - TEA5777_FM_IF) / TEA5777_FM_FREQ_STEP;
196                 tea->write_reg &= ~TEA5777_W_FM_PLL_MASK;
197                 tea->write_reg |= (u64)freq << TEA5777_W_FM_PLL_SHIFT;
198                 tea->write_reg &= ~TEA5777_W_FM_FREF_MASK;
199                 tea->write_reg |= TEA5777_W_FM_FREF_VALUE <<
200                                   TEA5777_W_FM_FREF_SHIFT;
201                 tea->write_reg &= ~TEA5777_W_FM_FORCEMONO_MASK;
202                 if (tea->audmode == V4L2_TUNER_MODE_MONO)
203                         tea->write_reg |= 1LL << TEA5777_W_FM_FORCEMONO_SHIFT;
204                 break;
205         case BAND_AM:
206                 tea->write_reg &= ~TEA5777_W_AM_FM_MASK;
207                 tea->write_reg |= (1LL << TEA5777_W_AM_FM_SHIFT);
208                 freq = (freq - TEA5777_AM_IF) / TEA5777_AM_FREQ_STEP;
209                 tea->write_reg &= ~TEA5777_W_AM_PLL_MASK;
210                 tea->write_reg |= (u64)freq << TEA5777_W_AM_PLL_SHIFT;
211                 tea->write_reg &= ~TEA5777_W_AM_AGCRF_MASK;
212                 tea->write_reg &= ~TEA5777_W_AM_AGCRF_MASK;
213                 tea->write_reg &= ~TEA5777_W_AM_MWLW_MASK;
214                 tea->write_reg |= TEA5777_W_AM_MW << TEA5777_W_AM_MWLW_SHIFT;
215                 tea->write_reg &= ~TEA5777_W_AM_LNA_MASK;
216                 tea->write_reg |= 1LL << TEA5777_W_AM_LNA_SHIFT;
217                 tea->write_reg &= ~TEA5777_W_AM_PEAK_MASK;
218                 tea->write_reg |= 1LL << TEA5777_W_AM_PEAK_SHIFT;
219                 tea->write_reg &= ~TEA5777_W_AM_CALLIGN_MASK;
220                 break;
221         }
222
223         res = tea->ops->write_reg(tea, tea->write_reg);
224         if (res)
225                 return res;
226
227         tea->needs_write = false;
228         tea->read_reg = -1;
229         tea->freq = tea5777_freq_to_v4l2_freq(tea, freq);
230
231         return 0;
232 }
233
234 static int radio_tea5777_update_read_reg(struct radio_tea5777 *tea, int wait)
235 {
236         int res;
237
238         if (tea->read_reg != -1)
239                 return 0;
240
241         if (tea->write_before_read && tea->needs_write) {
242                 res = radio_tea5777_set_freq(tea);
243                 if (res)
244                         return res;
245         }
246
247         if (wait) {
248                 if (schedule_timeout_interruptible(msecs_to_jiffies(wait)))
249                         return -ERESTARTSYS;
250         }
251
252         res = tea->ops->read_reg(tea, &tea->read_reg);
253         if (res)
254                 return res;
255
256         tea->needs_write = true;
257         return 0;
258 }
259
260 /*
261  * Linux Video interface
262  */
263
264 static int vidioc_querycap(struct file *file, void  *priv,
265                                         struct v4l2_capability *v)
266 {
267         struct radio_tea5777 *tea = video_drvdata(file);
268
269         strscpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver));
270         strscpy(v->card, tea->card, sizeof(v->card));
271         strlcat(v->card, " TEA5777", sizeof(v->card));
272         strscpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
273         v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
274         v->device_caps |= V4L2_CAP_HW_FREQ_SEEK;
275         v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
276         return 0;
277 }
278
279 static int vidioc_enum_freq_bands(struct file *file, void *priv,
280                                          struct v4l2_frequency_band *band)
281 {
282         struct radio_tea5777 *tea = video_drvdata(file);
283
284         if (band->tuner != 0 || band->index >= ARRAY_SIZE(bands) ||
285             (!tea->has_am && band->index == BAND_AM))
286                 return -EINVAL;
287
288         *band = bands[band->index];
289         return 0;
290 }
291
292 static int vidioc_g_tuner(struct file *file, void *priv,
293                                         struct v4l2_tuner *v)
294 {
295         struct radio_tea5777 *tea = video_drvdata(file);
296         int res;
297
298         if (v->index > 0)
299                 return -EINVAL;
300
301         res = radio_tea5777_update_read_reg(tea, 0);
302         if (res)
303                 return res;
304
305         memset(v, 0, sizeof(*v));
306         if (tea->has_am)
307                 strscpy(v->name, "AM/FM", sizeof(v->name));
308         else
309                 strscpy(v->name, "FM", sizeof(v->name));
310         v->type = V4L2_TUNER_RADIO;
311         v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
312                         V4L2_TUNER_CAP_FREQ_BANDS |
313                         V4L2_TUNER_CAP_HWSEEK_BOUNDED |
314                         V4L2_TUNER_CAP_HWSEEK_PROG_LIM;
315         v->rangelow   = tea->has_am ? bands[BAND_AM].rangelow :
316                                       bands[BAND_FM].rangelow;
317         v->rangehigh  = bands[BAND_FM].rangehigh;
318         if (tea->band == BAND_FM &&
319                         (tea->read_reg & TEA5777_R_FM_STEREO_MASK))
320                 v->rxsubchans = V4L2_TUNER_SUB_STEREO;
321         else
322                 v->rxsubchans = V4L2_TUNER_SUB_MONO;
323         v->audmode = tea->audmode;
324         /* shift - 12 to convert 4-bits (0-15) scale to 16-bits (0-65535) */
325         v->signal = (tea->read_reg & TEA5777_R_LEVEL_MASK) >>
326                     (TEA5777_R_LEVEL_SHIFT - 12);
327
328         /* Invalidate read_reg, so that next call we return up2date signal */
329         tea->read_reg = -1;
330
331         return 0;
332 }
333
334 static int vidioc_s_tuner(struct file *file, void *priv,
335                                         const struct v4l2_tuner *v)
336 {
337         struct radio_tea5777 *tea = video_drvdata(file);
338         u32 orig_audmode = tea->audmode;
339
340         if (v->index)
341                 return -EINVAL;
342
343         tea->audmode = v->audmode;
344         if (tea->audmode > V4L2_TUNER_MODE_STEREO)
345                 tea->audmode = V4L2_TUNER_MODE_STEREO;
346
347         if (tea->audmode != orig_audmode && tea->band == BAND_FM)
348                 return radio_tea5777_set_freq(tea);
349
350         return 0;
351 }
352
353 static int vidioc_g_frequency(struct file *file, void *priv,
354                                         struct v4l2_frequency *f)
355 {
356         struct radio_tea5777 *tea = video_drvdata(file);
357
358         if (f->tuner != 0)
359                 return -EINVAL;
360         f->type = V4L2_TUNER_RADIO;
361         f->frequency = tea->freq;
362         return 0;
363 }
364
365 static int vidioc_s_frequency(struct file *file, void *priv,
366                                         const struct v4l2_frequency *f)
367 {
368         struct radio_tea5777 *tea = video_drvdata(file);
369
370         if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
371                 return -EINVAL;
372
373         if (tea->has_am && f->frequency < (20000 * 16))
374                 tea->band = BAND_AM;
375         else
376                 tea->band = BAND_FM;
377
378         tea->freq = f->frequency;
379         return radio_tea5777_set_freq(tea);
380 }
381
382 static int vidioc_s_hw_freq_seek(struct file *file, void *fh,
383                                         const struct v4l2_hw_freq_seek *a)
384 {
385         struct radio_tea5777 *tea = video_drvdata(file);
386         unsigned long timeout;
387         u32 rangelow = a->rangelow;
388         u32 rangehigh = a->rangehigh;
389         int i, res, spacing;
390         u32 orig_freq;
391
392         if (a->tuner || a->wrap_around)
393                 return -EINVAL;
394
395         if (file->f_flags & O_NONBLOCK)
396                 return -EWOULDBLOCK;
397
398         if (rangelow || rangehigh) {
399                 for (i = 0; i < ARRAY_SIZE(bands); i++) {
400                         if (i == BAND_AM && !tea->has_am)
401                                 continue;
402                         if (bands[i].rangelow  >= rangelow &&
403                             bands[i].rangehigh <= rangehigh)
404                                 break;
405                 }
406                 if (i == ARRAY_SIZE(bands))
407                         return -EINVAL; /* No matching band found */
408
409                 tea->band = i;
410                 if (tea->freq < rangelow || tea->freq > rangehigh) {
411                         tea->freq = clamp(tea->freq, rangelow,
412                                                      rangehigh);
413                         res = radio_tea5777_set_freq(tea);
414                         if (res)
415                                 return res;
416                 }
417         } else {
418                 rangelow  = bands[tea->band].rangelow;
419                 rangehigh = bands[tea->band].rangehigh;
420         }
421
422         spacing   = (tea->band == BAND_AM) ? (5 * 16) : (200 * 16); /* kHz */
423         orig_freq = tea->freq;
424
425         tea->write_reg |= TEA5777_W_PROGBLIM_MASK;
426         if (tea->seek_rangelow != rangelow) {
427                 tea->write_reg &= ~TEA5777_W_UPDWN_MASK;
428                 tea->freq = rangelow;
429                 res = radio_tea5777_set_freq(tea);
430                 if (res)
431                         goto leave;
432                 tea->seek_rangelow = rangelow;
433         }
434         if (tea->seek_rangehigh != rangehigh) {
435                 tea->write_reg |= TEA5777_W_UPDWN_MASK;
436                 tea->freq = rangehigh;
437                 res = radio_tea5777_set_freq(tea);
438                 if (res)
439                         goto leave;
440                 tea->seek_rangehigh = rangehigh;
441         }
442         tea->write_reg &= ~TEA5777_W_PROGBLIM_MASK;
443
444         tea->write_reg |= TEA5777_W_SEARCH_MASK;
445         if (a->seek_upward) {
446                 tea->write_reg |= TEA5777_W_UPDWN_MASK;
447                 tea->freq = orig_freq + spacing;
448         } else {
449                 tea->write_reg &= ~TEA5777_W_UPDWN_MASK;
450                 tea->freq = orig_freq - spacing;
451         }
452         res = radio_tea5777_set_freq(tea);
453         if (res)
454                 goto leave;
455
456         timeout = jiffies + msecs_to_jiffies(5000);
457         for (;;) {
458                 if (time_after(jiffies, timeout)) {
459                         res = -ENODATA;
460                         break;
461                 }
462
463                 res = radio_tea5777_update_read_reg(tea, 100);
464                 if (res)
465                         break;
466
467                 /*
468                  * Note we use tea->freq to track how far we've searched sofar
469                  * this is necessary to ensure we continue seeking at the right
470                  * point, in the write_before_read case.
471                  */
472                 tea->freq = (tea->read_reg & TEA5777_R_FM_PLL_MASK);
473                 tea->freq = tea5777_freq_to_v4l2_freq(tea, tea->freq);
474
475                 if ((tea->read_reg & TEA5777_R_SFOUND_MASK)) {
476                         tea->write_reg &= ~TEA5777_W_SEARCH_MASK;
477                         return 0;
478                 }
479
480                 if (tea->read_reg & TEA5777_R_BLIM_MASK) {
481                         res = -ENODATA;
482                         break;
483                 }
484
485                 /* Force read_reg update */
486                 tea->read_reg = -1;
487         }
488 leave:
489         tea->write_reg &= ~TEA5777_W_PROGBLIM_MASK;
490         tea->write_reg &= ~TEA5777_W_SEARCH_MASK;
491         tea->freq = orig_freq;
492         radio_tea5777_set_freq(tea);
493         return res;
494 }
495
496 static int tea575x_s_ctrl(struct v4l2_ctrl *c)
497 {
498         struct radio_tea5777 *tea =
499                 container_of(c->handler, struct radio_tea5777, ctrl_handler);
500
501         switch (c->id) {
502         case V4L2_CID_AUDIO_MUTE:
503                 if (c->val)
504                         tea->write_reg |= TEA5777_W_MUTE_MASK;
505                 else
506                         tea->write_reg &= ~TEA5777_W_MUTE_MASK;
507
508                 return radio_tea5777_set_freq(tea);
509         }
510
511         return -EINVAL;
512 }
513
514 static const struct v4l2_file_operations tea575x_fops = {
515         .unlocked_ioctl = video_ioctl2,
516         .open           = v4l2_fh_open,
517         .release        = v4l2_fh_release,
518         .poll           = v4l2_ctrl_poll,
519 };
520
521 static const struct v4l2_ioctl_ops tea575x_ioctl_ops = {
522         .vidioc_querycap    = vidioc_querycap,
523         .vidioc_g_tuner     = vidioc_g_tuner,
524         .vidioc_s_tuner     = vidioc_s_tuner,
525         .vidioc_g_frequency = vidioc_g_frequency,
526         .vidioc_s_frequency = vidioc_s_frequency,
527         .vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek,
528         .vidioc_enum_freq_bands = vidioc_enum_freq_bands,
529         .vidioc_log_status  = v4l2_ctrl_log_status,
530         .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
531         .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
532 };
533
534 static const struct video_device tea575x_radio = {
535         .ioctl_ops      = &tea575x_ioctl_ops,
536         .release        = video_device_release_empty,
537 };
538
539 static const struct v4l2_ctrl_ops tea575x_ctrl_ops = {
540         .s_ctrl = tea575x_s_ctrl,
541 };
542
543 int radio_tea5777_init(struct radio_tea5777 *tea, struct module *owner)
544 {
545         int res;
546
547         tea->write_reg = (1LL << TEA5777_W_IFCE_SHIFT) |
548                          (1LL << TEA5777_W_IFW_SHIFT) |
549                          (1LL << TEA5777_W_INTEXT_SHIFT) |
550                          (1LL << TEA5777_W_CHP0_SHIFT) |
551                          (1LL << TEA5777_W_SLEV_SHIFT);
552         tea->freq = 90500 * 16; /* 90.5Mhz default */
553         tea->audmode = V4L2_TUNER_MODE_STEREO;
554         res = radio_tea5777_set_freq(tea);
555         if (res) {
556                 v4l2_err(tea->v4l2_dev, "can't set initial freq (%d)\n", res);
557                 return res;
558         }
559
560         tea->vd = tea575x_radio;
561         video_set_drvdata(&tea->vd, tea);
562         mutex_init(&tea->mutex);
563         strscpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name));
564         tea->vd.lock = &tea->mutex;
565         tea->vd.v4l2_dev = tea->v4l2_dev;
566         tea->fops = tea575x_fops;
567         tea->fops.owner = owner;
568         tea->vd.fops = &tea->fops;
569
570         tea->vd.ctrl_handler = &tea->ctrl_handler;
571         v4l2_ctrl_handler_init(&tea->ctrl_handler, 1);
572         v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops,
573                           V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
574         res = tea->ctrl_handler.error;
575         if (res) {
576                 v4l2_err(tea->v4l2_dev, "can't initialize controls\n");
577                 v4l2_ctrl_handler_free(&tea->ctrl_handler);
578                 return res;
579         }
580         v4l2_ctrl_handler_setup(&tea->ctrl_handler);
581
582         res = video_register_device(&tea->vd, VFL_TYPE_RADIO, -1);
583         if (res) {
584                 v4l2_err(tea->v4l2_dev, "can't register video device!\n");
585                 v4l2_ctrl_handler_free(tea->vd.ctrl_handler);
586                 return res;
587         }
588
589         return 0;
590 }
591 EXPORT_SYMBOL_GPL(radio_tea5777_init);
592
593 void radio_tea5777_exit(struct radio_tea5777 *tea)
594 {
595         video_unregister_device(&tea->vd);
596         v4l2_ctrl_handler_free(tea->vd.ctrl_handler);
597 }
598 EXPORT_SYMBOL_GPL(radio_tea5777_exit);