diff mbox

[2/2] mn88472: fix firmware loading

Message ID 1417990203-758-2-git-send-email-benjamin@southpole.se (mailing list archive)
State New, archived
Headers show

Commit Message

Benjamin Larsson Dec. 7, 2014, 10:10 p.m. UTC
The firmware must be loaded one byte at a time via the 0xf6 register.

Signed-off-by: Benjamin Larsson <benjamin@southpole.se>
---
 drivers/staging/media/mn88472/mn88472.c | 21 +++++++--------------
 1 file changed, 7 insertions(+), 14 deletions(-)

Comments

Antti Palosaari Dec. 7, 2014, 10:36 p.m. UTC | #1
On 12/08/2014 12:10 AM, Benjamin Larsson wrote:
> The firmware must be loaded one byte at a time via the 0xf6 register.

I don't think so. Currently it downloads firmware in 22 byte chunks and 
it seems to work, at least for me, both mn88472 and mn88473.

> Signed-off-by: Benjamin Larsson <benjamin@southpole.se>
> ---
>   drivers/staging/media/mn88472/mn88472.c | 21 +++++++--------------
>   1 file changed, 7 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/staging/media/mn88472/mn88472.c b/drivers/staging/media/mn88472/mn88472.c
> index ffee187..ba1bc8d 100644
> --- a/drivers/staging/media/mn88472/mn88472.c
> +++ b/drivers/staging/media/mn88472/mn88472.c
> @@ -290,7 +290,7 @@ static int mn88472_init(struct dvb_frontend *fe)
>   {
>   	struct i2c_client *client = fe->demodulator_priv;
>   	struct mn88472_dev *dev = i2c_get_clientdata(client);
> -	int ret, len, remaining;
> +	int ret, i;
>   	const struct firmware *fw = NULL;
>   	u8 *fw_file = MN88472_FIRMWARE;
>
> @@ -330,19 +330,12 @@ static int mn88472_init(struct dvb_frontend *fe)
>   	if (ret)
>   		goto err;
>
> -	for (remaining = fw->size; remaining > 0;
> -			remaining -= (dev->i2c_wr_max - 1)) {
> -		len = remaining;
> -		if (len > (dev->i2c_wr_max - 1))
> -			len = (dev->i2c_wr_max - 1);
> -
> -		ret = regmap_bulk_write(dev->regmap[0], 0xf6,
> -				&fw->data[fw->size - remaining], len);
> -		if (ret) {
> -			dev_err(&client->dev,
> -					"firmware download failed=%d\n", ret);
> -			goto err;
> -		}
> +	for (i = 0 ; i < fw->size ; i++)
> +		ret |= regmap_write(dev->regmap[0], 0xf6, fw->data[i]);
> +	if (ret) {
> +		dev_err(&client->dev,
> +				"firmware download failed=%d\n", ret);
> +		goto err;
>   	}

Not nice.

1) You mask status and you could not know if error code is valid after 
mask few thousand error codes.

2) Even worse, it is loop that runs thousand of times. Guess how much 
I/O errors there could happen. There is many times situation when first 
error occur then all the rest commands are failing too. And many cases 
failing I2C command could be failed USB message, which could take few 
seconds. Very typical USB timeout is 2 secs, this means 2k firmware, 
2*2000=4000 sec => it blocks that routine over *one* hour.

>
>   	ret = regmap_write(dev->regmap[0], 0xf5, 0x00);
>

regards
Antti
Benjamin Larsson Dec. 8, 2014, 11:12 a.m. UTC | #2
On 12/07/2014 11:36 PM, Antti Palosaari wrote:
> On 12/08/2014 12:10 AM, Benjamin Larsson wrote:
>> The firmware must be loaded one byte at a time via the 0xf6 register.
>
> I don't think so. Currently it downloads firmware in 22 byte chunks 
> and it seems to work, at least for me, both mn88472 and mn88473.

With both these changes I get much better sensitivity. So something is 
better then before. I will track down the needed changes and respin the 
patches.

MvH
Benjamin Larsson
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Benjamin Larsson Dec. 8, 2014, 4:04 p.m. UTC | #3
On 12/07/2014 11:36 PM, Antti Palosaari wrote:
> On 12/08/2014 12:10 AM, Benjamin Larsson wrote:
>> The firmware must be loaded one byte at a time via the 0xf6 register.
>
> I don't think so. Currently it downloads firmware in 22 byte chunks 
> and it seems to work, at least for me, both mn88472 and mn88473.

Ok, I have now tried the driver with my defaults patch in and with your 
method of loading the firmware and my patch. I have my antenna placed in 
a bad location with bad reception. With my patch I am getting data from 
the device, without my patch I am not. So whatever my code does it makes 
the device more sensitive.

