aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorAntti Palosaari <crope@iki.fi>2015-03-23 17:26:55 -0400
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2015-04-02 21:24:03 -0400
commitdc245a5f9b5163511e0c164c8aa47848f07b75a9 (patch)
treed0526e7d00fc06070d70ad640038949f20a087e9 /drivers/media
parentabd9025b95619c02f83583c9659298bc65dcdf50 (diff)
[media] ts2020: implement I2C client bindings
Implement I2C binding model. Signed-off-by: Antti Palosaari <crope@iki.fi> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/dvb-frontends/ts2020.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c
index 24c4712b77fe..b1d91dc46a47 100644
--- a/drivers/media/dvb-frontends/ts2020.c
+++ b/drivers/media/dvb-frontends/ts2020.c
@@ -26,6 +26,7 @@
26#define FREQ_OFFSET_LOW_SYM_RATE 3000 26#define FREQ_OFFSET_LOW_SYM_RATE 3000
27 27
28struct ts2020_priv { 28struct ts2020_priv {
29 struct dvb_frontend *fe;
29 /* i2c details */ 30 /* i2c details */
30 int i2c_address; 31 int i2c_address;
31 struct i2c_adapter *i2c; 32 struct i2c_adapter *i2c;
@@ -428,6 +429,7 @@ struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe,
428 priv->clk_out = config->clk_out; 429 priv->clk_out = config->clk_out;
429 priv->clk_out_div = config->clk_out_div; 430 priv->clk_out_div = config->clk_out_div;
430 priv->frequency_div = config->frequency_div; 431 priv->frequency_div = config->frequency_div;
432 priv->fe = fe;
431 fe->tuner_priv = priv; 433 fe->tuner_priv = priv;
432 434
433 if (!priv->frequency_div) 435 if (!priv->frequency_div)
@@ -463,6 +465,165 @@ struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe,
463} 465}
464EXPORT_SYMBOL(ts2020_attach); 466EXPORT_SYMBOL(ts2020_attach);
465 467
468static int ts2020_probe(struct i2c_client *client,
469 const struct i2c_device_id *id)
470{
471 struct ts2020_config *pdata = client->dev.platform_data;
472 struct dvb_frontend *fe = pdata->fe;
473 struct ts2020_priv *dev;
474 int ret;
475 u8 u8tmp;
476 unsigned int utmp;
477 char *chip_str;
478
479 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
480 if (!dev) {
481 ret = -ENOMEM;
482 goto err;
483 }
484
485 dev->i2c = client->adapter;
486 dev->i2c_address = client->addr;
487 dev->clk_out = pdata->clk_out;
488 dev->clk_out_div = pdata->clk_out_div;
489 dev->frequency_div = pdata->frequency_div;
490 dev->fe = fe;
491 fe->tuner_priv = dev;
492
493 /* check if the tuner is there */
494 ret = ts2020_readreg(fe, 0x00);
495 if (ret < 0)
496 goto err;
497 utmp = ret;
498
499 if ((utmp & 0x03) == 0x00) {
500 ret = ts2020_writereg(fe, 0x00, 0x01);
501 if (ret)
502 goto err;
503
504 usleep_range(2000, 50000);
505 }
506
507 ret = ts2020_writereg(fe, 0x00, 0x03);
508 if (ret)
509 goto err;
510
511 usleep_range(2000, 50000);
512
513 ret = ts2020_readreg(fe, 0x00);
514 if (ret < 0)
515 goto err;
516 utmp = ret;
517
518 dev_dbg(&client->dev, "chip_id=%02x\n", utmp);
519
520 switch (utmp) {
521 case 0x01:
522 case 0x41:
523 case 0x81:
524 dev->tuner = TS2020_M88TS2020;
525 chip_str = "TS2020";
526 if (!dev->frequency_div)
527 dev->frequency_div = 1060000;
528 break;
529 case 0xc3:
530 case 0x83:
531 dev->tuner = TS2020_M88TS2022;
532 chip_str = "TS2022";
533 if (!dev->frequency_div)
534 dev->frequency_div = 1103000;
535 break;
536 default:
537 ret = -ENODEV;
538 goto err;
539 }
540
541 if (dev->tuner == TS2020_M88TS2022) {
542 switch (dev->clk_out) {
543 case TS2020_CLK_OUT_DISABLED:
544 u8tmp = 0x60;
545 break;
546 case TS2020_CLK_OUT_ENABLED:
547 u8tmp = 0x70;
548 ret = ts2020_writereg(fe, 0x05, dev->clk_out_div);
549 if (ret)
550 goto err;
551 break;
552 case TS2020_CLK_OUT_ENABLED_XTALOUT:
553 u8tmp = 0x6c;
554 break;
555 default:
556 ret = -EINVAL;
557 goto err;
558 }
559
560 ret = ts2020_writereg(fe, 0x42, u8tmp);
561 if (ret)
562 goto err;
563
564 if (dev->loop_through)
565 u8tmp = 0xec;
566 else
567 u8tmp = 0x6c;
568
569 ret = ts2020_writereg(fe, 0x62, u8tmp);
570 if (ret)
571 goto err;
572 }
573
574 /* sleep */
575 ret = ts2020_writereg(fe, 0x00, 0x00);
576 if (ret)
577 goto err;
578
579 dev_info(&client->dev,
580 "Montage Technology %s successfully identified\n", chip_str);
581
582 memcpy(&fe->ops.tuner_ops, &ts2020_tuner_ops,
583 sizeof(struct dvb_tuner_ops));
584 fe->ops.tuner_ops.release = NULL;
585
586 i2c_set_clientdata(client, dev);
587 return 0;
588err:
589 dev_dbg(&client->dev, "failed=%d\n", ret);
590 kfree(dev);
591 return ret;
592}
593
594static int ts2020_remove(struct i2c_client *client)
595{
596 struct ts2020_priv *dev = i2c_get_clientdata(client);
597 struct dvb_frontend *fe = dev->fe;
598
599 dev_dbg(&client->dev, "\n");
600
601 memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
602 fe->tuner_priv = NULL;
603 kfree(dev);
604
605 return 0;
606}
607
608static const struct i2c_device_id ts2020_id_table[] = {
609 {"ts2020", 0},
610 {"ts2022", 0},
611 {}
612};
613MODULE_DEVICE_TABLE(i2c, ts2020_id_table);
614
615static struct i2c_driver ts2020_driver = {
616 .driver = {
617 .owner = THIS_MODULE,
618 .name = "ts2020",
619 },
620 .probe = ts2020_probe,
621 .remove = ts2020_remove,
622 .id_table = ts2020_id_table,
623};
624
625module_i2c_driver(ts2020_driver);
626
466MODULE_AUTHOR("Konstantin Dimitrov <kosio.dimitrov@gmail.com>"); 627MODULE_AUTHOR("Konstantin Dimitrov <kosio.dimitrov@gmail.com>");
467MODULE_DESCRIPTION("Montage Technology TS2020 - Silicon tuner driver module"); 628MODULE_DESCRIPTION("Montage Technology TS2020 - Silicon tuner driver module");
468MODULE_LICENSE("GPL"); 629MODULE_LICENSE("GPL");