aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/tuners/fc0012.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/tuners/fc0012.c')
-rw-r--r--drivers/media/tuners/fc0012.c113
1 files changed, 82 insertions, 31 deletions
diff --git a/drivers/media/tuners/fc0012.c b/drivers/media/tuners/fc0012.c
index 308135abd54c..f4d0e797a6cc 100644
--- a/drivers/media/tuners/fc0012.c
+++ b/drivers/media/tuners/fc0012.c
@@ -25,11 +25,13 @@ static int fc0012_writereg(struct fc0012_priv *priv, u8 reg, u8 val)
25{ 25{
26 u8 buf[2] = {reg, val}; 26 u8 buf[2] = {reg, val};
27 struct i2c_msg msg = { 27 struct i2c_msg msg = {
28 .addr = priv->addr, .flags = 0, .buf = buf, .len = 2 28 .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
29 }; 29 };
30 30
31 if (i2c_transfer(priv->i2c, &msg, 1) != 1) { 31 if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
32 err("I2C write reg failed, reg: %02x, val: %02x", reg, val); 32 dev_err(&priv->i2c->dev,
33 "%s: I2C write reg failed, reg: %02x, val: %02x\n",
34 KBUILD_MODNAME, reg, val);
33 return -EREMOTEIO; 35 return -EREMOTEIO;
34 } 36 }
35 return 0; 37 return 0;
@@ -38,12 +40,16 @@ static int fc0012_writereg(struct fc0012_priv *priv, u8 reg, u8 val)
38static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val) 40static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val)
39{ 41{
40 struct i2c_msg msg[2] = { 42 struct i2c_msg msg[2] = {
41 { .addr = priv->addr, .flags = 0, .buf = &reg, .len = 1 }, 43 { .addr = priv->cfg->i2c_address, .flags = 0,
42 { .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 }, 44 .buf = &reg, .len = 1 },
45 { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
46 .buf = val, .len = 1 },
43 }; 47 };
44 48
45 if (i2c_transfer(priv->i2c, msg, 2) != 2) { 49 if (i2c_transfer(priv->i2c, msg, 2) != 2) {
46 err("I2C read reg failed, reg: %02x", reg); 50 dev_err(&priv->i2c->dev,
51 "%s: I2C read reg failed, reg: %02x\n",
52 KBUILD_MODNAME, reg);
47 return -EREMOTEIO; 53 return -EREMOTEIO;
48 } 54 }
49 return 0; 55 return 0;
@@ -88,7 +94,7 @@ static int fc0012_init(struct dvb_frontend *fe)
88 0x04, /* reg. 0x15: Enable LNA COMPS */ 94 0x04, /* reg. 0x15: Enable LNA COMPS */
89 }; 95 };
90 96
91 switch (priv->xtal_freq) { 97 switch (priv->cfg->xtal_freq) {
92 case FC_XTAL_27_MHZ: 98 case FC_XTAL_27_MHZ:
93 case FC_XTAL_28_8_MHZ: 99 case FC_XTAL_28_8_MHZ:
94 reg[0x07] |= 0x20; 100 reg[0x07] |= 0x20;
@@ -98,9 +104,12 @@ static int fc0012_init(struct dvb_frontend *fe)
98 break; 104 break;
99 } 105 }
100 106
101 if (priv->dual_master) 107 if (priv->cfg->dual_master)
102 reg[0x0c] |= 0x02; 108 reg[0x0c] |= 0x02;
103 109
110 if (priv->cfg->loop_through)
111 reg[0x09] |= 0x01;
112
104 if (fe->ops.i2c_gate_ctrl) 113 if (fe->ops.i2c_gate_ctrl)
105 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ 114 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
106 115
@@ -114,17 +123,12 @@ static int fc0012_init(struct dvb_frontend *fe)
114 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ 123 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
115 124
116 if (ret) 125 if (ret)
117 err("fc0012_writereg failed: %d", ret); 126 dev_err(&priv->i2c->dev, "%s: fc0012_writereg failed: %d\n",
127 KBUILD_MODNAME, ret);
118 128
119 return ret; 129 return ret;
120} 130}
121 131
122static int fc0012_sleep(struct dvb_frontend *fe)
123{
124 /* nothing to do here */
125 return 0;
126}
127
128static int fc0012_set_params(struct dvb_frontend *fe) 132static int fc0012_set_params(struct dvb_frontend *fe)
129{ 133{
130 struct fc0012_priv *priv = fe->tuner_priv; 134 struct fc0012_priv *priv = fe->tuner_priv;
@@ -144,7 +148,7 @@ static int fc0012_set_params(struct dvb_frontend *fe)
144 goto exit; 148 goto exit;
145 } 149 }
146 150
147 switch (priv->xtal_freq) { 151 switch (priv->cfg->xtal_freq) {
148 case FC_XTAL_27_MHZ: 152 case FC_XTAL_27_MHZ:
149 xtal_freq_khz_2 = 27000 / 2; 153 xtal_freq_khz_2 = 27000 / 2;
150 break; 154 break;
@@ -256,7 +260,8 @@ static int fc0012_set_params(struct dvb_frontend *fe)
256 break; 260 break;
257 } 261 }
258 } else { 262 } else {
259 err("%s: modulation type not supported!", __func__); 263 dev_err(&priv->i2c->dev, "%s: modulation type not supported!\n",
264 KBUILD_MODNAME);
260 return -EINVAL; 265 return -EINVAL;
261 } 266 }
262 267
@@ -318,7 +323,8 @@ exit:
318 if (fe->ops.i2c_gate_ctrl) 323 if (fe->ops.i2c_gate_ctrl)
319 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ 324 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
320 if (ret) 325 if (ret)
321 warn("%s: failed: %d", __func__, ret); 326 dev_warn(&priv->i2c->dev, "%s: %s failed: %d\n",
327 KBUILD_MODNAME, __func__, ret);
322 return ret; 328 return ret;
323} 329}
324 330
@@ -331,8 +337,7 @@ static int fc0012_get_frequency(struct dvb_frontend *fe, u32 *frequency)
331 337
332static int fc0012_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) 338static int fc0012_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
333{ 339{
334 /* CHECK: always ? */ 340 *frequency = 0; /* Zero-IF */
335 *frequency = 0;
336 return 0; 341 return 0;
337} 342}
338 343
@@ -408,7 +413,8 @@ err:
408 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ 413 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
409exit: 414exit:
410 if (ret) 415 if (ret)
411 warn("%s: failed: %d", __func__, ret); 416 dev_warn(&priv->i2c->dev, "%s: %s failed: %d\n",
417 KBUILD_MODNAME, __func__, ret);
412 return ret; 418 return ret;
413} 419}
414 420
@@ -424,7 +430,6 @@ static const struct dvb_tuner_ops fc0012_tuner_ops = {
424 .release = fc0012_release, 430 .release = fc0012_release,
425 431
426 .init = fc0012_init, 432 .init = fc0012_init,
427 .sleep = fc0012_sleep,
428 433
429 .set_params = fc0012_set_params, 434 .set_params = fc0012_set_params,
430 435
@@ -436,27 +441,73 @@ static const struct dvb_tuner_ops fc0012_tuner_ops = {
436}; 441};
437 442
438struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe, 443struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
439 struct i2c_adapter *i2c, u8 i2c_address, int dual_master, 444 struct i2c_adapter *i2c, const struct fc0012_config *cfg)
440 enum fc001x_xtal_freq xtal_freq)
441{ 445{
442 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);
443 452
444 priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL); 453 priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL);
445 if (priv == NULL) 454 if (!priv) {
446 return NULL; 455 ret = -ENOMEM;
456 dev_err(&i2c->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
457 goto err;
458 }
447 459
460 priv->cfg = cfg;
448 priv->i2c = i2c; 461 priv->i2c = i2c;
449 priv->dual_master = dual_master;
450 priv->addr = i2c_address;
451 priv->xtal_freq = xtal_freq;
452 462
453 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;
454 467
455 fe->tuner_priv = priv; 468 dev_dbg(&i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id);
469
470 switch (chip_id) {
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 }
486
487 /*
488 * TODO: Clock out en or div?
489 * For dual tuner configuration clearing bit [0] is required.
490 */
491 if (priv->cfg->clock_out) {
492 ret = fc0012_writereg(priv, 0x0b, 0x82);
493 if (ret < 0)
494 goto err;
495 }
456 496
497 fe->tuner_priv = priv;
457 memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops, 498 memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops,
458 sizeof(struct dvb_tuner_ops)); 499 sizeof(struct dvb_tuner_ops));
459 500
501err:
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
460 return fe; 511 return fe;
461} 512}
462EXPORT_SYMBOL(fc0012_attach); 513EXPORT_SYMBOL(fc0012_attach);