diff options
author | Antti Palosaari <crope@iki.fi> | 2015-04-14 18:52:16 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-05-18 14:45:06 -0400 |
commit | 6802fc0b8126d8e2e5e982a9772d757e61e47c72 (patch) | |
tree | 5f34b4eb4bfb282c31d0efc8ce1fdefb59d7115f /drivers/media/tuners | |
parent | 0fae1997f09796aca8ada5edc028aef587f6716c (diff) |
[media] fc2580: implement I2C client bindings
Add I2C client bindings to driver.
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Diffstat (limited to 'drivers/media/tuners')
-rw-r--r-- | drivers/media/tuners/fc2580.c | 101 | ||||
-rw-r--r-- | drivers/media/tuners/fc2580.h | 15 | ||||
-rw-r--r-- | drivers/media/tuners/fc2580_priv.h | 4 |
3 files changed, 110 insertions, 10 deletions
diff --git a/drivers/media/tuners/fc2580.c b/drivers/media/tuners/fc2580.c index f0c9c42867de..d01fba8df3c0 100644 --- a/drivers/media/tuners/fc2580.c +++ b/drivers/media/tuners/fc2580.c | |||
@@ -47,7 +47,7 @@ static int fc2580_wr_regs(struct fc2580_priv *priv, u8 reg, u8 *val, int len) | |||
47 | u8 buf[MAX_XFER_SIZE]; | 47 | u8 buf[MAX_XFER_SIZE]; |
48 | struct i2c_msg msg[1] = { | 48 | struct i2c_msg msg[1] = { |
49 | { | 49 | { |
50 | .addr = priv->cfg->i2c_addr, | 50 | .addr = priv->i2c_addr, |
51 | .flags = 0, | 51 | .flags = 0, |
52 | .len = 1 + len, | 52 | .len = 1 + len, |
53 | .buf = buf, | 53 | .buf = buf, |
@@ -82,12 +82,12 @@ static int fc2580_rd_regs(struct fc2580_priv *priv, u8 reg, u8 *val, int len) | |||
82 | u8 buf[MAX_XFER_SIZE]; | 82 | u8 buf[MAX_XFER_SIZE]; |
83 | struct i2c_msg msg[2] = { | 83 | struct i2c_msg msg[2] = { |
84 | { | 84 | { |
85 | .addr = priv->cfg->i2c_addr, | 85 | .addr = priv->i2c_addr, |
86 | .flags = 0, | 86 | .flags = 0, |
87 | .len = 1, | 87 | .len = 1, |
88 | .buf = ®, | 88 | .buf = ®, |
89 | }, { | 89 | }, { |
90 | .addr = priv->cfg->i2c_addr, | 90 | .addr = priv->i2c_addr, |
91 | .flags = I2C_M_RD, | 91 | .flags = I2C_M_RD, |
92 | .len = len, | 92 | .len = len, |
93 | .buf = buf, | 93 | .buf = buf, |
@@ -182,10 +182,10 @@ static int fc2580_set_params(struct dvb_frontend *fe) | |||
182 | if (ret < 0) | 182 | if (ret < 0) |
183 | goto err; | 183 | goto err; |
184 | 184 | ||
185 | if (f_vco >= 2UL * 76 * priv->cfg->clock) { | 185 | if (f_vco >= 2UL * 76 * priv->clk) { |
186 | r_val = 1; | 186 | r_val = 1; |
187 | r18_val = 0x00; | 187 | r18_val = 0x00; |
188 | } else if (f_vco >= 1UL * 76 * priv->cfg->clock) { | 188 | } else if (f_vco >= 1UL * 76 * priv->clk) { |
189 | r_val = 2; | 189 | r_val = 2; |
190 | r18_val = 0x10; | 190 | r18_val = 0x10; |
191 | } else { | 191 | } else { |
@@ -193,7 +193,7 @@ static int fc2580_set_params(struct dvb_frontend *fe) | |||
193 | r18_val = 0x20; | 193 | r18_val = 0x20; |
194 | } | 194 | } |
195 | 195 | ||
196 | f_ref = 2UL * priv->cfg->clock / r_val; | 196 | f_ref = 2UL * priv->clk / r_val; |
197 | n_val = div_u64_rem(f_vco, f_ref, &k_val); | 197 | n_val = div_u64_rem(f_vco, f_ref, &k_val); |
198 | k_val_reg = div_u64(1ULL * k_val * (1 << 20), f_ref); | 198 | k_val_reg = div_u64(1ULL * k_val * (1 << 20), f_ref); |
199 | 199 | ||
@@ -213,7 +213,7 @@ static int fc2580_set_params(struct dvb_frontend *fe) | |||
213 | if (ret < 0) | 213 | if (ret < 0) |
214 | goto err; | 214 | goto err; |
215 | 215 | ||
216 | if (priv->cfg->clock >= 28000000) { | 216 | if (priv->clk >= 28000000) { |
217 | ret = fc2580_wr_reg(priv, 0x4b, 0x22); | 217 | ret = fc2580_wr_reg(priv, 0x4b, 0x22); |
218 | if (ret < 0) | 218 | if (ret < 0) |
219 | goto err; | 219 | goto err; |
@@ -348,7 +348,7 @@ static int fc2580_set_params(struct dvb_frontend *fe) | |||
348 | if (ret < 0) | 348 | if (ret < 0) |
349 | goto err; | 349 | goto err; |
350 | 350 | ||
351 | ret = fc2580_wr_reg(priv, 0x37, div_u64(1ULL * priv->cfg->clock * | 351 | ret = fc2580_wr_reg(priv, 0x37, div_u64(1ULL * priv->clk * |
352 | fc2580_if_filter_lut[i].mul, 1000000000)); | 352 | fc2580_if_filter_lut[i].mul, 1000000000)); |
353 | if (ret < 0) | 353 | if (ret < 0) |
354 | goto err; | 354 | goto err; |
@@ -510,8 +510,9 @@ struct dvb_frontend *fc2580_attach(struct dvb_frontend *fe, | |||
510 | goto err; | 510 | goto err; |
511 | } | 511 | } |
512 | 512 | ||
513 | priv->cfg = cfg; | 513 | priv->clk = cfg->clock; |
514 | priv->i2c = i2c; | 514 | priv->i2c = i2c; |
515 | priv->i2c_addr = cfg->i2c_addr; | ||
515 | 516 | ||
516 | /* check if the tuner is there */ | 517 | /* check if the tuner is there */ |
517 | ret = fc2580_rd_reg(priv, 0x01, &chip_id); | 518 | ret = fc2580_rd_reg(priv, 0x01, &chip_id); |
@@ -550,6 +551,88 @@ err: | |||
550 | } | 551 | } |
551 | EXPORT_SYMBOL(fc2580_attach); | 552 | EXPORT_SYMBOL(fc2580_attach); |
552 | 553 | ||
554 | static int fc2580_probe(struct i2c_client *client, | ||
555 | const struct i2c_device_id *id) | ||
556 | { | ||
557 | struct fc2580_priv *dev; | ||
558 | struct fc2580_platform_data *pdata = client->dev.platform_data; | ||
559 | struct dvb_frontend *fe = pdata->dvb_frontend; | ||
560 | int ret; | ||
561 | u8 chip_id; | ||
562 | |||
563 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
564 | if (!dev) { | ||
565 | ret = -ENOMEM; | ||
566 | goto err; | ||
567 | } | ||
568 | |||
569 | if (pdata->clk) | ||
570 | dev->clk = pdata->clk; | ||
571 | else | ||
572 | dev->clk = 16384000; /* internal clock */ | ||
573 | dev->client = client; | ||
574 | dev->i2c = client->adapter; | ||
575 | dev->i2c_addr = client->addr; | ||
576 | |||
577 | /* check if the tuner is there */ | ||
578 | ret = fc2580_rd_reg(dev, 0x01, &chip_id); | ||
579 | if (ret < 0) | ||
580 | goto err_kfree; | ||
581 | |||
582 | dev_dbg(&client->dev, "chip_id=%02x\n", chip_id); | ||
583 | |||
584 | switch (chip_id) { | ||
585 | case 0x56: | ||
586 | case 0x5a: | ||
587 | break; | ||
588 | default: | ||
589 | goto err_kfree; | ||
590 | } | ||
591 | |||
592 | fe->tuner_priv = dev; | ||
593 | memcpy(&fe->ops.tuner_ops, &fc2580_tuner_ops, | ||
594 | sizeof(struct dvb_tuner_ops)); | ||
595 | fe->ops.tuner_ops.release = NULL; | ||
596 | i2c_set_clientdata(client, dev); | ||
597 | |||
598 | dev_info(&client->dev, "FCI FC2580 successfully identified\n"); | ||
599 | return 0; | ||
600 | err_kfree: | ||
601 | kfree(dev); | ||
602 | err: | ||
603 | dev_dbg(&client->dev, "failed=%d\n", ret); | ||
604 | return ret; | ||
605 | } | ||
606 | |||
607 | static int fc2580_remove(struct i2c_client *client) | ||
608 | { | ||
609 | struct fc2580_priv *dev = i2c_get_clientdata(client); | ||
610 | |||
611 | dev_dbg(&client->dev, "\n"); | ||
612 | |||
613 | kfree(dev); | ||
614 | return 0; | ||
615 | } | ||
616 | |||
617 | static const struct i2c_device_id fc2580_id_table[] = { | ||
618 | {"fc2580", 0}, | ||
619 | {} | ||
620 | }; | ||
621 | MODULE_DEVICE_TABLE(i2c, fc2580_id_table); | ||
622 | |||
623 | static struct i2c_driver fc2580_driver = { | ||
624 | .driver = { | ||
625 | .owner = THIS_MODULE, | ||
626 | .name = "fc2580", | ||
627 | .suppress_bind_attrs = true, | ||
628 | }, | ||
629 | .probe = fc2580_probe, | ||
630 | .remove = fc2580_remove, | ||
631 | .id_table = fc2580_id_table, | ||
632 | }; | ||
633 | |||
634 | module_i2c_driver(fc2580_driver); | ||
635 | |||
553 | MODULE_DESCRIPTION("FCI FC2580 silicon tuner driver"); | 636 | MODULE_DESCRIPTION("FCI FC2580 silicon tuner driver"); |
554 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | 637 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); |
555 | MODULE_LICENSE("GPL"); | 638 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/media/tuners/fc2580.h b/drivers/media/tuners/fc2580.h index b1ce6770f88e..5679e44980f9 100644 --- a/drivers/media/tuners/fc2580.h +++ b/drivers/media/tuners/fc2580.h | |||
@@ -24,6 +24,21 @@ | |||
24 | #include <linux/kconfig.h> | 24 | #include <linux/kconfig.h> |
25 | #include "dvb_frontend.h" | 25 | #include "dvb_frontend.h" |
26 | 26 | ||
27 | /* | ||
28 | * I2C address | ||
29 | * 0x56, ... | ||
30 | */ | ||
31 | |||
32 | /** | ||
33 | * struct fc2580_platform_data - Platform data for the fc2580 driver | ||
34 | * @clk: Clock frequency (0 = internal clock). | ||
35 | * @dvb_frontend: DVB frontend. | ||
36 | */ | ||
37 | struct fc2580_platform_data { | ||
38 | u32 clk; | ||
39 | struct dvb_frontend *dvb_frontend; | ||
40 | }; | ||
41 | |||
27 | struct fc2580_config { | 42 | struct fc2580_config { |
28 | /* | 43 | /* |
29 | * I2C address | 44 | * I2C address |
diff --git a/drivers/media/tuners/fc2580_priv.h b/drivers/media/tuners/fc2580_priv.h index 646c99452136..a22ffc63749f 100644 --- a/drivers/media/tuners/fc2580_priv.h +++ b/drivers/media/tuners/fc2580_priv.h | |||
@@ -128,8 +128,10 @@ static const struct fc2580_freq_regs fc2580_freq_regs_lut[] = { | |||
128 | }; | 128 | }; |
129 | 129 | ||
130 | struct fc2580_priv { | 130 | struct fc2580_priv { |
131 | const struct fc2580_config *cfg; | 131 | u32 clk; |
132 | struct i2c_client *client; | ||
132 | struct i2c_adapter *i2c; | 133 | struct i2c_adapter *i2c; |
134 | u8 i2c_addr; | ||
133 | }; | 135 | }; |
134 | 136 | ||
135 | #endif | 137 | #endif |