linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] rtl2832: convert driver to I2C binding
@ 2014-12-02 14:31 Antti Palosaari
  2014-12-02 14:31 ` [PATCH 2/3] rtl28xxu: switch rtl2832 demod attach " Antti Palosaari
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Antti Palosaari @ 2014-12-02 14:31 UTC (permalink / raw)
  To: linux-media; +Cc: Benjamin Larsson, Antti Palosaari

Convert that driver to I2C driver model.
Legacy DVB binding is left also for later removal...

Signed-off-by: Antti Palosaari <crope@iki.fi>
---
 drivers/media/dvb-frontends/rtl2832.c      | 108 +++++++++++++++++++++++++++++
 drivers/media/dvb-frontends/rtl2832.h      |  10 +++
 drivers/media/dvb-frontends/rtl2832_priv.h |   1 +
 3 files changed, 119 insertions(+)

diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 9026e1a..53b446a 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -1183,6 +1183,114 @@ static struct dvb_frontend_ops rtl2832_ops = {
 	.i2c_gate_ctrl = rtl2832_i2c_gate_ctrl,
 };
 
+static int rtl2832_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct rtl2832_platform_data *pdata = client->dev.platform_data;
+	const struct rtl2832_config *config = pdata->config;
+	struct i2c_adapter *i2c = client->adapter;
+	struct rtl2832_priv *priv;
+	int ret;
+	u8 tmp;
+
+	dev_dbg(&client->dev, "\n");
+
+	/* Caller really need to provide pointer for frontend we create. */
+	if (pdata->dvb_frontend == NULL) {
+		dev_err(&client->dev, "frontend pointer not defined\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* allocate memory for the internal state */
+	priv = kzalloc(sizeof(struct rtl2832_priv), GFP_KERNEL);
+	if (priv == NULL) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	/* setup the priv */
+	priv->client = client;
+	priv->i2c = i2c;
+	priv->tuner = config->tuner;
+	priv->sleeping = true;
+	memcpy(&priv->cfg, config, sizeof(struct rtl2832_config));
+	INIT_DELAYED_WORK(&priv->i2c_gate_work, rtl2832_i2c_gate_work);
+
+	/* create muxed i2c adapter for demod itself */
+	priv->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, priv, 0, 0, 0,
+			rtl2832_select, NULL);
+	if (priv->i2c_adapter == NULL) {
+		ret = -ENODEV;
+		goto err_kfree;
+	}
+
+	/* check if the demod is there */
+	ret = rtl2832_rd_reg(priv, 0x00, 0x0, &tmp);
+	if (ret)
+		goto err_i2c_del_mux_adapter;
+
+	/* create muxed i2c adapter for demod tuner bus */
+	priv->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, priv,
+			0, 1, 0, rtl2832_select, rtl2832_deselect);
+	if (priv->i2c_adapter_tuner == NULL) {
+		ret = -ENODEV;
+		goto err_i2c_del_mux_adapter;
+	}
+
+	/* create dvb_frontend */
+	memcpy(&priv->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
+	priv->fe.ops.release = NULL;
+	priv->fe.demodulator_priv = priv;
+	i2c_set_clientdata(client, priv);
+	*pdata->dvb_frontend = &priv->fe;
+
+	dev_info(&client->dev, "Realtek RTL2832 successfully attached\n");
+	return 0;
+err_i2c_del_mux_adapter:
+	i2c_del_mux_adapter(priv->i2c_adapter);
+err_kfree:
+	kfree(priv);
+err:
+	dev_dbg(&client->dev, "failed=%d\n", ret);
+	return ret;
+}
+
+static int rtl2832_remove(struct i2c_client *client)
+{
+	struct rtl2832_priv *priv = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "\n");
+
+	cancel_delayed_work_sync(&priv->i2c_gate_work);
+
+	i2c_del_mux_adapter(priv->i2c_adapter_tuner);
+
+	i2c_del_mux_adapter(priv->i2c_adapter);
+
+	kfree(priv);
+
+	return 0;
+}
+
+static const struct i2c_device_id rtl2832_id_table[] = {
+	{"rtl2832", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, rtl2832_id_table);
+
+static struct i2c_driver rtl2832_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "rtl2832",
+	},
+	.probe		= rtl2832_probe,
+	.remove		= rtl2832_remove,
+	.id_table	= rtl2832_id_table,
+};
+
+module_i2c_driver(rtl2832_driver);
+
 MODULE_AUTHOR("Thomas Mair <mair.thomas86@gmail.com>");
 MODULE_DESCRIPTION("Realtek RTL2832 DVB-T demodulator driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h
index 5254c1d..cfd69d8 100644
--- a/drivers/media/dvb-frontends/rtl2832.h
+++ b/drivers/media/dvb-frontends/rtl2832.h
@@ -50,6 +50,16 @@ struct rtl2832_config {
 	u8 tuner;
 };
 
+struct rtl2832_platform_data {
+	const struct rtl2832_config *config;
+
+	/*
+	 * frontend
+	 * returned by driver
+	 */
+	struct dvb_frontend **dvb_frontend;
+};
+
 #if IS_ENABLED(CONFIG_DVB_RTL2832)
 struct dvb_frontend *rtl2832_attach(
 	const struct rtl2832_config *cfg,
diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h
index ae469f0..05b2b62 100644
--- a/drivers/media/dvb-frontends/rtl2832_priv.h
+++ b/drivers/media/dvb-frontends/rtl2832_priv.h
@@ -26,6 +26,7 @@
 #include <linux/i2c-mux.h>
 
 struct rtl2832_priv {
+	struct i2c_client *client;
 	struct i2c_adapter *i2c;
 	struct i2c_adapter *i2c_adapter;
 	struct i2c_adapter *i2c_adapter_tuner;
-- 
http://palosaari.fi/


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

* [PATCH 2/3] rtl28xxu: switch rtl2832 demod attach to I2C binding
  2014-12-02 14:31 [PATCH 1/3] rtl2832: convert driver to I2C binding Antti Palosaari
@ 2014-12-02 14:31 ` Antti Palosaari
  2014-12-02 14:31 ` [PATCH 3/3] rtl28xxu: change module unregister order Antti Palosaari
  2014-12-02 20:51 ` [PATCH 1/3] rtl2832: convert driver to I2C binding Benjamin Larsson
  2 siblings, 0 replies; 4+ messages in thread
