si2157.c (e955f959ac52e145f27ff2be9078b646d0352af0) si2157.c (7e80a8d14d9ffa5fbd10652da9a2d93c1cefd6f9)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver
4 *
5 * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
6 */
7
8#include "si2157_priv.h"

--- 357 unchanged lines hidden (view full) ---

366 memcpy(cmd.args, "\x14\x00\x02\x07\x00\x00", 6);
367 cmd.args[4] = dev->if_port;
368 cmd.wlen = 6;
369 cmd.rlen = 4;
370 ret = si2157_cmd_execute(client, &cmd);
371 if (ret)
372 goto err;
373
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver
4 *
5 * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
6 */
7
8#include "si2157_priv.h"

--- 357 unchanged lines hidden (view full) ---

366 memcpy(cmd.args, "\x14\x00\x02\x07\x00\x00", 6);
367 cmd.args[4] = dev->if_port;
368 cmd.wlen = 6;
369 cmd.rlen = 4;
370 ret = si2157_cmd_execute(client, &cmd);
371 if (ret)
372 goto err;
373
374 /* set if frequency if needed */
374 /* set digital if frequency if needed */
375 if (if_frequency != dev->if_frequency) {
376 memcpy(cmd.args, "\x14\x00\x06\x07", 4);
377 cmd.args[4] = (if_frequency / 1000) & 0xff;
378 cmd.args[5] = ((if_frequency / 1000) >> 8) & 0xff;
379 cmd.wlen = 6;
380 cmd.rlen = 4;
381 ret = si2157_cmd_execute(client, &cmd);
382 if (ret)
383 goto err;
384
385 dev->if_frequency = if_frequency;
386 }
387
375 if (if_frequency != dev->if_frequency) {
376 memcpy(cmd.args, "\x14\x00\x06\x07", 4);
377 cmd.args[4] = (if_frequency / 1000) & 0xff;
378 cmd.args[5] = ((if_frequency / 1000) >> 8) & 0xff;
379 cmd.wlen = 6;
380 cmd.rlen = 4;
381 ret = si2157_cmd_execute(client, &cmd);
382 if (ret)
383 goto err;
384
385 dev->if_frequency = if_frequency;
386 }
387
388 /* set frequency */
388 /* set digital frequency */
389 memcpy(cmd.args, "\x41\x00\x00\x00\x00\x00\x00\x00", 8);
390 cmd.args[4] = (c->frequency >> 0) & 0xff;
391 cmd.args[5] = (c->frequency >> 8) & 0xff;
392 cmd.args[6] = (c->frequency >> 16) & 0xff;
393 cmd.args[7] = (c->frequency >> 24) & 0xff;
394 cmd.wlen = 8;
395 cmd.rlen = 1;
396 ret = si2157_cmd_execute(client, &cmd);
397 if (ret)
398 goto err;
399
389 memcpy(cmd.args, "\x41\x00\x00\x00\x00\x00\x00\x00", 8);
390 cmd.args[4] = (c->frequency >> 0) & 0xff;
391 cmd.args[5] = (c->frequency >> 8) & 0xff;
392 cmd.args[6] = (c->frequency >> 16) & 0xff;
393 cmd.args[7] = (c->frequency >> 24) & 0xff;
394 cmd.wlen = 8;
395 cmd.rlen = 1;
396 ret = si2157_cmd_execute(client, &cmd);
397 if (ret)
398 goto err;
399
400 dev->bandwidth = bandwidth;
401 dev->frequency = c->frequency;
402
400 return 0;
401err:
403 return 0;
404err:
405 dev->bandwidth = 0;
406 dev->frequency = 0;
407 dev->if_frequency = 0;
402 dev_dbg(&client->dev, "failed=%d\n", ret);
403 return ret;
404}
405
408 dev_dbg(&client->dev, "failed=%d\n", ret);
409 return ret;
410}
411
412static int si2157_set_analog_params(struct dvb_frontend *fe,
413 struct analog_parameters *params)
414{
415 struct i2c_client *client = fe->tuner_priv;
416 struct si2157_dev *dev = i2c_get_clientdata(client);
417 char *std; /* for debugging */
418 int ret;
419 struct si2157_cmd cmd;
420 u32 bandwidth = 0;
421 u32 if_frequency = 0;
422 u32 freq = 0;
423 u64 tmp_lval = 0;
424 u8 system = 0;
425 u8 color = 0; /* 0=NTSC/PAL, 0x10=SECAM */
426 u8 invert_analog = 1; /* analog tuner spectrum; 0=normal, 1=inverted */
427
428 if (dev->chiptype != SI2157_CHIPTYPE_SI2157) {
429 dev_info(&client->dev, "Analog tuning not supported for chiptype=%u\n",
430 dev->chiptype);
431 ret = -EINVAL;
432 goto err;
433 }
434
435 if (!dev->active)
436 si2157_init(fe);
437
438 if (!dev->active) {
439 ret = -EAGAIN;
440 goto err;
441 }
442 if (params->mode == V4L2_TUNER_RADIO) {
443 /*
444 * std = "fm";
445 * bandwidth = 1700000; //best can do for FM, AGC will be a mess though
446 * if_frequency = 1250000; //HVR-225x(saa7164), HVR-12xx(cx23885)
447 * if_frequency = 6600000; //HVR-9xx(cx231xx)
448 * if_frequency = 5500000; //HVR-19xx(pvrusb2)
449 */
450 dev_err(&client->dev, "si2157 does not currently support FM radio\n");
451 ret = -EINVAL;
452 goto err;
453 }
454 tmp_lval = params->frequency * 625LL;
455 do_div(tmp_lval, 10); /* convert to HZ */
456 freq = (u32)tmp_lval;
457
458 if (freq < 1000000) /* is freq in KHz */
459 freq = freq * 1000;
460 dev->frequency = freq;
461
462 /* if_frequency values based on tda187271C2 */
463 if (params->std & (V4L2_STD_B | V4L2_STD_GH)) {
464 if (freq >= 470000000) {
465 std = "palGH";
466 bandwidth = 8000000;
467 if_frequency = 6000000;
468 system = 1;
469 if (params->std &
470 (V4L2_STD_SECAM_G | V4L2_STD_SECAM_H)) {
471 std = "secamGH";
472 color = 0x10;
473 }
474 } else {
475 std = "palB";
476 bandwidth = 7000000;
477 if_frequency = 6000000;
478 system = 0;
479 if (params->std & V4L2_STD_SECAM_B) {
480 std = "secamB";
481 color = 0x10;
482 }
483 }
484 } else if (params->std & V4L2_STD_MN) {
485 std = "MN";
486 bandwidth = 6000000;
487 if_frequency = 5400000;
488 system = 2;
489 } else if (params->std & V4L2_STD_PAL_I) {
490 std = "palI";
491 bandwidth = 8000000;
492 if_frequency = 7250000; /* TODO: does not work yet */
493 system = 4;
494 } else if (params->std & V4L2_STD_DK) {
495 std = "palDK";
496 bandwidth = 8000000;
497 if_frequency = 6900000; /* TODO: does not work yet */
498 system = 5;
499 if (params->std & V4L2_STD_SECAM_DK) {
500 std = "secamDK";
501 color = 0x10;
502 }
503 } else if (params->std & V4L2_STD_SECAM_L) {
504 std = "secamL";
505 bandwidth = 8000000;
506 if_frequency = 6750000; /* TODO: untested */
507 system = 6;
508 color = 0x10;
509 } else if (params->std & V4L2_STD_SECAM_LC) {
510 std = "secamL'";
511 bandwidth = 7000000;
512 if_frequency = 1250000; /* TODO: untested */
513 system = 7;
514 color = 0x10;
515 } else {
516 std = "unknown";
517 }
518 /* calc channel center freq */
519 freq = freq - 1250000 + (bandwidth / 2);
520
521 dev_dbg(&client->dev,
522 "mode=%d system=%u std='%s' params->frequency=%u center freq=%u if=%u bandwidth=%u\n",
523 params->mode, system, std, params->frequency,
524 freq, if_frequency, bandwidth);
525
526 /* set analog IF port */
527 memcpy(cmd.args, "\x14\x00\x03\x06\x08\x02", 6);
528 /* in using dev->if_port, we assume analog and digital IF's */
529 /* are always on different ports */
530 /* assumes if_port definition is 0 or 1 for digital out */
531 cmd.args[4] = (dev->if_port == 1) ? 8 : 10;
532 /* Analog AGC assumed external */
533 cmd.args[5] = (dev->if_port == 1) ? 2 : 1;
534 cmd.wlen = 6;
535 cmd.rlen = 4;
536 ret = si2157_cmd_execute(client, &cmd);
537 if (ret)
538 goto err;
539
540 /* set analog IF output config */
541 memcpy(cmd.args, "\x14\x00\x0d\x06\x94\x64", 6);
542 cmd.wlen = 6;
543 cmd.rlen = 4;
544 ret = si2157_cmd_execute(client, &cmd);
545 if (ret)
546 goto err;
547
548 /* make this distinct from a digital IF */
549 dev->if_frequency = if_frequency | 1;
550
551 /* calc and set tuner analog if center frequency */
552 if_frequency = if_frequency + 1250000 - (bandwidth / 2);
553 dev_dbg(&client->dev, "IF Ctr freq=%d\n", if_frequency);
554
555 memcpy(cmd.args, "\x14\x00\x0C\x06", 4);
556 cmd.args[4] = (if_frequency / 1000) & 0xff;
557 cmd.args[5] = ((if_frequency / 1000) >> 8) & 0xff;
558 cmd.wlen = 6;
559 cmd.rlen = 4;
560 ret = si2157_cmd_execute(client, &cmd);
561 if (ret)
562 goto err;
563
564 /* set analog AGC config */
565 memcpy(cmd.args, "\x14\x00\x07\x06\x32\xc8", 6);
566 cmd.wlen = 6;
567 cmd.rlen = 4;
568 ret = si2157_cmd_execute(client, &cmd);
569 if (ret)
570 goto err;
571
572 /* set analog video mode */
573 memcpy(cmd.args, "\x14\x00\x04\x06\x00\x00", 6);
574 cmd.args[4] = system | color;
575 /* can use dev->inversion if assumed applies to both digital/analog */
576 if (invert_analog)
577 cmd.args[5] |= 0x02;
578 cmd.wlen = 6;
579 cmd.rlen = 1;
580 ret = si2157_cmd_execute(client, &cmd);
581 if (ret)
582 goto err;
583
584 /* set analog frequency */
585 memcpy(cmd.args, "\x41\x01\x00\x00\x00\x00\x00\x00", 8);
586 cmd.args[4] = (freq >> 0) & 0xff;
587 cmd.args[5] = (freq >> 8) & 0xff;
588 cmd.args[6] = (freq >> 16) & 0xff;
589 cmd.args[7] = (freq >> 24) & 0xff;
590 cmd.wlen = 8;
591 cmd.rlen = 1;
592 ret = si2157_cmd_execute(client, &cmd);
593 if (ret)
594 goto err;
595
596 dev->bandwidth = bandwidth;
597
598 return 0;
599err:
600 dev->bandwidth = 0;
601 dev->frequency = 0;
602 dev->if_frequency = 0;
603 dev_dbg(&client->dev, "failed=%d\n", ret);
604 return ret;
605}
606
607static int si2157_get_frequency(struct dvb_frontend *fe, u32 *frequency)
608{
609 struct i2c_client *client = fe->tuner_priv;
610 struct si2157_dev *dev = i2c_get_clientdata(client);
611
612 *frequency = dev->frequency;
613 dev_dbg(&client->dev, "freq=%u\n", dev->frequency);
614 return 0;
615}
616
617static int si2157_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
618{
619 struct i2c_client *client = fe->tuner_priv;
620 struct si2157_dev *dev = i2c_get_clientdata(client);
621
622 *bandwidth = dev->bandwidth;
623 dev_dbg(&client->dev, "bandwidth=%u\n", dev->bandwidth);
624 return 0;
625}
626
406static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
407{
408 struct i2c_client *client = fe->tuner_priv;
409 struct si2157_dev *dev = i2c_get_clientdata(client);
410
627static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
628{
629 struct i2c_client *client = fe->tuner_priv;
630 struct si2157_dev *dev = i2c_get_clientdata(client);
631
411 *frequency = dev->if_frequency;
632 *frequency = dev->if_frequency & ~1; /* strip analog IF indicator bit */
633 dev_dbg(&client->dev, "if_frequency=%u\n", *frequency);
412 return 0;
413}
414
415static const struct dvb_tuner_ops si2157_ops = {
416 .info = {
417 .name = "Silicon Labs Si2141/Si2146/2147/2148/2157/2158",
418 .frequency_min_hz = 42 * MHz,
419 .frequency_max_hz = 870 * MHz,
420 },
421
422 .init = si2157_init,
423 .sleep = si2157_sleep,
424 .set_params = si2157_set_params,
634 return 0;
635}
636
637static const struct dvb_tuner_ops si2157_ops = {
638 .info = {
639 .name = "Silicon Labs Si2141/Si2146/2147/2148/2157/2158",
640 .frequency_min_hz = 42 * MHz,
641 .frequency_max_hz = 870 * MHz,
642 },
643
644 .init = si2157_init,
645 .sleep = si2157_sleep,
646 .set_params = si2157_set_params,
647 .set_analog_params = si2157_set_analog_params,
648 .get_frequency = si2157_get_frequency,
649 .get_bandwidth = si2157_get_bandwidth,
425 .get_if_frequency = si2157_get_if_frequency,
426};
427
428static void si2157_stat_work(struct work_struct *work)
429{
430 struct si2157_dev *dev = container_of(work, struct si2157_dev, stat_work.work);
431 struct dvb_frontend *fe = dev->fe;
432 struct i2c_client *client = fe->tuner_priv;

--- 150 unchanged lines hidden ---
650 .get_if_frequency = si2157_get_if_frequency,
651};
652
653static void si2157_stat_work(struct work_struct *work)
654{
655 struct si2157_dev *dev = container_of(work, struct si2157_dev, stat_work.work);
656 struct dvb_frontend *fe = dev->fe;
657 struct i2c_client *client = fe->tuner_priv;

--- 150 unchanged lines hidden ---