summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad Love <brad@nextdimension.cc>2019-11-14 21:03:59 +0100
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>2020-04-21 16:46:55 +0200
commit578147e968bd0cf6d74f4f04eee5a1f9b7e007da (patch)
tree6dfbf00714509be485238d25b848713bdea776d6
parent7e80a8d14d9ffa5fbd10652da9a2d93c1cefd6f9 (diff)
downloadlinux-stable-578147e968bd0cf6d74f4f04eee5a1f9b7e007da.tar.gz
linux-stable-578147e968bd0cf6d74f4f04eee5a1f9b7e007da.tar.bz2
linux-stable-578147e968bd0cf6d74f4f04eee5a1f9b7e007da.zip
media: si2157: Briefly wait for tuning operation to complete
To detect errors in the tuning operation, this waits up 40ms for operation completion status. This allows for error detection and prevents issuing additional commands to the tuner before it is finished. Tuning typically completes in 20-30ms. Signed-off-by: Brad Love <brad@nextdimension.cc> Signed-off-by: Sean Young <sean@mess.org> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
-rw-r--r--drivers/media/tuners/si2157.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
index 1dad46522033..b22441522921 100644
--- a/drivers/media/tuners/si2157.c
+++ b/drivers/media/tuners/si2157.c
@@ -301,6 +301,54 @@ err:
return ret;
}
+static int si2157_tune_wait(struct i2c_client *client)
+{
+#define TUN_TIMEOUT 40
+ struct si2157_dev *dev = i2c_get_clientdata(client);
+ int ret;
+ unsigned long timeout;
+ unsigned long start_time;
+ u8 wait_status;
+
+ mutex_lock(&dev->i2c_mutex);
+
+ /* wait tuner command complete */
+ start_time = jiffies;
+ timeout = start_time + msecs_to_jiffies(TUN_TIMEOUT);
+ while (!time_after(jiffies, timeout)) {
+ ret = i2c_master_recv(client, &wait_status,
+ sizeof(wait_status));
+ if (ret < 0) {
+ goto err_mutex_unlock;
+ } else if (ret != sizeof(wait_status)) {
+ ret = -EREMOTEIO;
+ goto err_mutex_unlock;
+ }
+
+ /* tuner done? */
+ if ((wait_status & 0x81) == 0x81)
+ break;
+ usleep_range(5000, 10000);
+ }
+
+ dev_dbg(&client->dev, "tuning took %d ms, status=0x%x\n",
+ jiffies_to_msecs(jiffies) - jiffies_to_msecs(start_time),
+ wait_status);
+
+ if ((wait_status & 0xc0) != 0x80) {
+ ret = -ETIMEDOUT;
+ goto err_mutex_unlock;
+ }
+
+ mutex_unlock(&dev->i2c_mutex);
+ return 0;
+
+err_mutex_unlock:
+ mutex_unlock(&dev->i2c_mutex);
+ dev_err(&client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
static int si2157_set_params(struct dvb_frontend *fe)
{
struct i2c_client *client = fe->tuner_priv;
@@ -400,6 +448,8 @@ static int si2157_set_params(struct dvb_frontend *fe)
dev->bandwidth = bandwidth;
dev->frequency = c->frequency;
+ si2157_tune_wait(client); /* wait to complete, ignore any errors */
+
return 0;
err:
dev->bandwidth = 0;
@@ -595,6 +645,8 @@ static int si2157_set_analog_params(struct dvb_frontend *fe,
dev->bandwidth = bandwidth;
+ si2157_tune_wait(client); /* wait to complete, ignore any errors */
+
return 0;
err:
dev->bandwidth = 0;