From: Antti Palosaari @ 2014-12-02 14:31 UTC (permalink / raw)
  To: linux-media; +Cc: Benjamin Larsson, Antti Palosaari

As rtl2832 driver support now I2C binding we will switch to that one.

Signed-off-by: Antti Palosaari <crope@iki.fi>
---
 drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 29 ++++++++++++++++++++++++++---
 drivers/media/usb/dvb-usb-v2/rtl28xxu.h |  1 +
 2 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index 896a225..de8caf7 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -790,7 +790,10 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
 	int ret;
 	struct dvb_usb_device *d = adap_to_d(adap);
 	struct rtl28xxu_priv *priv = d_to_priv(d);
+	struct rtl2832_platform_data platform_data;
 	const struct rtl2832_config *rtl2832_config;
+	struct i2c_board_info board_info = {};
+	struct i2c_client *client;
 
 	dev_dbg(&d->udev->dev, "%s:\n", __func__);
 
@@ -823,12 +826,26 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
 	}
 
 	/* attach demodulator */
-	adap->fe[0] = dvb_attach(rtl2832_attach, rtl2832_config, &d->i2c_adap);
-	if (!adap->fe[0]) {
+	platform_data.config = rtl2832_config;
+	platform_data.dvb_frontend = &adap->fe[0];
+	strlcpy(board_info.type, "rtl2832", I2C_NAME_SIZE);
+	board_info.addr = 0x10;
+	board_info.platform_data = &platform_data;
+	request_module("%s", board_info.type);
+	client = i2c_new_device(&d->i2c_adap, &board_info);
+	if (client == NULL || client->dev.driver == NULL) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
 		ret = -ENODEV;
 		goto err;
 	}
 
+	priv->i2c_client_demod = client;
+
 	/* RTL2832 I2C repeater */
 	priv->demod_i2c_adapter = rtl2832_get_i2c_adapter(adap->fe[0]);
 
