1 /* 2 * FM Driver for Connectivity chip of Texas Instruments. 3 * This file provides interfaces to V4L2 subsystem. 4 * 5 * This module registers with V4L2 subsystem as Radio 6 * data system interface (/dev/radio). During the registration, 7 * it will expose two set of function pointers. 8 * 9 * 1) File operation related API (open, close, read, write, poll...etc). 10 * 2) Set of V4L2 IOCTL complaint API. 11 * 12 * Copyright (C) 2011 Texas Instruments 13 * Author: Raja Mani <raja_mani@ti.com> 14 * Author: Manjunatha Halli <manjunatha_halli@ti.com> 15 * 16 * This program is free software; you can redistribute it and/or modify 17 * it under the terms of the GNU General Public License version 2 as 18 * published by the Free Software Foundation. 19 * 20 * This program is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * GNU General Public License for more details. 24 * 25 */ 26 27 #include <linux/export.h> 28 29 #include "fmdrv.h" 30 #include "fmdrv_v4l2.h" 31 #include "fmdrv_common.h" 32 #include "fmdrv_rx.h" 33 #include "fmdrv_tx.h" 34 35 static struct video_device gradio_dev; 36 static u8 radio_disconnected; 37 38 /* -- V4L2 RADIO (/dev/radioX) device file operation interfaces --- */ 39 40 /* Read RX RDS data */ 41 static ssize_t fm_v4l2_fops_read(struct file *file, char __user * buf, 42 size_t count, loff_t *ppos) 43 { 44 u8 rds_mode; 45 int ret; 46 struct fmdev *fmdev; 47 48 fmdev = video_drvdata(file); 49 50 if (!radio_disconnected) { 51 fmerr("FM device is already disconnected\n"); 52 return -EIO; 53 } 54 55 if (mutex_lock_interruptible(&fmdev->mutex)) 56 return -ERESTARTSYS; 57 58 /* Turn on RDS mode if it is disabled */ 59 ret = fm_rx_get_rds_mode(fmdev, &rds_mode); 60 if (ret < 0) { 61 fmerr("Unable to read current rds mode\n"); 62 goto read_unlock; 63 } 64 65 if (rds_mode == FM_RDS_DISABLE) { 66 ret = fmc_set_rds_mode(fmdev, FM_RDS_ENABLE); 67 if (ret < 0) { 68 fmerr("Failed to enable rds mode\n"); 69 goto read_unlock; 70 } 71 } 72 73 /* Copy RDS data from internal buffer to user buffer */ 74 ret = fmc_transfer_rds_from_internal_buff(fmdev, file, buf, count); 75 read_unlock: 76 mutex_unlock(&fmdev->mutex); 77 return ret; 78 } 79 80 /* Write TX RDS data */ 81 static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf, 82 size_t count, loff_t *ppos) 83 { 84 struct tx_rds rds; 85 int ret; 86 struct fmdev *fmdev; 87 88 ret = copy_from_user(&rds, buf, sizeof(rds)); 89 rds.text[sizeof(rds.text) - 1] = '\0'; 90 fmdbg("(%d)type: %d, text %s, af %d\n", 91 ret, rds.text_type, rds.text, rds.af_freq); 92 if (ret) 93 return -EFAULT; 94 95 fmdev = video_drvdata(file); 96 if (mutex_lock_interruptible(&fmdev->mutex)) 97 return -ERESTARTSYS; 98 fm_tx_set_radio_text(fmdev, rds.text, rds.text_type); 99 fm_tx_set_af(fmdev, rds.af_freq); 100 mutex_unlock(&fmdev->mutex); 101 102 return sizeof(rds); 103 } 104 105 static __poll_t fm_v4l2_fops_poll(struct file *file, struct poll_table_struct *pts) 106 { 107 int ret; 108 struct fmdev *fmdev; 109 110 fmdev = video_drvdata(file); 111 mutex_lock(&fmdev->mutex); 112 ret = fmc_is_rds_data_available(fmdev, file, pts); 113 mutex_unlock(&fmdev->mutex); 114 if (ret < 0) 115 return EPOLLIN | EPOLLRDNORM; 116 117 return 0; 118 } 119 120 /* 121 * Handle open request for "/dev/radioX" device. 122 * Start with FM RX mode as default. 123 */ 124 static int fm_v4l2_fops_open(struct file *file) 125 { 126 int ret; 127 struct fmdev *fmdev = NULL; 128 129 /* Don't allow multiple open */ 130 if (radio_disconnected) { 131 fmerr("FM device is already opened\n"); 132 return -EBUSY; 133 } 134 135 fmdev = video_drvdata(file); 136 137 if (mutex_lock_interruptible(&fmdev->mutex)) 138 return -ERESTARTSYS; 139 ret = fmc_prepare(fmdev); 140 if (ret < 0) { 141 fmerr("Unable to prepare FM CORE\n"); 142 goto open_unlock; 143 } 144 145 fmdbg("Load FM RX firmware..\n"); 146 147 ret = fmc_set_mode(fmdev, FM_MODE_RX); 148 if (ret < 0) { 149 fmerr("Unable to load FM RX firmware\n"); 150 goto open_unlock; 151 } 152 radio_disconnected = 1; 153 154 open_unlock: 155 mutex_unlock(&fmdev->mutex); 156 return ret; 157 } 158 159 static int fm_v4l2_fops_release(struct file *file) 160 { 161 int ret; 162 struct fmdev *fmdev; 163 164 fmdev = video_drvdata(file); 165 if (!radio_disconnected) { 166 fmdbg("FM device is already closed\n"); 167 return 0; 168 } 169 170 mutex_lock(&fmdev->mutex); 171 ret = fmc_set_mode(fmdev, FM_MODE_OFF); 172 if (ret < 0) { 173 fmerr("Unable to turn off the chip\n"); 174 goto release_unlock; 175 } 176 177 ret = fmc_release(fmdev); 178 if (ret < 0) { 179 fmerr("FM CORE release failed\n"); 180 goto release_unlock; 181 } 182 radio_disconnected = 0; 183 184 release_unlock: 185 mutex_unlock(&fmdev->mutex); 186 return ret; 187 } 188 189 /* V4L2 RADIO (/dev/radioX) device IOCTL interfaces */ 190 static int fm_v4l2_vidioc_querycap(struct file *file, void *priv, 191 struct v4l2_capability *capability) 192 { 193 strlcpy(capability->driver, FM_DRV_NAME, sizeof(capability->driver)); 194 strlcpy(capability->card, FM_DRV_CARD_SHORT_NAME, 195 sizeof(capability->card)); 196 sprintf(capability->bus_info, "UART"); 197 capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | 198 V4L2_CAP_RADIO | V4L2_CAP_MODULATOR | 199 V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | 200 V4L2_CAP_RDS_CAPTURE; 201 capability->capabilities = capability->device_caps | 202 V4L2_CAP_DEVICE_CAPS; 203 204 return 0; 205 } 206 207 static int fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl) 208 { 209 struct fmdev *fmdev = container_of(ctrl->handler, 210 struct fmdev, ctrl_handler); 211 212 switch (ctrl->id) { 213 case V4L2_CID_TUNE_ANTENNA_CAPACITOR: 214 ctrl->val = fm_tx_get_tune_cap_val(fmdev); 215 break; 216 default: 217 fmwarn("%s: Unknown IOCTL: %d\n", __func__, ctrl->id); 218 break; 219 } 220 221 return 0; 222 } 223 224 static int fm_v4l2_s_ctrl(struct v4l2_ctrl *ctrl) 225 { 226 struct fmdev *fmdev = container_of(ctrl->handler, 227 struct fmdev, ctrl_handler); 228 229 switch (ctrl->id) { 230 case V4L2_CID_AUDIO_VOLUME: /* set volume */ 231 return fm_rx_set_volume(fmdev, (u16)ctrl->val); 232 233 case V4L2_CID_AUDIO_MUTE: /* set mute */ 234 return fmc_set_mute_mode(fmdev, (u8)ctrl->val); 235 236 case V4L2_CID_TUNE_POWER_LEVEL: 237 /* set TX power level - ext control */ 238 return fm_tx_set_pwr_lvl(fmdev, (u8)ctrl->val); 239 240 case V4L2_CID_TUNE_PREEMPHASIS: 241 return fm_tx_set_preemph_filter(fmdev, (u8) ctrl->val); 242 243 default: 244 return -EINVAL; 245 } 246 } 247 248 static int fm_v4l2_vidioc_g_audio(struct file *file, void *priv, 249 struct v4l2_audio *audio) 250 { 251 memset(audio, 0, sizeof(*audio)); 252 strcpy(audio->name, "Radio"); 253 audio->capability = V4L2_AUDCAP_STEREO; 254 255 return 0; 256 } 257 258 static int fm_v4l2_vidioc_s_audio(struct file *file, void *priv, 259 const struct v4l2_audio *audio) 260 { 261 if (audio->index != 0) 262 return -EINVAL; 263 264 return 0; 265 } 266 267 /* Get tuner attributes. If current mode is NOT RX, return error */ 268 static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv, 269 struct v4l2_tuner *tuner) 270 { 271 struct fmdev *fmdev = video_drvdata(file); 272 u32 bottom_freq; 273 u32 top_freq; 274 u16 stereo_mono_mode; 275 u16 rssilvl; 276 int ret; 277 278 if (tuner->index != 0) 279 return -EINVAL; 280 281 if (fmdev->curr_fmmode != FM_MODE_RX) 282 return -EPERM; 283 284 ret = fm_rx_get_band_freq_range(fmdev, &bottom_freq, &top_freq); 285 if (ret != 0) 286 return ret; 287 288 ret = fm_rx_get_stereo_mono(fmdev, &stereo_mono_mode); 289 if (ret != 0) 290 return ret; 291 292 ret = fm_rx_get_rssi_level(fmdev, &rssilvl); 293 if (ret != 0) 294 return ret; 295 296 strcpy(tuner->name, "FM"); 297 tuner->type = V4L2_TUNER_RADIO; 298 /* Store rangelow and rangehigh freq in unit of 62.5 Hz */ 299 tuner->rangelow = bottom_freq * 16; 300 tuner->rangehigh = top_freq * 16; 301 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO | 302 ((fmdev->rx.rds.flag == FM_RDS_ENABLE) ? V4L2_TUNER_SUB_RDS : 0); 303 tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | 304 V4L2_TUNER_CAP_LOW | 305 V4L2_TUNER_CAP_HWSEEK_BOUNDED | 306 V4L2_TUNER_CAP_HWSEEK_WRAP; 307 tuner->audmode = (stereo_mono_mode ? 308 V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO); 309 310 /* 311 * Actual rssi value lies in between -128 to +127. 312 * Convert this range from 0 to 255 by adding +128 313 */ 314 rssilvl += 128; 315 316 /* 317 * Return signal strength value should be within 0 to 65535. 318 * Find out correct signal radio by multiplying (65535/255) = 257 319 */ 320 tuner->signal = rssilvl * 257; 321 tuner->afc = 0; 322 323 return ret; 324 } 325 326 /* 327 * Set tuner attributes. If current mode is NOT RX, set to RX. 328 * Currently, we set only audio mode (mono/stereo) and RDS state (on/off). 329 * Should we set other tuner attributes, too? 330 */ 331 static int fm_v4l2_vidioc_s_tuner(struct file *file, void *priv, 332 const struct v4l2_tuner *tuner) 333 { 334 struct fmdev *fmdev = video_drvdata(file); 335 u16 aud_mode; 336 u8 rds_mode; 337 int ret; 338 339 if (tuner->index != 0) 340 return -EINVAL; 341 342 aud_mode = (tuner->audmode == V4L2_TUNER_MODE_STEREO) ? 343 FM_STEREO_MODE : FM_MONO_MODE; 344 rds_mode = (tuner->rxsubchans & V4L2_TUNER_SUB_RDS) ? 345 FM_RDS_ENABLE : FM_RDS_DISABLE; 346 347 if (fmdev->curr_fmmode != FM_MODE_RX) { 348 ret = fmc_set_mode(fmdev, FM_MODE_RX); 349 if (ret < 0) { 350 fmerr("Failed to set RX mode\n"); 351 return ret; 352 } 353 } 354 355 ret = fmc_set_stereo_mono(fmdev, aud_mode); 356 if (ret < 0) { 357 fmerr("Failed to set RX stereo/mono mode\n"); 358 return ret; 359 } 360 361 ret = fmc_set_rds_mode(fmdev, rds_mode); 362 if (ret < 0) 363 fmerr("Failed to set RX RDS mode\n"); 364 365 return ret; 366 } 367 368 /* Get tuner or modulator radio frequency */ 369 static int fm_v4l2_vidioc_g_freq(struct file *file, void *priv, 370 struct v4l2_frequency *freq) 371 { 372 struct fmdev *fmdev = video_drvdata(file); 373 int ret; 374 375 ret = fmc_get_freq(fmdev, &freq->frequency); 376 if (ret < 0) { 377 fmerr("Failed to get frequency\n"); 378 return ret; 379 } 380 381 /* Frequency unit of 62.5 Hz*/ 382 freq->frequency = (u32) freq->frequency * 16; 383 384 return 0; 385 } 386 387 /* Set tuner or modulator radio frequency */ 388 static int fm_v4l2_vidioc_s_freq(struct file *file, void *priv, 389 const struct v4l2_frequency *freq) 390 { 391 struct fmdev *fmdev = video_drvdata(file); 392 393 /* 394 * As V4L2_TUNER_CAP_LOW is set 1 user sends the frequency 395 * in units of 62.5 Hz. 396 */ 397 return fmc_set_freq(fmdev, freq->frequency / 16); 398 } 399 400 /* Set hardware frequency seek. If current mode is NOT RX, set it RX. */ 401 static int fm_v4l2_vidioc_s_hw_freq_seek(struct file *file, void *priv, 402 const struct v4l2_hw_freq_seek *seek) 403 { 404 struct fmdev *fmdev = video_drvdata(file); 405 int ret; 406 407 if (file->f_flags & O_NONBLOCK) 408 return -EWOULDBLOCK; 409 410 if (fmdev->curr_fmmode != FM_MODE_RX) { 411 ret = fmc_set_mode(fmdev, FM_MODE_RX); 412 if (ret != 0) { 413 fmerr("Failed to set RX mode\n"); 414 return ret; 415 } 416 } 417 418 ret = fm_rx_seek(fmdev, seek->seek_upward, seek->wrap_around, 419 seek->spacing); 420 if (ret < 0) 421 fmerr("RX seek failed - %d\n", ret); 422 423 return ret; 424 } 425 /* Get modulator attributes. If mode is not TX, return no attributes. */ 426 static int fm_v4l2_vidioc_g_modulator(struct file *file, void *priv, 427 struct v4l2_modulator *mod) 428 { 429 struct fmdev *fmdev = video_drvdata(file); 430 431 if (mod->index != 0) 432 return -EINVAL; 433 434 if (fmdev->curr_fmmode != FM_MODE_TX) 435 return -EPERM; 436 437 mod->txsubchans = ((fmdev->tx_data.aud_mode == FM_STEREO_MODE) ? 438 V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO) | 439 ((fmdev->tx_data.rds.flag == FM_RDS_ENABLE) ? 440 V4L2_TUNER_SUB_RDS : 0); 441 442 mod->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | 443 V4L2_TUNER_CAP_LOW; 444 445 return 0; 446 } 447 448 /* Set modulator attributes. If mode is not TX, set to TX. */ 449 static int fm_v4l2_vidioc_s_modulator(struct file *file, void *priv, 450 const struct v4l2_modulator *mod) 451 { 452 struct fmdev *fmdev = video_drvdata(file); 453 u8 rds_mode; 454 u16 aud_mode; 455 int ret; 456 457 if (mod->index != 0) 458 return -EINVAL; 459 460 if (fmdev->curr_fmmode != FM_MODE_TX) { 461 ret = fmc_set_mode(fmdev, FM_MODE_TX); 462 if (ret != 0) { 463 fmerr("Failed to set TX mode\n"); 464 return ret; 465 } 466 } 467 468 aud_mode = (mod->txsubchans & V4L2_TUNER_SUB_STEREO) ? 469 FM_STEREO_MODE : FM_MONO_MODE; 470 rds_mode = (mod->txsubchans & V4L2_TUNER_SUB_RDS) ? 471 FM_RDS_ENABLE : FM_RDS_DISABLE; 472 ret = fm_tx_set_stereo_mono(fmdev, aud_mode); 473 if (ret < 0) { 474 fmerr("Failed to set mono/stereo mode for TX\n"); 475 return ret; 476 } 477 ret = fm_tx_set_rds_mode(fmdev, rds_mode); 478 if (ret < 0) 479 fmerr("Failed to set rds mode for TX\n"); 480 481 return ret; 482 } 483 484 static const struct v4l2_file_operations fm_drv_fops = { 485 .owner = THIS_MODULE, 486 .read = fm_v4l2_fops_read, 487 .write = fm_v4l2_fops_write, 488 .poll = fm_v4l2_fops_poll, 489 .unlocked_ioctl = video_ioctl2, 490 .open = fm_v4l2_fops_open, 491 .release = fm_v4l2_fops_release, 492 }; 493 494 static const struct v4l2_ctrl_ops fm_ctrl_ops = { 495 .s_ctrl = fm_v4l2_s_ctrl, 496 .g_volatile_ctrl = fm_g_volatile_ctrl, 497 }; 498 static const struct v4l2_ioctl_ops fm_drv_ioctl_ops = { 499 .vidioc_querycap = fm_v4l2_vidioc_querycap, 500 .vidioc_g_audio = fm_v4l2_vidioc_g_audio, 501 .vidioc_s_audio = fm_v4l2_vidioc_s_audio, 502 .vidioc_g_tuner = fm_v4l2_vidioc_g_tuner, 503 .vidioc_s_tuner = fm_v4l2_vidioc_s_tuner, 504 .vidioc_g_frequency = fm_v4l2_vidioc_g_freq, 505 .vidioc_s_frequency = fm_v4l2_vidioc_s_freq, 506 .vidioc_s_hw_freq_seek = fm_v4l2_vidioc_s_hw_freq_seek, 507 .vidioc_g_modulator = fm_v4l2_vidioc_g_modulator, 508 .vidioc_s_modulator = fm_v4l2_vidioc_s_modulator 509 }; 510 511 /* V4L2 RADIO device parent structure */ 512 static const struct video_device fm_viddev_template = { 513 .fops = &fm_drv_fops, 514 .ioctl_ops = &fm_drv_ioctl_ops, 515 .name = FM_DRV_NAME, 516 .release = video_device_release_empty, 517 /* 518 * To ensure both the tuner and modulator ioctls are accessible we 519 * set the vfl_dir to M2M to indicate this. 520 * 521 * It is not really a mem2mem device of course, but it can both receive 522 * and transmit using the same radio device. It's the only radio driver 523 * that does this and it should really be split in two radio devices, 524 * but that would affect applications using this driver. 525 */ 526 .vfl_dir = VFL_DIR_M2M, 527 }; 528 529 int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) 530 { 531 struct v4l2_ctrl *ctrl; 532 int ret; 533 534 strlcpy(fmdev->v4l2_dev.name, FM_DRV_NAME, sizeof(fmdev->v4l2_dev.name)); 535 ret = v4l2_device_register(NULL, &fmdev->v4l2_dev); 536 if (ret < 0) 537 return ret; 538 539 /* Init mutex for core locking */ 540 mutex_init(&fmdev->mutex); 541 542 /* Setup FM driver's V4L2 properties */ 543 gradio_dev = fm_viddev_template; 544 545 video_set_drvdata(&gradio_dev, fmdev); 546 547 gradio_dev.lock = &fmdev->mutex; 548 gradio_dev.v4l2_dev = &fmdev->v4l2_dev; 549 550 /* Register with V4L2 subsystem as RADIO device */ 551 if (video_register_device(&gradio_dev, VFL_TYPE_RADIO, radio_nr)) { 552 fmerr("Could not register video device\n"); 553 return -ENOMEM; 554 } 555 556 fmdev->radio_dev = &gradio_dev; 557 558 /* Register to v4l2 ctrl handler framework */ 559 fmdev->radio_dev->ctrl_handler = &fmdev->ctrl_handler; 560 561 ret = v4l2_ctrl_handler_init(&fmdev->ctrl_handler, 5); 562 if (ret < 0) { 563 fmerr("(fmdev): Can't init ctrl handler\n"); 564 v4l2_ctrl_handler_free(&fmdev->ctrl_handler); 565 return -EBUSY; 566 } 567 568 /* 569 * Following controls are handled by V4L2 control framework. 570 * Added in ascending ID order. 571 */ 572 v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops, 573 V4L2_CID_AUDIO_VOLUME, FM_RX_VOLUME_MIN, 574 FM_RX_VOLUME_MAX, 1, FM_RX_VOLUME_MAX); 575 576 v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops, 577 V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); 578 579 v4l2_ctrl_new_std_menu(&fmdev->ctrl_handler, &fm_ctrl_ops, 580 V4L2_CID_TUNE_PREEMPHASIS, V4L2_PREEMPHASIS_75_uS, 581 0, V4L2_PREEMPHASIS_75_uS); 582 583 v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops, 584 V4L2_CID_TUNE_POWER_LEVEL, FM_PWR_LVL_LOW, 585 FM_PWR_LVL_HIGH, 1, FM_PWR_LVL_HIGH); 586 587 ctrl = v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops, 588 V4L2_CID_TUNE_ANTENNA_CAPACITOR, 0, 589 255, 1, 255); 590 591 if (ctrl) 592 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; 593 594 return 0; 595 } 596 597 void *fm_v4l2_deinit_video_device(void) 598 { 599 struct fmdev *fmdev; 600 601 602 fmdev = video_get_drvdata(&gradio_dev); 603 604 /* Unregister to v4l2 ctrl handler framework*/ 605 v4l2_ctrl_handler_free(&fmdev->ctrl_handler); 606 607 /* Unregister RADIO device from V4L2 subsystem */ 608 video_unregister_device(&gradio_dev); 609 610 v4l2_device_unregister(&fmdev->v4l2_dev); 611 612 return fmdev; 613 } 614