1 /* 2 * drivers/media/radio/radio-si476x.c -- V4L2 driver for SI476X chips 3 * 4 * Copyright (C) 2012 Innovative Converged Devices(ICD) 5 * Copyright (C) 2013 Andrey Smirnov 6 * 7 * Author: Andrey Smirnov <andrew.smirnov@gmail.com> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; version 2 of the License. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 * 18 */ 19 20 #include <linux/module.h> 21 #include <linux/delay.h> 22 #include <linux/interrupt.h> 23 #include <linux/slab.h> 24 #include <linux/atomic.h> 25 #include <linux/videodev2.h> 26 #include <linux/mutex.h> 27 #include <linux/debugfs.h> 28 #include <media/v4l2-common.h> 29 #include <media/v4l2-ioctl.h> 30 #include <media/v4l2-ctrls.h> 31 #include <media/v4l2-event.h> 32 #include <media/v4l2-device.h> 33 34 #include <media/drv-intf/si476x.h> 35 #include <linux/mfd/si476x-core.h> 36 37 #define FM_FREQ_RANGE_LOW 64000000 38 #define FM_FREQ_RANGE_HIGH 108000000 39 40 #define AM_FREQ_RANGE_LOW 520000 41 #define AM_FREQ_RANGE_HIGH 30000000 42 43 #define PWRLINEFLTR (1 << 8) 44 45 #define FREQ_MUL (10000000 / 625) 46 47 #define SI476X_PHDIV_STATUS_LINK_LOCKED(status) (0x80 & (status)) 48 49 #define DRIVER_NAME "si476x-radio" 50 #define DRIVER_CARD "SI476x AM/FM Receiver" 51 52 enum si476x_freq_bands { 53 SI476X_BAND_FM, 54 SI476X_BAND_AM, 55 }; 56 57 static const struct v4l2_frequency_band si476x_bands[] = { 58 [SI476X_BAND_FM] = { 59 .type = V4L2_TUNER_RADIO, 60 .index = SI476X_BAND_FM, 61 .capability = V4L2_TUNER_CAP_LOW 62 | V4L2_TUNER_CAP_STEREO 63 | V4L2_TUNER_CAP_RDS 64 | V4L2_TUNER_CAP_RDS_BLOCK_IO 65 | V4L2_TUNER_CAP_FREQ_BANDS, 66 .rangelow = 64 * FREQ_MUL, 67 .rangehigh = 108 * FREQ_MUL, 68 .modulation = V4L2_BAND_MODULATION_FM, 69 }, 70 [SI476X_BAND_AM] = { 71 .type = V4L2_TUNER_RADIO, 72 .index = SI476X_BAND_AM, 73 .capability = V4L2_TUNER_CAP_LOW 74 | V4L2_TUNER_CAP_FREQ_BANDS, 75 .rangelow = 0.52 * FREQ_MUL, 76 .rangehigh = 30 * FREQ_MUL, 77 .modulation = V4L2_BAND_MODULATION_AM, 78 }, 79 }; 80 81 static inline bool si476x_radio_freq_is_inside_of_the_band(u32 freq, int band) 82 { 83 return freq >= si476x_bands[band].rangelow && 84 freq <= si476x_bands[band].rangehigh; 85 } 86 87 static inline bool si476x_radio_range_is_inside_of_the_band(u32 low, u32 high, 88 int band) 89 { 90 return low >= si476x_bands[band].rangelow && 91 high <= si476x_bands[band].rangehigh; 92 } 93 94 static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl); 95 static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl); 96 97 enum phase_diversity_modes_idx { 98 SI476X_IDX_PHDIV_DISABLED, 99 SI476X_IDX_PHDIV_PRIMARY_COMBINING, 100 SI476X_IDX_PHDIV_PRIMARY_ANTENNA, 101 SI476X_IDX_PHDIV_SECONDARY_ANTENNA, 102 SI476X_IDX_PHDIV_SECONDARY_COMBINING, 103 }; 104 105 static const char * const phase_diversity_modes[] = { 106 [SI476X_IDX_PHDIV_DISABLED] = "Disabled", 107 [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = "Primary with Secondary", 108 [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = "Primary Antenna", 109 [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = "Secondary Antenna", 110 [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = "Secondary with Primary", 111 }; 112 113 static inline enum phase_diversity_modes_idx 114 si476x_phase_diversity_mode_to_idx(enum si476x_phase_diversity_mode mode) 115 { 116 switch (mode) { 117 default: /* FALLTHROUGH */ 118 case SI476X_PHDIV_DISABLED: 119 return SI476X_IDX_PHDIV_DISABLED; 120 case SI476X_PHDIV_PRIMARY_COMBINING: 121 return SI476X_IDX_PHDIV_PRIMARY_COMBINING; 122 case SI476X_PHDIV_PRIMARY_ANTENNA: 123 return SI476X_IDX_PHDIV_PRIMARY_ANTENNA; 124 case SI476X_PHDIV_SECONDARY_ANTENNA: 125 return SI476X_IDX_PHDIV_SECONDARY_ANTENNA; 126 case SI476X_PHDIV_SECONDARY_COMBINING: 127 return SI476X_IDX_PHDIV_SECONDARY_COMBINING; 128 } 129 } 130 131 static inline enum si476x_phase_diversity_mode 132 si476x_phase_diversity_idx_to_mode(enum phase_diversity_modes_idx idx) 133 { 134 static const int idx_to_value[] = { 135 [SI476X_IDX_PHDIV_DISABLED] = SI476X_PHDIV_DISABLED, 136 [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = SI476X_PHDIV_PRIMARY_COMBINING, 137 [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = SI476X_PHDIV_PRIMARY_ANTENNA, 138 [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = SI476X_PHDIV_SECONDARY_ANTENNA, 139 [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = SI476X_PHDIV_SECONDARY_COMBINING, 140 }; 141 142 return idx_to_value[idx]; 143 } 144 145 static const struct v4l2_ctrl_ops si476x_ctrl_ops = { 146 .g_volatile_ctrl = si476x_radio_g_volatile_ctrl, 147 .s_ctrl = si476x_radio_s_ctrl, 148 }; 149 150 151 enum si476x_ctrl_idx { 152 SI476X_IDX_RSSI_THRESHOLD, 153 SI476X_IDX_SNR_THRESHOLD, 154 SI476X_IDX_MAX_TUNE_ERROR, 155 SI476X_IDX_HARMONICS_COUNT, 156 SI476X_IDX_DIVERSITY_MODE, 157 SI476X_IDX_INTERCHIP_LINK, 158 }; 159 static struct v4l2_ctrl_config si476x_ctrls[] = { 160 161 /* 162 * SI476X during its station seeking(or tuning) process uses several 163 * parameters to detrmine if "the station" is valid: 164 * 165 * - Signal's SNR(in dBuV) must be lower than 166 * #V4L2_CID_SI476X_SNR_THRESHOLD 167 * - Signal's RSSI(in dBuV) must be greater than 168 * #V4L2_CID_SI476X_RSSI_THRESHOLD 169 * - Signal's frequency deviation(in units of 2ppm) must not be 170 * more than #V4L2_CID_SI476X_MAX_TUNE_ERROR 171 */ 172 [SI476X_IDX_RSSI_THRESHOLD] = { 173 .ops = &si476x_ctrl_ops, 174 .id = V4L2_CID_SI476X_RSSI_THRESHOLD, 175 .name = "Valid RSSI Threshold", 176 .type = V4L2_CTRL_TYPE_INTEGER, 177 .min = -128, 178 .max = 127, 179 .step = 1, 180 }, 181 [SI476X_IDX_SNR_THRESHOLD] = { 182 .ops = &si476x_ctrl_ops, 183 .id = V4L2_CID_SI476X_SNR_THRESHOLD, 184 .type = V4L2_CTRL_TYPE_INTEGER, 185 .name = "Valid SNR Threshold", 186 .min = -128, 187 .max = 127, 188 .step = 1, 189 }, 190 [SI476X_IDX_MAX_TUNE_ERROR] = { 191 .ops = &si476x_ctrl_ops, 192 .id = V4L2_CID_SI476X_MAX_TUNE_ERROR, 193 .type = V4L2_CTRL_TYPE_INTEGER, 194 .name = "Max Tune Errors", 195 .min = 0, 196 .max = 126 * 2, 197 .step = 2, 198 }, 199 200 /* 201 * #V4L2_CID_SI476X_HARMONICS_COUNT -- number of harmonics 202 * built-in power-line noise supression filter is to reject 203 * during AM-mode operation. 204 */ 205 [SI476X_IDX_HARMONICS_COUNT] = { 206 .ops = &si476x_ctrl_ops, 207 .id = V4L2_CID_SI476X_HARMONICS_COUNT, 208 .type = V4L2_CTRL_TYPE_INTEGER, 209 210 .name = "Count of Harmonics to Reject", 211 .min = 0, 212 .max = 20, 213 .step = 1, 214 }, 215 216 /* 217 * #V4L2_CID_SI476X_DIVERSITY_MODE -- configuration which 218 * two tuners working in diversity mode are to work in. 219 * 220 * - #SI476X_IDX_PHDIV_DISABLED diversity mode disabled 221 * - #SI476X_IDX_PHDIV_PRIMARY_COMBINING diversity mode is 222 * on, primary tuner's antenna is the main one. 223 * - #SI476X_IDX_PHDIV_PRIMARY_ANTENNA diversity mode is 224 * off, primary tuner's antenna is the main one. 225 * - #SI476X_IDX_PHDIV_SECONDARY_ANTENNA diversity mode is 226 * off, secondary tuner's antenna is the main one. 227 * - #SI476X_IDX_PHDIV_SECONDARY_COMBINING diversity mode is 228 * on, secondary tuner's antenna is the main one. 229 */ 230 [SI476X_IDX_DIVERSITY_MODE] = { 231 .ops = &si476x_ctrl_ops, 232 .id = V4L2_CID_SI476X_DIVERSITY_MODE, 233 .type = V4L2_CTRL_TYPE_MENU, 234 .name = "Phase Diversity Mode", 235 .qmenu = phase_diversity_modes, 236 .min = 0, 237 .max = ARRAY_SIZE(phase_diversity_modes) - 1, 238 }, 239 240 /* 241 * #V4L2_CID_SI476X_INTERCHIP_LINK -- inter-chip link in 242 * diversity mode indicator. Allows user to determine if two 243 * chips working in diversity mode have established a link 244 * between each other and if the system as a whole uses 245 * signals from both antennas to receive FM radio. 246 */ 247 [SI476X_IDX_INTERCHIP_LINK] = { 248 .ops = &si476x_ctrl_ops, 249 .id = V4L2_CID_SI476X_INTERCHIP_LINK, 250 .type = V4L2_CTRL_TYPE_BOOLEAN, 251 .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE, 252 .name = "Inter-Chip Link", 253 .min = 0, 254 .max = 1, 255 .step = 1, 256 }, 257 }; 258 259 struct si476x_radio; 260 261 /** 262 * struct si476x_radio_ops - vtable of tuner functions 263 * 264 * This table holds pointers to functions implementing particular 265 * operations depending on the mode in which the tuner chip was 266 * configured to start in. If the function is not supported 267 * corresponding element is set to #NULL. 268 * 269 * @tune_freq: Tune chip to a specific frequency 270 * @seek_start: Star station seeking 271 * @rsq_status: Get Received Signal Quality(RSQ) status 272 * @rds_blckcnt: Get received RDS blocks count 273 * @phase_diversity: Change phase diversity mode of the tuner 274 * @phase_div_status: Get phase diversity mode status 275 * @acf_status: Get the status of Automatically Controlled 276 * Features(ACF) 277 * @agc_status: Get Automatic Gain Control(AGC) status 278 */ 279 struct si476x_radio_ops { 280 int (*tune_freq)(struct si476x_core *, struct si476x_tune_freq_args *); 281 int (*seek_start)(struct si476x_core *, bool, bool); 282 int (*rsq_status)(struct si476x_core *, struct si476x_rsq_status_args *, 283 struct si476x_rsq_status_report *); 284 int (*rds_blckcnt)(struct si476x_core *, bool, 285 struct si476x_rds_blockcount_report *); 286 287 int (*phase_diversity)(struct si476x_core *, 288 enum si476x_phase_diversity_mode); 289 int (*phase_div_status)(struct si476x_core *); 290 int (*acf_status)(struct si476x_core *, 291 struct si476x_acf_status_report *); 292 int (*agc_status)(struct si476x_core *, 293 struct si476x_agc_status_report *); 294 }; 295 296 /** 297 * struct si476x_radio - radio device 298 * 299 * @v4l2dev: Pointer to V4L2 device created by V4L2 subsystem 300 * @videodev: Pointer to video device created by V4L2 subsystem 301 * @ctrl_handler: V4L2 controls handler 302 * @core: Pointer to underlying core device 303 * @ops: Vtable of functions. See struct si476x_radio_ops for details 304 * @debugfs: pointer to &strucd dentry for debugfs 305 * @audmode: audio mode, as defined for the rxsubchans field 306 * at videodev2.h 307 * 308 * core structure is the radio device is being used 309 */ 310 struct si476x_radio { 311 struct v4l2_device v4l2dev; 312 struct video_device videodev; 313 struct v4l2_ctrl_handler ctrl_handler; 314 315 struct si476x_core *core; 316 /* This field should not be accesses unless core lock is held */ 317 const struct si476x_radio_ops *ops; 318 319 struct dentry *debugfs; 320 u32 audmode; 321 }; 322 323 static inline struct si476x_radio * 324 v4l2_dev_to_radio(struct v4l2_device *d) 325 { 326 return container_of(d, struct si476x_radio, v4l2dev); 327 } 328 329 static inline struct si476x_radio * 330 v4l2_ctrl_handler_to_radio(struct v4l2_ctrl_handler *d) 331 { 332 return container_of(d, struct si476x_radio, ctrl_handler); 333 } 334 335 /* 336 * si476x_vidioc_querycap - query device capabilities 337 */ 338 static int si476x_radio_querycap(struct file *file, void *priv, 339 struct v4l2_capability *capability) 340 { 341 struct si476x_radio *radio = video_drvdata(file); 342 343 strlcpy(capability->driver, radio->v4l2dev.name, 344 sizeof(capability->driver)); 345 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); 346 snprintf(capability->bus_info, sizeof(capability->bus_info), 347 "platform:%s", radio->v4l2dev.name); 348 349 capability->device_caps = V4L2_CAP_TUNER 350 | V4L2_CAP_RADIO 351 | V4L2_CAP_HW_FREQ_SEEK; 352 353 si476x_core_lock(radio->core); 354 if (!si476x_core_is_a_secondary_tuner(radio->core)) 355 capability->device_caps |= V4L2_CAP_RDS_CAPTURE 356 | V4L2_CAP_READWRITE; 357 si476x_core_unlock(radio->core); 358 359 capability->capabilities = capability->device_caps 360 | V4L2_CAP_DEVICE_CAPS; 361 return 0; 362 } 363 364 static int si476x_radio_enum_freq_bands(struct file *file, void *priv, 365 struct v4l2_frequency_band *band) 366 { 367 int err; 368 struct si476x_radio *radio = video_drvdata(file); 369 370 if (band->tuner != 0) 371 return -EINVAL; 372 373 switch (radio->core->chip_id) { 374 /* AM/FM tuners -- all bands are supported */ 375 case SI476X_CHIP_SI4761: 376 case SI476X_CHIP_SI4764: 377 if (band->index < ARRAY_SIZE(si476x_bands)) { 378 *band = si476x_bands[band->index]; 379 err = 0; 380 } else { 381 err = -EINVAL; 382 } 383 break; 384 /* FM companion tuner chips -- only FM bands are 385 * supported */ 386 case SI476X_CHIP_SI4768: 387 if (band->index == SI476X_BAND_FM) { 388 *band = si476x_bands[band->index]; 389 err = 0; 390 } else { 391 err = -EINVAL; 392 } 393 break; 394 default: 395 err = -EINVAL; 396 } 397 398 return err; 399 } 400 401 static int si476x_radio_g_tuner(struct file *file, void *priv, 402 struct v4l2_tuner *tuner) 403 { 404 int err; 405 struct si476x_rsq_status_report report; 406 struct si476x_radio *radio = video_drvdata(file); 407 408 struct si476x_rsq_status_args args = { 409 .primary = false, 410 .rsqack = false, 411 .attune = false, 412 .cancel = false, 413 .stcack = false, 414 }; 415 416 if (tuner->index != 0) 417 return -EINVAL; 418 419 tuner->type = V4L2_TUNER_RADIO; 420 tuner->capability = V4L2_TUNER_CAP_LOW /* Measure frequencies 421 * in multiples of 422 * 62.5 Hz */ 423 | V4L2_TUNER_CAP_STEREO 424 | V4L2_TUNER_CAP_HWSEEK_BOUNDED 425 | V4L2_TUNER_CAP_HWSEEK_WRAP 426 | V4L2_TUNER_CAP_HWSEEK_PROG_LIM; 427 428 si476x_core_lock(radio->core); 429 430 if (si476x_core_is_a_secondary_tuner(radio->core)) { 431 strlcpy(tuner->name, "FM (secondary)", sizeof(tuner->name)); 432 tuner->rxsubchans = 0; 433 tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow; 434 } else if (si476x_core_has_am(radio->core)) { 435 if (si476x_core_is_a_primary_tuner(radio->core)) 436 strlcpy(tuner->name, "AM/FM (primary)", 437 sizeof(tuner->name)); 438 else 439 strlcpy(tuner->name, "AM/FM", sizeof(tuner->name)); 440 441 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO 442 | V4L2_TUNER_SUB_RDS; 443 tuner->capability |= V4L2_TUNER_CAP_RDS 444 | V4L2_TUNER_CAP_RDS_BLOCK_IO 445 | V4L2_TUNER_CAP_FREQ_BANDS; 446 447 tuner->rangelow = si476x_bands[SI476X_BAND_AM].rangelow; 448 } else { 449 strlcpy(tuner->name, "FM", sizeof(tuner->name)); 450 tuner->rxsubchans = V4L2_TUNER_SUB_RDS; 451 tuner->capability |= V4L2_TUNER_CAP_RDS 452 | V4L2_TUNER_CAP_RDS_BLOCK_IO 453 | V4L2_TUNER_CAP_FREQ_BANDS; 454 tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow; 455 } 456 457 tuner->audmode = radio->audmode; 458 459 tuner->afc = 1; 460 tuner->rangehigh = si476x_bands[SI476X_BAND_FM].rangehigh; 461 462 err = radio->ops->rsq_status(radio->core, 463 &args, &report); 464 if (err < 0) { 465 tuner->signal = 0; 466 } else { 467 /* 468 * tuner->signal value range: 0x0000 .. 0xFFFF, 469 * report.rssi: -128 .. 127 470 */ 471 tuner->signal = (report.rssi + 128) * 257; 472 } 473 si476x_core_unlock(radio->core); 474 475 return err; 476 } 477 478 static int si476x_radio_s_tuner(struct file *file, void *priv, 479 const struct v4l2_tuner *tuner) 480 { 481 struct si476x_radio *radio = video_drvdata(file); 482 483 if (tuner->index != 0) 484 return -EINVAL; 485 486 if (tuner->audmode == V4L2_TUNER_MODE_MONO || 487 tuner->audmode == V4L2_TUNER_MODE_STEREO) 488 radio->audmode = tuner->audmode; 489 else 490 radio->audmode = V4L2_TUNER_MODE_STEREO; 491 492 return 0; 493 } 494 495 static int si476x_radio_init_vtable(struct si476x_radio *radio, 496 enum si476x_func func) 497 { 498 static const struct si476x_radio_ops fm_ops = { 499 .tune_freq = si476x_core_cmd_fm_tune_freq, 500 .seek_start = si476x_core_cmd_fm_seek_start, 501 .rsq_status = si476x_core_cmd_fm_rsq_status, 502 .rds_blckcnt = si476x_core_cmd_fm_rds_blockcount, 503 .phase_diversity = si476x_core_cmd_fm_phase_diversity, 504 .phase_div_status = si476x_core_cmd_fm_phase_div_status, 505 .acf_status = si476x_core_cmd_fm_acf_status, 506 .agc_status = si476x_core_cmd_agc_status, 507 }; 508 509 static const struct si476x_radio_ops am_ops = { 510 .tune_freq = si476x_core_cmd_am_tune_freq, 511 .seek_start = si476x_core_cmd_am_seek_start, 512 .rsq_status = si476x_core_cmd_am_rsq_status, 513 .rds_blckcnt = NULL, 514 .phase_diversity = NULL, 515 .phase_div_status = NULL, 516 .acf_status = si476x_core_cmd_am_acf_status, 517 .agc_status = NULL, 518 }; 519 520 switch (func) { 521 case SI476X_FUNC_FM_RECEIVER: 522 radio->ops = &fm_ops; 523 return 0; 524 525 case SI476X_FUNC_AM_RECEIVER: 526 radio->ops = &am_ops; 527 return 0; 528 default: 529 WARN(1, "Unexpected tuner function value\n"); 530 return -EINVAL; 531 } 532 } 533 534 static int si476x_radio_pretune(struct si476x_radio *radio, 535 enum si476x_func func) 536 { 537 int retval; 538 539 struct si476x_tune_freq_args args = { 540 .zifsr = false, 541 .hd = false, 542 .injside = SI476X_INJSIDE_AUTO, 543 .tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE, 544 .smoothmetrics = SI476X_SM_INITIALIZE_AUDIO, 545 .antcap = 0, 546 }; 547 548 switch (func) { 549 case SI476X_FUNC_FM_RECEIVER: 550 args.freq = v4l2_to_si476x(radio->core, 551 92 * FREQ_MUL); 552 retval = radio->ops->tune_freq(radio->core, &args); 553 break; 554 case SI476X_FUNC_AM_RECEIVER: 555 args.freq = v4l2_to_si476x(radio->core, 556 0.6 * FREQ_MUL); 557 retval = radio->ops->tune_freq(radio->core, &args); 558 break; 559 default: 560 WARN(1, "Unexpected tuner function value\n"); 561 retval = -EINVAL; 562 } 563 564 return retval; 565 } 566 static int si476x_radio_do_post_powerup_init(struct si476x_radio *radio, 567 enum si476x_func func) 568 { 569 int err; 570 571 /* regcache_mark_dirty(radio->core->regmap); */ 572 err = regcache_sync_region(radio->core->regmap, 573 SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE, 574 SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT); 575 if (err < 0) 576 return err; 577 578 err = regcache_sync_region(radio->core->regmap, 579 SI476X_PROP_AUDIO_DEEMPHASIS, 580 SI476X_PROP_AUDIO_PWR_LINE_FILTER); 581 if (err < 0) 582 return err; 583 584 err = regcache_sync_region(radio->core->regmap, 585 SI476X_PROP_INT_CTL_ENABLE, 586 SI476X_PROP_INT_CTL_ENABLE); 587 if (err < 0) 588 return err; 589 590 /* 591 * Is there any point in restoring SNR and the like 592 * when switching between AM/FM? 593 */ 594 err = regcache_sync_region(radio->core->regmap, 595 SI476X_PROP_VALID_MAX_TUNE_ERROR, 596 SI476X_PROP_VALID_MAX_TUNE_ERROR); 597 if (err < 0) 598 return err; 599 600 err = regcache_sync_region(radio->core->regmap, 601 SI476X_PROP_VALID_SNR_THRESHOLD, 602 SI476X_PROP_VALID_RSSI_THRESHOLD); 603 if (err < 0) 604 return err; 605 606 if (func == SI476X_FUNC_FM_RECEIVER) { 607 if (si476x_core_has_diversity(radio->core)) { 608 err = si476x_core_cmd_fm_phase_diversity(radio->core, 609 radio->core->diversity_mode); 610 if (err < 0) 611 return err; 612 } 613 614 err = regcache_sync_region(radio->core->regmap, 615 SI476X_PROP_FM_RDS_INTERRUPT_SOURCE, 616 SI476X_PROP_FM_RDS_CONFIG); 617 if (err < 0) 618 return err; 619 } 620 621 return si476x_radio_init_vtable(radio, func); 622 623 } 624 625 static int si476x_radio_change_func(struct si476x_radio *radio, 626 enum si476x_func func) 627 { 628 int err; 629 bool soft; 630 /* 631 * Since power/up down is a very time consuming operation, 632 * try to avoid doing it if the requested mode matches the one 633 * the tuner is in 634 */ 635 if (func == radio->core->power_up_parameters.func) 636 return 0; 637 638 soft = true; 639 err = si476x_core_stop(radio->core, soft); 640 if (err < 0) { 641 /* 642 * OK, if the chip does not want to play nice let's 643 * try to reset it in more brutal way 644 */ 645 soft = false; 646 err = si476x_core_stop(radio->core, soft); 647 if (err < 0) 648 return err; 649 } 650 /* 651 Set the desired radio tuner function 652 */ 653 radio->core->power_up_parameters.func = func; 654 655 err = si476x_core_start(radio->core, soft); 656 if (err < 0) 657 return err; 658 659 /* 660 * No need to do the rest of manipulations for the bootlader 661 * mode 662 */ 663 if (func != SI476X_FUNC_FM_RECEIVER && 664 func != SI476X_FUNC_AM_RECEIVER) 665 return err; 666 667 return si476x_radio_do_post_powerup_init(radio, func); 668 } 669 670 static int si476x_radio_g_frequency(struct file *file, void *priv, 671 struct v4l2_frequency *f) 672 { 673 int err; 674 struct si476x_radio *radio = video_drvdata(file); 675 676 if (f->tuner != 0 || 677 f->type != V4L2_TUNER_RADIO) 678 return -EINVAL; 679 680 si476x_core_lock(radio->core); 681 682 if (radio->ops->rsq_status) { 683 struct si476x_rsq_status_report report; 684 struct si476x_rsq_status_args args = { 685 .primary = false, 686 .rsqack = false, 687 .attune = true, 688 .cancel = false, 689 .stcack = false, 690 }; 691 692 err = radio->ops->rsq_status(radio->core, &args, &report); 693 if (!err) 694 f->frequency = si476x_to_v4l2(radio->core, 695 report.readfreq); 696 } else { 697 err = -EINVAL; 698 } 699 700 si476x_core_unlock(radio->core); 701 702 return err; 703 } 704 705 static int si476x_radio_s_frequency(struct file *file, void *priv, 706 const struct v4l2_frequency *f) 707 { 708 int err; 709 u32 freq = f->frequency; 710 struct si476x_tune_freq_args args; 711 struct si476x_radio *radio = video_drvdata(file); 712 713 const u32 midrange = (si476x_bands[SI476X_BAND_AM].rangehigh + 714 si476x_bands[SI476X_BAND_FM].rangelow) / 2; 715 const int band = (freq > midrange) ? 716 SI476X_BAND_FM : SI476X_BAND_AM; 717 const enum si476x_func func = (band == SI476X_BAND_AM) ? 718 SI476X_FUNC_AM_RECEIVER : SI476X_FUNC_FM_RECEIVER; 719 720 if (f->tuner != 0 || 721 f->type != V4L2_TUNER_RADIO) 722 return -EINVAL; 723 724 si476x_core_lock(radio->core); 725 726 freq = clamp(freq, 727 si476x_bands[band].rangelow, 728 si476x_bands[band].rangehigh); 729 730 if (si476x_radio_freq_is_inside_of_the_band(freq, 731 SI476X_BAND_AM) && 732 (!si476x_core_has_am(radio->core) || 733 si476x_core_is_a_secondary_tuner(radio->core))) { 734 err = -EINVAL; 735 goto unlock; 736 } 737 738 err = si476x_radio_change_func(radio, func); 739 if (err < 0) 740 goto unlock; 741 742 args.zifsr = false; 743 args.hd = false; 744 args.injside = SI476X_INJSIDE_AUTO; 745 args.freq = v4l2_to_si476x(radio->core, freq); 746 args.tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE; 747 args.smoothmetrics = SI476X_SM_INITIALIZE_AUDIO; 748 args.antcap = 0; 749 750 err = radio->ops->tune_freq(radio->core, &args); 751 752 unlock: 753 si476x_core_unlock(radio->core); 754 return err; 755 } 756 757 static int si476x_radio_s_hw_freq_seek(struct file *file, void *priv, 758 const struct v4l2_hw_freq_seek *seek) 759 { 760 int err; 761 enum si476x_func func; 762 u32 rangelow, rangehigh; 763 struct si476x_radio *radio = video_drvdata(file); 764 765 if (file->f_flags & O_NONBLOCK) 766 return -EAGAIN; 767 768 if (seek->tuner != 0 || 769 seek->type != V4L2_TUNER_RADIO) 770 return -EINVAL; 771 772 si476x_core_lock(radio->core); 773 774 if (!seek->rangelow) { 775 err = regmap_read(radio->core->regmap, 776 SI476X_PROP_SEEK_BAND_BOTTOM, 777 &rangelow); 778 if (!err) 779 rangelow = si476x_to_v4l2(radio->core, rangelow); 780 else 781 goto unlock; 782 } 783 if (!seek->rangehigh) { 784 err = regmap_read(radio->core->regmap, 785 SI476X_PROP_SEEK_BAND_TOP, 786 &rangehigh); 787 if (!err) 788 rangehigh = si476x_to_v4l2(radio->core, rangehigh); 789 else 790 goto unlock; 791 } 792 793 if (rangelow > rangehigh) { 794 err = -EINVAL; 795 goto unlock; 796 } 797 798 if (si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh, 799 SI476X_BAND_FM)) { 800 func = SI476X_FUNC_FM_RECEIVER; 801 802 } else if (si476x_core_has_am(radio->core) && 803 si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh, 804 SI476X_BAND_AM)) { 805 func = SI476X_FUNC_AM_RECEIVER; 806 } else { 807 err = -EINVAL; 808 goto unlock; 809 } 810 811 err = si476x_radio_change_func(radio, func); 812 if (err < 0) 813 goto unlock; 814 815 if (seek->rangehigh) { 816 err = regmap_write(radio->core->regmap, 817 SI476X_PROP_SEEK_BAND_TOP, 818 v4l2_to_si476x(radio->core, 819 seek->rangehigh)); 820 if (err) 821 goto unlock; 822 } 823 if (seek->rangelow) { 824 err = regmap_write(radio->core->regmap, 825 SI476X_PROP_SEEK_BAND_BOTTOM, 826 v4l2_to_si476x(radio->core, 827 seek->rangelow)); 828 if (err) 829 goto unlock; 830 } 831 if (seek->spacing) { 832 err = regmap_write(radio->core->regmap, 833 SI476X_PROP_SEEK_FREQUENCY_SPACING, 834 v4l2_to_si476x(radio->core, 835 seek->spacing)); 836 if (err) 837 goto unlock; 838 } 839 840 err = radio->ops->seek_start(radio->core, 841 seek->seek_upward, 842 seek->wrap_around); 843 unlock: 844 si476x_core_unlock(radio->core); 845 846 847 848 return err; 849 } 850 851 static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl) 852 { 853 int retval; 854 struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler); 855 856 si476x_core_lock(radio->core); 857 858 switch (ctrl->id) { 859 case V4L2_CID_SI476X_INTERCHIP_LINK: 860 if (si476x_core_has_diversity(radio->core)) { 861 if (radio->ops->phase_diversity) { 862 retval = radio->ops->phase_div_status(radio->core); 863 if (retval < 0) 864 break; 865 866 ctrl->val = !!SI476X_PHDIV_STATUS_LINK_LOCKED(retval); 867 retval = 0; 868 break; 869 } else { 870 retval = -ENOTTY; 871 break; 872 } 873 } 874 retval = -EINVAL; 875 break; 876 default: 877 retval = -EINVAL; 878 break; 879 } 880 si476x_core_unlock(radio->core); 881 return retval; 882 883 } 884 885 static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl) 886 { 887 int retval; 888 enum si476x_phase_diversity_mode mode; 889 struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler); 890 891 si476x_core_lock(radio->core); 892 893 switch (ctrl->id) { 894 case V4L2_CID_SI476X_HARMONICS_COUNT: 895 retval = regmap_update_bits(radio->core->regmap, 896 SI476X_PROP_AUDIO_PWR_LINE_FILTER, 897 SI476X_PROP_PWR_HARMONICS_MASK, 898 ctrl->val); 899 break; 900 case V4L2_CID_POWER_LINE_FREQUENCY: 901 switch (ctrl->val) { 902 case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: 903 retval = regmap_update_bits(radio->core->regmap, 904 SI476X_PROP_AUDIO_PWR_LINE_FILTER, 905 SI476X_PROP_PWR_ENABLE_MASK, 906 0); 907 break; 908 case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: 909 retval = regmap_update_bits(radio->core->regmap, 910 SI476X_PROP_AUDIO_PWR_LINE_FILTER, 911 SI476X_PROP_PWR_GRID_MASK, 912 SI476X_PROP_PWR_GRID_50HZ); 913 break; 914 case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: 915 retval = regmap_update_bits(radio->core->regmap, 916 SI476X_PROP_AUDIO_PWR_LINE_FILTER, 917 SI476X_PROP_PWR_GRID_MASK, 918 SI476X_PROP_PWR_GRID_60HZ); 919 break; 920 default: 921 retval = -EINVAL; 922 break; 923 } 924 break; 925 case V4L2_CID_SI476X_RSSI_THRESHOLD: 926 retval = regmap_write(radio->core->regmap, 927 SI476X_PROP_VALID_RSSI_THRESHOLD, 928 ctrl->val); 929 break; 930 case V4L2_CID_SI476X_SNR_THRESHOLD: 931 retval = regmap_write(radio->core->regmap, 932 SI476X_PROP_VALID_SNR_THRESHOLD, 933 ctrl->val); 934 break; 935 case V4L2_CID_SI476X_MAX_TUNE_ERROR: 936 retval = regmap_write(radio->core->regmap, 937 SI476X_PROP_VALID_MAX_TUNE_ERROR, 938 ctrl->val); 939 break; 940 case V4L2_CID_RDS_RECEPTION: 941 /* 942 * It looks like RDS related properties are 943 * inaccesable when tuner is in AM mode, so cache the 944 * changes 945 */ 946 if (si476x_core_is_in_am_receiver_mode(radio->core)) 947 regcache_cache_only(radio->core->regmap, true); 948 949 if (ctrl->val) { 950 retval = regmap_write(radio->core->regmap, 951 SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT, 952 radio->core->rds_fifo_depth); 953 if (retval < 0) 954 break; 955 956 if (radio->core->client->irq) { 957 retval = regmap_write(radio->core->regmap, 958 SI476X_PROP_FM_RDS_INTERRUPT_SOURCE, 959 SI476X_RDSRECV); 960 if (retval < 0) 961 break; 962 } 963 964 /* Drain RDS FIFO before enabling RDS processing */ 965 retval = si476x_core_cmd_fm_rds_status(radio->core, 966 false, 967 true, 968 true, 969 NULL); 970 if (retval < 0) 971 break; 972 973 retval = regmap_update_bits(radio->core->regmap, 974 SI476X_PROP_FM_RDS_CONFIG, 975 SI476X_PROP_RDSEN_MASK, 976 SI476X_PROP_RDSEN); 977 } else { 978 retval = regmap_update_bits(radio->core->regmap, 979 SI476X_PROP_FM_RDS_CONFIG, 980 SI476X_PROP_RDSEN_MASK, 981 !SI476X_PROP_RDSEN); 982 } 983 984 if (si476x_core_is_in_am_receiver_mode(radio->core)) 985 regcache_cache_only(radio->core->regmap, false); 986 break; 987 case V4L2_CID_TUNE_DEEMPHASIS: 988 retval = regmap_write(radio->core->regmap, 989 SI476X_PROP_AUDIO_DEEMPHASIS, 990 ctrl->val); 991 break; 992 993 case V4L2_CID_SI476X_DIVERSITY_MODE: 994 mode = si476x_phase_diversity_idx_to_mode(ctrl->val); 995 996 if (mode == radio->core->diversity_mode) { 997 retval = 0; 998 break; 999 } 1000 1001 if (si476x_core_is_in_am_receiver_mode(radio->core)) { 1002 /* 1003 * Diversity cannot be configured while tuner 1004 * is in AM mode so save the changes and carry on. 1005 */ 1006 radio->core->diversity_mode = mode; 1007 retval = 0; 1008 } else { 1009 retval = radio->ops->phase_diversity(radio->core, mode); 1010 if (!retval) 1011 radio->core->diversity_mode = mode; 1012 } 1013 break; 1014 1015 default: 1016 retval = -EINVAL; 1017 break; 1018 } 1019 1020 si476x_core_unlock(radio->core); 1021 1022 return retval; 1023 } 1024 1025 #ifdef CONFIG_VIDEO_ADV_DEBUG 1026 static int si476x_radio_g_register(struct file *file, void *fh, 1027 struct v4l2_dbg_register *reg) 1028 { 1029 int err; 1030 unsigned int value; 1031 struct si476x_radio *radio = video_drvdata(file); 1032 1033 si476x_core_lock(radio->core); 1034 reg->size = 2; 1035 err = regmap_read(radio->core->regmap, 1036 (unsigned int)reg->reg, &value); 1037 reg->val = value; 1038 si476x_core_unlock(radio->core); 1039 1040 return err; 1041 } 1042 static int si476x_radio_s_register(struct file *file, void *fh, 1043 const struct v4l2_dbg_register *reg) 1044 { 1045 1046 int err; 1047 struct si476x_radio *radio = video_drvdata(file); 1048 1049 si476x_core_lock(radio->core); 1050 err = regmap_write(radio->core->regmap, 1051 (unsigned int)reg->reg, 1052 (unsigned int)reg->val); 1053 si476x_core_unlock(radio->core); 1054 1055 return err; 1056 } 1057 #endif 1058 1059 static int si476x_radio_fops_open(struct file *file) 1060 { 1061 struct si476x_radio *radio = video_drvdata(file); 1062 int err; 1063 1064 err = v4l2_fh_open(file); 1065 if (err) 1066 return err; 1067 1068 if (v4l2_fh_is_singular_file(file)) { 1069 si476x_core_lock(radio->core); 1070 err = si476x_core_set_power_state(radio->core, 1071 SI476X_POWER_UP_FULL); 1072 if (err < 0) 1073 goto done; 1074 1075 err = si476x_radio_do_post_powerup_init(radio, 1076 radio->core->power_up_parameters.func); 1077 if (err < 0) 1078 goto power_down; 1079 1080 err = si476x_radio_pretune(radio, 1081 radio->core->power_up_parameters.func); 1082 if (err < 0) 1083 goto power_down; 1084 1085 si476x_core_unlock(radio->core); 1086 /*Must be done after si476x_core_unlock to prevent a deadlock*/ 1087 v4l2_ctrl_handler_setup(&radio->ctrl_handler); 1088 } 1089 1090 return err; 1091 1092 power_down: 1093 si476x_core_set_power_state(radio->core, 1094 SI476X_POWER_DOWN); 1095 done: 1096 si476x_core_unlock(radio->core); 1097 v4l2_fh_release(file); 1098 1099 return err; 1100 } 1101 1102 static int si476x_radio_fops_release(struct file *file) 1103 { 1104 int err; 1105 struct si476x_radio *radio = video_drvdata(file); 1106 1107 if (v4l2_fh_is_singular_file(file) && 1108 atomic_read(&radio->core->is_alive)) 1109 si476x_core_set_power_state(radio->core, 1110 SI476X_POWER_DOWN); 1111 1112 err = v4l2_fh_release(file); 1113 1114 return err; 1115 } 1116 1117 static ssize_t si476x_radio_fops_read(struct file *file, char __user *buf, 1118 size_t count, loff_t *ppos) 1119 { 1120 ssize_t rval; 1121 size_t fifo_len; 1122 unsigned int copied; 1123 1124 struct si476x_radio *radio = video_drvdata(file); 1125 1126 /* block if no new data available */ 1127 if (kfifo_is_empty(&radio->core->rds_fifo)) { 1128 if (file->f_flags & O_NONBLOCK) 1129 return -EWOULDBLOCK; 1130 1131 rval = wait_event_interruptible(radio->core->rds_read_queue, 1132 (!kfifo_is_empty(&radio->core->rds_fifo) || 1133 !atomic_read(&radio->core->is_alive))); 1134 if (rval < 0) 1135 return -EINTR; 1136 1137 if (!atomic_read(&radio->core->is_alive)) 1138 return -ENODEV; 1139 } 1140 1141 fifo_len = kfifo_len(&radio->core->rds_fifo); 1142 1143 if (kfifo_to_user(&radio->core->rds_fifo, buf, 1144 min(fifo_len, count), 1145 &copied) != 0) { 1146 dev_warn(&radio->videodev.dev, 1147 "Error during FIFO to userspace copy\n"); 1148 rval = -EIO; 1149 } else { 1150 rval = (ssize_t)copied; 1151 } 1152 1153 return rval; 1154 } 1155 1156 static unsigned int si476x_radio_fops_poll(struct file *file, 1157 struct poll_table_struct *pts) 1158 { 1159 struct si476x_radio *radio = video_drvdata(file); 1160 unsigned long req_events = poll_requested_events(pts); 1161 unsigned int err = v4l2_ctrl_poll(file, pts); 1162 1163 if (req_events & (POLLIN | POLLRDNORM)) { 1164 if (atomic_read(&radio->core->is_alive)) 1165 poll_wait(file, &radio->core->rds_read_queue, pts); 1166 1167 if (!atomic_read(&radio->core->is_alive)) 1168 err = POLLHUP; 1169 1170 if (!kfifo_is_empty(&radio->core->rds_fifo)) 1171 err = POLLIN | POLLRDNORM; 1172 } 1173 1174 return err; 1175 } 1176 1177 static const struct v4l2_file_operations si476x_fops = { 1178 .owner = THIS_MODULE, 1179 .read = si476x_radio_fops_read, 1180 .poll = si476x_radio_fops_poll, 1181 .unlocked_ioctl = video_ioctl2, 1182 .open = si476x_radio_fops_open, 1183 .release = si476x_radio_fops_release, 1184 }; 1185 1186 1187 static const struct v4l2_ioctl_ops si4761_ioctl_ops = { 1188 .vidioc_querycap = si476x_radio_querycap, 1189 .vidioc_g_tuner = si476x_radio_g_tuner, 1190 .vidioc_s_tuner = si476x_radio_s_tuner, 1191 1192 .vidioc_g_frequency = si476x_radio_g_frequency, 1193 .vidioc_s_frequency = si476x_radio_s_frequency, 1194 .vidioc_s_hw_freq_seek = si476x_radio_s_hw_freq_seek, 1195 .vidioc_enum_freq_bands = si476x_radio_enum_freq_bands, 1196 1197 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 1198 .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 1199 1200 #ifdef CONFIG_VIDEO_ADV_DEBUG 1201 .vidioc_g_register = si476x_radio_g_register, 1202 .vidioc_s_register = si476x_radio_s_register, 1203 #endif 1204 }; 1205 1206 1207 static const struct video_device si476x_viddev_template = { 1208 .fops = &si476x_fops, 1209 .name = DRIVER_NAME, 1210 .release = video_device_release_empty, 1211 }; 1212 1213 1214 1215 static ssize_t si476x_radio_read_acf_blob(struct file *file, 1216 char __user *user_buf, 1217 size_t count, loff_t *ppos) 1218 { 1219 int err; 1220 struct si476x_radio *radio = file->private_data; 1221 struct si476x_acf_status_report report; 1222 1223 si476x_core_lock(radio->core); 1224 if (radio->ops->acf_status) 1225 err = radio->ops->acf_status(radio->core, &report); 1226 else 1227 err = -ENOENT; 1228 si476x_core_unlock(radio->core); 1229 1230 if (err < 0) 1231 return err; 1232 1233 return simple_read_from_buffer(user_buf, count, ppos, &report, 1234 sizeof(report)); 1235 } 1236 1237 static const struct file_operations radio_acf_fops = { 1238 .open = simple_open, 1239 .llseek = default_llseek, 1240 .read = si476x_radio_read_acf_blob, 1241 }; 1242 1243 static ssize_t si476x_radio_read_rds_blckcnt_blob(struct file *file, 1244 char __user *user_buf, 1245 size_t count, loff_t *ppos) 1246 { 1247 int err; 1248 struct si476x_radio *radio = file->private_data; 1249 struct si476x_rds_blockcount_report report; 1250 1251 si476x_core_lock(radio->core); 1252 if (radio->ops->rds_blckcnt) 1253 err = radio->ops->rds_blckcnt(radio->core, true, 1254 &report); 1255 else 1256 err = -ENOENT; 1257 si476x_core_unlock(radio->core); 1258 1259 if (err < 0) 1260 return err; 1261 1262 return simple_read_from_buffer(user_buf, count, ppos, &report, 1263 sizeof(report)); 1264 } 1265 1266 static const struct file_operations radio_rds_blckcnt_fops = { 1267 .open = simple_open, 1268 .llseek = default_llseek, 1269 .read = si476x_radio_read_rds_blckcnt_blob, 1270 }; 1271 1272 static ssize_t si476x_radio_read_agc_blob(struct file *file, 1273 char __user *user_buf, 1274 size_t count, loff_t *ppos) 1275 { 1276 int err; 1277 struct si476x_radio *radio = file->private_data; 1278 struct si476x_agc_status_report report; 1279 1280 si476x_core_lock(radio->core); 1281 if (radio->ops->rds_blckcnt) 1282 err = radio->ops->agc_status(radio->core, &report); 1283 else 1284 err = -ENOENT; 1285 si476x_core_unlock(radio->core); 1286 1287 if (err < 0) 1288 return err; 1289 1290 return simple_read_from_buffer(user_buf, count, ppos, &report, 1291 sizeof(report)); 1292 } 1293 1294 static const struct file_operations radio_agc_fops = { 1295 .open = simple_open, 1296 .llseek = default_llseek, 1297 .read = si476x_radio_read_agc_blob, 1298 }; 1299 1300 static ssize_t si476x_radio_read_rsq_blob(struct file *file, 1301 char __user *user_buf, 1302 size_t count, loff_t *ppos) 1303 { 1304 int err; 1305 struct si476x_radio *radio = file->private_data; 1306 struct si476x_rsq_status_report report; 1307 struct si476x_rsq_status_args args = { 1308 .primary = false, 1309 .rsqack = false, 1310 .attune = false, 1311 .cancel = false, 1312 .stcack = false, 1313 }; 1314 1315 si476x_core_lock(radio->core); 1316 if (radio->ops->rds_blckcnt) 1317 err = radio->ops->rsq_status(radio->core, &args, &report); 1318 else 1319 err = -ENOENT; 1320 si476x_core_unlock(radio->core); 1321 1322 if (err < 0) 1323 return err; 1324 1325 return simple_read_from_buffer(user_buf, count, ppos, &report, 1326 sizeof(report)); 1327 } 1328 1329 static const struct file_operations radio_rsq_fops = { 1330 .open = simple_open, 1331 .llseek = default_llseek, 1332 .read = si476x_radio_read_rsq_blob, 1333 }; 1334 1335 static ssize_t si476x_radio_read_rsq_primary_blob(struct file *file, 1336 char __user *user_buf, 1337 size_t count, loff_t *ppos) 1338 { 1339 int err; 1340 struct si476x_radio *radio = file->private_data; 1341 struct si476x_rsq_status_report report; 1342 struct si476x_rsq_status_args args = { 1343 .primary = true, 1344 .rsqack = false, 1345 .attune = false, 1346 .cancel = false, 1347 .stcack = false, 1348 }; 1349 1350 si476x_core_lock(radio->core); 1351 if (radio->ops->rds_blckcnt) 1352 err = radio->ops->rsq_status(radio->core, &args, &report); 1353 else 1354 err = -ENOENT; 1355 si476x_core_unlock(radio->core); 1356 1357 if (err < 0) 1358 return err; 1359 1360 return simple_read_from_buffer(user_buf, count, ppos, &report, 1361 sizeof(report)); 1362 } 1363 1364 static const struct file_operations radio_rsq_primary_fops = { 1365 .open = simple_open, 1366 .llseek = default_llseek, 1367 .read = si476x_radio_read_rsq_primary_blob, 1368 }; 1369 1370 1371 static int si476x_radio_init_debugfs(struct si476x_radio *radio) 1372 { 1373 struct dentry *dentry; 1374 int ret; 1375 1376 dentry = debugfs_create_dir(dev_name(radio->v4l2dev.dev), NULL); 1377 if (IS_ERR(dentry)) { 1378 ret = PTR_ERR(dentry); 1379 goto exit; 1380 } 1381 radio->debugfs = dentry; 1382 1383 dentry = debugfs_create_file("acf", S_IRUGO, 1384 radio->debugfs, radio, &radio_acf_fops); 1385 if (IS_ERR(dentry)) { 1386 ret = PTR_ERR(dentry); 1387 goto cleanup; 1388 } 1389 1390 dentry = debugfs_create_file("rds_blckcnt", S_IRUGO, 1391 radio->debugfs, radio, 1392 &radio_rds_blckcnt_fops); 1393 if (IS_ERR(dentry)) { 1394 ret = PTR_ERR(dentry); 1395 goto cleanup; 1396 } 1397 1398 dentry = debugfs_create_file("agc", S_IRUGO, 1399 radio->debugfs, radio, &radio_agc_fops); 1400 if (IS_ERR(dentry)) { 1401 ret = PTR_ERR(dentry); 1402 goto cleanup; 1403 } 1404 1405 dentry = debugfs_create_file("rsq", S_IRUGO, 1406 radio->debugfs, radio, &radio_rsq_fops); 1407 if (IS_ERR(dentry)) { 1408 ret = PTR_ERR(dentry); 1409 goto cleanup; 1410 } 1411 1412 dentry = debugfs_create_file("rsq_primary", S_IRUGO, 1413 radio->debugfs, radio, 1414 &radio_rsq_primary_fops); 1415 if (IS_ERR(dentry)) { 1416 ret = PTR_ERR(dentry); 1417 goto cleanup; 1418 } 1419 1420 return 0; 1421 cleanup: 1422 debugfs_remove_recursive(radio->debugfs); 1423 exit: 1424 return ret; 1425 } 1426 1427 1428 static int si476x_radio_add_new_custom(struct si476x_radio *radio, 1429 enum si476x_ctrl_idx idx) 1430 { 1431 int rval; 1432 struct v4l2_ctrl *ctrl; 1433 1434 ctrl = v4l2_ctrl_new_custom(&radio->ctrl_handler, 1435 &si476x_ctrls[idx], 1436 NULL); 1437 rval = radio->ctrl_handler.error; 1438 if (ctrl == NULL && rval) 1439 dev_err(radio->v4l2dev.dev, 1440 "Could not initialize '%s' control %d\n", 1441 si476x_ctrls[idx].name, rval); 1442 1443 return rval; 1444 } 1445 1446 static int si476x_radio_probe(struct platform_device *pdev) 1447 { 1448 int rval; 1449 struct si476x_radio *radio; 1450 struct v4l2_ctrl *ctrl; 1451 1452 static atomic_t instance = ATOMIC_INIT(0); 1453 1454 radio = devm_kzalloc(&pdev->dev, sizeof(*radio), GFP_KERNEL); 1455 if (!radio) 1456 return -ENOMEM; 1457 1458 radio->core = i2c_mfd_cell_to_core(&pdev->dev); 1459 1460 v4l2_device_set_name(&radio->v4l2dev, DRIVER_NAME, &instance); 1461 1462 rval = v4l2_device_register(&pdev->dev, &radio->v4l2dev); 1463 if (rval) { 1464 dev_err(&pdev->dev, "Cannot register v4l2_device.\n"); 1465 return rval; 1466 } 1467 1468 memcpy(&radio->videodev, &si476x_viddev_template, 1469 sizeof(struct video_device)); 1470 1471 radio->videodev.v4l2_dev = &radio->v4l2dev; 1472 radio->videodev.ioctl_ops = &si4761_ioctl_ops; 1473 1474 video_set_drvdata(&radio->videodev, radio); 1475 platform_set_drvdata(pdev, radio); 1476 1477 1478 radio->v4l2dev.ctrl_handler = &radio->ctrl_handler; 1479 v4l2_ctrl_handler_init(&radio->ctrl_handler, 1480 1 + ARRAY_SIZE(si476x_ctrls)); 1481 1482 if (si476x_core_has_am(radio->core)) { 1483 ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler, 1484 &si476x_ctrl_ops, 1485 V4L2_CID_POWER_LINE_FREQUENCY, 1486 V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 1487 0, 0); 1488 rval = radio->ctrl_handler.error; 1489 if (ctrl == NULL && rval) { 1490 dev_err(&pdev->dev, "Could not initialize V4L2_CID_POWER_LINE_FREQUENCY control %d\n", 1491 rval); 1492 goto exit; 1493 } 1494 1495 rval = si476x_radio_add_new_custom(radio, 1496 SI476X_IDX_HARMONICS_COUNT); 1497 if (rval < 0) 1498 goto exit; 1499 } 1500 1501 rval = si476x_radio_add_new_custom(radio, SI476X_IDX_RSSI_THRESHOLD); 1502 if (rval < 0) 1503 goto exit; 1504 1505 rval = si476x_radio_add_new_custom(radio, SI476X_IDX_SNR_THRESHOLD); 1506 if (rval < 0) 1507 goto exit; 1508 1509 rval = si476x_radio_add_new_custom(radio, SI476X_IDX_MAX_TUNE_ERROR); 1510 if (rval < 0) 1511 goto exit; 1512 1513 ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler, 1514 &si476x_ctrl_ops, 1515 V4L2_CID_TUNE_DEEMPHASIS, 1516 V4L2_DEEMPHASIS_75_uS, 0, 0); 1517 rval = radio->ctrl_handler.error; 1518 if (ctrl == NULL && rval) { 1519 dev_err(&pdev->dev, "Could not initialize V4L2_CID_TUNE_DEEMPHASIS control %d\n", 1520 rval); 1521 goto exit; 1522 } 1523 1524 ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &si476x_ctrl_ops, 1525 V4L2_CID_RDS_RECEPTION, 1526 0, 1, 1, 1); 1527 rval = radio->ctrl_handler.error; 1528 if (ctrl == NULL && rval) { 1529 dev_err(&pdev->dev, "Could not initialize V4L2_CID_RDS_RECEPTION control %d\n", 1530 rval); 1531 goto exit; 1532 } 1533 1534 if (si476x_core_has_diversity(radio->core)) { 1535 si476x_ctrls[SI476X_IDX_DIVERSITY_MODE].def = 1536 si476x_phase_diversity_mode_to_idx(radio->core->diversity_mode); 1537 rval = si476x_radio_add_new_custom(radio, SI476X_IDX_DIVERSITY_MODE); 1538 if (rval < 0) 1539 goto exit; 1540 1541 rval = si476x_radio_add_new_custom(radio, SI476X_IDX_INTERCHIP_LINK); 1542 if (rval < 0) 1543 goto exit; 1544 } 1545 1546 /* register video device */ 1547 rval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, -1); 1548 if (rval < 0) { 1549 dev_err(&pdev->dev, "Could not register video device\n"); 1550 goto exit; 1551 } 1552 1553 rval = si476x_radio_init_debugfs(radio); 1554 if (rval < 0) { 1555 dev_err(&pdev->dev, "Could not creat debugfs interface\n"); 1556 goto exit; 1557 } 1558 1559 return 0; 1560 exit: 1561 v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); 1562 return rval; 1563 } 1564 1565 static int si476x_radio_remove(struct platform_device *pdev) 1566 { 1567 struct si476x_radio *radio = platform_get_drvdata(pdev); 1568 1569 v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); 1570 video_unregister_device(&radio->videodev); 1571 v4l2_device_unregister(&radio->v4l2dev); 1572 debugfs_remove_recursive(radio->debugfs); 1573 1574 return 0; 1575 } 1576 1577 MODULE_ALIAS("platform:si476x-radio"); 1578 1579 static struct platform_driver si476x_radio_driver = { 1580 .driver = { 1581 .name = DRIVER_NAME, 1582 }, 1583 .probe = si476x_radio_probe, 1584 .remove = si476x_radio_remove, 1585 }; 1586 module_platform_driver(si476x_radio_driver); 1587 1588 MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>"); 1589 MODULE_DESCRIPTION("Driver for Si4761/64/68 AM/FM Radio MFD Cell"); 1590 MODULE_LICENSE("GPL"); 1591