diff options
author | Antti Palosaari <crope@iki.fi> | 2015-03-23 17:26:55 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-04-02 21:24:03 -0400 |
commit | dc245a5f9b5163511e0c164c8aa47848f07b75a9 (patch) | |
tree | d0526e7d00fc06070d70ad640038949f20a087e9 /drivers/media | |
parent | abd9025b95619c02f83583c9659298bc65dcdf50 (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.c | 161 |
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 | ||
28 | struct ts2020_priv { | 28 | struct 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 | } |
464 | EXPORT_SYMBOL(ts2020_attach); | 466 | EXPORT_SYMBOL(ts2020_attach); |
465 | 467 | ||
468 | static 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; | ||
588 | err: | ||
589 | dev_dbg(&client->dev, "failed=%d\n", ret); | ||
590 | kfree(dev); | ||
591 | return ret; | ||
592 | } | ||
593 | |||
594 | static 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 | |||
608 | static const struct i2c_device_id ts2020_id_table[] = { | ||
609 | {"ts2020", 0}, | ||
610 | {"ts2022", 0}, | ||
611 | {} | ||
612 | }; | ||
613 | MODULE_DEVICE_TABLE(i2c, ts2020_id_table); | ||
614 | |||
615 | static 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 | |||
625 | module_i2c_driver(ts2020_driver); | ||
626 | |||
466 | MODULE_AUTHOR("Konstantin Dimitrov <kosio.dimitrov@gmail.com>"); | 627 | MODULE_AUTHOR("Konstantin Dimitrov <kosio.dimitrov@gmail.com>"); |
467 | MODULE_DESCRIPTION("Montage Technology TS2020 - Silicon tuner driver module"); | 628 | MODULE_DESCRIPTION("Montage Technology TS2020 - Silicon tuner driver module"); |
468 | MODULE_LICENSE("GPL"); | 629 | MODULE_LICENSE("GPL"); |