All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7] cx231xx: Add multiple frontend USB device
@ 2018-01-12 16:19 Brad Love
  2018-01-12 16:19 ` [PATCH 1/7] cx231xx: Add second frontend option Brad Love
                   ` (6 more replies)
  0 siblings, 7 replies; 25+ messages in thread
From: Brad Love @ 2018-01-12 16:19 UTC (permalink / raw)
  To: linux-media; +Cc: Brad Love

This patch set requires:

https://patchwork.linuxtv.org/patch/46396/
https://patchwork.linuxtv.org/patch/46397/

The Hauppauge HVR-975 is a dual frontend, single tuner USB device.
The 975 has lgdt3306a (currently enabled) and si2168 demodulators,
and one si2157 tuner. It provides analog capture via breakout cable.

This patch set adds pieces to the cx231xx USB bridge to allow a
second frontend, whether it is old dvb_attach style, or new i2c
device style. A new field is added to board config to accomodate
second demod address.

To accomodate addubg the second demodulator to the si2157 tuner,
hybrid tuner instance functionality was added. The contents of
probe, moved to attach, and .release is provided for shared
instances to clean their state. All changes are backwards
compatible and transparent to current usages.

The si2168 frontend driver required addition of ts bus control,
without this both frontends remain active, after switching between,
and the demux provides no data thereafter.

Finally the second demod is added to the HVR975 and attached
to the si2157.


Brad Love (7):
  cx231xx: Add second frontend option
  cx231xx: Add second i2c demod client
  si2157: Add hybrid tuner support
  si2168: Add ts bus coontrol, turn off bus on sleep
  si2168: Announce frontend creation failure
  lgdt3306a: Announce successful creation
  cx231xx: Add second i2c demod to Hauppauge 975

 drivers/media/dvb-frontends/lgdt3306a.c     |   4 +-
 drivers/media/dvb-frontends/si2168.c        |  40 ++++-
 drivers/media/dvb-frontends/si2168.h        |   1 +
 drivers/media/pci/saa7164/saa7164-dvb.c     |  11 +-
 drivers/media/tuners/si2157.c               | 232 +++++++++++++++++-------
 drivers/media/tuners/si2157.h               |  14 ++
 drivers/media/tuners/si2157_priv.h          |   5 +
 drivers/media/usb/cx231xx/cx231xx-cards.c   |   1 +
 drivers/media/usb/cx231xx/cx231xx-dvb.c     | 269 ++++++++++++++++++----------
 drivers/media/usb/cx231xx/cx231xx-dvb.c.rej |  11 ++
 drivers/media/usb/cx231xx/cx231xx.h         |   1 +
 11 files changed, 411 insertions(+), 178 deletions(-)
 create mode 100644 drivers/media/usb/cx231xx/cx231xx-dvb.c.rej

-- 
2.7.4

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 1/7] cx231xx: Add second frontend option
  2018-01-12 16:19 [PATCH 0/7] cx231xx: Add multiple frontend USB device Brad Love
@ 2018-01-12 16:19 ` Brad Love
  2018-01-12 19:09   ` Alex Deucher
  2018-02-12 21:40   ` [PATCH v2 " Brad Love
  2018-01-12 16:19 ` [PATCH 2/7] cx231xx: Add second i2c demod client Brad Love
                   ` (5 subsequent siblings)
  6 siblings, 2 replies; 25+ messages in thread
From: Brad Love @ 2018-01-12 16:19 UTC (permalink / raw)
  To: linux-media; +Cc: Brad Love

Include ability to add a second dvb attach style frontend to cx231xx
USB bridge. All current boards set to use frontend[0]. Changes are
backwards compatible with current behaviour.

Signed-off-by: Brad Love <brad@nextdimension.cc>
---
 drivers/media/usb/cx231xx/cx231xx-dvb.c | 173 ++++++++++++++++++--------------
 1 file changed, 97 insertions(+), 76 deletions(-)

diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index cb4209f..4c6d2f4 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -55,7 +55,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 #define CX231XX_DVB_MAX_PACKETS 64
 
 struct cx231xx_dvb {
-	struct dvb_frontend *frontend;
+	struct dvb_frontend *frontend[2];
 
 	/* feed count management */
 	struct mutex lock;
@@ -386,17 +386,17 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev)
 	cfg.i2c_adap = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master);
 	cfg.i2c_addr = addr;
 
-	if (!dev->dvb->frontend) {
+	if (!dev->dvb->frontend[0]) {
 		dev_err(dev->dev, "%s/2: dvb frontend not attached. Can't attach xc5000\n",
 			dev->name);
 		return -EINVAL;
 	}
 
-	fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg);
+	fe = dvb_attach(xc5000_attach, dev->dvb->frontend[0], &cfg);
 	if (!fe) {
 		dev_err(dev->dev, "%s/2: xc5000 attach failed\n", dev->name);
-		dvb_frontend_detach(dev->dvb->frontend);
-		dev->dvb->frontend = NULL;
+		dvb_frontend_detach(dev->dvb->frontend[0]);
+		dev->dvb->frontend[0] = NULL;
 		return -EINVAL;
 	}
 
@@ -408,9 +408,9 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev)
 
 int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
 {
-	if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
+	if ((dev->dvb != NULL) && (dev->dvb->frontend[0] != NULL)) {
 
-		struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
+		struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops;
 
 		if (dops->set_analog_params != NULL) {
 			struct analog_parameters params;
@@ -421,7 +421,7 @@ int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
 			/*params.audmode = ;       */
 
 			/* Set the analog parameters to set the frequency */
-			dops->set_analog_params(dev->dvb->frontend, &params);
+			dops->set_analog_params(dev->dvb->frontend[0], &params);
 		}
 
 	}
@@ -433,15 +433,15 @@ int cx231xx_reset_analog_tuner(struct cx231xx *dev)
 {
 	int status = 0;
 
-	if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
+	if ((dev->dvb != NULL) && (dev->dvb->frontend[0] != NULL)) {
 
-		struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
+		struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops;
 
 		if (dops->init != NULL && !dev->xc_fw_load_done) {
 
 			dev_dbg(dev->dev,
 				"Reloading firmware for XC5000\n");
-			status = dops->init(dev->dvb->frontend);
+			status = dops->init(dev->dvb->frontend[0]);
 			if (status == 0) {
 				dev->xc_fw_load_done = 1;
 				dev_dbg(dev->dev,
@@ -481,17 +481,29 @@ static int register_dvb(struct cx231xx_dvb *dvb,
 	dvb_register_media_controller(&dvb->adapter, dev->media_dev);
 
 	/* Ensure all frontends negotiate bus access */
-	dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
+	dvb->frontend[0]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
+	if (dvb->frontend[1])
+		dvb->frontend[1]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
 
 	dvb->adapter.priv = dev;
 
 	/* register frontend */
-	result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+	result = dvb_register_frontend(&dvb->adapter, dvb->frontend[0]);
 	if (result < 0) {
 		dev_warn(dev->dev,
 		       "%s: dvb_register_frontend failed (errno = %d)\n",
 		       dev->name, result);
-		goto fail_frontend;
+		goto fail_frontend0;
+	}
+
+	if (dvb->frontend[1]) {
+		result = dvb_register_frontend(&dvb->adapter, dvb->frontend[1]);
+		if (result < 0) {
+			dev_warn(dev->dev,
+				"%s: 2nd dvb_register_frontend failed (errno = %d)\n",
+				dev->name, result);
+			goto fail_frontend1;
+		}
 	}
 
 	/* register demux stuff */
@@ -569,9 +581,14 @@ static int register_dvb(struct cx231xx_dvb *dvb,
 fail_dmxdev:
 	dvb_dmx_release(&dvb->demux);
 fail_dmx:
-	dvb_unregister_frontend(dvb->frontend);
-fail_frontend:
-	dvb_frontend_detach(dvb->frontend);
+	if (dvb->frontend[1])
+		dvb_unregister_frontend(dvb->frontend[1]);
+	dvb_unregister_frontend(dvb->frontend[0]);
+fail_frontend1:
+	if (dvb->frontend[1])
+		dvb_frontend_detach(dvb->frontend[1]);
+fail_frontend0:
+	dvb_frontend_detach(dvb->frontend[0]);
 	dvb_unregister_adapter(&dvb->adapter);
 fail_adapter:
 	return result;
@@ -585,8 +602,12 @@ static void unregister_dvb(struct cx231xx_dvb *dvb)
 	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
 	dvb_dmxdev_release(&dvb->dmxdev);
 	dvb_dmx_release(&dvb->demux);
-	dvb_unregister_frontend(dvb->frontend);
-	dvb_frontend_detach(dvb->frontend);
+	if (dvb->frontend[1])
+		dvb_unregister_frontend(dvb->frontend[1]);
+	dvb_unregister_frontend(dvb->frontend[0]);
+	if (dvb->frontend[1])
+		dvb_frontend_detach(dvb->frontend[1]);
+	dvb_frontend_detach(dvb->frontend[0]);
 	dvb_unregister_adapter(&dvb->adapter);
 	/* remove I2C tuner */
 	client = dvb->i2c_client_tuner;
@@ -635,11 +656,11 @@ static int dvb_init(struct cx231xx *dev)
 	case CX231XX_BOARD_CNXT_CARRAERA:
 	case CX231XX_BOARD_CNXT_RDE_250:
 
-		dev->dvb->frontend = dvb_attach(s5h1432_attach,
+		dev->dvb->frontend[0] = dvb_attach(s5h1432_attach,
 					&dvico_s5h1432_config,
 					demod_i2c);
 
-		if (dev->dvb->frontend == NULL) {
+		if (dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach s5h1432 front end\n");
 			result = -EINVAL;
@@ -647,9 +668,9 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
-		if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
+		if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0],
 			       tuner_i2c,
 			       &cnxt_rde250_tunerconfig)) {
 			result = -EINVAL;
@@ -660,11 +681,11 @@ static int dvb_init(struct cx231xx *dev)
 	case CX231XX_BOARD_CNXT_SHELBY:
 	case CX231XX_BOARD_CNXT_RDU_250:
 
-		dev->dvb->frontend = dvb_attach(s5h1411_attach,
+		dev->dvb->frontend[0] = dvb_attach(s5h1411_attach,
 					       &xc5000_s5h1411_config,
 					       demod_i2c);
 
-		if (dev->dvb->frontend == NULL) {
+		if (dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach s5h1411 front end\n");
 			result = -EINVAL;
@@ -672,9 +693,9 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
-		if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
+		if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0],
 			       tuner_i2c,
 			       &cnxt_rdu250_tunerconfig)) {
 			result = -EINVAL;
@@ -683,11 +704,11 @@ static int dvb_init(struct cx231xx *dev)
 		break;
 	case CX231XX_BOARD_CNXT_RDE_253S:
 
-		dev->dvb->frontend = dvb_attach(s5h1432_attach,
+		dev->dvb->frontend[0] = dvb_attach(s5h1432_attach,
 					&dvico_s5h1432_config,
 					demod_i2c);
 
-		if (dev->dvb->frontend == NULL) {
+		if (dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach s5h1432 front end\n");
 			result = -EINVAL;
@@ -695,9 +716,9 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
-		if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
+		if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0],
 			       0x60, tuner_i2c,
 			       &cnxt_rde253s_tunerconfig)) {
 			result = -EINVAL;
@@ -707,11 +728,11 @@ static int dvb_init(struct cx231xx *dev)
 	case CX231XX_BOARD_CNXT_RDU_253S:
 	case CX231XX_BOARD_KWORLD_UB445_USB_HYBRID:
 
-		dev->dvb->frontend = dvb_attach(s5h1411_attach,
+		dev->dvb->frontend[0] = dvb_attach(s5h1411_attach,
 					       &tda18271_s5h1411_config,
 					       demod_i2c);
 
-		if (dev->dvb->frontend == NULL) {
+		if (dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach s5h1411 front end\n");
 			result = -EINVAL;
@@ -719,9 +740,9 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
-		if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
+		if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0],
 			       0x60, tuner_i2c,
 			       &cnxt_rde253s_tunerconfig)) {
 			result = -EINVAL;
@@ -734,11 +755,11 @@ static int dvb_init(struct cx231xx *dev)
 			 "%s: looking for tuner / demod on i2c bus: %d\n",
 		       __func__, i2c_adapter_id(tuner_i2c));
 
-		dev->dvb->frontend = dvb_attach(lgdt3305_attach,
+		dev->dvb->frontend[0] = dvb_attach(lgdt3305_attach,
 						&hcw_lgdt3305_config,
 						demod_i2c);
 
-		if (dev->dvb->frontend == NULL) {
+		if (dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach LG3305 front end\n");
 			result = -EINVAL;
@@ -746,9 +767,9 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
-		dvb_attach(tda18271_attach, dev->dvb->frontend,
+		dvb_attach(tda18271_attach, dev->dvb->frontend[0],
 			   0x60, tuner_i2c,
 			   &hcw_tda18271_config);
 		break;
@@ -761,7 +782,7 @@ static int dvb_init(struct cx231xx *dev)
 
 		/* attach demod */
 		memset(&si2165_pdata, 0, sizeof(si2165_pdata));
-		si2165_pdata.fe = &dev->dvb->frontend;
+		si2165_pdata.fe = &dev->dvb->frontend[0];
 		si2165_pdata.chip_mode = SI2165_MODE_PLL_XTAL;
 		si2165_pdata.ref_freq_hz = 16000000;
 
@@ -771,7 +792,7 @@ static int dvb_init(struct cx231xx *dev)
 		info.platform_data = &si2165_pdata;
 		request_module(info.type);
 		client = i2c_new_device(demod_i2c, &info);
-		if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) {
+		if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach SI2165 front end\n");
 			result = -EINVAL;
@@ -786,12 +807,12 @@ static int dvb_init(struct cx231xx *dev)
 
 		dvb->i2c_client_demod = client;
 
-		dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
+		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
-		dvb_attach(tda18271_attach, dev->dvb->frontend,
+		dvb_attach(tda18271_attach, dev->dvb->frontend[0],
 			0x60,
 			tuner_i2c,
 			&hcw_tda18271_config);
@@ -808,7 +829,7 @@ static int dvb_init(struct cx231xx *dev)
 
 		/* attach demod */
 		memset(&si2165_pdata, 0, sizeof(si2165_pdata));
-		si2165_pdata.fe = &dev->dvb->frontend;
+		si2165_pdata.fe = &dev->dvb->frontend[0];
 		si2165_pdata.chip_mode = SI2165_MODE_PLL_EXT;
 		si2165_pdata.ref_freq_hz = 24000000;
 
@@ -818,7 +839,7 @@ static int dvb_init(struct cx231xx *dev)
 		info.platform_data = &si2165_pdata;
 		request_module(info.type);
 		client = i2c_new_device(demod_i2c, &info);
-		if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) {
+		if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach SI2165 front end\n");
 			result = -EINVAL;
@@ -835,14 +856,14 @@ static int dvb_init(struct cx231xx *dev)
 
 		memset(&info, 0, sizeof(struct i2c_board_info));
 
-		dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
+		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
 		/* attach tuner */
 		memset(&si2157_config, 0, sizeof(si2157_config));
-		si2157_config.fe = dev->dvb->frontend;
+		si2157_config.fe = dev->dvb->frontend[0];
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
 		si2157_config.mdev = dev->media_dev;
 #endif
@@ -857,14 +878,14 @@ static int dvb_init(struct cx231xx *dev)
 			tuner_i2c,
 			&info);
 		if (client == NULL || client->dev.driver == NULL) {
-			dvb_frontend_detach(dev->dvb->frontend);
+			dvb_frontend_detach(dev->dvb->frontend[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
 
 		if (!try_module_get(client->dev.driver->owner)) {
 			i2c_unregister_device(client);
-			dvb_frontend_detach(dev->dvb->frontend);
+			dvb_frontend_detach(dev->dvb->frontend[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
@@ -882,26 +903,26 @@ static int dvb_init(struct cx231xx *dev)
 
 		memset(&info, 0, sizeof(struct i2c_board_info));
 
-		dev->dvb->frontend = dvb_attach(lgdt3306a_attach,
+		dev->dvb->frontend[0] = dvb_attach(lgdt3306a_attach,
 			&hauppauge_955q_lgdt3306a_config,
 			demod_i2c
 			);
 
-		if (dev->dvb->frontend == NULL) {
+		if (dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach LGDT3306A frontend.\n");
 			result = -EINVAL;
 			goto out_free;
 		}
 
-		dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
+		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
 		/* attach tuner */
 		memset(&si2157_config, 0, sizeof(si2157_config));
-		si2157_config.fe = dev->dvb->frontend;
+		si2157_config.fe = dev->dvb->frontend[0];
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
 		si2157_config.mdev = dev->media_dev;
 #endif
@@ -916,14 +937,14 @@ static int dvb_init(struct cx231xx *dev)
 			tuner_i2c,
 			&info);
 		if (client == NULL || client->dev.driver == NULL) {
-			dvb_frontend_detach(dev->dvb->frontend);
+			dvb_frontend_detach(dev->dvb->frontend[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
 
 		if (!try_module_get(client->dev.driver->owner)) {
 			i2c_unregister_device(client);
-			dvb_frontend_detach(dev->dvb->frontend);
+			dvb_frontend_detach(dev->dvb->frontend[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
@@ -940,11 +961,11 @@ static int dvb_init(struct cx231xx *dev)
 			 "%s: looking for demod on i2c bus: %d\n",
 			 __func__, i2c_adapter_id(tuner_i2c));
 
-		dev->dvb->frontend = dvb_attach(mb86a20s_attach,
+		dev->dvb->frontend[0] = dvb_attach(mb86a20s_attach,
 						&pv_mb86a20s_config,
 						demod_i2c);
 
-		if (dev->dvb->frontend == NULL) {
+		if (dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach mb86a20s demod\n");
 			result = -EINVAL;
@@ -952,9 +973,9 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
-		dvb_attach(tda18271_attach, dev->dvb->frontend,
+		dvb_attach(tda18271_attach, dev->dvb->frontend[0],
 			   0x60, tuner_i2c,
 			   &pv_tda18271_config);
 		break;
@@ -969,7 +990,7 @@ static int dvb_init(struct cx231xx *dev)
 
 		/* attach demodulator chip */
 		si2168_config.ts_mode = SI2168_TS_SERIAL; /* from *.inf file */
-		si2168_config.fe = &dev->dvb->frontend;
+		si2168_config.fe = &dev->dvb->frontend[0];
 		si2168_config.i2c_adapter = &adapter;
 		si2168_config.ts_clock_inv = true;
 
@@ -994,7 +1015,7 @@ static int dvb_init(struct cx231xx *dev)
 		dvb->i2c_client_demod = client;
 
 		/* attach tuner chip */
-		si2157_config.fe = dev->dvb->frontend;
+		si2157_config.fe = dev->dvb->frontend[0];
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
 		si2157_config.mdev = dev->media_dev;
 #endif
@@ -1037,7 +1058,7 @@ static int dvb_init(struct cx231xx *dev)
 		/* attach demodulator chip */
 		mn88473_config.i2c_wr_max = 16;
 		mn88473_config.xtal = 25000000;
-		mn88473_config.fe = &dev->dvb->frontend;
+		mn88473_config.fe = &dev->dvb->frontend[0];
 
 		strlcpy(info.type, "mn88473", sizeof(info.type));
 		info.addr = dev->board.demod_addr;
@@ -1060,10 +1081,10 @@ static int dvb_init(struct cx231xx *dev)
 		dvb->i2c_client_demod = client;
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
 		/* attach tuner chip */
-		dvb_attach(r820t_attach, dev->dvb->frontend,
+		dvb_attach(r820t_attach, dev->dvb->frontend[0],
 			   tuner_i2c,
 			   &astrometa_t2hybrid_r820t_config);
 		break;
@@ -1078,7 +1099,7 @@ static int dvb_init(struct cx231xx *dev)
 
 		/* attach demodulator chip */
 		si2168_config.ts_mode = SI2168_TS_SERIAL;
-		si2168_config.fe = &dev->dvb->frontend;
+		si2168_config.fe = &dev->dvb->frontend[0];
 		si2168_config.i2c_adapter = &adapter;
 		si2168_config.ts_clock_inv = true;
 
@@ -1102,13 +1123,13 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		dvb->i2c_client_demod = client;
-		dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
+		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
 		/* attach tuner */
-		si2157_config.fe = dev->dvb->frontend;
+		si2157_config.fe = dev->dvb->frontend[0];
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
 		si2157_config.mdev = dev->media_dev;
 #endif
@@ -1153,7 +1174,7 @@ static int dvb_init(struct cx231xx *dev)
 
 		/* attach demodulator chip */
 		lgdt3306a_config = hauppauge_955q_lgdt3306a_config;
-		lgdt3306a_config.fe = &dev->dvb->frontend;
+		lgdt3306a_config.fe = &dev->dvb->frontend[0];
 		lgdt3306a_config.i2c_adapter = &adapter;
 
 		strlcpy(info.type, "lgdt3306a", sizeof(info.type));
@@ -1176,13 +1197,13 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		dvb->i2c_client_demod = client;
-		dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
+		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
 		/* attach tuner */
-		si2157_config.fe = dev->dvb->frontend;
+		si2157_config.fe = dev->dvb->frontend[0];
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
 		si2157_config.mdev = dev->media_dev;
 #endif
@@ -1223,7 +1244,7 @@ static int dvb_init(struct cx231xx *dev)
 			dev->name);
 		break;
 	}
-	if (NULL == dvb->frontend) {
+	if (dvb->frontend[0] == NULL) {
 		dev_err(dev->dev,
 		       "%s/2: frontend initialization failed\n", dev->name);
 		result = -EINVAL;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 2/7] cx231xx: Add second i2c demod client
  2018-01-12 16:19 [PATCH 0/7] cx231xx: Add multiple frontend USB device Brad Love
  2018-01-12 16:19 ` [PATCH 1/7] cx231xx: Add second frontend option Brad Love
