diff options
author | Antti Palosaari <crope@iki.fi> | 2012-12-09 11:28:45 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-01-06 06:07:57 -0500 |
commit | 44ff69cd95308c115134f0546317b584fe1bf5b2 (patch) | |
tree | 86990b5113acde11f5e60e3963d2f0696ca851f7 | |
parent | 3a98477200b44328e50a5c0830f92fd5cdc1ea9b (diff) |
[media] fc0012: rework attach() to check chip id and I/O errors
Signed-off-by: Antti Palosaari <crope@iki.fi>
Acked-by: Hans-Frieder Vogt <hfvogt@gmx.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/tuners/fc0012.c | 59 |
1 files changed, 49 insertions, 10 deletions
diff --git a/drivers/media/tuners/fc0012.c b/drivers/media/tuners/fc0012.c index 01f5e406282c..feb15941cc5b 100644 --- a/drivers/media/tuners/fc0012.c +++ b/drivers/media/tuners/fc0012.c | |||
@@ -443,32 +443,71 @@ static const struct dvb_tuner_ops fc0012_tuner_ops = { | |||
443 | struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe, | 443 | struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe, |
444 | struct i2c_adapter *i2c, const struct fc0012_config *cfg) | 444 | struct i2c_adapter *i2c, const struct fc0012_config *cfg) |
445 | { | 445 | { |
446 | struct fc0012_priv *priv = NULL; | 446 | struct fc0012_priv *priv; |
447 | int ret; | ||
448 | u8 chip_id; | ||
449 | |||
450 | if (fe->ops.i2c_gate_ctrl) | ||
451 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
447 | 452 | ||
448 | priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL); | 453 | priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL); |
449 | if (priv == NULL) | 454 | if (!priv) { |
450 | return NULL; | 455 | ret = -ENOMEM; |
456 | dev_err(&i2c->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); | ||
457 | goto err; | ||
458 | } | ||
451 | 459 | ||
452 | priv->i2c = i2c; | ||
453 | priv->cfg = cfg; | 460 | priv->cfg = cfg; |
461 | priv->i2c = i2c; | ||
454 | 462 | ||
455 | info("Fitipower FC0012 successfully attached."); | 463 | /* check if the tuner is there */ |
464 | ret = fc0012_readreg(priv, 0x00, &chip_id); | ||
465 | if (ret < 0) | ||
466 | goto err; | ||
456 | 467 | ||
457 | fe->tuner_priv = priv; | 468 | dev_dbg(&i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id); |
458 | 469 | ||
459 | if (priv->cfg->loop_through) | 470 | switch (chip_id) { |
460 | fc0012_writereg(priv, 0x09, 0x6f); | 471 | case 0xa1: |
472 | break; | ||
473 | default: | ||
474 | ret = -ENODEV; | ||
475 | goto err; | ||
476 | } | ||
477 | |||
478 | dev_info(&i2c->dev, "%s: Fitipower FC0012 successfully identified\n", | ||
479 | KBUILD_MODNAME); | ||
480 | |||
481 | if (priv->cfg->loop_through) { | ||
482 | ret = fc0012_writereg(priv, 0x09, 0x6f); | ||
483 | if (ret < 0) | ||
484 | goto err; | ||
485 | } | ||
461 | 486 | ||
462 | /* | 487 | /* |
463 | * TODO: Clock out en or div? | 488 | * TODO: Clock out en or div? |
464 | * For dual tuner configuration clearing bit [0] is required. | 489 | * For dual tuner configuration clearing bit [0] is required. |
465 | */ | 490 | */ |
466 | if (priv->cfg->clock_out) | 491 | if (priv->cfg->clock_out) { |
467 | fc0012_writereg(priv, 0x0b, 0x82); | 492 | ret = fc0012_writereg(priv, 0x0b, 0x82); |
493 | if (ret < 0) | ||
494 | goto err; | ||
495 | } | ||
468 | 496 | ||
497 | fe->tuner_priv = priv; | ||
469 | memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops, | 498 | memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops, |
470 | sizeof(struct dvb_tuner_ops)); | 499 | sizeof(struct dvb_tuner_ops)); |
471 | 500 | ||
501 | err: | ||
502 | if (fe->ops.i2c_gate_ctrl) | ||
503 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
504 | |||
505 | if (ret) { | ||
506 | dev_dbg(&i2c->dev, "%s: failed: %d\n", __func__, ret); | ||
507 | kfree(priv); | ||
508 | return NULL; | ||
509 | } | ||
510 | |||
472 | return fe; | 511 | return fe; |
473 | } | 512 | } |
474 | EXPORT_SYMBOL(fc0012_attach); | 513 | EXPORT_SYMBOL(fc0012_attach); |