Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: media si2168: fully initialize si2168 on resume only when necessary

At connection time (or boot) in si2168_probe(), the firmware is not
loaded to the device and the device is not fully activated. It is
not useful or sensible to do this full initialization on resume in
case it has not been previously initialized and is expected to be
in this initialized state.
Calling si2168_init() and therefore reading the firmware file for
the first time during resume leads to problems and should be avoided.
It is however safe to read the firmware file once it has already been
read outside of a suspend/resume situation.

Add a staus flag 'initialized' to store whether si2168_init() has
successfully been called. If initialization fails (e.g. due to missing
firmware file), the flag is not set.
Register a separate si2168_resume callback which only calls
si2168_init() once the 'initialized' flag has been set and it is safe
to load the firmware at resume.
The first call to si2168_init() will now always happen when the device
is actually used for the first time and never during resume.
This avoids the unsafe firmware file reading and should also speed up
resume by skipping unnecessary device initialization.

Link: https://lore.kernel.org/linux-media/20210418001204.7453-3-kernel@tuxforce.de

[mchehab: fix several Coding Style issues]
Cc: Antti Palosaari <crope@iki.fi>
Signed-off-by: Lukas Middendorf <kernel@tuxforce.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>

authored by

Lukas Middendorf and committed by
Mauro Carvalho Chehab
51c2664a 40ae6eff

+23
+22
drivers/media/dvb-frontends/si2168.c
··· 514 514 goto err; 515 515 516 516 dev->warm = true; 517 + dev->initialized = true; 517 518 warm: 518 519 /* Init stats here to indicate which stats are supported */ 519 520 c->cnr.len = 1; ··· 534 533 err: 535 534 dev_dbg(&client->dev, "failed=%d\n", ret); 536 535 return ret; 536 + } 537 + 538 + static int si2168_resume(struct dvb_frontend *fe) 539 + { 540 + struct i2c_client *client = fe->demodulator_priv; 541 + struct si2168_dev *dev = i2c_get_clientdata(client); 542 + 543 + /* 544 + * check whether si2168_init() has been called successfully 545 + * outside of a resume cycle. Only call it (and load firmware) 546 + * in this case. si2168_init() is only called during resume 547 + * once the device has actually been used. Otherwise, leave the 548 + * device untouched. 549 + */ 550 + if (dev->initialized) { 551 + dev_dbg(&client->dev, "previsously initialized, call si2168_init()\n"); 552 + return si2168_init(fe); 553 + } 554 + dev_dbg(&client->dev, "not initialized yet, skipping init on resume\n"); 555 + return 0; 537 556 } 538 557 539 558 static int si2168_sleep(struct dvb_frontend *fe) ··· 665 644 666 645 .init = si2168_init, 667 646 .sleep = si2168_sleep, 647 + .resume = si2168_resume, 668 648 669 649 .set_frontend = si2168_set_frontend, 670 650
+1
drivers/media/dvb-frontends/si2168_priv.h
··· 36 36 u8 ts_mode; 37 37 unsigned int active:1; 38 38 unsigned int warm:1; 39 + unsigned int initialized:1; 39 40 unsigned int ts_clock_inv:1; 40 41 unsigned int ts_clock_gapped:1; 41 42 unsigned int spectral_inversion:1;