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_dev_to_radio(struct v4l2_device *d) 317 { 318 return container_of(d, struct si476x_radio, v4l2dev); 319 } 320 321 static inline struct si476x_radio * 322 v4l2_ctrl_handler_to_radio(struct v4l2_ctrl_handler *d) 323 { 324 return container_of(d, struct si476x_radio, ctrl_handler); 325 } 326 327 /* 328 * si476x_vidioc_querycap - query device capabilities 329 */ 330 static int si476x_radio_querycap(struct file *file, void *priv, 331 struct v4l2_capability *capability) 332 { 333 struct si476x_radio *radio = video_drvdata(file); 334 335 strscpy(capability->driver, radio->v4l2dev.name, 336 sizeof(capability->driver)); 337 strscpy(capability->card, DRIVER_CARD, sizeof(capability->card)); 338 snprintf(capability->bus_info, sizeof(capability->bus_info), 339 "platform:%s", radio->v4l2dev.name); 340 return 0; 341 } 342 343 static int si476x_radio_enum_freq_bands(struct file *file, void *priv, 344 struct v4l2_frequency_band *band) 345 { 346 int err; 347 struct si476x_radio *radio = video_drvdata(file); 348 349 if (band->tuner != 0) 350 return -EINVAL; 351 352 switch (radio->core->chip_id) { 353 /* AM/FM tuners -- all bands are supported */ 354 case SI476X_CHIP_SI4761: 355 case SI476X_CHIP_SI4764: 356 if (band->index < ARRAY_SIZE(si476x_bands)) { 357 *band = si476x_bands[band->index]; 358 err = 0; 359 } else { 360 err = -EINVAL; 361 } 362 break; 363 /* FM companion tuner chips -- only FM bands are 364 * supported */ 365 case SI476X_CHIP_SI4768: 366 if (band->index == SI476X_BAND_FM) { 367 *band = si476x_bands[band->index]; 368 err = 0; 369 } else { 370 err = -EINVAL; 371 } 372 break; 373 default: 374 err = -EINVAL; 375 } 376 377 return err; 378 } 379 380 static int si476x_radio_g_tuner(struct file *file, void *priv, 381 struct v4l2_tuner *tuner) 382 { 383 int err; 384 struct si476x_rsq_status_report report; 385 struct si476x_radio *radio = video_drvdata(file); 386 387 struct si476x_rsq_status_args args = { 388 .primary = false, 389 .rsqack = false, 390 .attune = false, 391 .cancel = false, 392 .stcack = false, 393 }; 394 395 if (tuner->index != 0) 396 return -EINVAL; 397 398 tuner->type = V4L2_TUNER_RADIO; 399 tuner->capability = V4L2_TUNER_CAP_LOW /* Measure frequencies 400 * in multiples of 401 * 62.5 Hz */ 402 | V4L2_TUNER_CAP_STEREO 403 | V4L2_TUNER_CAP_HWSEEK_BOUNDED 404 | V4L2_TUNER_CAP_HWSEEK_WRAP 405 | V4L2_TUNER_CAP_HWSEEK_PROG_LIM; 406 407 si476x_core_lock(radio->core); 408 409 if (si476x_core_is_a_secondary_tuner(radio->core)) { 410 strscpy(tuner->name, "FM (secondary)", sizeof(tuner->name)); 411 tuner->rxsubchans = 0; 412 tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow; 413 } else if (si476x_core_has_am(radio->core)) { 414 if (si476x_core_is_a_primary_tuner(radio->core)) 415 strscpy(tuner->name, "AM/FM (primary)", 416 sizeof(tuner->name)); 417 else 418 strscpy(tuner->name, "AM/FM", sizeof(tuner->name)); 419 420 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO 421 | V4L2_TUNER_SUB_RDS; 422 tuner->capability |= V4L2_TUNER_CAP_RDS 423 | V4L2_TUNER_CAP_RDS_BLOCK_IO 424 | V4L2_TUNER_CAP_FREQ_BANDS; 425 426 tuner->rangelow = si476x_bands[SI476X_BAND_AM].rangelow; 427 } else { 428 strscpy(tuner->name, "FM", sizeof(tuner->name)); 429 tuner->rxsubchans = V4L2_TUNER_SUB_RDS; 430 tuner->capability |= V4L2_TUNER_CAP_RDS 431 | V4L2_TUNER_CAP_RDS_BLOCK_IO 432 | V4L2_TUNER_CAP_FREQ_BANDS; 433 tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow; 434 } 435 436 tuner->audmode = radio->audmode; 437 438 tuner->afc = 1; 439 tuner->rangehigh = si476x_bands[SI476X_BAND_FM].rangehigh; 440 441 err = radio->ops->rsq_status(radio->core, 442 &args, &report); 443 if (err < 0) { 444 tuner->signal = 0; 445 } else { 446 /* 447 * tuner->signal value range: 0x0000 .. 0xFFFF, 448 * report.rssi: -128 .. 127 449 */ 450 tuner->signal = (report.rssi + 128) * 257; 451 } 452 si476x_core_unlock(radio->core); 453 454 return err; 455 } 456 457 static int si476x_radio_s_tuner(struct file *file, void *priv, 458 const struct v4l2_tuner *tuner) 459 { 460 struct si476x_radio *radio = video_drvdata(file); 461 462 if (tuner->index != 0) 463 return -EINVAL; 464 465 if (tuner->audmode == V4L2_TUNER_MODE_MONO || 466 tuner->audmode == V4L2_TUNER_MODE_STEREO) 467 radio->audmode = tuner->audmode; 468 else 469 radio->audmode = V4L2_TUNER_MODE_STEREO; 470 471 return 0; 472 } 473 474 static int si476x_radio_init_vtable(struct si476x_radio *radio, 475 enum si476x_func func) 476 { 477 static const struct si476x_radio_ops fm_ops = { 478 .tune_freq = si476x_core_cmd_fm_tune_freq, 479 .seek_start = si476x_core_cmd_fm_seek_start, 480 .rsq_status = si476x_core_cmd_fm_rsq_status, 481 .rds_blckcnt = si476x_core_cmd_fm_rds_blockcount, 482 .phase_diversity = si476x_core_cmd_fm_phase_diversity, 483 .phase_div_status = si476x_core_cmd_fm_phase_div_status, 484 .acf_status = si476x_core_cmd_fm_acf_status, 485 .agc_status = si476x_core_cmd_agc_status, 486 }; 487 488 static const struct si476x_radio_ops am_ops = { 489 .tune_freq = si476x_core_cmd_am_tune_freq, 490 .seek_start = si476x_core_cmd_am_seek_start, 491 .rsq_status = si476x_core_cmd_am_rsq_status, 492 .rds_blckcnt = NULL, 493 .phase_diversity = NULL, 494 .phase_div_status = NULL, 495 .acf_status = si476x_core_cmd_am_acf_status, 496 .agc_status = NULL, 497 }; 498 499 switch (func) { 500 case SI476X_FUNC_FM_RECEIVER: 501 radio->ops = &fm_ops; 502 return 0; 503 504 case SI476X_FUNC_AM_RECEIVER: 505 radio->ops = &am_ops; 506 return 0; 507 default: 508 WARN(1, "Unexpected tuner function value\n"); 509 return -EINVAL; 510 } 511 } 512 513 static int si476x_radio_pretune(struct si476x_radio *radio, 514 enum si476x_func func) 515 { 516 int retval; 517 518 struct si476x_tune_freq_args args = { 519 .zifsr = false, 520 .hd = false, 521 .injside = SI476X_INJSIDE_AUTO, 522 .tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE, 523 .smoothmetrics = SI476X_SM_INITIALIZE_AUDIO, 524 .antcap = 0, 525 }; 526 527 switch (func) { 528 case SI476X_FUNC_FM_RECEIVER: 529 args.freq = v4l2_to_si476x(radio->core, 530 92 * FREQ_MUL); 531 retval = radio->ops->tune_freq(radio->core, &args); 532 break; 533 case SI476X_FUNC_AM_RECEIVER: 534 args.freq = v4l2_to_si476x(radio->core, 535 0.6 * FREQ_MUL); 536 retval = radio->ops->tune_freq(radio->core, &args); 537 break; 538 default: 539 WARN(1, "Unexpected tuner function value\n"); 540 retval = -EINVAL; 541 } 542 543 return retval; 544 } 545 static int si476x_radio_do_post_powerup_init(struct si476x_radio *radio, 546 enum si476x_func func) 547 { 548 int err; 549 550 /* regcache_mark_dirty(radio->core->regmap); */ 551 err = regcache_sync_region(radio->core->regmap, 552 SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE, 553 SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT); 554 if (err < 0) 555 return err; 556 557 err = regcache_sync_region(radio->core->regmap, 558 SI476X_PROP_AUDIO_DEEMPHASIS, 559 SI476X_PROP_AUDIO_PWR_LINE_FILTER); 560 if (err < 0) 561 return err; 562 563 err = regcache_sync_region(radio->core->regmap, 564 SI476X_PROP_INT_CTL_ENABLE, 565 SI476X_PROP_INT_CTL_ENABLE); 566 if (err < 0) 567 return err; 568 569 /* 570 * Is there any point in restoring SNR and the like 571 * when switching between AM/FM? 572 */ 573 err = regcache_sync_region(radio->core->regmap, 574 SI476X_PROP_VALID_MAX_TUNE_ERROR, 575 SI476X_PROP_VALID_MAX_TUNE_ERROR); 576 if (err < 0) 577 return err; 578 579 err = regcache_sync_region(radio->core->regmap, 580 SI476X_PROP_VALID_SNR_THRESHOLD, 581 SI476X_PROP_VALID_RSSI_THRESHOLD); 582 if (err < 0) 583 return err; 584 585 if (func == SI476X_FUNC_FM_RECEIVER) { 586 if (si476x_core_has_diversity(radio->core)) { 587 err = si476x_core_cmd_fm_phase_diversity(radio->core, 588 radio->core->diversity_mode); 589 if (err < 0) 590 return err; 591 } 592 593 err = regcache_sync_region(radio->core->regmap, 594 SI476X_PROP_FM_RDS_INTERRUPT_SOURCE, 595 SI476X_PROP_FM_RDS_CONFIG); 596 if (err < 0) 597 return err; 598 } 599 600 return si476x_radio_init_vtable(radio, func); 601 602 } 603 604 static int si476x_radio_change_func(struct si476x_radio *radio, 605 enum si476x_func func) 606 { 607 int err; 608 bool soft; 609 /* 610 * Since power/up down is a very time consuming operation, 611 * try to avoid doing it if the requested mode matches the one 612 * the tuner is in 613 */ 614 if (func == radio->core->power_up_parameters.func) 615 return 0; 616 617 soft = true; 618 err = si476x_core_stop(radio->core, soft); 619 if (err < 0) { 620 /* 621 * OK, if the chip does not want to play nice let's 622 * try to reset it in more brutal way 623 */ 624 soft = false; 625 err = si476x_core_stop(radio->core, soft); 626 if (err < 0) 627 return err; 628 } 629 /* 630 Set the desired radio tuner function 631 */ 632 radio->core->power_up_parameters.func = func; 633 634 err = si476x_core_start(radio->core, soft); 635 if (err < 0) 636 return err; 637 638 /* 639 * No need to do the rest of manipulations for the bootlader 640 * mode 641 */ 642 if (func != SI476X_FUNC_FM_RECEIVER && 643 func != SI476X_FUNC_AM_RECEIVER) 644 return err; 645 646 return si476x_radio_do_post_powerup_init(radio, func); 647 } 648 649 static int si476x_radio_g_frequency(struct file *file, void *priv, 650 struct v4l2_frequency *f) 651 { 652 int err; 653 struct si476x_radio *radio = video_drvdata(file); 654 655 if (f->tuner != 0 || 656 f->type != V4L2_TUNER_RADIO) 657 return -EINVAL; 658 659 si476x_core_lock(radio->core); 660 661 if (radio->ops->rsq_status) { 662 struct si476x_rsq_status_report report; 663 struct si476x_rsq_status_args args = { 664 .primary = false, 665 .rsqack = false, 666 .attune = true, 667 .cancel = false, 668 .stcack = false, 669 }; 670 671 err = radio->ops->rsq_status(radio->core, &args, &report); 672 if (!err) 673 f->frequency = si476x_to_v4l2(radio->core, 674 report.readfreq); 675 } else { 676 err = -EINVAL; 677 } 678 679 si476x_core_unlock(radio->core); 680 681 return err; 682 } 683 684 static int si476x_radio_s_frequency(struct file *file, void *priv, 685 const struct v4l2_frequency *f) 686 { 687 int err; 688 u32 freq = f->frequency; 689 struct si476x_tune_freq_args args; 690 struct si476x_radio *radio = video_drvdata(file); 691 692 const u32 midrange = (si476x_bands[SI476X_BAND_AM].rangehigh + 693 si476x_bands[SI476X_BAND_FM].rangelow) / 2; 694 const int band = (freq > midrange) ? 695 SI476X_BAND_FM : SI476X_BAND_AM; 696 const enum si476x_func func = (band == SI476X_BAND_AM) ? 697 SI476X_FUNC_AM_RECEIVER : SI476X_FUNC_FM_RECEIVER; 698 699 if (f->tuner != 0 || 700 f->type != V4L2_TUNER_RADIO) 701 return -EINVAL; 702 703 si476x_core_lock(radio->core); 704 705 freq = clamp(freq, 706 si476x_bands[band].rangelow, 707 si476x_bands[band].rangehigh); 708 709 if (si476x_radio_freq_is_inside_of_the_band(freq, 710 SI476X_BAND_AM) && 711 (!si476x_core_has_am(radio->core) || 712 si476x_core_is_a_secondary_tuner(radio->core))) { 713 err = -EINVAL; 714 goto unlock; 715 } 716 717 err = si476x_radio_change_func(radio, func); 718 if (err < 0) 719 goto unlock; 720 721 args.zifsr = false; 722 args.hd = false; 723 args.injside = SI476X_INJSIDE_AUTO; 724 args.freq = v4l2_to_si476x(radio->core, freq); 725 args.tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE; 726 args.smoothmetrics = SI476X_SM_INITIALIZE_AUDIO; 727 args.antcap = 0; 728 729 err = radio->ops->tune_freq(radio->core, &args); 730 731 unlock: 732 si476x_core_unlock(radio->core); 733 return err; 734 } 735 736 static int si476x_radio_s_hw_freq_seek(struct file *file, void *priv, 737 const struct v4l2_hw_freq_seek *seek) 738 { 739 int err; 740 enum si476x_func func; 741 u32 rangelow = seek->rangelow, rangehigh = seek->rangehigh; 742 struct si476x_radio *radio = video_drvdata(file); 743 744 if (file->f_flags & O_NONBLOCK) 745 return -EAGAIN; 746 747 if (seek->tuner != 0 || 748 seek->type != V4L2_TUNER_RADIO) 749 return -EINVAL; 750 751 si476x_core_lock(radio->core); 752 753 if (!rangelow) { 754 err = regmap_read(radio->core->regmap, 755 SI476X_PROP_SEEK_BAND_BOTTOM, 756 &rangelow); 757 if (err) 758 goto unlock; 759 rangelow = si476x_to_v4l2(radio->core, rangelow); 760 } 761 if (!rangehigh) { 762 err = regmap_read(radio->core->regmap, 763 SI476X_PROP_SEEK_BAND_TOP, 764 &rangehigh); 765 if (err) 766 goto unlock; 767 rangehigh = si476x_to_v4l2(radio->core, rangehigh); 768 } 769 770 if (rangelow > rangehigh) { 771 err = -EINVAL; 772 goto unlock; 773 } 774 775 if (si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh, 776 SI476X_BAND_FM)) { 777 func = SI476X_FUNC_FM_RECEIVER; 778 779 } else if (si476x_core_has_am(radio->core) && 780 si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh, 781 SI476X_BAND_AM)) { 782 func = SI476X_FUNC_AM_RECEIVER; 783 } else { 784 err = -EINVAL; 785 goto unlock; 786 } 787 788 err = si476x_radio_change_func(radio, func); 789 if (err < 0) 790 goto unlock; 791 792 if (seek->rangehigh) { 793 err = regmap_write(radio->core->regmap, 794 SI476X_PROP_SEEK_BAND_TOP, 795 v4l2_to_si476x(radio->core, 796 seek->rangehigh)); 797 if (err) 798 goto unlock; 799 } 800 if (seek->rangelow) { 801 err = regmap_write(radio->core->regmap, 802 SI476X_PROP_SEEK_BAND_BOTTOM, 803 v4l2_to_si476x(radio->core, 804 seek->rangelow)); 805 if (err) 806 goto unlock; 807 } 808 if (seek->spacing) { 809 err = regmap_write(radio->core->regmap, 810 SI476X_PROP_SEEK_FREQUENCY_SPACING, 811 v4l2_to_si476x(radio->core, 812 seek->spacing)); 813 if (err) 814 goto unlock; 815 } 816 817 err = radio->ops->seek_start(radio->core, 818 seek->seek_upward, 819 seek->wrap_around); 820 unlock: 821 si476x_core_unlock(radio->core); 822 823 824 825 return err; 826 } 827 828 static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl) 829 { 830 int retval; 831 struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler); 832 833 si476x_core_lock(radio->core); 834 835 switch (ctrl->id) { 836 case V4L2_CID_SI476X_INTERCHIP_LINK: 837 if (si476x_core_has_diversity(radio->core)) { 838 if (radio->ops->phase_diversity) { 839 retval = radio->ops->phase_div_status(radio->core); 840 if (retval < 0) 841 break; 842 843 ctrl->val = !!SI476X_PHDIV_STATUS_LINK_LOCKED(retval); 844 retval = 0; 845 break; 846 } else { 847 retval = -ENOTTY; 848 break; 849 } 850 } 851 retval = -EINVAL; 852 break; 853 default: 854 retval = -EINVAL; 855 break; 856 } 857 si476x_core_unlock(radio->core); 858 return retval; 859 860 } 861 862 static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl) 863 { 864 int retval; 865 enum si476x_phase_diversity_mode mode; 866 struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler); 867 868 si476x_core_lock(radio->core); 869 870 switch (ctrl->id) { 871 case V4L2_CID_SI476X_HARMONICS_COUNT: 872 retval = regmap_update_bits(radio->core->regmap, 873 SI476X_PROP_AUDIO_PWR_LINE_FILTER, 874 SI476X_PROP_PWR_HARMONICS_MASK, 875 ctrl->val); 876 break; 877 case V4L2_CID_POWER_LINE_FREQUENCY: 878 switch (ctrl->val) { 879 case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: 880 retval = regmap_update_bits(radio->core->regmap, 881 SI476X_PROP_AUDIO_PWR_LINE_FILTER, 882 SI476X_PROP_PWR_ENABLE_MASK, 883 0); 884 break; 885 case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: 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_50HZ); 890 break; 891 case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: 892 retval = regmap_update_bits(radio->core->regmap, 893 SI476X_PROP_AUDIO_PWR_LINE_FILTER, 894 SI476X_PROP_PWR_GRID_MASK, 895 SI476X_PROP_PWR_GRID_60HZ); 896 break; 897 default: 898 retval = -EINVAL; 899 break; 900 } 901 break; 902 case V4L2_CID_SI476X_RSSI_THRESHOLD: 903 retval = regmap_write(radio->core->regmap, 904 SI476X_PROP_VALID_RSSI_THRESHOLD, 905 ctrl->val); 906 break; 907 case V4L2_CID_SI476X_SNR_THRESHOLD: 908 retval = regmap_write(radio->core->regmap, 909 SI476X_PROP_VALID_SNR_THRESHOLD, 910 ctrl->val); 911 break; 912 case V4L2_CID_SI476X_MAX_TUNE_ERROR: 913 retval = regmap_write(radio->core->regmap, 914 SI476X_PROP_VALID_MAX_TUNE_ERROR, 915 ctrl->val); 916 break; 917 case V4L2_CID_RDS_RECEPTION: 918 /* 919 * It looks like RDS related properties are 920 * inaccessible when tuner is in AM mode, so cache the 921 * changes 922 */ 923 if (si476x_core_is_in_am_receiver_mode(radio->core)) 924 regcache_cache_only(radio->core->regmap, true); 925 926 if (ctrl->val) { 927 retval = regmap_write(radio->core->regmap, 928 SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT, 929 radio->core->rds_fifo_depth); 930 if (retval < 0) 931 break; 932 933 if (radio->core->client->irq) { 934 retval = regmap_write(radio->core->regmap, 935 SI476X_PROP_FM_RDS_INTERRUPT_SOURCE, 936 SI476X_RDSRECV); 937 if (retval < 0) 938 break; 939 } 940 941 /* Drain RDS FIFO before enabling RDS processing */ 942 retval = si476x_core_cmd_fm_rds_status(radio->core, 943 false, 944 true, 945 true, 946 NULL); 947 if (retval < 0) 948 break; 949 950 retval = regmap_update_bits(radio->core->regmap, 951 SI476X_PROP_FM_RDS_CONFIG, 952 SI476X_PROP_RDSEN_MASK, 953 SI476X_PROP_RDSEN); 954 } else { 955 retval = regmap_update_bits(radio->core->regmap, 956 SI476X_PROP_FM_RDS_CONFIG, 957 SI476X_PROP_RDSEN_MASK, 958 !SI476X_PROP_RDSEN); 959 } 960 961 if (si476x_core_is_in_am_receiver_mode(radio->core)) 962 regcache_cache_only(radio->core->regmap, false); 963 break; 964 case V4L2_CID_TUNE_DEEMPHASIS: 965 retval = regmap_write(radio->core->regmap, 966 SI476X_PROP_AUDIO_DEEMPHASIS, 967 ctrl->val); 968 break; 969 970 case V4L2_CID_SI476X_DIVERSITY_MODE: 971 mode = si476x_phase_diversity_idx_to_mode(ctrl->val); 972 973 if (mode == radio->core->diversity_mode) { 974 retval = 0; 975 break; 976 } 977 978 if (si476x_core_is_in_am_receiver_mode(radio->core)) { 979 /* 980 * Diversity cannot be configured while tuner 981 * is in AM mode so save the changes and carry on. 982 */ 983 radio->core->diversity_mode = mode; 984 retval = 0; 985 } else { 986 retval = radio->ops->phase_diversity(radio->core, mode); 987 if (!retval) 988 radio->core->diversity_mode = mode; 989 } 990 break; 991 992 default: 993 retval = -EINVAL; 994 break; 995 } 996 997 si476x_core_unlock(radio->core); 998 999 return retval; 1000 } 1001 1002 #ifdef CONFIG_VIDEO_ADV_DEBUG 1003 static int si476x_radio_g_register(struct file *file, void *fh, 1004 struct v4l2_dbg_register *reg) 1005 { 1006 int err; 1007 unsigned int value; 1008 struct si476x_radio *radio = video_drvdata(file); 1009 1010 si476x_core_lock(radio->core); 1011 reg->size = 2; 1012 err = regmap_read(radio->core->regmap, 1013 (unsigned int)reg->reg, &value); 1014 reg->val = value; 1015 si476x_core_unlock(radio->core); 1016 1017 return err; 1018 } 1019 static int si476x_radio_s_register(struct file *file, void *fh, 1020 const struct v4l2_dbg_register *reg) 1021 { 1022 1023 int err; 1024 struct si476x_radio *radio = video_drvdata(file); 1025 1026 si476x_core_lock(radio->core); 1027 err = regmap_write(radio->core->regmap, 1028 (unsigned int)reg->reg, 1029 (unsigned int)reg->val); 1030 si476x_core_unlock(radio->core); 1031 1032 return err; 1033 } 1034 #endif 1035 1036 static int si476x_radio_fops_open(struct file *file) 1037 { 1038 struct si476x_radio *radio = video_drvdata(file); 1039 int err; 1040 1041 err = v4l2_fh_open(file); 1042 if (err) 1043 return err; 1044 1045 if (v4l2_fh_is_singular_file(file)) { 1046 si476x_core_lock(radio->core); 1047 err = si476x_core_set_power_state(radio->core, 1048 SI476X_POWER_UP_FULL); 1049 if (err < 0) 1050 goto done; 1051 1052 err = si476x_radio_do_post_powerup_init(radio, 1053 radio->core->power_up_parameters.func); 1054 if (err < 0) 1055 goto power_down; 1056 1057 err = si476x_radio_pretune(radio, 1058 radio->core->power_up_parameters.func); 1059 if (err < 0) 1060 goto power_down; 1061 1062 si476x_core_unlock(radio->core); 1063 /*Must be done after si476x_core_unlock to prevent a deadlock*/ 1064 v4l2_ctrl_handler_setup(&radio->ctrl_handler); 1065 } 1066 1067 return err; 1068 1069 power_down: 1070 si476x_core_set_power_state(radio->core, 1071 SI476X_POWER_DOWN); 1072 done: 1073 si476x_core_unlock(radio->core); 1074 v4l2_fh_release(file); 1075 1076 return err; 1077 } 1078 1079 static int si476x_radio_fops_release(struct file *file) 1080 { 1081 int err; 1082 struct si476x_radio *radio = video_drvdata(file); 1083 1084 if (v4l2_fh_is_singular_file(file) && 1085 atomic_read(&radio->core->is_alive)) 1086 si476x_core_set_power_state(radio->core, 1087 SI476X_POWER_DOWN); 1088 1089 err = v4l2_fh_release(file); 1090 1091 return err; 1092 } 1093 1094 static ssize_t si476x_radio_fops_read(struct file *file, char __user *buf, 1095 size_t count, loff_t *ppos) 1096 { 1097 ssize_t rval; 1098 size_t fifo_len; 1099 unsigned int copied; 1100 1101 struct si476x_radio *radio = video_drvdata(file); 1102 1103 /* block if no new data available */ 1104 if (kfifo_is_empty(&radio->core->rds_fifo)) { 1105 if (file->f_flags & O_NONBLOCK) 1106 return -EWOULDBLOCK; 1107 1108 rval = wait_event_interruptible(radio->core->rds_read_queue, 1109 (!kfifo_is_empty(&radio->core->rds_fifo) || 1110 !atomic_read(&radio->core->is_alive))); 1111 if (rval < 0) 1112 return -EINTR; 1113 1114 if (!atomic_read(&radio->core->is_alive)) 1115 return -ENODEV; 1116 } 1117 1118 fifo_len = kfifo_len(&radio->core->rds_fifo); 1119 1120 if (kfifo_to_user(&radio->core->rds_fifo, buf, 1121 min(fifo_len, count), 1122 &copied) != 0) { 1123 dev_warn(&radio->videodev.dev, 1124 "Error during FIFO to userspace copy\n"); 1125 rval = -EIO; 1126 } else { 1127 rval = (ssize_t)copied; 1128 } 1129 1130 return rval; 1131 } 1132 1133 static __poll_t si476x_radio_fops_poll(struct file *file, 1134 struct poll_table_struct *pts) 1135 { 1136 struct si476x_radio *radio = video_drvdata(file); 1137 __poll_t req_events = poll_requested_events(pts); 1138 __poll_t err = v4l2_ctrl_poll(file, pts); 1139 1140 if (req_events & (EPOLLIN | EPOLLRDNORM)) { 1141 if (atomic_read(&radio->core->is_alive)) 1142 poll_wait(file, &radio->core->rds_read_queue, pts); 1143 1144 if (!atomic_read(&radio->core->is_alive)) 1145 err = EPOLLHUP; 1146 1147 if (!kfifo_is_empty(&radio->core->rds_fifo)) 1148 err = EPOLLIN | EPOLLRDNORM; 1149 } 1150 1151 return err; 1152 } 1153 1154 static const struct v4l2_file_operations si476x_fops = { 1155 .owner = THIS_MODULE, 1156 .read = si476x_radio_fops_read, 1157 .poll = si476x_radio_fops_poll, 1158 .unlocked_ioctl = video_ioctl2, 1159 .open = si476x_radio_fops_open, 1160 .release = si476x_radio_fops_release, 1161 }; 1162 1163 1164 static const struct v4l2_ioctl_ops si4761_ioctl_ops = { 1165 .vidioc_querycap = si476x_radio_querycap, 1166 .vidioc_g_tuner = si476x_radio_g_tuner, 1167 .vidioc_s_tuner = si476x_radio_s_tuner, 1168 1169 .vidioc_g_frequency = si476x_radio_g_frequency, 1170 .vidioc_s_frequency = si476x_radio_s_frequency, 1171 .vidioc_s_hw_freq_seek = si476x_radio_s_hw_freq_seek, 1172 .vidioc_enum_freq_bands = si476x_radio_enum_freq_bands, 1173 1174 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 1175 .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 1176 1177 #ifdef CONFIG_VIDEO_ADV_DEBUG 1178 .vidioc_g_register = si476x_radio_g_register, 1179 .vidioc_s_register = si476x_radio_s_register, 1180 #endif 1181 }; 1182 1183 1184 static const struct video_device si476x_viddev_template = { 1185 .fops = &si476x_fops, 1186 .name = DRIVER_NAME, 1187 .release = video_device_release_empty, 1188 }; 1189 1190 1191 1192 static ssize_t si476x_radio_read_acf_blob(struct file *file, 1193 char __user *user_buf, 1194 size_t count, loff_t *ppos) 1195 { 1196 int err; 1197 struct si476x_radio *radio = file->private_data; 1198 struct si476x_acf_status_report report; 1199 1200 si476x_core_lock(radio->core); 1201 if (radio->ops->acf_status) 1202 err = radio->ops->acf_status(radio->core, &report); 1203 else 1204 err = -ENOENT; 1205 si476x_core_unlock(radio->core); 1206 1207 if (err < 0) 1208 return err; 1209 1210 return simple_read_from_buffer(user_buf, count, ppos, &report, 1211 sizeof(report)); 1212 } 1213 1214 static const struct file_operations radio_acf_fops = { 1215 .open = simple_open, 1216 .llseek = default_llseek, 1217 .read = si476x_radio_read_acf_blob, 1218 }; 1219 1220 static ssize_t si476x_radio_read_rds_blckcnt_blob(struct file *file, 1221 char __user *user_buf, 1222 size_t count, loff_t *ppos) 1223 { 1224 int err; 1225 struct si476x_radio *radio = file->private_data; 1226 struct si476x_rds_blockcount_report report; 1227 1228 si476x_core_lock(radio->core); 1229 if (radio->ops->rds_blckcnt) 1230 err = radio->ops->rds_blckcnt(radio->core, true, 1231 &report); 1232 else 1233 err = -ENOENT; 1234 si476x_core_unlock(radio->core); 1235 1236 if (err < 0) 1237 return err; 1238 1239 return simple_read_from_buffer(user_buf, count, ppos, &report, 1240 sizeof(report)); 1241 } 1242 1243 static const struct file_operations radio_rds_blckcnt_fops = { 1244 .open = simple_open, 1245 .llseek = default_llseek, 1246 .read = si476x_radio_read_rds_blckcnt_blob, 1247 }; 1248 1249 static ssize_t si476x_radio_read_agc_blob(struct file *file, 1250 char __user *user_buf, 1251 size_t count, loff_t *ppos) 1252 { 1253 int err; 1254 struct si476x_radio *radio = file->private_data; 1255 struct si476x_agc_status_report report; 1256 1257 si476x_core_lock(radio->core); 1258 if (radio->ops->rds_blckcnt) 1259 err = radio->ops->agc_status(radio->core, &report); 1260 else 1261 err = -ENOENT; 1262 si476x_core_unlock(radio->core); 1263 1264 if (err < 0) 1265 return err; 1266 1267 return simple_read_from_buffer(user_buf, count, ppos, &report, 1268 sizeof(report)); 1269 } 1270 1271 static const struct file_operations radio_agc_fops = { 1272 .open = simple_open, 1273 .llseek = default_llseek, 1274 .read = si476x_radio_read_agc_blob, 1275 }; 1276 1277 static ssize_t si476x_radio_read_rsq_blob(struct file *file, 1278 char __user *user_buf, 1279 size_t count, loff_t *ppos) 1280 { 1281 int err; 1282 struct si476x_radio *radio = file->private_data; 1283 struct si476x_rsq_status_report report; 1284 struct si476x_rsq_status_args args = { 1285 .primary = false, 1286 .rsqack = false, 1287 .attune = false, 1288 .cancel = false, 1289 .stcack = false, 1290 }; 1291 1292 si476x_core_lock(radio->core); 1293 if (radio->ops->rds_blckcnt) 1294 err = radio->ops->rsq_status(radio->core, &args, &report); 1295 else 1296 err = -ENOENT; 1297 si476x_core_unlock(radio->core); 1298 1299 if (err < 0) 1300 return err; 1301 1302 return simple_read_from_buffer(user_buf, count, ppos, &report, 1303 sizeof(report)); 1304 } 1305 1306 static const struct file_operations radio_rsq_fops = { 1307 .open = simple_open, 1308 .llseek = default_llseek, 1309 .read = si476x_radio_read_rsq_blob, 1310 }; 1311 1312 static ssize_t si476x_radio_read_rsq_primary_blob(struct file *file, 1313 char __user *user_buf, 1314 size_t count, loff_t *ppos) 1315 { 1316 int err; 1317 struct si476x_radio *radio = file->private_data; 1318 struct si476x_rsq_status_report report; 1319 struct si476x_rsq_status_args args = { 1320 .primary = true, 1321 .rsqack = false, 1322 .attune = false, 1323 .cancel = false, 1324 .stcack = false, 1325 }; 1326 1327 si476x_core_lock(radio->core); 1328 if (radio->ops->rds_blckcnt) 1329 err = radio->ops->rsq_status(radio->core, &args, &report); 1330 else 1331 err = -ENOENT; 1332 si476x_core_unlock(radio->core); 1333 1334 if (err < 0) 1335 return err; 1336 1337 return simple_read_from_buffer(user_buf, count, ppos, &report, 1338 sizeof(report)); 1339 } 1340 1341 static const struct file_operations radio_rsq_primary_fops = { 1342 .open = simple_open, 1343 .llseek = default_llseek, 1344 .read = si476x_radio_read_rsq_primary_blob, 1345 }; 1346 1347 1348 static void si476x_radio_init_debugfs(struct si476x_radio *radio) 1349 { 1350 radio->debugfs = debugfs_create_dir(dev_name(radio->v4l2dev.dev), NULL); 1351 1352 debugfs_create_file("acf", S_IRUGO, radio->debugfs, radio, 1353 &radio_acf_fops); 1354 1355 debugfs_create_file("rds_blckcnt", S_IRUGO, radio->debugfs, radio, 1356 &radio_rds_blckcnt_fops); 1357 1358 debugfs_create_file("agc", S_IRUGO, radio->debugfs, radio, 1359 &radio_agc_fops); 1360 1361 debugfs_create_file("rsq", S_IRUGO, radio->debugfs, radio, 1362 &radio_rsq_fops); 1363 1364 debugfs_create_file("rsq_primary", S_IRUGO, radio->debugfs, radio, 1365 &radio_rsq_primary_fops); 1366 } 1367 1368 1369 static int si476x_radio_add_new_custom(struct si476x_radio *radio, 1370 enum si476x_ctrl_idx idx) 1371 { 1372 int rval; 1373 struct v4l2_ctrl *ctrl; 1374 1375 ctrl = v4l2_ctrl_new_custom(&radio->ctrl_handler, 1376 &si476x_ctrls[idx], 1377 NULL); 1378 rval = radio->ctrl_handler.error; 1379 if (ctrl == NULL && rval) 1380 dev_err(radio->v4l2dev.dev, 1381 "Could not initialize '%s' control %d\n", 1382 si476x_ctrls[idx].name, rval); 1383 1384 return rval; 1385 } 1386 1387 static int si476x_radio_probe(struct platform_device *pdev) 1388 { 1389 int rval; 1390 struct si476x_radio *radio; 1391 struct v4l2_ctrl *ctrl; 1392 1393 static atomic_t instance = ATOMIC_INIT(0); 1394 1395 radio = devm_kzalloc(&pdev->dev, sizeof(*radio), GFP_KERNEL); 1396 if (!radio) 1397 return -ENOMEM; 1398 1399 radio->core = i2c_mfd_cell_to_core(&pdev->dev); 1400 1401 v4l2_device_set_name(&radio->v4l2dev, DRIVER_NAME, &instance); 1402 1403 rval = v4l2_device_register(&pdev->dev, &radio->v4l2dev); 1404 if (rval) { 1405 dev_err(&pdev->dev, "Cannot register v4l2_device.\n"); 1406 return rval; 1407 } 1408 1409 memcpy(&radio->videodev, &si476x_viddev_template, 1410 sizeof(struct video_device)); 1411 1412 radio->videodev.v4l2_dev = &radio->v4l2dev; 1413 radio->videodev.ioctl_ops = &si4761_ioctl_ops; 1414 radio->videodev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | 1415 V4L2_CAP_HW_FREQ_SEEK; 1416 1417 si476x_core_lock(radio->core); 1418 if (!si476x_core_is_a_secondary_tuner(radio->core)) 1419 radio->videodev.device_caps |= V4L2_CAP_RDS_CAPTURE | 1420 V4L2_CAP_READWRITE; 1421 si476x_core_unlock(radio->core); 1422 1423 video_set_drvdata(&radio->videodev, radio); 1424 platform_set_drvdata(pdev, radio); 1425 1426 1427 radio->v4l2dev.ctrl_handler = &radio->ctrl_handler; 1428 v4l2_ctrl_handler_init(&radio->ctrl_handler, 1429 1 + ARRAY_SIZE(si476x_ctrls)); 1430 1431 if (si476x_core_has_am(radio->core)) { 1432 ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler, 1433 &si476x_ctrl_ops, 1434 V4L2_CID_POWER_LINE_FREQUENCY, 1435 V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 1436 0, 0); 1437 rval = radio->ctrl_handler.error; 1438 if (ctrl == NULL && rval) { 1439 dev_err(&pdev->dev, "Could not initialize V4L2_CID_POWER_LINE_FREQUENCY control %d\n", 1440 rval); 1441 goto exit; 1442 } 1443 1444 rval = si476x_radio_add_new_custom(radio, 1445 SI476X_IDX_HARMONICS_COUNT); 1446 if (rval < 0) 1447 goto exit; 1448 } 1449 1450 rval = si476x_radio_add_new_custom(radio, SI476X_IDX_RSSI_THRESHOLD); 1451 if (rval < 0) 1452 goto exit; 1453 1454 rval = si476x_radio_add_new_custom(radio, SI476X_IDX_SNR_THRESHOLD); 1455 if (rval < 0) 1456 goto exit; 1457 1458 rval = si476x_radio_add_new_custom(radio, SI476X_IDX_MAX_TUNE_ERROR); 1459 if (rval < 0) 1460 goto exit; 1461 1462 ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler, 1463 &si476x_ctrl_ops, 1464 V4L2_CID_TUNE_DEEMPHASIS, 1465 V4L2_DEEMPHASIS_75_uS, 0, 0); 1466 rval = radio->ctrl_handler.error; 1467 if (ctrl == NULL && rval) { 1468 dev_err(&pdev->dev, "Could not initialize V4L2_CID_TUNE_DEEMPHASIS control %d\n", 1469 rval); 1470 goto exit; 1471 } 1472 1473 ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &si476x_ctrl_ops, 1474 V4L2_CID_RDS_RECEPTION, 1475 0, 1, 1, 1); 1476 rval = radio->ctrl_handler.error; 1477 if (ctrl == NULL && rval) { 1478 dev_err(&pdev->dev, "Could not initialize V4L2_CID_RDS_RECEPTION control %d\n", 1479 rval); 1480 goto exit; 1481 } 1482 1483 if (si476x_core_has_diversity(radio->core)) { 1484 si476x_ctrls[SI476X_IDX_DIVERSITY_MODE].def = 1485 si476x_phase_diversity_mode_to_idx(radio->core->diversity_mode); 1486 rval = si476x_radio_add_new_custom(radio, SI476X_IDX_DIVERSITY_MODE); 1487 if (rval < 0) 1488 goto exit; 1489 1490 rval = si476x_radio_add_new_custom(radio, SI476X_IDX_INTERCHIP_LINK); 1491 if (rval < 0) 1492 goto exit; 1493 } 1494 1495 /* register video device */ 1496 rval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, -1); 1497 if (rval < 0) { 1498 dev_err(&pdev->dev, "Could not register video device\n"); 1499 goto exit; 1500 } 1501 1502 si476x_radio_init_debugfs(radio); 1503 1504 return 0; 1505 exit: 1506 v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); 1507 return rval; 1508 } 1509 1510 static int si476x_radio_remove(struct platform_device *pdev) 1511 { 1512 struct si476x_radio *radio = platform_get_drvdata(pdev); 1513 1514 v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); 1515 video_unregister_device(&radio->videodev); 1516 v4l2_device_unregister(&radio->v4l2dev); 1517 debugfs_remove_recursive(radio->debugfs); 1518 1519 return 0; 1520 } 1521 1522 MODULE_ALIAS("platform:si476x-radio"); 1523 1524 static struct platform_driver si476x_radio_driver = { 1525 .driver = { 1526 .name = DRIVER_NAME, 1527 }, 1528 .probe = si476x_radio_probe, 1529 .remove = si476x_radio_remove, 1530 }; 1531 module_platform_driver(si476x_radio_driver); 1532 1533 MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>"); 1534 MODULE_DESCRIPTION("Driver for Si4761/64/68 AM/FM Radio MFD Cell"); 1535 MODULE_LICENSE("GPL"); 1536