aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAntti Palosaari <crope@iki.fi>2016-08-09 19:49:09 -0400
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2016-09-22 09:41:15 -0400
commit07fdf7d9f19fb601a0cc75c47ecd55aa26019eed (patch)
tree42c2533a8007e3e57a6156a989558836788a3041 /drivers
parent4aa4fd86bca5769c9884838501454ef4c486936d (diff)
[media] cxd2820r: add I2C driver bindings
Add I2C driver bindings in order to support proper I2C driver registration with driver core. Signed-off-by: Antti Palosaari <crope@iki.fi> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/dvb-frontends/cxd2820r.h26
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_c.c6
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_core.c190
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_priv.h7
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_t.c6
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_t2.c8
6 files changed, 191 insertions, 52 deletions
diff --git a/drivers/media/dvb-frontends/cxd2820r.h b/drivers/media/dvb-frontends/cxd2820r.h
index 56d42760263d..d77afe0b8a9e 100644
--- a/drivers/media/dvb-frontends/cxd2820r.h
+++ b/drivers/media/dvb-frontends/cxd2820r.h
@@ -37,6 +37,32 @@
37#define CXD2820R_TS_PARALLEL 0x30 37#define CXD2820R_TS_PARALLEL 0x30
38#define CXD2820R_TS_PARALLEL_MSB 0x70 38#define CXD2820R_TS_PARALLEL_MSB 0x70
39 39
40/*
41 * I2C address: 0x6c, 0x6d
42 */
43
44/**
45 * struct cxd2820r_platform_data - Platform data for the cxd2820r driver
46 * @ts_mode: TS mode.
47 * @ts_clk_inv: TS clock inverted.
48 * @if_agc_polarity: IF AGC polarity.
49 * @spec_inv: Input spectrum inverted.
50 * @gpio_chip_base: GPIO.
51 * @get_dvb_frontend: Get DVB frontend.
52 */
53
54struct cxd2820r_platform_data {
55 u8 ts_mode;
56 bool ts_clk_inv;
57 bool if_agc_polarity;
58 bool spec_inv;
59 int **gpio_chip_base;
60
61 struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *);
62/* private: For legacy media attach wrapper. Do not set value. */
63 bool attach_in_use;
64};
65
40struct cxd2820r_config { 66struct cxd2820r_config {
41 /* Demodulator I2C address. 67 /* Demodulator I2C address.
42 * Driver determines DVB-C slave I2C address automatically from master 68 * Driver determines DVB-C slave I2C address automatically from master
diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c
index 82df94413aeb..0d036e1a43e2 100644
--- a/drivers/media/dvb-frontends/cxd2820r_c.c
+++ b/drivers/media/dvb-frontends/cxd2820r_c.c
@@ -42,9 +42,9 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe)
42 { 0x10059, 0x50, 0xff }, 42 { 0x10059, 0x50, 0xff },
43 { 0x10087, 0x0c, 0x3c }, 43 { 0x10087, 0x0c, 0x3c },
44 { 0x1008b, 0x07, 0xff }, 44 { 0x1008b, 0x07, 0xff },
45 { 0x1001f, priv->cfg.if_agc_polarity << 7, 0x80 }, 45 { 0x1001f, priv->if_agc_polarity << 7, 0x80 },
46 { 0x10070, priv->cfg.ts_mode, 0xff }, 46 { 0x10070, priv->ts_mode, 0xff },
47 { 0x10071, !priv->cfg.ts_clock_inv << 4, 0x10 }, 47 { 0x10071, !priv->ts_clk_inv << 4, 0x10 },
48 }; 48 };
49 49
50 dev_dbg(&priv->i2c->dev, "%s: frequency=%d symbol_rate=%d\n", __func__, 50 dev_dbg(&priv->i2c->dev, "%s: frequency=%d symbol_rate=%d\n", __func__,
diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c
index 66da8212cb60..cf5eed477c44 100644
--- a/drivers/media/dvb-frontends/cxd2820r_core.c
+++ b/drivers/media/dvb-frontends/cxd2820r_core.c
@@ -49,7 +49,7 @@ static int cxd2820r_wr_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg,
49 buf[0] = reg; 49 buf[0] = reg;
50 memcpy(&buf[1], val, len); 50 memcpy(&buf[1], val, len);
51 51
52 ret = i2c_transfer(priv->i2c, msg, 1); 52 ret = i2c_transfer(priv->client[0]->adapter, msg, 1);
53 if (ret == 1) { 53 if (ret == 1) {
54 ret = 0; 54 ret = 0;
55 } else { 55 } else {
@@ -87,7 +87,7 @@ static int cxd2820r_rd_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg,
87 return -EINVAL; 87 return -EINVAL;
88 } 88 }
89 89
90 ret = i2c_transfer(priv->i2c, msg, 2); 90 ret = i2c_transfer(priv->client[0]->adapter, msg, 2);
91 if (ret == 2) { 91 if (ret == 2) {
92 memcpy(val, buf, len); 92 memcpy(val, buf, len);
93 ret = 0; 93 ret = 0;
@@ -112,9 +112,9 @@ int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
112 112
113 /* select I2C */ 113 /* select I2C */
114 if (i2c) 114 if (i2c)
115 i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */ 115 i2c_addr = priv->client[1]->addr; /* DVB-C */
116 else 116 else
117 i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */ 117 i2c_addr = priv->client[0]->addr; /* DVB-T/T2 */
118 118
119 /* switch bank if needed */ 119 /* switch bank if needed */
120 if (bank != priv->bank[i2c]) { 120 if (bank != priv->bank[i2c]) {
@@ -138,9 +138,9 @@ int cxd2820r_rd_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
138 138
139 /* select I2C */ 139 /* select I2C */
140 if (i2c) 140 if (i2c)
141 i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */ 141 i2c_addr = priv->client[1]->addr; /* DVB-C */
142 else 142 else
143 i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */ 143 i2c_addr = priv->client[0]->addr; /* DVB-T/T2 */
144 144
145 /* switch bank if needed */ 145 /* switch bank if needed */
146 if (bank != priv->bank[i2c]) { 146 if (bank != priv->bank[i2c]) {
@@ -537,16 +537,12 @@ static int cxd2820r_get_frontend_algo(struct dvb_frontend *fe)
537static void cxd2820r_release(struct dvb_frontend *fe) 537static void cxd2820r_release(struct dvb_frontend *fe)
538{ 538{
539 struct cxd2820r_priv *priv = fe->demodulator_priv; 539 struct cxd2820r_priv *priv = fe->demodulator_priv;
540 struct i2c_client *client = priv->client[0];
540 541
541 dev_dbg(&priv->i2c->dev, "%s\n", __func__); 542 dev_dbg(&priv->i2c->dev, "%s\n", __func__);
542 543
543#ifdef CONFIG_GPIOLIB 544 i2c_unregister_device(client);
544 /* remove GPIOs */
545 if (priv->gpio_chip.label)
546 gpiochip_remove(&priv->gpio_chip);
547 545
548#endif
549 kfree(priv);
550 return; 546 return;
551} 547}
552 548
@@ -646,49 +642,113 @@ static const struct dvb_frontend_ops cxd2820r_ops = {
646 .read_signal_strength = cxd2820r_read_signal_strength, 642 .read_signal_strength = cxd2820r_read_signal_strength,
647}; 643};
648 644
649struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, 645/*
650 struct i2c_adapter *i2c, int *gpio_chip_base 646 * XXX: That is wrapper to cxd2820r_probe() via driver core in order to provide
651) 647 * proper I2C client for legacy media attach binding.
648 * New users must use I2C client binding directly!
649 */
650struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *config,
651 struct i2c_adapter *adapter,
652 int *gpio_chip_base)
652{ 653{
654 struct i2c_client *client;
655 struct i2c_board_info board_info;
656 struct cxd2820r_platform_data pdata;
657
658 pdata.ts_mode = config->ts_mode;
659 pdata.ts_clk_inv = config->ts_clock_inv;
660 pdata.if_agc_polarity = config->if_agc_polarity;
661 pdata.spec_inv = config->spec_inv;
662 pdata.gpio_chip_base = &gpio_chip_base;
663 pdata.attach_in_use = true;
664
665 memset(&board_info, 0, sizeof(board_info));
666 strlcpy(board_info.type, "cxd2820r", I2C_NAME_SIZE);
667 board_info.addr = config->i2c_address;
668 board_info.platform_data = &pdata;
669 client = i2c_new_device(adapter, &board_info);
670 if (!client || !client->dev.driver)
671 return NULL;
672
673 return pdata.get_dvb_frontend(client);
674}
675EXPORT_SYMBOL(cxd2820r_attach);
676
677static struct dvb_frontend *cxd2820r_get_dvb_frontend(struct i2c_client *client)
678{
679 struct cxd2820r_priv *priv = i2c_get_clientdata(client);
680
681 dev_dbg(&client->dev, "\n");
682
683 return &priv->fe;
684}
685
686static int cxd2820r_probe(struct i2c_client *client,
687 const struct i2c_device_id *id)
688{
689 struct cxd2820r_platform_data *pdata = client->dev.platform_data;
653 struct cxd2820r_priv *priv; 690 struct cxd2820r_priv *priv;
654 int ret; 691 int ret, *gpio_chip_base;
655 u8 tmp; 692 u8 u8tmp;
656 693
657 priv = kzalloc(sizeof(struct cxd2820r_priv), GFP_KERNEL); 694 dev_dbg(&client->dev, "\n");
695
696 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
658 if (!priv) { 697 if (!priv) {
659 ret = -ENOMEM; 698 ret = -ENOMEM;
660 dev_err(&i2c->dev, "%s: kzalloc() failed\n", 699 goto err;
661 KBUILD_MODNAME);
662 goto error;
663 } 700 }
664 701
665 priv->i2c = i2c; 702 priv->client[0] = client;
666 memcpy(&priv->cfg, cfg, sizeof(struct cxd2820r_config)); 703 priv->i2c = client->adapter;
667 memcpy(&priv->fe.ops, &cxd2820r_ops, sizeof(struct dvb_frontend_ops)); 704 priv->ts_mode = pdata->ts_mode;
668 priv->fe.demodulator_priv = priv; 705 priv->ts_clk_inv = pdata->ts_clk_inv;
706 priv->if_agc_polarity = pdata->if_agc_polarity;
707 priv->spec_inv = pdata->spec_inv;
708 priv->bank[0] = 0xff;
709 priv->bank[1] = 0xff;
710 gpio_chip_base = *pdata->gpio_chip_base;
711
712 /* Check demod answers with correct chip id */
713 ret = cxd2820r_rd_reg(priv, 0x000fd, &u8tmp);
714 if (ret)
715 goto err_kfree;
669 716
670 priv->bank[0] = priv->bank[1] = 0xff; 717 dev_dbg(&client->dev, "chip_id=%02x\n", u8tmp);
671 ret = cxd2820r_rd_reg(priv, 0x000fd, &tmp); 718
672 dev_dbg(&priv->i2c->dev, "%s: chip id=%02x\n", __func__, tmp); 719 if (u8tmp != 0xe1) {
673 if (ret || tmp != 0xe1) 720 ret = -ENODEV;
674 goto error; 721 goto err_kfree;
722 }
723
724 /*
725 * Chip has two I2C addresses for different register banks. We register
726 * one dummy I2C client in in order to get own I2C client for each
727 * register bank.
728 */
729 priv->client[1] = i2c_new_dummy(client->adapter, client->addr | (1 << 1));
730 if (!priv->client[1]) {
731 ret = -ENODEV;
732 dev_err(&client->dev, "I2C registration failed\n");
733 if (ret)
734 goto err_kfree;
735 }
675 736
676 if (gpio_chip_base) { 737 if (gpio_chip_base) {
677#ifdef CONFIG_GPIOLIB 738#ifdef CONFIG_GPIOLIB
678 /* add GPIOs */ 739 /* Add GPIOs */
679 priv->gpio_chip.label = KBUILD_MODNAME; 740 priv->gpio_chip.label = KBUILD_MODNAME;
680 priv->gpio_chip.parent = &priv->i2c->dev; 741 priv->gpio_chip.parent = &priv->i2c->dev;
681 priv->gpio_chip.owner = THIS_MODULE; 742 priv->gpio_chip.owner = THIS_MODULE;
682 priv->gpio_chip.direction_output = 743 priv->gpio_chip.direction_output = cxd2820r_gpio_direction_output;
683 cxd2820r_gpio_direction_output;
684 priv->gpio_chip.set = cxd2820r_gpio_set; 744 priv->gpio_chip.set = cxd2820r_gpio_set;
685 priv->gpio_chip.get = cxd2820r_gpio_get; 745 priv->gpio_chip.get = cxd2820r_gpio_get;
686 priv->gpio_chip.base = -1; /* dynamic allocation */ 746 priv->gpio_chip.base = -1; /* Dynamic allocation */
687 priv->gpio_chip.ngpio = GPIO_COUNT; 747 priv->gpio_chip.ngpio = GPIO_COUNT;
688 priv->gpio_chip.can_sleep = 1; 748 priv->gpio_chip.can_sleep = 1;
689 ret = gpiochip_add_data(&priv->gpio_chip, priv); 749 ret = gpiochip_add_data(&priv->gpio_chip, priv);
690 if (ret) 750 if (ret)
691 goto error; 751 goto err_client_1_i2c_unregister_device;
692 752
693 dev_dbg(&priv->i2c->dev, "%s: gpio_chip.base=%d\n", __func__, 753 dev_dbg(&priv->i2c->dev, "%s: gpio_chip.base=%d\n", __func__,
694 priv->gpio_chip.base); 754 priv->gpio_chip.base);
@@ -705,17 +765,65 @@ struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg,
705 gpio[2] = 0; 765 gpio[2] = 0;
706 ret = cxd2820r_gpio(&priv->fe, gpio); 766 ret = cxd2820r_gpio(&priv->fe, gpio);
707 if (ret) 767 if (ret)
708 goto error; 768 goto err_client_1_i2c_unregister_device;
709#endif 769#endif
710 } 770 }
711 771
712 return &priv->fe; 772 /* Create dvb frontend */
713error: 773 memcpy(&priv->fe.ops, &cxd2820r_ops, sizeof(priv->fe.ops));
714 dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); 774 if (!pdata->attach_in_use)
775 priv->fe.ops.release = NULL;
776 priv->fe.demodulator_priv = priv;
777 i2c_set_clientdata(client, priv);
778
779 /* Setup callbacks */
780 pdata->get_dvb_frontend = cxd2820r_get_dvb_frontend;
781
782 dev_info(&client->dev, "Sony CXD2820R successfully identified\n");
783
784 return 0;
785err_client_1_i2c_unregister_device:
786 i2c_unregister_device(priv->client[1]);
787err_kfree:
715 kfree(priv); 788 kfree(priv);
716 return NULL; 789err:
790 dev_dbg(&client->dev, "failed=%d\n", ret);
791 return ret;
717} 792}
718EXPORT_SYMBOL(cxd2820r_attach); 793
794static int cxd2820r_remove(struct i2c_client *client)
795{
796 struct cxd2820r_priv *priv = i2c_get_clientdata(client);
797
798 dev_dbg(&client->dev, "\n");
799
800#ifdef CONFIG_GPIOLIB
801 if (priv->gpio_chip.label)
802 gpiochip_remove(&priv->gpio_chip);
803#endif
804 i2c_unregister_device(priv->client[1]);
805 kfree(priv);
806
807 return 0;
808}
809
810static const struct i2c_device_id cxd2820r_id_table[] = {
811 {"cxd2820r", 0},
812 {}
813};
814MODULE_DEVICE_TABLE(i2c, cxd2820r_id_table);
815
816static struct i2c_driver cxd2820r_driver = {
817 .driver = {
818 .name = "cxd2820r",
819 .suppress_bind_attrs = true,
820 },
821 .probe = cxd2820r_probe,
822 .remove = cxd2820r_remove,
823 .id_table = cxd2820r_id_table,
824};
825
826module_i2c_driver(cxd2820r_driver);
719 827
720MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 828MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
721MODULE_DESCRIPTION("Sony CXD2820R demodulator driver"); 829MODULE_DESCRIPTION("Sony CXD2820R demodulator driver");
diff --git a/drivers/media/dvb-frontends/cxd2820r_priv.h b/drivers/media/dvb-frontends/cxd2820r_priv.h
index 66b19dd1f186..f711fbd6e7e7 100644
--- a/drivers/media/dvb-frontends/cxd2820r_priv.h
+++ b/drivers/media/dvb-frontends/cxd2820r_priv.h
@@ -38,9 +38,14 @@ struct reg_val_mask {
38#define CXD2820R_CLK 41000000 38#define CXD2820R_CLK 41000000
39 39
40struct cxd2820r_priv { 40struct cxd2820r_priv {
41 struct i2c_client *client[2];
41 struct i2c_adapter *i2c; 42 struct i2c_adapter *i2c;
42 struct dvb_frontend fe; 43 struct dvb_frontend fe;
43 struct cxd2820r_config cfg; 44 u8 ts_mode;
45 bool ts_clk_inv;
46 bool if_agc_polarity;
47 bool spec_inv;
48
44 u64 post_bit_error_prev_dvbv3; 49 u64 post_bit_error_prev_dvbv3;
45 u64 post_bit_error; 50 u64 post_bit_error;
46 51
diff --git a/drivers/media/dvb-frontends/cxd2820r_t.c b/drivers/media/dvb-frontends/cxd2820r_t.c
index ddd8e46511a9..e328fe2f7bf9 100644
--- a/drivers/media/dvb-frontends/cxd2820r_t.c
+++ b/drivers/media/dvb-frontends/cxd2820r_t.c
@@ -45,9 +45,9 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe)
45 { 0x00085, 0x07, 0xff }, 45 { 0x00085, 0x07, 0xff },
46 { 0x00088, 0x01, 0xff }, 46 { 0x00088, 0x01, 0xff },
47 47
48 { 0x00070, priv->cfg.ts_mode, 0xff }, 48 { 0x00070, priv->ts_mode, 0xff },
49 { 0x00071, !priv->cfg.ts_clock_inv << 4, 0x10 }, 49 { 0x00071, !priv->ts_clk_inv << 4, 0x10 },
50 { 0x000cb, priv->cfg.if_agc_polarity << 6, 0x40 }, 50 { 0x000cb, priv->if_agc_polarity << 6, 0x40 },
51 { 0x000a5, 0x00, 0x01 }, 51 { 0x000a5, 0x00, 0x01 },
52 { 0x00082, 0x20, 0x60 }, 52 { 0x00082, 0x20, 0x60 },
53 { 0x000c2, 0xc3, 0xff }, 53 { 0x000c2, 0xc3, 0xff },
diff --git a/drivers/media/dvb-frontends/cxd2820r_t2.c b/drivers/media/dvb-frontends/cxd2820r_t2.c
index e09f1527ef0c..3a2c198153a3 100644
--- a/drivers/media/dvb-frontends/cxd2820r_t2.c
+++ b/drivers/media/dvb-frontends/cxd2820r_t2.c
@@ -45,10 +45,10 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe)
45 { 0x0207f, 0x2a, 0xff }, 45 { 0x0207f, 0x2a, 0xff },
46 { 0x02082, 0x0a, 0xff }, 46 { 0x02082, 0x0a, 0xff },
47 { 0x02083, 0x0a, 0xff }, 47 { 0x02083, 0x0a, 0xff },
48 { 0x020cb, priv->cfg.if_agc_polarity << 6, 0x40 }, 48 { 0x020cb, priv->if_agc_polarity << 6, 0x40 },
49 { 0x02070, priv->cfg.ts_mode, 0xff }, 49 { 0x02070, priv->ts_mode, 0xff },
50 { 0x02071, !priv->cfg.ts_clock_inv << 6, 0x40 }, 50 { 0x02071, !priv->ts_clk_inv << 6, 0x40 },
51 { 0x020b5, priv->cfg.spec_inv << 4, 0x10 }, 51 { 0x020b5, priv->spec_inv << 4, 0x10 },
52 { 0x02567, 0x07, 0x0f }, 52 { 0x02567, 0x07, 0x0f },
53 { 0x02569, 0x03, 0x03 }, 53 { 0x02569, 0x03, 0x03 },
54 { 0x02595, 0x1a, 0xff }, 54 { 0x02595, 0x1a, 0xff },