diff options
author | Mauro Carvalho Chehab <mchehab+huawei@kernel.org> | 2021-12-09 11:56:01 +0100 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab+huawei@kernel.org> | 2021-12-14 16:19:04 +0100 |
commit | 1c35ba3bf97213538b82067acc0f23f18e652226 (patch) | |
tree | 4dc9419176e463ce0fe24abe2b217dec1affaa5e /drivers/media/tuners | |
parent | media: si2157: rework the firmware load logic (diff) | |
download | linux-1c35ba3bf97213538b82067acc0f23f18e652226.tar.xz linux-1c35ba3bf97213538b82067acc0f23f18e652226.zip |
media: si2157: use a different namespace for firmware
Each chip at the si21xx TER family seems to have a different firmware,
with seems to actually be a patch against the ROM code.
Rework the code in order to use different firmware files depending
on the chip ID and rom ID.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Diffstat (limited to 'drivers/media/tuners')
-rw-r--r-- | drivers/media/tuners/si2157.c | 180 | ||||
-rw-r--r-- | drivers/media/tuners/si2157_priv.h | 31 |
2 files changed, 132 insertions, 79 deletions
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index 5f4ae8593864..bb590395e81a 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -76,6 +76,19 @@ err_mutex_unlock: return ret; } +static const struct si2157_tuner_info si2157_tuners[] = { + { SI2141, false, 0x60, SI2141_60_FIRMWARE, SI2141_A10_FIRMWARE }, + { SI2141, false, 0x61, SI2141_61_FIRMWARE, SI2141_A10_FIRMWARE }, + { SI2146, false, 0x11, SI2146_11_FIRMWARE, NULL }, + { SI2147, false, 0x50, SI2147_50_FIRMWARE, NULL }, + { SI2148, true, 0x32, SI2148_32_FIRMWARE, SI2158_A20_FIRMWARE }, + { SI2148, true, 0x33, SI2148_33_FIRMWARE, SI2158_A20_FIRMWARE }, + { SI2157, false, 0x50, SI2157_50_FIRMWARE, SI2157_A30_FIRMWARE }, + { SI2158, false, 0x50, SI2158_50_FIRMWARE, SI2158_A20_FIRMWARE }, + { SI2158, false, 0x51, SI2158_51_FIRMWARE, SI2158_A20_FIRMWARE }, + { SI2177, false, 0x50, SI2177_50_FIRMWARE, SI2157_A30_FIRMWARE }, +}; + static int si2157_load_firmware(struct dvb_frontend *fe, const char *fw_name) { @@ -85,7 +98,7 @@ static int si2157_load_firmware(struct dvb_frontend *fe, struct si2157_cmd cmd; /* request the firmware, this will block and timeout */ - ret = request_firmware(&fw, fw_name, &client->dev); + ret = firmware_request_nowarn(&fw, fw_name, &client->dev); if (ret) return ret; @@ -124,16 +137,86 @@ err_release_firmware: return ret; } +static int si2157_find_and_load_firmware(struct dvb_frontend *fe) +{ + struct i2c_client *client = fe->tuner_priv; + struct si2157_dev *dev = i2c_get_clientdata(client); + const char *fw_alt_name = NULL; + unsigned char part_id, rom_id; + const char *fw_name = NULL; + struct si2157_cmd cmd; + bool required = true; + int ret, i; + + if (dev->dont_load_firmware) { + dev_info(&client->dev, + "device is buggy, skipping firmware download\n"); + return 0; + } + + /* query chip revision */ + memcpy(cmd.args, "\x02", 1); + cmd.wlen = 1; + cmd.rlen = 13; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + return ret; + + part_id = cmd.args[2]; + rom_id = cmd.args[12]; + + for (i = 0; i < ARRAY_SIZE(si2157_tuners); i++) { + if (si2157_tuners[i].part_id != part_id) + continue; + required = si2157_tuners[i].required; + fw_alt_name = si2157_tuners[i].fw_alt_name; + + /* Both part and rom ID match */ + if (si2157_tuners[i].rom_id == rom_id) { + fw_name = si2157_tuners[i].fw_name; + break; + } + } + + if (!fw_name && !fw_alt_name) { + dev_err(&client->dev, + "unknown chip version Si21%d-%c%c%c ROM 0x%02x\n", + part_id, cmd.args[1], cmd.args[3], cmd.args[4], rom_id); + return -EINVAL; + } + + dev_info(&client->dev, + "found a 'Silicon Labs Si21%d-%c%c%c ROM 0x%02x'\n", + part_id, cmd.args[1], cmd.args[3], cmd.args[4], rom_id); + + if (fw_name) + ret = si2157_load_firmware(fe, fw_name); + else + ret = -ENOENT; + + /* Try alternate name, if any */ + if (ret == -ENOENT && fw_alt_name) + ret = si2157_load_firmware(fe, fw_alt_name); + + if (ret == -ENOENT) { + if (!required) { + dev_info(&client->dev, "Using ROM firmware.\n"); + return 0; + } + dev_err(&client->dev, "Can't continue without a firmware.\n"); + } else if (ret < 0) { + dev_err(&client->dev, "error %d when loading firmware\n", ret); + } + return ret; +} + static int si2157_init(struct dvb_frontend *fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct i2c_client *client = fe->tuner_priv; struct si2157_dev *dev = i2c_get_clientdata(client); - bool warn_firmware_not_loaded = false; - unsigned int chip_id, xtal_trim; - bool fw_required = true; + unsigned int xtal_trim; struct si2157_cmd cmd; - const char *fw_name; int ret; dev_dbg(&client->dev, "\n"); @@ -176,72 +259,11 @@ static int si2157_init(struct dvb_frontend *fe) goto err; } - if (dev->dont_load_firmware) { - dev_info(&client->dev, "device is buggy, skipping firmware download\n"); - goto skip_fw_download; - } - - /* query chip revision */ - memcpy(cmd.args, "\x02", 1); - cmd.wlen = 1; - cmd.rlen = 13; - ret = si2157_cmd_execute(client, &cmd); - if (ret) + /* Try to load the firmware */ + ret = si2157_find_and_load_firmware(fe); + if (ret < 0) goto err; - chip_id = cmd.args[1] << 24 | cmd.args[2] << 16 | cmd.args[3] << 8 | - cmd.args[4] << 0; - - #define SI2177_A30 ('A' << 24 | 77 << 16 | '3' << 8 | '0' << 0) - #define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0) - #define SI2148_A20 ('A' << 24 | 48 << 16 | '2' << 8 | '0' << 0) - #define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0) - #define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0) - #define SI2146_A10 ('A' << 24 | 46 << 16 | '1' << 8 | '0' << 0) - #define SI2141_A10 ('A' << 24 | 41 << 16 | '1' << 8 | '0' << 0) - - switch (chip_id) { - case SI2158_A20: - case SI2148_A20: - fw_name = SI2158_A20_FIRMWARE; - break; - case SI2141_A10: - fw_name = SI2141_A10_FIRMWARE; - break; - case SI2157_A30: - fw_required = false; - fallthrough; - case SI2177_A30: - fw_name = SI2157_A30_FIRMWARE; - break; - case SI2147_A30: - case SI2146_A10: - fw_name = NULL; - break; - default: - dev_err(&client->dev, "unknown chip version Si21%d-%c%c%c\n", - cmd.args[2], cmd.args[1], - cmd.args[3], cmd.args[4]); - ret = -EINVAL; - goto err; - } - - dev_info(&client->dev, "found a 'Silicon Labs Si21%d-%c%c%c'\n", - cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]); - - if (fw_name == NULL) - goto skip_fw_download; - - ret = si2157_load_firmware(fe, fw_name); - if (fw_required && ret == -ENOENT) - warn_firmware_not_loaded = true; - else if (ret < 0) { - dev_err(&client->dev, "error %d when loading firmware file '%s'\n", - ret, fw_name); - goto err; - } - -skip_fw_download: /* reboot the tuner with new firmware? */ memcpy(cmd.args, "\x01\x01", 2); cmd.wlen = 2; @@ -258,11 +280,6 @@ skip_fw_download: if (ret) goto err; - if (warn_firmware_not_loaded) { - dev_warn(&client->dev, "firmware file '%s' not found. Using firmware from eeprom.\n", - fw_name); - warn_firmware_not_loaded = false; - } dev_info(&client->dev, "firmware version: %c.%c.%d\n", cmd.args[6], cmd.args[7], cmd.args[8]); @@ -298,11 +315,6 @@ warm: return 0; err: - if (warn_firmware_not_loaded) - dev_err(&client->dev, - "firmware file '%s' not found. Can't continue without a firmware.\n", - fw_name); - dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } @@ -968,3 +980,13 @@ MODULE_LICENSE("GPL"); MODULE_FIRMWARE(SI2158_A20_FIRMWARE); MODULE_FIRMWARE(SI2141_A10_FIRMWARE); MODULE_FIRMWARE(SI2157_A30_FIRMWARE); +MODULE_FIRMWARE(SI2141_60_FIRMWARE); +MODULE_FIRMWARE(SI2141_61_FIRMWARE); +MODULE_FIRMWARE(SI2146_11_FIRMWARE); +MODULE_FIRMWARE(SI2147_50_FIRMWARE); +MODULE_FIRMWARE(SI2148_32_FIRMWARE); +MODULE_FIRMWARE(SI2148_33_FIRMWARE); +MODULE_FIRMWARE(SI2157_50_FIRMWARE); +MODULE_FIRMWARE(SI2158_50_FIRMWARE); +MODULE_FIRMWARE(SI2158_51_FIRMWARE); +MODULE_FIRMWARE(SI2177_50_FIRMWARE); diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h index ef4796098931..0db21b082ba9 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h @@ -41,6 +41,23 @@ struct si2157_dev { }; +enum si2157_part_id { + SI2141 = 41, + SI2146 = 46, + SI2147 = 47, + SI2148 = 48, + SI2157 = 57, + SI2158 = 58, + SI2177 = 77, +}; + +struct si2157_tuner_info { + enum si2157_part_id part_id; + unsigned char rom_id; + bool required; + const char *fw_name, *fw_alt_name; +}; + #define SI2157_CHIPTYPE_SI2157 0 #define SI2157_CHIPTYPE_SI2146 1 #define SI2157_CHIPTYPE_SI2141 2 @@ -54,7 +71,21 @@ struct si2157_cmd { unsigned rlen; }; +/* Old firmware namespace */ #define SI2158_A20_FIRMWARE "dvb-tuner-si2158-a20-01.fw" #define SI2141_A10_FIRMWARE "dvb-tuner-si2141-a10-01.fw" #define SI2157_A30_FIRMWARE "dvb-tuner-si2157-a30-01.fw" + +/* New firmware namespace */ +#define SI2141_60_FIRMWARE "dvb_driver_si2141_rom60.fw" +#define SI2141_61_FIRMWARE "dvb_driver_si2141_rom61.fw" +#define SI2146_11_FIRMWARE "dvb_driver_si2146_rom11.fw" +#define SI2147_50_FIRMWARE "dvb_driver_si2147_rom50.fw" +#define SI2148_32_FIRMWARE "dvb_driver_si2148_rom32.fw" +#define SI2148_33_FIRMWARE "dvb_driver_si2148_rom33.fw" +#define SI2157_50_FIRMWARE "dvb_driver_si2157_rom50.fw" +#define SI2158_50_FIRMWARE "dvb_driver_si2178_rom50.fw" +#define SI2158_51_FIRMWARE "dvb_driver_si2158_rom51.fw" +#define SI2177_50_FIRMWARE "dvb_driver_si2177_rom50.fw" + #endif |