@@ -301,6 +301,89 @@ static int si2157_sleep(struct dvb_frontend *fe)
return ret;
}
+static int si2157_tune_wait(struct i2c_client *client, u8 is_digital)
+{
+#define TUN_TIMEOUT 40
+#define DIG_TIMEOUT 30
+#define ANALOG_TIMEOUT 150
+ struct si2157_dev *dev = i2c_get_clientdata(client);
+ int ret;
+ unsigned long timeout;
+ unsigned long start_time;
+ u8 wait_status;
+ u8 tune_lock_mask;
+
+ if (is_digital)
+ tune_lock_mask = 0x04;
+ else
+ tune_lock_mask = 0x02;
+
+ 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 we tuned ok, wait a bit for tuner lock */
+ if ((wait_status & 0x81) == 0x81) {
+ if (is_digital)
+ timeout = jiffies + msecs_to_jiffies(DIG_TIMEOUT);
+ else
+ timeout = jiffies + msecs_to_jiffies(ANALOG_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 locked? */
+ if (wait_status & tune_lock_mask)
+ break;
+ usleep_range(5000, 10000);
+ }
+ }
+
+ dev_dbg(&client->dev, "tuning+lock 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_dbg(&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 +483,8 @@ static int si2157_set_params(struct dvb_frontend *fe)
dev->bandwidth = bandwidth;
dev->frequency = c->frequency;
+ si2157_tune_wait(client, 1); /* wait to complete, ignore any errors */
+
return 0;
err:
dev->bandwidth = 0;
@@ -609,6 +694,8 @@ static int si2157_set_analog_params(struct dvb_frontend *fe,
#endif
dev->bandwidth = bandwidth;
+ si2157_tune_wait(client, 0); /* wait to complete, ignore any errors */
+
return 0;
err:
dev->bandwidth = 0;
Some software reports no signal found on a frequency due to immediately checking for lock as soon as set_params returns. This waits up 40ms for tuning operation, then from 30-150ms (dig/analog) for signal lock before returning from set_params and set_analog_params. Tuning typically completes in 20-30ms. Digital tuning will additionally wait depending on signal characteristics. Analog tuning will wait the full timeout in case of no signal. Signed-off-by: Brad Love <brad@nextdimension.cc> --- No changes drivers/media/tuners/si2157.c | 87 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+)