All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC/PATCH] dvb-core: add template code for i2c binding model
@ 2014-12-05 10:49 tskd08
  2014-12-05 10:55 ` [PATCH 0/5] ports to dvb-core i2c template code tskd08
                   ` (8 more replies)
  0 siblings, 9 replies; 15+ messages in thread
From: tskd08 @ 2014-12-05 10:49 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab, Akihiro Tsukada

From: Akihiro Tsukada <tskd08@gmail.com>

Define a standard interface for demod/tuner i2c driver modules.
A module client calls dvb_i2c_attach_{fe,tuner}(),
and a module driver defines struct dvb_i2c_module_param and
calls DEFINE_DVB_I2C_MODULE() macro.

This template provides implicit module requests and ref-counting,
alloc/free's private data structures,
fixes the usage of clientdata of i2c devices,
and defines the platformdata structures for passing around
device specific config/output parameters between drivers and clients.
These kinds of code are common to (almost) all dvb i2c drivers/client,
but they were scattered over adapter modules and demod/tuner modules.

Signed-off-by: Akihiro Tsukada <tskd08@gmail.com>
---
 drivers/media/dvb-core/Makefile       |   4 +
 drivers/media/dvb-core/dvb_frontend.h |   1 +
 drivers/media/dvb-core/dvb_i2c.c      | 219 ++++++++++++++++++++++++++++++++++
 drivers/media/dvb-core/dvb_i2c.h      | 110 +++++++++++++++++
 4 files changed, 334 insertions(+)
 create mode 100644 drivers/media/dvb-core/dvb_i2c.c
 create mode 100644 drivers/media/dvb-core/dvb_i2c.h

diff --git a/drivers/media/dvb-core/Makefile b/drivers/media/dvb-core/Makefile
index 8f22bcd..271648d 100644
--- a/drivers/media/dvb-core/Makefile
+++ b/drivers/media/dvb-core/Makefile
@@ -8,4 +8,8 @@ dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o 	\
 		 dvb_ca_en50221.o dvb_frontend.o 		\
 		 $(dvb-net-y) dvb_ringbuffer.o dvb_math.o
 
+ifneq ($(CONFIG_I2C)$(CONFIG_I2C_MODULE),)
+dvb-core-objs += dvb_i2c.o
+endif
+
 obj-$(CONFIG_DVB_CORE) += dvb-core.o
diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h
index 816269e..41aae1b 100644
--- a/drivers/media/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb-core/dvb_frontend.h
@@ -415,6 +415,7 @@ struct dtv_frontend_properties {
 struct dvb_frontend {
 	struct dvb_frontend_ops ops;
 	struct dvb_adapter *dvb;
+	struct i2c_client *fe_cl;
 	void *demodulator_priv;
 	void *tuner_priv;
 	void *frontend_priv;
diff --git a/drivers/media/dvb-core/dvb_i2c.c b/drivers/media/dvb-core/dvb_i2c.c
new file mode 100644
index 0000000..4ea4e5e
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_i2c.c
@@ -0,0 +1,219 @@
+/*
+ * dvb_i2c.c
+ *
+ * Copyright 2014 Akihiro Tsukada <tskd08 AT gmail DOT com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "dvb_i2c.h"
+
+static struct i2c_client *
+dvb_i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info *info,
+		   const unsigned short *probe_addrs)
+{
+	struct i2c_client *cl;
+
+	request_module(I2C_MODULE_PREFIX "%s", info->type);
+	/* Create the i2c client */
+	if (info->addr == 0 && probe_addrs)
+		cl = i2c_new_probed_device(adap, info, probe_addrs, NULL);
+	else
+		cl = i2c_new_device(adap, info);
+	if (!cl || !cl->dev.driver)
+		return NULL;
+	return cl;
+}
+
+struct dvb_frontend *
+dvb_i2c_attach_fe(struct i2c_adapter *adap, const struct i2c_board_info *info,
+		  const void *cfg, void **out)
+{
+	struct i2c_client *cl;
+	struct i2c_board_info bi;
+	struct dvb_i2c_dev_config dcfg;
+
+	dcfg.priv_cfg = cfg;
+	dcfg.out = out;
+	bi = *info;
+	bi.platform_data = &dcfg;
+
+	cl = dvb_i2c_new_device(adap, &bi, NULL);
+	if (!cl)
+		return NULL;
+	return i2c_get_clientdata(cl);
+}
+EXPORT_SYMBOL(dvb_i2c_attach_fe);
+
+struct i2c_client *
+dvb_i2c_attach_tuner(struct i2c_adapter *adap,
+		     const struct i2c_board_info *info,
+		     struct dvb_frontend *fe,
+		     const void *cfg, void **out)
+{
+	struct i2c_board_info bi;
+	struct dvb_i2c_tuner_config tcfg;
+
+	tcfg.fe = fe;
+	tcfg.devcfg.priv_cfg = cfg;
+	tcfg.devcfg.out = out;
+	bi = *info;
+	bi.platform_data = &tcfg;
+
+	return dvb_i2c_new_device(adap, &bi, NULL);
+}
+EXPORT_SYMBOL(dvb_i2c_attach_tuner);
+
+
+static int
+probe_tuner(struct i2c_client *client, const struct i2c_device_id *id,
+	    const struct dvb_i2c_module_param *param,
+	    struct module *this_module)
+{
+	struct dvb_frontend *fe;
+	struct dvb_i2c_tuner_config *tcfg;
+	int ret;
+
+	if (!try_module_get(this_module))
+		return -ENODEV;
+
+	tcfg = client->dev.platform_data;
+	fe = tcfg->fe;
+	i2c_set_clientdata(client, fe);
+
+	if (param->priv_size > 0) {
+		fe->tuner_priv = kzalloc(param->priv_size, GFP_KERNEL);
+		if (!fe->tuner_priv) {
+			ret = -ENOMEM;
+			goto err_mem;
+		}
+	}
+
+	if (param->ops.tuner_ops)
+		memcpy(&fe->ops.tuner_ops, param->ops.tuner_ops,
+			sizeof(fe->ops.tuner_ops));
+
+	ret = 0;
+	if (param->priv_probe)
+		ret = param->priv_probe(client, id);
+	if (ret != 0) {
+		dev_info(&client->dev, "driver private probe failed.\n");
+		goto err_priv;
+	}
+	return 0;
+
+err_priv:
+	kfree(fe->tuner_priv);
+err_mem:
+	fe->tuner_priv = NULL;
+	module_put(this_module);
+	return ret;
+}
+
+static int remove_tuner(struct i2c_client *client,
+			const struct dvb_i2c_module_param *param,
+			struct module *this_module)
+{
+	struct dvb_frontend *fe;
+
+	if (param->priv_remove)
+		param->priv_remove(client);
+	fe = i2c_get_clientdata(client);
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	module_put(this_module);
+	return 0;
+}
+
+
+static int probe_fe(struct i2c_client *client, const struct i2c_device_id *id,
+		    const struct dvb_i2c_module_param *param,
+		    struct module *this_module)
+{
+	struct dvb_frontend *fe;
+	int ret;
+
+	if (!try_module_get(this_module))
+		return -ENODEV;
+
+	fe = kzalloc(sizeof(*fe), GFP_KERNEL);
+	if (!fe) {
+		ret = -ENOMEM;
+		goto err_fe_kfree;
+	}
+	i2c_set_clientdata(client, fe);
+	fe->fe_cl = client;
+
+	if (param->priv_size > 0) {
+		fe->demodulator_priv = kzalloc(param->priv_size, GFP_KERNEL);
+		if (!fe->demodulator_priv) {
+			ret = -ENOMEM;
+			goto err_fe_kfree;
+		}
+	}
+
+	if (param->ops.fe_ops)
+		memcpy(&fe->ops, param->ops.fe_ops, sizeof(fe->ops));
+
+	ret = 0;
+	if (param->priv_probe)
+		ret = param->priv_probe(client, id);
+	if (ret != 0) {
+		dev_info(&client->dev, "driver private probe failed.\n");
+		goto err_priv_kfree;
+	}
+	return 0;
+
+err_priv_kfree:
+	kfree(fe->demodulator_priv);
+err_fe_kfree:
+	kfree(fe);
+	module_put(this_module);
+	return ret;
+}
+
+static int remove_fe(struct i2c_client *client,
+		     const struct dvb_i2c_module_param *param,
+		     struct module *this_module)
+{
+	struct dvb_frontend *fe;
+
+	if (param->priv_remove)
+		param->priv_remove(client);
+	fe = i2c_get_clientdata(client);
+	kfree(fe->demodulator_priv);
+	kfree(fe);
+	module_put(this_module);
+	return 0;
+}
+
+
+int dvb_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id,
+		  const struct dvb_i2c_module_param *param,
+		  struct module *this_module)
+{
+	return param->is_tuner ? probe_tuner(client, id, param, this_module) :
+				 probe_fe(client, id, param, this_module);
+}
+EXPORT_SYMBOL(dvb_i2c_probe);
+
+int dvb_i2c_remove(struct i2c_client *client,
+		   const struct dvb_i2c_module_param *param,
+		   struct module *this_module)
+{
+	return param->is_tuner ? remove_tuner(client, param, this_module) :
+				 remove_fe(client, param, this_module);
+}
+EXPORT_SYMBOL(dvb_i2c_remove);
diff --git a/drivers/media/dvb-core/dvb_i2c.h b/drivers/media/dvb-core/dvb_i2c.h
new file mode 100644
index 0000000..2bf409d
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_i2c.h
@@ -0,0 +1,110 @@
+/*
+ * dvb_i2c.h
+ *
+ * Copyright 2014 Akihiro Tsukada <tskd08 AT gmail DOT com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* template code for i2c driver modules */
+
+#ifndef _DVB_I2C_H_
+#define _DVB_I2C_H_
+
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "dvb_frontend.h"
+
+/* interface for module clients */
+
+struct dvb_frontend *dvb_i2c_attach_fe(struct i2c_adapter *adap,
+				       const struct i2c_board_info *info,
+				       const void *cfg, void **out);
+
+struct i2c_client *dvb_i2c_attach_tuner(struct i2c_adapter *adap,
+					const struct i2c_board_info *info,
+					struct dvb_frontend *fe,
+					const void *cfg, void **out);
+
+/* interface for module drivers */
+
+/* data structures that are set to i2c_client.dev.platform_data */
+
+struct dvb_i2c_dev_config {
+	const void *priv_cfg;
+	/* @out [OUT] pointer to per-device data returned from driver */
+	void **out;
+};
+
+struct dvb_i2c_tuner_config {
+	struct dvb_frontend *fe;
+	struct dvb_i2c_dev_config devcfg;
+};
+
+typedef int (*dvb_i2c_probe_func)(struct i2c_client *client,
+				  const struct i2c_device_id *id);
+typedef int (*dvb_i2c_remove_func)(struct i2c_client *client);
+
+struct dvb_i2c_module_param {
+	union {
+		const struct dvb_frontend_ops *fe_ops;
+		const struct dvb_tuner_ops *tuner_ops;
+	} ops;
+	/* driver private probe/remove functions */
+	dvb_i2c_probe_func  priv_probe;
+	dvb_i2c_remove_func priv_remove;
+
+	u32 priv_size; /* sizeof(device private data) */
+	bool is_tuner;
+};
+
+
+int dvb_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id,
+		  const struct dvb_i2c_module_param *param,
+		  struct module *this_module);
+
+int dvb_i2c_remove(struct i2c_client *client,
+		   const struct dvb_i2c_module_param *param,
+		   struct module *this_module);
+
+
+#define DEFINE_DVB_I2C_MODULE(dname, idtab, param) \
+static int _##dname##_probe(struct i2c_client *client,\
+				const struct i2c_device_id *id)\
+{\
+	return dvb_i2c_probe(client, id, &(param), THIS_MODULE);\
+} \
+\
+static int _##dname##_remove(struct i2c_client *client)\
+{\
+	return dvb_i2c_remove(client, &(param), THIS_MODULE);\
+} \
+\
+MODULE_DEVICE_TABLE(i2c, idtab);\
+\
+static struct i2c_driver dname##_driver = {\
+	.driver = {\
+		.name = #dname,\
+	},\
+	.probe    = _##dname##_probe,\
+	.remove   = _##dname##_remove,\
+	.id_table = idtab,\
+};\
+\
+module_i2c_driver(dname##_driver)
+
+#endif /* _DVB_I2C_H */
-- 
2.1.3


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

* [PATCH 0/5] ports to dvb-core i2c template code
  2014-12-05 10:49 [RFC/PATCH] dvb-core: add template code for i2c binding model tskd08
@ 2014-12-05 10:55 ` tskd08
  2014-12-05 10:55 ` [PATCH 1/5] dvb: qm1d1c0042: use dvb-core i2c binding model template tskd08
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: tskd08 @ 2014-12-05 10:55 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab, Akihiro Tsukada

From: Akihiro Tsukada <tskd08@gmail.com>

These patches are example ports of earth-pt3 (adapter),
tc90522 (demod), qm1d1c0042,mxl301rf (tuners) drivers
using the i2c template code in dvb-core.

Akihiro Tsukada (5):
  dvb: qm1d1c0042: use dvb-core i2c binding model template
  dvb: mxl301rf: use dvb-core i2c binding model template
  dvb: tc90522: use dvb-core i2c binding model template
  dvb: tc90522: remove a redundant state variable
  dvb: pci/pt3: use dvb-core i2c binding model template

 drivers/media/dvb-frontends/tc90522.c | 145 ++++++++++++++--------------------
 drivers/media/dvb-frontends/tc90522.h |   8 +-
 drivers/media/pci/pt3/pt3.c           |  89 +++++++--------------
 drivers/media/pci/pt3/pt3.h           |  12 +--
 drivers/media/tuners/mxl301rf.c       |  50 +++---------
 drivers/media/tuners/mxl301rf.h       |   2 +-
 drivers/media/tuners/qm1d1c0042.c     |  61 +++++---------
 drivers/media/tuners/qm1d1c0042.h     |   2 -
 8 files changed, 131 insertions(+), 238 deletions(-)

-- 
2.1.3


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

* [PATCH 1/5] dvb: qm1d1c0042: use dvb-core i2c binding model template
  2014-12-05 10:49 [RFC/PATCH] dvb-core: add template code for i2c binding model tskd08
  2014-12-05 10:55 ` [PATCH 0/5] ports to dvb-core i2c template code tskd08
@ 2014-12-05 10:55 ` tskd08
  2014-12-05 10:55 ` [PATCH 2/5] dvb: mxl301rf: " tskd08
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: tskd08 @ 2014-12-05 10:55 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab, Akihiro Tsukada

From: Akihiro Tsukada <tskd08@gmail.com>

Signed-off-by: Akihiro Tsukada <tskd08@gmail.com>
---
 drivers/media/tuners/qm1d1c0042.c | 61 +++++++++++++--------------------------
 drivers/media/tuners/qm1d1c0042.h |  2 --
 2 files changed, 20 insertions(+), 43 deletions(-)

diff --git a/drivers/media/tuners/qm1d1c0042.c b/drivers/media/tuners/qm1d1c0042.c
index 18bc745..f1f4bec 100644
--- a/drivers/media/tuners/qm1d1c0042.c
+++ b/drivers/media/tuners/qm1d1c0042.c
@@ -29,6 +29,7 @@
 
 #include <linux/kernel.h>
 #include <linux/math64.h>
+#include "dvb_i2c.h"
 #include "qm1d1c0042.h"
 
 #define QM1D1C0042_NUM_REGS 0x20
@@ -55,11 +56,6 @@ struct qm1d1c0042_state {
 	u8 regs[QM1D1C0042_NUM_REGS];
 };
 
-static struct qm1d1c0042_state *cfg_to_state(struct qm1d1c0042_config *c)
-{
-	return container_of(c, struct qm1d1c0042_state, cfg);
-}
-
 static int reg_write(struct qm1d1c0042_state *state, u8 reg, u8 val)
 {
 	u8 wbuf[2] = { reg, val };
@@ -106,10 +102,12 @@ static int qm1d1c0042_set_srch_mode(struct qm1d1c0042_state *state, bool fast)
 	return reg_write(state, 0x03, state->regs[0x03]);
 }
 
-static int qm1d1c0042_wakeup(struct qm1d1c0042_state *state)
+static int qm1d1c0042_wakeup(struct dvb_frontend *fe)
 {
+	struct qm1d1c0042_state *state;
 	int ret;
 
+	state = fe->tuner_priv;
 	state->regs[0x01] |= 1 << 3;             /* BB_Reg_enable */
 	state->regs[0x01] &= (~(1 << 0)) & 0xff; /* NORMAL (wake-up) */
 	state->regs[0x05] &= (~(1 << 3)) & 0xff; /* pfd_rst NORMAL */
@@ -119,7 +117,7 @@ static int qm1d1c0042_wakeup(struct qm1d1c0042_state *state)
 
 	if (ret < 0)
 		dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
-			__func__, state->cfg.fe->dvb->num, state->cfg.fe->id);
+			__func__, fe->dvb->num, fe->id);
 	return ret;
 }
 
@@ -133,9 +131,6 @@ static int qm1d1c0042_set_config(struct dvb_frontend *fe, void *priv_cfg)
 	state = fe->tuner_priv;
 	cfg = priv_cfg;
 
-	if (cfg->fe)
-		state->cfg.fe = cfg->fe;
-
 	if (cfg->xtal_freq != QM1D1C0042_CFG_XTAL_DFLT)
 		dev_warn(&state->i2c->dev,
 			"(%s) changing xtal_freq not supported. ", __func__);
@@ -359,7 +354,7 @@ static int qm1d1c0042_init(struct dvb_frontend *fe)
 			goto failed;
 	}
 
-	ret = qm1d1c0042_wakeup(state);
+	ret = qm1d1c0042_wakeup(fe);
 	if (ret < 0)
 		goto failed;
 
@@ -395,53 +390,37 @@ static const struct dvb_tuner_ops qm1d1c0042_ops = {
 static int qm1d1c0042_probe(struct i2c_client *client,
 			    const struct i2c_device_id *id)
 {
-	struct qm1d1c0042_state *state;
-	struct qm1d1c0042_config *cfg;
+	struct dvb_i2c_tuner_config *tcfg;
 	struct dvb_frontend *fe;
+	struct qm1d1c0042_state *state;
 
-	state = kzalloc(sizeof(*state), GFP_KERNEL);
-	if (!state)
-		return -ENOMEM;
+dev_info(&client->dev, "qm1d1c0042_probe().\n");
+	tcfg = client->dev.platform_data;
+	fe = tcfg->fe;
+	state = fe->tuner_priv;
 	state->i2c = client;
 
-	cfg = client->dev.platform_data;
-	fe = cfg->fe;
-	fe->tuner_priv = state;
-	qm1d1c0042_set_config(fe, cfg);
-	memcpy(&fe->ops.tuner_ops, &qm1d1c0042_ops, sizeof(qm1d1c0042_ops));
+	qm1d1c0042_set_config(fe, (void *)tcfg->devcfg.priv_cfg);
 
-	i2c_set_clientdata(client, &state->cfg);
 	dev_info(&client->dev, "Sharp QM1D1C0042 attached.\n");
 	return 0;
 }
 
-static int qm1d1c0042_remove(struct i2c_client *client)
-{
-	struct qm1d1c0042_state *state;
-
-	state = cfg_to_state(i2c_get_clientdata(client));
-	state->cfg.fe->tuner_priv = NULL;
-	kfree(state);
-	return 0;
-}
-
 
 static const struct i2c_device_id qm1d1c0042_id[] = {
 	{"qm1d1c0042", 0},
 	{}
 };
-MODULE_DEVICE_TABLE(i2c, qm1d1c0042_id);
 
-static struct i2c_driver qm1d1c0042_driver = {
-	.driver = {
-		.name	= "qm1d1c0042",
-	},
-	.probe		= qm1d1c0042_probe,
-	.remove		= qm1d1c0042_remove,
-	.id_table	= qm1d1c0042_id,
+static const struct dvb_i2c_module_param qm1d1c0042_param = {
+	.ops.tuner_ops = &qm1d1c0042_ops,
+	.priv_probe = qm1d1c0042_probe,
+
+	.priv_size = sizeof(struct qm1d1c0042_state),
+	.is_tuner = true,
 };
 
-module_i2c_driver(qm1d1c0042_driver);
+DEFINE_DVB_I2C_MODULE(qm1d1c0042, qm1d1c0042_id, qm1d1c0042_param);
 
 MODULE_DESCRIPTION("Sharp QM1D1C0042 tuner");
 MODULE_AUTHOR("Akihiro TSUKADA");
diff --git a/drivers/media/tuners/qm1d1c0042.h b/drivers/media/tuners/qm1d1c0042.h
index 4f5c188..043787e 100644
--- a/drivers/media/tuners/qm1d1c0042.h
+++ b/drivers/media/tuners/qm1d1c0042.h
@@ -21,8 +21,6 @@
 
 
 struct qm1d1c0042_config {
-	struct dvb_frontend *fe;
-
 	u32  xtal_freq;    /* [kHz] */ /* currently ignored */
 	bool lpf;          /* enable LPF */
 	bool fast_srch;    /* enable fast search mode, no LPF */
-- 
2.1.3


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

* [PATCH 2/5] dvb: mxl301rf: use dvb-core i2c binding model template
  2014-12-05 10:49 [RFC/PATCH] dvb-core: add template code for i2c binding model tskd08
  2014-12-05 10:55 ` [PATCH 0/5] ports to dvb-core i2c template code tskd08
  2014-12-05 10:55 ` [PATCH 1/5] dvb: qm1d1c0042: use dvb-core i2c binding model template tskd08
@ 2014-12-05 10:55 ` tskd08
  2014-12-05 10:55 ` [PATCH 3/5] dvb: tc90522: " tskd08
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: tskd08 @ 2014-12-05 10:55 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab, Akihiro Tsukada

From: Akihiro Tsukada <tskd08@gmail.com>

Signed-off-by: Akihiro Tsukada <tskd08@gmail.com>
---
 drivers/media/tuners/mxl301rf.c | 50 +++++++++++------------------------------
 drivers/media/tuners/mxl301rf.h |  2 +-
 2 files changed, 14 insertions(+), 38 deletions(-)

diff --git a/drivers/media/tuners/mxl301rf.c b/drivers/media/tuners/mxl301rf.c
index 1575a5d..d428132 100644
--- a/drivers/media/tuners/mxl301rf.c
+++ b/drivers/media/tuners/mxl301rf.c
@@ -29,6 +29,8 @@
  */
 
 #include <linux/kernel.h>
+#include "dvb_i2c.h"
+
 #include "mxl301rf.h"
 
 struct mxl301rf_state {
@@ -36,11 +38,6 @@ struct mxl301rf_state {
 	struct i2c_client *i2c;
 };
 
-static struct mxl301rf_state *cfg_to_state(struct mxl301rf_config *c)
-{
-	return container_of(c, struct mxl301rf_state, cfg);
-}
-
 static int raw_write(struct mxl301rf_state *state, const u8 *buf, int len)
 {
 	int ret;
@@ -295,54 +292,33 @@ static const struct dvb_tuner_ops mxl301rf_ops = {
 static int mxl301rf_probe(struct i2c_client *client,
 			  const struct i2c_device_id *id)
 {
+	struct dvb_i2c_tuner_config *tcfg;
 	struct mxl301rf_state *state;
-	struct mxl301rf_config *cfg;
-	struct dvb_frontend *fe;
-
-	state = kzalloc(sizeof(*state), GFP_KERNEL);
-	if (!state)
-		return -ENOMEM;
 
+	tcfg = client->dev.platform_data;
+	state = tcfg->fe->tuner_priv;
 	state->i2c = client;
-	cfg = client->dev.platform_data;
 
-	memcpy(&state->cfg, cfg, sizeof(state->cfg));
-	fe = cfg->fe;
-	fe->tuner_priv = state;
-	memcpy(&fe->ops.tuner_ops, &mxl301rf_ops, sizeof(mxl301rf_ops));
+	memcpy(&state->cfg, tcfg->devcfg.priv_cfg, sizeof(state->cfg));
 
-	i2c_set_clientdata(client, &state->cfg);
 	dev_info(&client->dev, "MaxLinear MxL301RF attached.\n");
 	return 0;
 }
 
-static int mxl301rf_remove(struct i2c_client *client)
-{
-	struct mxl301rf_state *state;
-
-	state = cfg_to_state(i2c_get_clientdata(client));
-	state->cfg.fe->tuner_priv = NULL;
-	kfree(state);
-	return 0;
-}
-
-
 static const struct i2c_device_id mxl301rf_id[] = {
 	{"mxl301rf", 0},
 	{}
 };
-MODULE_DEVICE_TABLE(i2c, mxl301rf_id);
 
-static struct i2c_driver mxl301rf_driver = {
-	.driver = {
-		.name	= "mxl301rf",
-	},
-	.probe		= mxl301rf_probe,
-	.remove		= mxl301rf_remove,
-	.id_table	= mxl301rf_id,
+static const struct dvb_i2c_module_param mxl301rf_param = {
+	.ops.tuner_ops = &mxl301rf_ops,
+	.priv_probe = mxl301rf_probe,
+
+	.priv_size = sizeof(struct mxl301rf_state),
+	.is_tuner = true,
 };
 
-module_i2c_driver(mxl301rf_driver);
+DEFINE_DVB_I2C_MODULE(mxl301rf, mxl301rf_id, mxl301rf_param);
 
 MODULE_DESCRIPTION("MaxLinear MXL301RF tuner");
 MODULE_AUTHOR("Akihiro TSUKADA");
diff --git a/drivers/media/tuners/mxl301rf.h b/drivers/media/tuners/mxl301rf.h
index 19e6840..069a6a0 100644
--- a/drivers/media/tuners/mxl301rf.h
+++ b/drivers/media/tuners/mxl301rf.h
@@ -20,7 +20,7 @@
 #include "dvb_frontend.h"
 
 struct mxl301rf_config {
-	struct dvb_frontend *fe;
+	/* none now */
 };
 
 #endif /* MXL301RF_H */
-- 
2.1.3


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

* [PATCH 3/5] dvb: tc90522: use dvb-core i2c binding model template
  2014-12-05 10:49 [RFC/PATCH] dvb-core: add template code for i2c binding model tskd08
                   ` (2 preceding siblings ...)
  2014-12-05 10:55 ` [PATCH 2/5] dvb: mxl301rf: " tskd08
@ 2014-12-05 10:55 ` tskd08
  2014-12-05 10:55 ` [PATCH 4/5] dvb: tc90522: remove a redundant state variable tskd08
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: tskd08 @ 2014-12-05 10:55 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab, Akihiro Tsukada

From: Akihiro Tsukada <tskd08@gmail.com>

Signed-off-by: Akihiro Tsukada <tskd08@gmail.com>
---
 drivers/media/dvb-frontends/tc90522.c | 56 ++++++++++++++++-------------------
 drivers/media/dvb-frontends/tc90522.h |  8 ++---
 2 files changed, 29 insertions(+), 35 deletions(-)

diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c
index b35d65c..0f4ddd7 100644
--- a/drivers/media/dvb-frontends/tc90522.c
+++ b/drivers/media/dvb-frontends/tc90522.c
@@ -30,6 +30,7 @@
 #include <linux/kernel.h>
 #include <linux/math64.h>
 #include <linux/dvb/frontend.h>
+#include "dvb_i2c.h"
 #include "dvb_math.h"
 #include "tc90522.h"
 
@@ -39,7 +40,6 @@
 
 struct tc90522_state {
 	struct tc90522_config cfg;
-	struct dvb_frontend fe;
 	struct i2c_client *i2c_client;
 	struct i2c_adapter tuner_i2c;
 
@@ -98,11 +98,6 @@ static int reg_read(struct tc90522_state *state, u8 reg, u8 *val, u8 len)
 	return ret;
 }
 
-static struct tc90522_state *cfg_to_state(struct tc90522_config *c)
-{
-	return container_of(c, struct tc90522_state, cfg);
-}
-
 
 static int tc90522s_set_tsid(struct dvb_frontend *fe)
 {
@@ -766,51 +761,51 @@ static const struct dvb_frontend_ops tc90522_ops_ter = {
 static int tc90522_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
+	struct dvb_frontend *fe;
 	struct tc90522_state *state;
-	struct tc90522_config *cfg;
+	struct dvb_i2c_dev_config *dcfg;
 	const struct dvb_frontend_ops *ops;
 	struct i2c_adapter *adap;
 	int ret;
 
-	state = kzalloc(sizeof(*state), GFP_KERNEL);
-	if (!state)
-		return -ENOMEM;
+	fe = i2c_get_clientdata(client);
+	state = fe->demodulator_priv;
 	state->i2c_client = client;
 
-	cfg = client->dev.platform_data;
-	memcpy(&state->cfg, cfg, sizeof(state->cfg));
-	cfg->fe = state->cfg.fe = &state->fe;
+	dcfg = client->dev.platform_data;
+	if (dcfg && dcfg->priv_cfg)
+		memcpy(&state->cfg, dcfg->priv_cfg, sizeof(state->cfg));
 	ops =  id->driver_data == 0 ? &tc90522_ops_sat : &tc90522_ops_ter;
-	memcpy(&state->fe.ops, ops, sizeof(*ops));
-	state->fe.demodulator_priv = state;
+	memcpy(&fe->ops, ops, sizeof(*ops));
 
 	adap = &state->tuner_i2c;
 	adap->owner = THIS_MODULE;
 	adap->algo = &tc90522_tuner_i2c_algo;
 	adap->dev.parent = &client->dev;
 	strlcpy(adap->name, "tc90522_sub", sizeof(adap->name));
-	i2c_set_adapdata(adap, state);
 	ret = i2c_add_adapter(adap);
 	if (ret < 0)
-		goto err;
-	cfg->tuner_i2c = state->cfg.tuner_i2c = adap;
+		goto err_mem;
+	if (dcfg && dcfg->out)
+		*dcfg->out = (struct tc90522_out *)adap;
+	i2c_set_adapdata(adap, state); /* used in tc90522_master_xfer() */
 
-	i2c_set_clientdata(client, &state->cfg);
 	dev_info(&client->dev, "Toshiba TC90522 attached.\n");
 	return 0;
 
-err:
+err_mem:
 	kfree(state);
 	return ret;
 }
 
 static int tc90522_remove(struct i2c_client *client)
 {
+	struct dvb_frontend *fe;
 	struct tc90522_state *state;
 
-	state = cfg_to_state(i2c_get_clientdata(client));
+	fe = i2c_get_clientdata(client);
+	state = fe->demodulator_priv;
 	i2c_del_adapter(&state->tuner_i2c);
-	kfree(state);
 	return 0;
 }
 
@@ -820,18 +815,17 @@ static const struct i2c_device_id tc90522_id[] = {
 	{ TC90522_I2C_DEV_TER, 1 },
 	{}
 };
-MODULE_DEVICE_TABLE(i2c, tc90522_id);
 
-static struct i2c_driver tc90522_driver = {
-	.driver = {
-		.name	= "tc90522",
-	},
-	.probe		= tc90522_probe,
-	.remove		= tc90522_remove,
-	.id_table	= tc90522_id,
+static const struct dvb_i2c_module_param tc90522_param = {
+	.ops.fe_ops = NULL,
+	.priv_probe = tc90522_probe,
+	.priv_remove = tc90522_remove,
+
+	.priv_size = sizeof(struct tc90522_state),
+	.is_tuner = false,
 };
 
-module_i2c_driver(tc90522_driver);
+DEFINE_DVB_I2C_MODULE(tc90522, tc90522_id, tc90522_param);
 
 MODULE_DESCRIPTION("Toshiba TC90522 frontend");
 MODULE_AUTHOR("Akihiro TSUKADA");
diff --git a/drivers/media/dvb-frontends/tc90522.h b/drivers/media/dvb-frontends/tc90522.h
index b1cbddf..4b69d03 100644
--- a/drivers/media/dvb-frontends/tc90522.h
+++ b/drivers/media/dvb-frontends/tc90522.h
@@ -32,11 +32,11 @@
 #define TC90522_I2C_DEV_TER "tc90522ter"
 
 struct tc90522_config {
-	/* [OUT] frontend returned by driver */
-	struct dvb_frontend *fe;
+	/* none now */
+};
 
-	/* [OUT] tuner I2C adapter returned by driver */
-	struct i2c_adapter *tuner_i2c;
+struct tc90522_out {
+	struct i2c_adapter demod_bus;
 };
 
 #endif /* TC90522_H */
-- 
2.1.3


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

* [PATCH 4/5] dvb: tc90522: remove a redundant state variable
  2014-12-05 10:49 [RFC/PATCH] dvb-core: add template code for i2c binding model tskd08
                   ` (3 preceding siblings ...)
  2014-12-05 10:55 ` [PATCH 3/5] dvb: tc90522: " tskd08
@ 2014-12-05 10:55 ` tskd08
  2014-12-05 10:55 ` [PATCH 5/5] dvb: pci/pt3: use dvb-core i2c binding model template tskd08
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: tskd08 @ 2014-12-05 10:55 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab, Akihiro Tsukada

From: Akihiro Tsukada <tskd08@gmail.com>

Signed-off-by: Akihiro Tsukada <tskd08@gmail.com>
---
 drivers/media/dvb-frontends/tc90522.c | 91 ++++++++++++++---------------------
 1 file changed, 36 insertions(+), 55 deletions(-)

diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c
index 0f4ddd7..a06d6f5 100644
--- a/drivers/media/dvb-frontends/tc90522.c
+++ b/drivers/media/dvb-frontends/tc90522.c
@@ -40,7 +40,6 @@
 
 struct tc90522_state {
 	struct tc90522_config cfg;
-	struct i2c_client *i2c_client;
 	struct i2c_adapter tuner_i2c;
 
 	bool lna;
@@ -52,18 +51,18 @@ struct reg_val {
 };
 
 static int
-reg_write(struct tc90522_state *state, const struct reg_val *regs, int num)
+reg_write(struct dvb_frontend *fe, const struct reg_val *regs, int num)
 {
 	int i, ret;
 	struct i2c_msg msg;
 
 	ret = 0;
-	msg.addr = state->i2c_client->addr;
+	msg.addr = fe->fe_cl->addr;
 	msg.flags = 0;
 	msg.len = 2;
 	for (i = 0; i < num; i++) {
 		msg.buf = (u8 *)&regs[i];
-		ret = i2c_transfer(state->i2c_client->adapter, &msg, 1);
+		ret = i2c_transfer(fe->fe_cl->adapter, &msg, 1);
 		if (ret == 0)
 			ret = -EIO;
 		if (ret < 0)
@@ -72,17 +71,17 @@ reg_write(struct tc90522_state *state, const struct reg_val *regs, int num)
 	return 0;
 }
 
-static int reg_read(struct tc90522_state *state, u8 reg, u8 *val, u8 len)
+static int reg_read(struct dvb_frontend *fe, u8 reg, u8 *val, u8 len)
 {
 	struct i2c_msg msgs[2] = {
 		{
-			.addr = state->i2c_client->addr,
+			.addr = fe->fe_cl->addr,
 			.flags = 0,
 			.buf = &reg,
 			.len = 1,
 		},
 		{
-			.addr = state->i2c_client->addr,
+			.addr = fe->fe_cl->addr,
 			.flags = I2C_M_RD,
 			.buf = val,
 			.len = len,
@@ -90,7 +89,7 @@ static int reg_read(struct tc90522_state *state, u8 reg, u8 *val, u8 len)
 	};
 	int ret;
 
-	ret = i2c_transfer(state->i2c_client->adapter, msgs, ARRAY_SIZE(msgs));
+	ret = i2c_transfer(fe->fe_cl->adapter, msgs, ARRAY_SIZE(msgs));
 	if (ret == ARRAY_SIZE(msgs))
 		ret = 0;
 	else if (ret >= 0)
@@ -108,7 +107,7 @@ static int tc90522s_set_tsid(struct dvb_frontend *fe)
 
 	set_tsid[0].val = (fe->dtv_property_cache.stream_id & 0xff00) >> 8;
 	set_tsid[1].val = fe->dtv_property_cache.stream_id & 0xff;
-	return reg_write(fe->demodulator_priv, set_tsid, ARRAY_SIZE(set_tsid));
+	return reg_write(fe, set_tsid, ARRAY_SIZE(set_tsid));
 }
 
 static int tc90522t_set_layers(struct dvb_frontend *fe)
@@ -120,19 +119,17 @@ static int tc90522t_set_layers(struct dvb_frontend *fe)
 	laysel = (laysel & 0x01) << 2 | (laysel & 0x02) | (laysel & 0x04) >> 2;
 	rv.reg = 0x71;
 	rv.val = laysel;
-	return reg_write(fe->demodulator_priv, &rv, 1);
+	return reg_write(fe, &rv, 1);
 }
 
 /* frontend ops */
 
 static int tc90522s_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
-	struct tc90522_state *state;
 	int ret;
 	u8 reg;
 
-	state = fe->demodulator_priv;
-	ret = reg_read(state, 0xc3, &reg, 1);
+	ret = reg_read(fe, 0xc3, &reg, 1);
 	if (ret < 0)
 		return ret;
 
@@ -147,7 +144,7 @@ static int tc90522s_read_status(struct dvb_frontend *fe, fe_status_t *status)
 
 	if (reg & 0x10)
 		return 0;
-	if (reg_read(state, 0xc5, &reg, 1) < 0 || !(reg & 0x03))
+	if (reg_read(fe, 0xc5, &reg, 1) < 0 || !(reg & 0x03))
 		return 0;
 	*status |= FE_HAS_LOCK;
 	return 0;
@@ -155,12 +152,10 @@ static int tc90522s_read_status(struct dvb_frontend *fe, fe_status_t *status)
 
 static int tc90522t_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
-	struct tc90522_state *state;
 	int ret;
 	u8 reg;
 
-	state = fe->demodulator_priv;
-	ret = reg_read(state, 0x96, &reg, 1);
+	ret = reg_read(fe, 0x96, &reg, 1);
 	if (ret < 0)
 		return ret;
 
@@ -171,7 +166,7 @@ static int tc90522t_read_status(struct dvb_frontend *fe, fe_status_t *status)
 		return 0;
 	}
 
-	ret = reg_read(state, 0x80, &reg, 1);
+	ret = reg_read(fe, 0x80, &reg, 1);
 	if (ret < 0)
 		return ret;
 
@@ -198,7 +193,6 @@ static const fe_code_rate_t fec_conv_sat[] = {
 
 static int tc90522s_get_frontend(struct dvb_frontend *fe)
 {
-	struct tc90522_state *state;
 	struct dtv_frontend_properties *c;
 	struct dtv_fe_stats *stats;
 	int ret, i;
@@ -206,12 +200,11 @@ static int tc90522s_get_frontend(struct dvb_frontend *fe)
 	u8 val[10];
 	u32 cndat;
 
-	state = fe->demodulator_priv;
 	c = &fe->dtv_property_cache;
 	c->delivery_system = SYS_ISDBS;
 
 	layers = 0;
-	ret = reg_read(state, 0xe6, val, 5);
+	ret = reg_read(fe, 0xe6, val, 5);
 	if (ret == 0) {
 		u8 v;
 
@@ -252,7 +245,7 @@ static int tc90522s_get_frontend(struct dvb_frontend *fe)
 	stats->len = 1;
 	stats->stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 	cndat = 0;
-	ret = reg_read(state, 0xbc, val, 2);
+	ret = reg_read(fe, 0xbc, val, 2);
 	if (ret == 0)
 		cndat = val[0] << 8 | val[1];
 	if (cndat >= 3000) {
@@ -283,7 +276,7 @@ static int tc90522s_get_frontend(struct dvb_frontend *fe)
 	stats = &c->post_bit_error;
 	memset(stats, 0, sizeof(*stats));
 	stats->len = layers;
-	ret = reg_read(state, 0xeb, val, 10);
+	ret = reg_read(fe, 0xeb, val, 10);
 	if (ret < 0)
 		for (i = 0; i < layers; i++)
 			stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE;
@@ -330,7 +323,6 @@ static const fe_modulation_t mod_conv[] = {
 
 static int tc90522t_get_frontend(struct dvb_frontend *fe)
 {
-	struct tc90522_state *state;
 	struct dtv_frontend_properties *c;
 	struct dtv_fe_stats *stats;
 	int ret, i;
@@ -338,19 +330,18 @@ static int tc90522t_get_frontend(struct dvb_frontend *fe)
 	u8 val[15], mode;
 	u32 cndat;
 
-	state = fe->demodulator_priv;
 	c = &fe->dtv_property_cache;
 	c->delivery_system = SYS_ISDBT;
 	c->bandwidth_hz = 6000000;
 	mode = 1;
-	ret = reg_read(state, 0xb0, val, 1);
+	ret = reg_read(fe, 0xb0, val, 1);
 	if (ret == 0) {
 		mode = (val[0] & 0xc0) >> 2;
 		c->transmission_mode = tm_conv[mode];
 		c->guard_interval = (val[0] & 0x30) >> 4;
 	}
 
-	ret = reg_read(state, 0xb2, val, 6);
+	ret = reg_read(fe, 0xb2, val, 6);
 	layers = 0;
 	if (ret == 0) {
 		u8 v;
@@ -411,7 +402,7 @@ static int tc90522t_get_frontend(struct dvb_frontend *fe)
 	stats->len = 1;
 	stats->stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 	cndat = 0;
-	ret = reg_read(state, 0x8b, val, 3);
+	ret = reg_read(fe, 0x8b, val, 3);
 	if (ret == 0)
 		cndat = val[0] << 16 | val[1] << 8 | val[2];
 	if (cndat != 0) {
@@ -444,7 +435,7 @@ static int tc90522t_get_frontend(struct dvb_frontend *fe)
 	stats = &c->post_bit_error;
 	memset(stats, 0, sizeof(*stats));
 	stats->len = layers;
-	ret = reg_read(state, 0x9d, val, 15);
+	ret = reg_read(fe, 0x9d, val, 15);
 	if (ret < 0)
 		for (i = 0; i < layers; i++)
 			stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE;
@@ -478,11 +469,8 @@ static const struct reg_val reset_ter = { 0x01, 0x40 };
 
 static int tc90522_set_frontend(struct dvb_frontend *fe)
 {
-	struct tc90522_state *state;
 	int ret;
 
-	state = fe->demodulator_priv;
-
 	if (fe->ops.tuner_ops.set_params)
 		ret = fe->ops.tuner_ops.set_params(fe);
 	else
@@ -494,12 +482,12 @@ static int tc90522_set_frontend(struct dvb_frontend *fe)
 		ret = tc90522s_set_tsid(fe);
 		if (ret < 0)
 			goto failed;
-		ret = reg_write(state, &reset_sat, 1);
+		ret = reg_write(fe, &reset_sat, 1);
 	} else {
 		ret = tc90522t_set_layers(fe);
 		if (ret < 0)
 			goto failed;
-		ret = reg_write(state, &reset_ter, 1);
+		ret = reg_write(fe, &reset_ter, 1);
 	}
 	if (ret < 0)
 		goto failed;
@@ -507,7 +495,7 @@ static int tc90522_set_frontend(struct dvb_frontend *fe)
 	return 0;
 
 failed:
-	dev_warn(&state->tuner_i2c.dev, "(%s) failed. [adap%d-fe%d]\n",
+	dev_warn(&fe->fe_cl->dev, "(%s) failed. [adap%d-fe%d]\n",
 			__func__, fe->dvb->num, fe->id);
 	return ret;
 }
@@ -540,11 +528,9 @@ static int tc90522_set_if_agc(struct dvb_frontend *fe, bool on)
 		{ 0x23, 0x4c },
 		{ 0x01, 0x40 },
 	};
-	struct tc90522_state *state;
 	struct reg_val *rv;
 	int num;
 
-	state = fe->demodulator_priv;
 	if (fe->ops.delsys[0] == SYS_ISDBS) {
 		agc_sat[0].val = on ? 0xff : 0x00;
 		agc_sat[1].val |= 0x80;
@@ -558,7 +544,7 @@ static int tc90522_set_if_agc(struct dvb_frontend *fe, bool on)
 		rv = agc_ter;
 		num = ARRAY_SIZE(agc_ter);
 	}
-	return reg_write(state, rv, num);
+	return reg_write(fe, rv, num);
 }
 
 static const struct reg_val sleep_sat = { 0x17, 0x01 };
@@ -566,14 +552,12 @@ static const struct reg_val sleep_ter = { 0x03, 0x90 };
 
 static int tc90522_sleep(struct dvb_frontend *fe)
 {
-	struct tc90522_state *state;
 	int ret;
 
-	state = fe->demodulator_priv;
 	if (fe->ops.delsys[0] == SYS_ISDBS)
-		ret = reg_write(state, &sleep_sat, 1);
+		ret = reg_write(fe, &sleep_sat, 1);
 	else {
-		ret = reg_write(state, &sleep_ter, 1);
+		ret = reg_write(fe, &sleep_ter, 1);
 		if (ret == 0 && fe->ops.set_lna &&
 		    fe->dtv_property_cache.lna == LNA_AUTO) {
 			fe->dtv_property_cache.lna = 0;
@@ -582,7 +566,7 @@ static int tc90522_sleep(struct dvb_frontend *fe)
 		}
 	}
 	if (ret < 0)
-		dev_warn(&state->tuner_i2c.dev,
+		dev_warn(&fe->fe_cl->dev,
 			"(%s) failed. [adap%d-fe%d]\n",
 			__func__, fe->dvb->num, fe->id);
 	return ret;
@@ -593,7 +577,6 @@ static const struct reg_val wakeup_ter = { 0x03, 0x80 };
 
 static int tc90522_init(struct dvb_frontend *fe)
 {
-	struct tc90522_state *state;
 	int ret;
 
 	/*
@@ -602,11 +585,10 @@ static int tc90522_init(struct dvb_frontend *fe)
 	 * just wake up the device here.
 	 */
 
-	state = fe->demodulator_priv;
 	if (fe->ops.delsys[0] == SYS_ISDBS)
-		ret = reg_write(state, &wakeup_sat, 1);
+		ret = reg_write(fe, &wakeup_sat, 1);
 	else {
-		ret = reg_write(state, &wakeup_ter, 1);
+		ret = reg_write(fe, &wakeup_ter, 1);
 		if (ret == 0 && fe->ops.set_lna &&
 		    fe->dtv_property_cache.lna == LNA_AUTO) {
 			fe->dtv_property_cache.lna = 1;
@@ -615,7 +597,7 @@ static int tc90522_init(struct dvb_frontend *fe)
 		}
 	}
 	if (ret < 0) {
-		dev_warn(&state->tuner_i2c.dev,
+		dev_warn(&fe->fe_cl->dev,
 			"(%s) failed. [adap%d-fe%d]\n",
 			__func__, fe->dvb->num, fe->id);
 		return ret;
@@ -635,7 +617,7 @@ static int tc90522_init(struct dvb_frontend *fe)
 static int
 tc90522_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 {
-	struct tc90522_state *state;
+	struct dvb_frontend *fe;
 	struct i2c_msg *new_msgs;
 	int i, j;
 	int ret, rd_num;
@@ -653,11 +635,11 @@ tc90522_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 	if (!new_msgs)
 		return -ENOMEM;
 
-	state = i2c_get_adapdata(adap);
+	fe = i2c_get_adapdata(adap);
 	p = wbuf;
 	bufend = wbuf + sizeof(wbuf);
 	for (i = 0, j = 0; i < num; i++, j++) {
-		new_msgs[j].addr = state->i2c_client->addr;
+		new_msgs[j].addr = fe->fe_cl->addr;
 		new_msgs[j].flags = msgs[i].flags;
 
 		if (msgs[i].flags & I2C_M_RD) {
@@ -670,7 +652,7 @@ tc90522_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 			new_msgs[j].len = 2;
 			p += 2;
 			j++;
-			new_msgs[j].addr = state->i2c_client->addr;
+			new_msgs[j].addr = fe->fe_cl->addr;
 			new_msgs[j].flags = msgs[i].flags;
 			new_msgs[j].buf = msgs[i].buf;
 			new_msgs[j].len = msgs[i].len;
@@ -690,7 +672,7 @@ tc90522_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 	if (i < num)
 		ret = -ENOMEM;
 	else
-		ret = i2c_transfer(state->i2c_client->adapter, new_msgs, j);
+		ret = i2c_transfer(fe->fe_cl->adapter, new_msgs, j);
 	if (ret >= 0 && ret < j)
 		ret = -EIO;
 	kfree(new_msgs);
@@ -770,7 +752,6 @@ static int tc90522_probe(struct i2c_client *client,
 
 	fe = i2c_get_clientdata(client);
 	state = fe->demodulator_priv;
-	state->i2c_client = client;
 
 	dcfg = client->dev.platform_data;
 	if (dcfg && dcfg->priv_cfg)
@@ -788,7 +769,7 @@ static int tc90522_probe(struct i2c_client *client,
 		goto err_mem;
 	if (dcfg && dcfg->out)
 		*dcfg->out = (struct tc90522_out *)adap;
-	i2c_set_adapdata(adap, state); /* used in tc90522_master_xfer() */
+	i2c_set_adapdata(adap, fe); /* used in tc90522_master_xfer() */
 
 	dev_info(&client->dev, "Toshiba TC90522 attached.\n");
 	return 0;
-- 
2.1.3


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

* [PATCH 5/5] dvb: pci/pt3: use dvb-core i2c binding model template
  2014-12-05 10:49 [RFC/PATCH] dvb-core: add template code for i2c binding model tskd08
                   ` (4 preceding siblings ...)
  2014-12-05 10:55 ` [PATCH 4/5] dvb: tc90522: remove a redundant state variable tskd08
@ 2014-12-05 10:55 ` tskd08
  2014-12-26 11:00 ` [RFC/PATCH] dvb-core: add template code for i2c binding model Akihiro TSUKADA
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: tskd08 @ 2014-12-05 10:55 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab, Akihiro Tsukada

From: Akihiro Tsukada <tskd08@gmail.com>

Signed-off-by: Akihiro Tsukada <tskd08@gmail.com>
---
 drivers/media/pci/pt3/pt3.c | 89 ++++++++++++++-------------------------------
 drivers/media/pci/pt3/pt3.h | 12 +++---
 2 files changed, 33 insertions(+), 68 deletions(-)

diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c
index 7a37e8f..3fe491b 100644
--- a/drivers/media/pci/pt3/pt3.c
+++ b/drivers/media/pci/pt3/pt3.c
@@ -26,6 +26,7 @@
 #include "dvbdev.h"
 #include "dvb_demux.h"
 #include "dvb_frontend.h"
+#include "dvb_i2c.h"
 
 #include "pt3.h"
 
@@ -103,12 +104,12 @@ pt3_demod_write(struct pt3_adapter *adap, const struct reg_val *data, int num)
 	int i, ret;
 
 	ret = 0;
-	msg.addr = adap->i2c_demod->addr;
+	msg.addr = adap->fe->fe_cl->addr;
 	msg.flags = 0;
 	msg.len = 2;
 	for (i = 0; i < num; i++) {
 		msg.buf = (u8 *)&data[i];
-		ret = i2c_transfer(adap->i2c_demod->adapter, &msg, 1);
+		ret = i2c_transfer(adap->fe->fe_cl->adapter, &msg, 1);
 		if (ret == 0)
 			ret = -EREMOTE;
 		if (ret < 0)
@@ -375,67 +376,38 @@ static int pt3_fe_init(struct pt3_board *pt3)
 
 static int pt3_attach_fe(struct pt3_board *pt3, int i)
 {
-	struct i2c_board_info info;
-	struct tc90522_config cfg;
-	struct i2c_client *cl;
+	struct dvb_frontend *fe;
+	struct tc90522_out *out;
+	struct i2c_client *tuner_cl;
 	struct dvb_adapter *dvb_adap;
 	int ret;
 
-	info = adap_conf[i].demod_info;
-	cfg = adap_conf[i].demod_cfg;
-	cfg.tuner_i2c = NULL;
-	info.platform_data = &cfg;
+	out = NULL;
+	fe = dvb_i2c_attach_fe(&pt3->i2c_adap, &adap_conf[i].demod_info,
+			       &adap_conf[i].demod_cfg, (void **)&out);
+	if (!fe)
+		return -ENODEV;
 
 	ret = -ENODEV;
-	request_module("tc90522");
-	cl = i2c_new_device(&pt3->i2c_adap, &info);
-	if (!cl || !cl->dev.driver)
-		return -ENODEV;
-	pt3->adaps[i]->i2c_demod = cl;
-	if (!try_module_get(cl->dev.driver->owner))
-		goto err_demod_i2c_unregister_device;
-
-	if (!strncmp(cl->name, TC90522_I2C_DEV_SAT, sizeof(cl->name))) {
-		struct qm1d1c0042_config tcfg;
-
-		tcfg = adap_conf[i].tuner_cfg.qm1d1c0042;
-		tcfg.fe = cfg.fe;
-		info = adap_conf[i].tuner_info;
-		info.platform_data = &tcfg;
-		request_module("qm1d1c0042");
-		cl = i2c_new_device(cfg.tuner_i2c, &info);
-	} else {
-		struct mxl301rf_config tcfg;
-
-		tcfg = adap_conf[i].tuner_cfg.mxl301rf;
-		tcfg.fe = cfg.fe;
-		info = adap_conf[i].tuner_info;
-		info.platform_data = &tcfg;
-		request_module("mxl301rf");
-		cl = i2c_new_device(cfg.tuner_i2c, &info);
-	}
-	if (!cl || !cl->dev.driver)
-		goto err_demod_module_put;
-	pt3->adaps[i]->i2c_tuner = cl;
-	if (!try_module_get(cl->dev.driver->owner))
-		goto err_tuner_i2c_unregister_device;
+	if (!out)
+		goto err;
+	tuner_cl = dvb_i2c_attach_tuner(&(out->demod_bus),
+					&adap_conf[i].tuner_info, fe,
+					&adap_conf[i].tuner_cfg, NULL);
+	if (!tuner_cl)
+		goto err;
 
 	dvb_adap = &pt3->adaps[one_adapter ? 0 : i]->dvb_adap;
-	ret = dvb_register_frontend(dvb_adap, cfg.fe);
+	ret = dvb_register_frontend(dvb_adap, fe);
 	if (ret < 0)
-		goto err_tuner_module_put;
-	pt3->adaps[i]->fe = cfg.fe;
+		goto err;
+	pt3->adaps[i]->fe = fe;
 	return 0;
 
-err_tuner_module_put:
-	module_put(pt3->adaps[i]->i2c_tuner->dev.driver->owner);
-err_tuner_i2c_unregister_device:
-	i2c_unregister_device(pt3->adaps[i]->i2c_tuner);
-err_demod_module_put:
-	module_put(pt3->adaps[i]->i2c_demod->dev.driver->owner);
-err_demod_i2c_unregister_device:
-	i2c_unregister_device(pt3->adaps[i]->i2c_demod);
-
+err:
+	/* tuner i2c_client is unregister'ed as well, */
+	/* because it is a (grand) child of the demod i2c_client device */
+	i2c_unregister_device(fe->fe_cl);
 	return ret;
 }
 
@@ -630,17 +602,10 @@ static void pt3_cleanup_adapter(struct pt3_board *pt3, int index)
 	dmx = &adap->demux.dmx;
 	dmx->close(dmx);
 	if (adap->fe) {
-		adap->fe->callback = NULL;
 		if (adap->fe->frontend_priv)
 			dvb_unregister_frontend(adap->fe);
-		if (adap->i2c_tuner) {
-			module_put(adap->i2c_tuner->dev.driver->owner);
-			i2c_unregister_device(adap->i2c_tuner);
-		}
-		if (adap->i2c_demod) {
-			module_put(adap->i2c_demod->dev.driver->owner);
-			i2c_unregister_device(adap->i2c_demod);
-		}
+		if (adap->fe->fe_cl)
+			i2c_unregister_device(adap->fe->fe_cl);
 	}
 	pt3_free_dmabuf(adap);
 	dvb_dmxdev_release(&adap->dmxdev);
diff --git a/drivers/media/pci/pt3/pt3.h b/drivers/media/pci/pt3/pt3.h
index 1b3f2ad..88c3d17 100644
--- a/drivers/media/pci/pt3/pt3.h
+++ b/drivers/media/pci/pt3/pt3.h
@@ -104,15 +104,17 @@ struct dma_data_buffer {
 /*
  * device things
  */
+union pt3_tuner_config {
+	struct qm1d1c0042_config qm1d1c0042;
+	struct mxl301rf_config   mxl301rf;
+};
+
 struct pt3_adap_config {
 	struct i2c_board_info demod_info;
 	struct tc90522_config demod_cfg;
 
 	struct i2c_board_info tuner_info;
-	union tuner_config {
-		struct qm1d1c0042_config qm1d1c0042;
-		struct mxl301rf_config   mxl301rf;
-	} tuner_cfg;
+	union pt3_tuner_config tuner_cfg;
 	u32 init_freq;
 };
 
@@ -123,8 +125,6 @@ struct pt3_adapter {
 	struct dvb_demux    demux;
 	struct dmxdev       dmxdev;
 	struct dvb_frontend *fe;
-	struct i2c_client   *i2c_demod;
-	struct i2c_client   *i2c_tuner;
 
 	/* data fetch thread */
 	struct task_struct *thread;
-- 
2.1.3


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

* Re: [RFC/PATCH] dvb-core: add template code for i2c binding model
  2014-12-05 10:49 [RFC/PATCH] dvb-core: add template code for i2c binding model tskd08
                   ` (5 preceding siblings ...)
  2014-12-05 10:55 ` [PATCH 5/5] dvb: pci/pt3: use dvb-core i2c binding model template tskd08
@ 2014-12-26 11:00 ` Akihiro TSUKADA
  2014-12-30 13:10 ` Mauro Carvalho Chehab
  2015-01-13 18:54 ` Antti Palosaari
  8 siblings, 0 replies; 15+ messages in thread
From: Akihiro TSUKADA @ 2014-12-26 11:00 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab

ping.
we don't need this kind of feature in the dvb-core?
--
akihiro

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

* Re: [RFC/PATCH] dvb-core: add template code for i2c binding model
  2014-12-05 10:49 [RFC/PATCH] dvb-core: add template code for i2c binding model tskd08
                   ` (6 preceding siblings ...)
  2014-12-26 11:00 ` [RFC/PATCH] dvb-core: add template code for i2c binding model Akihiro TSUKADA
@ 2014-12-30 13:10 ` Mauro Carvalho Chehab
  2014-12-30 20:01   ` Mauro Carvalho Chehab
  2015-01-05 11:59   ` Akihiro TSUKADA
  2015-01-13 18:54 ` Antti Palosaari
  8 siblings, 2 replies; 15+ messages in thread
From: Mauro Carvalho Chehab @ 2014-12-30 13:10 UTC (permalink / raw)
  To: tskd08; +Cc: linux-media

Em Fri, 05 Dec 2014 19:49:33 +0900
tskd08@gmail.com escreveu:

> From: Akihiro Tsukada <tskd08@gmail.com>
> 
> Define a standard interface for demod/tuner i2c driver modules.
> A module client calls dvb_i2c_attach_{fe,tuner}(),
> and a module driver defines struct dvb_i2c_module_param and
> calls DEFINE_DVB_I2C_MODULE() macro.
> 
> This template provides implicit module requests and ref-counting,
> alloc/free's private data structures,
> fixes the usage of clientdata of i2c devices,
> and defines the platformdata structures for passing around
> device specific config/output parameters between drivers and clients.
> These kinds of code are common to (almost) all dvb i2c drivers/client,
> but they were scattered over adapter modules and demod/tuner modules.

The idea behind this patch is good. I didn't have time yet to test it on a
device that I have currently access.

I have a few comments below, mostly regards with naming convention.

By seeing the patches you converted a few drivers to use this, I'm a little
bit concern about the conversion. We need something that won't be hard to
convert to the new model without requiring to re-test everything.

Anyway, my plan is to take a deeper look on it next week and convert one
or two drivers to use the new I2C binding approach you're proposing.
> 
> Signed-off-by: Akihiro Tsukada <tskd08@gmail.com>
> ---
>  drivers/media/dvb-core/Makefile       |   4 +
>  drivers/media/dvb-core/dvb_frontend.h |   1 +
>  drivers/media/dvb-core/dvb_i2c.c      | 219 ++++++++++++++++++++++++++++++++++
>  drivers/media/dvb-core/dvb_i2c.h      | 110 +++++++++++++++++
>  4 files changed, 334 insertions(+)
>  create mode 100644 drivers/media/dvb-core/dvb_i2c.c
>  create mode 100644 drivers/media/dvb-core/dvb_i2c.h
> 
> diff --git a/drivers/media/dvb-core/Makefile b/drivers/media/dvb-core/Makefile
> index 8f22bcd..271648d 100644
> --- a/drivers/media/dvb-core/Makefile
> +++ b/drivers/media/dvb-core/Makefile
> @@ -8,4 +8,8 @@ dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o 	\
>  		 dvb_ca_en50221.o dvb_frontend.o 		\
>  		 $(dvb-net-y) dvb_ringbuffer.o dvb_math.o
>  
> +ifneq ($(CONFIG_I2C)$(CONFIG_I2C_MODULE),)
> +dvb-core-objs += dvb_i2c.o
> +endif
> +
>  obj-$(CONFIG_DVB_CORE) += dvb-core.o
> diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h
> index 816269e..41aae1b 100644
> --- a/drivers/media/dvb-core/dvb_frontend.h
> +++ b/drivers/media/dvb-core/dvb_frontend.h
> @@ -415,6 +415,7 @@ struct dtv_frontend_properties {
>  struct dvb_frontend {
>  	struct dvb_frontend_ops ops;
>  	struct dvb_adapter *dvb;
> +	struct i2c_client *fe_cl;

fe_cl doesn't seem to be a good name for something that should be
accessed by all drivers that use it. fe_i2c_client is likely a
better name for it.

>  	void *demodulator_priv;
>  	void *tuner_priv;
>  	void *frontend_priv;
> diff --git a/drivers/media/dvb-core/dvb_i2c.c b/drivers/media/dvb-core/dvb_i2c.c
> new file mode 100644
> index 0000000..4ea4e5e
> --- /dev/null
> +++ b/drivers/media/dvb-core/dvb_i2c.c
> @@ -0,0 +1,219 @@
> +/*
> + * dvb_i2c.c
> + *
> + * Copyright 2014 Akihiro Tsukada <tskd08 AT gmail DOT com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#include "dvb_i2c.h"
> +
> +static struct i2c_client *
> +dvb_i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info *info,
> +		   const unsigned short *probe_addrs)
> +{
> +	struct i2c_client *cl;
> +
> +	request_module(I2C_MODULE_PREFIX "%s", info->type);
> +	/* Create the i2c client */
> +	if (info->addr == 0 && probe_addrs)
> +		cl = i2c_new_probed_device(adap, info, probe_addrs, NULL);
> +	else
> +		cl = i2c_new_device(adap, info);
> +	if (!cl || !cl->dev.driver)
> +		return NULL;
> +	return cl;

The best would be to also register the device with the media controller,
if CONFIG_MEDIA_CONTROLLER is defined, just like v4l2_i2c_subdev_init()
does.

I would also try to use similar names for the function calls to the ones
that the v4l subsystem uses for subdevices.

> +}
> +
> +struct dvb_frontend *
> +dvb_i2c_attach_fe(struct i2c_adapter *adap, const struct i2c_board_info *info,
> +		  const void *cfg, void **out)
> +{
> +	struct i2c_client *cl;
> +	struct i2c_board_info bi;

Better to call this as "tmp_info", as this seems to be just a temp var.

> +	struct dvb_i2c_dev_config dcfg;

I would, instead, call this as "cfg", and rename the parameter as
cfg_template.

> +
> +	dcfg.priv_cfg = cfg;
> +	dcfg.out = out;
> +	bi = *info;
> +	bi.platform_data = &dcfg;
> +
> +	cl = dvb_i2c_new_device(adap, &bi, NULL);
> +	if (!cl)
> +		return NULL;
> +	return i2c_get_clientdata(cl);
> +}
> +EXPORT_SYMBOL(dvb_i2c_attach_fe);
> +
> +struct i2c_client *
> +dvb_i2c_attach_tuner(struct i2c_adapter *adap,
> +		     const struct i2c_board_info *info,
> +		     struct dvb_frontend *fe,
> +		     const void *cfg, void **out)
> +{
> +	struct i2c_board_info bi;
> +	struct dvb_i2c_tuner_config tcfg;

Same as above with regards to name: please rename:
	- bi -> tmp_info
	- tcfg -> cfg

> +
> +	tcfg.fe = fe;
> +	tcfg.devcfg.priv_cfg = cfg;
> +	tcfg.devcfg.out = out;
> +	bi = *info;
> +	bi.platform_data = &tcfg;
> +
> +	return dvb_i2c_new_device(adap, &bi, NULL);
> +}
> +EXPORT_SYMBOL(dvb_i2c_attach_tuner);
> +
> +
> +static int
> +probe_tuner(struct i2c_client *client, const struct i2c_device_id *id,
> +	    const struct dvb_i2c_module_param *param,
> +	    struct module *this_module)
> +{
> +	struct dvb_frontend *fe;
> +	struct dvb_i2c_tuner_config *tcfg;

Same here with regards to naming convention.

> +	int ret;
> +
> +	if (!try_module_get(this_module))
> +		return -ENODEV;
> +
> +	tcfg = client->dev.platform_data;
> +	fe = tcfg->fe;
> +	i2c_set_clientdata(client, fe);
> +
> +	if (param->priv_size > 0) {
> +		fe->tuner_priv = kzalloc(param->priv_size, GFP_KERNEL);
> +		if (!fe->tuner_priv) {
> +			ret = -ENOMEM;
> +			goto err_mem;
> +		}
> +	}
> +
> +	if (param->ops.tuner_ops)
> +		memcpy(&fe->ops.tuner_ops, param->ops.tuner_ops,
> +			sizeof(fe->ops.tuner_ops));
> +
> +	ret = 0;
> +	if (param->priv_probe)
> +		ret = param->priv_probe(client, id);
> +	if (ret != 0) {
> +		dev_info(&client->dev, "driver private probe failed.\n");
> +		goto err_priv;
> +	}
> +	return 0;
> +
> +err_priv:
> +	kfree(fe->tuner_priv);
> +err_mem:
> +	fe->tuner_priv = NULL;
> +	module_put(this_module);
> +	return ret;
> +}
> +
> +static int remove_tuner(struct i2c_client *client,
> +			const struct dvb_i2c_module_param *param,
> +			struct module *this_module)
> +{
> +	struct dvb_frontend *fe;
> +
> +	if (param->priv_remove)
> +		param->priv_remove(client);
> +	fe = i2c_get_clientdata(client);
> +	kfree(fe->tuner_priv);
> +	fe->tuner_priv = NULL;
> +	module_put(this_module);
> +	return 0;
> +}
> +
> +
> +static int probe_fe(struct i2c_client *client, const struct i2c_device_id *id,
> +		    const struct dvb_i2c_module_param *param,
> +		    struct module *this_module)
> +{
> +	struct dvb_frontend *fe;
> +	int ret;
> +
> +	if (!try_module_get(this_module))
> +		return -ENODEV;
> +
> +	fe = kzalloc(sizeof(*fe), GFP_KERNEL);
> +	if (!fe) {
> +		ret = -ENOMEM;
> +		goto err_fe_kfree;
> +	}
> +	i2c_set_clientdata(client, fe);
> +	fe->fe_cl = client;
> +
> +	if (param->priv_size > 0) {
> +		fe->demodulator_priv = kzalloc(param->priv_size, GFP_KERNEL);
> +		if (!fe->demodulator_priv) {
> +			ret = -ENOMEM;
> +			goto err_fe_kfree;
> +		}
> +	}
> +
> +	if (param->ops.fe_ops)
> +		memcpy(&fe->ops, param->ops.fe_ops, sizeof(fe->ops));
> +
> +	ret = 0;
> +	if (param->priv_probe)
> +		ret = param->priv_probe(client, id);
> +	if (ret != 0) {
> +		dev_info(&client->dev, "driver private probe failed.\n");
> +		goto err_priv_kfree;
> +	}
> +	return 0;
> +
> +err_priv_kfree:
> +	kfree(fe->demodulator_priv);
> +err_fe_kfree:
> +	kfree(fe);
> +	module_put(this_module);
> +	return ret;
> +}
> +
> +static int remove_fe(struct i2c_client *client,
> +		     const struct dvb_i2c_module_param *param,
> +		     struct module *this_module)
> +{
> +	struct dvb_frontend *fe;
> +
> +	if (param->priv_remove)
> +		param->priv_remove(client);
> +	fe = i2c_get_clientdata(client);
> +	kfree(fe->demodulator_priv);
> +	kfree(fe);
> +	module_put(this_module);
> +	return 0;
> +}
> +
> +
> +int dvb_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id,
> +		  const struct dvb_i2c_module_param *param,
> +		  struct module *this_module)
> +{
> +	return param->is_tuner ? probe_tuner(client, id, param, this_module) :
> +				 probe_fe(client, id, param, this_module);
> +}
> +EXPORT_SYMBOL(dvb_i2c_probe);
> +
> +int dvb_i2c_remove(struct i2c_client *client,
> +		   const struct dvb_i2c_module_param *param,
> +		   struct module *this_module)
> +{
> +	return param->is_tuner ? remove_tuner(client, param, this_module) :
> +				 remove_fe(client, param, this_module);
> +}
> +EXPORT_SYMBOL(dvb_i2c_remove);
> diff --git a/drivers/media/dvb-core/dvb_i2c.h b/drivers/media/dvb-core/dvb_i2c.h
> new file mode 100644
> index 0000000..2bf409d
> --- /dev/null
> +++ b/drivers/media/dvb-core/dvb_i2c.h
> @@ -0,0 +1,110 @@
> +/*
> + * dvb_i2c.h
> + *
> + * Copyright 2014 Akihiro Tsukada <tskd08 AT gmail DOT com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +/* template code for i2c driver modules */
> +
> +#ifndef _DVB_I2C_H_
> +#define _DVB_I2C_H_
> +
> +#include <linux/i2c.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +
> +#include "dvb_frontend.h"
> +
> +/* interface for module clients */
> +
> +struct dvb_frontend *dvb_i2c_attach_fe(struct i2c_adapter *adap,
> +				       const struct i2c_board_info *info,
> +				       const void *cfg, void **out);
> +
> +struct i2c_client *dvb_i2c_attach_tuner(struct i2c_adapter *adap,
> +					const struct i2c_board_info *info,
> +					struct dvb_frontend *fe,
> +					const void *cfg, void **out);
> +
> +/* interface for module drivers */
> +
> +/* data structures that are set to i2c_client.dev.platform_data */
> +
> +struct dvb_i2c_dev_config {
> +	const void *priv_cfg;
> +	/* @out [OUT] pointer to per-device data returned from driver */
> +	void **out;
> +};
> +
> +struct dvb_i2c_tuner_config {
> +	struct dvb_frontend *fe;
> +	struct dvb_i2c_dev_config devcfg;
> +};
> +
> +typedef int (*dvb_i2c_probe_func)(struct i2c_client *client,
> +				  const struct i2c_device_id *id);
> +typedef int (*dvb_i2c_remove_func)(struct i2c_client *client);
> +
> +struct dvb_i2c_module_param {
> +	union {
> +		const struct dvb_frontend_ops *fe_ops;
> +		const struct dvb_tuner_ops *tuner_ops;
> +	} ops;
> +	/* driver private probe/remove functions */
> +	dvb_i2c_probe_func  priv_probe;
> +	dvb_i2c_remove_func priv_remove;
> +
> +	u32 priv_size; /* sizeof(device private data) */
> +	bool is_tuner;
> +};
> +
> +
> +int dvb_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id,
> +		  const struct dvb_i2c_module_param *param,
> +		  struct module *this_module);
> +
> +int dvb_i2c_remove(struct i2c_client *client,
> +		   const struct dvb_i2c_module_param *param,
> +		   struct module *this_module);
> +
> +
> +#define DEFINE_DVB_I2C_MODULE(dname, idtab, param) \
> +static int _##dname##_probe(struct i2c_client *client,\
> +				const struct i2c_device_id *id)\
> +{\
> +	return dvb_i2c_probe(client, id, &(param), THIS_MODULE);\
> +} \
> +\
> +static int _##dname##_remove(struct i2c_client *client)\
> +{\
> +	return dvb_i2c_remove(client, &(param), THIS_MODULE);\
> +} \
> +\
> +MODULE_DEVICE_TABLE(i2c, idtab);\
> +\
> +static struct i2c_driver dname##_driver = {\
> +	.driver = {\
> +		.name = #dname,\
> +	},\
> +	.probe    = _##dname##_probe,\
> +	.remove   = _##dname##_remove,\
> +	.id_table = idtab,\
> +};\
> +\
> +module_i2c_driver(dname##_driver)
> +
> +#endif /* _DVB_I2C_H */


-- 

Cheers,
Mauro

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

* Re: [RFC/PATCH] dvb-core: add template code for i2c binding model
  2014-12-30 13:10 ` Mauro Carvalho Chehab
@ 2014-12-30 20:01   ` Mauro Carvalho Chehab
  2015-01-05 12:14     ` Akihiro TSUKADA
  2015-01-05 11:59   ` Akihiro TSUKADA
  1 sibling, 1 reply; 15+ messages in thread
From: Mauro Carvalho Chehab @ 2014-12-30 20:01 UTC (permalink / raw)
  To: tskd08; +Cc: linux-media

Em Tue, 30 Dec 2014 11:10:51 -0200
Mauro Carvalho Chehab <mchehab@osg.samsung.com> escreveu:

> Em Fri, 05 Dec 2014 19:49:33 +0900
> tskd08@gmail.com escreveu:
> 
> > From: Akihiro Tsukada <tskd08@gmail.com>
> > 
> > Define a standard interface for demod/tuner i2c driver modules.
> > A module client calls dvb_i2c_attach_{fe,tuner}(),
> > and a module driver defines struct dvb_i2c_module_param and
> > calls DEFINE_DVB_I2C_MODULE() macro.
> > 
> > This template provides implicit module requests and ref-counting,
> > alloc/free's private data structures,
> > fixes the usage of clientdata of i2c devices,
> > and defines the platformdata structures for passing around
> > device specific config/output parameters between drivers and clients.
> > These kinds of code are common to (almost) all dvb i2c drivers/client,
> > but they were scattered over adapter modules and demod/tuner modules.
> 
> The idea behind this patch is good. I didn't have time yet to test it on a
> device that I have currently access.
> 
> I have a few comments below, mostly regards with naming convention.
> 
> By seeing the patches you converted a few drivers to use this, I'm a little
> bit concern about the conversion. We need something that won't be hard to
> convert to the new model without requiring to re-test everything.
> 
> Anyway, my plan is to take a deeper look on it next week and convert one
> or two drivers to use the new I2C binding approach you're proposing.

Ok, did some tests and it worked. The issues I commented on my last email
may be fixed latter. I'm working on adding media controller support for
it.

The only thing I noticed is that it is causing some warnings at
dmesg about trying to create already created sysfs nodes, when the
driver is removed/reinserted.

Probably, the remove callback is called too soon or too late.

I'll do more tests latter (either this or the next week).

I used the enclosed patch on my tests.

Regards,
Mauro

[PATCH] mb86a20s: convert it to I2C binding model

Instead of using I2C raw API, use the standard I2C binding API,
with the DVB core support for it.

Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>

diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c
index 8f54c39..8dd608b 100644
--- a/drivers/media/dvb-frontends/mb86a20s.c
+++ b/drivers/media/dvb-frontends/mb86a20s.c
@@ -18,6 +18,7 @@
 #include <asm/div64.h>
 
 #include "dvb_frontend.h"
+#include "dvb_i2c.h"
 #include "mb86a20s.h"
 
 #define NUM_LAYERS 3
@@ -35,12 +36,10 @@ static u8 mb86a20s_subchannel[] = {
 };
 
 struct mb86a20s_state {
-	struct i2c_adapter *i2c;
+	struct i2c_client *i2c;
 	const struct mb86a20s_config *config;
 	u32 last_frequency;
 
-	struct dvb_frontend frontend;
-
 	u32 if_freq;
 	enum mb86a20s_bandwidth bw;
 	bool inversion;
@@ -234,7 +233,7 @@ static int mb86a20s_i2c_writereg(struct mb86a20s_state *state,
 	};
 	int rc;
 
-	rc = i2c_transfer(state->i2c, &msg, 1);
+	rc = i2c_transfer(state->i2c->adapter, &msg, 1);
 	if (rc != 1) {
 		dev_err(&state->i2c->dev,
 			"%s: writereg error (rc == %i, reg == 0x%02x, data == 0x%02x)\n",
@@ -269,7 +268,7 @@ static int mb86a20s_i2c_readreg(struct mb86a20s_state *state,
 		{ .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
 	};
 
-	rc = i2c_transfer(state->i2c, msg, 2);
+	rc = i2c_transfer(state->i2c->adapter, msg, 2);
 
 	if (rc != 2) {
 		dev_err(&state->i2c->dev, "%s: reg=0x%x (error=%d)\n",
@@ -281,11 +280,11 @@ static int mb86a20s_i2c_readreg(struct mb86a20s_state *state,
 }
 
 #define mb86a20s_readreg(state, reg) \
-	mb86a20s_i2c_readreg(state, state->config->demod_address, reg)
+	mb86a20s_i2c_readreg(state, state->i2c->addr, reg)
 #define mb86a20s_writereg(state, reg, val) \
-	mb86a20s_i2c_writereg(state, state->config->demod_address, reg, val)
+	mb86a20s_i2c_writereg(state, state->i2c->addr, reg, val)
 #define mb86a20s_writeregdata(state, regdata) \
-	mb86a20s_i2c_writeregdata(state, state->config->demod_address, \
+	mb86a20s_i2c_writeregdata(state, state->i2c->addr, \
 	regdata, ARRAY_SIZE(regdata))
 
 /*
@@ -2058,41 +2057,34 @@ static int mb86a20s_tune(struct dvb_frontend *fe,
 	return rc;
 }
 
-static void mb86a20s_release(struct dvb_frontend *fe)
+static int mb86a20s_remove(struct i2c_client *i2c)
 {
-	struct mb86a20s_state *state = fe->demodulator_priv;
-
-	dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+	dev_dbg(&i2c->dev, "%s called.\n", __func__);
 
-	kfree(state);
+	return 0;
 }
 
 static struct dvb_frontend_ops mb86a20s_ops;
 
-struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
-				    struct i2c_adapter *i2c)
+static int mb86a20s_probe(struct i2c_client *i2c,
+			  const struct i2c_device_id *id)
 {
+	struct dvb_frontend *fe;
 	struct mb86a20s_state *state;
 	u8	rev;
 
 	dev_dbg(&i2c->dev, "%s called.\n", __func__);
 
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL);
-	if (state == NULL) {
-		dev_err(&i2c->dev,
-			"%s: unable to allocate memory for state\n", __func__);
-		goto error;
-	}
+	fe = i2c_get_clientdata(i2c);
+	state = fe->demodulator_priv;
 
 	/* setup the state */
-	state->config = config;
+	memcpy(&state->config, i2c->dev.platform_data, sizeof(state->config));
 	state->i2c = i2c;
 
 	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &mb86a20s_ops,
+	memcpy(&fe->ops, &mb86a20s_ops,
 		sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
 
 	/* Check if it is a mb86a20s frontend */
 	rev = mb86a20s_readreg(state, 0);
@@ -2104,16 +2096,11 @@ struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
 		dev_dbg(&i2c->dev,
 			"Frontend revision %d is unknown - aborting.\n",
 		       rev);
-		goto error;
+		return -ENODEV;
 	}
 
-	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
+	return 0;
 }
-EXPORT_SYMBOL(mb86a20s_attach);
 
 static struct dvb_frontend_ops mb86a20s_ops = {
 	.delsys = { SYS_ISDBT },
@@ -2132,8 +2119,6 @@ static struct dvb_frontend_ops mb86a20s_ops = {
 		.frequency_stepsize = 62500,
 	},
 
-	.release = mb86a20s_release,
-
 	.init = mb86a20s_initfe,
 	.set_frontend = mb86a20s_set_frontend,
 	.get_frontend = mb86a20s_get_frontend_dummy,
@@ -2142,6 +2127,21 @@ static struct dvb_frontend_ops mb86a20s_ops = {
 	.tune = mb86a20s_tune,
 };
 
+static const struct i2c_device_id mb86a20s_id[] = {
+	{ "mb86a20s", 0 },
+	{}
+};
+
+static const struct dvb_i2c_module_param mb86a20s_param = {
+	.ops.fe_ops = NULL,
+	.priv_probe = mb86a20s_probe,
+	.priv_remove = mb86a20s_remove,
+	.priv_size = sizeof(struct mb86a20s_state),
+	.is_tuner = false,
+};
+
+DEFINE_DVB_I2C_MODULE(mb86a20s, mb86a20s_id, mb86a20s_param);
+
 MODULE_DESCRIPTION("DVB Frontend module for Fujitsu mb86A20s hardware");
 MODULE_AUTHOR("Mauro Carvalho Chehab");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/mb86a20s.h b/drivers/media/dvb-frontends/mb86a20s.h
index cbeb941..18743c3 100644
--- a/drivers/media/dvb-frontends/mb86a20s.h
+++ b/drivers/media/dvb-frontends/mb86a20s.h
@@ -34,23 +34,4 @@ struct mb86a20s_config {
 	bool	is_serial;
 };
 
-#if IS_ENABLED(CONFIG_DVB_MB86A20S)
-extern struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
-					   struct i2c_adapter *i2c);
-extern struct i2c_adapter *mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *);
-#else
-static inline struct dvb_frontend *mb86a20s_attach(
-	const struct mb86a20s_config *config, struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-static struct i2c_adapter *
-	mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
 #endif /* MB86A20S */
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index c47d182..fc23b7a 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -26,6 +26,7 @@
 #include "cx23885.h"
 #include <media/v4l2-common.h>
 
+#include "dvb_i2c.h"
 #include "dvb_ca_en50221.h"
 #include "s5h1409.h"
 #include "s5h1411.h"
@@ -542,7 +543,10 @@ static struct xc5000_config mygica_x8506_xc5000_config = {
 };
 
 static struct mb86a20s_config mygica_x8507_mb86a20s_config = {
-	.demod_address = 0x10,
+};
+
+static const struct i2c_board_info mb86a20s_board_info = {
+	I2C_BOARD_INFO("mb86a20s", 0x10)
 };
 
 static struct xc5000_config mygica_x8507_xc5000_config = {
@@ -1503,9 +1507,10 @@ static int dvb_register(struct cx23885_tsport *port)
 	case CX23885_BOARD_MYGICA_X8507:
 		i2c_bus = &dev->i2c_bus[0];
 		i2c_bus2 = &dev->i2c_bus[1];
-		fe0->dvb.frontend = dvb_attach(mb86a20s_attach,
-			&mygica_x8507_mb86a20s_config,
-			&i2c_bus->i2c_adap);
+		fe0->dvb.frontend = dvb_i2c_attach_fe(&i2c_bus->i2c_adap,
+						       &mb86a20s_board_info,
+						       &mygica_x8507_mb86a20s_config,
+						       NULL);
 		if (fe0->dvb.frontend == NULL)
 			break;
 
diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c
index 73ffbab..74b5ce0 100644
--- a/drivers/media/pci/saa7134/saa7134-dvb.c
+++ b/drivers/media/pci/saa7134/saa7134-dvb.c
@@ -34,6 +34,7 @@
 #include "dvb-pll.h"
 #include <dvb_frontend.h>
 
+#include "dvb_i2c.h"
 #include "mt352.h"
 #include "mt352_priv.h" /* FIXME */
 #include "tda1004x.h"
@@ -245,7 +246,10 @@ static struct tda18271_config kworld_tda18271_config = {
 };
 
 static const struct mb86a20s_config kworld_mb86a20s_config = {
-	.demod_address = 0x10,
+};
+
+static const struct i2c_board_info mb86a20s_board_info = {
+	I2C_BOARD_INFO("mb86a20s", 0x10)
 };
 
 static int kworld_sbtvd_gate_ctrl(struct dvb_frontend* fe, int enable)
@@ -1807,9 +1811,10 @@ static int dvb_init(struct saa7134_dev *dev)
 		/* Switch to digital mode */
 		saa7134_tuner_callback(dev, 0,
 				       TDA18271_CALLBACK_CMD_AGC_ENABLE, 1);
-		fe0->dvb.frontend = dvb_attach(mb86a20s_attach,
-					       &kworld_mb86a20s_config,
-					       &dev->i2c_adap);
+		fe0->dvb.frontend = dvb_i2c_attach_fe(&dev->i2c_adap,
+						       &mb86a20s_board_info,
+						       &kworld_mb86a20s_config,
+						       NULL);
 		if (fe0->dvb.frontend != NULL) {
 			dvb_attach(tda829x_attach, fe0->dvb.frontend,
 				   &dev->i2c_adap, 0x4b,
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index dd600b9..27803a8 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -26,6 +26,7 @@
 #include <media/v4l2-common.h>
 #include <media/videobuf-vmalloc.h>
 
+#include "dvb_i2c.h"
 #include "xc5000.h"
 #include "s5h1432.h"
 #include "tda18271.h"
@@ -138,10 +139,13 @@ static struct tda18271_config hcw_tda18271_config = {
 };
 
 static const struct mb86a20s_config pv_mb86a20s_config = {
-	.demod_address = 0x10,
 	.is_serial = true,
 };
 
+static const struct i2c_board_info mb86a20s_board_info = {
+	I2C_BOARD_INFO("mb86a20s", 0x10)
+};
+
 static struct tda18271_config pv_tda18271_config = {
 	.std_map = &mb86a20s_tda18271_config,
 	.gate    = TDA18271_GATE_DIGITAL,
@@ -815,10 +819,10 @@ 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,
-						&pv_mb86a20s_config,
-						demod_i2c);
-
+		dev->dvb->frontend = dvb_i2c_attach_fe(demod_i2c,
+						       &mb86a20s_board_info,
+						       &pv_mb86a20s_config,
+						       NULL);
 		if (dev->dvb->frontend == NULL) {
 			dev_err(dev->dev,
 				"Failed to attach mb86a20s demod\n");
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index aee70d4..6fa4eee 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -34,6 +34,7 @@
 #include "tuner-simple.h"
 #include <linux/gpio.h>
 
+#include "dvb_i2c.h"
 #include "lgdt330x.h"
 #include "lgdt3305.h"
 #include "zl10353.h"
@@ -833,10 +834,13 @@ static struct qt1010_config em28xx_qt1010_config = {
 };
 
 static const struct mb86a20s_config c3tech_duo_mb86a20s_config = {
-	.demod_address = 0x10,
 	.is_serial = true,
 };
 
+static const struct i2c_board_info mb86a20s_board_info = {
+	I2C_BOARD_INFO("mb86a20s", 0x10)
+};
+
 static struct tda18271_std_map mb86a20s_tda18271_config = {
 	.dvbt_6   = { .if_freq = 4000, .agc_mode = 3, .std = 4,
 		      .if_lvl = 1, .rfagc_top = 0x37, },
@@ -1323,9 +1327,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
 
 		break;
 	case EM2884_BOARD_C3TECH_DIGITAL_DUO:
-		dvb->fe[0] = dvb_attach(mb86a20s_attach,
-					   &c3tech_duo_mb86a20s_config,
-					   &dev->i2c_adap[dev->def_i2c_bus]);
+		dvb->fe[0] = dvb_i2c_attach_fe(&dev->i2c_adap[dev->def_i2c_bus],
+					       &mb86a20s_board_info,
+					       &c3tech_duo_mb86a20s_config,
+					       NULL);
 		if (dvb->fe[0] != NULL)
 			dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
 				   &dev->i2c_adap[dev->def_i2c_bus],


-- 

Cheers,
Mauro

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

* Re: [RFC/PATCH] dvb-core: add template code for i2c binding model
  2014-12-30 13:10 ` Mauro Carvalho Chehab
  2014-12-30 20:01   ` Mauro Carvalho Chehab
@ 2015-01-05 11:59   ` Akihiro TSUKADA
  1 sibling, 0 replies; 15+ messages in thread
From: Akihiro TSUKADA @ 2015-01-05 11:59 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media, tskd08

Hi, thank you for the comment.
I understood the naming conventions you mentioned,
and I'll update them in the next version.

>> diff --git a/drivers/media/dvb-core/dvb_i2c.c b/drivers/media/dvb-core/dvb_i2c.c
>> new file mode 100644
>> index 0000000..4ea4e5e
>> --- /dev/null
>> +++ b/drivers/media/dvb-core/dvb_i2c.c
....
>> +static struct i2c_client *
>> +dvb_i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info *info,
>> +		   const unsigned short *probe_addrs)
>> +{
>> +	struct i2c_client *cl;
>> +
>> +	request_module(I2C_MODULE_PREFIX "%s", info->type);
>> +	/* Create the i2c client */
>> +	if (info->addr == 0 && probe_addrs)
>> +		cl = i2c_new_probed_device(adap, info, probe_addrs, NULL);
>> +	else
>> +		cl = i2c_new_device(adap, info);
>> +	if (!cl || !cl->dev.driver)
>> +		return NULL;
>> +	return cl;
> 
> The best would be to also register the device with the media controller,
> if CONFIG_MEDIA_CONTROLLER is defined, just like v4l2_i2c_subdev_init()
> does.

I'll comment to your patch on this.

> I would also try to use similar names for the function calls to the ones
> that the v4l subsystem uses for subdevices.

So the name should be dvb_i2c_new_subdev()?
I am a bit worried that it would be rather confusing because
this func is different from v4l2_i2c_new_subdev() in that
it does not return "struct dvb_frontend *", requires info.platform_data parameter,
and is a static/internal function.

One more thing that I'm wondering about is whether we should add fe->demod_i2c_bus
to support tuner devices on a (dedicated) i2c bus hosted on a demod device.
I guess that this structure is pretty common (to reduce noise),
and this removes i2c_adapter from "out" structure and
confines the usage of "out" structure to just device-specific ones.

--
akihiro 


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

* Re: [RFC/PATCH] dvb-core: add template code for i2c binding model
  2014-12-30 20:01   ` Mauro Carvalho Chehab
@ 2015-01-05 12:14     ` Akihiro TSUKADA
  2015-01-05 12:24       ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 15+ messages in thread
From: Akihiro TSUKADA @ 2015-01-05 12:14 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media, tskd08

> The only thing I noticed is that it is causing some warnings at
> dmesg about trying to create already created sysfs nodes, when the
> driver is removed/reinserted.
> 
> Probably, the remove callback is called too soon or too late.

I don't have any warnings in syslog when reinserting earth-pt3 + tc90522,
but I'll look into it.

> -struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
> -				    struct i2c_adapter *i2c)
> +static int mb86a20s_probe(struct i2c_client *i2c,
> +			  const struct i2c_device_id *id)
>  {
> +	struct dvb_frontend *fe;
>  	struct mb86a20s_state *state;
>  	u8	rev;
>  
>  	dev_dbg(&i2c->dev, "%s called.\n", __func__);
>  
> -	/* allocate memory for the internal state */
> -	state = kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL);
> -	if (state == NULL) {
> -		dev_err(&i2c->dev,
> -			"%s: unable to allocate memory for state\n", __func__);
> -		goto error;
> -	}
> +	fe = i2c_get_clientdata(i2c);
> +	state = fe->demodulator_priv;
>  
>  	/* setup the state */
> -	state->config = config;
> +	memcpy(&state->config, i2c->dev.platform_data, sizeof(state->config));
>  	state->i2c = i2c;
>  
>  	/* create dvb_frontend */
> -	memcpy(&state->frontend.ops, &mb86a20s_ops,
> +	memcpy(&fe->ops, &mb86a20s_ops,
>  		sizeof(struct dvb_frontend_ops));

btw,
we can go with "mb86a20s_param = { .ops.fe_ops = &mb86a20s_ops,}" insead.

--
regards,
akihiro

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

* Re: [RFC/PATCH] dvb-core: add template code for i2c binding model
  2015-01-05 12:14     ` Akihiro TSUKADA
@ 2015-01-05 12:24       ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 15+ messages in thread
From: Mauro Carvalho Chehab @ 2015-01-05 12:24 UTC (permalink / raw)
  To: Akihiro TSUKADA; +Cc: linux-media

Em Mon, 05 Jan 2015 21:14:42 +0900
Akihiro TSUKADA <tskd08@gmail.com> escreveu:

> > The only thing I noticed is that it is causing some warnings at
> > dmesg about trying to create already created sysfs nodes, when the
> > driver is removed/reinserted.
> > 
> > Probably, the remove callback is called too soon or too late.
> 
> I don't have any warnings in syslog when reinserting earth-pt3 + tc90522,
> but I'll look into it.

This seems to be an already existing bug at cx231xx, as I'm also getting
those without those patches.

> 
> > -struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
> > -				    struct i2c_adapter *i2c)
> > +static int mb86a20s_probe(struct i2c_client *i2c,
> > +			  const struct i2c_device_id *id)
> >  {
> > +	struct dvb_frontend *fe;
> >  	struct mb86a20s_state *state;
> >  	u8	rev;
> >  
> >  	dev_dbg(&i2c->dev, "%s called.\n", __func__);
> >  
> > -	/* allocate memory for the internal state */
> > -	state = kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL);
> > -	if (state == NULL) {
> > -		dev_err(&i2c->dev,
> > -			"%s: unable to allocate memory for state\n", __func__);
> > -		goto error;
> > -	}
> > +	fe = i2c_get_clientdata(i2c);
> > +	state = fe->demodulator_priv;
> >  
> >  	/* setup the state */
> > -	state->config = config;
> > +	memcpy(&state->config, i2c->dev.platform_data, sizeof(state->config));
> >  	state->i2c = i2c;
> >  
> >  	/* create dvb_frontend */
> > -	memcpy(&state->frontend.ops, &mb86a20s_ops,
> > +	memcpy(&fe->ops, &mb86a20s_ops,
> >  		sizeof(struct dvb_frontend_ops));
> 
> btw,
> we can go with "mb86a20s_param = { .ops.fe_ops = &mb86a20s_ops,}" insead.
> 
> --
> regards,
> akihiro


-- 

Cheers,
Mauro

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

* Re: [RFC/PATCH] dvb-core: add template code for i2c binding model
  2014-12-05 10:49 [RFC/PATCH] dvb-core: add template code for i2c binding model tskd08
                   ` (7 preceding siblings ...)
  2014-12-30 13:10 ` Mauro Carvalho Chehab
@ 2015-01-13 18:54 ` Antti Palosaari
  2015-01-15 11:20   ` Akihiro TSUKADA
  8 siblings, 1 reply; 15+ messages in thread
From: Antti Palosaari @ 2015-01-13 18:54 UTC (permalink / raw)
  To: tskd08, linux-media; +Cc: m.chehab

On 12/05/2014 12:49 PM, tskd08@gmail.com wrote:
> From: Akihiro Tsukada <tskd08@gmail.com>
>
> Define a standard interface for demod/tuner i2c driver modules.
> A module client calls dvb_i2c_attach_{fe,tuner}(),
> and a module driver defines struct dvb_i2c_module_param and
> calls DEFINE_DVB_I2C_MODULE() macro.
>
> This template provides implicit module requests and ref-counting,
> alloc/free's private data structures,
> fixes the usage of clientdata of i2c devices,
> and defines the platformdata structures for passing around
> device specific config/output parameters between drivers and clients.
> These kinds of code are common to (almost) all dvb i2c drivers/client,
> but they were scattered over adapter modules and demod/tuner modules.
>
> Signed-off-by: Akihiro Tsukada <tskd08@gmail.com>
> ---
>   drivers/media/dvb-core/Makefile       |   4 +
>   drivers/media/dvb-core/dvb_frontend.h |   1 +
>   drivers/media/dvb-core/dvb_i2c.c      | 219 ++++++++++++++++++++++++++++++++++
>   drivers/media/dvb-core/dvb_i2c.h      | 110 +++++++++++++++++
>   4 files changed, 334 insertions(+)
>   create mode 100644 drivers/media/dvb-core/dvb_i2c.c
>   create mode 100644 drivers/media/dvb-core/dvb_i2c.h
>
> diff --git a/drivers/media/dvb-core/Makefile b/drivers/media/dvb-core/Makefile
> index 8f22bcd..271648d 100644
> --- a/drivers/media/dvb-core/Makefile
> +++ b/drivers/media/dvb-core/Makefile
> @@ -8,4 +8,8 @@ dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o 	\
>   		 dvb_ca_en50221.o dvb_frontend.o 		\
>   		 $(dvb-net-y) dvb_ringbuffer.o dvb_math.o
>
> +ifneq ($(CONFIG_I2C)$(CONFIG_I2C_MODULE),)
> +dvb-core-objs += dvb_i2c.o
> +endif
> +
>   obj-$(CONFIG_DVB_CORE) += dvb-core.o
> diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h
> index 816269e..41aae1b 100644
> --- a/drivers/media/dvb-core/dvb_frontend.h
> +++ b/drivers/media/dvb-core/dvb_frontend.h
> @@ -415,6 +415,7 @@ struct dtv_frontend_properties {
>   struct dvb_frontend {
>   	struct dvb_frontend_ops ops;
>   	struct dvb_adapter *dvb;
> +	struct i2c_client *fe_cl;

IMHO that is ugly as hell. You should not add any hardware/driver things 
to DVB frontend, even more bad this adds I2C dependency to DVB frontend, 
how about some other busses... DVB frontend is *logical* entity 
representing the DVB device to system. All hardware specific things 
belongs to drivers - not the frontend at all.


>   	void *demodulator_priv;
>   	void *tuner_priv;
>   	void *frontend_priv;

regards
Antti

-- 
http://palosaari.fi/

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

* Re: [RFC/PATCH] dvb-core: add template code for i2c binding model
  2015-01-13 18:54 ` Antti Palosaari
@ 2015-01-15 11:20   ` Akihiro TSUKADA
  0 siblings, 0 replies; 15+ messages in thread
From: Akihiro TSUKADA @ 2015-01-15 11:20 UTC (permalink / raw)
  To: Antti Palosaari, linux-media; +Cc: m.chehab

Moikka,
thank you for the comment.

On 2015年01月14日 03:54, Antti Palosaari wrote:
>> --- a/drivers/media/dvb-core/dvb_frontend.h
>> +++ b/drivers/media/dvb-core/dvb_frontend.h
>> @@ -415,6 +415,7 @@ struct dtv_frontend_properties {
>>   struct dvb_frontend {
>>       struct dvb_frontend_ops ops;
>>       struct dvb_adapter *dvb;
>> +    struct i2c_client *fe_cl;
> 
> IMHO that is ugly as hell. You should not add any hardware/driver things
> to DVB frontend, even more bad this adds I2C dependency to DVB frontend,
> how about some other busses... DVB frontend is *logical* entity
> representing the DVB device to system. All hardware specific things
> belongs to drivers - not the frontend at all.

Currently, the i2c_client pointer is distributed/copied among
each demod drivers plus adapter drivers,
so I thought it would be better to unify them into one place,
but since there seems to be no good (common) place to store it,
I'll consider your advice and remove this fe_cl member.

Regards,
akihiro

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

end of thread, other threads:[~2015-01-15 11:20 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-05 10:49 [RFC/PATCH] dvb-core: add template code for i2c binding model tskd08
2014-12-05 10:55 ` [PATCH 0/5] ports to dvb-core i2c template code tskd08
2014-12-05 10:55 ` [PATCH 1/5] dvb: qm1d1c0042: use dvb-core i2c binding model template tskd08
2014-12-05 10:55 ` [PATCH 2/5] dvb: mxl301rf: " tskd08
2014-12-05 10:55 ` [PATCH 3/5] dvb: tc90522: " tskd08
2014-12-05 10:55 ` [PATCH 4/5] dvb: tc90522: remove a redundant state variable tskd08
2014-12-05 10:55 ` [PATCH 5/5] dvb: pci/pt3: use dvb-core i2c binding model template tskd08
2014-12-26 11:00 ` [RFC/PATCH] dvb-core: add template code for i2c binding model Akihiro TSUKADA
2014-12-30 13:10 ` Mauro Carvalho Chehab
2014-12-30 20:01   ` Mauro Carvalho Chehab
2015-01-05 12:14     ` Akihiro TSUKADA
2015-01-05 12:24       ` Mauro Carvalho Chehab
2015-01-05 11:59   ` Akihiro TSUKADA
2015-01-13 18:54 ` Antti Palosaari
2015-01-15 11:20   ` Akihiro TSUKADA

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.