media: si2157: Add analog tuning related functions
Include set_analog_params, get_frequency, and get_bandwidth. Tested with NTSC and PAL standards via ch3/4 generator. Other standards are included, but are untested due to lack of generator. Signed-off-by: Brad Love <brad@nextdimension.cc> Signed-off-by: Sean Young <sean@mess.org> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
parent
e955f959ac
commit
7e80a8d14d
@ -371,7 +371,7 @@ static int si2157_set_params(struct dvb_frontend *fe)
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/* set if frequency if needed */
|
||||
/* 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;
|
||||
@ -385,7 +385,7 @@ static int si2157_set_params(struct dvb_frontend *fe)
|
||||
dev->if_frequency = if_frequency;
|
||||
}
|
||||
|
||||
/* set 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;
|
||||
@ -397,18 +397,240 @@ static int si2157_set_params(struct dvb_frontend *fe)
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
dev->bandwidth = bandwidth;
|
||||
dev->frequency = c->frequency;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
dev->bandwidth = 0;
|
||||
dev->frequency = 0;
|
||||
dev->if_frequency = 0;
|
||||
dev_dbg(&client->dev, "failed=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int si2157_set_analog_params(struct dvb_frontend *fe,
|
||||
struct analog_parameters *params)
|
||||
{
|
||||
struct i2c_client *client = fe->tuner_priv;
|
||||
struct si2157_dev *dev = i2c_get_clientdata(client);
|
||||
char *std; /* for debugging */
|
||||
int ret;
|
||||
struct si2157_cmd cmd;
|
||||
u32 bandwidth = 0;
|
||||
u32 if_frequency = 0;
|
||||
u32 freq = 0;
|
||||
u64 tmp_lval = 0;
|
||||
u8 system = 0;
|
||||
u8 color = 0; /* 0=NTSC/PAL, 0x10=SECAM */
|
||||
u8 invert_analog = 1; /* analog tuner spectrum; 0=normal, 1=inverted */
|
||||
|
||||
if (dev->chiptype != SI2157_CHIPTYPE_SI2157) {
|
||||
dev_info(&client->dev, "Analog tuning not supported for chiptype=%u\n",
|
||||
dev->chiptype);
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else if (params->std & V4L2_STD_MN) {
|
||||
std = "MN";
|
||||
bandwidth = 6000000;
|
||||
if_frequency = 5400000;
|
||||
system = 2;
|
||||
} else if (params->std & V4L2_STD_PAL_I) {
|
||||
std = "palI";
|
||||
bandwidth = 8000000;
|
||||
if_frequency = 7250000; /* TODO: does not work yet */
|
||||
system = 4;
|
||||
} else if (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;
|
||||
}
|
||||
} else if (params->std & V4L2_STD_SECAM_L) {
|
||||
std = "secamL";
|
||||
bandwidth = 8000000;
|
||||
if_frequency = 6750000; /* TODO: untested */
|
||||
system = 6;
|
||||
color = 0x10;
|
||||
} else if (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);
|
||||
|
||||
dev_dbg(&client->dev,
|
||||
"mode=%d system=%u std='%s' params->frequency=%u center freq=%u if=%u bandwidth=%u\n",
|
||||
params->mode, system, std, params->frequency,
|
||||
freq, if_frequency, bandwidth);
|
||||
|
||||
/* 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);
|
||||
|
||||
memcpy(cmd.args, "\x14\x00\x0C\x06", 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;
|
||||
|
||||
/* 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;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
dev->bandwidth = 0;
|
||||
dev->frequency = 0;
|
||||
dev->if_frequency = 0;
|
||||
dev_dbg(&client->dev, "failed=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int si2157_get_frequency(struct dvb_frontend *fe, u32 *frequency)
|
||||
{
|
||||
struct i2c_client *client = fe->tuner_priv;
|
||||
struct si2157_dev *dev = i2c_get_clientdata(client);
|
||||
|
||||
*frequency = dev->frequency;
|
||||
dev_dbg(&client->dev, "freq=%u\n", dev->frequency);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int si2157_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
|
||||
{
|
||||
struct i2c_client *client = fe->tuner_priv;
|
||||
struct si2157_dev *dev = i2c_get_clientdata(client);
|
||||
|
||||
*bandwidth = dev->bandwidth;
|
||||
dev_dbg(&client->dev, "bandwidth=%u\n", dev->bandwidth);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
|
||||
{
|
||||
struct i2c_client *client = fe->tuner_priv;
|
||||
struct si2157_dev *dev = i2c_get_clientdata(client);
|
||||
|
||||
*frequency = dev->if_frequency;
|
||||
*frequency = dev->if_frequency & ~1; /* strip analog IF indicator bit */
|
||||
dev_dbg(&client->dev, "if_frequency=%u\n", *frequency);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -422,6 +644,9 @@ static const struct dvb_tuner_ops si2157_ops = {
|
||||
.init = si2157_init,
|
||||
.sleep = si2157_sleep,
|
||||
.set_params = si2157_set_params,
|
||||
.set_analog_params = si2157_set_analog_params,
|
||||
.get_frequency = si2157_get_frequency,
|
||||
.get_bandwidth = si2157_get_bandwidth,
|
||||
.get_if_frequency = si2157_get_if_frequency,
|
||||
};
|
||||
|
||||
|
@ -29,6 +29,8 @@ struct si2157_dev {
|
||||
u8 chiptype;
|
||||
u8 if_port;
|
||||
u32 if_frequency;
|
||||
u32 bandwidth;
|
||||
u32 frequency;
|
||||
struct delayed_work stat_work;
|
||||
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER)
|
||||
|
Loading…
Reference in New Issue
Block a user