Commit e6d7ffcd authored by Antti Palosaari's avatar Antti Palosaari Committed by Wolfram Sang

[media] si2168: change the i2c gate to be mux-locked

The root i2c adapter lock is then no longer held by the i2c mux during
accesses behind the i2c gate, and such accesses need to take that lock
just like any other ordinary i2c accesses do.

So, declare the i2c gate mux-locked, and zap the code that makes the
i2c accesses unlocked. But add a mutex so that firmware commands are
still serialized.
Signed-off-by: default avatarAntti Palosaari <crope@iki.fi>
Signed-off-by: default avatarPeter Rosin <peda@axentia.se>
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
parent 1ffcfaf1
...@@ -56,7 +56,7 @@ In drivers/media/ ...@@ -56,7 +56,7 @@ In drivers/media/
dvb-frontends/m88ds3103 Parent-locked dvb-frontends/m88ds3103 Parent-locked
dvb-frontends/rtl2830 Parent-locked dvb-frontends/rtl2830 Parent-locked
dvb-frontends/rtl2832 Parent-locked dvb-frontends/rtl2832 Parent-locked
dvb-frontends/si2168 Parent-locked dvb-frontends/si2168 Mux-locked
usb/cx231xx/ Parent-locked usb/cx231xx/ Parent-locked
......
...@@ -18,53 +18,23 @@ ...@@ -18,53 +18,23 @@
static const struct dvb_frontend_ops si2168_ops; static const struct dvb_frontend_ops si2168_ops;
/* Own I2C adapter locking is needed because of I2C gate logic. */
static int si2168_i2c_master_send_unlocked(const struct i2c_client *client,
const char *buf, int count)
{
int ret;
struct i2c_msg msg = {
.addr = client->addr,
.flags = 0,
.len = count,
.buf = (char *)buf,
};
ret = __i2c_transfer(client->adapter, &msg, 1);
return (ret == 1) ? count : ret;
}
static int si2168_i2c_master_recv_unlocked(const struct i2c_client *client,
char *buf, int count)
{
int ret;
struct i2c_msg msg = {
.addr = client->addr,
.flags = I2C_M_RD,
.len = count,
.buf = buf,
};
ret = __i2c_transfer(client->adapter, &msg, 1);
return (ret == 1) ? count : ret;
}
/* execute firmware command */ /* execute firmware command */
static int si2168_cmd_execute_unlocked(struct i2c_client *client, static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd)
struct si2168_cmd *cmd)
{ {
struct si2168_dev *dev = i2c_get_clientdata(client);
int ret; int ret;
unsigned long timeout; unsigned long timeout;
mutex_lock(&dev->i2c_mutex);
if (cmd->wlen) { if (cmd->wlen) {
/* write cmd and args for firmware */ /* write cmd and args for firmware */
ret = si2168_i2c_master_send_unlocked(client, cmd->args, ret = i2c_master_send(client, cmd->args, cmd->wlen);
cmd->wlen);
if (ret < 0) { if (ret < 0) {
goto err; goto err_mutex_unlock;
} else if (ret != cmd->wlen) { } else if (ret != cmd->wlen) {
ret = -EREMOTEIO; ret = -EREMOTEIO;
goto err; goto err_mutex_unlock;
} }
} }
...@@ -73,13 +43,12 @@ static int si2168_cmd_execute_unlocked(struct i2c_client *client, ...@@ -73,13 +43,12 @@ static int si2168_cmd_execute_unlocked(struct i2c_client *client,
#define TIMEOUT 70 #define TIMEOUT 70
timeout = jiffies + msecs_to_jiffies(TIMEOUT); timeout = jiffies + msecs_to_jiffies(TIMEOUT);
while (!time_after(jiffies, timeout)) { while (!time_after(jiffies, timeout)) {
ret = si2168_i2c_master_recv_unlocked(client, cmd->args, ret = i2c_master_recv(client, cmd->args, cmd->rlen);
cmd->rlen);
if (ret < 0) { if (ret < 0) {
goto err; goto err_mutex_unlock;
} else if (ret != cmd->rlen) { } else if (ret != cmd->rlen) {
ret = -EREMOTEIO; ret = -EREMOTEIO;
goto err; goto err_mutex_unlock;
} }
/* firmware ready? */ /* firmware ready? */
...@@ -94,32 +63,23 @@ static int si2168_cmd_execute_unlocked(struct i2c_client *client, ...@@ -94,32 +63,23 @@ static int si2168_cmd_execute_unlocked(struct i2c_client *client,
/* error bit set? */ /* error bit set? */
if ((cmd->args[0] >> 6) & 0x01) { if ((cmd->args[0] >> 6) & 0x01) {
ret = -EREMOTEIO; ret = -EREMOTEIO;
goto err; goto err_mutex_unlock;
} }
if (!((cmd->args[0] >> 7) & 0x01)) { if (!((cmd->args[0] >> 7) & 0x01)) {
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
goto err; goto err_mutex_unlock;
} }
} }
mutex_unlock(&dev->i2c_mutex);
return 0; return 0;
err: err_mutex_unlock:
mutex_unlock(&dev->i2c_mutex);
dev_dbg(&client->dev, "failed=%d\n", ret); dev_dbg(&client->dev, "failed=%d\n", ret);
return ret; return ret;
} }
static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd)
{
int ret;
i2c_lock_adapter(client->adapter);
ret = si2168_cmd_execute_unlocked(client, cmd);
i2c_unlock_adapter(client->adapter);
return ret;
}
static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status)
{ {
struct i2c_client *client = fe->demodulator_priv; struct i2c_client *client = fe->demodulator_priv;
...@@ -610,11 +570,6 @@ static int si2168_get_tune_settings(struct dvb_frontend *fe, ...@@ -610,11 +570,6 @@ static int si2168_get_tune_settings(struct dvb_frontend *fe,
return 0; return 0;
} }
/*
* I2C gate logic
* We must use unlocked I2C I/O because I2C adapter lock is already taken
* by the caller (usually tuner driver).
*/
static int si2168_select(struct i2c_mux_core *muxc, u32 chan) static int si2168_select(struct i2c_mux_core *muxc, u32 chan)
{ {
struct i2c_client *client = i2c_mux_priv(muxc); struct i2c_client *client = i2c_mux_priv(muxc);
...@@ -625,7 +580,7 @@ static int si2168_select(struct i2c_mux_core *muxc, u32 chan) ...@@ -625,7 +580,7 @@ static int si2168_select(struct i2c_mux_core *muxc, u32 chan)
memcpy(cmd.args, "\xc0\x0d\x01", 3); memcpy(cmd.args, "\xc0\x0d\x01", 3);
cmd.wlen = 3; cmd.wlen = 3;
cmd.rlen = 0; cmd.rlen = 0;
ret = si2168_cmd_execute_unlocked(client, &cmd); ret = si2168_cmd_execute(client, &cmd);
if (ret) if (ret)
goto err; goto err;
...@@ -645,7 +600,7 @@ static int si2168_deselect(struct i2c_mux_core *muxc, u32 chan) ...@@ -645,7 +600,7 @@ static int si2168_deselect(struct i2c_mux_core *muxc, u32 chan)
memcpy(cmd.args, "\xc0\x0d\x00", 3); memcpy(cmd.args, "\xc0\x0d\x00", 3);
cmd.wlen = 3; cmd.wlen = 3;
cmd.rlen = 0; cmd.rlen = 0;
ret = si2168_cmd_execute_unlocked(client, &cmd); ret = si2168_cmd_execute(client, &cmd);
if (ret) if (ret)
goto err; goto err;
...@@ -708,9 +663,11 @@ static int si2168_probe(struct i2c_client *client, ...@@ -708,9 +663,11 @@ static int si2168_probe(struct i2c_client *client,
goto err; goto err;
} }
mutex_init(&dev->i2c_mutex);
/* create mux i2c adapter for tuner */ /* create mux i2c adapter for tuner */
dev->muxc = i2c_mux_alloc(client->adapter, &client->dev, dev->muxc = i2c_mux_alloc(client->adapter, &client->dev,
1, 0, 0, 1, 0, I2C_MUX_LOCKED,
si2168_select, si2168_deselect); si2168_select, si2168_deselect);
if (!dev->muxc) { if (!dev->muxc) {
ret = -ENOMEM; ret = -ENOMEM;
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
/* state struct */ /* state struct */
struct si2168_dev { struct si2168_dev {
struct mutex i2c_mutex;
struct i2c_mux_core *muxc; struct i2c_mux_core *muxc;
struct dvb_frontend fe; struct dvb_frontend fe;
enum fe_delivery_system delivery_system; enum fe_delivery_system delivery_system;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment