staticint tuner_lock_debug;
module_param(tuner_lock_debug, int, 0644);
MODULE_PARM_DESC(tuner_lock_debug, "if set, signal lock is briefly waited on after setting params");
/* request the firmware, this will block and timeout */
ret = firmware_request_nowarn(&fw, fw_name, &client->dev); if (ret) return ret;
/* firmware should be n chunks of 17 bytes */ if (fw->size % 17 != 0) {
dev_err(&client->dev, "firmware file '%s' is invalid\n",
fw_name);
ret = -EINVAL; goto err_release_firmware;
}
dev_info(&client->dev, "downloading firmware from file '%s'\n",
fw_name);
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 (required && !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;
}
/* Update the part id based on device's report */
dev->part_id = part_id;
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");
} elseif (ret < 0) {
dev_err(&client->dev, "error %d when loading firmware\n", ret);
} return ret;
}
/* Try to get Xtal trim property, to verify tuner still running */
memcpy(cmd.args, "\x15\x00\x02\x04", 4);
cmd.wlen = 4;
cmd.rlen = 4;
ret = si2157_cmd_execute(client, &cmd);
xtal_trim = cmd.args[2] | (cmd.args[3] << 8);
if (ret == 0 && xtal_trim < 16) goto warm;
dev->if_frequency = 0; /* we no longer know current tuner state */
/* Si2141 needs a wake up command */ if (dev->part_id == SI2141) {
memcpy(cmd.args, "\xc0\x08\x01\x02\x00\x00\x01", 7);
cmd.wlen = 7;
ret = si2157_cmd_execute(client, &cmd); if (ret) goto err;
}
/* Try to load the firmware */
ret = si2157_find_and_load_firmware(fe); if (ret < 0) goto err;
/* reboot the tuner with new firmware? */
memcpy(cmd.args, "\x01\x01", 2);
cmd.wlen = 2;
cmd.rlen = 1;
ret = si2157_cmd_execute(client, &cmd); if (ret) goto err;
/* query firmware version */
memcpy(cmd.args, "\x11", 1);
cmd.wlen = 1;
cmd.rlen = 10;
ret = si2157_cmd_execute(client, &cmd); if (ret) goto err;
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 (tuner_lock_debug && (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;
} elseif (ret != sizeof(wait_status)) {
ret = -EREMOTEIO; goto err_mutex_unlock;
}
switch (c->delivery_system) { case SYS_ATSC:
delivery_system = 0x00;
if_frequency = 3250000; break; case SYS_DVBC_ANNEX_B:
delivery_system = 0x10;
if_frequency = 4000000; break; case SYS_DVBT: case SYS_DVBT2: /* it seems DVB-T and DVB-T2 both are 0x20 here */
delivery_system = 0x20; break; case SYS_DVBC_ANNEX_A: case SYS_DVBC_ANNEX_C:
delivery_system = 0x30; break; case SYS_ISDBT:
delivery_system = 0x40; break; case SYS_DTMB:
delivery_system = 0x60; break; default:
ret = -EINVAL; goto err;
}
memcpy(cmd.args, "\x14\x00\x03\x07\x00\x00", 6);
cmd.args[4] = delivery_system | bw; if (dev->inversion)
cmd.args[5] = 0x01;
cmd.wlen = 6;
cmd.rlen = 4;
ret = si2157_cmd_execute(client, &cmd); if (ret) goto err;
/* On SI2146, set DTV AGC source to DLIF_AGC_3DB */ if (dev->part_id == SI2146)
memcpy(cmd.args, "\x14\x00\x02\x07\x00\x01", 6); else
memcpy(cmd.args, "\x14\x00\x02\x07\x00\x00", 6);
cmd.args[4] = dev->if_port;
cmd.wlen = 6;
cmd.rlen = 4;
ret = si2157_cmd_execute(client, &cmd); if (ret) goto err;
/* set digital if frequency if needed */ if (if_frequency != dev->if_frequency) {
memcpy(cmd.args, "\x14\x00\x06\x07", 4);
cmd.args[4] = (if_frequency / 1000) & 0xff;
cmd.args[5] = ((if_frequency / 1000) >> 8) & 0xff;
cmd.wlen = 6;
cmd.rlen = 4;
ret = si2157_cmd_execute(client, &cmd); if (ret) goto err;
dev->if_frequency = if_frequency;
}
/* set digital frequency */
memcpy(cmd.args, "\x41\x00\x00\x00\x00\x00\x00\x00", 8);
cmd.args[4] = (c->frequency >> 0) & 0xff;
cmd.args[5] = (c->frequency >> 8) & 0xff;
cmd.args[6] = (c->frequency >> 16) & 0xff;
cmd.args[7] = (c->frequency >> 24) & 0xff;
cmd.wlen = 8;
cmd.rlen = 1;
ret = si2157_cmd_execute(client, &cmd); if (ret) goto err;
if (!SUPPORTS_ATV_IF(dev)) {
dev_info(&client->dev, "Analog tuning not supported yet for Si21%d\n",
dev->part_id);
ret = -EINVAL; goto err;
}
if (!dev->active)
si2157_init(fe);
if (!dev->active) {
ret = -EAGAIN; goto err;
} if (params->mode == V4L2_TUNER_RADIO) { /* * std = "fm"; * bandwidth = 1700000; //best can do for FM, AGC will be a mess though * if_frequency = 1250000; //HVR-225x(saa7164), HVR-12xx(cx23885) * if_frequency = 6600000; //HVR-9xx(cx231xx) * if_frequency = 5500000; //HVR-19xx(pvrusb2)
*/
dev_err(&client->dev, "si2157 does not currently support FM radio\n");
ret = -EINVAL; goto err;
}
tmp_lval = params->frequency * 625LL;
do_div(tmp_lval, 10); /* convert to HZ */
freq = (u32)tmp_lval;
if (freq < 1000000) /* is freq in KHz */
freq = freq * 1000;
dev->frequency = freq;
/* if_frequency values based on tda187271C2 */ if (params->std & (V4L2_STD_B | V4L2_STD_GH)) { if (freq >= 470000000) {
std = "palGH";
bandwidth = 8000000;
if_frequency = 6000000;
system = 1; if (params->std &
(V4L2_STD_SECAM_G | V4L2_STD_SECAM_H)) {
std = "secamGH";
color = 0x10;
}
} else {
std = "palB";
bandwidth = 7000000;
if_frequency = 6000000;
system = 0; if (params->std & V4L2_STD_SECAM_B) {
std = "secamB";
color = 0x10;
}
}
} elseif (params->std & V4L2_STD_MN) {
std = "MN";
bandwidth = 6000000;
if_frequency = 5400000;
system = 2;
} elseif (params->std & V4L2_STD_PAL_I) {
std = "palI";
bandwidth = 8000000;
if_frequency = 7250000; /* TODO: does not work yet */
system = 4;
} elseif (params->std & V4L2_STD_DK) {
std = "palDK";
bandwidth = 8000000;
if_frequency = 6900000; /* TODO: does not work yet */
system = 5; if (params->std & V4L2_STD_SECAM_DK) {
std = "secamDK";
color = 0x10;
}
} elseif (params->std & V4L2_STD_SECAM_L) {
std = "secamL";
bandwidth = 8000000;
if_frequency = 6750000; /* TODO: untested */
system = 6;
color = 0x10;
} elseif (params->std & V4L2_STD_SECAM_LC) {
std = "secamL'";
bandwidth = 7000000;
if_frequency = 1250000; /* TODO: untested */
system = 7;
color = 0x10;
} else {
std = "unknown";
} /* calc channel center freq */
freq = freq - 1250000 + (bandwidth / 2);
/* set analog IF port */
memcpy(cmd.args, "\x14\x00\x03\x06\x08\x02", 6); /* in using dev->if_port, we assume analog and digital IF's */ /* are always on different ports */ /* assumes if_port definition is 0 or 1 for digital out */
cmd.args[4] = (dev->if_port == 1) ? 8 : 10; /* Analog AGC assumed external */
cmd.args[5] = (dev->if_port == 1) ? 2 : 1;
cmd.wlen = 6;
cmd.rlen = 4;
ret = si2157_cmd_execute(client, &cmd); if (ret) goto err;
/* set analog IF output config */
memcpy(cmd.args, "\x14\x00\x0d\x06\x94\x64", 6);
cmd.wlen = 6;
cmd.rlen = 4;
ret = si2157_cmd_execute(client, &cmd); if (ret) goto err;
/* make this distinct from a digital IF */
dev->if_frequency = if_frequency | 1;
/* calc and set tuner analog if center frequency */
if_frequency = if_frequency + 1250000 - (bandwidth / 2);
dev_dbg(&client->dev, "IF Ctr freq=%d\n", if_frequency);
/* set analog AGC config */
memcpy(cmd.args, "\x14\x00\x07\x06\x32\xc8", 6);
cmd.wlen = 6;
cmd.rlen = 4;
ret = si2157_cmd_execute(client, &cmd); if (ret) goto err;
/* set analog video mode */
memcpy(cmd.args, "\x14\x00\x04\x06\x00\x00", 6);
cmd.args[4] = system | color; /* can use dev->inversion if assumed applies to both digital/analog */ if (invert_analog)
cmd.args[5] |= 0x02;
cmd.wlen = 6;
cmd.rlen = 1;
ret = si2157_cmd_execute(client, &cmd); if (ret) goto err;
/* set analog frequency */
memcpy(cmd.args, "\x41\x01\x00\x00\x00\x00\x00\x00", 8);
cmd.args[4] = (freq >> 0) & 0xff;
cmd.args[5] = (freq >> 8) & 0xff;
cmd.args[6] = (freq >> 16) & 0xff;
cmd.args[7] = (freq >> 24) & 0xff;
cmd.wlen = 8;
cmd.rlen = 1;
ret = si2157_cmd_execute(client, &cmd); if (ret) goto err;
dev->bandwidth = bandwidth;
si2157_tune_wait(client, 0); /* wait to complete, ignore any errors */
/* * The part_id used here will only be used on buggy devices that don't * accept firmware uploads. Non-buggy devices should just use "si2157" for * all SiLabs TER tuners, as the driver should auto-detect it.
*/ staticconststruct i2c_device_id si2157_id_table[] = {
{"si2157", SI2157},
{"si2146", SI2146},
{"si2141", SI2141},
{"si2177", SI2177},
{}
};
MODULE_DEVICE_TABLE(i2c, si2157_id_table);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.