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