0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/module.h>
0013 #include <linux/completion.h>
0014 #include <linux/delay.h>
0015 #include <linux/atomic.h>
0016 #include <linux/i2c.h>
0017 #include <linux/device.h>
0018 #include <linux/gpio.h>
0019 #include <linux/videodev2.h>
0020
0021 #include <linux/mfd/si476x-core.h>
0022
0023 #include <asm/unaligned.h>
0024
0025 #define msb(x) ((u8)((u16) x >> 8))
0026 #define lsb(x) ((u8)((u16) x & 0x00FF))
0027
0028
0029
0030 #define CMD_POWER_UP 0x01
0031 #define CMD_POWER_UP_A10_NRESP 1
0032 #define CMD_POWER_UP_A10_NARGS 5
0033
0034 #define CMD_POWER_UP_A20_NRESP 1
0035 #define CMD_POWER_UP_A20_NARGS 5
0036
0037 #define POWER_UP_DELAY_MS 110
0038
0039 #define CMD_POWER_DOWN 0x11
0040 #define CMD_POWER_DOWN_A10_NRESP 1
0041
0042 #define CMD_POWER_DOWN_A20_NRESP 1
0043 #define CMD_POWER_DOWN_A20_NARGS 1
0044
0045 #define CMD_FUNC_INFO 0x12
0046 #define CMD_FUNC_INFO_NRESP 7
0047
0048 #define CMD_SET_PROPERTY 0x13
0049 #define CMD_SET_PROPERTY_NARGS 5
0050 #define CMD_SET_PROPERTY_NRESP 1
0051
0052 #define CMD_GET_PROPERTY 0x14
0053 #define CMD_GET_PROPERTY_NARGS 3
0054 #define CMD_GET_PROPERTY_NRESP 4
0055
0056 #define CMD_AGC_STATUS 0x17
0057 #define CMD_AGC_STATUS_NRESP_A10 2
0058 #define CMD_AGC_STATUS_NRESP_A20 6
0059
0060 #define PIN_CFG_BYTE(x) (0x7F & (x))
0061 #define CMD_DIG_AUDIO_PIN_CFG 0x18
0062 #define CMD_DIG_AUDIO_PIN_CFG_NARGS 4
0063 #define CMD_DIG_AUDIO_PIN_CFG_NRESP 5
0064
0065 #define CMD_ZIF_PIN_CFG 0x19
0066 #define CMD_ZIF_PIN_CFG_NARGS 4
0067 #define CMD_ZIF_PIN_CFG_NRESP 5
0068
0069 #define CMD_IC_LINK_GPO_CTL_PIN_CFG 0x1A
0070 #define CMD_IC_LINK_GPO_CTL_PIN_CFG_NARGS 4
0071 #define CMD_IC_LINK_GPO_CTL_PIN_CFG_NRESP 5
0072
0073 #define CMD_ANA_AUDIO_PIN_CFG 0x1B
0074 #define CMD_ANA_AUDIO_PIN_CFG_NARGS 1
0075 #define CMD_ANA_AUDIO_PIN_CFG_NRESP 2
0076
0077 #define CMD_INTB_PIN_CFG 0x1C
0078 #define CMD_INTB_PIN_CFG_NARGS 2
0079 #define CMD_INTB_PIN_CFG_A10_NRESP 6
0080 #define CMD_INTB_PIN_CFG_A20_NRESP 3
0081
0082 #define CMD_FM_TUNE_FREQ 0x30
0083 #define CMD_FM_TUNE_FREQ_A10_NARGS 5
0084 #define CMD_FM_TUNE_FREQ_A20_NARGS 3
0085 #define CMD_FM_TUNE_FREQ_NRESP 1
0086
0087 #define CMD_FM_RSQ_STATUS 0x32
0088
0089 #define CMD_FM_RSQ_STATUS_A10_NARGS 1
0090 #define CMD_FM_RSQ_STATUS_A10_NRESP 17
0091 #define CMD_FM_RSQ_STATUS_A30_NARGS 1
0092 #define CMD_FM_RSQ_STATUS_A30_NRESP 23
0093
0094
0095 #define CMD_FM_SEEK_START 0x31
0096 #define CMD_FM_SEEK_START_NARGS 1
0097 #define CMD_FM_SEEK_START_NRESP 1
0098
0099 #define CMD_FM_RDS_STATUS 0x36
0100 #define CMD_FM_RDS_STATUS_NARGS 1
0101 #define CMD_FM_RDS_STATUS_NRESP 16
0102
0103 #define CMD_FM_RDS_BLOCKCOUNT 0x37
0104 #define CMD_FM_RDS_BLOCKCOUNT_NARGS 1
0105 #define CMD_FM_RDS_BLOCKCOUNT_NRESP 8
0106
0107 #define CMD_FM_PHASE_DIVERSITY 0x38
0108 #define CMD_FM_PHASE_DIVERSITY_NARGS 1
0109 #define CMD_FM_PHASE_DIVERSITY_NRESP 1
0110
0111 #define CMD_FM_PHASE_DIV_STATUS 0x39
0112 #define CMD_FM_PHASE_DIV_STATUS_NRESP 2
0113
0114 #define CMD_AM_TUNE_FREQ 0x40
0115 #define CMD_AM_TUNE_FREQ_NARGS 3
0116 #define CMD_AM_TUNE_FREQ_NRESP 1
0117
0118 #define CMD_AM_RSQ_STATUS 0x42
0119 #define CMD_AM_RSQ_STATUS_NARGS 1
0120 #define CMD_AM_RSQ_STATUS_NRESP 13
0121
0122 #define CMD_AM_SEEK_START 0x41
0123 #define CMD_AM_SEEK_START_NARGS 1
0124 #define CMD_AM_SEEK_START_NRESP 1
0125
0126
0127 #define CMD_AM_ACF_STATUS 0x45
0128 #define CMD_AM_ACF_STATUS_NRESP 6
0129 #define CMD_AM_ACF_STATUS_NARGS 1
0130
0131 #define CMD_FM_ACF_STATUS 0x35
0132 #define CMD_FM_ACF_STATUS_NRESP 8
0133 #define CMD_FM_ACF_STATUS_NARGS 1
0134
0135 #define CMD_MAX_ARGS_COUNT (10)
0136
0137
0138 enum si476x_acf_status_report_bits {
0139 SI476X_ACF_BLEND_INT = (1 << 4),
0140 SI476X_ACF_HIBLEND_INT = (1 << 3),
0141 SI476X_ACF_HICUT_INT = (1 << 2),
0142 SI476X_ACF_CHBW_INT = (1 << 1),
0143 SI476X_ACF_SOFTMUTE_INT = (1 << 0),
0144
0145 SI476X_ACF_SMUTE = (1 << 0),
0146 SI476X_ACF_SMATTN = 0x1f,
0147 SI476X_ACF_PILOT = (1 << 7),
0148 SI476X_ACF_STBLEND = ~SI476X_ACF_PILOT,
0149 };
0150
0151 enum si476x_agc_status_report_bits {
0152 SI476X_AGC_MXHI = (1 << 5),
0153 SI476X_AGC_MXLO = (1 << 4),
0154 SI476X_AGC_LNAHI = (1 << 3),
0155 SI476X_AGC_LNALO = (1 << 2),
0156 };
0157
0158 enum si476x_errors {
0159 SI476X_ERR_BAD_COMMAND = 0x10,
0160 SI476X_ERR_BAD_ARG1 = 0x11,
0161 SI476X_ERR_BAD_ARG2 = 0x12,
0162 SI476X_ERR_BAD_ARG3 = 0x13,
0163 SI476X_ERR_BAD_ARG4 = 0x14,
0164 SI476X_ERR_BUSY = 0x18,
0165 SI476X_ERR_BAD_INTERNAL_MEMORY = 0x20,
0166 SI476X_ERR_BAD_PATCH = 0x30,
0167 SI476X_ERR_BAD_BOOT_MODE = 0x31,
0168 SI476X_ERR_BAD_PROPERTY = 0x40,
0169 };
0170
0171 static int si476x_core_parse_and_nag_about_error(struct si476x_core *core)
0172 {
0173 int err;
0174 char *cause;
0175 u8 buffer[2];
0176
0177 if (core->revision != SI476X_REVISION_A10) {
0178 err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV,
0179 buffer, sizeof(buffer));
0180 if (err == sizeof(buffer)) {
0181 switch (buffer[1]) {
0182 case SI476X_ERR_BAD_COMMAND:
0183 cause = "Bad command";
0184 err = -EINVAL;
0185 break;
0186 case SI476X_ERR_BAD_ARG1:
0187 cause = "Bad argument #1";
0188 err = -EINVAL;
0189 break;
0190 case SI476X_ERR_BAD_ARG2:
0191 cause = "Bad argument #2";
0192 err = -EINVAL;
0193 break;
0194 case SI476X_ERR_BAD_ARG3:
0195 cause = "Bad argument #3";
0196 err = -EINVAL;
0197 break;
0198 case SI476X_ERR_BAD_ARG4:
0199 cause = "Bad argument #4";
0200 err = -EINVAL;
0201 break;
0202 case SI476X_ERR_BUSY:
0203 cause = "Chip is busy";
0204 err = -EBUSY;
0205 break;
0206 case SI476X_ERR_BAD_INTERNAL_MEMORY:
0207 cause = "Bad internal memory";
0208 err = -EIO;
0209 break;
0210 case SI476X_ERR_BAD_PATCH:
0211 cause = "Bad patch";
0212 err = -EINVAL;
0213 break;
0214 case SI476X_ERR_BAD_BOOT_MODE:
0215 cause = "Bad boot mode";
0216 err = -EINVAL;
0217 break;
0218 case SI476X_ERR_BAD_PROPERTY:
0219 cause = "Bad property";
0220 err = -EINVAL;
0221 break;
0222 default:
0223 cause = "Unknown";
0224 err = -EIO;
0225 }
0226
0227 dev_err(&core->client->dev,
0228 "[Chip error status]: %s\n", cause);
0229 } else {
0230 dev_err(&core->client->dev,
0231 "Failed to fetch error code\n");
0232 err = (err >= 0) ? -EIO : err;
0233 }
0234 } else {
0235 err = -EIO;
0236 }
0237
0238 return err;
0239 }
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257 static int si476x_core_send_command(struct si476x_core *core,
0258 const u8 command,
0259 const u8 args[],
0260 const int argn,
0261 u8 resp[],
0262 const int respn,
0263 const int usecs)
0264 {
0265 struct i2c_client *client = core->client;
0266 int err;
0267 u8 data[CMD_MAX_ARGS_COUNT + 1];
0268
0269 if (argn > CMD_MAX_ARGS_COUNT) {
0270 err = -ENOMEM;
0271 goto exit;
0272 }
0273
0274 if (!client->adapter) {
0275 err = -ENODEV;
0276 goto exit;
0277 }
0278
0279
0280 data[0] = command;
0281 memcpy(&data[1], args, argn);
0282 dev_dbg(&client->dev, "Command:\n %*ph\n", argn + 1, data);
0283
0284 err = si476x_core_i2c_xfer(core, SI476X_I2C_SEND,
0285 (char *) data, argn + 1);
0286 if (err != argn + 1) {
0287 dev_err(&core->client->dev,
0288 "Error while sending command 0x%02x\n",
0289 command);
0290 err = (err >= 0) ? -EIO : err;
0291 goto exit;
0292 }
0293
0294
0295 atomic_set(&core->cts, 0);
0296
0297
0298 if (!wait_event_timeout(core->command,
0299 atomic_read(&core->cts),
0300 usecs_to_jiffies(usecs) + 1))
0301 dev_warn(&core->client->dev,
0302 "(%s) [CMD 0x%02x] Answer timeout.\n",
0303 __func__, command);
0304
0305
0306
0307
0308
0309
0310
0311
0312 if (unlikely(!core->client->irq && command == CMD_POWER_UP)) {
0313 if (!wait_event_timeout(core->command,
0314 atomic_read(&core->cts),
0315 usecs_to_jiffies(usecs) + 1))
0316 dev_warn(&core->client->dev,
0317 "(%s) Power up took too much time.\n",
0318 __func__);
0319 }
0320
0321
0322 err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, resp, respn);
0323 if (err != respn) {
0324 dev_err(&core->client->dev,
0325 "Error while reading response for command 0x%02x\n",
0326 command);
0327 err = (err >= 0) ? -EIO : err;
0328 goto exit;
0329 }
0330 dev_dbg(&client->dev, "Response:\n %*ph\n", respn, resp);
0331
0332 err = 0;
0333
0334 if (resp[0] & SI476X_ERR) {
0335 dev_err(&core->client->dev,
0336 "[CMD 0x%02x] Chip set error flag\n", command);
0337 err = si476x_core_parse_and_nag_about_error(core);
0338 goto exit;
0339 }
0340
0341 if (!(resp[0] & SI476X_CTS))
0342 err = -EBUSY;
0343 exit:
0344 return err;
0345 }
0346
0347 static int si476x_cmd_clear_stc(struct si476x_core *core)
0348 {
0349 int err;
0350 struct si476x_rsq_status_args args = {
0351 .primary = false,
0352 .rsqack = false,
0353 .attune = false,
0354 .cancel = false,
0355 .stcack = true,
0356 };
0357
0358 switch (core->power_up_parameters.func) {
0359 case SI476X_FUNC_FM_RECEIVER:
0360 err = si476x_core_cmd_fm_rsq_status(core, &args, NULL);
0361 break;
0362 case SI476X_FUNC_AM_RECEIVER:
0363 err = si476x_core_cmd_am_rsq_status(core, &args, NULL);
0364 break;
0365 default:
0366 err = -EINVAL;
0367 }
0368
0369 return err;
0370 }
0371
0372 static int si476x_cmd_tune_seek_freq(struct si476x_core *core,
0373 uint8_t cmd,
0374 const uint8_t args[], size_t argn,
0375 uint8_t *resp, size_t respn)
0376 {
0377 int err;
0378
0379
0380 atomic_set(&core->stc, 0);
0381 err = si476x_core_send_command(core, cmd, args, argn, resp, respn,
0382 SI476X_TIMEOUT_TUNE);
0383 if (!err) {
0384 wait_event_killable(core->tuning,
0385 atomic_read(&core->stc));
0386 si476x_cmd_clear_stc(core);
0387 }
0388
0389 return err;
0390 }
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404 int si476x_core_cmd_func_info(struct si476x_core *core,
0405 struct si476x_func_info *info)
0406 {
0407 int err;
0408 u8 resp[CMD_FUNC_INFO_NRESP];
0409
0410 err = si476x_core_send_command(core, CMD_FUNC_INFO,
0411 NULL, 0,
0412 resp, ARRAY_SIZE(resp),
0413 SI476X_DEFAULT_TIMEOUT);
0414
0415 info->firmware.major = resp[1];
0416 info->firmware.minor[0] = resp[2];
0417 info->firmware.minor[1] = resp[3];
0418
0419 info->patch_id = ((u16) resp[4] << 8) | resp[5];
0420 info->func = resp[6];
0421
0422 return err;
0423 }
0424 EXPORT_SYMBOL_GPL(si476x_core_cmd_func_info);
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435 int si476x_core_cmd_set_property(struct si476x_core *core,
0436 u16 property, u16 value)
0437 {
0438 u8 resp[CMD_SET_PROPERTY_NRESP];
0439 const u8 args[CMD_SET_PROPERTY_NARGS] = {
0440 0x00,
0441 msb(property),
0442 lsb(property),
0443 msb(value),
0444 lsb(value),
0445 };
0446
0447 return si476x_core_send_command(core, CMD_SET_PROPERTY,
0448 args, ARRAY_SIZE(args),
0449 resp, ARRAY_SIZE(resp),
0450 SI476X_DEFAULT_TIMEOUT);
0451 }
0452 EXPORT_SYMBOL_GPL(si476x_core_cmd_set_property);
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462 int si476x_core_cmd_get_property(struct si476x_core *core, u16 property)
0463 {
0464 int err;
0465 u8 resp[CMD_GET_PROPERTY_NRESP];
0466 const u8 args[CMD_GET_PROPERTY_NARGS] = {
0467 0x00,
0468 msb(property),
0469 lsb(property),
0470 };
0471
0472 err = si476x_core_send_command(core, CMD_GET_PROPERTY,
0473 args, ARRAY_SIZE(args),
0474 resp, ARRAY_SIZE(resp),
0475 SI476X_DEFAULT_TIMEOUT);
0476 if (err < 0)
0477 return err;
0478 else
0479 return get_unaligned_be16(resp + 2);
0480 }
0481 EXPORT_SYMBOL_GPL(si476x_core_cmd_get_property);
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520 int si476x_core_cmd_dig_audio_pin_cfg(struct si476x_core *core,
0521 enum si476x_dclk_config dclk,
0522 enum si476x_dfs_config dfs,
0523 enum si476x_dout_config dout,
0524 enum si476x_xout_config xout)
0525 {
0526 u8 resp[CMD_DIG_AUDIO_PIN_CFG_NRESP];
0527 const u8 args[CMD_DIG_AUDIO_PIN_CFG_NARGS] = {
0528 PIN_CFG_BYTE(dclk),
0529 PIN_CFG_BYTE(dfs),
0530 PIN_CFG_BYTE(dout),
0531 PIN_CFG_BYTE(xout),
0532 };
0533
0534 return si476x_core_send_command(core, CMD_DIG_AUDIO_PIN_CFG,
0535 args, ARRAY_SIZE(args),
0536 resp, ARRAY_SIZE(resp),
0537 SI476X_DEFAULT_TIMEOUT);
0538 }
0539 EXPORT_SYMBOL_GPL(si476x_core_cmd_dig_audio_pin_cfg);
0540
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569 int si476x_core_cmd_zif_pin_cfg(struct si476x_core *core,
0570 enum si476x_iqclk_config iqclk,
0571 enum si476x_iqfs_config iqfs,
0572 enum si476x_iout_config iout,
0573 enum si476x_qout_config qout)
0574 {
0575 u8 resp[CMD_ZIF_PIN_CFG_NRESP];
0576 const u8 args[CMD_ZIF_PIN_CFG_NARGS] = {
0577 PIN_CFG_BYTE(iqclk),
0578 PIN_CFG_BYTE(iqfs),
0579 PIN_CFG_BYTE(iout),
0580 PIN_CFG_BYTE(qout),
0581 };
0582
0583 return si476x_core_send_command(core, CMD_ZIF_PIN_CFG,
0584 args, ARRAY_SIZE(args),
0585 resp, ARRAY_SIZE(resp),
0586 SI476X_DEFAULT_TIMEOUT);
0587 }
0588 EXPORT_SYMBOL_GPL(si476x_core_cmd_zif_pin_cfg);
0589
0590
0591
0592
0593
0594
0595
0596
0597
0598
0599
0600
0601
0602
0603
0604
0605
0606
0607
0608
0609
0610
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620
0621
0622
0623
0624
0625
0626 int si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(struct si476x_core *core,
0627 enum si476x_icin_config icin,
0628 enum si476x_icip_config icip,
0629 enum si476x_icon_config icon,
0630 enum si476x_icop_config icop)
0631 {
0632 u8 resp[CMD_IC_LINK_GPO_CTL_PIN_CFG_NRESP];
0633 const u8 args[CMD_IC_LINK_GPO_CTL_PIN_CFG_NARGS] = {
0634 PIN_CFG_BYTE(icin),
0635 PIN_CFG_BYTE(icip),
0636 PIN_CFG_BYTE(icon),
0637 PIN_CFG_BYTE(icop),
0638 };
0639
0640 return si476x_core_send_command(core, CMD_IC_LINK_GPO_CTL_PIN_CFG,
0641 args, ARRAY_SIZE(args),
0642 resp, ARRAY_SIZE(resp),
0643 SI476X_DEFAULT_TIMEOUT);
0644 }
0645 EXPORT_SYMBOL_GPL(si476x_core_cmd_ic_link_gpo_ctl_pin_cfg);
0646
0647
0648
0649
0650
0651
0652
0653
0654
0655
0656
0657
0658
0659
0660 int si476x_core_cmd_ana_audio_pin_cfg(struct si476x_core *core,
0661 enum si476x_lrout_config lrout)
0662 {
0663 u8 resp[CMD_ANA_AUDIO_PIN_CFG_NRESP];
0664 const u8 args[CMD_ANA_AUDIO_PIN_CFG_NARGS] = {
0665 PIN_CFG_BYTE(lrout),
0666 };
0667
0668 return si476x_core_send_command(core, CMD_ANA_AUDIO_PIN_CFG,
0669 args, ARRAY_SIZE(args),
0670 resp, ARRAY_SIZE(resp),
0671 SI476X_DEFAULT_TIMEOUT);
0672 }
0673 EXPORT_SYMBOL_GPL(si476x_core_cmd_ana_audio_pin_cfg);
0674
0675
0676
0677
0678
0679
0680
0681
0682
0683
0684
0685
0686
0687
0688
0689
0690
0691
0692
0693
0694 static int si476x_core_cmd_intb_pin_cfg_a10(struct si476x_core *core,
0695 enum si476x_intb_config intb,
0696 enum si476x_a1_config a1)
0697 {
0698 u8 resp[CMD_INTB_PIN_CFG_A10_NRESP];
0699 const u8 args[CMD_INTB_PIN_CFG_NARGS] = {
0700 PIN_CFG_BYTE(intb),
0701 PIN_CFG_BYTE(a1),
0702 };
0703
0704 return si476x_core_send_command(core, CMD_INTB_PIN_CFG,
0705 args, ARRAY_SIZE(args),
0706 resp, ARRAY_SIZE(resp),
0707 SI476X_DEFAULT_TIMEOUT);
0708 }
0709
0710 static int si476x_core_cmd_intb_pin_cfg_a20(struct si476x_core *core,
0711 enum si476x_intb_config intb,
0712 enum si476x_a1_config a1)
0713 {
0714 u8 resp[CMD_INTB_PIN_CFG_A20_NRESP];
0715 const u8 args[CMD_INTB_PIN_CFG_NARGS] = {
0716 PIN_CFG_BYTE(intb),
0717 PIN_CFG_BYTE(a1),
0718 };
0719
0720 return si476x_core_send_command(core, CMD_INTB_PIN_CFG,
0721 args, ARRAY_SIZE(args),
0722 resp, ARRAY_SIZE(resp),
0723 SI476X_DEFAULT_TIMEOUT);
0724 }
0725
0726
0727
0728
0729
0730
0731
0732
0733
0734
0735
0736
0737
0738
0739 int si476x_core_cmd_am_rsq_status(struct si476x_core *core,
0740 struct si476x_rsq_status_args *rsqargs,
0741 struct si476x_rsq_status_report *report)
0742 {
0743 int err;
0744 u8 resp[CMD_AM_RSQ_STATUS_NRESP];
0745 const u8 args[CMD_AM_RSQ_STATUS_NARGS] = {
0746 rsqargs->rsqack << 3 | rsqargs->attune << 2 |
0747 rsqargs->cancel << 1 | rsqargs->stcack,
0748 };
0749
0750 err = si476x_core_send_command(core, CMD_AM_RSQ_STATUS,
0751 args, ARRAY_SIZE(args),
0752 resp, ARRAY_SIZE(resp),
0753 SI476X_DEFAULT_TIMEOUT);
0754
0755
0756
0757
0758
0759
0760
0761 if (!report)
0762 return err;
0763
0764 report->snrhint = 0x08 & resp[1];
0765 report->snrlint = 0x04 & resp[1];
0766 report->rssihint = 0x02 & resp[1];
0767 report->rssilint = 0x01 & resp[1];
0768
0769 report->bltf = 0x80 & resp[2];
0770 report->snr_ready = 0x20 & resp[2];
0771 report->rssiready = 0x08 & resp[2];
0772 report->afcrl = 0x02 & resp[2];
0773 report->valid = 0x01 & resp[2];
0774
0775 report->readfreq = get_unaligned_be16(resp + 3);
0776 report->freqoff = resp[5];
0777 report->rssi = resp[6];
0778 report->snr = resp[7];
0779 report->lassi = resp[9];
0780 report->hassi = resp[10];
0781 report->mult = resp[11];
0782 report->dev = resp[12];
0783
0784 return err;
0785 }
0786 EXPORT_SYMBOL_GPL(si476x_core_cmd_am_rsq_status);
0787
0788 int si476x_core_cmd_fm_acf_status(struct si476x_core *core,
0789 struct si476x_acf_status_report *report)
0790 {
0791 int err;
0792 u8 resp[CMD_FM_ACF_STATUS_NRESP];
0793 const u8 args[CMD_FM_ACF_STATUS_NARGS] = {
0794 0x0,
0795 };
0796
0797 if (!report)
0798 return -EINVAL;
0799
0800 err = si476x_core_send_command(core, CMD_FM_ACF_STATUS,
0801 args, ARRAY_SIZE(args),
0802 resp, ARRAY_SIZE(resp),
0803 SI476X_DEFAULT_TIMEOUT);
0804 if (err < 0)
0805 return err;
0806
0807 report->blend_int = resp[1] & SI476X_ACF_BLEND_INT;
0808 report->hblend_int = resp[1] & SI476X_ACF_HIBLEND_INT;
0809 report->hicut_int = resp[1] & SI476X_ACF_HICUT_INT;
0810 report->chbw_int = resp[1] & SI476X_ACF_CHBW_INT;
0811 report->softmute_int = resp[1] & SI476X_ACF_SOFTMUTE_INT;
0812 report->smute = resp[2] & SI476X_ACF_SMUTE;
0813 report->smattn = resp[3] & SI476X_ACF_SMATTN;
0814 report->chbw = resp[4];
0815 report->hicut = resp[5];
0816 report->hiblend = resp[6];
0817 report->pilot = resp[7] & SI476X_ACF_PILOT;
0818 report->stblend = resp[7] & SI476X_ACF_STBLEND;
0819
0820 return err;
0821 }
0822 EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_acf_status);
0823
0824 int si476x_core_cmd_am_acf_status(struct si476x_core *core,
0825 struct si476x_acf_status_report *report)
0826 {
0827 int err;
0828 u8 resp[CMD_AM_ACF_STATUS_NRESP];
0829 const u8 args[CMD_AM_ACF_STATUS_NARGS] = {
0830 0x0,
0831 };
0832
0833 if (!report)
0834 return -EINVAL;
0835
0836 err = si476x_core_send_command(core, CMD_AM_ACF_STATUS,
0837 args, ARRAY_SIZE(args),
0838 resp, ARRAY_SIZE(resp),
0839 SI476X_DEFAULT_TIMEOUT);
0840 if (err < 0)
0841 return err;
0842
0843 report->blend_int = resp[1] & SI476X_ACF_BLEND_INT;
0844 report->hblend_int = resp[1] & SI476X_ACF_HIBLEND_INT;
0845 report->hicut_int = resp[1] & SI476X_ACF_HICUT_INT;
0846 report->chbw_int = resp[1] & SI476X_ACF_CHBW_INT;
0847 report->softmute_int = resp[1] & SI476X_ACF_SOFTMUTE_INT;
0848 report->smute = resp[2] & SI476X_ACF_SMUTE;
0849 report->smattn = resp[3] & SI476X_ACF_SMATTN;
0850 report->chbw = resp[4];
0851 report->hicut = resp[5];
0852
0853 return err;
0854 }
0855 EXPORT_SYMBOL_GPL(si476x_core_cmd_am_acf_status);
0856
0857
0858
0859
0860
0861
0862
0863
0864
0865
0866
0867
0868
0869
0870
0871
0872 int si476x_core_cmd_fm_seek_start(struct si476x_core *core,
0873 bool seekup, bool wrap)
0874 {
0875 u8 resp[CMD_FM_SEEK_START_NRESP];
0876 const u8 args[CMD_FM_SEEK_START_NARGS] = {
0877 seekup << 3 | wrap << 2,
0878 };
0879
0880 return si476x_cmd_tune_seek_freq(core, CMD_FM_SEEK_START,
0881 args, sizeof(args),
0882 resp, sizeof(resp));
0883 }
0884 EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_seek_start);
0885
0886
0887
0888
0889
0890
0891
0892
0893
0894
0895
0896
0897
0898
0899
0900 int si476x_core_cmd_fm_rds_status(struct si476x_core *core,
0901 bool status_only,
0902 bool mtfifo,
0903 bool intack,
0904 struct si476x_rds_status_report *report)
0905 {
0906 int err;
0907 u8 resp[CMD_FM_RDS_STATUS_NRESP];
0908 const u8 args[CMD_FM_RDS_STATUS_NARGS] = {
0909 status_only << 2 | mtfifo << 1 | intack,
0910 };
0911
0912 err = si476x_core_send_command(core, CMD_FM_RDS_STATUS,
0913 args, ARRAY_SIZE(args),
0914 resp, ARRAY_SIZE(resp),
0915 SI476X_DEFAULT_TIMEOUT);
0916
0917
0918
0919
0920
0921
0922 if (err < 0 || report == NULL)
0923 return err;
0924
0925 report->rdstpptyint = 0x10 & resp[1];
0926 report->rdspiint = 0x08 & resp[1];
0927 report->rdssyncint = 0x02 & resp[1];
0928 report->rdsfifoint = 0x01 & resp[1];
0929
0930 report->tpptyvalid = 0x10 & resp[2];
0931 report->pivalid = 0x08 & resp[2];
0932 report->rdssync = 0x02 & resp[2];
0933 report->rdsfifolost = 0x01 & resp[2];
0934
0935 report->tp = 0x20 & resp[3];
0936 report->pty = 0x1f & resp[3];
0937
0938 report->pi = get_unaligned_be16(resp + 4);
0939 report->rdsfifoused = resp[6];
0940
0941 report->ble[V4L2_RDS_BLOCK_A] = 0xc0 & resp[7];
0942 report->ble[V4L2_RDS_BLOCK_B] = 0x30 & resp[7];
0943 report->ble[V4L2_RDS_BLOCK_C] = 0x0c & resp[7];
0944 report->ble[V4L2_RDS_BLOCK_D] = 0x03 & resp[7];
0945
0946 report->rds[V4L2_RDS_BLOCK_A].block = V4L2_RDS_BLOCK_A;
0947 report->rds[V4L2_RDS_BLOCK_A].msb = resp[8];
0948 report->rds[V4L2_RDS_BLOCK_A].lsb = resp[9];
0949
0950 report->rds[V4L2_RDS_BLOCK_B].block = V4L2_RDS_BLOCK_B;
0951 report->rds[V4L2_RDS_BLOCK_B].msb = resp[10];
0952 report->rds[V4L2_RDS_BLOCK_B].lsb = resp[11];
0953
0954 report->rds[V4L2_RDS_BLOCK_C].block = V4L2_RDS_BLOCK_C;
0955 report->rds[V4L2_RDS_BLOCK_C].msb = resp[12];
0956 report->rds[V4L2_RDS_BLOCK_C].lsb = resp[13];
0957
0958 report->rds[V4L2_RDS_BLOCK_D].block = V4L2_RDS_BLOCK_D;
0959 report->rds[V4L2_RDS_BLOCK_D].msb = resp[14];
0960 report->rds[V4L2_RDS_BLOCK_D].lsb = resp[15];
0961
0962 return err;
0963 }
0964 EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rds_status);
0965
0966 int si476x_core_cmd_fm_rds_blockcount(struct si476x_core *core,
0967 bool clear,
0968 struct si476x_rds_blockcount_report *report)
0969 {
0970 int err;
0971 u8 resp[CMD_FM_RDS_BLOCKCOUNT_NRESP];
0972 const u8 args[CMD_FM_RDS_BLOCKCOUNT_NARGS] = {
0973 clear,
0974 };
0975
0976 if (!report)
0977 return -EINVAL;
0978
0979 err = si476x_core_send_command(core, CMD_FM_RDS_BLOCKCOUNT,
0980 args, ARRAY_SIZE(args),
0981 resp, ARRAY_SIZE(resp),
0982 SI476X_DEFAULT_TIMEOUT);
0983
0984 if (!err) {
0985 report->expected = get_unaligned_be16(resp + 2);
0986 report->received = get_unaligned_be16(resp + 4);
0987 report->uncorrectable = get_unaligned_be16(resp + 6);
0988 }
0989
0990 return err;
0991 }
0992 EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rds_blockcount);
0993
0994 int si476x_core_cmd_fm_phase_diversity(struct si476x_core *core,
0995 enum si476x_phase_diversity_mode mode)
0996 {
0997 u8 resp[CMD_FM_PHASE_DIVERSITY_NRESP];
0998 const u8 args[CMD_FM_PHASE_DIVERSITY_NARGS] = {
0999 mode & 0x07,
1000 };
1001
1002 return si476x_core_send_command(core, CMD_FM_PHASE_DIVERSITY,
1003 args, ARRAY_SIZE(args),
1004 resp, ARRAY_SIZE(resp),
1005 SI476X_DEFAULT_TIMEOUT);
1006 }
1007 EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_diversity);
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019 int si476x_core_cmd_fm_phase_div_status(struct si476x_core *core)
1020 {
1021 int err;
1022 u8 resp[CMD_FM_PHASE_DIV_STATUS_NRESP];
1023
1024 err = si476x_core_send_command(core, CMD_FM_PHASE_DIV_STATUS,
1025 NULL, 0,
1026 resp, ARRAY_SIZE(resp),
1027 SI476X_DEFAULT_TIMEOUT);
1028
1029 return (err < 0) ? err : resp[1];
1030 }
1031 EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_div_status);
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048 int si476x_core_cmd_am_seek_start(struct si476x_core *core,
1049 bool seekup, bool wrap)
1050 {
1051 u8 resp[CMD_AM_SEEK_START_NRESP];
1052 const u8 args[CMD_AM_SEEK_START_NARGS] = {
1053 seekup << 3 | wrap << 2,
1054 };
1055
1056 return si476x_cmd_tune_seek_freq(core, CMD_AM_SEEK_START,
1057 args, sizeof(args),
1058 resp, sizeof(resp));
1059 }
1060 EXPORT_SYMBOL_GPL(si476x_core_cmd_am_seek_start);
1061
1062
1063
1064 static int si476x_core_cmd_power_up_a10(struct si476x_core *core,
1065 struct si476x_power_up_args *puargs)
1066 {
1067 u8 resp[CMD_POWER_UP_A10_NRESP];
1068 const bool intsel = (core->pinmux.a1 == SI476X_A1_IRQ);
1069 const bool ctsen = (core->client->irq != 0);
1070 const u8 args[CMD_POWER_UP_A10_NARGS] = {
1071 0xF7,
1072 0x3F & puargs->xcload,
1073
1074 ctsen << 7 | intsel << 6 | 0x07,
1075
1076
1077 puargs->func << 4 | puargs->freq,
1078 0x11,
1079 };
1080
1081 return si476x_core_send_command(core, CMD_POWER_UP,
1082 args, ARRAY_SIZE(args),
1083 resp, ARRAY_SIZE(resp),
1084 SI476X_TIMEOUT_POWER_UP);
1085 }
1086
1087 static int si476x_core_cmd_power_up_a20(struct si476x_core *core,
1088 struct si476x_power_up_args *puargs)
1089 {
1090 u8 resp[CMD_POWER_UP_A20_NRESP];
1091 const bool intsel = (core->pinmux.a1 == SI476X_A1_IRQ);
1092 const bool ctsen = (core->client->irq != 0);
1093 const u8 args[CMD_POWER_UP_A20_NARGS] = {
1094 puargs->ibias6x << 7 | puargs->xstart,
1095 0x3F & puargs->xcload,
1096
1097 ctsen << 7 | intsel << 6 | puargs->fastboot << 5 |
1098 puargs->xbiashc << 3 | puargs->xbias,
1099 puargs->func << 4 | puargs->freq,
1100 0x10 | puargs->xmode,
1101 };
1102
1103 return si476x_core_send_command(core, CMD_POWER_UP,
1104 args, ARRAY_SIZE(args),
1105 resp, ARRAY_SIZE(resp),
1106 SI476X_TIMEOUT_POWER_UP);
1107 }
1108
1109 static int si476x_core_cmd_power_down_a10(struct si476x_core *core,
1110 struct si476x_power_down_args *pdargs)
1111 {
1112 u8 resp[CMD_POWER_DOWN_A10_NRESP];
1113
1114 return si476x_core_send_command(core, CMD_POWER_DOWN,
1115 NULL, 0,
1116 resp, ARRAY_SIZE(resp),
1117 SI476X_DEFAULT_TIMEOUT);
1118 }
1119
1120 static int si476x_core_cmd_power_down_a20(struct si476x_core *core,
1121 struct si476x_power_down_args *pdargs)
1122 {
1123 u8 resp[CMD_POWER_DOWN_A20_NRESP];
1124 const u8 args[CMD_POWER_DOWN_A20_NARGS] = {
1125 pdargs->xosc,
1126 };
1127 return si476x_core_send_command(core, CMD_POWER_DOWN,
1128 args, ARRAY_SIZE(args),
1129 resp, ARRAY_SIZE(resp),
1130 SI476X_DEFAULT_TIMEOUT);
1131 }
1132
1133 static int si476x_core_cmd_am_tune_freq_a10(struct si476x_core *core,
1134 struct si476x_tune_freq_args *tuneargs)
1135 {
1136
1137 const int am_freq = tuneargs->freq;
1138 u8 resp[CMD_AM_TUNE_FREQ_NRESP];
1139 const u8 args[CMD_AM_TUNE_FREQ_NARGS] = {
1140 (tuneargs->hd << 6),
1141 msb(am_freq),
1142 lsb(am_freq),
1143 };
1144
1145 return si476x_cmd_tune_seek_freq(core, CMD_AM_TUNE_FREQ, args,
1146 sizeof(args),
1147 resp, sizeof(resp));
1148 }
1149
1150 static int si476x_core_cmd_am_tune_freq_a20(struct si476x_core *core,
1151 struct si476x_tune_freq_args *tuneargs)
1152 {
1153 const int am_freq = tuneargs->freq;
1154 u8 resp[CMD_AM_TUNE_FREQ_NRESP];
1155 const u8 args[CMD_AM_TUNE_FREQ_NARGS] = {
1156 (tuneargs->zifsr << 6) | (tuneargs->injside & 0x03),
1157 msb(am_freq),
1158 lsb(am_freq),
1159 };
1160
1161 return si476x_cmd_tune_seek_freq(core, CMD_AM_TUNE_FREQ,
1162 args, sizeof(args),
1163 resp, sizeof(resp));
1164 }
1165
1166 static int si476x_core_cmd_fm_rsq_status_a10(struct si476x_core *core,
1167 struct si476x_rsq_status_args *rsqargs,
1168 struct si476x_rsq_status_report *report)
1169 {
1170 int err;
1171 u8 resp[CMD_FM_RSQ_STATUS_A10_NRESP];
1172 const u8 args[CMD_FM_RSQ_STATUS_A10_NARGS] = {
1173 rsqargs->rsqack << 3 | rsqargs->attune << 2 |
1174 rsqargs->cancel << 1 | rsqargs->stcack,
1175 };
1176
1177 err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS,
1178 args, ARRAY_SIZE(args),
1179 resp, ARRAY_SIZE(resp),
1180 SI476X_DEFAULT_TIMEOUT);
1181
1182
1183
1184
1185
1186
1187
1188 if (err < 0 || report == NULL)
1189 return err;
1190
1191 report->multhint = 0x80 & resp[1];
1192 report->multlint = 0x40 & resp[1];
1193 report->snrhint = 0x08 & resp[1];
1194 report->snrlint = 0x04 & resp[1];
1195 report->rssihint = 0x02 & resp[1];
1196 report->rssilint = 0x01 & resp[1];
1197
1198 report->bltf = 0x80 & resp[2];
1199 report->snr_ready = 0x20 & resp[2];
1200 report->rssiready = 0x08 & resp[2];
1201 report->afcrl = 0x02 & resp[2];
1202 report->valid = 0x01 & resp[2];
1203
1204 report->readfreq = get_unaligned_be16(resp + 3);
1205 report->freqoff = resp[5];
1206 report->rssi = resp[6];
1207 report->snr = resp[7];
1208 report->lassi = resp[9];
1209 report->hassi = resp[10];
1210 report->mult = resp[11];
1211 report->dev = resp[12];
1212 report->readantcap = get_unaligned_be16(resp + 13);
1213 report->assi = resp[15];
1214 report->usn = resp[16];
1215
1216 return err;
1217 }
1218
1219 static int si476x_core_cmd_fm_rsq_status_a20(struct si476x_core *core,
1220 struct si476x_rsq_status_args *rsqargs,
1221 struct si476x_rsq_status_report *report)
1222 {
1223 int err;
1224 u8 resp[CMD_FM_RSQ_STATUS_A10_NRESP];
1225 const u8 args[CMD_FM_RSQ_STATUS_A30_NARGS] = {
1226 rsqargs->primary << 4 | rsqargs->rsqack << 3 |
1227 rsqargs->attune << 2 | rsqargs->cancel << 1 |
1228 rsqargs->stcack,
1229 };
1230
1231 err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS,
1232 args, ARRAY_SIZE(args),
1233 resp, ARRAY_SIZE(resp),
1234 SI476X_DEFAULT_TIMEOUT);
1235
1236
1237
1238
1239
1240
1241
1242 if (err < 0 || report == NULL)
1243 return err;
1244
1245 report->multhint = 0x80 & resp[1];
1246 report->multlint = 0x40 & resp[1];
1247 report->snrhint = 0x08 & resp[1];
1248 report->snrlint = 0x04 & resp[1];
1249 report->rssihint = 0x02 & resp[1];
1250 report->rssilint = 0x01 & resp[1];
1251
1252 report->bltf = 0x80 & resp[2];
1253 report->snr_ready = 0x20 & resp[2];
1254 report->rssiready = 0x08 & resp[2];
1255 report->afcrl = 0x02 & resp[2];
1256 report->valid = 0x01 & resp[2];
1257
1258 report->readfreq = get_unaligned_be16(resp + 3);
1259 report->freqoff = resp[5];
1260 report->rssi = resp[6];
1261 report->snr = resp[7];
1262 report->lassi = resp[9];
1263 report->hassi = resp[10];
1264 report->mult = resp[11];
1265 report->dev = resp[12];
1266 report->readantcap = get_unaligned_be16(resp + 13);
1267 report->assi = resp[15];
1268 report->usn = resp[16];
1269
1270 return err;
1271 }
1272
1273
1274 static int si476x_core_cmd_fm_rsq_status_a30(struct si476x_core *core,
1275 struct si476x_rsq_status_args *rsqargs,
1276 struct si476x_rsq_status_report *report)
1277 {
1278 int err;
1279 u8 resp[CMD_FM_RSQ_STATUS_A30_NRESP];
1280 const u8 args[CMD_FM_RSQ_STATUS_A30_NARGS] = {
1281 rsqargs->primary << 4 | rsqargs->rsqack << 3 |
1282 rsqargs->attune << 2 | rsqargs->cancel << 1 |
1283 rsqargs->stcack,
1284 };
1285
1286 err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS,
1287 args, ARRAY_SIZE(args),
1288 resp, ARRAY_SIZE(resp),
1289 SI476X_DEFAULT_TIMEOUT);
1290
1291
1292
1293
1294
1295
1296
1297 if (err < 0 || report == NULL)
1298 return err;
1299
1300 report->multhint = 0x80 & resp[1];
1301 report->multlint = 0x40 & resp[1];
1302 report->snrhint = 0x08 & resp[1];
1303 report->snrlint = 0x04 & resp[1];
1304 report->rssihint = 0x02 & resp[1];
1305 report->rssilint = 0x01 & resp[1];
1306
1307 report->bltf = 0x80 & resp[2];
1308 report->snr_ready = 0x20 & resp[2];
1309 report->rssiready = 0x08 & resp[2];
1310 report->injside = 0x04 & resp[2];
1311 report->afcrl = 0x02 & resp[2];
1312 report->valid = 0x01 & resp[2];
1313
1314 report->readfreq = get_unaligned_be16(resp + 3);
1315 report->freqoff = resp[5];
1316 report->rssi = resp[6];
1317 report->snr = resp[7];
1318 report->issi = resp[8];
1319 report->lassi = resp[9];
1320 report->hassi = resp[10];
1321 report->mult = resp[11];
1322 report->dev = resp[12];
1323 report->readantcap = get_unaligned_be16(resp + 13);
1324 report->assi = resp[15];
1325 report->usn = resp[16];
1326
1327 report->pilotdev = resp[17];
1328 report->rdsdev = resp[18];
1329 report->assidev = resp[19];
1330 report->strongdev = resp[20];
1331 report->rdspi = get_unaligned_be16(resp + 21);
1332
1333 return err;
1334 }
1335
1336 static int si476x_core_cmd_fm_tune_freq_a10(struct si476x_core *core,
1337 struct si476x_tune_freq_args *tuneargs)
1338 {
1339 u8 resp[CMD_FM_TUNE_FREQ_NRESP];
1340 const u8 args[CMD_FM_TUNE_FREQ_A10_NARGS] = {
1341 (tuneargs->hd << 6) | (tuneargs->tunemode << 4)
1342 | (tuneargs->smoothmetrics << 2),
1343 msb(tuneargs->freq),
1344 lsb(tuneargs->freq),
1345 msb(tuneargs->antcap),
1346 lsb(tuneargs->antcap)
1347 };
1348
1349 return si476x_cmd_tune_seek_freq(core, CMD_FM_TUNE_FREQ,
1350 args, sizeof(args),
1351 resp, sizeof(resp));
1352 }
1353
1354 static int si476x_core_cmd_fm_tune_freq_a20(struct si476x_core *core,
1355 struct si476x_tune_freq_args *tuneargs)
1356 {
1357 u8 resp[CMD_FM_TUNE_FREQ_NRESP];
1358 const u8 args[CMD_FM_TUNE_FREQ_A20_NARGS] = {
1359 (tuneargs->hd << 6) | (tuneargs->tunemode << 4)
1360 | (tuneargs->smoothmetrics << 2) | (tuneargs->injside),
1361 msb(tuneargs->freq),
1362 lsb(tuneargs->freq),
1363 };
1364
1365 return si476x_cmd_tune_seek_freq(core, CMD_FM_TUNE_FREQ,
1366 args, sizeof(args),
1367 resp, sizeof(resp));
1368 }
1369
1370 static int si476x_core_cmd_agc_status_a20(struct si476x_core *core,
1371 struct si476x_agc_status_report *report)
1372 {
1373 int err;
1374 u8 resp[CMD_AGC_STATUS_NRESP_A20];
1375
1376 if (!report)
1377 return -EINVAL;
1378
1379 err = si476x_core_send_command(core, CMD_AGC_STATUS,
1380 NULL, 0,
1381 resp, ARRAY_SIZE(resp),
1382 SI476X_DEFAULT_TIMEOUT);
1383 if (err < 0)
1384 return err;
1385
1386 report->mxhi = resp[1] & SI476X_AGC_MXHI;
1387 report->mxlo = resp[1] & SI476X_AGC_MXLO;
1388 report->lnahi = resp[1] & SI476X_AGC_LNAHI;
1389 report->lnalo = resp[1] & SI476X_AGC_LNALO;
1390 report->fmagc1 = resp[2];
1391 report->fmagc2 = resp[3];
1392 report->pgagain = resp[4];
1393 report->fmwblang = resp[5];
1394
1395 return err;
1396 }
1397
1398 static int si476x_core_cmd_agc_status_a10(struct si476x_core *core,
1399 struct si476x_agc_status_report *report)
1400 {
1401 int err;
1402 u8 resp[CMD_AGC_STATUS_NRESP_A10];
1403
1404 if (!report)
1405 return -EINVAL;
1406
1407 err = si476x_core_send_command(core, CMD_AGC_STATUS,
1408 NULL, 0,
1409 resp, ARRAY_SIZE(resp),
1410 SI476X_DEFAULT_TIMEOUT);
1411 if (err < 0)
1412 return err;
1413
1414 report->mxhi = resp[1] & SI476X_AGC_MXHI;
1415 report->mxlo = resp[1] & SI476X_AGC_MXLO;
1416 report->lnahi = resp[1] & SI476X_AGC_LNAHI;
1417 report->lnalo = resp[1] & SI476X_AGC_LNALO;
1418
1419 return err;
1420 }
1421
1422 typedef int (*tune_freq_func_t) (struct si476x_core *core,
1423 struct si476x_tune_freq_args *tuneargs);
1424
1425 static struct {
1426 int (*power_up)(struct si476x_core *,
1427 struct si476x_power_up_args *);
1428 int (*power_down)(struct si476x_core *,
1429 struct si476x_power_down_args *);
1430
1431 tune_freq_func_t fm_tune_freq;
1432 tune_freq_func_t am_tune_freq;
1433
1434 int (*fm_rsq_status)(struct si476x_core *,
1435 struct si476x_rsq_status_args *,
1436 struct si476x_rsq_status_report *);
1437
1438 int (*agc_status)(struct si476x_core *,
1439 struct si476x_agc_status_report *);
1440 int (*intb_pin_cfg)(struct si476x_core *core,
1441 enum si476x_intb_config intb,
1442 enum si476x_a1_config a1);
1443 } si476x_cmds_vtable[] = {
1444 [SI476X_REVISION_A10] = {
1445 .power_up = si476x_core_cmd_power_up_a10,
1446 .power_down = si476x_core_cmd_power_down_a10,
1447 .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a10,
1448 .am_tune_freq = si476x_core_cmd_am_tune_freq_a10,
1449 .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a10,
1450 .agc_status = si476x_core_cmd_agc_status_a10,
1451 .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a10,
1452 },
1453 [SI476X_REVISION_A20] = {
1454 .power_up = si476x_core_cmd_power_up_a20,
1455 .power_down = si476x_core_cmd_power_down_a20,
1456 .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a20,
1457 .am_tune_freq = si476x_core_cmd_am_tune_freq_a20,
1458 .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a20,
1459 .agc_status = si476x_core_cmd_agc_status_a20,
1460 .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a20,
1461 },
1462 [SI476X_REVISION_A30] = {
1463 .power_up = si476x_core_cmd_power_up_a20,
1464 .power_down = si476x_core_cmd_power_down_a20,
1465 .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a20,
1466 .am_tune_freq = si476x_core_cmd_am_tune_freq_a20,
1467 .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a30,
1468 .agc_status = si476x_core_cmd_agc_status_a20,
1469 .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a20,
1470 },
1471 };
1472
1473 int si476x_core_cmd_power_up(struct si476x_core *core,
1474 struct si476x_power_up_args *args)
1475 {
1476 BUG_ON(core->revision > SI476X_REVISION_A30 ||
1477 core->revision == -1);
1478 return si476x_cmds_vtable[core->revision].power_up(core, args);
1479 }
1480 EXPORT_SYMBOL_GPL(si476x_core_cmd_power_up);
1481
1482 int si476x_core_cmd_power_down(struct si476x_core *core,
1483 struct si476x_power_down_args *args)
1484 {
1485 BUG_ON(core->revision > SI476X_REVISION_A30 ||
1486 core->revision == -1);
1487 return si476x_cmds_vtable[core->revision].power_down(core, args);
1488 }
1489 EXPORT_SYMBOL_GPL(si476x_core_cmd_power_down);
1490
1491 int si476x_core_cmd_fm_tune_freq(struct si476x_core *core,
1492 struct si476x_tune_freq_args *args)
1493 {
1494 BUG_ON(core->revision > SI476X_REVISION_A30 ||
1495 core->revision == -1);
1496 return si476x_cmds_vtable[core->revision].fm_tune_freq(core, args);
1497 }
1498 EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_tune_freq);
1499
1500 int si476x_core_cmd_am_tune_freq(struct si476x_core *core,
1501 struct si476x_tune_freq_args *args)
1502 {
1503 BUG_ON(core->revision > SI476X_REVISION_A30 ||
1504 core->revision == -1);
1505 return si476x_cmds_vtable[core->revision].am_tune_freq(core, args);
1506 }
1507 EXPORT_SYMBOL_GPL(si476x_core_cmd_am_tune_freq);
1508
1509 int si476x_core_cmd_fm_rsq_status(struct si476x_core *core,
1510 struct si476x_rsq_status_args *args,
1511 struct si476x_rsq_status_report *report)
1512
1513 {
1514 BUG_ON(core->revision > SI476X_REVISION_A30 ||
1515 core->revision == -1);
1516 return si476x_cmds_vtable[core->revision].fm_rsq_status(core, args,
1517 report);
1518 }
1519 EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rsq_status);
1520
1521 int si476x_core_cmd_agc_status(struct si476x_core *core,
1522 struct si476x_agc_status_report *report)
1523
1524 {
1525 BUG_ON(core->revision > SI476X_REVISION_A30 ||
1526 core->revision == -1);
1527 return si476x_cmds_vtable[core->revision].agc_status(core, report);
1528 }
1529 EXPORT_SYMBOL_GPL(si476x_core_cmd_agc_status);
1530
1531 int si476x_core_cmd_intb_pin_cfg(struct si476x_core *core,
1532 enum si476x_intb_config intb,
1533 enum si476x_a1_config a1)
1534 {
1535 BUG_ON(core->revision > SI476X_REVISION_A30 ||
1536 core->revision == -1);
1537
1538 return si476x_cmds_vtable[core->revision].intb_pin_cfg(core, intb, a1);
1539 }
1540 EXPORT_SYMBOL_GPL(si476x_core_cmd_intb_pin_cfg);
1541
1542 MODULE_LICENSE("GPL");
1543 MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
1544 MODULE_DESCRIPTION("API for command exchange for si476x");