@ 2018-01-12 16:19 ` Brad Love
  2018-02-12 21:41   ` [PATCH v2 " Brad Love
  2018-01-12 16:19 ` [PATCH 3/7] si2157: Add hybrid tuner support Brad Love
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 25+ messages in thread
From: Brad Love @ 2018-01-12 16:19 UTC (permalink / raw)
  To: linux-media; +Cc: Brad Love

Include ability to add a i2c device style frontend to cx231xx USB
bridge. All current boards set to use frontend[0]. Changes are
backwards compatible with current behaviour.

Signed-off-by: Brad Love <brad@nextdimension.cc>
---
 drivers/media/usb/cx231xx/cx231xx-dvb.c | 45 ++++++++++++++++++---------------
 drivers/media/usb/cx231xx/cx231xx.h     |  1 +
 2 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index 4c6d2f4..7201e14 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -68,7 +68,7 @@ struct cx231xx_dvb {
 	struct dmx_frontend fe_hw;
 	struct dmx_frontend fe_mem;
 	struct dvb_net net;
-	struct i2c_client *i2c_client_demod;
+	struct i2c_client *i2c_client_demod[2];
 	struct i2c_client *i2c_client_tuner;
 };
 
@@ -616,7 +616,12 @@ static void unregister_dvb(struct cx231xx_dvb *dvb)
 		i2c_unregister_device(client);
 	}
 	/* remove I2C demod */
-	client = dvb->i2c_client_demod;
+	client = dvb->i2c_client_demod[1];
+	if (client) {
+		module_put(client->dev.driver->owner);
+		i2c_unregister_device(client);
+	}
+	client = dvb->i2c_client_demod[0];
 	if (client) {
 		module_put(client->dev.driver->owner);
 		i2c_unregister_device(client);
@@ -805,7 +810,7 @@ static int dvb_init(struct cx231xx *dev)
 			goto out_free;
 		}
 
-		dvb->i2c_client_demod = client;
+		dvb->i2c_client_demod[0] = client;
 
 		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
 
@@ -852,7 +857,7 @@ static int dvb_init(struct cx231xx *dev)
 			goto out_free;
 		}
 
-		dvb->i2c_client_demod = client;
+		dvb->i2c_client_demod[0] = client;
 
 		memset(&info, 0, sizeof(struct i2c_board_info));
 
@@ -1012,7 +1017,7 @@ static int dvb_init(struct cx231xx *dev)
 			goto out_free;
 		}
 
-		dvb->i2c_client_demod = client;
+		dvb->i2c_client_demod[0] = client;
 
 		/* attach tuner chip */
 		si2157_config.fe = dev->dvb->frontend[0];
@@ -1031,16 +1036,16 @@ static int dvb_init(struct cx231xx *dev)
 		client = i2c_new_device(tuner_i2c, &info);
 
 		if (client == NULL || client->dev.driver == NULL) {
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
+			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
 
 		if (!try_module_get(client->dev.driver->owner)) {
 			i2c_unregister_device(client);
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
+			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
@@ -1078,7 +1083,7 @@ static int dvb_init(struct cx231xx *dev)
 			goto out_free;
 		}
 
-		dvb->i2c_client_demod = client;
+		dvb->i2c_client_demod[0] = client;
 
 		/* define general-purpose callback pointer */
 		dvb->frontend[0]->callback = cx231xx_tuner_callback;
@@ -1122,7 +1127,7 @@ static int dvb_init(struct cx231xx *dev)
 			goto out_free;
 		}
 
-		dvb->i2c_client_demod = client;
+		dvb->i2c_client_demod[0] = client;
 		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
 
 		/* define general-purpose callback pointer */
@@ -1144,8 +1149,8 @@ static int dvb_init(struct cx231xx *dev)
 
 		client = i2c_new_device(adapter, &info);
 		if (client == NULL || client->dev.driver == NULL) {
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
+			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
@@ -1154,8 +1159,8 @@ static int dvb_init(struct cx231xx *dev)
 			dev_err(dev->dev,
 				"Failed to obtain %s tuner.\n",	info.type);
 			i2c_unregister_device(client);
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
+			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
@@ -1196,7 +1201,7 @@ static int dvb_init(struct cx231xx *dev)
 			goto out_free;
 		}
 
-		dvb->i2c_client_demod = client;
+		dvb->i2c_client_demod[0] = client;
 		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
 
 		/* define general-purpose callback pointer */
@@ -1218,8 +1223,8 @@ static int dvb_init(struct cx231xx *dev)
 
 		client = i2c_new_device(tuner_i2c, &info);
 		if (client == NULL || client->dev.driver == NULL) {
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
+			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
@@ -1228,8 +1233,8 @@ static int dvb_init(struct cx231xx *dev)
 			dev_err(dev->dev,
 				"Failed to obtain %s tuner.\n",	info.type);
 			i2c_unregister_device(client);
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
+			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index fa993f7..6ffa4bd 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -345,6 +345,7 @@ struct cx231xx_board {
 
 	/* demod related */
 	int demod_addr;
+	int demod_addr2;
 	u8 demod_xfer_mode;	/* 0 - Serial; 1 - parallel */
 
 	/* GPIO Pins */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 3/7] si2157: Add hybrid tuner support
  2018-01-12 16:19 [PATCH 0/7] cx231xx: Add multiple frontend USB device Brad Love
  2018-01-12 16:19 ` [PATCH 1/7] cx231xx: Add second frontend option Brad Love
  2018-01-12 16:19 ` [PATCH 2/7] cx231xx: Add second i2c demod client Brad Love
@ 2018-01-12 16:19 ` Brad Love
  2018-01-16  5:05   ` Antti Palosaari
  2018-01-12 16:19 ` [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep Brad Love
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 25+ messages in thread
From: Brad Love @ 2018-01-12 16:19 UTC (permalink / raw)
  To: linux-media; +Cc: Brad Love

Add ability to share a tuner amongst demodulators. Addtional
demods are attached using hybrid_tuner_instance_list.

The changes are equivalent to moving all of probe to _attach.
Results are backwards compatible with current usage.

If the tuner is acquired via attach, then .release cleans state.
if the tuner is an i2c driver, then .release is set to NULL, and
.remove cleans remaining state.

The following file contains a static si2157_attach:
- drivers/media/pci/saa7164/saa7164-dvb.c
The function name has been appended with _priv to appease
the compiler.

Signed-off-by: Brad Love <brad@nextdimension.cc>
---
 drivers/media/pci/saa7164/saa7164-dvb.c |  11 +-
 drivers/media/tuners/si2157.c           | 232 +++++++++++++++++++++++---------
 drivers/media/tuners/si2157.h           |  14 ++
 drivers/media/tuners/si2157_priv.h      |   5 +
 4 files changed, 192 insertions(+), 70 deletions(-)

diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c b/drivers/media/pci/saa7164/saa7164-dvb.c
index e76d3ba..9522c6c 100644
--- a/drivers/media/pci/saa7164/saa7164-dvb.c
+++ b/drivers/media/pci/saa7164/saa7164-dvb.c
@@ -110,8 +110,9 @@ static struct si2157_config hauppauge_hvr2255_tuner_config = {
 	.if_port = 1,
 };
 
-static int si2157_attach(struct saa7164_port *port, struct i2c_adapter *adapter,
-	struct dvb_frontend *fe, u8 addr8bit, struct si2157_config *cfg)
+static int si2157_attach_priv(struct saa7164_port *port,
+	struct i2c_adapter *adapter, struct dvb_frontend *fe,
+	u8 addr8bit, struct si2157_config *cfg)
 {
 	struct i2c_board_info bi;
 	struct i2c_client *tuner;
@@ -624,11 +625,13 @@ int saa7164_dvb_register(struct saa7164_port *port)
 		if (port->dvb.frontend != NULL) {
 
 			if (port->nr == 0) {
-				si2157_attach(port, &dev->i2c_bus[0].i2c_adap,
+				si2157_attach_priv(port,
+					      &dev->i2c_bus[0].i2c_adap,
 					      port->dvb.frontend, 0xc0,
 					      &hauppauge_hvr2255_tuner_config);
 			} else {
-				si2157_attach(port, &dev->i2c_bus[1].i2c_adap,
+				si2157_attach_priv(port,
+					      &dev->i2c_bus[1].i2c_adap,
 					      port->dvb.frontend, 0xc0,
 					      &hauppauge_hvr2255_tuner_config);
 			}
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
index e35b1fa..9121361 100644
--- a/drivers/media/tuners/si2157.c
+++ b/drivers/media/tuners/si2157.c
@@ -18,6 +18,11 @@
 
 static const struct dvb_tuner_ops si2157_ops;
 
+static DEFINE_MUTEX(si2157_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
+/*---------------------------------------------------------------------*/
+
 /* execute firmware command */
 static int si2157_cmd_execute(struct i2c_client *client, struct si2157_cmd *cmd)
 {
@@ -385,6 +390,31 @@ static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
 	return 0;
 }
 
+static void si2157_release(struct dvb_frontend *fe)
+{
+	struct i2c_client *client = fe->tuner_priv;
+	struct si2157_dev *dev = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "%s()\n", __func__);
+
+	/* only do full cleanup on final instance */
+	if (hybrid_tuner_report_instance_count(dev) == 1) {
+		/* stop statistics polling */
+		cancel_delayed_work_sync(&dev->stat_work);
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+		if (dev->mdev)
+			media_device_unregister_entity(&dev->ent);
+#endif
+		i2c_set_clientdata(client, NULL);
+	}
+
+	mutex_lock(&si2157_list_mutex);
+	hybrid_tuner_release_state(dev);
+	mutex_unlock(&si2157_list_mutex);
+
+	fe->tuner_priv = NULL;
+}
+
 static const struct dvb_tuner_ops si2157_ops = {
 	.info = {
 		.name           = "Silicon Labs Si2141/Si2146/2147/2148/2157/2158",
@@ -396,6 +426,7 @@ static const struct dvb_tuner_ops si2157_ops = {
 	.sleep = si2157_sleep,
 	.set_params = si2157_set_params,
 	.get_if_frequency = si2157_get_if_frequency,
+	.release = si2157_release,
 };
 
 static void si2157_stat_work(struct work_struct *work)
@@ -431,72 +462,30 @@ static int si2157_probe(struct i2c_client *client,
 {
 	struct si2157_config *cfg = client->dev.platform_data;
 	struct dvb_frontend *fe = cfg->fe;
-	struct si2157_dev *dev;
-	struct si2157_cmd cmd;
-	int ret;
-
-	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-	if (!dev) {
-		ret = -ENOMEM;
-		dev_err(&client->dev, "kzalloc() failed\n");
-		goto err;
-	}
-
-	i2c_set_clientdata(client, dev);
-	dev->fe = cfg->fe;
-	dev->inversion = cfg->inversion;
-	dev->if_port = cfg->if_port;
-	dev->chiptype = (u8)id->driver_data;
-	dev->if_frequency = 5000000; /* default value of property 0x0706 */
-	mutex_init(&dev->i2c_mutex);
-	INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work);
+	struct si2157_dev *dev = NULL;
+	unsigned short addr = client->addr;
+	int ret = 0;
 
-	/* check if the tuner is there */
-	cmd.wlen = 0;
-	cmd.rlen = 1;
-	ret = si2157_cmd_execute(client, &cmd);
-	if (ret)
-		goto err_kfree;
-
-	memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops));
+	dev_dbg(&client->dev, "Probing tuner\n");
 	fe->tuner_priv = client;
 
-#ifdef CONFIG_MEDIA_CONTROLLER
-	if (cfg->mdev) {
-		dev->mdev = cfg->mdev;
-
-		dev->ent.name = KBUILD_MODNAME;
-		dev->ent.function = MEDIA_ENT_F_TUNER;
-
-		dev->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
-		dev->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
-		dev->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
-
-		ret = media_entity_pads_init(&dev->ent, TUNER_NUM_PADS,
-					     &dev->pad[0]);
-
-		if (ret)
-			goto err_kfree;
-
-		ret = media_device_register_entity(cfg->mdev, &dev->ent);
-		if (ret) {
-			media_entity_cleanup(&dev->ent);
-			goto err_kfree;
-		}
+	if (si2157_attach(fe, (u8)addr, client->adapter, cfg) == NULL) {
+		dev_err(&client->dev, "%s: attaching si2157 tuner failed\n",
+				__func__);
+		goto err;
 	}
-#endif
+	fe->ops.tuner_ops.release = NULL;
 
+	dev = i2c_get_clientdata(client);
+	dev->chiptype = (u8)id->driver_data;
 	dev_info(&client->dev, "Silicon Labs %s successfully attached\n",
 			dev->chiptype == SI2157_CHIPTYPE_SI2141 ?  "Si2141" :
 			dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
 			"Si2146" : "Si2147/2148/2157/2158");
 
 	return 0;
-
-err_kfree:
-	kfree(dev);
 err:
-	dev_dbg(&client->dev, "failed=%d\n", ret);
+	dev_warn(&client->dev, "probe failed = %d\n", ret);
 	return ret;
 }
 
@@ -505,19 +494,10 @@ static int si2157_remove(struct i2c_client *client)
 	struct si2157_dev *dev = i2c_get_clientdata(client);
 	struct dvb_frontend *fe = dev->fe;
 
-	dev_dbg(&client->dev, "\n");
-
-	/* stop statistics polling */
-	cancel_delayed_work_sync(&dev->stat_work);
-
-#ifdef CONFIG_MEDIA_CONTROLLER_DVB
-	if (dev->mdev)
-		media_device_unregister_entity(&dev->ent);
-#endif
+	dev_dbg(&client->dev, "%s()\n", __func__);
 
 	memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
-	fe->tuner_priv = NULL;
-	kfree(dev);
+	si2157_release(fe);
 
 	return 0;
 }
@@ -542,7 +522,127 @@ static struct i2c_driver si2157_driver = {
 
 module_i2c_driver(si2157_driver);
 
-MODULE_DESCRIPTION("Silicon Labs Si2141/Si2146/2147/2148/2157/2158 silicon tuner driver");
+struct dvb_frontend *si2157_attach(struct dvb_frontend *fe, u8 addr,
+		struct i2c_adapter *i2c,
+		struct si2157_config *cfg)
+{
+	struct i2c_client *client = NULL;
+	struct si2157_dev *dev = NULL;
+	struct si2157_cmd cmd;
+	int instance = 0, ret;
+
+	pr_debug("%s (%d-%04x)\n", __func__,
+	       i2c ? i2c_adapter_id(i2c) : 0,
+	       addr);
+
+	if (!cfg) {
+		pr_warn("no configuration submitted\n");
+		goto fail;
+	}
+
+	if (!fe) {
+		pr_warn("fe is NULL\n");
+		goto fail;
+	}
+
+	client = fe->tuner_priv;
+	if (!client) {
+		pr_warn("client is NULL\n");
+		goto fail;
+	}
+
+	mutex_lock(&si2157_list_mutex);
+
+	instance = hybrid_tuner_request_state(struct si2157_dev, dev,
+			hybrid_tuner_instance_list,
+			i2c, addr, "si2157");
+
+	switch (instance) {
+	case 0:
+		goto fail;
+	case 1:
+		/* new tuner instance */
+		dev_dbg(&client->dev, "%s(): new instance for tuner @0x%02x\n",
+				__func__, addr);
+		dev->addr = addr;
+		i2c_set_clientdata(client, dev);
+
+		dev->fe = fe;
+		dev->chiptype = SI2157_CHIPTYPE_SI2157;
+		dev->if_frequency = 0;
+		dev->if_port   = cfg->if_port;
+		dev->inversion = cfg->inversion;
+
+		mutex_init(&dev->i2c_mutex);
+		INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work);
+
+		break;
+	default:
+		/* existing tuner instance */
+		dev_dbg(&client->dev,
+				"%s(): using existing instance for tuner @0x%02x\n",
+				 __func__, addr);
+		break;
+	}
+
+	/* check if the tuner is there */
+	cmd.wlen = 0;
+	cmd.rlen = 1;
+	ret = si2157_cmd_execute(client, &cmd);
+	/* verify no i2c error and CTS is set */
+	if (ret) {
+		dev_warn(&client->dev, "no HW found ret=%d\n", ret);
+		goto fail_instance;
+	}
+
+	memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops));
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+	if (instance == 1 && cfg->mdev) {
+		dev->mdev = cfg->mdev;
+
+		dev->ent.name = KBUILD_MODNAME;
+		dev->ent.function = MEDIA_ENT_F_TUNER;
+
+		dev->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
+		dev->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
+		dev->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
+
+		ret = media_entity_pads_init(&dev->ent, TUNER_NUM_PADS,
+					     &dev->pad[0]);
+
+		if (ret)
+			goto fail_instance;
+
+		ret = media_device_register_entity(cfg->mdev, &dev->ent);
+		if (ret) {
+			dev_warn(&client->dev,
+				"media_device_regiser_entity returns %d\n", ret);
+			media_entity_cleanup(&dev->ent);
+			goto fail_instance;
+		}
+	}
+#endif
+	mutex_unlock(&si2157_list_mutex);
+
+	if (instance != 1)
+		dev_info(&client->dev, "Silicon Labs %s successfully attached\n",
+			dev->chiptype == SI2157_CHIPTYPE_SI2141 ?  "Si2141" :
+			dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
+			"Si2146" : "Si2147/2148/2157/2158");
+
+	return fe;
+fail_instance:
+	mutex_unlock(&si2157_list_mutex);
+
+	si2157_release(fe);
+fail:
+	dev_warn(&client->dev, "Attach failed\n");
+	return NULL;
+}
+EXPORT_SYMBOL(si2157_attach);
+
+MODULE_DESCRIPTION("Silicon Labs Si2141/2146/2147/2148/2157/2158 silicon tuner driver");
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 MODULE_LICENSE("GPL");
 MODULE_FIRMWARE(SI2158_A20_FIRMWARE);
diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h
index de597fa..26b94ca 100644
--- a/drivers/media/tuners/si2157.h
+++ b/drivers/media/tuners/si2157.h
@@ -46,4 +46,18 @@ struct si2157_config {
 	u8 if_port;
 };
 
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_SI2157)
+extern struct dvb_frontend *si2157_attach(struct dvb_frontend *fe, u8 addr,
+					    struct i2c_adapter *i2c,
+					    struct si2157_config *cfg);
+#else
+static inline struct dvb_frontend *si2157_attach(struct dvb_frontend *fe,
+						   u8 addr,
+						   struct i2c_adapter *i2c,
+						   struct si2157_config *cfg)
+{
+	pr_err("%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
 #endif
diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h
index e6436f7..2801aaa 100644
--- a/drivers/media/tuners/si2157_priv.h
+++ b/drivers/media/tuners/si2157_priv.h
@@ -19,15 +19,20 @@
 
 #include <linux/firmware.h>
 #include <media/v4l2-mc.h>
+#include "tuner-i2c.h"
 #include "si2157.h"
 
 /* state struct */
 struct si2157_dev {
+	struct list_head hybrid_tuner_instance_list;
+	struct tuner_i2c_props  i2c_props;
+
 	struct mutex i2c_mutex;
 	struct dvb_frontend *fe;
 	bool active;
 	bool inversion;
 	u8 chiptype;
+	u8 addr;
 	u8 if_port;
 	u32 if_frequency;
 	struct delayed_work stat_work;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep
  2018-01-12 16:19 [PATCH 0/7] cx231xx: Add multiple frontend USB device Brad Love
                   ` (2 preceding siblings ...)
  2018-01-12 16:19 ` [PATCH 3/7] si2157: Add hybrid tuner support Brad Love
@ 2018-01-12 16:19 ` Brad Love
  2018-01-16  5:07   ` Antti Palosaari
  2018-02-12 20:19   ` [PATCH v2 4/7] si2168: Add ts bus control, " Brad Love
  2018-01-12 16:19 ` [PATCH 6/7] si2168: Announce frontend creation failure Brad Love
                   ` (2 subsequent siblings)
  6 siblings, 2 replies; 25+ messages in thread
From: Brad Love @ 2018-01-12 16:19 UTC (permalink / raw)
  To: linux-media; +Cc: Brad Love

Includes a function to set TS MODE property os si2168. The function
either disables the TS output bus, or sets mode to config option.

When going to sleep the TS bus is turned off, this makes the driver
compatible with multiple frontend usage.

Signed-off-by: Brad Love <brad@nextdimension.cc>
---
 drivers/media/dvb-frontends/si2168.c | 38 ++++++++++++++++++++++++++++--------
 drivers/media/dvb-frontends/si2168.h |  1 +
 2 files changed, 31 insertions(+), 8 deletions(-)

diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
index 539399d..429c03a 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -409,6 +409,30 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
 	return ret;
 }
 
+static int si2168_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+	struct i2c_client *client = fe->demodulator_priv;
+	struct si2168_dev *dev = i2c_get_clientdata(client);
+	struct si2168_cmd cmd;
+	int ret = 0;
+
+	dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire);
+
+	/* set TS_MODE property */
+	memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
+	if (acquire)
+		cmd.args[4] |= dev->ts_mode;
+	else
+		cmd.args[4] |= SI2168_TS_TRISTATE;
+	if (dev->ts_clock_gapped)
+		cmd.args[4] |= 0x40;
+	cmd.wlen = 6;
+	cmd.rlen = 4;
+	ret = si2168_cmd_execute(client, &cmd);
+
+	return ret;
+}
+
 static int si2168_init(struct dvb_frontend *fe)
 {
 	struct i2c_client *client = fe->demodulator_priv;
@@ -540,14 +564,7 @@ static int si2168_init(struct dvb_frontend *fe)
 		 dev->version >> 24 & 0xff, dev->version >> 16 & 0xff,
 		 dev->version >> 8 & 0xff, dev->version >> 0 & 0xff);
 
-	/* set ts mode */
-	memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
-	cmd.args[4] |= dev->ts_mode;
-	if (dev->ts_clock_gapped)
-		cmd.args[4] |= 0x40;
-	cmd.wlen = 6;
-	cmd.rlen = 4;
-	ret = si2168_cmd_execute(client, &cmd);
+	ret = si2168_ts_bus_ctrl(fe, 1);
 	if (ret)
 		goto err;
 
@@ -584,6 +601,9 @@ static int si2168_sleep(struct dvb_frontend *fe)
 
 	dev->active = false;
 
+	/* tri-state data bus */
+	si2168_ts_bus_ctrl(fe, 0);
+
 	/* Firmware B 4.0-11 or later loses warm state during sleep */
 	if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0))
 		dev->warm = false;
@@ -681,6 +701,8 @@ static const struct dvb_frontend_ops si2168_ops = {
 	.init = si2168_init,
 	.sleep = si2168_sleep,
 
+	.ts_bus_ctrl          = si2168_ts_bus_ctrl,
+
 	.set_frontend = si2168_set_frontend,
 
 	.read_status = si2168_read_status,
diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h
index 3225d0c..f48f0fb 100644
--- a/drivers/media/dvb-frontends/si2168.h
+++ b/drivers/media/dvb-frontends/si2168.h
@@ -38,6 +38,7 @@ struct si2168_config {
 	/* TS mode */
 #define SI2168_TS_PARALLEL	0x06
 #define SI2168_TS_SERIAL	0x03
+#define SI2168_TS_TRISTATE	0x00
 	u8 ts_mode;
 
 	/* TS clock inverted */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 6/7] si2168: Announce frontend creation failure
  2018-01-12 16:19 [PATCH 0/7] cx231xx: Add multiple frontend USB device Brad Love
                   ` (3 preceding siblings ...)
  2018-01-12 16:19 ` [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep Brad Love
@ 2018-01-12 16:19 ` Brad Love
  2018-01-16  5:10   ` Antti Palosaari
  2018-01-12 16:19 ` [PATCH 5/7] lgdt3306a: Announce successful creation Brad Love
  2018-01-12 16:19 ` [PATCH 7/7] cx231xx: Add second i2c demod to Hauppauge 975 Brad Love
  6 siblings, 1 reply; 25+ messages in thread
From: Brad Love @ 2018-01-12 16:19 UTC (permalink / raw)
  To: linux-media; +Cc: Brad Love

The driver outputs on success, but is silent on failure. Give
one message that probe failed.

Signed-off-by: Brad Love <brad@nextdimension.cc>
---
 drivers/media/dvb-frontends/si2168.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
index 429c03a..c1a638c 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -810,7 +810,7 @@ static int si2168_probe(struct i2c_client *client,
 err_kfree:
 	kfree(dev);
 err:
-	dev_dbg(&client->dev, "failed=%d\n", ret);
+	dev_warn(&client->dev, "probe failed = %d\n", ret);
 	return ret;
 }
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 5/7] lgdt3306a: Announce successful creation
  2018-01-12 16:19 [PATCH 0/7] cx231xx: Add multiple frontend USB device Brad Love
                   ` (4 preceding siblings ...)
  2018-01-12 16:19 ` [PATCH 6/7] si2168: Announce frontend creation failure Brad Love
@ 2018-01-12 16:19 ` Brad Love
  2018-01-12 16:19 ` [PATCH 7/7] cx231xx: Add second i2c demod to Hauppauge 975 Brad Love
  6 siblings, 0 replies; 25+ messages in thread
From: Brad Love @ 2018-01-12 16:19 UTC (permalink / raw)
  To: linux-media; +Cc: Brad Love

The driver is near silent, this adds a simple announcement at the
end of probe after the chip has been detected and upgrades a debug
message to error if probe has failed.

Signed-off-by: Brad Love <brad@nextdimension.cc>
---
 drivers/media/dvb-frontends/lgdt3306a.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c
index 3642e6e..ec7d04d 100644
--- a/drivers/media/dvb-frontends/lgdt3306a.c
+++ b/drivers/media/dvb-frontends/lgdt3306a.c
@@ -2202,6 +2202,8 @@ static int lgdt3306a_probe(struct i2c_client *client,
 	*config->i2c_adapter = state->muxc->adapter[0];
 	*config->fe = fe;
 
+	dev_info(&client->dev, "LG Electronics LGDT3306A successfully identified\n");
+
 	return 0;
 
 err_kfree:
@@ -2209,7 +2211,7 @@ static int lgdt3306a_probe(struct i2c_client *client,
 err_fe:
 	kfree(config);
 fail:
-	dev_dbg(&client->dev, "failed=%d\n", ret);
+	dev_warn(&client->dev, "probe failed = %d\n", ret);
 	return ret;
 }
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 7/7] cx231xx: Add second i2c demod to Hauppauge 975
  2018-01-12 16:19 [PATCH 0/7] cx231xx: Add multiple frontend USB device Brad Love
                   ` (5 preceding siblings ...)
  2018-01-12 16:19 ` [PATCH 5/7] lgdt3306a: Announce successful creation Brad Love
@ 2018-01-12 16:19 ` Brad Love
  2018-02-12 21:45   ` [PATCH v2 " Brad Love
  6 siblings, 1 reply; 25+ messages in thread
From: Brad Love @ 2018-01-12 16:19 UTC (permalink / raw)
  To: linux-media; +Cc: Brad Love

Hauppauge HVR-975 is a dual frontend, single tuner USB device. It contains
lgdt3306a and si2168 frontends and one si2157 tuner. The lgdt3306a frontend
is currently enabled. This creates the second demodulator and attaches it
to the tuner.

Enables lgdt3306a|si2168 + si2157

Signed-off-by: Brad Love <brad@nextdimension.cc>
---
 drivers/media/usb/cx231xx/cx231xx-cards.c |  1 +
 drivers/media/usb/cx231xx/cx231xx-dvb.c   | 50 +++++++++++++++++++++++++++++--
 2 files changed, 48 insertions(+), 3 deletions(-)

diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index 8582568..00e88a8f 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -979,6 +979,7 @@ struct cx231xx_board cx231xx_boards[] = {
 		.demod_i2c_master = I2C_1_MUX_3,
 		.has_dvb = 1,
 		.demod_addr = 0x59, /* 0xb2 >> 1 */
+		.demod_addr2 = 0x64, /* 0xc8 >> 1 */
 		.norm = V4L2_STD_ALL,
 
 		.input = {{
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index 7201e14..7c947ca 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -1173,14 +1173,17 @@ static int dvb_init(struct cx231xx *dev)
 	{
 		struct i2c_client *client;
 		struct i2c_adapter *adapter;
+		struct i2c_adapter *adapter2;
 		struct i2c_board_info info = {};
 		struct si2157_config si2157_config = {};
 		struct lgdt3306a_config lgdt3306a_config = {};
+		struct si2168_config si2168_config = {};
 
-		/* attach demodulator chip */
+		/* attach first demodulator chip */
 		lgdt3306a_config = hauppauge_955q_lgdt3306a_config;
 		lgdt3306a_config.fe = &dev->dvb->frontend[0];
 		lgdt3306a_config.i2c_adapter = &adapter;
+		lgdt3306a_config.deny_i2c_rptr = 0;
 
 		strlcpy(info.type, "lgdt3306a", sizeof(info.type));
 		info.addr = dev->board.demod_addr;
@@ -1202,10 +1205,39 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		dvb->i2c_client_demod[0] = client;
-		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
+
+		/* attach second demodulator chip */
+		si2168_config.ts_mode = SI2168_TS_SERIAL;
+		si2168_config.fe = &dev->dvb->frontend[1];
+		si2168_config.i2c_adapter = &adapter2;
+		si2168_config.ts_clock_inv = true;
+
+		memset(&info, 0, sizeof(struct i2c_board_info));
+		strlcpy(info.type, "si2168", sizeof(info.type));
+		info.addr = dev->board.demod_addr2;
+		info.platform_data = &si2168_config;
+
+		request_module(info.type);
+		client = i2c_new_device(adapter, &info);
+		if (client == NULL || client->dev.driver == NULL) {
+			result = -ENODEV;
+			goto out_free;
+		}
+
+		if (!try_module_get(client->dev.driver->owner)) {
+			dev_err(dev->dev,
+				"Failed to attach %s frontend.\n", info.type);
+			i2c_unregister_device(client);
+			result = -ENODEV;
+			goto out_free;
+		}
+
+		dvb->i2c_client_demod[1] = client;
+		dev->dvb->frontend[1]->id = 1;
 
 		/* define general-purpose callback pointer */
 		dvb->frontend[0]->callback = cx231xx_tuner_callback;
+		dvb->frontend[1]->callback = cx231xx_tuner_callback;
 
 		/* attach tuner */
 		si2157_config.fe = dev->dvb->frontend[0];
@@ -1221,8 +1253,10 @@ static int dvb_init(struct cx231xx *dev)
 		info.platform_data = &si2157_config;
 		request_module("si2157");
 
-		client = i2c_new_device(tuner_i2c, &info);
+		client = i2c_new_device(adapter, &info);
 		if (client == NULL || client->dev.driver == NULL) {
+			module_put(dvb->i2c_client_demod[1]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[1]);
 			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
 			i2c_unregister_device(dvb->i2c_client_demod[0]);
 			result = -ENODEV;
@@ -1233,6 +1267,8 @@ static int dvb_init(struct cx231xx *dev)
 			dev_err(dev->dev,
 				"Failed to obtain %s tuner.\n",	info.type);
 			i2c_unregister_device(client);
+			module_put(dvb->i2c_client_demod[1]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[1]);
 			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
 			i2c_unregister_device(dvb->i2c_client_demod[0]);
 			result = -ENODEV;
@@ -1241,6 +1277,14 @@ static int dvb_init(struct cx231xx *dev)
 
 		dev->cx231xx_reset_analog_tuner = NULL;
 		dev->dvb->i2c_client_tuner = client;
+
+		dev->dvb->frontend[1]->tuner_priv =
+			dev->dvb->frontend[0]->tuner_priv;
+
+		dvb_attach(si2157_attach, dev->dvb->frontend[1],
+			dev->board.tuner_addr, adapter,
+			&si2157_config);
+
 		break;
 	}
 	default:
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/7] cx231xx: Add second frontend option
  2018-01-12 16:19 ` [PATCH 1/7] cx231xx: Add second frontend option Brad Love
@ 2018-01-12 19:09   ` Alex Deucher
  2018-02-12 21:43     ` Brad Love
  2018-02-12 21:40   ` [PATCH v2 " Brad Love
  1 sibling, 1 reply; 25+ messages in thread
From: Alex Deucher @ 2018-01-12 19:09 UTC (permalink / raw)
  To: Brad Love; +Cc: linux-media

On Fri, Jan 12, 2018 at 11:19 AM, Brad Love <brad@nextdimension.cc> wrote:
> Include ability to add a second dvb attach style frontend to cx231xx
> USB bridge. All current boards set to use frontend[0]. Changes are
> backwards compatible with current behaviour.
>
> Signed-off-by: Brad Love <brad@nextdimension.cc>
> ---
>  drivers/media/usb/cx231xx/cx231xx-dvb.c | 173 ++++++++++++++++++--------------
>  1 file changed, 97 insertions(+), 76 deletions(-)
>
> diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
> index cb4209f..4c6d2f4 100644
> --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
> +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
> @@ -55,7 +55,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
>  #define CX231XX_DVB_MAX_PACKETS 64
>
>  struct cx231xx_dvb {
> -       struct dvb_frontend *frontend;
> +       struct dvb_frontend *frontend[2];

Maybe define something like CX231XX_MAX_FRONTEND and use it here
rather than using a hardcoded 2.

Alex


>
>         /* feed count management */
>         struct mutex lock;
> @@ -386,17 +386,17 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev)
>         cfg.i2c_adap = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master);
>         cfg.i2c_addr = addr;
>
> -       if (!dev->dvb->frontend) {
> +       if (!dev->dvb->frontend[0]) {
>                 dev_err(dev->dev, "%s/2: dvb frontend not attached. Can't attach xc5000\n",
>                         dev->name);
>                 return -EINVAL;
>         }
>
> -       fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg);
> +       fe = dvb_attach(xc5000_attach, dev->dvb->frontend[0], &cfg);
>         if (!fe) {
>                 dev_err(dev->dev, "%s/2: xc5000 attach failed\n", dev->name);
> -               dvb_frontend_detach(dev->dvb->frontend);
> -               dev->dvb->frontend = NULL;
> +               dvb_frontend_detach(dev->dvb->frontend[0]);
> +               dev->dvb->frontend[0] = NULL;
>                 return -EINVAL;
>         }
>
> @@ -408,9 +408,9 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev)
>
>  int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
>  {
> -       if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
> +       if ((dev->dvb != NULL) && (dev->dvb->frontend[0] != NULL)) {
>
> -               struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
> +               struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops;
>
>                 if (dops->set_analog_params != NULL) {
>                         struct analog_parameters params;
> @@ -421,7 +421,7 @@ int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
>                         /*params.audmode = ;       */
>
>                         /* Set the analog parameters to set the frequency */
> -                       dops->set_analog_params(dev->dvb->frontend, &params);
> +                       dops->set_analog_params(dev->dvb->frontend[0], &params);
>                 }
>
>         }
> @@ -433,15 +433,15 @@ int cx231xx_reset_analog_tuner(struct cx231xx *dev)
>  {
>         int status = 0;
>
> -       if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
> +       if ((dev->dvb != NULL) && (dev->dvb->frontend[0] != NULL)) {
>
> -               struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
> +               struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops;
>
>                 if (dops->init != NULL && !dev->xc_fw_load_done) {
>
>                         dev_dbg(dev->dev,
>                                 "Reloading firmware for XC5000\n");
> -                       status = dops->init(dev->dvb->frontend);
> +                       status = dops->init(dev->dvb->frontend[0]);
>                         if (status == 0) {
>                                 dev->xc_fw_load_done = 1;
>                                 dev_dbg(dev->dev,
> @@ -481,17 +481,29 @@ static int register_dvb(struct cx231xx_dvb *dvb,
>         dvb_register_media_controller(&dvb->adapter, dev->media_dev);
>
>         /* Ensure all frontends negotiate bus access */
> -       dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
> +       dvb->frontend[0]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
> +       if (dvb->frontend[1])
> +               dvb->frontend[1]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
>
>         dvb->adapter.priv = dev;
>
>         /* register frontend */
> -       result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
> +       result = dvb_register_frontend(&dvb->adapter, dvb->frontend[0]);
>         if (result < 0) {
>                 dev_warn(dev->dev,
>                        "%s: dvb_register_frontend failed (errno = %d)\n",
>                        dev->name, result);
> -               goto fail_frontend;
> +               goto fail_frontend0;
> +       }
> +
> +       if (dvb->frontend[1]) {
> +               result = dvb_register_frontend(&dvb->adapter, dvb->frontend[1]);
> +               if (result < 0) {
> +                       dev_warn(dev->dev,
> +                               "%s: 2nd dvb_register_frontend failed (errno = %d)\n",
> +                               dev->name, result);
> +                       goto fail_frontend1;
> +               }
>         }
>
>         /* register demux stuff */
> @@ -569,9 +581,14 @@ static int register_dvb(struct cx231xx_dvb *dvb,
>  fail_dmxdev:
>         dvb_dmx_release(&dvb->demux);
>  fail_dmx:
> -       dvb_unregister_frontend(dvb->frontend);
> -fail_frontend:
> -       dvb_frontend_detach(dvb->frontend);
> +       if (dvb->frontend[1])
> +               dvb_unregister_frontend(dvb->frontend[1]);
> +       dvb_unregister_frontend(dvb->frontend[0]);
> +fail_frontend1:
> +       if (dvb->frontend[1])
> +               dvb_frontend_detach(dvb->frontend[1]);
> +fail_frontend0:
> +       dvb_frontend_detach(dvb->frontend[0]);
>         dvb_unregister_adapter(&dvb->adapter);
>  fail_adapter:
>         return result;
> @@ -585,8 +602,12 @@ static void unregister_dvb(struct cx231xx_dvb *dvb)
>         dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
>         dvb_dmxdev_release(&dvb->dmxdev);
>         dvb_dmx_release(&dvb->demux);
> -       dvb_unregister_frontend(dvb->frontend);
> -       dvb_frontend_detach(dvb->frontend);
> +       if (dvb->frontend[1])
> +               dvb_unregister_frontend(dvb->frontend[1]);
> +       dvb_unregister_frontend(dvb->frontend[0]);
> +       if (dvb->frontend[1])
> +               dvb_frontend_detach(dvb->frontend[1]);
> +       dvb_frontend_detach(dvb->frontend[0]);
>         dvb_unregister_adapter(&dvb->adapter);
>         /* remove I2C tuner */
>         client = dvb->i2c_client_tuner;
> @@ -635,11 +656,11 @@ static int dvb_init(struct cx231xx *dev)
>         case CX231XX_BOARD_CNXT_CARRAERA:
>         case CX231XX_BOARD_CNXT_RDE_250:
>
> -               dev->dvb->frontend = dvb_attach(s5h1432_attach,
> +               dev->dvb->frontend[0] = dvb_attach(s5h1432_attach,
>                                         &dvico_s5h1432_config,
>                                         demod_i2c);
>
> -               if (dev->dvb->frontend == NULL) {
> +               if (dev->dvb->frontend[0] == NULL) {
>                         dev_err(dev->dev,
>                                 "Failed to attach s5h1432 front end\n");
>                         result = -EINVAL;
> @@ -647,9 +668,9 @@ static int dvb_init(struct cx231xx *dev)
>                 }
>
>                 /* define general-purpose callback pointer */
> -               dvb->frontend->callback = cx231xx_tuner_callback;
> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>
> -               if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
> +               if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0],
>                                tuner_i2c,
>                                &cnxt_rde250_tunerconfig)) {
>                         result = -EINVAL;
> @@ -660,11 +681,11 @@ static int dvb_init(struct cx231xx *dev)
>         case CX231XX_BOARD_CNXT_SHELBY:
>         case CX231XX_BOARD_CNXT_RDU_250:
>
> -               dev->dvb->frontend = dvb_attach(s5h1411_attach,
> +               dev->dvb->frontend[0] = dvb_attach(s5h1411_attach,
>                                                &xc5000_s5h1411_config,
>                                                demod_i2c);
>
> -               if (dev->dvb->frontend == NULL) {
> +               if (dev->dvb->frontend[0] == NULL) {
>                         dev_err(dev->dev,
>                                 "Failed to attach s5h1411 front end\n");
>                         result = -EINVAL;
> @@ -672,9 +693,9 @@ static int dvb_init(struct cx231xx *dev)
>                 }
>
>                 /* define general-purpose callback pointer */
> -               dvb->frontend->callback = cx231xx_tuner_callback;
> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>
> -               if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
> +               if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0],
>                                tuner_i2c,
>                                &cnxt_rdu250_tunerconfig)) {
>                         result = -EINVAL;
> @@ -683,11 +704,11 @@ static int dvb_init(struct cx231xx *dev)
>                 break;
>         case CX231XX_BOARD_CNXT_RDE_253S:
>
> -               dev->dvb->frontend = dvb_attach(s5h1432_attach,
> +               dev->dvb->frontend[0] = dvb_attach(s5h1432_attach,
>                                         &dvico_s5h1432_config,
>                                         demod_i2c);
>
> -               if (dev->dvb->frontend == NULL) {
> +               if (dev->dvb->frontend[0] == NULL) {
>                         dev_err(dev->dev,
>                                 "Failed to attach s5h1432 front end\n");
>                         result = -EINVAL;
> @@ -695,9 +716,9 @@ static int dvb_init(struct cx231xx *dev)
>                 }
>
>                 /* define general-purpose callback pointer */
> -               dvb->frontend->callback = cx231xx_tuner_callback;
> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>
> -               if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
> +               if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0],
>                                0x60, tuner_i2c,
>                                &cnxt_rde253s_tunerconfig)) {
>                         result = -EINVAL;
> @@ -707,11 +728,11 @@ static int dvb_init(struct cx231xx *dev)
>         case CX231XX_BOARD_CNXT_RDU_253S:
>         case CX231XX_BOARD_KWORLD_UB445_USB_HYBRID:
>
> -               dev->dvb->frontend = dvb_attach(s5h1411_attach,
> +               dev->dvb->frontend[0] = dvb_attach(s5h1411_attach,
>                                                &tda18271_s5h1411_config,
>                                                demod_i2c);
>
> -               if (dev->dvb->frontend == NULL) {
> +               if (dev->dvb->frontend[0] == NULL) {
>                         dev_err(dev->dev,
>                                 "Failed to attach s5h1411 front end\n");
>                         result = -EINVAL;
> @@ -719,9 +740,9 @@ static int dvb_init(struct cx231xx *dev)
>                 }
>
>                 /* define general-purpose callback pointer */
> -               dvb->frontend->callback = cx231xx_tuner_callback;
> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>
> -               if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
> +               if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0],
>                                0x60, tuner_i2c,
>                                &cnxt_rde253s_tunerconfig)) {
>                         result = -EINVAL;
> @@ -734,11 +755,11 @@ static int dvb_init(struct cx231xx *dev)
>                          "%s: looking for tuner / demod on i2c bus: %d\n",
>                        __func__, i2c_adapter_id(tuner_i2c));
>
> -               dev->dvb->frontend = dvb_attach(lgdt3305_attach,
> +               dev->dvb->frontend[0] = dvb_attach(lgdt3305_attach,
>                                                 &hcw_lgdt3305_config,
>                                                 demod_i2c);
>
> -               if (dev->dvb->frontend == NULL) {
> +               if (dev->dvb->frontend[0] == NULL) {
>                         dev_err(dev->dev,
>                                 "Failed to attach LG3305 front end\n");
>                         result = -EINVAL;
> @@ -746,9 +767,9 @@ static int dvb_init(struct cx231xx *dev)
>                 }
>
>                 /* define general-purpose callback pointer */
> -               dvb->frontend->callback = cx231xx_tuner_callback;
> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>
> -               dvb_attach(tda18271_attach, dev->dvb->frontend,
> +               dvb_attach(tda18271_attach, dev->dvb->frontend[0],
>                            0x60, tuner_i2c,
>                            &hcw_tda18271_config);
>                 break;
> @@ -761,7 +782,7 @@ static int dvb_init(struct cx231xx *dev)
>
>                 /* attach demod */
>                 memset(&si2165_pdata, 0, sizeof(si2165_pdata));
> -               si2165_pdata.fe = &dev->dvb->frontend;
> +               si2165_pdata.fe = &dev->dvb->frontend[0];
>                 si2165_pdata.chip_mode = SI2165_MODE_PLL_XTAL;
>                 si2165_pdata.ref_freq_hz = 16000000;
>
> @@ -771,7 +792,7 @@ static int dvb_init(struct cx231xx *dev)
>                 info.platform_data = &si2165_pdata;
>                 request_module(info.type);
>                 client = i2c_new_device(demod_i2c, &info);
> -               if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) {
> +               if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend[0] == NULL) {
>                         dev_err(dev->dev,
>                                 "Failed to attach SI2165 front end\n");
>                         result = -EINVAL;
> @@ -786,12 +807,12 @@ static int dvb_init(struct cx231xx *dev)
>
>                 dvb->i2c_client_demod = client;
>
> -               dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
> +               dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
>
>                 /* define general-purpose callback pointer */
> -               dvb->frontend->callback = cx231xx_tuner_callback;
> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>
> -               dvb_attach(tda18271_attach, dev->dvb->frontend,
> +               dvb_attach(tda18271_attach, dev->dvb->frontend[0],
>                         0x60,
>                         tuner_i2c,
>                         &hcw_tda18271_config);
> @@ -808,7 +829,7 @@ static int dvb_init(struct cx231xx *dev)
>
>                 /* attach demod */
>                 memset(&si2165_pdata, 0, sizeof(si2165_pdata));
> -               si2165_pdata.fe = &dev->dvb->frontend;
> +               si2165_pdata.fe = &dev->dvb->frontend[0];
>                 si2165_pdata.chip_mode = SI2165_MODE_PLL_EXT;
>                 si2165_pdata.ref_freq_hz = 24000000;
>
> @@ -818,7 +839,7 @@ static int dvb_init(struct cx231xx *dev)
>                 info.platform_data = &si2165_pdata;
>                 request_module(info.type);
>                 client = i2c_new_device(demod_i2c, &info);
> -               if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) {
> +               if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend[0] == NULL) {
>                         dev_err(dev->dev,
>                                 "Failed to attach SI2165 front end\n");
>                         result = -EINVAL;
> @@ -835,14 +856,14 @@ static int dvb_init(struct cx231xx *dev)
>
>                 memset(&info, 0, sizeof(struct i2c_board_info));
>
> -               dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
> +               dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
>
>                 /* define general-purpose callback pointer */
> -               dvb->frontend->callback = cx231xx_tuner_callback;
> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>
>                 /* attach tuner */
>                 memset(&si2157_config, 0, sizeof(si2157_config));
> -               si2157_config.fe = dev->dvb->frontend;
> +               si2157_config.fe = dev->dvb->frontend[0];
>  #ifdef CONFIG_MEDIA_CONTROLLER_DVB
>                 si2157_config.mdev = dev->media_dev;
>  #endif
> @@ -857,14 +878,14 @@ static int dvb_init(struct cx231xx *dev)
>                         tuner_i2c,
>                         &info);
>                 if (client == NULL || client->dev.driver == NULL) {
> -                       dvb_frontend_detach(dev->dvb->frontend);
> +                       dvb_frontend_detach(dev->dvb->frontend[0]);
>                         result = -ENODEV;
>                         goto out_free;
>                 }
>
>                 if (!try_module_get(client->dev.driver->owner)) {
>                         i2c_unregister_device(client);
> -                       dvb_frontend_detach(dev->dvb->frontend);
> +                       dvb_frontend_detach(dev->dvb->frontend[0]);
>                         result = -ENODEV;
>                         goto out_free;
>                 }
> @@ -882,26 +903,26 @@ static int dvb_init(struct cx231xx *dev)
>
>                 memset(&info, 0, sizeof(struct i2c_board_info));
>
> -               dev->dvb->frontend = dvb_attach(lgdt3306a_attach,
> +               dev->dvb->frontend[0] = dvb_attach(lgdt3306a_attach,
>                         &hauppauge_955q_lgdt3306a_config,
>                         demod_i2c
>                         );
>
> -               if (dev->dvb->frontend == NULL) {
> +               if (dev->dvb->frontend[0] == NULL) {
>                         dev_err(dev->dev,
>                                 "Failed to attach LGDT3306A frontend.\n");
>                         result = -EINVAL;
>                         goto out_free;
>                 }
>
> -               dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
> +               dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
>
>                 /* define general-purpose callback pointer */
> -               dvb->frontend->callback = cx231xx_tuner_callback;
> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>
>                 /* attach tuner */
>                 memset(&si2157_config, 0, sizeof(si2157_config));
> -               si2157_config.fe = dev->dvb->frontend;
> +               si2157_config.fe = dev->dvb->frontend[0];
>  #ifdef CONFIG_MEDIA_CONTROLLER_DVB
>                 si2157_config.mdev = dev->media_dev;
>  #endif
> @@ -916,14 +937,14 @@ static int dvb_init(struct cx231xx *dev)
>                         tuner_i2c,
>                         &info);
>                 if (client == NULL || client->dev.driver == NULL) {
> -                       dvb_frontend_detach(dev->dvb->frontend);
> +                       dvb_frontend_detach(dev->dvb->frontend[0]);
>                         result = -ENODEV;
>                         goto out_free;
>                 }
>
>                 if (!try_module_get(client->dev.driver->owner)) {
>                         i2c_unregister_device(client);
> -                       dvb_frontend_detach(dev->dvb->frontend);
> +                       dvb_frontend_detach(dev->dvb->frontend[0]);
>                         result = -ENODEV;
>                         goto out_free;
>                 }
> @@ -940,11 +961,11 @@ static int dvb_init(struct cx231xx *dev)
>                          "%s: looking for demod on i2c bus: %d\n",
>                          __func__, i2c_adapter_id(tuner_i2c));
>
> -               dev->dvb->frontend = dvb_attach(mb86a20s_attach,
> +               dev->dvb->frontend[0] = dvb_attach(mb86a20s_attach,
>                                                 &pv_mb86a20s_config,
>                                                 demod_i2c);
>
> -               if (dev->dvb->frontend == NULL) {
> +               if (dev->dvb->frontend[0] == NULL) {
>                         dev_err(dev->dev,
>                                 "Failed to attach mb86a20s demod\n");
>                         result = -EINVAL;
> @@ -952,9 +973,9 @@ static int dvb_init(struct cx231xx *dev)
>                 }
>
>                 /* define general-purpose callback pointer */
> -               dvb->frontend->callback = cx231xx_tuner_callback;
> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>
> -               dvb_attach(tda18271_attach, dev->dvb->frontend,
> +               dvb_attach(tda18271_attach, dev->dvb->frontend[0],
>                            0x60, tuner_i2c,
>                            &pv_tda18271_config);
>                 break;
> @@ -969,7 +990,7 @@ static int dvb_init(struct cx231xx *dev)
>
>                 /* attach demodulator chip */
>                 si2168_config.ts_mode = SI2168_TS_SERIAL; /* from *.inf file */
> -               si2168_config.fe = &dev->dvb->frontend;
> +               si2168_config.fe = &dev->dvb->frontend[0];
>                 si2168_config.i2c_adapter = &adapter;
>                 si2168_config.ts_clock_inv = true;
>
> @@ -994,7 +1015,7 @@ static int dvb_init(struct cx231xx *dev)
>                 dvb->i2c_client_demod = client;
>
>                 /* attach tuner chip */
> -               si2157_config.fe = dev->dvb->frontend;
> +               si2157_config.fe = dev->dvb->frontend[0];
>  #ifdef CONFIG_MEDIA_CONTROLLER_DVB
>                 si2157_config.mdev = dev->media_dev;
>  #endif
> @@ -1037,7 +1058,7 @@ static int dvb_init(struct cx231xx *dev)
>                 /* attach demodulator chip */
>                 mn88473_config.i2c_wr_max = 16;
>                 mn88473_config.xtal = 25000000;
> -               mn88473_config.fe = &dev->dvb->frontend;
> +               mn88473_config.fe = &dev->dvb->frontend[0];
>
>                 strlcpy(info.type, "mn88473", sizeof(info.type));
>                 info.addr = dev->board.demod_addr;
> @@ -1060,10 +1081,10 @@ static int dvb_init(struct cx231xx *dev)
>                 dvb->i2c_client_demod = client;
>
>                 /* define general-purpose callback pointer */
> -               dvb->frontend->callback = cx231xx_tuner_callback;
> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>
>                 /* attach tuner chip */
> -               dvb_attach(r820t_attach, dev->dvb->frontend,
> +               dvb_attach(r820t_attach, dev->dvb->frontend[0],
>                            tuner_i2c,
>                            &astrometa_t2hybrid_r820t_config);
>                 break;
> @@ -1078,7 +1099,7 @@ static int dvb_init(struct cx231xx *dev)
>
>                 /* attach demodulator chip */
>                 si2168_config.ts_mode = SI2168_TS_SERIAL;
> -               si2168_config.fe = &dev->dvb->frontend;
> +               si2168_config.fe = &dev->dvb->frontend[0];
>                 si2168_config.i2c_adapter = &adapter;
>                 si2168_config.ts_clock_inv = true;
>
> @@ -1102,13 +1123,13 @@ static int dvb_init(struct cx231xx *dev)
>                 }
>
>                 dvb->i2c_client_demod = client;
> -               dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
> +               dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
>
>                 /* define general-purpose callback pointer */
> -               dvb->frontend->callback = cx231xx_tuner_callback;
> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>
>                 /* attach tuner */
> -               si2157_config.fe = dev->dvb->frontend;
> +               si2157_config.fe = dev->dvb->frontend[0];
>  #ifdef CONFIG_MEDIA_CONTROLLER_DVB
>                 si2157_config.mdev = dev->media_dev;
>  #endif
> @@ -1153,7 +1174,7 @@ static int dvb_init(struct cx231xx *dev)
>
>                 /* attach demodulator chip */
>                 lgdt3306a_config = hauppauge_955q_lgdt3306a_config;
> -               lgdt3306a_config.fe = &dev->dvb->frontend;
> +               lgdt3306a_config.fe = &dev->dvb->frontend[0];
>                 lgdt3306a_config.i2c_adapter = &adapter;
>
>                 strlcpy(info.type, "lgdt3306a", sizeof(info.type));
> @@ -1176,13 +1197,13 @@ static int dvb_init(struct cx231xx *dev)
>                 }
>
>                 dvb->i2c_client_demod = client;
> -               dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
> +               dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
>
>                 /* define general-purpose callback pointer */
> -               dvb->frontend->callback = cx231xx_tuner_callback;
> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>
>                 /* attach tuner */
> -               si2157_config.fe = dev->dvb->frontend;
> +               si2157_config.fe = dev->dvb->frontend[0];
>  #ifdef CONFIG_MEDIA_CONTROLLER_DVB
>                 si2157_config.mdev = dev->media_dev;
>  #endif
> @@ -1223,7 +1244,7 @@ static int dvb_init(struct cx231xx *dev)
>                         dev->name);
>                 break;
>         }
> -       if (NULL == dvb->frontend) {
> +       if (dvb->frontend[0] == NULL) {
>                 dev_err(dev->dev,
>                        "%s/2: frontend initialization failed\n", dev->name);
>                 result = -EINVAL;
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 3/7] si2157: Add hybrid tuner support
  2018-01-12 16:19 ` [PATCH 3/7] si2157: Add hybrid tuner support Brad Love
@ 2018-01-16  5:05   ` Antti Palosaari
  2018-01-16 20:48     ` Brad Love
  0 siblings, 1 reply; 25+ messages in thread
From: Antti Palosaari @ 2018-01-16  5:05 UTC (permalink / raw)
  To: Brad Love, linux-media

Hello
So the use case is to share single tuner with multiple demodulators? Why 
don't just register single tuner and pass that info to multiple demods?

Antti

On 01/12/2018 06:19 PM, Brad Love wrote:
> Add ability to share a tuner amongst demodulators. Addtional
> demods are attached using hybrid_tuner_instance_list.
> 
> The changes are equivalent to moving all of probe to _attach.
> Results are backwards compatible with current usage.
> 
> If the tuner is acquired via attach, then .release cleans state.
> if the tuner is an i2c driver, then .release is set to NULL, and
> .remove cleans remaining state.
> 
> The following file contains a static si2157_attach:
> - drivers/media/pci/saa7164/saa7164-dvb.c
> The function name has been appended with _priv to appease
> the compiler.
> 
> Signed-off-by: Brad Love <brad@nextdimension.cc>
> ---
>   drivers/media/pci/saa7164/saa7164-dvb.c |  11 +-
>   drivers/media/tuners/si2157.c           | 232 +++++++++++++++++++++++---------
>   drivers/media/tuners/si2157.h           |  14 ++
>   drivers/media/tuners/si2157_priv.h      |   5 +
>   4 files changed, 192 insertions(+), 70 deletions(-)
> 
> diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c b/drivers/media/pci/saa7164/saa7164-dvb.c
> index e76d3ba..9522c6c 100644
> --- a/drivers/media/pci/saa7164/saa7164-dvb.c
> +++ b/drivers/media/pci/saa7164/saa7164-dvb.c
> @@ -110,8 +110,9 @@ static struct si2157_config hauppauge_hvr2255_tuner_config = {
>   	.if_port = 1,
>   };
>   
> -static int si2157_attach(struct saa7164_port *port, struct i2c_adapter *adapter,
> -	struct dvb_frontend *fe, u8 addr8bit, struct si2157_config *cfg)
> +static int si2157_attach_priv(struct saa7164_port *port,
> +	struct i2c_adapter *adapter, struct dvb_frontend *fe,
> +	u8 addr8bit, struct si2157_config *cfg)
>   {
>   	struct i2c_board_info bi;
>   	struct i2c_client *tuner;
> @@ -624,11 +625,13 @@ int saa7164_dvb_register(struct saa7164_port *port)
>   		if (port->dvb.frontend != NULL) {
>   
>   			if (port->nr == 0) {
> -				si2157_attach(port, &dev->i2c_bus[0].i2c_adap,
> +				si2157_attach_priv(port,
> +					      &dev->i2c_bus[0].i2c_adap,
>   					      port->dvb.frontend, 0xc0,
>   					      &hauppauge_hvr2255_tuner_config);
>   			} else {
> -				si2157_attach(port, &dev->i2c_bus[1].i2c_adap,
> +				si2157_attach_priv(port,
> +					      &dev->i2c_bus[1].i2c_adap,
>   					      port->dvb.frontend, 0xc0,
>   					      &hauppauge_hvr2255_tuner_config);
>   			}
> diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
> index e35b1fa..9121361 100644
> --- a/drivers/media/tuners/si2157.c
> +++ b/drivers/media/tuners/si2157.c
> @@ -18,6 +18,11 @@
>   
>   static const struct dvb_tuner_ops si2157_ops;
>   
> +static DEFINE_MUTEX(si2157_list_mutex);
> +static LIST_HEAD(hybrid_tuner_instance_list);
> +
> +/*---------------------------------------------------------------------*/
> +
>   /* execute firmware command */
>   static int si2157_cmd_execute(struct i2c_client *client, struct si2157_cmd *cmd)
>   {
> @@ -385,6 +390,31 @@ static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
>   	return 0;
>   }
>   
> +static void si2157_release(struct dvb_frontend *fe)
> +{
> +	struct i2c_client *client = fe->tuner_priv;
> +	struct si2157_dev *dev = i2c_get_clientdata(client);
> +
> +	dev_dbg(&client->dev, "%s()\n", __func__);
> +
> +	/* only do full cleanup on final instance */
> +	if (hybrid_tuner_report_instance_count(dev) == 1) {
> +		/* stop statistics polling */
> +		cancel_delayed_work_sync(&dev->stat_work);
> +#ifdef CONFIG_MEDIA_CONTROLLER_DVB
> +		if (dev->mdev)
> +			media_device_unregister_entity(&dev->ent);
> +#endif
> +		i2c_set_clientdata(client, NULL);
> +	}
> +
> +	mutex_lock(&si2157_list_mutex);
> +	hybrid_tuner_release_state(dev);
> +	mutex_unlock(&si2157_list_mutex);
> +
> +	fe->tuner_priv = NULL;
> +}
> +
>   static const struct dvb_tuner_ops si2157_ops = {
>   	.info = {
>   		.name           = "Silicon Labs Si2141/Si2146/2147/2148/2157/2158",
> @@ -396,6 +426,7 @@ static const struct dvb_tuner_ops si2157_ops = {
>   	.sleep = si2157_sleep,
>   	.set_params = si2157_set_params,
>   	.get_if_frequency = si2157_get_if_frequency,
> +	.release = si2157_release,
>   };
>   
>   static void si2157_stat_work(struct work_struct *work)
> @@ -431,72 +462,30 @@ static int si2157_probe(struct i2c_client *client,
>   {
>   	struct si2157_config *cfg = client->dev.platform_data;
>   	struct dvb_frontend *fe = cfg->fe;
> -	struct si2157_dev *dev;
> -	struct si2157_cmd cmd;
> -	int ret;
> -
> -	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
> -	if (!dev) {
> -		ret = -ENOMEM;
> -		dev_err(&client->dev, "kzalloc() failed\n");
> -		goto err;
> -	}
> -
> -	i2c_set_clientdata(client, dev);
> -	dev->fe = cfg->fe;
> -	dev->inversion = cfg->inversion;
> -	dev->if_port = cfg->if_port;
> -	dev->chiptype = (u8)id->driver_data;
> -	dev->if_frequency = 5000000; /* default value of property 0x0706 */
> -	mutex_init(&dev->i2c_mutex);
> -	INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work);
> +	struct si2157_dev *dev = NULL;
> +	unsigned short addr = client->addr;
> +	int ret = 0;
>   
> -	/* check if the tuner is there */
> -	cmd.wlen = 0;
> -	cmd.rlen = 1;
> -	ret = si2157_cmd_execute(client, &cmd);
> -	if (ret)
> -		goto err_kfree;
> -
> -	memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops));
> +	dev_dbg(&client->dev, "Probing tuner\n");
>   	fe->tuner_priv = client;
>   
> -#ifdef CONFIG_MEDIA_CONTROLLER
> -	if (cfg->mdev) {
> -		dev->mdev = cfg->mdev;
> -
> -		dev->ent.name = KBUILD_MODNAME;
> -		dev->ent.function = MEDIA_ENT_F_TUNER;
> -
> -		dev->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
> -		dev->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
> -		dev->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
> -
> -		ret = media_entity_pads_init(&dev->ent, TUNER_NUM_PADS,
> -					     &dev->pad[0]);
> -
> -		if (ret)
> -			goto err_kfree;
> -
> -		ret = media_device_register_entity(cfg->mdev, &dev->ent);
> -		if (ret) {
> -			media_entity_cleanup(&dev->ent);
> -			goto err_kfree;
> -		}
> +	if (si2157_attach(fe, (u8)addr, client->adapter, cfg) == NULL) {
> +		dev_err(&client->dev, "%s: attaching si2157 tuner failed\n",
> +				__func__);
> +		goto err;
>   	}
> -#endif
> +	fe->ops.tuner_ops.release = NULL;
>   
> +	dev = i2c_get_clientdata(client);
> +	dev->chiptype = (u8)id->driver_data;
>   	dev_info(&client->dev, "Silicon Labs %s successfully attached\n",
>   			dev->chiptype == SI2157_CHIPTYPE_SI2141 ?  "Si2141" :
>   			dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
>   			"Si2146" : "Si2147/2148/2157/2158");
>   
>   	return 0;
> -
> -err_kfree:
> -	kfree(dev);
>   err:
> -	dev_dbg(&client->dev, "failed=%d\n", ret);
> +	dev_warn(&client->dev, "probe failed = %d\n", ret);
>   	return ret;
>   }
>   
> @@ -505,19 +494,10 @@ static int si2157_remove(struct i2c_client *client)
>   	struct si2157_dev *dev = i2c_get_clientdata(client);
>   	struct dvb_frontend *fe = dev->fe;
>   
> -	dev_dbg(&client->dev, "\n");
> -
> -	/* stop statistics polling */
> -	cancel_delayed_work_sync(&dev->stat_work);
> -
> -#ifdef CONFIG_MEDIA_CONTROLLER_DVB
> -	if (dev->mdev)
> -		media_device_unregister_entity(&dev->ent);
> -#endif
> +	dev_dbg(&client->dev, "%s()\n", __func__);
>   
>   	memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
> -	fe->tuner_priv = NULL;
> -	kfree(dev);
> +	si2157_release(fe);
>   
>   	return 0;
>   }
> @@ -542,7 +522,127 @@ static struct i2c_driver si2157_driver = {
>   
>   module_i2c_driver(si2157_driver);
>   
> -MODULE_DESCRIPTION("Silicon Labs Si2141/Si2146/2147/2148/2157/2158 silicon tuner driver");
> +struct dvb_frontend *si2157_attach(struct dvb_frontend *fe, u8 addr,
> +		struct i2c_adapter *i2c,
> +		struct si2157_config *cfg)
> +{
> +	struct i2c_client *client = NULL;
> +	struct si2157_dev *dev = NULL;
> +	struct si2157_cmd cmd;
> +	int instance = 0, ret;
> +
> +	pr_debug("%s (%d-%04x)\n", __func__,
> +	       i2c ? i2c_adapter_id(i2c) : 0,
> +	       addr);
> +
> +	if (!cfg) {
> +		pr_warn("no configuration submitted\n");
> +		goto fail;
> +	}
> +
> +	if (!fe) {
> +		pr_warn("fe is NULL\n");
> +		goto fail;
> +	}
> +
> +	client = fe->tuner_priv;
> +	if (!client) {
> +		pr_warn("client is NULL\n");
> +		goto fail;
> +	}
> +
> +	mutex_lock(&si2157_list_mutex);
> +
> +	instance = hybrid_tuner_request_state(struct si2157_dev, dev,
> +			hybrid_tuner_instance_list,
> +			i2c, addr, "si2157");
> +
> +	switch (instance) {
> +	case 0:
> +		goto fail;
> +	case 1:
> +		/* new tuner instance */
> +		dev_dbg(&client->dev, "%s(): new instance for tuner @0x%02x\n",
> +				__func__, addr);
> +		dev->addr = addr;
> +		i2c_set_clientdata(client, dev);
> +
> +		dev->fe = fe;
> +		dev->chiptype = SI2157_CHIPTYPE_SI2157;
> +		dev->if_frequency = 0;
> +		dev->if_port   = cfg->if_port;
> +		dev->inversion = cfg->inversion;
> +
> +		mutex_init(&dev->i2c_mutex);
> +		INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work);
> +
> +		break;
> +	default:
> +		/* existing tuner instance */
> +		dev_dbg(&client->dev,
> +				"%s(): using existing instance for tuner @0x%02x\n",
> +				 __func__, addr);
> +		break;
> +	}
> +
> +	/* check if the tuner is there */
> +	cmd.wlen = 0;
> +	cmd.rlen = 1;
> +	ret = si2157_cmd_execute(client, &cmd);
> +	/* verify no i2c error and CTS is set */
> +	if (ret) {
> +		dev_warn(&client->dev, "no HW found ret=%d\n", ret);
> +		goto fail_instance;
> +	}
> +
> +	memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops));
> +
> +#ifdef CONFIG_MEDIA_CONTROLLER
> +	if (instance == 1 && cfg->mdev) {
> +		dev->mdev = cfg->mdev;
> +
> +		dev->ent.name = KBUILD_MODNAME;
> +		dev->ent.function = MEDIA_ENT_F_TUNER;
> +
> +		dev->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
> +		dev->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
> +		dev->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
> +
> +		ret = media_entity_pads_init(&dev->ent, TUNER_NUM_PADS,
> +					     &dev->pad[0]);
> +
> +		if (ret)
> +			goto fail_instance;
> +
> +		ret = media_device_register_entity(cfg->mdev, &dev->ent);
> +		if (ret) {
> +			dev_warn(&client->dev,
> +				"media_device_regiser_entity returns %d\n", ret);
> +			media_entity_cleanup(&dev->ent);
> +			goto fail_instance;
> +		}
> +	}
> +#endif
> +	mutex_unlock(&si2157_list_mutex);
> +
> +	if (instance != 1)
> +		dev_info(&client->dev, "Silicon Labs %s successfully attached\n",
> +			dev->chiptype == SI2157_CHIPTYPE_SI2141 ?  "Si2141" :
> +			dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
> +			"Si2146" : "Si2147/2148/2157/2158");
> +
> +	return fe;
> +fail_instance:
> +	mutex_unlock(&si2157_list_mutex);
> +
> +	si2157_release(fe);
> +fail:
> +	dev_warn(&client->dev, "Attach failed\n");
> +	return NULL;
> +}
> +EXPORT_SYMBOL(si2157_attach);
> +
> +MODULE_DESCRIPTION("Silicon Labs Si2141/2146/2147/2148/2157/2158 silicon tuner driver");
>   MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
>   MODULE_LICENSE("GPL");
>   MODULE_FIRMWARE(SI2158_A20_FIRMWARE);
> diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h
> index de597fa..26b94ca 100644
> --- a/drivers/media/tuners/si2157.h
> +++ b/drivers/media/tuners/si2157.h
> @@ -46,4 +46,18 @@ struct si2157_config {
>   	u8 if_port;
>   };
>   
> +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_SI2157)
> +extern struct dvb_frontend *si2157_attach(struct dvb_frontend *fe, u8 addr,
> +					    struct i2c_adapter *i2c,
> +					    struct si2157_config *cfg);
> +#else
> +static inline struct dvb_frontend *si2157_attach(struct dvb_frontend *fe,
> +						   u8 addr,
> +						   struct i2c_adapter *i2c,
> +						   struct si2157_config *cfg)
> +{
> +	pr_err("%s: driver disabled by Kconfig\n", __func__);
> +	return NULL;
> +}
> +#endif
>   #endif
> diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h
> index e6436f7..2801aaa 100644
> --- a/drivers/media/tuners/si2157_priv.h
> +++ b/drivers/media/tuners/si2157_priv.h
> @@ -19,15 +19,20 @@
>   
>   #include <linux/firmware.h>
>   #include <media/v4l2-mc.h>
> +#include "tuner-i2c.h"
>   #include "si2157.h"
>   
>   /* state struct */
>   struct si2157_dev {
> +	struct list_head hybrid_tuner_instance_list;
> +	struct tuner_i2c_props  i2c_props;
> +
>   	struct mutex i2c_mutex;
>   	struct dvb_frontend *fe;
>   	bool active;
>   	bool inversion;
>   	u8 chiptype;
> +	u8 addr;
>   	u8 if_port;
>   	u32 if_frequency;
>   	struct delayed_work stat_work;
> 

-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep
  2018-01-12 16:19 ` [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep Brad Love
@ 2018-01-16  5:07   ` Antti Palosaari
  2018-01-16 17:31     ` Brad Love
  2018-02-12 20:19   ` [PATCH v2 4/7] si2168: Add ts bus control, " Brad Love
  1 sibling, 1 reply; 25+ messages in thread
From: Antti Palosaari @ 2018-01-16  5:07 UTC (permalink / raw)
  To: Brad Love, linux-media

Hello
And what is rationale here, is there some use case demod must be active 
and ts set to tristate (disabled)? Just put demod sleep when you don't 
use it.

regards
Antti

On 01/12/2018 06:19 PM, Brad Love wrote:
> Includes a function to set TS MODE property os si2168. The function
> either disables the TS output bus, or sets mode to config option.
> 
> When going to sleep the TS bus is turned off, this makes the driver
> compatible with multiple frontend usage.
> 
> Signed-off-by: Brad Love <brad@nextdimension.cc>
> ---
>   drivers/media/dvb-frontends/si2168.c | 38 ++++++++++++++++++++++++++++--------
>   drivers/media/dvb-frontends/si2168.h |  1 +
>   2 files changed, 31 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
> index 539399d..429c03a 100644
> --- a/drivers/media/dvb-frontends/si2168.c
> +++ b/drivers/media/dvb-frontends/si2168.c
> @@ -409,6 +409,30 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
>   	return ret;
>   }
>   
> +static int si2168_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
> +{
> +	struct i2c_client *client = fe->demodulator_priv;
> +	struct si2168_dev *dev = i2c_get_clientdata(client);
> +	struct si2168_cmd cmd;
> +	int ret = 0;
> +
> +	dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire);
> +
> +	/* set TS_MODE property */
> +	memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
> +	if (acquire)
> +		cmd.args[4] |= dev->ts_mode;
> +	else
> +		cmd.args[4] |= SI2168_TS_TRISTATE;
> +	if (dev->ts_clock_gapped)
> +		cmd.args[4] |= 0x40;
> +	cmd.wlen = 6;
> +	cmd.rlen = 4;
> +	ret = si2168_cmd_execute(client, &cmd);
> +
> +	return ret;
> +}
> +
>   static int si2168_init(struct dvb_frontend *fe)
>   {
>   	struct i2c_client *client = fe->demodulator_priv;
> @@ -540,14 +564,7 @@ static int si2168_init(struct dvb_frontend *fe)
>   		 dev->version >> 24 & 0xff, dev->version >> 16 & 0xff,
>   		 dev->version >> 8 & 0xff, dev->version >> 0 & 0xff);
>   
> -	/* set ts mode */
> -	memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
> -	cmd.args[4] |= dev->ts_mode;
> -	if (dev->ts_clock_gapped)
> -		cmd.args[4] |= 0x40;
> -	cmd.wlen = 6;
> -	cmd.rlen = 4;
> -	ret = si2168_cmd_execute(client, &cmd);
> +	ret = si2168_ts_bus_ctrl(fe, 1);
>   	if (ret)
>   		goto err;
>   
> @@ -584,6 +601,9 @@ static int si2168_sleep(struct dvb_frontend *fe)
>   
>   	dev->active = false;
>   
> +	/* tri-state data bus */
> +	si2168_ts_bus_ctrl(fe, 0);
> +
>   	/* Firmware B 4.0-11 or later loses warm state during sleep */
>   	if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0))
>   		dev->warm = false;
> @@ -681,6 +701,8 @@ static const struct dvb_frontend_ops si2168_ops = {
>   	.init = si2168_init,
>   	.sleep = si2168_sleep,
>   
> +	.ts_bus_ctrl          = si2168_ts_bus_ctrl,
> +
>   	.set_frontend = si2168_set_frontend,
>   
>   	.read_status = si2168_read_status,
> diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h
> index 3225d0c..f48f0fb 100644
> --- a/drivers/media/dvb-frontends/si2168.h
> +++ b/drivers/media/dvb-frontends/si2168.h
> @@ -38,6 +38,7 @@ struct si2168_config {
>   	/* TS mode */
>   #define SI2168_TS_PARALLEL	0x06
>   #define SI2168_TS_SERIAL	0x03
> +#define SI2168_TS_TRISTATE	0x00
>   	u8 ts_mode;
>   
>   	/* TS clock inverted */
> 

-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 6/7] si2168: Announce frontend creation failure
  2018-01-12 16:19 ` [PATCH 6/7] si2168: Announce frontend creation failure Brad Love
@ 2018-01-16  5:10   ` Antti Palosaari
  0 siblings, 0 replies; 25+ messages in thread
From: Antti Palosaari @ 2018-01-16  5:10 UTC (permalink / raw)
  To: Brad Love, linux-media

hmmm, IIRC driver core even prints some error when driver probe fails? 
After that you could enable module debug logging to see more 
information. So I don't see point for that change.

regards
Antti

On 01/12/2018 06:19 PM, Brad Love wrote:
> The driver outputs on success, but is silent on failure. Give
> one message that probe failed.
> 
> Signed-off-by: Brad Love <brad@nextdimension.cc>
> ---
>   drivers/media/dvb-frontends/si2168.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
> index 429c03a..c1a638c 100644
> --- a/drivers/media/dvb-frontends/si2168.c
> +++ b/drivers/media/dvb-frontends/si2168.c
> @@ -810,7 +810,7 @@ static int si2168_probe(struct i2c_client *client,
>   err_kfree:
>   	kfree(dev);
>   err:
> -	dev_dbg(&client->dev, "failed=%d\n", ret);
> +	dev_warn(&client->dev, "probe failed = %d\n", ret);
>   	return ret;
>   }
>   
> 

-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep
  2018-01-16  5:07   ` Antti Palosaari
@ 2018-01-16 17:31     ` Brad Love
  2018-01-16 19:32       ` Antti Palosaari
  0 siblings, 1 reply; 25+ messages in thread
From: Brad Love @ 2018-01-16 17:31 UTC (permalink / raw)
  To: Antti Palosaari, Brad Love, linux-media


On 2018-01-15 23:07, Antti Palosaari wrote:
> Hello
> And what is rationale here, is there some use case demod must be
> active and ts set to tristate (disabled)? Just put demod sleep when
> you don't use it.
>
> regards
> Antti

Hello Antti,

Perhaps the .ts_bus_ctrl callback does not need to be included in ops,
but the function is necessary. The demod is already put to sleep when
not in use, but it leaves the ts bus open. The ts bus has no reason to
be open when the demod is put to sleep. Leaving the ts bus open during
sleep affects the other connected demod and nothing is received by it.
The lgdt3306a driver already tri states its ts bus when put to sleep,
the si2168 should as well.

Cheers,

Brad



>
> On 01/12/2018 06:19 PM, Brad Love wrote:
>> Includes a function to set TS MODE property os si2168. The function
>> either disables the TS output bus, or sets mode to config option.
>>
>> When going to sleep the TS bus is turned off, this makes the driver
>> compatible with multiple frontend usage.
>>
>> Signed-off-by: Brad Love <brad@nextdimension.cc>
>> ---
>>   drivers/media/dvb-frontends/si2168.c | 38
>> ++++++++++++++++++++++++++++--------
>>   drivers/media/dvb-frontends/si2168.h |  1 +
>>   2 files changed, 31 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/media/dvb-frontends/si2168.c
>> b/drivers/media/dvb-frontends/si2168.c
>> index 539399d..429c03a 100644
>> --- a/drivers/media/dvb-frontends/si2168.c
>> +++ b/drivers/media/dvb-frontends/si2168.c
>> @@ -409,6 +409,30 @@ static int si2168_set_frontend(struct
>> dvb_frontend *fe)
>>       return ret;
>>   }
>>   +static int si2168_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
>> +{
>> +    struct i2c_client *client = fe->demodulator_priv;
>> +    struct si2168_dev *dev = i2c_get_clientdata(client);
>> +    struct si2168_cmd cmd;
>> +    int ret = 0;
>> +
>> +    dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire);
>> +
>> +    /* set TS_MODE property */
>> +    memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
>> +    if (acquire)
>> +        cmd.args[4] |= dev->ts_mode;
>> +    else
>> +        cmd.args[4] |= SI2168_TS_TRISTATE;
>> +    if (dev->ts_clock_gapped)
>> +        cmd.args[4] |= 0x40;
>> +    cmd.wlen = 6;
>> +    cmd.rlen = 4;
>> +    ret = si2168_cmd_execute(client, &cmd);
>> +
>> +    return ret;
>> +}
>> +
>>   static int si2168_init(struct dvb_frontend *fe)
>>   {
>>       struct i2c_client *client = fe->demodulator_priv;
>> @@ -540,14 +564,7 @@ static int si2168_init(struct dvb_frontend *fe)
>>            dev->version >> 24 & 0xff, dev->version >> 16 & 0xff,
>>            dev->version >> 8 & 0xff, dev->version >> 0 & 0xff);
>>   -    /* set ts mode */
>> -    memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
>> -    cmd.args[4] |= dev->ts_mode;
>> -    if (dev->ts_clock_gapped)
>> -        cmd.args[4] |= 0x40;
>> -    cmd.wlen = 6;
>> -    cmd.rlen = 4;
>> -    ret = si2168_cmd_execute(client, &cmd);
>> +    ret = si2168_ts_bus_ctrl(fe, 1);
>>       if (ret)
>>           goto err;
>>   @@ -584,6 +601,9 @@ static int si2168_sleep(struct dvb_frontend *fe)
>>         dev->active = false;
>>   +    /* tri-state data bus */
>> +    si2168_ts_bus_ctrl(fe, 0);
>> +
>>       /* Firmware B 4.0-11 or later loses warm state during sleep */
>>       if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0))
>>           dev->warm = false;
>> @@ -681,6 +701,8 @@ static const struct dvb_frontend_ops si2168_ops = {
>>       .init = si2168_init,
>>       .sleep = si2168_sleep,
>>   +    .ts_bus_ctrl          = si2168_ts_bus_ctrl,
>> +
>>       .set_frontend = si2168_set_frontend,
>>         .read_status = si2168_read_status,
>> diff --git a/drivers/media/dvb-frontends/si2168.h
>> b/drivers/media/dvb-frontends/si2168.h
>> index 3225d0c..f48f0fb 100644
>> --- a/drivers/media/dvb-frontends/si2168.h
>> +++ b/drivers/media/dvb-frontends/si2168.h
>> @@ -38,6 +38,7 @@ struct si2168_config {
>>       /* TS mode */
>>   #define SI2168_TS_PARALLEL    0x06
>>   #define SI2168_TS_SERIAL    0x03
>> +#define SI2168_TS_TRISTATE    0x00
>>       u8 ts_mode;
>>         /* TS clock inverted */
>>
>


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep
  2018-01-16 17:31     ` Brad Love
@ 2018-01-16 19:32       ` Antti Palosaari
  2018-01-16 20:14         ` Brad Love
  0 siblings, 1 reply; 25+ messages in thread
From: Antti Palosaari @ 2018-01-16 19:32 UTC (permalink / raw)
  To: Brad Love, linux-media

On 01/16/2018 07:31 PM, Brad Love wrote:
> 
> On 2018-01-15 23:07, Antti Palosaari wrote:
>> Hello
>> And what is rationale here, is there some use case demod must be
>> active and ts set to tristate (disabled)? Just put demod sleep when
>> you don't use it.
>>
>> regards
>> Antti
> 
> Hello Antti,
> 
> Perhaps the .ts_bus_ctrl callback does not need to be included in ops,
> but the function is necessary. The demod is already put to sleep when
> not in use, but it leaves the ts bus open. The ts bus has no reason to
> be open when the demod is put to sleep. Leaving the ts bus open during
> sleep affects the other connected demod and nothing is received by it.
> The lgdt3306a driver already tri states its ts bus when put to sleep,
> the si2168 should as well.

Sounds possible, but unlikely as chip is firmware driven. When you put 
chip to sleep you usually want set ts pins to tristate (also other 
unused pins) in order to save energy. I haven't never tested it anyway 
though, so it could be possible it leaves those pins to some other state 
like random output at given time.

And if you cannot get stream from lgdt3306a, which is connected to same 
bus, it really sounds like ts bus pins are left some state (cannot work 
if same pin is driven high to other demod whilst other tries to drive it 
low.

Setting ts pins to tri-state during sleep should resolve your issue.


regards
Antti
-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep
  2018-01-16 19:32       ` Antti Palosaari
@ 2018-01-16 20:14         ` Brad Love
  2018-01-16 20:38           ` Antti Palosaari
  0 siblings, 1 reply; 25+ messages in thread
From: Brad Love @ 2018-01-16 20:14 UTC (permalink / raw)
  To: Antti Palosaari, Brad Love, linux-media


On 2018-01-16 13:32, Antti Palosaari wrote:
> On 01/16/2018 07:31 PM, Brad Love wrote:
>>
>> On 2018-01-15 23:07, Antti Palosaari wrote:
>>> Hello
>>> And what is rationale here, is there some use case demod must be
>>> active and ts set to tristate (disabled)? Just put demod sleep when
>>> you don't use it.
>>>
>>> regards
>>> Antti
>>
>> Hello Antti,
>>
>> Perhaps the .ts_bus_ctrl callback does not need to be included in ops,
>> but the function is necessary. The demod is already put to sleep when
>> not in use, but it leaves the ts bus open. The ts bus has no reason to
>> be open when the demod is put to sleep. Leaving the ts bus open during
>> sleep affects the other connected demod and nothing is received by it.
>> The lgdt3306a driver already tri states its ts bus when put to sleep,
>> the si2168 should as well.
>
> Sounds possible, but unlikely as chip is firmware driven. When you put
> chip to sleep you usually want set ts pins to tristate (also other
> unused pins) in order to save energy. I haven't never tested it anyway
> though, so it could be possible it leaves those pins to some other
> state like random output at given time.
>
> And if you cannot get stream from lgdt3306a, which is connected to
> same bus, it really sounds like ts bus pins are left some state
> (cannot work if same pin is driven high to other demod whilst other
> tries to drive it low.
>
> Setting ts pins to tri-state during sleep should resolve your issue.

Hello Antti,

This patch fixes the issue I'm describing, hence why I submitted it. The
ts bus must be tristated before putting the chip to sleep for the other
demod to get a stream.

Cheers,

Brad



>
>
> regards
> Antti

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep
  2018-01-16 20:14         ` Brad Love
@ 2018-01-16 20:38           ` Antti Palosaari
  2018-01-16 22:04             ` Brad Love
  0 siblings, 1 reply; 25+ messages in thread
From: Antti Palosaari @ 2018-01-16 20:38 UTC (permalink / raw)
  To: Brad Love, linux-media

On 01/16/2018 10:14 PM, Brad Love wrote:
> 
> On 2018-01-16 13:32, Antti Palosaari wrote:
>> On 01/16/2018 07:31 PM, Brad Love wrote:
>>>
>>> On 2018-01-15 23:07, Antti Palosaari wrote:
>>>> Hello
>>>> And what is rationale here, is there some use case demod must be
>>>> active and ts set to tristate (disabled)? Just put demod sleep when
>>>> you don't use it.
>>>>
>>>> regards
>>>> Antti
>>>
>>> Hello Antti,
>>>
>>> Perhaps the .ts_bus_ctrl callback does not need to be included in ops,
>>> but the function is necessary. The demod is already put to sleep when
>>> not in use, but it leaves the ts bus open. The ts bus has no reason to
>>> be open when the demod is put to sleep. Leaving the ts bus open during
>>> sleep affects the other connected demod and nothing is received by it.
>>> The lgdt3306a driver already tri states its ts bus when put to sleep,
>>> the si2168 should as well.
>>
>> Sounds possible, but unlikely as chip is firmware driven. When you put
>> chip to sleep you usually want set ts pins to tristate (also other
>> unused pins) in order to save energy. I haven't never tested it anyway
>> though, so it could be possible it leaves those pins to some other
>> state like random output at given time.
>>
>> And if you cannot get stream from lgdt3306a, which is connected to
>> same bus, it really sounds like ts bus pins are left some state
>> (cannot work if same pin is driven high to other demod whilst other
>> tries to drive it low.
>>
>> Setting ts pins to tri-state during sleep should resolve your issue.
> 
> Hello Antti,
> 
> This patch fixes the issue I'm describing, hence why I submitted it. The
> ts bus must be tristated before putting the chip to sleep for the other
> demod to get a stream.
> 

I can test tri-state using power meter on some day, but it may be so 
small current that it cannot be seen usb power meter I use (YZXstudio, 
very nice small power meter).

regards
Antti

-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 3/7] si2157: Add hybrid tuner support
  2018-01-16  5:05   ` Antti Palosaari
@ 2018-01-16 20:48     ` Brad Love
  2018-03-06 12:24       ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 25+ messages in thread
From: Brad Love @ 2018-01-16 20:48 UTC (permalink / raw)
  To: Antti Palosaari, Brad Love, linux-media


On 2018-01-15 23:05, Antti Palosaari wrote:
> Hello
> So the use case is to share single tuner with multiple demodulators?
> Why don't just register single tuner and pass that info to multiple
> demods?
>
> Antti

Hello Antti,

It was done this way because of lack of knowledge of other ways. The
method I used mirrored that done by the three other drivers I found
which supported *and* included multiple front ends. We had this _attach
function sitting around as part of wip analog support to the si2157, and
it seemed like a nice fit here.

I just perused the tree again and noticed one spot I missed originally,
which does not use an _attach function. I didn't realize I could just
memcpy tuner_ops from fe[0] to fe[1] and call it a done deal, it does
appear to work the same though.

Is this really all that is required? If so, I'll modify patch 7/7 and
put this patch to the side for now.

Cheers,

Brad


>
> On 01/12/2018 06:19 PM, Brad Love wrote:
>> Add ability to share a tuner amongst demodulators. Addtional
>> demods are attached using hybrid_tuner_instance_list.
>>
>> The changes are equivalent to moving all of probe to _attach.
>> Results are backwards compatible with current usage.
>>
>> If the tuner is acquired via attach, then .release cleans state.
>> if the tuner is an i2c driver, then .release is set to NULL, and
>> .remove cleans remaining state.
>>
>> The following file contains a static si2157_attach:
>> - drivers/media/pci/saa7164/saa7164-dvb.c
>> The function name has been appended with _priv to appease
>> the compiler.
>>
>> Signed-off-by: Brad Love <brad@nextdimension.cc>
>> ---
>>   drivers/media/pci/saa7164/saa7164-dvb.c |  11 +-
>>   drivers/media/tuners/si2157.c           | 232
>> +++++++++++++++++++++++---------
>>   drivers/media/tuners/si2157.h           |  14 ++
>>   drivers/media/tuners/si2157_priv.h      |   5 +
>>   4 files changed, 192 insertions(+), 70 deletions(-)
>>
>> diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c
>> b/drivers/media/pci/saa7164/saa7164-dvb.c
>> index e76d3ba..9522c6c 100644
>> --- a/drivers/media/pci/saa7164/saa7164-dvb.c
>> +++ b/drivers/media/pci/saa7164/saa7164-dvb.c
>> @@ -110,8 +110,9 @@ static struct si2157_config
>> hauppauge_hvr2255_tuner_config = {
>>       .if_port = 1,
>>   };
>>   -static int si2157_attach(struct saa7164_port *port, struct
>> i2c_adapter *adapter,
>> -    struct dvb_frontend *fe, u8 addr8bit, struct si2157_config *cfg)
>> +static int si2157_attach_priv(struct saa7164_port *port,
>> +    struct i2c_adapter *adapter, struct dvb_frontend *fe,
>> +    u8 addr8bit, struct si2157_config *cfg)
>>   {
>>       struct i2c_board_info bi;
>>       struct i2c_client *tuner;
>> @@ -624,11 +625,13 @@ int saa7164_dvb_register(struct saa7164_port
>> *port)
>>           if (port->dvb.frontend != NULL) {
>>                 if (port->nr == 0) {
>> -                si2157_attach(port, &dev->i2c_bus[0].i2c_adap,
>> +                si2157_attach_priv(port,
>> +                          &dev->i2c_bus[0].i2c_adap,
>>                             port->dvb.frontend, 0xc0,
>>                             &hauppauge_hvr2255_tuner_config);
>>               } else {
>> -                si2157_attach(port, &dev->i2c_bus[1].i2c_adap,
>> +                si2157_attach_priv(port,
>> +                          &dev->i2c_bus[1].i2c_adap,
>>                             port->dvb.frontend, 0xc0,
>>                             &hauppauge_hvr2255_tuner_config);
>>               }
>> diff --git a/drivers/media/tuners/si2157.c
>> b/drivers/media/tuners/si2157.c
>> index e35b1fa..9121361 100644
>> --- a/drivers/media/tuners/si2157.c
>> +++ b/drivers/media/tuners/si2157.c
>> @@ -18,6 +18,11 @@
>>     static const struct dvb_tuner_ops si2157_ops;
>>   +static DEFINE_MUTEX(si2157_list_mutex);
>> +static LIST_HEAD(hybrid_tuner_instance_list);
>> +
>> +/*---------------------------------------------------------------------*/
>>
>> +
>>   /* execute firmware command */
>>   static int si2157_cmd_execute(struct i2c_client *client, struct
>> si2157_cmd *cmd)
>>   {
>> @@ -385,6 +390,31 @@ static int si2157_get_if_frequency(struct
>> dvb_frontend *fe, u32 *frequency)
>>       return 0;
>>   }
>>   +static void si2157_release(struct dvb_frontend *fe)
>> +{
>> +    struct i2c_client *client = fe->tuner_priv;
>> +    struct si2157_dev *dev = i2c_get_clientdata(client);
>> +
>> +    dev_dbg(&client->dev, "%s()\n", __func__);
>> +
>> +    /* only do full cleanup on final instance */
>> +    if (hybrid_tuner_report_instance_count(dev) == 1) {
>> +        /* stop statistics polling */
>> +        cancel_delayed_work_sync(&dev->stat_work);
>> +#ifdef CONFIG_MEDIA_CONTROLLER_DVB
>> +        if (dev->mdev)
>> +            media_device_unregister_entity(&dev->ent);
>> +#endif
>> +        i2c_set_clientdata(client, NULL);
>> +    }
>> +
>> +    mutex_lock(&si2157_list_mutex);
>> +    hybrid_tuner_release_state(dev);
>> +    mutex_unlock(&si2157_list_mutex);
>> +
>> +    fe->tuner_priv = NULL;
>> +}
>> +
>>   static const struct dvb_tuner_ops si2157_ops = {
>>       .info = {
>>           .name           = "Silicon Labs
>> Si2141/Si2146/2147/2148/2157/2158",
>> @@ -396,6 +426,7 @@ static const struct dvb_tuner_ops si2157_ops = {
>>       .sleep = si2157_sleep,
>>       .set_params = si2157_set_params,
>>       .get_if_frequency = si2157_get_if_frequency,
>> +    .release = si2157_release,
>>   };
>>     static void si2157_stat_work(struct work_struct *work)
>> @@ -431,72 +462,30 @@ static int si2157_probe(struct i2c_client *client,
>>   {
>>       struct si2157_config *cfg = client->dev.platform_data;
>>       struct dvb_frontend *fe = cfg->fe;
>> -    struct si2157_dev *dev;
>> -    struct si2157_cmd cmd;
>> -    int ret;
>> -
>> -    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
>> -    if (!dev) {
>> -        ret = -ENOMEM;
>> -        dev_err(&client->dev, "kzalloc() failed\n");
>> -        goto err;
>> -    }
>> -
>> -    i2c_set_clientdata(client, dev);
>> -    dev->fe = cfg->fe;
>> -    dev->inversion = cfg->inversion;
>> -    dev->if_port = cfg->if_port;
>> -    dev->chiptype = (u8)id->driver_data;
>> -    dev->if_frequency = 5000000; /* default value of property 0x0706 */
>> -    mutex_init(&dev->i2c_mutex);
>> -    INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work);
>> +    struct si2157_dev *dev = NULL;
>> +    unsigned short addr = client->addr;
>> +    int ret = 0;
>>   -    /* check if the tuner is there */
>> -    cmd.wlen = 0;
>> -    cmd.rlen = 1;
>> -    ret = si2157_cmd_execute(client, &cmd);
>> -    if (ret)
>> -        goto err_kfree;
>> -
>> -    memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct
>> dvb_tuner_ops));
>> +    dev_dbg(&client->dev, "Probing tuner\n");
>>       fe->tuner_priv = client;
>>   -#ifdef CONFIG_MEDIA_CONTROLLER
>> -    if (cfg->mdev) {
>> -        dev->mdev = cfg->mdev;
>> -
>> -        dev->ent.name = KBUILD_MODNAME;
>> -        dev->ent.function = MEDIA_ENT_F_TUNER;
>> -
>> -        dev->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
>> -        dev->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
>> -        dev->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
>> -
>> -        ret = media_entity_pads_init(&dev->ent, TUNER_NUM_PADS,
>> -                         &dev->pad[0]);
>> -
>> -        if (ret)
>> -            goto err_kfree;
>> -
>> -        ret = media_device_register_entity(cfg->mdev, &dev->ent);
>> -        if (ret) {
>> -            media_entity_cleanup(&dev->ent);
>> -            goto err_kfree;
>> -        }
>> +    if (si2157_attach(fe, (u8)addr, client->adapter, cfg) == NULL) {
>> +        dev_err(&client->dev, "%s: attaching si2157 tuner failed\n",
>> +                __func__);
>> +        goto err;
>>       }
>> -#endif
>> +    fe->ops.tuner_ops.release = NULL;
>>   +    dev = i2c_get_clientdata(client);
>> +    dev->chiptype = (u8)id->driver_data;
>>       dev_info(&client->dev, "Silicon Labs %s successfully attached\n",
>>               dev->chiptype == SI2157_CHIPTYPE_SI2141 ?  "Si2141" :
>>               dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
>>               "Si2146" : "Si2147/2148/2157/2158");
>>         return 0;
>> -
>> -err_kfree:
>> -    kfree(dev);
>>   err:
>> -    dev_dbg(&client->dev, "failed=%d\n", ret);
>> +    dev_warn(&client->dev, "probe failed = %d\n", ret);
>>       return ret;
>>   }
>>   @@ -505,19 +494,10 @@ static int si2157_remove(struct i2c_client
>> *client)
>>       struct si2157_dev *dev = i2c_get_clientdata(client);
>>       struct dvb_frontend *fe = dev->fe;
>>   -    dev_dbg(&client->dev, "\n");
>> -
>> -    /* stop statistics polling */
>> -    cancel_delayed_work_sync(&dev->stat_work);
>> -
>> -#ifdef CONFIG_MEDIA_CONTROLLER_DVB
>> -    if (dev->mdev)
>> -        media_device_unregister_entity(&dev->ent);
>> -#endif
>> +    dev_dbg(&client->dev, "%s()\n", __func__);
>>         memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
>> -    fe->tuner_priv = NULL;
>> -    kfree(dev);
>> +    si2157_release(fe);
>>         return 0;
>>   }
>> @@ -542,7 +522,127 @@ static struct i2c_driver si2157_driver = {
>>     module_i2c_driver(si2157_driver);
>>   -MODULE_DESCRIPTION("Silicon Labs Si2141/Si2146/2147/2148/2157/2158
>> silicon tuner driver");
>> +struct dvb_frontend *si2157_attach(struct dvb_frontend *fe, u8 addr,
>> +        struct i2c_adapter *i2c,
>> +        struct si2157_config *cfg)
>> +{
>> +    struct i2c_client *client = NULL;
>> +    struct si2157_dev *dev = NULL;
>> +    struct si2157_cmd cmd;
>> +    int instance = 0, ret;
>> +
>> +    pr_debug("%s (%d-%04x)\n", __func__,
>> +           i2c ? i2c_adapter_id(i2c) : 0,
>> +           addr);
>> +
>> +    if (!cfg) {
>> +        pr_warn("no configuration submitted\n");
>> +        goto fail;
>> +    }
>> +
>> +    if (!fe) {
>> +        pr_warn("fe is NULL\n");
>> +        goto fail;
>> +    }
>> +
>> +    client = fe->tuner_priv;
>> +    if (!client) {
>> +        pr_warn("client is NULL\n");
>> +        goto fail;
>> +    }
>> +
>> +    mutex_lock(&si2157_list_mutex);
>> +
>> +    instance = hybrid_tuner_request_state(struct si2157_dev, dev,
>> +            hybrid_tuner_instance_list,
>> +            i2c, addr, "si2157");
>> +
>> +    switch (instance) {
>> +    case 0:
>> +        goto fail;
>> +    case 1:
>> +        /* new tuner instance */
>> +        dev_dbg(&client->dev, "%s(): new instance for tuner @0x%02x\n",
>> +                __func__, addr);
>> +        dev->addr = addr;
>> +        i2c_set_clientdata(client, dev);
>> +
>> +        dev->fe = fe;
>> +        dev->chiptype = SI2157_CHIPTYPE_SI2157;
>> +        dev->if_frequency = 0;
>> +        dev->if_port   = cfg->if_port;
>> +        dev->inversion = cfg->inversion;
>> +
>> +        mutex_init(&dev->i2c_mutex);
>> +        INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work);
>> +
>> +        break;
>> +    default:
>> +        /* existing tuner instance */
>> +        dev_dbg(&client->dev,
>> +                "%s(): using existing instance for tuner @0x%02x\n",
>> +                 __func__, addr);
>> +        break;
>> +    }
>> +
>> +    /* check if the tuner is there */
>> +    cmd.wlen = 0;
>> +    cmd.rlen = 1;
>> +    ret = si2157_cmd_execute(client, &cmd);
>> +    /* verify no i2c error and CTS is set */
>> +    if (ret) {
>> +        dev_warn(&client->dev, "no HW found ret=%d\n", ret);
>> +        goto fail_instance;
>> +    }
>> +
>> +    memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct
>> dvb_tuner_ops));
>> +
>> +#ifdef CONFIG_MEDIA_CONTROLLER
>> +    if (instance == 1 && cfg->mdev) {
>> +        dev->mdev = cfg->mdev;
>> +
>> +        dev->ent.name = KBUILD_MODNAME;
>> +        dev->ent.function = MEDIA_ENT_F_TUNER;
>> +
>> +        dev->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
>> +        dev->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
>> +        dev->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
>> +
>> +        ret = media_entity_pads_init(&dev->ent, TUNER_NUM_PADS,
>> +                         &dev->pad[0]);
>> +
>> +        if (ret)
>> +            goto fail_instance;
>> +
>> +        ret = media_device_register_entity(cfg->mdev, &dev->ent);
>> +        if (ret) {
>> +            dev_warn(&client->dev,
>> +                "media_device_regiser_entity returns %d\n", ret);
>> +            media_entity_cleanup(&dev->ent);
>> +            goto fail_instance;
>> +        }
>> +    }
>> +#endif
>> +    mutex_unlock(&si2157_list_mutex);
>> +
>> +    if (instance != 1)
>> +        dev_info(&client->dev, "Silicon Labs %s successfully
>> attached\n",
>> +            dev->chiptype == SI2157_CHIPTYPE_SI2141 ?  "Si2141" :
>> +            dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
>> +            "Si2146" : "Si2147/2148/2157/2158");
>> +
>> +    return fe;
>> +fail_instance:
>> +    mutex_unlock(&si2157_list_mutex);
>> +
>> +    si2157_release(fe);
>> +fail:
>> +    dev_warn(&client->dev, "Attach failed\n");
>> +    return NULL;
>> +}
>> +EXPORT_SYMBOL(si2157_attach);
>> +
>> +MODULE_DESCRIPTION("Silicon Labs Si2141/2146/2147/2148/2157/2158
>> silicon tuner driver");
>>   MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
>>   MODULE_LICENSE("GPL");
>>   MODULE_FIRMWARE(SI2158_A20_FIRMWARE);
>> diff --git a/drivers/media/tuners/si2157.h
>> b/drivers/media/tuners/si2157.h
>> index de597fa..26b94ca 100644
>> --- a/drivers/media/tuners/si2157.h
>> +++ b/drivers/media/tuners/si2157.h
>> @@ -46,4 +46,18 @@ struct si2157_config {
>>       u8 if_port;
>>   };
>>   +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_SI2157)
>> +extern struct dvb_frontend *si2157_attach(struct dvb_frontend *fe,
>> u8 addr,
>> +                        struct i2c_adapter *i2c,
>> +                        struct si2157_config *cfg);
>> +#else
>> +static inline struct dvb_frontend *si2157_attach(struct dvb_frontend
>> *fe,
>> +                           u8 addr,
>> +                           struct i2c_adapter *i2c,
>> +                           struct si2157_config *cfg)
>> +{
>> +    pr_err("%s: driver disabled by Kconfig\n", __func__);
>> +    return NULL;
>> +}
>> +#endif
>>   #endif
>> diff --git a/drivers/media/tuners/si2157_priv.h
>> b/drivers/media/tuners/si2157_priv.h
>> index e6436f7..2801aaa 100644
>> --- a/drivers/media/tuners/si2157_priv.h
>> +++ b/drivers/media/tuners/si2157_priv.h
>> @@ -19,15 +19,20 @@
>>     #include <linux/firmware.h>
>>   #include <media/v4l2-mc.h>
>> +#include "tuner-i2c.h"
>>   #include "si2157.h"
>>     /* state struct */
>>   struct si2157_dev {
>> +    struct list_head hybrid_tuner_instance_list;
>> +    struct tuner_i2c_props  i2c_props;
>> +
>>       struct mutex i2c_mutex;
>>       struct dvb_frontend *fe;
>>       bool active;
>>       bool inversion;
>>       u8 chiptype;
>> +    u8 addr;
>>       u8 if_port;
>>       u32 if_frequency;
>>       struct delayed_work stat_work;
>>
>


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep
  2018-01-16 20:38           ` Antti Palosaari
@ 2018-01-16 22:04             ` Brad Love
  0 siblings, 0 replies; 25+ messages in thread
From: Brad Love @ 2018-01-16 22:04 UTC (permalink / raw)
  To: Antti Palosaari, Brad Love, linux-media


On 2018-01-16 14:38, Antti Palosaari wrote:
> On 01/16/2018 10:14 PM, Brad Love wrote:
>>
>> On 2018-01-16 13:32, Antti Palosaari wrote:
>>> On 01/16/2018 07:31 PM, Brad Love wrote:
>>>>
>>>> On 2018-01-15 23:07, Antti Palosaari wrote:
>>>>> Hello
>>>>> And what is rationale here, is there some use case demod must be
>>>>> active and ts set to tristate (disabled)? Just put demod sleep when
>>>>> you don't use it.
>>>>>
>>>>> regards
>>>>> Antti
>>>>
>>>> Hello Antti,
>>>>
>>>> Perhaps the .ts_bus_ctrl callback does not need to be included in ops,
>>>> but the function is necessary. The demod is already put to sleep when
>>>> not in use, but it leaves the ts bus open. The ts bus has no reason to
>>>> be open when the demod is put to sleep. Leaving the ts bus open during
>>>> sleep affects the other connected demod and nothing is received by it.
>>>> The lgdt3306a driver already tri states its ts bus when put to sleep,
>>>> the si2168 should as well.
>>>
>>> Sounds possible, but unlikely as chip is firmware driven. When you put
>>> chip to sleep you usually want set ts pins to tristate (also other
>>> unused pins) in order to save energy. I haven't never tested it anyway
>>> though, so it could be possible it leaves those pins to some other
>>> state like random output at given time.
>>>
>>> And if you cannot get stream from lgdt3306a, which is connected to
>>> same bus, it really sounds like ts bus pins are left some state
>>> (cannot work if same pin is driven high to other demod whilst other
>>> tries to drive it low.
>>>
>>> Setting ts pins to tri-state during sleep should resolve your issue.
>>
>> Hello Antti,
>>
>> This patch fixes the issue I'm describing, hence why I submitted it. The
>> ts bus must be tristated before putting the chip to sleep for the other
>> demod to get a stream.
>>
>
> I can test tri-state using power meter on some day, but it may be so
> small current that it cannot be seen usb power meter I use (YZXstudio,
> very nice small power meter).
>
> regards
> Antti
>


Nifty looking devices, one just fell into my shopping cart :)

Cheers,

Brad

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH v2 4/7] si2168: Add ts bus control, turn off bus on sleep
  2018-01-12 16:19 ` [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep Brad Love
  2018-01-16  5:07   ` Antti Palosaari
@ 2018-02-12 20:19   ` Brad Love
  1 sibling, 0 replies; 25+ messages in thread
From: Brad Love @ 2018-02-12 20:19 UTC (permalink / raw)
  To: linux-media; +Cc: Brad Love

Includes a function to set TS MODE property os si2168. The function
either disables the TS output bus, or sets mode to config option.

After setting up the frontend the TS bus is enabled. When going
to sleep the TS bus is tri-stated, this makes the driver
compatible with multiple frontend usage.

Signed-off-by: Brad Love <brad@nextdimension.cc>
---
Changes since v1:
- fix spelling error in subject line
- ts bus control function moved higher
- enable ts bus after configuring frontend
- remove ts_bus_ctrl callback
- added error checking
- re-add a comment

 drivers/media/dvb-frontends/si2168.c | 42 ++++++++++++++++++++++++++++++------
 drivers/media/dvb-frontends/si2168.h |  1 +
 2 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
index 25984d3..66ecab3 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -82,6 +82,30 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd)
 	return ret;
 }
 
+static int si2168_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+	struct i2c_client *client = fe->demodulator_priv;
+	struct si2168_dev *dev = i2c_get_clientdata(client);
+	struct si2168_cmd cmd;
+	int ret = 0;
+
+	dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire);
+
+	/* set TS_MODE property */
+	memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
+	if (acquire)
+		cmd.args[4] |= dev->ts_mode;
+	else
+		cmd.args[4] |= SI2168_TS_TRISTATE;
+	if (dev->ts_clock_gapped)
+		cmd.args[4] |= 0x40;
+	cmd.wlen = 6;
+	cmd.rlen = 4;
+	ret = si2168_cmd_execute(client, &cmd);
+
+	return ret;
+}
+
 static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status)
 {
 	struct i2c_client *client = fe->demodulator_priv;
@@ -405,6 +429,11 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
 
 	dev->delivery_system = c->delivery_system;
 
+	/* enable ts bus */
+	ret = si2168_ts_bus_ctrl(fe, 1);
+	if (ret)
+		goto err;
+
 	return 0;
 err:
 	dev_dbg(&client->dev, "failed=%d\n", ret);
@@ -543,13 +572,7 @@ static int si2168_init(struct dvb_frontend *fe)
 		 dev->version >> 8 & 0xff, dev->version >> 0 & 0xff);
 
 	/* set ts mode */
-	memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
-	cmd.args[4] |= dev->ts_mode;
-	if (dev->ts_clock_gapped)
-		cmd.args[4] |= 0x40;
-	cmd.wlen = 6;
-	cmd.rlen = 4;
-	ret = si2168_cmd_execute(client, &cmd);
+	ret = si2168_ts_bus_ctrl(fe, 1);
 	if (ret)
 		goto err;
 
@@ -586,6 +609,11 @@ static int si2168_sleep(struct dvb_frontend *fe)
 
 	dev->active = false;
 
+	/* tri-state data bus */
+	ret = si2168_ts_bus_ctrl(fe, 0);
+	if (ret)
+		goto err;
+
 	/* Firmware B 4.0-11 or later loses warm state during sleep */
 	if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0))
 		dev->warm = false;
diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h
index 5104d9f..d519edd 100644
--- a/drivers/media/dvb-frontends/si2168.h
+++ b/drivers/media/dvb-frontends/si2168.h
@@ -38,6 +38,7 @@ struct si2168_config {
 	/* TS mode */
 #define SI2168_TS_PARALLEL	0x06
 #define SI2168_TS_SERIAL	0x03
+#define SI2168_TS_TRISTATE	0x00
 	u8 ts_mode;
 
 	/* TS clock inverted */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 1/7] cx231xx: Add second frontend option
  2018-01-12 16:19 ` [PATCH 1/7] cx231xx: Add second frontend option Brad Love
  2018-01-12 19:09   ` Alex Deucher
@ 2018-02-12 21:40   ` Brad Love
  1 sibling, 0 replies; 25+ messages in thread
From: Brad Love @ 2018-02-12 21:40 UTC (permalink / raw)
  To: linux-media; +Cc: Brad Love

Include ability to add a second dvb attach style frontend to cx231xx
USB bridge. All current boards set to use frontend[0]. Changes are
backwards compatible with current behaviour.

Signed-off-by: Brad Love <brad@nextdimension.cc>
---
Changes since v1:
- replace hard coded value with a constant
- regen for dependency

 drivers/media/usb/cx231xx/cx231xx-dvb.c | 174 ++++++++++++++++++--------------
 1 file changed, 98 insertions(+), 76 deletions(-)

diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index a3c5449..a68b5c0 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -53,9 +53,10 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 #define CX231XX_DVB_NUM_BUFS 5
 #define CX231XX_DVB_MAX_PACKETSIZE 564
 #define CX231XX_DVB_MAX_PACKETS 64
+#define CX231XX_DVB_MAX_FRONTENDS 2
 
 struct cx231xx_dvb {
-	struct dvb_frontend *frontend;
+	struct dvb_frontend *frontend[CX231XX_DVB_MAX_FRONTENDS];
 
 	/* feed count management */
 	struct mutex lock;
@@ -386,17 +387,17 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev)
 	cfg.i2c_adap = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master);
 	cfg.i2c_addr = addr;
 
-	if (!dev->dvb->frontend) {
+	if (!dev->dvb->frontend[0]) {
 		dev_err(dev->dev, "%s/2: dvb frontend not attached. Can't attach xc5000\n",
 			dev->name);
 		return -EINVAL;
 	}
 
-	fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg);
+	fe = dvb_attach(xc5000_attach, dev->dvb->frontend[0], &cfg);
 	if (!fe) {
 		dev_err(dev->dev, "%s/2: xc5000 attach failed\n", dev->name);
-		dvb_frontend_detach(dev->dvb->frontend);
-		dev->dvb->frontend = NULL;
+		dvb_frontend_detach(dev->dvb->frontend[0]);
+		dev->dvb->frontend[0] = NULL;
 		return -EINVAL;
 	}
 
@@ -408,9 +409,9 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev)
 
 int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
 {
-	if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
+	if ((dev->dvb != NULL) && (dev->dvb->frontend[0] != NULL)) {
 
-		struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
+		struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops;
 
 		if (dops->set_analog_params != NULL) {
 			struct analog_parameters params;
@@ -421,7 +422,7 @@ int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
 			/*params.audmode = ;       */
 
 			/* Set the analog parameters to set the frequency */
-			dops->set_analog_params(dev->dvb->frontend, &params);
+			dops->set_analog_params(dev->dvb->frontend[0], &params);
 		}
 
 	}
@@ -433,15 +434,15 @@ int cx231xx_reset_analog_tuner(struct cx231xx *dev)
 {
 	int status = 0;
 
-	if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
+	if ((dev->dvb != NULL) && (dev->dvb->frontend[0] != NULL)) {
 
-		struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
+		struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops;
 
 		if (dops->init != NULL && !dev->xc_fw_load_done) {
 
 			dev_dbg(dev->dev,
 				"Reloading firmware for XC5000\n");
-			status = dops->init(dev->dvb->frontend);
+			status = dops->init(dev->dvb->frontend[0]);
 			if (status == 0) {
 				dev->xc_fw_load_done = 1;
 				dev_dbg(dev->dev,
@@ -481,17 +482,29 @@ static int register_dvb(struct cx231xx_dvb *dvb,
 	dvb_register_media_controller(&dvb->adapter, dev->media_dev);
 
 	/* Ensure all frontends negotiate bus access */
-	dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
+	dvb->frontend[0]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
+	if (dvb->frontend[1])
+		dvb->frontend[1]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
 
 	dvb->adapter.priv = dev;
 
 	/* register frontend */
-	result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+	result = dvb_register_frontend(&dvb->adapter, dvb->frontend[0]);
 	if (result < 0) {
 		dev_warn(dev->dev,
 		       "%s: dvb_register_frontend failed (errno = %d)\n",
 		       dev->name, result);
-		goto fail_frontend;
+		goto fail_frontend0;
+	}
+
+	if (dvb->frontend[1]) {
+		result = dvb_register_frontend(&dvb->adapter, dvb->frontend[1]);
+		if (result < 0) {
+			dev_warn(dev->dev,
+				"%s: 2nd dvb_register_frontend failed (errno = %d)\n",
+				dev->name, result);
+			goto fail_frontend1;
+		}
 	}
 
 	/* register demux stuff */
@@ -569,9 +582,14 @@ static int register_dvb(struct cx231xx_dvb *dvb,
 fail_dmxdev:
 	dvb_dmx_release(&dvb->demux);
 fail_dmx:
-	dvb_unregister_frontend(dvb->frontend);
-fail_frontend:
-	dvb_frontend_detach(dvb->frontend);
+	if (dvb->frontend[1])
+		dvb_unregister_frontend(dvb->frontend[1]);
+	dvb_unregister_frontend(dvb->frontend[0]);
+fail_frontend1:
+	if (dvb->frontend[1])
+		dvb_frontend_detach(dvb->frontend[1]);
+fail_frontend0:
+	dvb_frontend_detach(dvb->frontend[0]);
 	dvb_unregister_adapter(&dvb->adapter);
 fail_adapter:
 	return result;
@@ -585,8 +603,12 @@ static void unregister_dvb(struct cx231xx_dvb *dvb)
 	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
 	dvb_dmxdev_release(&dvb->dmxdev);
 	dvb_dmx_release(&dvb->demux);
-	dvb_unregister_frontend(dvb->frontend);
-	dvb_frontend_detach(dvb->frontend);
+	if (dvb->frontend[1])
+		dvb_unregister_frontend(dvb->frontend[1]);
+	dvb_unregister_frontend(dvb->frontend[0]);
+	if (dvb->frontend[1])
+		dvb_frontend_detach(dvb->frontend[1]);
+	dvb_frontend_detach(dvb->frontend[0]);
 	dvb_unregister_adapter(&dvb->adapter);
 	/* remove I2C tuner */
 	client = dvb->i2c_client_tuner;
@@ -635,11 +657,11 @@ static int dvb_init(struct cx231xx *dev)
 	case CX231XX_BOARD_CNXT_CARRAERA:
 	case CX231XX_BOARD_CNXT_RDE_250:
 
-		dev->dvb->frontend = dvb_attach(s5h1432_attach,
+		dev->dvb->frontend[0] = dvb_attach(s5h1432_attach,
 					&dvico_s5h1432_config,
 					demod_i2c);
 
-		if (dev->dvb->frontend == NULL) {
+		if (dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach s5h1432 front end\n");
 			result = -EINVAL;
@@ -647,9 +669,9 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
-		if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
+		if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0],
 			       tuner_i2c,
 			       &cnxt_rde250_tunerconfig)) {
 			result = -EINVAL;
@@ -660,11 +682,11 @@ static int dvb_init(struct cx231xx *dev)
 	case CX231XX_BOARD_CNXT_SHELBY:
 	case CX231XX_BOARD_CNXT_RDU_250:
 
-		dev->dvb->frontend = dvb_attach(s5h1411_attach,
+		dev->dvb->frontend[0] = dvb_attach(s5h1411_attach,
 					       &xc5000_s5h1411_config,
 					       demod_i2c);
 
-		if (dev->dvb->frontend == NULL) {
+		if (dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach s5h1411 front end\n");
 			result = -EINVAL;
@@ -672,9 +694,9 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
-		if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
+		if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0],
 			       tuner_i2c,
 			       &cnxt_rdu250_tunerconfig)) {
 			result = -EINVAL;
@@ -683,11 +705,11 @@ static int dvb_init(struct cx231xx *dev)
 		break;
 	case CX231XX_BOARD_CNXT_RDE_253S:
 
-		dev->dvb->frontend = dvb_attach(s5h1432_attach,
+		dev->dvb->frontend[0] = dvb_attach(s5h1432_attach,
 					&dvico_s5h1432_config,
 					demod_i2c);
 
-		if (dev->dvb->frontend == NULL) {
+		if (dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach s5h1432 front end\n");
 			result = -EINVAL;
@@ -695,9 +717,9 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
-		if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
+		if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0],
 			       0x60, tuner_i2c,
 			       &cnxt_rde253s_tunerconfig)) {
 			result = -EINVAL;
@@ -707,11 +729,11 @@ static int dvb_init(struct cx231xx *dev)
 	case CX231XX_BOARD_CNXT_RDU_253S:
 	case CX231XX_BOARD_KWORLD_UB445_USB_HYBRID:
 
-		dev->dvb->frontend = dvb_attach(s5h1411_attach,
+		dev->dvb->frontend[0] = dvb_attach(s5h1411_attach,
 					       &tda18271_s5h1411_config,
 					       demod_i2c);
 
-		if (dev->dvb->frontend == NULL) {
+		if (dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach s5h1411 front end\n");
 			result = -EINVAL;
@@ -719,9 +741,9 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
-		if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
+		if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0],
 			       0x60, tuner_i2c,
 			       &cnxt_rde253s_tunerconfig)) {
 			result = -EINVAL;
@@ -734,11 +756,11 @@ static int dvb_init(struct cx231xx *dev)
 			 "%s: looking for tuner / demod on i2c bus: %d\n",
 		       __func__, i2c_adapter_id(tuner_i2c));
 
-		dev->dvb->frontend = dvb_attach(lgdt3305_attach,
+		dev->dvb->frontend[0] = dvb_attach(lgdt3305_attach,
 						&hcw_lgdt3305_config,
 						demod_i2c);
 
-		if (dev->dvb->frontend == NULL) {
+		if (dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach LG3305 front end\n");
 			result = -EINVAL;
@@ -746,9 +768,9 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
-		dvb_attach(tda18271_attach, dev->dvb->frontend,
+		dvb_attach(tda18271_attach, dev->dvb->frontend[0],
 			   0x60, tuner_i2c,
 			   &hcw_tda18271_config);
 		break;
@@ -761,7 +783,7 @@ static int dvb_init(struct cx231xx *dev)
 
 		/* attach demod */
 		memset(&si2165_pdata, 0, sizeof(si2165_pdata));
-		si2165_pdata.fe = &dev->dvb->frontend;
+		si2165_pdata.fe = &dev->dvb->frontend[0];
 		si2165_pdata.chip_mode = SI2165_MODE_PLL_XTAL;
 		si2165_pdata.ref_freq_hz = 16000000;
 
@@ -771,7 +793,7 @@ static int dvb_init(struct cx231xx *dev)
 		info.platform_data = &si2165_pdata;
 		request_module(info.type);
 		client = i2c_new_device(demod_i2c, &info);
-		if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) {
+		if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach SI2165 front end\n");
 			result = -EINVAL;
@@ -786,12 +808,12 @@ static int dvb_init(struct cx231xx *dev)
 
 		dvb->i2c_client_demod = client;
 
-		dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
+		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
-		dvb_attach(tda18271_attach, dev->dvb->frontend,
+		dvb_attach(tda18271_attach, dev->dvb->frontend[0],
 			0x60,
 			tuner_i2c,
 			&hcw_tda18271_config);
@@ -808,7 +830,7 @@ static int dvb_init(struct cx231xx *dev)
 
 		/* attach demod */
 		memset(&si2165_pdata, 0, sizeof(si2165_pdata));
-		si2165_pdata.fe = &dev->dvb->frontend;
+		si2165_pdata.fe = &dev->dvb->frontend[0];
 		si2165_pdata.chip_mode = SI2165_MODE_PLL_EXT;
 		si2165_pdata.ref_freq_hz = 24000000;
 
@@ -818,7 +840,7 @@ static int dvb_init(struct cx231xx *dev)
 		info.platform_data = &si2165_pdata;
 		request_module(info.type);
 		client = i2c_new_device(demod_i2c, &info);
-		if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) {
+		if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach SI2165 front end\n");
 			result = -EINVAL;
@@ -835,14 +857,14 @@ static int dvb_init(struct cx231xx *dev)
 
 		memset(&info, 0, sizeof(struct i2c_board_info));
 
-		dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
+		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
 		/* attach tuner */
 		memset(&si2157_config, 0, sizeof(si2157_config));
-		si2157_config.fe = dev->dvb->frontend;
+		si2157_config.fe = dev->dvb->frontend[0];
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
 		si2157_config.mdev = dev->media_dev;
 #endif
@@ -857,14 +879,14 @@ static int dvb_init(struct cx231xx *dev)
 			tuner_i2c,
 			&info);
 		if (client == NULL || client->dev.driver == NULL) {
-			dvb_frontend_detach(dev->dvb->frontend);
+			dvb_frontend_detach(dev->dvb->frontend[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
 
 		if (!try_module_get(client->dev.driver->owner)) {
 			i2c_unregister_device(client);
-			dvb_frontend_detach(dev->dvb->frontend);
+			dvb_frontend_detach(dev->dvb->frontend[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
@@ -882,26 +904,26 @@ static int dvb_init(struct cx231xx *dev)
 
 		memset(&info, 0, sizeof(struct i2c_board_info));
 
-		dev->dvb->frontend = dvb_attach(lgdt3306a_attach,
+		dev->dvb->frontend[0] = dvb_attach(lgdt3306a_attach,
 			&hauppauge_955q_lgdt3306a_config,
 			demod_i2c
 			);
 
-		if (dev->dvb->frontend == NULL) {
+		if (dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach LGDT3306A frontend.\n");
 			result = -EINVAL;
 			goto out_free;
 		}
 
-		dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
+		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
 		/* attach tuner */
 		memset(&si2157_config, 0, sizeof(si2157_config));
-		si2157_config.fe = dev->dvb->frontend;
+		si2157_config.fe = dev->dvb->frontend[0];
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
 		si2157_config.mdev = dev->media_dev;
 #endif
@@ -916,14 +938,14 @@ static int dvb_init(struct cx231xx *dev)
 			tuner_i2c,
 			&info);
 		if (client == NULL || client->dev.driver == NULL) {
-			dvb_frontend_detach(dev->dvb->frontend);
+			dvb_frontend_detach(dev->dvb->frontend[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
 
 		if (!try_module_get(client->dev.driver->owner)) {
 			i2c_unregister_device(client);
-			dvb_frontend_detach(dev->dvb->frontend);
+			dvb_frontend_detach(dev->dvb->frontend[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
@@ -940,11 +962,11 @@ static int dvb_init(struct cx231xx *dev)
 			 "%s: looking for demod on i2c bus: %d\n",
 			 __func__, i2c_adapter_id(tuner_i2c));
 
-		dev->dvb->frontend = dvb_attach(mb86a20s_attach,
+		dev->dvb->frontend[0] = dvb_attach(mb86a20s_attach,
 						&pv_mb86a20s_config,
 						demod_i2c);
 
-		if (dev->dvb->frontend == NULL) {
+		if (dev->dvb->frontend[0] == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach mb86a20s demod\n");
 			result = -EINVAL;
@@ -952,9 +974,9 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
-		dvb_attach(tda18271_attach, dev->dvb->frontend,
+		dvb_attach(tda18271_attach, dev->dvb->frontend[0],
 			   0x60, tuner_i2c,
 			   &pv_tda18271_config);
 		break;
@@ -969,7 +991,7 @@ static int dvb_init(struct cx231xx *dev)
 
 		/* attach demodulator chip */
 		si2168_config.ts_mode = SI2168_TS_SERIAL; /* from *.inf file */
-		si2168_config.fe = &dev->dvb->frontend;
+		si2168_config.fe = &dev->dvb->frontend[0];
 		si2168_config.i2c_adapter = &adapter;
 		si2168_config.ts_clock_inv = true;
 
@@ -994,7 +1016,7 @@ static int dvb_init(struct cx231xx *dev)
 		dvb->i2c_client_demod = client;
 
 		/* attach tuner chip */
-		si2157_config.fe = dev->dvb->frontend;
+		si2157_config.fe = dev->dvb->frontend[0];
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
 		si2157_config.mdev = dev->media_dev;
 #endif
@@ -1037,7 +1059,7 @@ static int dvb_init(struct cx231xx *dev)
 		/* attach demodulator chip */
 		mn88473_config.i2c_wr_max = 16;
 		mn88473_config.xtal = 25000000;
-		mn88473_config.fe = &dev->dvb->frontend;
+		mn88473_config.fe = &dev->dvb->frontend[0];
 
 		strlcpy(info.type, "mn88473", sizeof(info.type));
 		info.addr = dev->board.demod_addr;
@@ -1060,10 +1082,10 @@ static int dvb_init(struct cx231xx *dev)
 		dvb->i2c_client_demod = client;
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
 		/* attach tuner chip */
-		dvb_attach(r820t_attach, dev->dvb->frontend,
+		dvb_attach(r820t_attach, dev->dvb->frontend[0],
 			   tuner_i2c,
 			   &astrometa_t2hybrid_r820t_config);
 		break;
@@ -1078,7 +1100,7 @@ static int dvb_init(struct cx231xx *dev)
 
 		/* attach demodulator chip */
 		si2168_config.ts_mode = SI2168_TS_SERIAL;
-		si2168_config.fe = &dev->dvb->frontend;
+		si2168_config.fe = &dev->dvb->frontend[0];
 		si2168_config.i2c_adapter = &adapter;
 		si2168_config.ts_clock_inv = true;
 
@@ -1102,13 +1124,13 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		dvb->i2c_client_demod = client;
-		dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
+		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
 		/* attach tuner */
-		si2157_config.fe = dev->dvb->frontend;
+		si2157_config.fe = dev->dvb->frontend[0];
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
 		si2157_config.mdev = dev->media_dev;
 #endif
@@ -1153,7 +1175,7 @@ static int dvb_init(struct cx231xx *dev)
 
 		/* attach demodulator chip */
 		lgdt3306a_config = hauppauge_955q_lgdt3306a_config;
-		lgdt3306a_config.fe = &dev->dvb->frontend;
+		lgdt3306a_config.fe = &dev->dvb->frontend[0];
 		lgdt3306a_config.i2c_adapter = &adapter;
 
 		strlcpy(info.type, "lgdt3306a", sizeof(info.type));
@@ -1176,13 +1198,13 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		dvb->i2c_client_demod = client;
-		dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
+		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
 
 		/* define general-purpose callback pointer */
-		dvb->frontend->callback = cx231xx_tuner_callback;
+		dvb->frontend[0]->callback = cx231xx_tuner_callback;
 
 		/* attach tuner */
-		si2157_config.fe = dev->dvb->frontend;
+		si2157_config.fe = dev->dvb->frontend[0];
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
 		si2157_config.mdev = dev->media_dev;
 #endif
@@ -1223,7 +1245,7 @@ static int dvb_init(struct cx231xx *dev)
 			dev->name);
 		break;
 	}
-	if (NULL == dvb->frontend) {
+	if (dvb->frontend[0] == NULL) {
 		dev_err(dev->dev,
 		       "%s/2: frontend initialization failed\n", dev->name);
 		result = -EINVAL;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 2/7] cx231xx: Add second i2c demod client
  2018-01-12 16:19 ` [PATCH 2/7] cx231xx: Add second i2c demod client Brad Love
@ 2018-02-12 21:41   ` Brad Love
  0 siblings, 0 replies; 25+ messages in thread
From: Brad Love @ 2018-02-12 21:41 UTC (permalink / raw)
  To: linux-media; +Cc: Brad Love

Include ability to add a i2c device style frontend to cx231xx USB
bridge. All current boards set to use frontend[0]. Changes are
backwards compatible with current behaviour.

Signed-off-by: Brad Love <brad@nextdimension.cc>
---
Changes since v1:
- replace hard coded value with a constant
- regen for dependency

  drivers/media/usb/cx231xx/cx231xx-dvb.c | 45 ++++++++++++++++++---------------
 drivers/media/usb/cx231xx/cx231xx.h     |  1 +
 2 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index a68b5c0..a70db61 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -69,7 +69,7 @@ struct cx231xx_dvb {
 	struct dmx_frontend fe_hw;
 	struct dmx_frontend fe_mem;
 	struct dvb_net net;
-	struct i2c_client *i2c_client_demod;
+	struct i2c_client *i2c_client_demod[CX231XX_DVB_MAX_FRONTENDS];
 	struct i2c_client *i2c_client_tuner;
 };
 
@@ -617,7 +617,12 @@ static void unregister_dvb(struct cx231xx_dvb *dvb)
 		i2c_unregister_device(client);
 	}
 	/* remove I2C demod */
-	client = dvb->i2c_client_demod;
+	client = dvb->i2c_client_demod[1];
+	if (client) {
+		module_put(client->dev.driver->owner);
+		i2c_unregister_device(client);
+	}
+	client = dvb->i2c_client_demod[0];
 	if (client) {
 		module_put(client->dev.driver->owner);
 		i2c_unregister_device(client);
@@ -806,7 +811,7 @@ static int dvb_init(struct cx231xx *dev)
 			goto out_free;
 		}
 
-		dvb->i2c_client_demod = client;
+		dvb->i2c_client_demod[0] = client;
 
 		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
 
@@ -853,7 +858,7 @@ static int dvb_init(struct cx231xx *dev)
 			goto out_free;
 		}
 
-		dvb->i2c_client_demod = client;
+		dvb->i2c_client_demod[0] = client;
 
 		memset(&info, 0, sizeof(struct i2c_board_info));
 
@@ -1013,7 +1018,7 @@ static int dvb_init(struct cx231xx *dev)
 			goto out_free;
 		}
 
-		dvb->i2c_client_demod = client;
+		dvb->i2c_client_demod[0] = client;
 
 		/* attach tuner chip */
 		si2157_config.fe = dev->dvb->frontend[0];
@@ -1032,16 +1037,16 @@ static int dvb_init(struct cx231xx *dev)
 		client = i2c_new_device(tuner_i2c, &info);
 
 		if (client == NULL || client->dev.driver == NULL) {
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
+			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
 
 		if (!try_module_get(client->dev.driver->owner)) {
 			i2c_unregister_device(client);
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
+			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
@@ -1079,7 +1084,7 @@ static int dvb_init(struct cx231xx *dev)
 			goto out_free;
 		}
 
-		dvb->i2c_client_demod = client;
+		dvb->i2c_client_demod[0] = client;
 
 		/* define general-purpose callback pointer */
 		dvb->frontend[0]->callback = cx231xx_tuner_callback;
@@ -1123,7 +1128,7 @@ static int dvb_init(struct cx231xx *dev)
 			goto out_free;
 		}
 
-		dvb->i2c_client_demod = client;
+		dvb->i2c_client_demod[0] = client;
 		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
 
 		/* define general-purpose callback pointer */
@@ -1147,16 +1152,16 @@ static int dvb_init(struct cx231xx *dev)
 		if (client == NULL || client->dev.driver == NULL) {
 			dev_err(dev->dev,
 				"Failed to obtain %s tuner.\n",	info.type);
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
+			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
 
 		if (!try_module_get(client->dev.driver->owner)) {
 			i2c_unregister_device(client);
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
+			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
@@ -1197,7 +1202,7 @@ static int dvb_init(struct cx231xx *dev)
 			goto out_free;
 		}
 
-		dvb->i2c_client_demod = client;
+		dvb->i2c_client_demod[0] = client;
 		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
 
 		/* define general-purpose callback pointer */
@@ -1221,16 +1226,16 @@ static int dvb_init(struct cx231xx *dev)
 		if (client == NULL || client->dev.driver == NULL) {
 			dev_err(dev->dev,
 				"Failed to obtain %s tuner.\n",	info.type);
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
+			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
 
 		if (!try_module_get(client->dev.driver->owner)) {
 			i2c_unregister_device(client);
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
+			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index fa993f7..6ffa4bd 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -345,6 +345,7 @@ struct cx231xx_board {
 
 	/* demod related */
 	int demod_addr;
+	int demod_addr2;
 	u8 demod_xfer_mode;	/* 0 - Serial; 1 - parallel */
 
 	/* GPIO Pins */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/7] cx231xx: Add second frontend option
  2018-01-12 19:09   ` Alex Deucher
@ 2018-02-12 21:43     ` Brad Love
  0 siblings, 0 replies; 25+ messages in thread
From: Brad Love @ 2018-02-12 21:43 UTC (permalink / raw)
  To: Alex Deucher, Brad Love; +Cc: linux-media

Hi Alex,


On 2018-01-12 13:09, Alex Deucher wrote:
> On Fri, Jan 12, 2018 at 11:19 AM, Brad Love <brad@nextdimension.cc> wrote:
>> Include ability to add a second dvb attach style frontend to cx231xx
>> USB bridge. All current boards set to use frontend[0]. Changes are
>> backwards compatible with current behaviour.
>>
>> Signed-off-by: Brad Love <brad@nextdimension.cc>
>> ---
>>  drivers/media/usb/cx231xx/cx231xx-dvb.c | 173 ++++++++++++++++++--------------
>>  1 file changed, 97 insertions(+), 76 deletions(-)
>>
>> diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
>> index cb4209f..4c6d2f4 100644
>> --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
>> +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
>> @@ -55,7 +55,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
>>  #define CX231XX_DVB_MAX_PACKETS 64
>>
>>  struct cx231xx_dvb {
>> -       struct dvb_frontend *frontend;
>> +       struct dvb_frontend *frontend[2];
> Maybe define something like CX231XX_MAX_FRONTEND and use it here
> rather than using a hardcoded 2.
>
> Alex

Done. See v2 1/7 and v2 2/7.

Cheers,

Brad



>
>>         /* feed count management */
>>         struct mutex lock;
>> @@ -386,17 +386,17 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev)
>>         cfg.i2c_adap = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master);
>>         cfg.i2c_addr = addr;
>>
>> -       if (!dev->dvb->frontend) {
>> +       if (!dev->dvb->frontend[0]) {
>>                 dev_err(dev->dev, "%s/2: dvb frontend not attached. Can't attach xc5000\n",
>>                         dev->name);
>>                 return -EINVAL;
>>         }
>>
>> -       fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg);
>> +       fe = dvb_attach(xc5000_attach, dev->dvb->frontend[0], &cfg);
>>         if (!fe) {
>>                 dev_err(dev->dev, "%s/2: xc5000 attach failed\n", dev->name);
>> -               dvb_frontend_detach(dev->dvb->frontend);
>> -               dev->dvb->frontend = NULL;
>> +               dvb_frontend_detach(dev->dvb->frontend[0]);
>> +               dev->dvb->frontend[0] = NULL;
>>                 return -EINVAL;
>>         }
>>
>> @@ -408,9 +408,9 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev)
>>
>>  int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
>>  {
>> -       if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
>> +       if ((dev->dvb != NULL) && (dev->dvb->frontend[0] != NULL)) {
>>
>> -               struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
>> +               struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops;
>>
>>                 if (dops->set_analog_params != NULL) {
>>                         struct analog_parameters params;
>> @@ -421,7 +421,7 @@ int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
>>                         /*params.audmode = ;       */
>>
>>                         /* Set the analog parameters to set the frequency */
>> -                       dops->set_analog_params(dev->dvb->frontend, &params);
>> +                       dops->set_analog_params(dev->dvb->frontend[0], &params);
>>                 }
>>
>>         }
>> @@ -433,15 +433,15 @@ int cx231xx_reset_analog_tuner(struct cx231xx *dev)
>>  {
>>         int status = 0;
>>
>> -       if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
>> +       if ((dev->dvb != NULL) && (dev->dvb->frontend[0] != NULL)) {
>>
>> -               struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
>> +               struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops;
>>
>>                 if (dops->init != NULL && !dev->xc_fw_load_done) {
>>
>>                         dev_dbg(dev->dev,
>>                                 "Reloading firmware for XC5000\n");
>> -                       status = dops->init(dev->dvb->frontend);
>> +                       status = dops->init(dev->dvb->frontend[0]);
>>                         if (status == 0) {
>>                                 dev->xc_fw_load_done = 1;
>>                                 dev_dbg(dev->dev,
>> @@ -481,17 +481,29 @@ static int register_dvb(struct cx231xx_dvb *dvb,
>>         dvb_register_media_controller(&dvb->adapter, dev->media_dev);
>>
>>         /* Ensure all frontends negotiate bus access */
>> -       dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
>> +       dvb->frontend[0]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
>> +       if (dvb->frontend[1])
>> +               dvb->frontend[1]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
>>
>>         dvb->adapter.priv = dev;
>>
>>         /* register frontend */
>> -       result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
>> +       result = dvb_register_frontend(&dvb->adapter, dvb->frontend[0]);
>>         if (result < 0) {
>>                 dev_warn(dev->dev,
>>                        "%s: dvb_register_frontend failed (errno = %d)\n",
>>                        dev->name, result);
>> -               goto fail_frontend;
>> +               goto fail_frontend0;
>> +       }
>> +
>> +       if (dvb->frontend[1]) {
>> +               result = dvb_register_frontend(&dvb->adapter, dvb->frontend[1]);
>> +               if (result < 0) {
>> +                       dev_warn(dev->dev,
>> +                               "%s: 2nd dvb_register_frontend failed (errno = %d)\n",
>> +                               dev->name, result);
>> +                       goto fail_frontend1;
>> +               }
>>         }
>>
>>         /* register demux stuff */
>> @@ -569,9 +581,14 @@ static int register_dvb(struct cx231xx_dvb *dvb,
>>  fail_dmxdev:
>>         dvb_dmx_release(&dvb->demux);
>>  fail_dmx:
>> -       dvb_unregister_frontend(dvb->frontend);
>> -fail_frontend:
>> -       dvb_frontend_detach(dvb->frontend);
>> +       if (dvb->frontend[1])
>> +               dvb_unregister_frontend(dvb->frontend[1]);
>> +       dvb_unregister_frontend(dvb->frontend[0]);
>> +fail_frontend1:
>> +       if (dvb->frontend[1])
>> +               dvb_frontend_detach(dvb->frontend[1]);
>> +fail_frontend0:
>> +       dvb_frontend_detach(dvb->frontend[0]);
>>         dvb_unregister_adapter(&dvb->adapter);
>>  fail_adapter:
>>         return result;
>> @@ -585,8 +602,12 @@ static void unregister_dvb(struct cx231xx_dvb *dvb)
>>         dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
>>         dvb_dmxdev_release(&dvb->dmxdev);
>>         dvb_dmx_release(&dvb->demux);
>> -       dvb_unregister_frontend(dvb->frontend);
>> -       dvb_frontend_detach(dvb->frontend);
>> +       if (dvb->frontend[1])
>> +               dvb_unregister_frontend(dvb->frontend[1]);
>> +       dvb_unregister_frontend(dvb->frontend[0]);
>> +       if (dvb->frontend[1])
>> +               dvb_frontend_detach(dvb->frontend[1]);
>> +       dvb_frontend_detach(dvb->frontend[0]);
>>         dvb_unregister_adapter(&dvb->adapter);
>>         /* remove I2C tuner */
>>         client = dvb->i2c_client_tuner;
>> @@ -635,11 +656,11 @@ static int dvb_init(struct cx231xx *dev)
>>         case CX231XX_BOARD_CNXT_CARRAERA:
>>         case CX231XX_BOARD_CNXT_RDE_250:
>>
>> -               dev->dvb->frontend = dvb_attach(s5h1432_attach,
>> +               dev->dvb->frontend[0] = dvb_attach(s5h1432_attach,
>>                                         &dvico_s5h1432_config,
>>                                         demod_i2c);
>>
>> -               if (dev->dvb->frontend == NULL) {
>> +               if (dev->dvb->frontend[0] == NULL) {
>>                         dev_err(dev->dev,
>>                                 "Failed to attach s5h1432 front end\n");
>>                         result = -EINVAL;
>> @@ -647,9 +668,9 @@ static int dvb_init(struct cx231xx *dev)
>>                 }
>>
>>                 /* define general-purpose callback pointer */
>> -               dvb->frontend->callback = cx231xx_tuner_callback;
>> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>>
>> -               if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
>> +               if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0],
>>                                tuner_i2c,
>>                                &cnxt_rde250_tunerconfig)) {
>>                         result = -EINVAL;
>> @@ -660,11 +681,11 @@ static int dvb_init(struct cx231xx *dev)
>>         case CX231XX_BOARD_CNXT_SHELBY:
>>         case CX231XX_BOARD_CNXT_RDU_250:
>>
>> -               dev->dvb->frontend = dvb_attach(s5h1411_attach,
>> +               dev->dvb->frontend[0] = dvb_attach(s5h1411_attach,
>>                                                &xc5000_s5h1411_config,
>>                                                demod_i2c);
>>
>> -               if (dev->dvb->frontend == NULL) {
>> +               if (dev->dvb->frontend[0] == NULL) {
>>                         dev_err(dev->dev,
>>                                 "Failed to attach s5h1411 front end\n");
>>                         result = -EINVAL;
>> @@ -672,9 +693,9 @@ static int dvb_init(struct cx231xx *dev)
>>                 }
>>
>>                 /* define general-purpose callback pointer */
>> -               dvb->frontend->callback = cx231xx_tuner_callback;
>> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>>
>> -               if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
>> +               if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0],
>>                                tuner_i2c,
>>                                &cnxt_rdu250_tunerconfig)) {
>>                         result = -EINVAL;
>> @@ -683,11 +704,11 @@ static int dvb_init(struct cx231xx *dev)
>>                 break;
>>         case CX231XX_BOARD_CNXT_RDE_253S:
>>
>> -               dev->dvb->frontend = dvb_attach(s5h1432_attach,
>> +               dev->dvb->frontend[0] = dvb_attach(s5h1432_attach,
>>                                         &dvico_s5h1432_config,
>>                                         demod_i2c);
>>
>> -               if (dev->dvb->frontend == NULL) {
>> +               if (dev->dvb->frontend[0] == NULL) {
>>                         dev_err(dev->dev,
>>                                 "Failed to attach s5h1432 front end\n");
>>                         result = -EINVAL;
>> @@ -695,9 +716,9 @@ static int dvb_init(struct cx231xx *dev)
>>                 }
>>
>>                 /* define general-purpose callback pointer */
>> -               dvb->frontend->callback = cx231xx_tuner_callback;
>> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>>
>> -               if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
>> +               if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0],
>>                                0x60, tuner_i2c,
>>                                &cnxt_rde253s_tunerconfig)) {
>>                         result = -EINVAL;
>> @@ -707,11 +728,11 @@ static int dvb_init(struct cx231xx *dev)
>>         case CX231XX_BOARD_CNXT_RDU_253S:
>>         case CX231XX_BOARD_KWORLD_UB445_USB_HYBRID:
>>
>> -               dev->dvb->frontend = dvb_attach(s5h1411_attach,
>> +               dev->dvb->frontend[0] = dvb_attach(s5h1411_attach,
>>                                                &tda18271_s5h1411_config,
>>                                                demod_i2c);
>>
>> -               if (dev->dvb->frontend == NULL) {
>> +               if (dev->dvb->frontend[0] == NULL) {
>>                         dev_err(dev->dev,
>>                                 "Failed to attach s5h1411 front end\n");
>>                         result = -EINVAL;
>> @@ -719,9 +740,9 @@ static int dvb_init(struct cx231xx *dev)
>>                 }
>>
>>                 /* define general-purpose callback pointer */
>> -               dvb->frontend->callback = cx231xx_tuner_callback;
>> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>>
>> -               if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
>> +               if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0],
>>                                0x60, tuner_i2c,
>>                                &cnxt_rde253s_tunerconfig)) {
>>                         result = -EINVAL;
>> @@ -734,11 +755,11 @@ static int dvb_init(struct cx231xx *dev)
>>                          "%s: looking for tuner / demod on i2c bus: %d\n",
>>                        __func__, i2c_adapter_id(tuner_i2c));
>>
>> -               dev->dvb->frontend = dvb_attach(lgdt3305_attach,
>> +               dev->dvb->frontend[0] = dvb_attach(lgdt3305_attach,
>>                                                 &hcw_lgdt3305_config,
>>                                                 demod_i2c);
>>
>> -               if (dev->dvb->frontend == NULL) {
>> +               if (dev->dvb->frontend[0] == NULL) {
>>                         dev_err(dev->dev,
>>                                 "Failed to attach LG3305 front end\n");
>>                         result = -EINVAL;
>> @@ -746,9 +767,9 @@ static int dvb_init(struct cx231xx *dev)
>>                 }
>>
>>                 /* define general-purpose callback pointer */
>> -               dvb->frontend->callback = cx231xx_tuner_callback;
>> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>>
>> -               dvb_attach(tda18271_attach, dev->dvb->frontend,
>> +               dvb_attach(tda18271_attach, dev->dvb->frontend[0],
>>                            0x60, tuner_i2c,
>>                            &hcw_tda18271_config);
>>                 break;
>> @@ -761,7 +782,7 @@ static int dvb_init(struct cx231xx *dev)
>>
>>                 /* attach demod */
>>                 memset(&si2165_pdata, 0, sizeof(si2165_pdata));
>> -               si2165_pdata.fe = &dev->dvb->frontend;
>> +               si2165_pdata.fe = &dev->dvb->frontend[0];
>>                 si2165_pdata.chip_mode = SI2165_MODE_PLL_XTAL;
>>                 si2165_pdata.ref_freq_hz = 16000000;
>>
>> @@ -771,7 +792,7 @@ static int dvb_init(struct cx231xx *dev)
>>                 info.platform_data = &si2165_pdata;
>>                 request_module(info.type);
>>                 client = i2c_new_device(demod_i2c, &info);
>> -               if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) {
>> +               if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend[0] == NULL) {
>>                         dev_err(dev->dev,
>>                                 "Failed to attach SI2165 front end\n");
>>                         result = -EINVAL;
>> @@ -786,12 +807,12 @@ static int dvb_init(struct cx231xx *dev)
>>
>>                 dvb->i2c_client_demod = client;
>>
>> -               dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
>> +               dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
>>
>>                 /* define general-purpose callback pointer */
>> -               dvb->frontend->callback = cx231xx_tuner_callback;
>> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>>
>> -               dvb_attach(tda18271_attach, dev->dvb->frontend,
>> +               dvb_attach(tda18271_attach, dev->dvb->frontend[0],
>>                         0x60,
>>                         tuner_i2c,
>>                         &hcw_tda18271_config);
>> @@ -808,7 +829,7 @@ static int dvb_init(struct cx231xx *dev)
>>
>>                 /* attach demod */
>>                 memset(&si2165_pdata, 0, sizeof(si2165_pdata));
>> -               si2165_pdata.fe = &dev->dvb->frontend;
>> +               si2165_pdata.fe = &dev->dvb->frontend[0];
>>                 si2165_pdata.chip_mode = SI2165_MODE_PLL_EXT;
>>                 si2165_pdata.ref_freq_hz = 24000000;
>>
>> @@ -818,7 +839,7 @@ static int dvb_init(struct cx231xx *dev)
>>                 info.platform_data = &si2165_pdata;
>>                 request_module(info.type);
>>                 client = i2c_new_device(demod_i2c, &info);
>> -               if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) {
>> +               if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend[0] == NULL) {
>>                         dev_err(dev->dev,
>>                                 "Failed to attach SI2165 front end\n");
>>                         result = -EINVAL;
>> @@ -835,14 +856,14 @@ static int dvb_init(struct cx231xx *dev)
>>
>>                 memset(&info, 0, sizeof(struct i2c_board_info));
>>
>> -               dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
>> +               dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
>>
>>                 /* define general-purpose callback pointer */
>> -               dvb->frontend->callback = cx231xx_tuner_callback;
>> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>>
>>                 /* attach tuner */
>>                 memset(&si2157_config, 0, sizeof(si2157_config));
>> -               si2157_config.fe = dev->dvb->frontend;
>> +               si2157_config.fe = dev->dvb->frontend[0];
>>  #ifdef CONFIG_MEDIA_CONTROLLER_DVB
>>                 si2157_config.mdev = dev->media_dev;
>>  #endif
>> @@ -857,14 +878,14 @@ static int dvb_init(struct cx231xx *dev)
>>                         tuner_i2c,
>>                         &info);
>>                 if (client == NULL || client->dev.driver == NULL) {
>> -                       dvb_frontend_detach(dev->dvb->frontend);
>> +                       dvb_frontend_detach(dev->dvb->frontend[0]);
>>                         result = -ENODEV;
>>                         goto out_free;
>>                 }
>>
>>                 if (!try_module_get(client->dev.driver->owner)) {
>>                         i2c_unregister_device(client);
>> -                       dvb_frontend_detach(dev->dvb->frontend);
>> +                       dvb_frontend_detach(dev->dvb->frontend[0]);
>>                         result = -ENODEV;
>>                         goto out_free;
>>                 }
>> @@ -882,26 +903,26 @@ static int dvb_init(struct cx231xx *dev)
>>
>>                 memset(&info, 0, sizeof(struct i2c_board_info));
>>
>> -               dev->dvb->frontend = dvb_attach(lgdt3306a_attach,
>> +               dev->dvb->frontend[0] = dvb_attach(lgdt3306a_attach,
>>                         &hauppauge_955q_lgdt3306a_config,
>>                         demod_i2c
>>                         );
>>
>> -               if (dev->dvb->frontend == NULL) {
>> +               if (dev->dvb->frontend[0] == NULL) {
>>                         dev_err(dev->dev,
>>                                 "Failed to attach LGDT3306A frontend.\n");
>>                         result = -EINVAL;
>>                         goto out_free;
>>                 }
>>
>> -               dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
>> +               dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
>>
>>                 /* define general-purpose callback pointer */
>> -               dvb->frontend->callback = cx231xx_tuner_callback;
>> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>>
>>                 /* attach tuner */
>>                 memset(&si2157_config, 0, sizeof(si2157_config));
>> -               si2157_config.fe = dev->dvb->frontend;
>> +               si2157_config.fe = dev->dvb->frontend[0];
>>  #ifdef CONFIG_MEDIA_CONTROLLER_DVB
>>                 si2157_config.mdev = dev->media_dev;
>>  #endif
>> @@ -916,14 +937,14 @@ static int dvb_init(struct cx231xx *dev)
>>                         tuner_i2c,
>>                         &info);
>>                 if (client == NULL || client->dev.driver == NULL) {
>> -                       dvb_frontend_detach(dev->dvb->frontend);
>> +                       dvb_frontend_detach(dev->dvb->frontend[0]);
>>                         result = -ENODEV;
>>                         goto out_free;
>>                 }
>>
>>                 if (!try_module_get(client->dev.driver->owner)) {
>>                         i2c_unregister_device(client);
>> -                       dvb_frontend_detach(dev->dvb->frontend);
>> +                       dvb_frontend_detach(dev->dvb->frontend[0]);
>>                         result = -ENODEV;
>>                         goto out_free;
>>                 }
>> @@ -940,11 +961,11 @@ static int dvb_init(struct cx231xx *dev)
>>                          "%s: looking for demod on i2c bus: %d\n",
>>                          __func__, i2c_adapter_id(tuner_i2c));
>>
>> -               dev->dvb->frontend = dvb_attach(mb86a20s_attach,
>> +               dev->dvb->frontend[0] = dvb_attach(mb86a20s_attach,
>>                                                 &pv_mb86a20s_config,
>>                                                 demod_i2c);
>>
>> -               if (dev->dvb->frontend == NULL) {
>> +               if (dev->dvb->frontend[0] == NULL) {
>>                         dev_err(dev->dev,
>>                                 "Failed to attach mb86a20s demod\n");
>>                         result = -EINVAL;
>> @@ -952,9 +973,9 @@ static int dvb_init(struct cx231xx *dev)
>>                 }
>>
>>                 /* define general-purpose callback pointer */
>> -               dvb->frontend->callback = cx231xx_tuner_callback;
>> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>>
>> -               dvb_attach(tda18271_attach, dev->dvb->frontend,
>> +               dvb_attach(tda18271_attach, dev->dvb->frontend[0],
>>                            0x60, tuner_i2c,
>>                            &pv_tda18271_config);
>>                 break;
>> @@ -969,7 +990,7 @@ static int dvb_init(struct cx231xx *dev)
>>
>>                 /* attach demodulator chip */
>>                 si2168_config.ts_mode = SI2168_TS_SERIAL; /* from *.inf file */
>> -               si2168_config.fe = &dev->dvb->frontend;
>> +               si2168_config.fe = &dev->dvb->frontend[0];
>>                 si2168_config.i2c_adapter = &adapter;
>>                 si2168_config.ts_clock_inv = true;
>>
>> @@ -994,7 +1015,7 @@ static int dvb_init(struct cx231xx *dev)
>>                 dvb->i2c_client_demod = client;
>>
>>                 /* attach tuner chip */
>> -               si2157_config.fe = dev->dvb->frontend;
>> +               si2157_config.fe = dev->dvb->frontend[0];
>>  #ifdef CONFIG_MEDIA_CONTROLLER_DVB
>>                 si2157_config.mdev = dev->media_dev;
>>  #endif
>> @@ -1037,7 +1058,7 @@ static int dvb_init(struct cx231xx *dev)
>>                 /* attach demodulator chip */
>>                 mn88473_config.i2c_wr_max = 16;
>>                 mn88473_config.xtal = 25000000;
>> -               mn88473_config.fe = &dev->dvb->frontend;
>> +               mn88473_config.fe = &dev->dvb->frontend[0];
>>
>>                 strlcpy(info.type, "mn88473", sizeof(info.type));
>>                 info.addr = dev->board.demod_addr;
>> @@ -1060,10 +1081,10 @@ static int dvb_init(struct cx231xx *dev)
>>                 dvb->i2c_client_demod = client;
>>
>>                 /* define general-purpose callback pointer */
>> -               dvb->frontend->callback = cx231xx_tuner_callback;
>> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>>
>>                 /* attach tuner chip */
>> -               dvb_attach(r820t_attach, dev->dvb->frontend,
>> +               dvb_attach(r820t_attach, dev->dvb->frontend[0],
>>                            tuner_i2c,
>>                            &astrometa_t2hybrid_r820t_config);
>>                 break;
>> @@ -1078,7 +1099,7 @@ static int dvb_init(struct cx231xx *dev)
>>
>>                 /* attach demodulator chip */
>>                 si2168_config.ts_mode = SI2168_TS_SERIAL;
>> -               si2168_config.fe = &dev->dvb->frontend;
>> +               si2168_config.fe = &dev->dvb->frontend[0];
>>                 si2168_config.i2c_adapter = &adapter;
>>                 si2168_config.ts_clock_inv = true;
>>
>> @@ -1102,13 +1123,13 @@ static int dvb_init(struct cx231xx *dev)
>>                 }
>>
>>                 dvb->i2c_client_demod = client;
>> -               dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
>> +               dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
>>
>>                 /* define general-purpose callback pointer */
>> -               dvb->frontend->callback = cx231xx_tuner_callback;
>> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>>
>>                 /* attach tuner */
>> -               si2157_config.fe = dev->dvb->frontend;
>> +               si2157_config.fe = dev->dvb->frontend[0];
>>  #ifdef CONFIG_MEDIA_CONTROLLER_DVB
>>                 si2157_config.mdev = dev->media_dev;
>>  #endif
>> @@ -1153,7 +1174,7 @@ static int dvb_init(struct cx231xx *dev)
>>
>>                 /* attach demodulator chip */
>>                 lgdt3306a_config = hauppauge_955q_lgdt3306a_config;
>> -               lgdt3306a_config.fe = &dev->dvb->frontend;
>> +               lgdt3306a_config.fe = &dev->dvb->frontend[0];
>>                 lgdt3306a_config.i2c_adapter = &adapter;
>>
>>                 strlcpy(info.type, "lgdt3306a", sizeof(info.type));
>> @@ -1176,13 +1197,13 @@ static int dvb_init(struct cx231xx *dev)
>>                 }
>>
>>                 dvb->i2c_client_demod = client;
>> -               dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
>> +               dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
>>
>>                 /* define general-purpose callback pointer */
>> -               dvb->frontend->callback = cx231xx_tuner_callback;
>> +               dvb->frontend[0]->callback = cx231xx_tuner_callback;
>>
>>                 /* attach tuner */
>> -               si2157_config.fe = dev->dvb->frontend;
>> +               si2157_config.fe = dev->dvb->frontend[0];
>>  #ifdef CONFIG_MEDIA_CONTROLLER_DVB
>>                 si2157_config.mdev = dev->media_dev;
>>  #endif
>> @@ -1223,7 +1244,7 @@ static int dvb_init(struct cx231xx *dev)
>>                         dev->name);
>>                 break;
>>         }
>> -       if (NULL == dvb->frontend) {
>> +       if (dvb->frontend[0] == NULL) {
>>                 dev_err(dev->dev,
>>                        "%s/2: frontend initialization failed\n", dev->name);
>>                 result = -EINVAL;
>> --
>> 2.7.4
>>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH v2 7/7] cx231xx: Add second i2c demod to Hauppauge 975
  2018-01-12 16:19 ` [PATCH 7/7] cx231xx: Add second i2c demod to Hauppauge 975 Brad Love
@ 2018-02-12 21:45   ` Brad Love
  0 siblings, 0 replies; 25+ messages in thread
From: Brad Love @ 2018-02-12 21:45 UTC (permalink / raw)
  To: linux-media; +Cc: Brad Love

Hauppauge HVR-975 is a hybrid, dual frontend, single tuner USB device.
It contains lgdt3306a and si2168 frontends and one si2157 tuner. The
lgdt3306a frontend is currently enabled. This creates the second
demodulator and attaches it to the tuner.

Enables lgdt3306a|si2168 + si2157

Signed-off-by: Brad Love <brad@nextdimension.cc>
---
Changes since v1:
- memcpy tuner ops to frontend[1] instead of dvb attach
- remove a couple redundant dev-> spots
- moved failure messages one block up where probe would fail

 drivers/media/usb/cx231xx/cx231xx-cards.c |  1 +
 drivers/media/usb/cx231xx/cx231xx-dvb.c   | 52 +++++++++++++++++++++++++++++--
 2 files changed, 50 insertions(+), 3 deletions(-)

diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index 8582568..00e88a8f 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -979,6 +979,7 @@ struct cx231xx_board cx231xx_boards[] = {
 		.demod_i2c_master = I2C_1_MUX_3,
 		.has_dvb = 1,
 		.demod_addr = 0x59, /* 0xb2 >> 1 */
+		.demod_addr2 = 0x64, /* 0xc8 >> 1 */
 		.norm = V4L2_STD_ALL,
 
 		.input = {{
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index ac3ad77..f1ffb57 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -1173,14 +1173,17 @@ static int dvb_init(struct cx231xx *dev)
 	{
 		struct i2c_client *client;
 		struct i2c_adapter *adapter;
+		struct i2c_adapter *adapter2;
 		struct i2c_board_info info = {};
 		struct si2157_config si2157_config = {};
 		struct lgdt3306a_config lgdt3306a_config = {};
+		struct si2168_config si2168_config = {};
 
-		/* attach demodulator chip */
+		/* attach first demodulator chip */
 		lgdt3306a_config = hauppauge_955q_lgdt3306a_config;
 		lgdt3306a_config.fe = &dev->dvb->frontend[0];
 		lgdt3306a_config.i2c_adapter = &adapter;
+		lgdt3306a_config.deny_i2c_rptr = 0;
 
 		strlcpy(info.type, "lgdt3306a", sizeof(info.type));
 		info.addr = dev->board.demod_addr;
@@ -1202,10 +1205,43 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		dvb->i2c_client_demod[0] = client;
-		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
+
+		/* attach second demodulator chip */
+		si2168_config.ts_mode = SI2168_TS_SERIAL;
+		si2168_config.fe = &dev->dvb->frontend[1];
+		si2168_config.i2c_adapter = &adapter2;
+		si2168_config.ts_clock_inv = true;
+
+		memset(&info, 0, sizeof(struct i2c_board_info));
+		strlcpy(info.type, "si2168", sizeof(info.type));
+		info.addr = dev->board.demod_addr2;
+		info.platform_data = &si2168_config;
+
+		request_module(info.type);
+		client = i2c_new_device(adapter, &info);
+		if (client == NULL || client->dev.driver == NULL) {
+			dev_err(dev->dev,
+				"Failed to attach %s frontend.\n", info.type);
+			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[0]);
+			result = -ENODEV;
+			goto out_free;
+		}
+
+		if (!try_module_get(client->dev.driver->owner)) {
+			i2c_unregister_device(client);
+			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[0]);
+			result = -ENODEV;
+			goto out_free;
+		}
+
+		dvb->i2c_client_demod[1] = client;
+		dvb->frontend[1]->id = 1;
 
 		/* define general-purpose callback pointer */
 		dvb->frontend[0]->callback = cx231xx_tuner_callback;
+		dvb->frontend[1]->callback = cx231xx_tuner_callback;
 
 		/* attach tuner */
 		si2157_config.fe = dev->dvb->frontend[0];
@@ -1225,6 +1261,8 @@ static int dvb_init(struct cx231xx *dev)
 		if (client == NULL || client->dev.driver == NULL) {
 			dev_err(dev->dev,
 				"Failed to obtain %s tuner.\n",	info.type);
+			module_put(dvb->i2c_client_demod[1]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[1]);
 			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
 			i2c_unregister_device(dvb->i2c_client_demod[0]);
 			result = -ENODEV;
@@ -1233,6 +1271,8 @@ static int dvb_init(struct cx231xx *dev)
 
 		if (!try_module_get(client->dev.driver->owner)) {
 			i2c_unregister_device(client);
+			module_put(dvb->i2c_client_demod[1]->dev.driver->owner);
+			i2c_unregister_device(dvb->i2c_client_demod[1]);
 			module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
 			i2c_unregister_device(dvb->i2c_client_demod[0]);
 			result = -ENODEV;
@@ -1240,7 +1280,13 @@ static int dvb_init(struct cx231xx *dev)
 		}
 
 		dev->cx231xx_reset_analog_tuner = NULL;
-		dev->dvb->i2c_client_tuner = client;
+		dvb->i2c_client_tuner = client;
+
+		dvb->frontend[1]->tuner_priv = dvb->frontend[0]->tuner_priv;
+
+		memcpy(&dvb->frontend[1]->ops.tuner_ops,
+			&dvb->frontend[0]->ops.tuner_ops,
+			sizeof(struct dvb_tuner_ops));
 		break;
 	}
 	default:
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH 3/7] si2157: Add hybrid tuner support
  2018-01-16 20:48     ` Brad Love
@ 2018-03-06 12:24       ` Mauro Carvalho Chehab
  2018-03-06 14:44         ` Brad Love
  0 siblings, 1 reply; 25+ messages in thread
From: Mauro Carvalho Chehab @ 2018-03-06 12:24 UTC (permalink / raw)
  To: Brad Love, Antti Palosaari; +Cc: linux-media

Hi Brad,

As patches 1 and 2 are independent of this one, and should be backward
compatible, I'm applying them, but I have issues with this one too :-)

Em Tue, 16 Jan 2018 14:48:35 -0600
Brad Love <brad@nextdimension.cc> escreveu:

> On 2018-01-15 23:05, Antti Palosaari wrote:
> > Hello
> > So the use case is to share single tuner with multiple demodulators?
> > Why don't just register single tuner and pass that info to multiple
> > demods?
> >
> > Antti  
> 
> Hello Antti,
> 
> It was done this way because of lack of knowledge of other ways. The
> method I used mirrored that done by the three other drivers I found
> which supported *and* included multiple front ends. We had this _attach
> function sitting around as part of wip analog support to the si2157, and
> it seemed like a nice fit here.

The thing is that dvb_attach() is a very dirty and ugly hack,
done when we needed to use I2C low level API calls inside DVB,
while using high level bus-attach based I2C API for V4L.

The hybrid_tuner_instance is yet-another-ugly dirty hack, with even
causes lots of troubles for static analyzers.

Nowadays, we should, instead, let the I2C bus bind the device
at the bus and take care of lifetime issues.

Btw, please take a look on this changeset:

	8f569c0b4e6b ("media: dvb-core: add helper functions for I2C binding")

and an example about how to simplify the binding code at:

	ad32495b1513 ("media: em28xx-dvb: simplify DVB module probing logic")

Em28xx is currently the only driver using the newer functions - My
plan is to cleanup other drivers using the same logic as well,
eventually improving the implementation of the new functions if needed.

> I just perused the tree again and noticed one spot I missed originally,
> which does not use an _attach function. I didn't realize I could just
> memcpy tuner_ops from fe[0] to fe[1] and call it a done deal, it does
> appear to work the same though.

I didn't write any hybrid tuner support using the new I2C binding
schema, but, if both demods use the same tuner, I guess that's all
it should be needed (and set adap->mfe_shared to 1).

> Is this really all that is required? If so, I'll modify patch 7/7 and
> put this patch to the side for now.
> 
> Cheers,
> 
> Brad
> 
> 
> >
> > On 01/12/2018 06:19 PM, Brad Love wrote:  
> >> Add ability to share a tuner amongst demodulators. Addtional
> >> demods are attached using hybrid_tuner_instance_list.
> >>
> >> The changes are equivalent to moving all of probe to _attach.
> >> Results are backwards compatible with current usage.
> >>
> >> If the tuner is acquired via attach, then .release cleans state.
> >> if the tuner is an i2c driver, then .release is set to NULL, and
> >> .remove cleans remaining state.
> >>
> >> The following file contains a static si2157_attach:
> >> - drivers/media/pci/saa7164/saa7164-dvb.c
> >> The function name has been appended with _priv to appease
> >> the compiler.
> >>
> >> Signed-off-by: Brad Love <brad@nextdimension.cc>
> >> ---
> >>   drivers/media/pci/saa7164/saa7164-dvb.c |  11 +-
> >>   drivers/media/tuners/si2157.c           | 232
> >> +++++++++++++++++++++++---------
> >>   drivers/media/tuners/si2157.h           |  14 ++
> >>   drivers/media/tuners/si2157_priv.h      |   5 +
> >>   4 files changed, 192 insertions(+), 70 deletions(-)
> >>
> >> diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c
> >> b/drivers/media/pci/saa7164/saa7164-dvb.c
> >> index e76d3ba..9522c6c 100644
> >> --- a/drivers/media/pci/saa7164/saa7164-dvb.c
> >> +++ b/drivers/media/pci/saa7164/saa7164-dvb.c
> >> @@ -110,8 +110,9 @@ static struct si2157_config
> >> hauppauge_hvr2255_tuner_config = {
> >>       .if_port = 1,
> >>   };
> >>   -static int si2157_attach(struct saa7164_port *port, struct
> >> i2c_adapter *adapter,
> >> -    struct dvb_frontend *fe, u8 addr8bit, struct si2157_config *cfg)
> >> +static int si2157_attach_priv(struct saa7164_port *port,
> >> +    struct i2c_adapter *adapter, struct dvb_frontend *fe,
> >> +    u8 addr8bit, struct si2157_config *cfg)
> >>   {
> >>       struct i2c_board_info bi;
> >>       struct i2c_client *tuner;
> >> @@ -624,11 +625,13 @@ int saa7164_dvb_register(struct saa7164_port
> >> *port)
> >>           if (port->dvb.frontend != NULL) {
> >>                 if (port->nr == 0) {
> >> -                si2157_attach(port, &dev->i2c_bus[0].i2c_adap,
> >> +                si2157_attach_priv(port,
> >> +                          &dev->i2c_bus[0].i2c_adap,
> >>                             port->dvb.frontend, 0xc0,
> >>                             &hauppauge_hvr2255_tuner_config);
> >>               } else {
> >> -                si2157_attach(port, &dev->i2c_bus[1].i2c_adap,
> >> +                si2157_attach_priv(port,
> >> +                          &dev->i2c_bus[1].i2c_adap,
> >>                             port->dvb.frontend, 0xc0,
> >>                             &hauppauge_hvr2255_tuner_config);
> >>               }
> >> diff --git a/drivers/media/tuners/si2157.c
> >> b/drivers/media/tuners/si2157.c
> >> index e35b1fa..9121361 100644
> >> --- a/drivers/media/tuners/si2157.c
> >> +++ b/drivers/media/tuners/si2157.c
> >> @@ -18,6 +18,11 @@
> >>     static const struct dvb_tuner_ops si2157_ops;
> >>   +static DEFINE_MUTEX(si2157_list_mutex);
> >> +static LIST_HEAD(hybrid_tuner_instance_list);
> >> +
> >> +/*---------------------------------------------------------------------*/
> >>
> >> +
> >>   /* execute firmware command */
> >>   static int si2157_cmd_execute(struct i2c_client *client, struct
> >> si2157_cmd *cmd)
> >>   {
> >> @@ -385,6 +390,31 @@ static int si2157_get_if_frequency(struct
> >> dvb_frontend *fe, u32 *frequency)
> >>       return 0;
> >>   }
> >>   +static void si2157_release(struct dvb_frontend *fe)
> >> +{
> >> +    struct i2c_client *client = fe->tuner_priv;
> >> +    struct si2157_dev *dev = i2c_get_clientdata(client);
> >> +
> >> +    dev_dbg(&client->dev, "%s()\n", __func__);
> >> +
> >> +    /* only do full cleanup on final instance */
> >> +    if (hybrid_tuner_report_instance_count(dev) == 1) {
> >> +        /* stop statistics polling */
> >> +        cancel_delayed_work_sync(&dev->stat_work);
> >> +#ifdef CONFIG_MEDIA_CONTROLLER_DVB
> >> +        if (dev->mdev)
> >> +            media_device_unregister_entity(&dev->ent);
> >> +#endif
> >> +        i2c_set_clientdata(client, NULL);
> >> +    }
> >> +
> >> +    mutex_lock(&si2157_list_mutex);
> >> +    hybrid_tuner_release_state(dev);
> >> +    mutex_unlock(&si2157_list_mutex);
> >> +
> >> +    fe->tuner_priv = NULL;
> >> +}
> >> +
> >>   static const struct dvb_tuner_ops si2157_ops = {
> >>       .info = {
> >>           .name           = "Silicon Labs
> >> Si2141/Si2146/2147/2148/2157/2158",
> >> @@ -396,6 +426,7 @@ static const struct dvb_tuner_ops si2157_ops = {
> >>       .sleep = si2157_sleep,
> >>       .set_params = si2157_set_params,
> >>       .get_if_frequency = si2157_get_if_frequency,
> >> +    .release = si2157_release,
> >>   };
> >>     static void si2157_stat_work(struct work_struct *work)
> >> @@ -431,72 +462,30 @@ static int si2157_probe(struct i2c_client *client,
> >>   {
> >>       struct si2157_config *cfg = client->dev.platform_data;
> >>       struct dvb_frontend *fe = cfg->fe;
> >> -    struct si2157_dev *dev;
> >> -    struct si2157_cmd cmd;
> >> -    int ret;
> >> -
> >> -    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
> >> -    if (!dev) {
> >> -        ret = -ENOMEM;
> >> -        dev_err(&client->dev, "kzalloc() failed\n");
> >> -        goto err;
> >> -    }
> >> -
> >> -    i2c_set_clientdata(client, dev);
> >> -    dev->fe = cfg->fe;
> >> -    dev->inversion = cfg->inversion;
> >> -    dev->if_port = cfg->if_port;
> >> -    dev->chiptype = (u8)id->driver_data;
> >> -    dev->if_frequency = 5000000; /* default value of property 0x0706 */
> >> -    mutex_init(&dev->i2c_mutex);
> >> -    INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work);
> >> +    struct si2157_dev *dev = NULL;
> >> +    unsigned short addr = client->addr;
> >> +    int ret = 0;
> >>   -    /* check if the tuner is there */
> >> -    cmd.wlen = 0;
> >> -    cmd.rlen = 1;
> >> -    ret = si2157_cmd_execute(client, &cmd);
> >> -    if (ret)
> >> -        goto err_kfree;
> >> -
> >> -    memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct
> >> dvb_tuner_ops));
> >> +    dev_dbg(&client->dev, "Probing tuner\n");
> >>       fe->tuner_priv = client;
> >>   -#ifdef CONFIG_MEDIA_CONTROLLER
> >> -    if (cfg->mdev) {
> >> -        dev->mdev = cfg->mdev;
> >> -
> >> -        dev->ent.name = KBUILD_MODNAME;
> >> -        dev->ent.function = MEDIA_ENT_F_TUNER;
> >> -
> >> -        dev->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
> >> -        dev->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
> >> -        dev->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
> >> -
> >> -        ret = media_entity_pads_init(&dev->ent, TUNER_NUM_PADS,
> >> -                         &dev->pad[0]);
> >> -
> >> -        if (ret)
> >> -            goto err_kfree;
> >> -
> >> -        ret = media_device_register_entity(cfg->mdev, &dev->ent);
> >> -        if (ret) {
> >> -            media_entity_cleanup(&dev->ent);
> >> -            goto err_kfree;
> >> -        }
> >> +    if (si2157_attach(fe, (u8)addr, client->adapter, cfg) == NULL) {
> >> +        dev_err(&client->dev, "%s: attaching si2157 tuner failed\n",
> >> +                __func__);
> >> +        goto err;
> >>       }
> >> -#endif
> >> +    fe->ops.tuner_ops.release = NULL;
> >>   +    dev = i2c_get_clientdata(client);
> >> +    dev->chiptype = (u8)id->driver_data;
> >>       dev_info(&client->dev, "Silicon Labs %s successfully attached\n",
> >>               dev->chiptype == SI2157_CHIPTYPE_SI2141 ?  "Si2141" :
> >>               dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
> >>               "Si2146" : "Si2147/2148/2157/2158");
> >>         return 0;
> >> -
> >> -err_kfree:
> >> -    kfree(dev);
> >>   err:
> >> -    dev_dbg(&client->dev, "failed=%d\n", ret);
> >> +    dev_warn(&client->dev, "probe failed = %d\n", ret);
> >>       return ret;
> >>   }
> >>   @@ -505,19 +494,10 @@ static int si2157_remove(struct i2c_client
> >> *client)
> >>       struct si2157_dev *dev = i2c_get_clientdata(client);
> >>       struct dvb_frontend *fe = dev->fe;
> >>   -    dev_dbg(&client->dev, "\n");
> >> -
> >> -    /* stop statistics polling */
> >> -    cancel_delayed_work_sync(&dev->stat_work);
> >> -
> >> -#ifdef CONFIG_MEDIA_CONTROLLER_DVB
> >> -    if (dev->mdev)
> >> -        media_device_unregister_entity(&dev->ent);
> >> -#endif
> >> +    dev_dbg(&client->dev, "%s()\n", __func__);
> >>         memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
> >> -    fe->tuner_priv = NULL;
> >> -    kfree(dev);
> >> +    si2157_release(fe);
> >>         return 0;
> >>   }
> >> @@ -542,7 +522,127 @@ static struct i2c_driver si2157_driver = {
> >>     module_i2c_driver(si2157_driver);
> >>   -MODULE_DESCRIPTION("Silicon Labs Si2141/Si2146/2147/2148/2157/2158
> >> silicon tuner driver");
> >> +struct dvb_frontend *si2157_attach(struct dvb_frontend *fe, u8 addr,
> >> +        struct i2c_adapter *i2c,
> >> +        struct si2157_config *cfg)
> >> +{
> >> +    struct i2c_client *client = NULL;
> >> +    struct si2157_dev *dev = NULL;
> >> +    struct si2157_cmd cmd;
> >> +    int instance = 0, ret;
> >> +
> >> +    pr_debug("%s (%d-%04x)\n", __func__,
> >> +           i2c ? i2c_adapter_id(i2c) : 0,
> >> +           addr);
> >> +
> >> +    if (!cfg) {
> >> +        pr_warn("no configuration submitted\n");
> >> +        goto fail;
> >> +    }
> >> +
> >> +    if (!fe) {
> >> +        pr_warn("fe is NULL\n");
> >> +        goto fail;
> >> +    }
> >> +
> >> +    client = fe->tuner_priv;
> >> +    if (!client) {
> >> +        pr_warn("client is NULL\n");
> >> +        goto fail;
> >> +    }
> >> +
> >> +    mutex_lock(&si2157_list_mutex);
> >> +
> >> +    instance = hybrid_tuner_request_state(struct si2157_dev, dev,
> >> +            hybrid_tuner_instance_list,
> >> +            i2c, addr, "si2157");
> >> +
> >> +    switch (instance) {
> >> +    case 0:
> >> +        goto fail;
> >> +    case 1:
> >> +        /* new tuner instance */
> >> +        dev_dbg(&client->dev, "%s(): new instance for tuner @0x%02x\n",
> >> +                __func__, addr);
> >> +        dev->addr = addr;
> >> +        i2c_set_clientdata(client, dev);
> >> +
> >> +        dev->fe = fe;
> >> +        dev->chiptype = SI2157_CHIPTYPE_SI2157;
> >> +        dev->if_frequency = 0;
> >> +        dev->if_port   = cfg->if_port;
> >> +        dev->inversion = cfg->inversion;
> >> +
> >> +        mutex_init(&dev->i2c_mutex);
> >> +        INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work);
> >> +
> >> +        break;
> >> +    default:
> >> +        /* existing tuner instance */
> >> +        dev_dbg(&client->dev,
> >> +                "%s(): using existing instance for tuner @0x%02x\n",
> >> +                 __func__, addr);
> >> +        break;
> >> +    }
> >> +
> >> +    /* check if the tuner is there */
> >> +    cmd.wlen = 0;
> >> +    cmd.rlen = 1;
> >> +    ret = si2157_cmd_execute(client, &cmd);
> >> +    /* verify no i2c error and CTS is set */
> >> +    if (ret) {
> >> +        dev_warn(&client->dev, "no HW found ret=%d\n", ret);
> >> +        goto fail_instance;
> >> +    }
> >> +
> >> +    memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct
> >> dvb_tuner_ops));
> >> +
> >> +#ifdef CONFIG_MEDIA_CONTROLLER
> >> +    if (instance == 1 && cfg->mdev) {
> >> +        dev->mdev = cfg->mdev;
> >> +
> >> +        dev->ent.name = KBUILD_MODNAME;
> >> +        dev->ent.function = MEDIA_ENT_F_TUNER;
> >> +
> >> +        dev->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
> >> +        dev->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
> >> +        dev->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
> >> +
> >> +        ret = media_entity_pads_init(&dev->ent, TUNER_NUM_PADS,
> >> +                         &dev->pad[0]);
> >> +
> >> +        if (ret)
> >> +            goto fail_instance;
> >> +
> >> +        ret = media_device_register_entity(cfg->mdev, &dev->ent);
> >> +        if (ret) {
> >> +            dev_warn(&client->dev,
> >> +                "media_device_regiser_entity returns %d\n", ret);
> >> +            media_entity_cleanup(&dev->ent);
> >> +            goto fail_instance;
> >> +        }
> >> +    }
> >> +#endif
> >> +    mutex_unlock(&si2157_list_mutex);
> >> +
> >> +    if (instance != 1)
> >> +        dev_info(&client->dev, "Silicon Labs %s successfully
> >> attached\n",
> >> +            dev->chiptype == SI2157_CHIPTYPE_SI2141 ?  "Si2141" :
> >> +            dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
> >> +            "Si2146" : "Si2147/2148/2157/2158");
> >> +
> >> +    return fe;
> >> +fail_instance:
> >> +    mutex_unlock(&si2157_list_mutex);
> >> +
> >> +    si2157_release(fe);
> >> +fail:
> >> +    dev_warn(&client->dev, "Attach failed\n");
> >> +    return NULL;
> >> +}
> >> +EXPORT_SYMBOL(si2157_attach);
> >> +
> >> +MODULE_DESCRIPTION("Silicon Labs Si2141/2146/2147/2148/2157/2158
> >> silicon tuner driver");
> >>   MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
> >>   MODULE_LICENSE("GPL");
> >>   MODULE_FIRMWARE(SI2158_A20_FIRMWARE);
> >> diff --git a/drivers/media/tuners/si2157.h
> >> b/drivers/media/tuners/si2157.h
> >> index de597fa..26b94ca 100644
> >> --- a/drivers/media/tuners/si2157.h
> >> +++ b/drivers/media/tuners/si2157.h
> >> @@ -46,4 +46,18 @@ struct si2157_config {
> >>       u8 if_port;
> >>   };
> >>   +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_SI2157)
> >> +extern struct dvb_frontend *si2157_attach(struct dvb_frontend *fe,
> >> u8 addr,
> >> +                        struct i2c_adapter *i2c,
> >> +                        struct si2157_config *cfg);
> >> +#else
> >> +static inline struct dvb_frontend *si2157_attach(struct dvb_frontend
> >> *fe,
> >> +                           u8 addr,
> >> +                           struct i2c_adapter *i2c,
> >> +                           struct si2157_config *cfg)
> >> +{
> >> +    pr_err("%s: driver disabled by Kconfig\n", __func__);
> >> +    return NULL;
> >> +}
> >> +#endif
> >>   #endif
> >> diff --git a/drivers/media/tuners/si2157_priv.h
> >> b/drivers/media/tuners/si2157_priv.h
> >> index e6436f7..2801aaa 100644
> >> --- a/drivers/media/tuners/si2157_priv.h
> >> +++ b/drivers/media/tuners/si2157_priv.h
> >> @@ -19,15 +19,20 @@
> >>     #include <linux/firmware.h>
> >>   #include <media/v4l2-mc.h>
> >> +#include "tuner-i2c.h"
> >>   #include "si2157.h"
> >>     /* state struct */
> >>   struct si2157_dev {
> >> +    struct list_head hybrid_tuner_instance_list;
> >> +    struct tuner_i2c_props  i2c_props;
> >> +
> >>       struct mutex i2c_mutex;
> >>       struct dvb_frontend *fe;
> >>       bool active;
> >>       bool inversion;
> >>       u8 chiptype;
> >> +    u8 addr;
> >>       u8 if_port;
> >>       u32 if_frequency;
> >>       struct delayed_work stat_work;
> >>  
> >  
> 



Thanks,
Mauro

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 3/7] si2157: Add hybrid tuner support
  2018-03-06 12:24       ` Mauro Carvalho Chehab
@ 2018-03-06 14:44         ` Brad Love
  0 siblings, 0 replies; 25+ messages in thread
From: Brad Love @ 2018-03-06 14:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Brad Love, Antti Palosaari; +Cc: linux-media

Hi Mauro,


On 2018-03-06 06:24, Mauro Carvalho Chehab wrote:
> Hi Brad,
>
> As patches 1 and 2 are independent of this one, and should be backward
> compatible, I'm applying them, but I have issues with this one too :-)
>
> Em Tue, 16 Jan 2018 14:48:35 -0600
> Brad Love <brad@nextdimension.cc> escreveu:
>
>> On 2018-01-15 23:05, Antti Palosaari wrote:
>>> Hello
>>> So the use case is to share single tuner with multiple demodulators?
>>> Why don't just register single tuner and pass that info to multiple
>>> demods?
>>>
>>> Antti  
>> Hello Antti,
>>
>> It was done this way because of lack of knowledge of other ways. The
>> method I used mirrored that done by the three other drivers I found
>> which supported *and* included multiple front ends. We had this _attach
>> function sitting around as part of wip analog support to the si2157, and
>> it seemed like a nice fit here.
> The thing is that dvb_attach() is a very dirty and ugly hack,
> done when we needed to use I2C low level API calls inside DVB,
> while using high level bus-attach based I2C API for V4L.
>
> The hybrid_tuner_instance is yet-another-ugly dirty hack, with even
> causes lots of troubles for static analyzers.
>
> Nowadays, we should, instead, let the I2C bus bind the device
> at the bus and take care of lifetime issues.
>
> Btw, please take a look on this changeset:
>
> 	8f569c0b4e6b ("media: dvb-core: add helper functions for I2C binding")
>
> and an example about how to simplify the binding code at:
>
> 	ad32495b1513 ("media: em28xx-dvb: simplify DVB module probing logic")
>
> Em28xx is currently the only driver using the newer functions - My
> plan is to cleanup other drivers using the same logic as well,
> eventually improving the implementation of the new functions if needed.

I noticed the cleanup, I'll include it in my revised patch.



>
>> I just perused the tree again and noticed one spot I missed originally,
>> which does not use an _attach function. I didn't realize I could just
>> memcpy tuner_ops from fe[0] to fe[1] and call it a done deal, it does
>> appear to work the same though.
> I didn't write any hybrid tuner support using the new I2C binding
> schema, but, if both demods use the same tuner, I guess that's all
> it should be needed (and set adap->mfe_shared to 1).


This patch can be removed from the set, I have just memcpy'd
the tuner_ops to fe[1] now and everything works. I will resubmit a patch
with the mfe_shared property set though.



>
>> Is this really all that is required? If so, I'll modify patch 7/7 and
>> put this patch to the side for now.
>>
>> Cheers,
>>
>> Brad
>>
>>
>>> On 01/12/2018 06:19 PM, Brad Love wrote:  
>>>> Add ability to share a tuner amongst demodulators. Addtional
>>>> demods are attached using hybrid_tuner_instance_list.
>>>>
>>>> The changes are equivalent to moving all of probe to _attach.
>>>> Results are backwards compatible with current usage.
>>>>
>>>> If the tuner is acquired via attach, then .release cleans state.
>>>> if the tuner is an i2c driver, then .release is set to NULL, and
>>>> .remove cleans remaining state.
>>>>
>>>> The following file contains a static si2157_attach:
>>>> - drivers/media/pci/saa7164/saa7164-dvb.c
>>>> The function name has been appended with _priv to appease
>>>> the compiler.
>>>>
>>>> Signed-off-by: Brad Love <brad@nextdimension.cc>
>>>> ---
>>>>   drivers/media/pci/saa7164/saa7164-dvb.c |  11 +-
>>>>   drivers/media/tuners/si2157.c           | 232
>>>> +++++++++++++++++++++++---------
>>>>   drivers/media/tuners/si2157.h           |  14 ++
>>>>   drivers/media/tuners/si2157_priv.h      |   5 +
>>>>   4 files changed, 192 insertions(+), 70 deletions(-)
>>>>
>>>> diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c
>>>> b/drivers/media/pci/saa7164/saa7164-dvb.c
>>>> index e76d3ba..9522c6c 100644
>>>> --- a/drivers/media/pci/saa7164/saa7164-dvb.c
>>>> +++ b/drivers/media/pci/saa7164/saa7164-dvb.c
>>>> @@ -110,8 +110,9 @@ static struct si2157_config
>>>> hauppauge_hvr2255_tuner_config = {
>>>>       .if_port = 1,
>>>>   };
>>>>   -static int si2157_attach(struct saa7164_port *port, struct
>>>> i2c_adapter *adapter,
>>>> -    struct dvb_frontend *fe, u8 addr8bit, struct si2157_config *cfg)
>>>> +static int si2157_attach_priv(struct saa7164_port *port,
>>>> +    struct i2c_adapter *adapter, struct dvb_frontend *fe,
>>>> +    u8 addr8bit, struct si2157_config *cfg)
>>>>   {
>>>>       struct i2c_board_info bi;
>>>>       struct i2c_client *tuner;
>>>> @@ -624,11 +625,13 @@ int saa7164_dvb_register(struct saa7164_port
>>>> *port)
>>>>           if (port->dvb.frontend != NULL) {
>>>>                 if (port->nr == 0) {
>>>> -                si2157_attach(port, &dev->i2c_bus[0].i2c_adap,
>>>> +                si2157_attach_priv(port,
>>>> +                          &dev->i2c_bus[0].i2c_adap,
>>>>                             port->dvb.frontend, 0xc0,
>>>>                             &hauppauge_hvr2255_tuner_config);
>>>>               } else {
>>>> -                si2157_attach(port, &dev->i2c_bus[1].i2c_adap,
>>>> +                si2157_attach_priv(port,
>>>> +                          &dev->i2c_bus[1].i2c_adap,
>>>>                             port->dvb.frontend, 0xc0,
>>>>                             &hauppauge_hvr2255_tuner_config);
>>>>               }
>>>> diff --git a/drivers/media/tuners/si2157.c
>>>> b/drivers/media/tuners/si2157.c
>>>> index e35b1fa..9121361 100644
>>>> --- a/drivers/media/tuners/si2157.c
>>>> +++ b/drivers/media/tuners/si2157.c
>>>> @@ -18,6 +18,11 @@
>>>>     static const struct dvb_tuner_ops si2157_ops;
>>>>   +static DEFINE_MUTEX(si2157_list_mutex);
>>>> +static LIST_HEAD(hybrid_tuner_instance_list);
>>>> +
>>>> +/*---------------------------------------------------------------------*/
>>>>
>>>> +
>>>>   /* execute firmware command */
>>>>   static int si2157_cmd_execute(struct i2c_client *client, struct
>>>> si2157_cmd *cmd)
>>>>   {
>>>> @@ -385,6 +390,31 @@ static int si2157_get_if_frequency(struct
>>>> dvb_frontend *fe, u32 *frequency)
>>>>       return 0;
>>>>   }
>>>>   +static void si2157_release(struct dvb_frontend *fe)
>>>> +{
>>>> +    struct i2c_client *client = fe->tuner_priv;
>>>> +    struct si2157_dev *dev = i2c_get_clientdata(client);
>>>> +
>>>> +    dev_dbg(&client->dev, "%s()\n", __func__);
>>>> +
>>>> +    /* only do full cleanup on final instance */
>>>> +    if (hybrid_tuner_report_instance_count(dev) == 1) {
>>>> +        /* stop statistics polling */
>>>> +        cancel_delayed_work_sync(&dev->stat_work);
>>>> +#ifdef CONFIG_MEDIA_CONTROLLER_DVB
>>>> +        if (dev->mdev)
>>>> +            media_device_unregister_entity(&dev->ent);
>>>> +#endif
>>>> +        i2c_set_clientdata(client, NULL);
>>>> +    }
>>>> +
>>>> +    mutex_lock(&si2157_list_mutex);
>>>> +    hybrid_tuner_release_state(dev);
>>>> +    mutex_unlock(&si2157_list_mutex);
>>>> +
>>>> +    fe->tuner_priv = NULL;
>>>> +}
>>>> +
>>>>   static const struct dvb_tuner_ops si2157_ops = {
>>>>       .info = {
>>>>           .name           = "Silicon Labs
>>>> Si2141/Si2146/2147/2148/2157/2158",
>>>> @@ -396,6 +426,7 @@ static const struct dvb_tuner_ops si2157_ops = {
>>>>       .sleep = si2157_sleep,
>>>>       .set_params = si2157_set_params,
>>>>       .get_if_frequency = si2157_get_if_frequency,
>>>> +    .release = si2157_release,
>>>>   };
>>>>     static void si2157_stat_work(struct work_struct *work)
>>>> @@ -431,72 +462,30 @@ static int si2157_probe(struct i2c_client *client,
>>>>   {
>>>>       struct si2157_config *cfg = client->dev.platform_data;
>>>>       struct dvb_frontend *fe = cfg->fe;
>>>> -    struct si2157_dev *dev;
>>>> -    struct si2157_cmd cmd;
>>>> -    int ret;
>>>> -
>>>> -    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
>>>> -    if (!dev) {
>>>> -        ret = -ENOMEM;
>>>> -        dev_err(&client->dev, "kzalloc() failed\n");
>>>> -        goto err;
>>>> -    }
>>>> -
>>>> -    i2c_set_clientdata(client, dev);
>>>> -    dev->fe = cfg->fe;
>>>> -    dev->inversion = cfg->inversion;
>>>> -    dev->if_port = cfg->if_port;
>>>> -    dev->chiptype = (u8)id->driver_data;
>>>> -    dev->if_frequency = 5000000; /* default value of property 0x0706 */
>>>> -    mutex_init(&dev->i2c_mutex);
>>>> -    INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work);
>>>> +    struct si2157_dev *dev = NULL;
>>>> +    unsigned short addr = client->addr;
>>>> +    int ret = 0;
>>>>   -    /* check if the tuner is there */
>>>> -    cmd.wlen = 0;
>>>> -    cmd.rlen = 1;
>>>> -    ret = si2157_cmd_execute(client, &cmd);
>>>> -    if (ret)
>>>> -        goto err_kfree;
>>>> -
>>>> -    memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct
>>>> dvb_tuner_ops));
>>>> +    dev_dbg(&client->dev, "Probing tuner\n");
>>>>       fe->tuner_priv = client;
>>>>   -#ifdef CONFIG_MEDIA_CONTROLLER
>>>> -    if (cfg->mdev) {
>>>> -        dev->mdev = cfg->mdev;
>>>> -
>>>> -        dev->ent.name = KBUILD_MODNAME;
>>>> -        dev->ent.function = MEDIA_ENT_F_TUNER;
>>>> -
>>>> -        dev->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
>>>> -        dev->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
>>>> -        dev->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
>>>> -
>>>> -        ret = media_entity_pads_init(&dev->ent, TUNER_NUM_PADS,
>>>> -                         &dev->pad[0]);
>>>> -
>>>> -        if (ret)
>>>> -            goto err_kfree;
>>>> -
>>>> -        ret = media_device_register_entity(cfg->mdev, &dev->ent);
>>>> -        if (ret) {
>>>> -            media_entity_cleanup(&dev->ent);
>>>> -            goto err_kfree;
>>>> -        }
>>>> +    if (si2157_attach(fe, (u8)addr, client->adapter, cfg) == NULL) {
>>>> +        dev_err(&client->dev, "%s: attaching si2157 tuner failed\n",
>>>> +                __func__);
>>>> +        goto err;
>>>>       }
>>>> -#endif
>>>> +    fe->ops.tuner_ops.release = NULL;
>>>>   +    dev = i2c_get_clientdata(client);
>>>> +    dev->chiptype = (u8)id->driver_data;
>>>>       dev_info(&client->dev, "Silicon Labs %s successfully attached\n",
>>>>               dev->chiptype == SI2157_CHIPTYPE_SI2141 ?  "Si2141" :
>>>>               dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
>>>>               "Si2146" : "Si2147/2148/2157/2158");
>>>>         return 0;
>>>> -
>>>> -err_kfree:
>>>> -    kfree(dev);
>>>>   err:
>>>> -    dev_dbg(&client->dev, "failed=%d\n", ret);
>>>> +    dev_warn(&client->dev, "probe failed = %d\n", ret);
>>>>       return ret;
>>>>   }
>>>>   @@ -505,19 +494,10 @@ static int si2157_remove(struct i2c_client
>>>> *client)
>>>>       struct si2157_dev *dev = i2c_get_clientdata(client);
>>>>       struct dvb_frontend *fe = dev->fe;
>>>>   -    dev_dbg(&client->dev, "\n");
>>>> -
>>>> -    /* stop statistics polling */
>>>> -    cancel_delayed_work_sync(&dev->stat_work);
>>>> -
>>>> -#ifdef CONFIG_MEDIA_CONTROLLER_DVB
>>>> -    if (dev->mdev)
>>>> -        media_device_unregister_entity(&dev->ent);
>>>> -#endif
>>>> +    dev_dbg(&client->dev, "%s()\n", __func__);
>>>>         memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
>>>> -    fe->tuner_priv = NULL;
>>>> -    kfree(dev);
>>>> +    si2157_release(fe);
>>>>         return 0;
>>>>   }
>>>> @@ -542,7 +522,127 @@ static struct i2c_driver si2157_driver = {
>>>>     module_i2c_driver(si2157_driver);
>>>>   -MODULE_DESCRIPTION("Silicon Labs Si2141/Si2146/2147/2148/2157/2158
>>>> silicon tuner driver");
>>>> +struct dvb_frontend *si2157_attach(struct dvb_frontend *fe, u8 addr,
>>>> +        struct i2c_adapter *i2c,
>>>> +        struct si2157_config *cfg)
>>>> +{
>>>> +    struct i2c_client *client = NULL;
>>>> +    struct si2157_dev *dev = NULL;
>>>> +    struct si2157_cmd cmd;
>>>> +    int instance = 0, ret;
>>>> +
>>>> +    pr_debug("%s (%d-%04x)\n", __func__,
>>>> +           i2c ? i2c_adapter_id(i2c) : 0,
>>>> +           addr);
>>>> +
>>>> +    if (!cfg) {
>>>> +        pr_warn("no configuration submitted\n");
>>>> +        goto fail;
>>>> +    }
>>>> +
>>>> +    if (!fe) {
>>>> +        pr_warn("fe is NULL\n");
>>>> +        goto fail;
>>>> +    }
>>>> +
>>>> +    client = fe->tuner_priv;
>>>> +    if (!client) {
>>>> +        pr_warn("client is NULL\n");
>>>> +        goto fail;
>>>> +    }
>>>> +
>>>> +    mutex_lock(&si2157_list_mutex);
>>>> +
>>>> +    instance = hybrid_tuner_request_state(struct si2157_dev, dev,
>>>> +            hybrid_tuner_instance_list,
>>>> +            i2c, addr, "si2157");
>>>> +
>>>> +    switch (instance) {
>>>> +    case 0:
>>>> +        goto fail;
>>>> +    case 1:
>>>> +        /* new tuner instance */
>>>> +        dev_dbg(&client->dev, "%s(): new instance for tuner @0x%02x\n",
>>>> +                __func__, addr);
>>>> +        dev->addr = addr;
>>>> +        i2c_set_clientdata(client, dev);
>>>> +
>>>> +        dev->fe = fe;
>>>> +        dev->chiptype = SI2157_CHIPTYPE_SI2157;
>>>> +        dev->if_frequency = 0;
>>>> +        dev->if_port   = cfg->if_port;
>>>> +        dev->inversion = cfg->inversion;
>>>> +
>>>> +        mutex_init(&dev->i2c_mutex);
>>>> +        INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work);
>>>> +
>>>> +        break;
>>>> +    default:
>>>> +        /* existing tuner instance */
>>>> +        dev_dbg(&client->dev,
>>>> +                "%s(): using existing instance for tuner @0x%02x\n",
>>>> +                 __func__, addr);
>>>> +        break;
>>>> +    }
>>>> +
>>>> +    /* check if the tuner is there */
>>>> +    cmd.wlen = 0;
>>>> +    cmd.rlen = 1;
>>>> +    ret = si2157_cmd_execute(client, &cmd);
>>>> +    /* verify no i2c error and CTS is set */
>>>> +    if (ret) {
>>>> +        dev_warn(&client->dev, "no HW found ret=%d\n", ret);
>>>> +        goto fail_instance;
>>>> +    }
>>>> +
>>>> +    memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct
>>>> dvb_tuner_ops));
>>>> +
>>>> +#ifdef CONFIG_MEDIA_CONTROLLER
>>>> +    if (instance == 1 && cfg->mdev) {
>>>> +        dev->mdev = cfg->mdev;
>>>> +
>>>> +        dev->ent.name = KBUILD_MODNAME;
>>>> +        dev->ent.function = MEDIA_ENT_F_TUNER;
>>>> +
>>>> +        dev->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
>>>> +        dev->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
>>>> +        dev->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
>>>> +
>>>> +        ret = media_entity_pads_init(&dev->ent, TUNER_NUM_PADS,
>>>> +                         &dev->pad[0]);
>>>> +
>>>> +        if (ret)
>>>> +            goto fail_instance;
>>>> +
>>>> +        ret = media_device_register_entity(cfg->mdev, &dev->ent);
>>>> +        if (ret) {
>>>> +            dev_warn(&client->dev,
>>>> +                "media_device_regiser_entity returns %d\n", ret);
>>>> +            media_entity_cleanup(&dev->ent);
>>>> +            goto fail_instance;
>>>> +        }
>>>> +    }
>>>> +#endif
>>>> +    mutex_unlock(&si2157_list_mutex);
>>>> +
>>>> +    if (instance != 1)
>>>> +        dev_info(&client->dev, "Silicon Labs %s successfully
>>>> attached\n",
>>>> +            dev->chiptype == SI2157_CHIPTYPE_SI2141 ?  "Si2141" :
>>>> +            dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
>>>> +            "Si2146" : "Si2147/2148/2157/2158");
>>>> +
>>>> +    return fe;
>>>> +fail_instance:
>>>> +    mutex_unlock(&si2157_list_mutex);
>>>> +
>>>> +    si2157_release(fe);
>>>> +fail:
>>>> +    dev_warn(&client->dev, "Attach failed\n");
>>>> +    return NULL;
>>>> +}
>>>> +EXPORT_SYMBOL(si2157_attach);
>>>> +
>>>> +MODULE_DESCRIPTION("Silicon Labs Si2141/2146/2147/2148/2157/2158
>>>> silicon tuner driver");
>>>>   MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
>>>>   MODULE_LICENSE("GPL");
>>>>   MODULE_FIRMWARE(SI2158_A20_FIRMWARE);
>>>> diff --git a/drivers/media/tuners/si2157.h
>>>> b/drivers/media/tuners/si2157.h
>>>> index de597fa..26b94ca 100644
>>>> --- a/drivers/media/tuners/si2157.h
>>>> +++ b/drivers/media/tuners/si2157.h
>>>> @@ -46,4 +46,18 @@ struct si2157_config {
>>>>       u8 if_port;
>>>>   };
>>>>   +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_SI2157)
>>>> +extern struct dvb_frontend *si2157_attach(struct dvb_frontend *fe,
>>>> u8 addr,
>>>> +                        struct i2c_adapter *i2c,
>>>> +                        struct si2157_config *cfg);
>>>> +#else
>>>> +static inline struct dvb_frontend *si2157_attach(struct dvb_frontend
>>>> *fe,
>>>> +                           u8 addr,
>>>> +                           struct i2c_adapter *i2c,
>>>> +                           struct si2157_config *cfg)
>>>> +{
>>>> +    pr_err("%s: driver disabled by Kconfig\n", __func__);
>>>> +    return NULL;
>>>> +}
>>>> +#endif
>>>>   #endif
>>>> diff --git a/drivers/media/tuners/si2157_priv.h
>>>> b/drivers/media/tuners/si2157_priv.h
>>>> index e6436f7..2801aaa 100644
>>>> --- a/drivers/media/tuners/si2157_priv.h
>>>> +++ b/drivers/media/tuners/si2157_priv.h
>>>> @@ -19,15 +19,20 @@
>>>>     #include <linux/firmware.h>
>>>>   #include <media/v4l2-mc.h>
>>>> +#include "tuner-i2c.h"
>>>>   #include "si2157.h"
>>>>     /* state struct */
>>>>   struct si2157_dev {
>>>> +    struct list_head hybrid_tuner_instance_list;
>>>> +    struct tuner_i2c_props  i2c_props;
>>>> +
>>>>       struct mutex i2c_mutex;
>>>>       struct dvb_frontend *fe;
>>>>       bool active;
>>>>       bool inversion;
>>>>       u8 chiptype;
>>>> +    u8 addr;
>>>>       u8 if_port;
>>>>       u32 if_frequency;
>>>>       struct delayed_work stat_work;
>>>>  
>>>  
>
>
> Thanks,
> Mauro

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2018-03-06 14:44 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-12 16:19 [PATCH 0/7] cx231xx: Add multiple frontend USB device Brad Love
2018-01-12 16:19 ` [PATCH 1/7] cx231xx: Add second frontend option Brad Love
2018-01-12 19:09   ` Alex Deucher
2018-02-12 21:43     ` Brad Love
2018-02-12 21:40   ` [PATCH v2 " Brad Love
2018-01-12 16:19 ` [PATCH 2/7] cx231xx: Add second i2c demod client Brad Love
2018-02-12 21:41   ` [PATCH v2 " Brad Love
2018-01-12 16:19 ` [PATCH 3/7] si2157: Add hybrid tuner support Brad Love
2018-01-16  5:05   ` Antti Palosaari
2018-01-16 20:48     ` Brad Love
2018-03-06 12:24       ` Mauro Carvalho Chehab
2018-03-06 14:44         ` Brad Love
2018-01-12 16:19 ` [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep Brad Love
2018-01-16  5:07   ` Antti Palosaari
2018-01-16 17:31     ` Brad Love
2018-01-16 19:32       ` Antti Palosaari
2018-01-16 20:14         ` Brad Love
2018-01-16 20:38           ` Antti Palosaari
2018-01-16 22:04             ` Brad Love
2018-02-12 20:19   ` [PATCH v2 4/7] si2168: Add ts bus control, " Brad Love
2018-01-12 16:19 ` [PATCH 6/7] si2168: Announce frontend creation failure Brad Love
2018-01-16  5:10   ` Antti Palosaari
2018-01-12 16:19 ` [PATCH 5/7] lgdt3306a: Announce successful creation Brad Love
2018-01-12 16:19 ` [PATCH 7/7] cx231xx: Add second i2c demod to Hauppauge 975 Brad Love
2018-02-12 21:45   ` [PATCH v2 " Brad Love

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.