Message ID | 20191114200408.28883-6-brad@nextdimension.cc (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | si2157: Analog tuning and optimizations | expand |
On 11/14/19 10:03 PM, Brad Love wrote: > 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. So that adds some magic waiting at the end of both digital and analog tuning. For digital side it surely is not needed, it has been ages without. Tuning on digital side works almost always on 3 phases, 1) program tuner, 2) program demod, 3) start waiting demod lock. Tuner is generally ready much faster than demod, it is usually just programming PLL and PLL locks very fast if it is inside supported frequency ranges and outside ranges it does not lock at all. Some tuners supports PLL lock reading, but generally there is no idea to read it on normal operation. So all-in-all, tuner is almost certainly first device which is ready on that chain and if something fails dvb-frontend does retuning. For analog stuff you added I am not very familiar. Maybe you should check analog demod status somehow, is there such callback to read status as digital side is..? Antti > > Signed-off-by: Brad Love <brad@nextdimension.cc> > --- > Since v2: > - Split into two patches, tune completion and signal lock > > drivers/media/tuners/si2157.c | 52 +++++++++++++++++++++++++++++++++++ > 1 file changed, 52 insertions(+) > > diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c > index 78a855df30da..cac4870017f5 100644 > --- a/drivers/media/tuners/si2157.c > +++ b/drivers/media/tuners/si2157.c > @@ -301,6 +301,54 @@ static int si2157_sleep(struct dvb_frontend *fe) > 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; > @@ -594,6 +644,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; >
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index 78a855df30da..cac4870017f5 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -301,6 +301,54 @@ static int si2157_sleep(struct dvb_frontend *fe) 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; @@ -594,6 +644,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;
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> --- Since v2: - Split into two patches, tune completion and signal lock drivers/media/tuners/si2157.c | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+)