And then there is this comment in the regmap code:

regmap_bulk_write(): Write multiple registers to the device

In this case we want to write multiple bytes to the same register. So I 
think that my patch is correct in principle.

MvH
Benjamin Larsson
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Antti Palosaari Dec. 8, 2014, 5:35 p.m. UTC | #4
Moikka!

On 12/08/2014 01:12 PM, Benjamin Larsson wrote:
> On 12/07/2014 11:36 PM, Antti Palosaari wrote:
>> On 12/08/2014 12:10 AM, Benjamin Larsson wrote:
>>> The firmware must be loaded one byte at a time via the 0xf6 register.
>>
>> I don't think so. Currently it downloads firmware in 22 byte chunks
>> and it seems to work, at least for me, both mn88472 and mn88473.
>
> With both these changes I get much better sensitivity. So something is
> better then before. I will track down the needed changes and respin the
> patches.

I suspect it is that initialization of all registers which has something 
to do with sensitivity. I haven't tested if firmware uploading is 
critical, what happens when some byte is skipped or so...

Did you saw there is config parameter i2c_wr_max? Setting it to '1' does 
same what that your patch did, but leaves amount of max I2C bytes 
configurable...

Anyhow, good finding, which needs to be track down.

regards
Antti
Antti Palosaari Dec. 8, 2014, 5:46 p.m. UTC | #5
Hello!

On 12/08/2014 06:04 PM, Benjamin Larsson wrote:
> On 12/07/2014 11:36 PM, Antti Palosaari wrote:
>> On 12/08/2014 12:10 AM, Benjamin Larsson wrote:
>>> The firmware must be loaded one byte at a time via the 0xf6 register.
>>
>> I don't think so. Currently it downloads firmware in 22 byte chunks
>> and it seems to work, at least for me, both mn88472 and mn88473.
>
> Ok, I have now tried the driver with my defaults patch in and with your
> method of loading the firmware and my patch. I have my antenna placed in
> a bad location with bad reception. With my patch I am getting data from
> the device, without my patch I am not. So whatever my code does it makes
> the device more sensitive.
>
> And then there is this comment in the regmap code:
>
> regmap_bulk_write(): Write multiple registers to the device
>
> In this case we want to write multiple bytes to the same register. So I
> think that my patch is correct in principle.

You haven't make any test whether it is possible to write that firmware 
in a large chunks *or* writing one byte (smallest possible ~chuck) at 
the time? I think it does not matter. I suspect you could even download 
whole firmware as one go - but rtl2832p I2C adapter does support only 22 
bytes on one xfer.

Even those are written to one register, chip knows how many bytes one 
message has and could increase its internal address counter. That is 
usually called register address auto-increment.

A) writing:
f6 00
f6 01
f6 02
f6 03
f6 04
f6 05
f6 06
f6 07
f6 08
f6 09

B) writing:
f6 00 01 02 03 04
f6 05 06 07 08 09

will likely end up same. B is better as only 2 xfers are done - much 
less IO.

regards
Antti
diff mbox

Patch

diff --git a/drivers/staging/media/mn88472/mn88472.c b/drivers/staging/media/mn88472/mn88472.c
index ffee187..ba1bc8d 100644
--- a/drivers/staging/media/mn88472/mn88472.c
+++ b/drivers/staging/media/mn88472/mn88472.c
@@ -290,7 +290,7 @@  static int mn88472_init(struct dvb_frontend *fe)
 {
 	struct i2c_client *client = fe->demodulator_priv;
 	struct mn88472_dev *dev = i2c_get_clientdata(client);
-	int ret, len, remaining;
+	int ret, i;
 	const struct firmware *fw = NULL;
 	u8 *fw_file = MN88472_FIRMWARE;
 
@@ -330,19 +330,12 @@  static int mn88472_init(struct dvb_frontend *fe)
 	if (ret)
 		goto err;
 
-	for (remaining = fw->size; remaining > 0;
-			remaining -= (dev->i2c_wr_max - 1)) {
-		len = remaining;
-		if (len > (dev->i2c_wr_max - 1))
-			len = (dev->i2c_wr_max - 1);
-
-		ret = regmap_bulk_write(dev->regmap[0], 0xf6,
-				&fw->data[fw->size - remaining], len);
-		if (ret) {
-			dev_err(&client->dev,
-					"firmware download failed=%d\n", ret);
-			goto err;
-		}
+	for (i = 0 ; i < fw->size ; i++)
+		ret |= regmap_write(dev->regmap[0], 0xf6, fw->data[i]);
+	if (ret) {
+		dev_err(&client->dev,
+				"firmware download failed=%d\n", ret);
+		goto err;
 	}
 
 	ret = regmap_write(dev->regmap[0], 0xf5, 0x00);