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