From 0694082db8a1744c407865e12c738f440cb33fad Mon Sep 17 00:00:00 2001 From: Bradford Love Date: Tue, 24 Mar 2026 13:25:02 -0500 Subject: [PATCH] media: si2157: Include support for si2177 chip The si2177 is very closely related to si2157, with slight differences when doing analog operations. Digital is left as is, but analog needs to be configured specially because the signal is internally demodulated and CVBS video is output directly from the tuner. Verified locked and working with all supported standards. Signed-off-by: Bradford Love Signed-off-by: Hans Verkuil --- drivers/media/tuners/si2157.c | 217 ++++++++++++++++++++++------- drivers/media/tuners/si2157_priv.h | 3 +- 2 files changed, 167 insertions(+), 53 deletions(-) diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index b041cd854732..4d67e347c22f 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -687,64 +687,107 @@ static int si2157_set_analog_params(struct dvb_frontend *fe, 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; + if (dev->part_id != SI2177) { + /* AGC speed */ + memcpy(cmd.args, "\x14\x00\x11\x06\x00\x00", 6); + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + + /* 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; + } else { + /* analog video equalizer - Si2177_ATV_VIDEO_EQUALIZER_PROP */ + memcpy(cmd.args, "\x14\x00\x08\x06\xf8\x00", 6); + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + + /* analog CVBS output properties - Si2177_ATV_CVBS_OUT_FINE_PROP */ + memcpy(cmd.args, "\x14\x00\x14\x06\x00\x64", 6); + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + + dev_err(&client->dev, "%s() Settings HSYNC\n", __func__); + /* HSYNC output - Si2177_ATV_HSYNC_OUT_PROP */ + memcpy(cmd.args, "\x14\x00\x27\x06\xa8\x00", 6); + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + } + + /* AFC qcuisition range 1.5MHz */ + memcpy(cmd.args, "\x14\x00\x10\x06\xdc\x05", 6); 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; @@ -757,6 +800,76 @@ static int si2157_set_analog_params(struct dvb_frontend *fe, if (ret) goto err; + if (dev->part_id == SI2177) { + /* Ref driver tunes, resets registers, then retunes, leaving steps as is */ + /* set analog video mode - Si2158_ATV_VIDEO_MODE_PROP */ + 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; + + /* Si2177_ATV_AUDIO_MODE_PROP */ + memcpy(cmd.args, "\x14\x00\x02\x06\x20\x0f", 6); + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + + /* af out - Si2177_ATV_AF_OUT_PROP */ /* BRL */ + memcpy(cmd.args, "\x14\x00\x0b\x06\x30\x00", 6); + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + + /* analog CVBS output enable - Si2177_ATV_CVBS_OUT_PROP */ + memcpy(cmd.args, "\x14\x00\x09\x06\x19\x99", 6); + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + + /* analog video equalizer - Si2177_ATV_VIDEO_EQUALIZER_PROP */ + memcpy(cmd.args, "\x14\x00\x08\x06\xf8\x00", 6); + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + + /* ATV restart */ + memcpy(cmd.args, "\x51\x00", 2); + cmd.wlen = 2; + cmd.rlen = 1; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + + usleep_range(10000, 11000); + + /* 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 */ diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h index 8579e80f7af7..aaada2bb0f21 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h @@ -72,7 +72,8 @@ struct si2157_cmd { ((dev)->part_id == SI2177)) #define SUPPORTS_ATV_IF(dev) (((dev)->part_id == SI2157) || \ - ((dev)->part_id == SI2158)) + ((dev)->part_id == SI2158) || \ + ((dev)->part_id == SI2177)) /* Old firmware namespace */ #define SI2158_A20_FIRMWARE "dvb-tuner-si2158-a20-01.fw"