linux/drivers/media/radio/tea575x.c
<<
>>
Prefs
   1/*
   2 *   ALSA driver for TEA5757/5759 Philips AM/FM radio tuner chips
   3 *
   4 *      Copyright (c) 2004 Jaroslav Kysela <perex@perex.cz>
   5 *
   6 *
   7 *   This program is free software; you can redistribute it and/or modify
   8 *   it under the terms of the GNU General Public License as published by
   9 *   the Free Software Foundation; either version 2 of the License, or
  10 *   (at your option) any later version.
  11 *
  12 *   This program is distributed in the hope that it will be useful,
  13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 *   GNU General Public License for more details.
  16 *
  17 */
  18
  19#include <linux/delay.h>
  20#include <linux/module.h>
  21#include <linux/init.h>
  22#include <linux/slab.h>
  23#include <linux/sched.h>
  24#include <asm/io.h>
  25#include <media/v4l2-device.h>
  26#include <media/v4l2-dev.h>
  27#include <media/v4l2-fh.h>
  28#include <media/v4l2-ioctl.h>
  29#include <media/v4l2-event.h>
  30#include <media/drv-intf/tea575x.h>
  31
  32MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
  33MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips");
  34MODULE_LICENSE("GPL");
  35
  36/*
  37 * definitions
  38 */
  39
  40#define TEA575X_BIT_SEARCH      (1<<24)         /* 1 = search action, 0 = tuned */
  41#define TEA575X_BIT_UPDOWN      (1<<23)         /* 0 = search down, 1 = search up */
  42#define TEA575X_BIT_MONO        (1<<22)         /* 0 = stereo, 1 = mono */
  43#define TEA575X_BIT_BAND_MASK   (3<<20)
  44#define TEA575X_BIT_BAND_FM     (0<<20)
  45#define TEA575X_BIT_BAND_MW     (1<<20)
  46#define TEA575X_BIT_BAND_LW     (2<<20)
  47#define TEA575X_BIT_BAND_SW     (3<<20)
  48#define TEA575X_BIT_PORT_0      (1<<19)         /* user bit */
  49#define TEA575X_BIT_PORT_1      (1<<18)         /* user bit */
  50#define TEA575X_BIT_SEARCH_MASK (3<<16)         /* search level */
  51#define TEA575X_BIT_SEARCH_5_28      (0<<16)    /* FM >5uV, AM >28uV */
  52#define TEA575X_BIT_SEARCH_10_40     (1<<16)    /* FM >10uV, AM > 40uV */
  53#define TEA575X_BIT_SEARCH_30_63     (2<<16)    /* FM >30uV, AM > 63uV */
  54#define TEA575X_BIT_SEARCH_150_1000  (3<<16)    /* FM > 150uV, AM > 1000uV */
  55#define TEA575X_BIT_DUMMY       (1<<15)         /* buffer */
  56#define TEA575X_BIT_FREQ_MASK   0x7fff
  57
  58enum { BAND_FM, BAND_FM_JAPAN, BAND_AM };
  59
  60static const struct v4l2_frequency_band bands[] = {
  61        {
  62                .type = V4L2_TUNER_RADIO,
  63                .index = 0,
  64                .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
  65                              V4L2_TUNER_CAP_FREQ_BANDS,
  66                .rangelow   =  87500 * 16,
  67                .rangehigh  = 108000 * 16,
  68                .modulation = V4L2_BAND_MODULATION_FM,
  69        },
  70        {
  71                .type = V4L2_TUNER_RADIO,
  72                .index = 0,
  73                .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
  74                              V4L2_TUNER_CAP_FREQ_BANDS,
  75                .rangelow   = 76000 * 16,
  76                .rangehigh  = 91000 * 16,
  77                .modulation = V4L2_BAND_MODULATION_FM,
  78        },
  79        {
  80                .type = V4L2_TUNER_RADIO,
  81                .index = 1,
  82                .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
  83                .rangelow   =  530 * 16,
  84                .rangehigh  = 1710 * 16,
  85                .modulation = V4L2_BAND_MODULATION_AM,
  86        },
  87};
  88
  89/*
  90 * lowlevel part
  91 */
  92
  93static void snd_tea575x_write(struct snd_tea575x *tea, unsigned int val)
  94{
  95        u16 l;
  96        u8 data;
  97
  98        if (tea->ops->write_val)
  99                return tea->ops->write_val(tea, val);
 100
 101        tea->ops->set_direction(tea, 1);
 102        udelay(16);
 103
 104        for (l = 25; l > 0; l--) {
 105                data = (val >> 24) & TEA575X_DATA;
 106                val <<= 1;                      /* shift data */
 107                tea->ops->set_pins(tea, data | TEA575X_WREN);
 108                udelay(2);
 109                tea->ops->set_pins(tea, data | TEA575X_WREN | TEA575X_CLK);
 110                udelay(2);
 111                tea->ops->set_pins(tea, data | TEA575X_WREN);
 112                udelay(2);
 113        }
 114
 115        if (!tea->mute)
 116                tea->ops->set_pins(tea, 0);
 117}
 118
 119static u32 snd_tea575x_read(struct snd_tea575x *tea)
 120{
 121        u16 l, rdata;
 122        u32 data = 0;
 123
 124        if (tea->ops->read_val)
 125                return tea->ops->read_val(tea);
 126
 127        tea->ops->set_direction(tea, 0);
 128        tea->ops->set_pins(tea, 0);
 129        udelay(16);
 130
 131        for (l = 24; l--;) {
 132                tea->ops->set_pins(tea, TEA575X_CLK);
 133                udelay(2);
 134                if (!l)
 135                        tea->tuned = tea->ops->get_pins(tea) & TEA575X_MOST ? 0 : 1;
 136                tea->ops->set_pins(tea, 0);
 137                udelay(2);
 138                data <<= 1;                     /* shift data */
 139                rdata = tea->ops->get_pins(tea);
 140                if (!l)
 141                        tea->stereo = (rdata & TEA575X_MOST) ?  0 : 1;
 142                if (rdata & TEA575X_DATA)
 143                        data++;
 144                udelay(2);
 145        }
 146
 147        if (tea->mute)
 148                tea->ops->set_pins(tea, TEA575X_WREN);
 149
 150        return data;
 151}
 152
 153static u32 snd_tea575x_val_to_freq(struct snd_tea575x *tea, u32 val)
 154{
 155        u32 freq = val & TEA575X_BIT_FREQ_MASK;
 156
 157        if (freq == 0)
 158                return freq;
 159
 160        switch (tea->band) {
 161        case BAND_FM:
 162                /* freq *= 12.5 */
 163                freq *= 125;
 164                freq /= 10;
 165                /* crystal fixup */
 166                freq -= TEA575X_FMIF;
 167                break;
 168        case BAND_FM_JAPAN:
 169                /* freq *= 12.5 */
 170                freq *= 125;
 171                freq /= 10;
 172                /* crystal fixup */
 173                freq += TEA575X_FMIF;
 174                break;
 175        case BAND_AM:
 176                /* crystal fixup */
 177                freq -= TEA575X_AMIF;
 178                break;
 179        }
 180
 181        return clamp(freq * 16, bands[tea->band].rangelow,
 182                                bands[tea->band].rangehigh); /* from kHz */
 183}
 184
 185static u32 snd_tea575x_get_freq(struct snd_tea575x *tea)
 186{
 187        return snd_tea575x_val_to_freq(tea, snd_tea575x_read(tea));
 188}
 189
 190void snd_tea575x_set_freq(struct snd_tea575x *tea)
 191{
 192        u32 freq = tea->freq / 16;      /* to kHz */
 193        u32 band = 0;
 194
 195        switch (tea->band) {
 196        case BAND_FM:
 197                band = TEA575X_BIT_BAND_FM;
 198                /* crystal fixup */
 199                freq += TEA575X_FMIF;
 200                /* freq /= 12.5 */
 201                freq *= 10;
 202                freq /= 125;
 203                break;
 204        case BAND_FM_JAPAN:
 205                band = TEA575X_BIT_BAND_FM;
 206                /* crystal fixup */
 207                freq -= TEA575X_FMIF;
 208                /* freq /= 12.5 */
 209                freq *= 10;
 210                freq /= 125;
 211                break;
 212        case BAND_AM:
 213                band = TEA575X_BIT_BAND_MW;
 214                /* crystal fixup */
 215                freq += TEA575X_AMIF;
 216                break;
 217        }
 218
 219        tea->val &= ~(TEA575X_BIT_FREQ_MASK | TEA575X_BIT_BAND_MASK);
 220        tea->val |= band;
 221        tea->val |= freq & TEA575X_BIT_FREQ_MASK;
 222        snd_tea575x_write(tea, tea->val);
 223        tea->freq = snd_tea575x_val_to_freq(tea, tea->val);
 224}
 225EXPORT_SYMBOL(snd_tea575x_set_freq);
 226
 227/*
 228 * Linux Video interface
 229 */
 230
 231static int vidioc_querycap(struct file *file, void  *priv,
 232                                        struct v4l2_capability *v)
 233{
 234        struct snd_tea575x *tea = video_drvdata(file);
 235
 236        strlcpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver));
 237        strlcpy(v->card, tea->card, sizeof(v->card));
 238        strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card));
 239        strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
 240        v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
 241        if (!tea->cannot_read_data)
 242                v->device_caps |= V4L2_CAP_HW_FREQ_SEEK;
 243        v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
 244        return 0;
 245}
 246
 247int snd_tea575x_enum_freq_bands(struct snd_tea575x *tea,
 248                                        struct v4l2_frequency_band *band)
 249{
 250        int index;
 251
 252        if (band->tuner != 0)
 253                return -EINVAL;
 254
 255        switch (band->index) {
 256        case 0:
 257                if (tea->tea5759)
 258                        index = BAND_FM_JAPAN;
 259                else
 260                        index = BAND_FM;
 261                break;
 262        case 1:
 263                if (tea->has_am) {
 264                        index = BAND_AM;
 265                        break;
 266                }
 267                /* Fall through */
 268        default:
 269                return -EINVAL;
 270        }
 271
 272        *band = bands[index];
 273        if (!tea->cannot_read_data)
 274                band->capability |= V4L2_TUNER_CAP_HWSEEK_BOUNDED;
 275
 276        return 0;
 277}
 278EXPORT_SYMBOL(snd_tea575x_enum_freq_bands);
 279
 280static int vidioc_enum_freq_bands(struct file *file, void *priv,
 281                                         struct v4l2_frequency_band *band)
 282{
 283        struct snd_tea575x *tea = video_drvdata(file);
 284
 285        return snd_tea575x_enum_freq_bands(tea, band);
 286}
 287
 288int snd_tea575x_g_tuner(struct snd_tea575x *tea, struct v4l2_tuner *v)
 289{
 290        struct v4l2_frequency_band band_fm = { 0, };
 291
 292        if (v->index > 0)
 293                return -EINVAL;
 294
 295        snd_tea575x_read(tea);
 296        snd_tea575x_enum_freq_bands(tea, &band_fm);
 297
 298        memset(v, 0, sizeof(*v));
 299        strlcpy(v->name, tea->has_am ? "FM/AM" : "FM", sizeof(v->name));
 300        v->type = V4L2_TUNER_RADIO;
 301        v->capability = band_fm.capability;
 302        v->rangelow = tea->has_am ? bands[BAND_AM].rangelow : band_fm.rangelow;
 303        v->rangehigh = band_fm.rangehigh;
 304        v->rxsubchans = tea->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
 305        v->audmode = (tea->val & TEA575X_BIT_MONO) ?
 306                V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO;
 307        v->signal = tea->tuned ? 0xffff : 0;
 308        return 0;
 309}
 310EXPORT_SYMBOL(snd_tea575x_g_tuner);
 311
 312static int vidioc_g_tuner(struct file *file, void *priv,
 313                                        struct v4l2_tuner *v)
 314{
 315        struct snd_tea575x *tea = video_drvdata(file);
 316
 317        return snd_tea575x_g_tuner(tea, v);
 318}
 319
 320static int vidioc_s_tuner(struct file *file, void *priv,
 321                                        const struct v4l2_tuner *v)
 322{
 323        struct snd_tea575x *tea = video_drvdata(file);
 324        u32 orig_val = tea->val;
 325
 326        if (v->index)
 327                return -EINVAL;
 328        tea->val &= ~TEA575X_BIT_MONO;
 329        if (v->audmode == V4L2_TUNER_MODE_MONO)
 330                tea->val |= TEA575X_BIT_MONO;
 331        /* Only apply changes if currently tuning FM */
 332        if (tea->band != BAND_AM && tea->val != orig_val)
 333                snd_tea575x_set_freq(tea);
 334
 335        return 0;
 336}
 337
 338static int vidioc_g_frequency(struct file *file, void *priv,
 339                                        struct v4l2_frequency *f)
 340{
 341        struct snd_tea575x *tea = video_drvdata(file);
 342
 343        if (f->tuner != 0)
 344                return -EINVAL;
 345        f->type = V4L2_TUNER_RADIO;
 346        f->frequency = tea->freq;
 347        return 0;
 348}
 349
 350static int vidioc_s_frequency(struct file *file, void *priv,
 351                                        const struct v4l2_frequency *f)
 352{
 353        struct snd_tea575x *tea = video_drvdata(file);
 354
 355        if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
 356                return -EINVAL;
 357
 358        if (tea->has_am && f->frequency < (20000 * 16))
 359                tea->band = BAND_AM;
 360        else if (tea->tea5759)
 361                tea->band = BAND_FM_JAPAN;
 362        else
 363                tea->band = BAND_FM;
 364
 365        tea->freq = clamp_t(u32, f->frequency, bands[tea->band].rangelow,
 366                                        bands[tea->band].rangehigh);
 367        snd_tea575x_set_freq(tea);
 368        return 0;
 369}
 370
 371int snd_tea575x_s_hw_freq_seek(struct file *file, struct snd_tea575x *tea,
 372                                const struct v4l2_hw_freq_seek *a)
 373{
 374        unsigned long timeout;
 375        int i, spacing;
 376
 377        if (tea->cannot_read_data)
 378                return -ENOTTY;
 379        if (a->tuner || a->wrap_around)
 380                return -EINVAL;
 381
 382        if (file->f_flags & O_NONBLOCK)
 383                return -EWOULDBLOCK;
 384
 385        if (a->rangelow || a->rangehigh) {
 386                for (i = 0; i < ARRAY_SIZE(bands); i++) {
 387                        if ((i == BAND_FM && tea->tea5759) ||
 388                            (i == BAND_FM_JAPAN && !tea->tea5759) ||
 389                            (i == BAND_AM && !tea->has_am))
 390                                continue;
 391                        if (bands[i].rangelow  == a->rangelow &&
 392                            bands[i].rangehigh == a->rangehigh)
 393                                break;
 394                }
 395                if (i == ARRAY_SIZE(bands))
 396                        return -EINVAL; /* No matching band found */
 397                if (i != tea->band) {
 398                        tea->band = i;
 399                        tea->freq = clamp(tea->freq, bands[i].rangelow,
 400                                                     bands[i].rangehigh);
 401                        snd_tea575x_set_freq(tea);
 402                }
 403        }
 404
 405        spacing = (tea->band == BAND_AM) ? 5 : 50; /* kHz */
 406
 407        /* clear the frequency, HW will fill it in */
 408        tea->val &= ~TEA575X_BIT_FREQ_MASK;
 409        tea->val |= TEA575X_BIT_SEARCH;
 410        if (a->seek_upward)
 411                tea->val |= TEA575X_BIT_UPDOWN;
 412        else
 413                tea->val &= ~TEA575X_BIT_UPDOWN;
 414        snd_tea575x_write(tea, tea->val);
 415        timeout = jiffies + msecs_to_jiffies(10000);
 416        for (;;) {
 417                if (time_after(jiffies, timeout))
 418                        break;
 419                if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
 420                        /* some signal arrived, stop search */
 421                        tea->val &= ~TEA575X_BIT_SEARCH;
 422                        snd_tea575x_set_freq(tea);
 423                        return -ERESTARTSYS;
 424                }
 425                if (!(snd_tea575x_read(tea) & TEA575X_BIT_SEARCH)) {
 426                        u32 freq;
 427
 428                        /* Found a frequency, wait until it can be read */
 429                        for (i = 0; i < 100; i++) {
 430                                msleep(10);
 431                                freq = snd_tea575x_get_freq(tea);
 432                                if (freq) /* available */
 433                                        break;
 434                        }
 435                        if (freq == 0) /* shouldn't happen */
 436                                break;
 437                        /*
 438                         * if we moved by less than the spacing, or in the
 439                         * wrong direction, continue seeking
 440                         */
 441                        if (abs(tea->freq - freq) < 16 * spacing ||
 442                                        (a->seek_upward && freq < tea->freq) ||
 443                                        (!a->seek_upward && freq > tea->freq)) {
 444                                snd_tea575x_write(tea, tea->val);
 445                                continue;
 446                        }
 447                        tea->freq = freq;
 448                        tea->val &= ~TEA575X_BIT_SEARCH;
 449                        return 0;
 450                }
 451        }
 452        tea->val &= ~TEA575X_BIT_SEARCH;
 453        snd_tea575x_set_freq(tea);
 454        return -ENODATA;
 455}
 456EXPORT_SYMBOL(snd_tea575x_s_hw_freq_seek);
 457
 458static int vidioc_s_hw_freq_seek(struct file *file, void *fh,
 459                                        const struct v4l2_hw_freq_seek *a)
 460{
 461        struct snd_tea575x *tea = video_drvdata(file);
 462
 463        return snd_tea575x_s_hw_freq_seek(file, tea, a);
 464}
 465
 466static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl)
 467{
 468        struct snd_tea575x *tea = container_of(ctrl->handler, struct snd_tea575x, ctrl_handler);
 469
 470        switch (ctrl->id) {
 471        case V4L2_CID_AUDIO_MUTE:
 472                tea->mute = ctrl->val;
 473                snd_tea575x_set_freq(tea);
 474                return 0;
 475        }
 476
 477        return -EINVAL;
 478}
 479
 480static const struct v4l2_file_operations tea575x_fops = {
 481        .unlocked_ioctl = video_ioctl2,
 482        .open           = v4l2_fh_open,
 483        .release        = v4l2_fh_release,
 484        .poll           = v4l2_ctrl_poll,
 485};
 486
 487static const struct v4l2_ioctl_ops tea575x_ioctl_ops = {
 488        .vidioc_querycap    = vidioc_querycap,
 489        .vidioc_g_tuner     = vidioc_g_tuner,
 490        .vidioc_s_tuner     = vidioc_s_tuner,
 491        .vidioc_g_frequency = vidioc_g_frequency,
 492        .vidioc_s_frequency = vidioc_s_frequency,
 493        .vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek,
 494        .vidioc_enum_freq_bands = vidioc_enum_freq_bands,
 495        .vidioc_log_status  = v4l2_ctrl_log_status,
 496        .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
 497        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 498};
 499
 500static const struct video_device tea575x_radio = {
 501        .ioctl_ops      = &tea575x_ioctl_ops,
 502        .release        = video_device_release_empty,
 503};
 504
 505static const struct v4l2_ctrl_ops tea575x_ctrl_ops = {
 506        .s_ctrl = tea575x_s_ctrl,
 507};
 508
 509
 510int snd_tea575x_hw_init(struct snd_tea575x *tea)
 511{
 512        tea->mute = true;
 513
 514        /* Not all devices can or know how to read the data back.
 515           Such devices can set cannot_read_data to true. */
 516        if (!tea->cannot_read_data) {
 517                snd_tea575x_write(tea, 0x55AA);
 518                if (snd_tea575x_read(tea) != 0x55AA)
 519                        return -ENODEV;
 520        }
 521
 522        tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_5_28;
 523        tea->freq = 90500 * 16;         /* 90.5Mhz default */
 524        snd_tea575x_set_freq(tea);
 525
 526        return 0;
 527}
 528EXPORT_SYMBOL(snd_tea575x_hw_init);
 529
 530int snd_tea575x_init(struct snd_tea575x *tea, struct module *owner)
 531{
 532        int retval = snd_tea575x_hw_init(tea);
 533
 534        if (retval)
 535                return retval;
 536
 537        tea->vd = tea575x_radio;
 538        video_set_drvdata(&tea->vd, tea);
 539        mutex_init(&tea->mutex);
 540        strlcpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name));
 541        tea->vd.lock = &tea->mutex;
 542        tea->vd.v4l2_dev = tea->v4l2_dev;
 543        tea->fops = tea575x_fops;
 544        tea->fops.owner = owner;
 545        tea->vd.fops = &tea->fops;
 546        /* disable hw_freq_seek if we can't use it */
 547        if (tea->cannot_read_data)
 548                v4l2_disable_ioctl(&tea->vd, VIDIOC_S_HW_FREQ_SEEK);
 549
 550        if (!tea->cannot_mute) {
 551                tea->vd.ctrl_handler = &tea->ctrl_handler;
 552                v4l2_ctrl_handler_init(&tea->ctrl_handler, 1);
 553                v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops,
 554                                  V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
 555                retval = tea->ctrl_handler.error;
 556                if (retval) {
 557                        v4l2_err(tea->v4l2_dev, "can't initialize controls\n");
 558                        v4l2_ctrl_handler_free(&tea->ctrl_handler);
 559                        return retval;
 560                }
 561
 562                if (tea->ext_init) {
 563                        retval = tea->ext_init(tea);
 564                        if (retval) {
 565                                v4l2_ctrl_handler_free(&tea->ctrl_handler);
 566                                return retval;
 567                        }
 568                }
 569
 570                v4l2_ctrl_handler_setup(&tea->ctrl_handler);
 571        }
 572
 573        retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, tea->radio_nr);
 574        if (retval) {
 575                v4l2_err(tea->v4l2_dev, "can't register video device!\n");
 576                v4l2_ctrl_handler_free(tea->vd.ctrl_handler);
 577                return retval;
 578        }
 579
 580        return 0;
 581}
 582EXPORT_SYMBOL(snd_tea575x_init);
 583
 584void snd_tea575x_exit(struct snd_tea575x *tea)
 585{
 586        video_unregister_device(&tea->vd);
 587        v4l2_ctrl_handler_free(tea->vd.ctrl_handler);
 588}
 589EXPORT_SYMBOL(snd_tea575x_exit);
 590