@@ -837,7 +854,6 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
 
 	if (priv->slave_demod) {
 		struct i2c_board_info info = {};
-		struct i2c_client *client;
 
 		/*
 		 * We continue on reduced mode, without DVB-T2/C, using master
@@ -1189,6 +1205,13 @@ static void rtl28xxu_exit(struct dvb_usb_device *d)
 		i2c_unregister_device(client);
 	}
 
+	/* remove I2C demod */
+	client = priv->i2c_client_demod;
+	if (client) {
+		module_put(client->dev.driver->owner);
+		i2c_unregister_device(client);
+	}
+
 	return;
 }
 
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
index 3e3ea9d..e52a2b7 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
@@ -57,6 +57,7 @@ struct rtl28xxu_priv {
 	u8 page; /* integrated demod active register page */
 	struct i2c_adapter *demod_i2c_adapter;
 	bool rc_active;
+	struct i2c_client *i2c_client_demod;
 	struct i2c_client *i2c_client_tuner;
 	struct i2c_client *i2c_client_slave_demod;
 	#define SLAVE_DEMOD_NONE           0
-- 
http://palosaari.fi/


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

* [PATCH 3/3] rtl28xxu: change module unregister order
  2014-12-02 14:31 [PATCH 1/3] rtl2832: convert driver to I2C binding Antti Palosaari
  2014-12-02 14:31 ` [PATCH 2/3] rtl28xxu: switch rtl2832 demod attach " Antti Palosaari
@ 2014-12-02 14:31 ` Antti Palosaari
  2014-12-02 20:51 ` [PATCH 1/3] rtl2832: convert driver to I2C binding Benjamin Larsson
  2 siblings, 0 replies; 4+ messages in thread
From: Antti Palosaari @ 2014-12-02 14:31 UTC (permalink / raw)
  To: linux-media; +Cc: Benjamin Larsson, Antti Palosaari

We must unregister frontend first and after that driver itself. That
order went wrong after demod drivers were switched to kernel I2C
drivers, causing crashes.

Signed-off-by: Antti Palosaari <crope@iki.fi>
---
 drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 77 +++++++++++++++++++--------------
 1 file changed, 45 insertions(+), 32 deletions(-)

diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index de8caf7..93bb7c9 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -916,6 +916,31 @@ err:
 	return ret;
 }
 
+static int rtl2832u_frontend_detach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct rtl28xxu_priv *priv = d_to_priv(d);
+	struct i2c_client *client;
+
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	/* remove I2C slave demod */
+	client = priv->i2c_client_slave_demod;
+	if (client) {
+		module_put(client->dev.driver->owner);
+		i2c_unregister_device(client);
+	}
+
+	/* remove I2C demod */
+	client = priv->i2c_client_demod;
+	if (client) {
+		module_put(client->dev.driver->owner);
+		i2c_unregister_device(client);
+	}
+
+	return 0;
+}
+
 static struct qt1010_config rtl28xxu_qt1010_config = {
 	.i2c_address = 0x62, /* 0xc4 */
 };
@@ -1150,6 +1175,24 @@ err:
 	return ret;
 }
 
+static int rtl2832u_tuner_detach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	struct rtl28xxu_priv *priv = d_to_priv(d);
+	struct i2c_client *client;
+
+	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	/* remove I2C tuner */
+	client = priv->i2c_client_tuner;
+	if (client) {
+		module_put(client->dev.driver->owner);
+		i2c_unregister_device(client);
+	}
+
+	return 0;
+}
+
 static int rtl28xxu_init(struct dvb_usb_device *d)
 {
 	int ret;
@@ -1184,37 +1227,6 @@ err:
 	return ret;
 }
 
-static void rtl28xxu_exit(struct dvb_usb_device *d)
-{
-	struct rtl28xxu_priv *priv = d->priv;
-	struct i2c_client *client;
-
-	dev_dbg(&d->udev->dev, "%s:\n", __func__);
-
-	/* remove I2C tuner */
-	client = priv->i2c_client_tuner;
-	if (client) {
-		module_put(client->dev.driver->owner);
-		i2c_unregister_device(client);
-	}
-
-	/* remove I2C slave demod */
-	client = priv->i2c_client_slave_demod;
-	if (client) {
-		module_put(client->dev.driver->owner);
-		i2c_unregister_device(client);
-	}
-
-	/* remove I2C demod */
-	client = priv->i2c_client_demod;
-	if (client) {
-		module_put(client->dev.driver->owner);
-		i2c_unregister_device(client);
-	}
-
-	return;
-}
-
 static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
 {
 	int ret;
@@ -1596,9 +1608,10 @@ static const struct dvb_usb_device_properties rtl2832u_props = {
 	.i2c_algo = &rtl28xxu_i2c_algo,
 	.read_config = rtl2832u_read_config,
 	.frontend_attach = rtl2832u_frontend_attach,
+	.frontend_detach = rtl2832u_frontend_detach,
 	.tuner_attach = rtl2832u_tuner_attach,
+	.tuner_detach = rtl2832u_tuner_detach,
 	.init = rtl28xxu_init,
-	.exit = rtl28xxu_exit,
 	.get_rc_config = rtl2832u_get_rc_config,
 
 	.num_adapters = 1,
-- 
http://palosaari.fi/


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

* Re: [PATCH 1/3] rtl2832: convert driver to I2C binding
  2014-12-02 14:31 [PATCH 1/3] rtl2832: convert driver to I2C binding Antti Palosaari
  2014-12-02 14:31 ` [PATCH 2/3] rtl28xxu: switch rtl2832 demod attach " Antti Palosaari
  2014-12-02 14:31 ` [PATCH 3/3] rtl28xxu: change module unregister order Antti Palosaari
@ 2014-12-02 20:51 ` Benjamin Larsson
  2 siblings, 0 replies; 4+ messages in thread
From: Benjamin Larsson @ 2014-12-02 20:51 UTC (permalink / raw)
  To: Antti Palosaari, linux-media

On 12/02/2014 03:31 PM, Antti Palosaari wrote:
> Convert that driver to I2C driver model.
> Legacy DVB binding is left also for later removal...
>
> Signed-off-by: Antti Palosaari <crope@iki.fi>

Works fine. Thanks for the quick fix.

Tested-by: Benjamin Larsson <benjamin@southpole.se>

MvH
Benjamin Larsson

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

end of thread, other threads:[~2014-12-02 20:51 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-02 14:31 [PATCH 1/3] rtl2832: convert driver to I2C binding Antti Palosaari
2014-12-02 14:31 ` [PATCH 2/3] rtl28xxu: switch rtl2832 demod attach " Antti Palosaari
2014-12-02 14:31 ` [PATCH 3/3] rtl28xxu: change module unregister order Antti Palosaari
2014-12-02 20:51 ` [PATCH 1/3] rtl2832: convert driver to I2C binding Benjamin Larsson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).