Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *   v4l2 driver for TEA5777 Philips AM/FM radio tuner chips
0004  *
0005  *  Copyright (c) 2012 Hans de Goede <hdegoede@redhat.com>
0006  *
0007  *   Based on the ALSA driver for TEA5757/5759 Philips AM/FM radio tuner chips:
0008  *
0009  *  Copyright (c) 2004 Jaroslav Kysela <perex@perex.cz>
0010  */
0011 
0012 #include <linux/delay.h>
0013 #include <linux/init.h>
0014 #include <linux/module.h>
0015 #include <linux/sched.h>
0016 #include <linux/slab.h>
0017 #include <media/v4l2-device.h>
0018 #include <media/v4l2-dev.h>
0019 #include <media/v4l2-fh.h>
0020 #include <media/v4l2-ioctl.h>
0021 #include <media/v4l2-event.h>
0022 #include "radio-tea5777.h"
0023 
0024 MODULE_AUTHOR("Hans de Goede <perex@perex.cz>");
0025 MODULE_DESCRIPTION("Routines for control of TEA5777 Philips AM/FM radio tuner chips");
0026 MODULE_LICENSE("GPL");
0027 
0028 #define TEA5777_FM_IF           150 /* kHz */
0029 #define TEA5777_FM_FREQ_STEP        50  /* kHz */
0030 
0031 #define TEA5777_AM_IF           21  /* kHz */
0032 #define TEA5777_AM_FREQ_STEP        1   /* kHz */
0033 
0034 /* Write reg, common bits */
0035 #define TEA5777_W_MUTE_MASK     (1LL << 47)
0036 #define TEA5777_W_MUTE_SHIFT        47
0037 #define TEA5777_W_AM_FM_MASK        (1LL << 46)
0038 #define TEA5777_W_AM_FM_SHIFT       46
0039 #define TEA5777_W_STB_MASK      (1LL << 45)
0040 #define TEA5777_W_STB_SHIFT     45
0041 
0042 #define TEA5777_W_IFCE_MASK     (1LL << 29)
0043 #define TEA5777_W_IFCE_SHIFT        29
0044 #define TEA5777_W_IFW_MASK      (1LL << 28)
0045 #define TEA5777_W_IFW_SHIFT     28
0046 #define TEA5777_W_HILO_MASK     (1LL << 27)
0047 #define TEA5777_W_HILO_SHIFT        27
0048 #define TEA5777_W_DBUS_MASK     (1LL << 26)
0049 #define TEA5777_W_DBUS_SHIFT        26
0050 
0051 #define TEA5777_W_INTEXT_MASK       (1LL << 24)
0052 #define TEA5777_W_INTEXT_SHIFT      24
0053 #define TEA5777_W_P1_MASK       (1LL << 23)
0054 #define TEA5777_W_P1_SHIFT      23
0055 #define TEA5777_W_P0_MASK       (1LL << 22)
0056 #define TEA5777_W_P0_SHIFT      22
0057 #define TEA5777_W_PEN1_MASK     (1LL << 21)
0058 #define TEA5777_W_PEN1_SHIFT        21
0059 #define TEA5777_W_PEN0_MASK     (1LL << 20)
0060 #define TEA5777_W_PEN0_SHIFT        20
0061 
0062 #define TEA5777_W_CHP0_MASK     (1LL << 18)
0063 #define TEA5777_W_CHP0_SHIFT        18
0064 #define TEA5777_W_DEEM_MASK     (1LL << 17)
0065 #define TEA5777_W_DEEM_SHIFT        17
0066 
0067 #define TEA5777_W_SEARCH_MASK       (1LL << 7)
0068 #define TEA5777_W_SEARCH_SHIFT      7
0069 #define TEA5777_W_PROGBLIM_MASK     (1LL << 6)
0070 #define TEA5777_W_PROGBLIM_SHIFT    6
0071 #define TEA5777_W_UPDWN_MASK        (1LL << 5)
0072 #define TEA5777_W_UPDWN_SHIFT       5
0073 #define TEA5777_W_SLEV_MASK     (3LL << 3)
0074 #define TEA5777_W_SLEV_SHIFT        3
0075 
0076 /* Write reg, FM specific bits */
0077 #define TEA5777_W_FM_PLL_MASK       (0x1fffLL << 32)
0078 #define TEA5777_W_FM_PLL_SHIFT      32
0079 #define TEA5777_W_FM_FREF_MASK      (0x03LL << 30)
0080 #define TEA5777_W_FM_FREF_SHIFT     30
0081 #define TEA5777_W_FM_FREF_VALUE     0LL /* 50k steps, 150k IF */
0082 
0083 #define TEA5777_W_FM_FORCEMONO_MASK (1LL << 15)
0084 #define TEA5777_W_FM_FORCEMONO_SHIFT    15
0085 #define TEA5777_W_FM_SDSOFF_MASK    (1LL << 14)
0086 #define TEA5777_W_FM_SDSOFF_SHIFT   14
0087 #define TEA5777_W_FM_DOFF_MASK      (1LL << 13)
0088 #define TEA5777_W_FM_DOFF_SHIFT     13
0089 
0090 #define TEA5777_W_FM_STEP_MASK      (3LL << 1)
0091 #define TEA5777_W_FM_STEP_SHIFT     1
0092 
0093 /* Write reg, AM specific bits */
0094 #define TEA5777_W_AM_PLL_MASK       (0x7ffLL << 34)
0095 #define TEA5777_W_AM_PLL_SHIFT      34
0096 #define TEA5777_W_AM_AGCRF_MASK     (1LL << 33)
0097 #define TEA5777_W_AM_AGCRF_SHIFT    33
0098 #define TEA5777_W_AM_AGCIF_MASK     (1LL << 32)
0099 #define TEA5777_W_AM_AGCIF_SHIFT    32
0100 #define TEA5777_W_AM_MWLW_MASK      (1LL << 31)
0101 #define TEA5777_W_AM_MWLW_SHIFT     31
0102 #define TEA5777_W_AM_LW         0LL
0103 #define TEA5777_W_AM_MW         1LL
0104 #define TEA5777_W_AM_LNA_MASK       (1LL << 30)
0105 #define TEA5777_W_AM_LNA_SHIFT      30
0106 
0107 #define TEA5777_W_AM_PEAK_MASK      (1LL << 25)
0108 #define TEA5777_W_AM_PEAK_SHIFT     25
0109 
0110 #define TEA5777_W_AM_RFB_MASK       (1LL << 16)
0111 #define TEA5777_W_AM_RFB_SHIFT      16
0112 #define TEA5777_W_AM_CALLIGN_MASK   (1LL << 15)
0113 #define TEA5777_W_AM_CALLIGN_SHIFT  15
0114 #define TEA5777_W_AM_CBANK_MASK     (0x7fLL << 8)
0115 #define TEA5777_W_AM_CBANK_SHIFT    8
0116 
0117 #define TEA5777_W_AM_DELAY_MASK     (1LL << 2)
0118 #define TEA5777_W_AM_DELAY_SHIFT    2
0119 #define TEA5777_W_AM_STEP_MASK      (1LL << 1)
0120 #define TEA5777_W_AM_STEP_SHIFT     1
0121 
0122 /* Read reg, common bits */
0123 #define TEA5777_R_LEVEL_MASK        (0x0f << 17)
0124 #define TEA5777_R_LEVEL_SHIFT       17
0125 #define TEA5777_R_SFOUND_MASK       (0x01 << 16)
0126 #define TEA5777_R_SFOUND_SHIFT      16
0127 #define TEA5777_R_BLIM_MASK     (0x01 << 15)
0128 #define TEA5777_R_BLIM_SHIFT        15
0129 
0130 /* Read reg, FM specific bits */
0131 #define TEA5777_R_FM_STEREO_MASK    (0x01 << 21)
0132 #define TEA5777_R_FM_STEREO_SHIFT   21
0133 #define TEA5777_R_FM_PLL_MASK       0x1fff
0134 #define TEA5777_R_FM_PLL_SHIFT      0
0135 
0136 enum { BAND_FM, BAND_AM };
0137 
0138 static const struct v4l2_frequency_band bands[] = {
0139     {
0140         .type = V4L2_TUNER_RADIO,
0141         .index = 0,
0142         .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
0143                   V4L2_TUNER_CAP_FREQ_BANDS |
0144                   V4L2_TUNER_CAP_HWSEEK_BOUNDED |
0145                   V4L2_TUNER_CAP_HWSEEK_PROG_LIM,
0146         .rangelow   =  76000 * 16,
0147         .rangehigh  = 108000 * 16,
0148         .modulation = V4L2_BAND_MODULATION_FM,
0149     },
0150     {
0151         .type = V4L2_TUNER_RADIO,
0152         .index = 1,
0153         .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS |
0154                   V4L2_TUNER_CAP_HWSEEK_BOUNDED |
0155                   V4L2_TUNER_CAP_HWSEEK_PROG_LIM,
0156         .rangelow   =  530 * 16,
0157         .rangehigh  = 1710 * 16,
0158         .modulation = V4L2_BAND_MODULATION_AM,
0159     },
0160 };
0161 
0162 static u32 tea5777_freq_to_v4l2_freq(struct radio_tea5777 *tea, u32 freq)
0163 {
0164     switch (tea->band) {
0165     case BAND_FM:
0166         return (freq * TEA5777_FM_FREQ_STEP + TEA5777_FM_IF) * 16;
0167     case BAND_AM:
0168         return (freq * TEA5777_AM_FREQ_STEP + TEA5777_AM_IF) * 16;
0169     }
0170     return 0; /* Never reached */
0171 }
0172 
0173 int radio_tea5777_set_freq(struct radio_tea5777 *tea)
0174 {
0175     u32 freq;
0176     int res;
0177 
0178     freq = clamp(tea->freq, bands[tea->band].rangelow,
0179                 bands[tea->band].rangehigh);
0180     freq = (freq + 8) / 16; /* to kHz */
0181 
0182     switch (tea->band) {
0183     case BAND_FM:
0184         tea->write_reg &= ~TEA5777_W_AM_FM_MASK;
0185         freq = (freq - TEA5777_FM_IF) / TEA5777_FM_FREQ_STEP;
0186         tea->write_reg &= ~TEA5777_W_FM_PLL_MASK;
0187         tea->write_reg |= (u64)freq << TEA5777_W_FM_PLL_SHIFT;
0188         tea->write_reg &= ~TEA5777_W_FM_FREF_MASK;
0189         tea->write_reg |= TEA5777_W_FM_FREF_VALUE <<
0190                   TEA5777_W_FM_FREF_SHIFT;
0191         tea->write_reg &= ~TEA5777_W_FM_FORCEMONO_MASK;
0192         if (tea->audmode == V4L2_TUNER_MODE_MONO)
0193             tea->write_reg |= 1LL << TEA5777_W_FM_FORCEMONO_SHIFT;
0194         break;
0195     case BAND_AM:
0196         tea->write_reg &= ~TEA5777_W_AM_FM_MASK;
0197         tea->write_reg |= (1LL << TEA5777_W_AM_FM_SHIFT);
0198         freq = (freq - TEA5777_AM_IF) / TEA5777_AM_FREQ_STEP;
0199         tea->write_reg &= ~TEA5777_W_AM_PLL_MASK;
0200         tea->write_reg |= (u64)freq << TEA5777_W_AM_PLL_SHIFT;
0201         tea->write_reg &= ~TEA5777_W_AM_AGCRF_MASK;
0202         tea->write_reg &= ~TEA5777_W_AM_AGCRF_MASK;
0203         tea->write_reg &= ~TEA5777_W_AM_MWLW_MASK;
0204         tea->write_reg |= TEA5777_W_AM_MW << TEA5777_W_AM_MWLW_SHIFT;
0205         tea->write_reg &= ~TEA5777_W_AM_LNA_MASK;
0206         tea->write_reg |= 1LL << TEA5777_W_AM_LNA_SHIFT;
0207         tea->write_reg &= ~TEA5777_W_AM_PEAK_MASK;
0208         tea->write_reg |= 1LL << TEA5777_W_AM_PEAK_SHIFT;
0209         tea->write_reg &= ~TEA5777_W_AM_CALLIGN_MASK;
0210         break;
0211     }
0212 
0213     res = tea->ops->write_reg(tea, tea->write_reg);
0214     if (res)
0215         return res;
0216 
0217     tea->needs_write = false;
0218     tea->read_reg = -1;
0219     tea->freq = tea5777_freq_to_v4l2_freq(tea, freq);
0220 
0221     return 0;
0222 }
0223 
0224 static int radio_tea5777_update_read_reg(struct radio_tea5777 *tea, int wait)
0225 {
0226     int res;
0227 
0228     if (tea->read_reg != -1)
0229         return 0;
0230 
0231     if (tea->write_before_read && tea->needs_write) {
0232         res = radio_tea5777_set_freq(tea);
0233         if (res)
0234             return res;
0235     }
0236 
0237     if (wait) {
0238         if (schedule_timeout_interruptible(msecs_to_jiffies(wait)))
0239             return -ERESTARTSYS;
0240     }
0241 
0242     res = tea->ops->read_reg(tea, &tea->read_reg);
0243     if (res)
0244         return res;
0245 
0246     tea->needs_write = true;
0247     return 0;
0248 }
0249 
0250 /*
0251  * Linux Video interface
0252  */
0253 
0254 static int vidioc_querycap(struct file *file, void  *priv,
0255                     struct v4l2_capability *v)
0256 {
0257     struct radio_tea5777 *tea = video_drvdata(file);
0258 
0259     strscpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver));
0260     strscpy(v->card, tea->card, sizeof(v->card));
0261     strlcat(v->card, " TEA5777", sizeof(v->card));
0262     strscpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
0263     return 0;
0264 }
0265 
0266 static int vidioc_enum_freq_bands(struct file *file, void *priv,
0267                      struct v4l2_frequency_band *band)
0268 {
0269     struct radio_tea5777 *tea = video_drvdata(file);
0270 
0271     if (band->tuner != 0 || band->index >= ARRAY_SIZE(bands) ||
0272         (!tea->has_am && band->index == BAND_AM))
0273         return -EINVAL;
0274 
0275     *band = bands[band->index];
0276     return 0;
0277 }
0278 
0279 static int vidioc_g_tuner(struct file *file, void *priv,
0280                     struct v4l2_tuner *v)
0281 {
0282     struct radio_tea5777 *tea = video_drvdata(file);
0283     int res;
0284 
0285     if (v->index > 0)
0286         return -EINVAL;
0287 
0288     res = radio_tea5777_update_read_reg(tea, 0);
0289     if (res)
0290         return res;
0291 
0292     memset(v, 0, sizeof(*v));
0293     if (tea->has_am)
0294         strscpy(v->name, "AM/FM", sizeof(v->name));
0295     else
0296         strscpy(v->name, "FM", sizeof(v->name));
0297     v->type = V4L2_TUNER_RADIO;
0298     v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
0299             V4L2_TUNER_CAP_FREQ_BANDS |
0300             V4L2_TUNER_CAP_HWSEEK_BOUNDED |
0301             V4L2_TUNER_CAP_HWSEEK_PROG_LIM;
0302     v->rangelow   = tea->has_am ? bands[BAND_AM].rangelow :
0303                       bands[BAND_FM].rangelow;
0304     v->rangehigh  = bands[BAND_FM].rangehigh;
0305     if (tea->band == BAND_FM &&
0306             (tea->read_reg & TEA5777_R_FM_STEREO_MASK))
0307         v->rxsubchans = V4L2_TUNER_SUB_STEREO;
0308     else
0309         v->rxsubchans = V4L2_TUNER_SUB_MONO;
0310     v->audmode = tea->audmode;
0311     /* shift - 12 to convert 4-bits (0-15) scale to 16-bits (0-65535) */
0312     v->signal = (tea->read_reg & TEA5777_R_LEVEL_MASK) >>
0313             (TEA5777_R_LEVEL_SHIFT - 12);
0314 
0315     /* Invalidate read_reg, so that next call we return up2date signal */
0316     tea->read_reg = -1;
0317 
0318     return 0;
0319 }
0320 
0321 static int vidioc_s_tuner(struct file *file, void *priv,
0322                     const struct v4l2_tuner *v)
0323 {
0324     struct radio_tea5777 *tea = video_drvdata(file);
0325     u32 orig_audmode = tea->audmode;
0326 
0327     if (v->index)
0328         return -EINVAL;
0329 
0330     tea->audmode = v->audmode;
0331     if (tea->audmode > V4L2_TUNER_MODE_STEREO)
0332         tea->audmode = V4L2_TUNER_MODE_STEREO;
0333 
0334     if (tea->audmode != orig_audmode && tea->band == BAND_FM)
0335         return radio_tea5777_set_freq(tea);
0336 
0337     return 0;
0338 }
0339 
0340 static int vidioc_g_frequency(struct file *file, void *priv,
0341                     struct v4l2_frequency *f)
0342 {
0343     struct radio_tea5777 *tea = video_drvdata(file);
0344 
0345     if (f->tuner != 0)
0346         return -EINVAL;
0347     f->type = V4L2_TUNER_RADIO;
0348     f->frequency = tea->freq;
0349     return 0;
0350 }
0351 
0352 static int vidioc_s_frequency(struct file *file, void *priv,
0353                     const struct v4l2_frequency *f)
0354 {
0355     struct radio_tea5777 *tea = video_drvdata(file);
0356 
0357     if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
0358         return -EINVAL;
0359 
0360     if (tea->has_am && f->frequency < (20000 * 16))
0361         tea->band = BAND_AM;
0362     else
0363         tea->band = BAND_FM;
0364 
0365     tea->freq = f->frequency;
0366     return radio_tea5777_set_freq(tea);
0367 }
0368 
0369 static int vidioc_s_hw_freq_seek(struct file *file, void *fh,
0370                     const struct v4l2_hw_freq_seek *a)
0371 {
0372     struct radio_tea5777 *tea = video_drvdata(file);
0373     unsigned long timeout;
0374     u32 rangelow = a->rangelow;
0375     u32 rangehigh = a->rangehigh;
0376     int i, res, spacing;
0377     u32 orig_freq;
0378 
0379     if (a->tuner || a->wrap_around)
0380         return -EINVAL;
0381 
0382     if (file->f_flags & O_NONBLOCK)
0383         return -EWOULDBLOCK;
0384 
0385     if (rangelow || rangehigh) {
0386         for (i = 0; i < ARRAY_SIZE(bands); i++) {
0387             if (i == BAND_AM && !tea->has_am)
0388                 continue;
0389             if (bands[i].rangelow  >= rangelow &&
0390                 bands[i].rangehigh <= rangehigh)
0391                 break;
0392         }
0393         if (i == ARRAY_SIZE(bands))
0394             return -EINVAL; /* No matching band found */
0395 
0396         tea->band = i;
0397         if (tea->freq < rangelow || tea->freq > rangehigh) {
0398             tea->freq = clamp(tea->freq, rangelow,
0399                              rangehigh);
0400             res = radio_tea5777_set_freq(tea);
0401             if (res)
0402                 return res;
0403         }
0404     } else {
0405         rangelow  = bands[tea->band].rangelow;
0406         rangehigh = bands[tea->band].rangehigh;
0407     }
0408 
0409     spacing   = (tea->band == BAND_AM) ? (5 * 16) : (200 * 16); /* kHz */
0410     orig_freq = tea->freq;
0411 
0412     tea->write_reg |= TEA5777_W_PROGBLIM_MASK;
0413     if (tea->seek_rangelow != rangelow) {
0414         tea->write_reg &= ~TEA5777_W_UPDWN_MASK;
0415         tea->freq = rangelow;
0416         res = radio_tea5777_set_freq(tea);
0417         if (res)
0418             goto leave;
0419         tea->seek_rangelow = rangelow;
0420     }
0421     if (tea->seek_rangehigh != rangehigh) {
0422         tea->write_reg |= TEA5777_W_UPDWN_MASK;
0423         tea->freq = rangehigh;
0424         res = radio_tea5777_set_freq(tea);
0425         if (res)
0426             goto leave;
0427         tea->seek_rangehigh = rangehigh;
0428     }
0429     tea->write_reg &= ~TEA5777_W_PROGBLIM_MASK;
0430 
0431     tea->write_reg |= TEA5777_W_SEARCH_MASK;
0432     if (a->seek_upward) {
0433         tea->write_reg |= TEA5777_W_UPDWN_MASK;
0434         tea->freq = orig_freq + spacing;
0435     } else {
0436         tea->write_reg &= ~TEA5777_W_UPDWN_MASK;
0437         tea->freq = orig_freq - spacing;
0438     }
0439     res = radio_tea5777_set_freq(tea);
0440     if (res)
0441         goto leave;
0442 
0443     timeout = jiffies + msecs_to_jiffies(5000);
0444     for (;;) {
0445         if (time_after(jiffies, timeout)) {
0446             res = -ENODATA;
0447             break;
0448         }
0449 
0450         res = radio_tea5777_update_read_reg(tea, 100);
0451         if (res)
0452             break;
0453 
0454         /*
0455          * Note we use tea->freq to track how far we've searched sofar
0456          * this is necessary to ensure we continue seeking at the right
0457          * point, in the write_before_read case.
0458          */
0459         tea->freq = (tea->read_reg & TEA5777_R_FM_PLL_MASK);
0460         tea->freq = tea5777_freq_to_v4l2_freq(tea, tea->freq);
0461 
0462         if ((tea->read_reg & TEA5777_R_SFOUND_MASK)) {
0463             tea->write_reg &= ~TEA5777_W_SEARCH_MASK;
0464             return 0;
0465         }
0466 
0467         if (tea->read_reg & TEA5777_R_BLIM_MASK) {
0468             res = -ENODATA;
0469             break;
0470         }
0471 
0472         /* Force read_reg update */
0473         tea->read_reg = -1;
0474     }
0475 leave:
0476     tea->write_reg &= ~TEA5777_W_PROGBLIM_MASK;
0477     tea->write_reg &= ~TEA5777_W_SEARCH_MASK;
0478     tea->freq = orig_freq;
0479     radio_tea5777_set_freq(tea);
0480     return res;
0481 }
0482 
0483 static int tea575x_s_ctrl(struct v4l2_ctrl *c)
0484 {
0485     struct radio_tea5777 *tea =
0486         container_of(c->handler, struct radio_tea5777, ctrl_handler);
0487 
0488     switch (c->id) {
0489     case V4L2_CID_AUDIO_MUTE:
0490         if (c->val)
0491             tea->write_reg |= TEA5777_W_MUTE_MASK;
0492         else
0493             tea->write_reg &= ~TEA5777_W_MUTE_MASK;
0494 
0495         return radio_tea5777_set_freq(tea);
0496     }
0497 
0498     return -EINVAL;
0499 }
0500 
0501 static const struct v4l2_file_operations tea575x_fops = {
0502     .unlocked_ioctl = video_ioctl2,
0503     .open       = v4l2_fh_open,
0504     .release    = v4l2_fh_release,
0505     .poll       = v4l2_ctrl_poll,
0506 };
0507 
0508 static const struct v4l2_ioctl_ops tea575x_ioctl_ops = {
0509     .vidioc_querycap    = vidioc_querycap,
0510     .vidioc_g_tuner     = vidioc_g_tuner,
0511     .vidioc_s_tuner     = vidioc_s_tuner,
0512     .vidioc_g_frequency = vidioc_g_frequency,
0513     .vidioc_s_frequency = vidioc_s_frequency,
0514     .vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek,
0515     .vidioc_enum_freq_bands = vidioc_enum_freq_bands,
0516     .vidioc_log_status  = v4l2_ctrl_log_status,
0517     .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
0518     .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
0519 };
0520 
0521 static const struct video_device tea575x_radio = {
0522     .ioctl_ops  = &tea575x_ioctl_ops,
0523     .release    = video_device_release_empty,
0524 };
0525 
0526 static const struct v4l2_ctrl_ops tea575x_ctrl_ops = {
0527     .s_ctrl = tea575x_s_ctrl,
0528 };
0529 
0530 int radio_tea5777_init(struct radio_tea5777 *tea, struct module *owner)
0531 {
0532     int res;
0533 
0534     tea->write_reg = (1LL << TEA5777_W_IFCE_SHIFT) |
0535              (1LL << TEA5777_W_IFW_SHIFT) |
0536              (1LL << TEA5777_W_INTEXT_SHIFT) |
0537              (1LL << TEA5777_W_CHP0_SHIFT) |
0538              (1LL << TEA5777_W_SLEV_SHIFT);
0539     tea->freq = 90500 * 16; /* 90.5Mhz default */
0540     tea->audmode = V4L2_TUNER_MODE_STEREO;
0541     res = radio_tea5777_set_freq(tea);
0542     if (res) {
0543         v4l2_err(tea->v4l2_dev, "can't set initial freq (%d)\n", res);
0544         return res;
0545     }
0546 
0547     tea->vd = tea575x_radio;
0548     video_set_drvdata(&tea->vd, tea);
0549     mutex_init(&tea->mutex);
0550     strscpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name));
0551     tea->vd.lock = &tea->mutex;
0552     tea->vd.v4l2_dev = tea->v4l2_dev;
0553     tea->vd.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
0554                   V4L2_CAP_HW_FREQ_SEEK;
0555     tea->fops = tea575x_fops;
0556     tea->fops.owner = owner;
0557     tea->vd.fops = &tea->fops;
0558 
0559     tea->vd.ctrl_handler = &tea->ctrl_handler;
0560     v4l2_ctrl_handler_init(&tea->ctrl_handler, 1);
0561     v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops,
0562               V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
0563     res = tea->ctrl_handler.error;
0564     if (res) {
0565         v4l2_err(tea->v4l2_dev, "can't initialize controls\n");
0566         v4l2_ctrl_handler_free(&tea->ctrl_handler);
0567         return res;
0568     }
0569     v4l2_ctrl_handler_setup(&tea->ctrl_handler);
0570 
0571     res = video_register_device(&tea->vd, VFL_TYPE_RADIO, -1);
0572     if (res) {
0573         v4l2_err(tea->v4l2_dev, "can't register video device!\n");
0574         v4l2_ctrl_handler_free(tea->vd.ctrl_handler);
0575         return res;
0576     }
0577 
0578     return 0;
0579 }
0580 EXPORT_SYMBOL_GPL(radio_tea5777_init);
0581 
0582 void radio_tea5777_exit(struct radio_tea5777 *tea)
0583 {
0584     video_unregister_device(&tea->vd);
0585     v4l2_ctrl_handler_free(tea->vd.ctrl_handler);
0586 }
0587 EXPORT_SYMBOL_GPL(radio_tea5777_exit);