Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 44b9055b authored by Antti Palosaari's avatar Antti Palosaari Committed by Mauro Carvalho Chehab
Browse files

[media] m88ds3103: use I2C mux for tuner I2C adapter



Switch standard I2C adapter to muxed I2C adapter.

David reported that I2C adapter implementation caused deadlock.
I discussed with Jean and he suggested to implement it as a
multiplexed i2c adapter because tuner I2C bus could be seen like
own I2C segment.

Reported-by: default avatarDavid Howells <dhowells@redhat.com>
Cc: Jean Delvare <khali@linux-fr.org>
Signed-off-by: default avatarAntti Palosaari <crope@iki.fi>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent 63c80f70
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@ config DVB_STV6110x

config DVB_M88DS3103
	tristate "Montage M88DS3103"
	depends on DVB_CORE && I2C
	depends on DVB_CORE && I2C && I2C_MUX
	default m if !MEDIA_SUBDRV_AUTOSELECT
	help
	  Say Y when you want to support this frontend.
+28 −45
Original line number Diff line number Diff line
@@ -1108,15 +1108,16 @@ static int m88ds3103_get_tune_settings(struct dvb_frontend *fe,
	return 0;
}

static u32 m88ds3103_tuner_i2c_func(struct i2c_adapter *adapter)
static void m88ds3103_release(struct dvb_frontend *fe)
{
	return I2C_FUNC_I2C;
	struct m88ds3103_priv *priv = fe->demodulator_priv;
	i2c_del_mux_adapter(priv->i2c_adapter);
	kfree(priv);
}

static int m88ds3103_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
		struct i2c_msg msg[], int num)
static int m88ds3103_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
{
	struct m88ds3103_priv *priv = i2c_get_adapdata(i2c_adap);
	struct m88ds3103_priv *priv = mux_priv;
	int ret;
	struct i2c_msg gate_open_msg[1] = {
		{
@@ -1126,43 +1127,31 @@ static int m88ds3103_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
			.buf = "\x03\x11",
		}
	};
	dev_dbg(&priv->i2c->dev, "%s: num=%d\n", __func__, num);

	mutex_lock(&priv->i2c_mutex);

	/* open i2c-gate */
	/* open tuner I2C repeater for 1 xfer, closes automatically */
	ret = i2c_transfer(priv->i2c, gate_open_msg, 1);
	if (ret != 1) {
		mutex_unlock(&priv->i2c_mutex);
		dev_warn(&priv->i2c->dev,
				"%s: i2c wr failed=%d\n",
		dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d\n",
				KBUILD_MODNAME, ret);
		if (ret >= 0)
			ret = -EREMOTEIO;
		goto err;
	}

	ret = i2c_transfer(priv->i2c, msg, num);
	mutex_unlock(&priv->i2c_mutex);
	if (ret < 0)
		dev_warn(&priv->i2c->dev, "%s: i2c failed=%d\n",
				KBUILD_MODNAME, ret);

		return ret;
err:
	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
	return ret;
	}

static struct i2c_algorithm m88ds3103_tuner_i2c_algo = {
	.master_xfer   = m88ds3103_tuner_i2c_xfer,
	.functionality = m88ds3103_tuner_i2c_func,
};
	return 0;
}

static void m88ds3103_release(struct dvb_frontend *fe)
static int m88ds3103_deselect(struct i2c_adapter *adap, void *mux_priv,
		u32 chan)
{
	struct m88ds3103_priv *priv = fe->demodulator_priv;
	i2c_del_adapter(&priv->i2c_adapter);
	kfree(priv);
	struct m88ds3103_priv *priv = mux_priv;

	mutex_unlock(&priv->i2c_mutex);

	return 0;
}

struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg,
@@ -1228,24 +1217,18 @@ struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg,
	if (ret)
		goto err;

	/* create mux i2c adapter for tuner */
	priv->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, priv, 0, 0, 0,
			m88ds3103_select, m88ds3103_deselect);
	if (priv->i2c_adapter == NULL)
		goto err;

	*tuner_i2c_adapter = priv->i2c_adapter;

	/* create dvb_frontend */
	memcpy(&priv->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops));
	priv->fe.demodulator_priv = priv;

	/* create i2c adapter for tuner */
	strlcpy(priv->i2c_adapter.name, KBUILD_MODNAME,
			sizeof(priv->i2c_adapter.name));
	priv->i2c_adapter.algo = &m88ds3103_tuner_i2c_algo;
	priv->i2c_adapter.algo_data = NULL;
	i2c_set_adapdata(&priv->i2c_adapter, priv);
	ret = i2c_add_adapter(&priv->i2c_adapter);
	if (ret) {
		dev_err(&i2c->dev, "%s: i2c bus could not be initialized\n",
				KBUILD_MODNAME);
		goto err;
	}
	*tuner_i2c_adapter = &priv->i2c_adapter;

	return &priv->fe;
err:
	dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
+2 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include "m88ds3103.h"
#include "dvb_math.h"
#include <linux/firmware.h>
#include <linux/i2c-mux.h>

#define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw"
#define M88DS3103_MCLK_KHZ 96000
@@ -38,7 +39,7 @@ struct m88ds3103_priv {
	fe_delivery_system_t delivery_system;
	fe_status_t fe_status;
	bool warm; /* FW running */
	struct i2c_adapter i2c_adapter;
	struct i2c_adapter *i2c_adapter;
};

struct m88ds3103_reg_val {