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