diff options
Diffstat (limited to 'drivers/media/tuners/fc0012.c')
-rw-r--r-- | drivers/media/tuners/fc0012.c | 113 |
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) | |||
38 | static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val) | 40 | static 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 = ®, .len = 1 }, | 43 | { .addr = priv->cfg->i2c_address, .flags = 0, |
42 | { .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 }, | 44 | .buf = ®, .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 | ||
122 | static int fc0012_sleep(struct dvb_frontend *fe) | ||
123 | { | ||
124 | /* nothing to do here */ | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int fc0012_set_params(struct dvb_frontend *fe) | 132 | static 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 | ||
332 | static int fc0012_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) | 338 | static 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 */ |
409 | exit: | 414 | exit: |
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 | ||
438 | struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe, | 443 | struct 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 | ||
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 | |||
460 | return fe; | 511 | return fe; |
461 | } | 512 | } |
462 | EXPORT_SYMBOL(fc0012_attach); | 513 | EXPORT_SYMBOL(fc0012_attach); |