* [PATCH 0/4] wintv 930c-hd: Add basic support
@ 2014-07-01 19:55 Matthias Schwarzott
2014-07-01 19:55 ` [PATCH 1/4] get_dvb_firmware: Add firmware extractor for si2165 Matthias Schwarzott
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Matthias Schwarzott @ 2014-07-01 19:55 UTC (permalink / raw)
To: linux-media, crope
This patch series is the third version of my si2165 driver.
It supports only DVB-T and was tested on 8MHz channels in germany.
Maybe the si2165 driver also works on other si2165/si2163/si2161 based cards.
Regards
Matthias
Documentation/dvb/get_dvb_firmware | 33 +-
drivers/media/dvb-frontends/Kconfig | 9 +
drivers/media/dvb-frontends/Makefile | 1 +
drivers/media/dvb-frontends/si2165.c | 1036 ++++++++++++++++++++++++++++
drivers/media/dvb-frontends/si2165.h | 61 ++
drivers/media/dvb-frontends/si2165_priv.h | 23 +
drivers/media/pci/cx23885/Kconfig | 1 +
drivers/media/pci/cx23885/cx23885-cards.c | 17 +-
drivers/media/pci/cx23885/cx23885-dvb.c | 43 +-
drivers/media/usb/cx231xx/Kconfig | 1 +
drivers/media/usb/cx231xx/cx231xx-avcore.c | 1 +
drivers/media/usb/cx231xx/cx231xx-cards.c | 92 +++
drivers/media/usb/cx231xx/cx231xx-core.c | 3 +
drivers/media/usb/cx231xx/cx231xx-dvb.c | 32 +
drivers/media/usb/cx231xx/cx231xx.h | 1 +
15 files changed, 1345 insertions(+), 9 deletions(-)
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/4] get_dvb_firmware: Add firmware extractor for si2165
2014-07-01 19:55 [PATCH 0/4] wintv 930c-hd: Add basic support Matthias Schwarzott
@ 2014-07-01 19:55 ` Matthias Schwarzott
2014-07-01 19:55 ` [PATCH 2/4] si2165: Add demod driver for DVB-T only Matthias Schwarzott
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Matthias Schwarzott @ 2014-07-01 19:55 UTC (permalink / raw)
To: linux-media, crope; +Cc: Matthias Schwarzott
Signed-off-by: Matthias Schwarzott <zzam@gentoo.org>
---
Documentation/dvb/get_dvb_firmware | 33 ++++++++++++++++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index d91b8be..26c623d 100755
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -29,7 +29,7 @@ use IO::Handle;
"af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395",
"lme2510c_s7395_old", "drxk", "drxk_terratec_h5",
"drxk_hauppauge_hvr930c", "tda10071", "it9135", "drxk_pctv",
- "drxk_terratec_htc_stick", "sms1xxx_hcw");
+ "drxk_terratec_htc_stick", "sms1xxx_hcw", "si2165");
# Check args
syntax() if (scalar(@ARGV) != 1);
@@ -783,6 +783,37 @@ sub sms1xxx_hcw {
$allfiles;
}
+sub si2165 {
+ my $sourcefile = "model_111xxx_122xxx_driver_6_0_119_31191_WHQL.zip";
+ my $url = "http://www.hauppauge.de/files/drivers/";
+ my $hash = "76633e7c76b0edee47c3ba18ded99336";
+ my $fwfile = "dvb-demod-si2165.fw";
+ my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+ checkstandard();
+
+ wgetfile($sourcefile, $url . $sourcefile);
+ verify($sourcefile, $hash);
+ unzip($sourcefile, $tmpdir);
+ extract("$tmpdir/Driver10/Hcw10bda.sys", 0x80788, 0x81E08-0x80788, "$tmpdir/fw1");
+
+ delzero("$tmpdir/fw1","$tmpdir/fw1-1");
+ #verify("$tmpdir/fw1","5e0909858fdf0b5b09ad48b9fe622e70");
+
+ my $CRC="\x0A\xCC";
+ my $BLOCKS_MAIN="\x27";
+ open FW,">$fwfile";
+ print FW "\x01\x00"; # just a version id for the driver itself
+ print FW "\x9A"; # fw version
+ print FW "\x00"; # padding
+ print FW "$BLOCKS_MAIN"; # number of blocks of main part
+ print FW "\x00"; # padding
+ print FW "$CRC"; # 16bit crc value of main part
+ appendfile(FW,"$tmpdir/fw1");
+
+ "$fwfile";
+}
+
# ---------------------------------------------------------------
# Utilities
--
2.0.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/4] si2165: Add demod driver for DVB-T only
2014-07-01 19:55 [PATCH 0/4] wintv 930c-hd: Add basic support Matthias Schwarzott
2014-07-01 19:55 ` [PATCH 1/4] get_dvb_firmware: Add firmware extractor for si2165 Matthias Schwarzott
@ 2014-07-01 19:55 ` Matthias Schwarzott
2014-07-01 19:55 ` [PATCH 3/4] cx231xx: Add [2040:b130] Hauppauge WinTV 930C-hd 1113xx Matthias Schwarzott
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Matthias Schwarzott @ 2014-07-01 19:55 UTC (permalink / raw)
To: linux-media, crope; +Cc: Matthias Schwarzott
DVB-T was tested with 8MHz BW channels in germany
This driver is the simplest possible, it uses automatic mode for all
parameters (TPS).
Signed-off-by: Matthias Schwarzott <zzam@gentoo.org>
---
drivers/media/dvb-frontends/Kconfig | 9 +
drivers/media/dvb-frontends/Makefile | 1 +
drivers/media/dvb-frontends/si2165.c | 1036 +++++++++++++++++++++++++++++
drivers/media/dvb-frontends/si2165.h | 61 ++
drivers/media/dvb-frontends/si2165_priv.h | 23 +
5 files changed, 1130 insertions(+)
create mode 100644 drivers/media/dvb-frontends/si2165.c
create mode 100644 drivers/media/dvb-frontends/si2165.h
create mode 100644 drivers/media/dvb-frontends/si2165_priv.h
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 1469d44..0da53c2 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -63,6 +63,15 @@ config DVB_TDA18271C2DD
Say Y when you want to support this tuner.
+config DVB_SI2165
+ tristate "Silicon Labs si2165 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-C/T demodulator.
+
+ Say Y when you want to support this frontend.
+
comment "DVB-S (satellite) frontends"
depends on DVB_CORE
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index dda0bee..595dd8d 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -100,6 +100,7 @@ obj-$(CONFIG_DVB_STV0367) += stv0367.o
obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
obj-$(CONFIG_DVB_DRXK) += drxk.o
obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
+obj-$(CONFIG_DVB_SI2165) += si2165.o
obj-$(CONFIG_DVB_A8293) += a8293.o
obj-$(CONFIG_DVB_TDA10071) += tda10071.o
obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c
new file mode 100644
index 0000000..bc122e4
--- /dev/null
+++ b/drivers/media/dvb-frontends/si2165.c
@@ -0,0 +1,1036 @@
+/*
+ Driver for Silicon Labs SI2165 DVB-C/-T Demodulator
+
+ Copyright (C) 2013-2014 Matthias Schwarzott <zzam@gentoo.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ References:
+ http://www.silabs.com/Support%20Documents/TechnicalDocs/Si2165-short.pdf
+*/
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+
+#include "dvb_frontend.h"
+#include "dvb_math.h"
+#include "si2165_priv.h"
+#include "si2165.h"
+
+/* Hauppauge WinTV-HVR-930C-HD B130 / PCTV QuatroStick 521e 1113xx
+ * uses 16 MHz xtal */
+
+/* Hauppauge WinTV-HVR-930C-HD B131 / PCTV QuatroStick 522e 1114xx
+ * uses 24 MHz clock provided by tuner */
+
+struct si2165_state {
+ struct i2c_adapter *i2c;
+
+ struct dvb_frontend frontend;
+
+ struct si2165_config config;
+
+ /* chip revision */
+ u8 revcode;
+ /* chip type */
+ u8 chip_type;
+
+ /* calculated by xtal and div settings */
+ u32 fvco_hz;
+ u32 sys_clk;
+ u32 adc_clk;
+
+ bool has_dvbc;
+ bool has_dvbt;
+ bool firmware_loaded;
+};
+
+#define DEBUG_OTHER 0x01
+#define DEBUG_I2C_WRITE 0x02
+#define DEBUG_I2C_READ 0x04
+#define DEBUG_REG_READ 0x08
+#define DEBUG_REG_WRITE 0x10
+#define DEBUG_FW_LOAD 0x20
+
+static int debug = 0x00;
+
+#define dprintk(args...) \
+ do { \
+ if (debug & DEBUG_OTHER) \
+ printk(KERN_DEBUG "si2165: " args); \
+ } while (0)
+
+#define deb_i2c_write(args...) \
+ do { \
+ if (debug & DEBUG_I2C_WRITE) \
+ printk(KERN_DEBUG "si2165: i2c write: " args); \
+ } while (0)
+
+#define deb_i2c_read(args...) \
+ do { \
+ if (debug & DEBUG_I2C_READ) \
+ printk(KERN_DEBUG "si2165: i2c read: " args); \
+ } while (0)
+
+#define deb_readreg(args...) \
+ do { \
+ if (debug & DEBUG_REG_READ) \
+ printk(KERN_DEBUG "si2165: reg read: " args); \
+ } while (0)
+
+#define deb_writereg(args...) \
+ do { \
+ if (debug & DEBUG_REG_WRITE) \
+ printk(KERN_DEBUG "si2165: reg write: " args); \
+ } while (0)
+
+#define deb_fw_load(args...) \
+ do { \
+ if (debug & DEBUG_FW_LOAD) \
+ printk(KERN_DEBUG "si2165: fw load: " args); \
+ } while (0)
+
+static int si2165_write(struct si2165_state *state, const u16 reg,
+ const u8 *src, const int count)
+{
+ int ret;
+ struct i2c_msg msg;
+ u8 buf[2 + 4]; /* write a maximum of 4 bytes of data */
+
+ if (count + 2 > sizeof(buf)) {
+ dev_warn(&state->i2c->dev,
+ "%s: i2c wr reg=%04x: count=%d is too big!\n",
+ KBUILD_MODNAME, reg, count);
+ return -EINVAL;
+ }
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xff;
+ memcpy(buf + 2, src, count);
+
+ msg.addr = state->config.i2c_addr;
+ msg.flags = 0;
+ msg.buf = buf;
+ msg.len = count + 2;
+
+ if (debug & DEBUG_I2C_WRITE)
+ deb_i2c_write("reg: 0x%04x, data: %*ph\n", reg, count, src);
+
+ ret = i2c_transfer(state->i2c, &msg, 1);
+
+ if (ret != 1) {
+ dev_err(&state->i2c->dev, "%s: ret == %d\n", __func__, ret);
+ if (ret < 0)
+ return ret;
+ else
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int si2165_read(struct si2165_state *state,
+ const u16 reg, u8 *val, const int count)
+{
+ int ret;
+ u8 reg_buf[] = { reg >> 8, reg & 0xff };
+ struct i2c_msg msg[] = {
+ { .addr = state->config.i2c_addr,
+ .flags = 0, .buf = reg_buf, .len = 2 },
+ { .addr = state->config.i2c_addr,
+ .flags = I2C_M_RD, .buf = val, .len = count },
+ };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2) {
+ dev_err(&state->i2c->dev, "%s: error (addr %02x reg %04x error (ret == %i)\n",
+ __func__, state->config.i2c_addr, reg, ret);
+ if (ret < 0)
+ return ret;
+ else
+ return -EREMOTEIO;
+ }
+
+ if (debug & DEBUG_I2C_READ)
+ deb_i2c_read("reg: 0x%04x, data: %*ph\n", reg, count, val);
+
+ return 0;
+}
+
+static int si2165_readreg8(struct si2165_state *state,
+ const u16 reg, u8 *val)
+{
+ int ret;
+
+ ret = si2165_read(state, reg, val, 1);
+ deb_readreg("R(0x%04x)=0x%02x\n", reg, *val);
+ return ret;
+}
+
+static int si2165_readreg16(struct si2165_state *state,
+ const u16 reg, u16 *val)
+{
+ u8 buf[2];
+
+ int ret = si2165_read(state, reg, buf, 2);
+ *val = buf[0] | buf[1] << 8;
+ deb_readreg("R(0x%04x)=0x%04x\n", reg, *val);
+ return ret;
+}
+
+static int si2165_writereg8(struct si2165_state *state, const u16 reg, u8 val)
+{
+ return si2165_write(state, reg, &val, 1);
+}
+
+static int si2165_writereg16(struct si2165_state *state, const u16 reg, u16 val)
+{
+ u8 buf[2] = { val & 0xff, (val >> 8) & 0xff };
+
+ return si2165_write(state, reg, buf, 2);
+}
+
+static int si2165_writereg24(struct si2165_state *state, const u16 reg, u32 val)
+{
+ u8 buf[3] = { val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff };
+
+ return si2165_write(state, reg, buf, 3);
+}
+
+static int si2165_writereg32(struct si2165_state *state, const u16 reg, u32 val)
+{
+ u8 buf[4] = {
+ val & 0xff,
+ (val >> 8) & 0xff,
+ (val >> 16) & 0xff,
+ (val >> 24) & 0xff
+ };
+ return si2165_write(state, reg, buf, 4);
+}
+
+static int si2165_writereg_mask8(struct si2165_state *state, const u16 reg,
+ u8 val, u8 mask)
+{
+ int ret;
+ u8 tmp;
+
+ if (mask != 0xff) {
+ ret = si2165_readreg8(state, reg, &tmp);
+ if (ret < 0)
+ goto err;
+
+ val &= mask;
+ tmp &= ~mask;
+ val |= tmp;
+ }
+
+ ret = si2165_writereg8(state, reg, val);
+err:
+ return ret;
+}
+
+static int si2165_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *s)
+{
+ s->min_delay_ms = 1000;
+ return 0;
+}
+
+static int si2165_init_pll(struct si2165_state *state)
+{
+ u32 ref_freq_Hz = state->config.ref_freq_Hz;
+ u8 divr = 1; /* 1..7 */
+ u8 divp = 1; /* only 1 or 4 */
+ u8 divn = 56; /* 1..63 */
+ u8 divm = 8;
+ u8 divl = 12;
+ u8 buf[4];
+
+ /* hardcoded values can be deleted if calculation is verified
+ * or it yields the same values as the windows driver */
+ switch (ref_freq_Hz) {
+ case 16000000u:
+ divn = 56;
+ break;
+ case 24000000u:
+ divr = 2;
+ divp = 4;
+ divn = 19;
+ break;
+ default:
+ /* ref_freq / divr must be between 4 and 16 MHz */
+ if (ref_freq_Hz > 16000000u)
+ divr = 2;
+
+ /* now select divn and divp such that
+ * fvco is in 1624..1824 MHz */
+ if (1624000000u * divr > ref_freq_Hz * 2u * 63u)
+ divp = 4;
+
+ /* is this already correct regarding rounding? */
+ divn = 1624000000u * divr / (ref_freq_Hz * 2u * divp);
+ break;
+ }
+
+ /* adc_clk and sys_clk depend on xtal and pll settings */
+ state->fvco_hz = ref_freq_Hz / divr
+ * 2u * divn * divp;
+ state->adc_clk = state->fvco_hz / (divm * 4u);
+ state->sys_clk = state->fvco_hz / (divl * 2u);
+
+ /* write pll registers 0x00a0..0x00a3 at once */
+ buf[0] = divl;
+ buf[1] = divm;
+ buf[2] = (divn & 0x3f) | ((divp == 1) ? 0x40 : 0x00) | 0x80;
+ buf[3] = divr;
+ return si2165_write(state, 0x00a0, buf, 4);
+}
+
+static int si2165_adjust_pll_divl(struct si2165_state *state, u8 divl)
+{
+ state->sys_clk = state->fvco_hz / (divl * 2u);
+ return si2165_writereg8(state, 0x00a0, divl); /* pll_divl */
+}
+
+static u32 si2165_get_fe_clk(struct si2165_state *state)
+{
+ /* assume Oversampling mode Ovr4 is used */
+ return state->adc_clk;
+}
+
+static bool si2165_wait_init_done(struct si2165_state *state)
+{
+ int ret = -EINVAL;
+ u8 val = 0;
+ int i;
+
+ for (i = 0; i < 3; ++i) {
+ si2165_readreg8(state, 0x0054, &val);
+ if (val == 0x01)
+ return 0;
+ usleep_range(1000, 50000);
+ }
+ dev_err(&state->i2c->dev, "%s: init_done was not set\n",
+ KBUILD_MODNAME);
+ return ret;
+}
+
+static int si2165_upload_firmware_block(struct si2165_state *state,
+ const u8 *data, u32 len, u32 *poffset, u32 block_count)
+{
+ int ret;
+ u8 buf_ctrl[4] = { 0x00, 0x00, 0x00, 0xc0 };
+ u8 wordcount;
+ u32 cur_block = 0;
+ u32 offset = poffset ? *poffset : 0;
+
+ if (len < 4)
+ return -EINVAL;
+ if (len % 4 != 0)
+ return -EINVAL;
+
+ deb_fw_load("si2165_upload_firmware_block called with len=0x%x offset=0x%x blockcount=0x%x\n",
+ len, offset, block_count);
+ while (offset+12 <= len && cur_block < block_count) {
+ deb_fw_load("si2165_upload_firmware_block in while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n",
+ len, offset, cur_block, block_count);
+ wordcount = data[offset];
+ if (wordcount < 1 || data[offset+1] ||
+ data[offset+2] || data[offset+3]) {
+ dev_warn(&state->i2c->dev,
+ "%s: bad fw data[0..3] = %*ph\n",
+ KBUILD_MODNAME, 4, data);
+ return -EINVAL;
+ }
+
+ if (offset + 8 + wordcount * 4 > len) {
+ dev_warn(&state->i2c->dev,
+ "%s: len is too small for block len=%d, wordcount=%d\n",
+ KBUILD_MODNAME, len, wordcount);
+ return -EINVAL;
+ }
+
+ buf_ctrl[0] = wordcount - 1;
+
+ ret = si2165_write(state, 0x0364, buf_ctrl, 4);
+ if (ret < 0)
+ goto error;
+ ret = si2165_write(state, 0x0368, data+offset+4, 4);
+ if (ret < 0)
+ goto error;
+
+ offset += 8;
+
+ while (wordcount > 0) {
+ ret = si2165_write(state, 0x36c, data+offset, 4);
+ if (ret < 0)
+ goto error;
+ wordcount--;
+ offset += 4;
+ }
+ cur_block++;
+ }
+
+ deb_fw_load("si2165_upload_firmware_block after while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n",
+ len, offset, cur_block, block_count);
+
+ if (poffset)
+ *poffset = offset;
+
+ deb_fw_load("si2165_upload_firmware_block returned offset=0x%x\n",
+ offset);
+
+ return 0;
+error:
+ return ret;
+}
+
+static int si2165_upload_firmware(struct si2165_state *state)
+{
+ /* int ret; */
+ u8 val[3];
+ u16 val16;
+ int ret;
+
+ const struct firmware *fw = NULL;
+ u8 *fw_file = SI2165_FIRMWARE;
+ const u8 *data;
+ u32 len;
+ u32 offset;
+ u8 patch_version;
+ u8 block_count;
+ u16 crc_expected;
+
+ /* request the firmware, this will block and timeout */
+ ret = request_firmware(&fw, fw_file, state->i2c->dev.parent);
+ if (ret) {
+ dev_warn(&state->i2c->dev, "%s: firmare file '%s' not found\n",
+ KBUILD_MODNAME, fw_file);
+ goto error;
+ }
+
+ data = fw->data;
+ len = fw->size;
+
+ dev_info(&state->i2c->dev, "%s: downloading firmware from file '%s' size=%d\n",
+ KBUILD_MODNAME, fw_file, len);
+
+ if (len % 4 != 0) {
+ dev_warn(&state->i2c->dev, "%s: firmware size is not multiple of 4\n",
+ KBUILD_MODNAME);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* check header (8 bytes) */
+ if (len < 8) {
+ dev_warn(&state->i2c->dev, "%s: firmware header is missing\n",
+ KBUILD_MODNAME);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (data[0] != 1 || data[1] != 0) {
+ dev_warn(&state->i2c->dev, "%s: firmware file version is wrong\n",
+ KBUILD_MODNAME);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ patch_version = data[2];
+ block_count = data[4];
+ crc_expected = data[7] << 8 | data[6];
+
+ /* start uploading fw */
+ /* boot/wdog status */
+ ret = si2165_writereg8(state, 0x0341, 0x00);
+ if (ret < 0)
+ goto error;
+ /* reset */
+ ret = si2165_writereg8(state, 0x00c0, 0x00);
+ if (ret < 0)
+ goto error;
+ /* boot/wdog status */
+ ret = si2165_readreg8(state, 0x0341, val);
+ if (ret < 0)
+ goto error;
+
+ /* enable reset on error */
+ ret = si2165_readreg8(state, 0x035c, val);
+ if (ret < 0)
+ goto error;
+ ret = si2165_readreg8(state, 0x035c, val);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x035c, 0x02);
+ if (ret < 0)
+ goto error;
+
+ /* start right after the header */
+ offset = 8;
+
+ dev_info(&state->i2c->dev, "%s: si2165_upload_firmware extracted patch_version=0x%02x, block_count=0x%02x, crc_expected=0x%04x\n",
+ KBUILD_MODNAME, patch_version, block_count, crc_expected);
+
+ ret = si2165_upload_firmware_block(state, data, len, &offset, 1);
+ if (ret < 0)
+ goto error;
+
+ ret = si2165_writereg8(state, 0x0344, patch_version);
+ if (ret < 0)
+ goto error;
+
+ /* reset crc */
+ ret = si2165_writereg8(state, 0x0379, 0x01);
+ if (ret)
+ return ret;
+
+ ret = si2165_upload_firmware_block(state, data, len,
+ &offset, block_count);
+ if (ret < 0) {
+ dev_err(&state->i2c->dev,
+ "%s: firmare could not be uploaded\n",
+ KBUILD_MODNAME);
+ goto error;
+ }
+
+ /* read crc */
+ ret = si2165_readreg16(state, 0x037a, &val16);
+ if (ret)
+ goto error;
+
+ if (val16 != crc_expected) {
+ dev_err(&state->i2c->dev,
+ "%s: firmware crc mismatch %04x != %04x\n",
+ KBUILD_MODNAME, val16, crc_expected);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = si2165_upload_firmware_block(state, data, len, &offset, 5);
+ if (ret)
+ goto error;
+
+ if (len != offset) {
+ dev_err(&state->i2c->dev,
+ "%s: firmare len mismatch %04x != %04x\n",
+ KBUILD_MODNAME, len, offset);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* reset watchdog error register */
+ ret = si2165_writereg_mask8(state, 0x0341, 0x02, 0x02);
+ if (ret < 0)
+ goto error;
+
+ /* enable reset on error */
+ ret = si2165_writereg_mask8(state, 0x035c, 0x01, 0x01);
+ if (ret < 0)
+ goto error;
+
+ dev_info(&state->i2c->dev, "%s: fw load finished\n", KBUILD_MODNAME);
+
+ ret = 0;
+ state->firmware_loaded = true;
+error:
+ if (fw) {
+ release_firmware(fw);
+ fw = NULL;
+ }
+
+ return ret;
+}
+
+static int si2165_init(struct dvb_frontend *fe)
+{
+ int ret = 0;
+ struct si2165_state *state = fe->demodulator_priv;
+ u8 val;
+ u8 patch_version = 0x00;
+
+ dprintk("%s: called\n", __func__);
+
+ /* powerup */
+ ret = si2165_writereg8(state, 0x0000, state->config.chip_mode);
+ if (ret < 0)
+ goto error;
+ /* dsp_clock_enable */
+ ret = si2165_writereg8(state, 0x0104, 0x01);
+ if (ret < 0)
+ goto error;
+ ret = si2165_readreg8(state, 0x0000, &val); /* verify chip_mode */
+ if (ret < 0)
+ goto error;
+ if (val != state->config.chip_mode) {
+ dev_err(&state->i2c->dev, "%s: could not set chip_mode\n",
+ KBUILD_MODNAME);
+ return -EINVAL;
+ }
+
+ /* agc */
+ ret = si2165_writereg8(state, 0x018b, 0x00);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x0190, 0x01);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x0170, 0x00);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x0171, 0x07);
+ if (ret < 0)
+ goto error;
+ /* rssi pad */
+ ret = si2165_writereg8(state, 0x0646, 0x00);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x0641, 0x00);
+ if (ret < 0)
+ goto error;
+
+ ret = si2165_init_pll(state);
+ if (ret < 0)
+ goto error;
+
+ /* enable chip_init */
+ ret = si2165_writereg8(state, 0x0050, 0x01);
+ if (ret < 0)
+ goto error;
+ /* set start_init */
+ ret = si2165_writereg8(state, 0x0096, 0x01);
+ if (ret < 0)
+ goto error;
+ ret = si2165_wait_init_done(state);
+ if (ret < 0)
+ goto error;
+
+ /* disable chip_init */
+ ret = si2165_writereg8(state, 0x0050, 0x00);
+ if (ret < 0)
+ goto error;
+
+ /* ber_pkt */
+ ret = si2165_writereg16(state, 0x0470 , 0x7530);
+ if (ret < 0)
+ goto error;
+
+ ret = si2165_readreg8(state, 0x0344, &patch_version);
+ if (ret < 0)
+ goto error;
+
+ ret = si2165_writereg8(state, 0x00cb, 0x00);
+ if (ret < 0)
+ goto error;
+
+ /* dsp_addr_jump */
+ ret = si2165_writereg32(state, 0x0348, 0xf4000000);
+ if (ret < 0)
+ goto error;
+ /* boot/wdog status */
+ ret = si2165_readreg8(state, 0x0341, &val);
+ if (ret < 0)
+ goto error;
+
+ if (patch_version == 0x00) {
+ ret = si2165_upload_firmware(state);
+ if (ret < 0)
+ goto error;
+ }
+
+ /* write adc values after each reset*/
+ ret = si2165_writereg8(state, 0x012a, 0x46);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x012c, 0x00);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x012e, 0x0a);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x012f, 0xff);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x0123, 0x70);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+error:
+ return ret;
+}
+
+static int si2165_sleep(struct dvb_frontend *fe)
+{
+ int ret;
+ struct si2165_state *state = fe->demodulator_priv;
+
+ /* dsp clock disable */
+ ret = si2165_writereg8(state, 0x0104, 0x00);
+ if (ret < 0)
+ return ret;
+ /* chip mode */
+ ret = si2165_writereg8(state, 0x0000, SI2165_MODE_OFF);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int si2165_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ int ret;
+ u8 fec_lock = 0;
+ struct si2165_state *state = fe->demodulator_priv;
+
+ if (!state->has_dvbt)
+ return -EINVAL;
+
+ /* check fec_lock */
+ ret = si2165_readreg8(state, 0x4e0, &fec_lock);
+ if (ret < 0)
+ return ret;
+ *status = 0;
+ if (fec_lock & 0x01) {
+ *status |= FE_HAS_SIGNAL;
+ *status |= FE_HAS_CARRIER;
+ *status |= FE_HAS_VITERBI;
+ *status |= FE_HAS_SYNC;
+ *status |= FE_HAS_LOCK;
+ }
+
+ return 0;
+}
+
+static int si2165_set_oversamp(struct si2165_state *state, u32 dvb_rate)
+{
+ u64 oversamp;
+ u32 reg_value;
+
+ oversamp = si2165_get_fe_clk(state);
+ oversamp <<= 23;
+ if (dvb_rate > 0)
+ oversamp /= (u64)dvb_rate;
+ reg_value = oversamp & 0x3fffffff;
+
+ /* oversamp, usbdump contained 0x03100000; */
+ return si2165_writereg32(state, 0x00e4, reg_value);
+}
+
+static int si2165_set_if_freq_shift(struct si2165_state *state, u32 IF)
+{
+ s64 if_freq_shift;
+ u32 reg_value;
+ u32 fe_clk = si2165_get_fe_clk(state);
+
+ if_freq_shift = IF;
+ if_freq_shift <<= 29;
+ if (fe_clk > 0)
+ if_freq_shift /= (u64)fe_clk;
+ reg_value = ((u32)if_freq_shift) & 0x1fffffff;
+
+ /* if_freq_shift, usbdump contained 0x023ee08f; */
+ return si2165_writereg32(state, 0x00e8, reg_value);
+}
+
+static int si2165_set_parameters(struct dvb_frontend *fe)
+{
+ int ret;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ struct si2165_state *state = fe->demodulator_priv;
+ u8 val[3];
+ u32 IF;
+ u32 dvb_rate = 0;
+ u16 bw10k;
+
+ dprintk("%s: called\n", __func__);
+
+ if (!fe->ops.tuner_ops.get_if_frequency) {
+ dev_err(&state->i2c->dev,
+ "%s: Error: get_if_frequency() not defined at tuner. Can't work without it!\n",
+ KBUILD_MODNAME);
+ return -EINVAL;
+ }
+
+ if (!state->has_dvbt)
+ return -EINVAL;
+
+ if (p->bandwidth_hz > 0) {
+ dvb_rate = p->bandwidth_hz * 8 / 7;
+ bw10k = p->bandwidth_hz / 10000;
+ } else {
+ dvb_rate = 8 * 8 / 7;
+ bw10k = 800;
+ }
+
+ /* standard = DVB-T */
+ ret = si2165_writereg8(state, 0x00ec, 0x01);
+ if (ret < 0)
+ return ret;
+ ret = si2165_adjust_pll_divl(state, 12);
+ if (ret < 0)
+ return ret;
+
+ fe->ops.tuner_ops.get_if_frequency(fe, &IF);
+ ret = si2165_set_if_freq_shift(state, IF);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x08f8, 0x00);
+ if (ret < 0)
+ return ret;
+ /* ts output config */
+ ret = si2165_writereg8(state, 0x04e4, 0x20);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg16(state, 0x04ef, 0x00fe);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg24(state, 0x04f4, 0x555555);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x04e5, 0x01);
+ if (ret < 0)
+ return ret;
+ /* bandwidth in 10KHz steps */
+ ret = si2165_writereg16(state, 0x0308, bw10k);
+ if (ret < 0)
+ return ret;
+ ret = si2165_set_oversamp(state, dvb_rate);
+ if (ret < 0)
+ return ret;
+ /* impulsive_noise_remover */
+ ret = si2165_writereg8(state, 0x031c, 0x01);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x00cb, 0x00);
+ if (ret < 0)
+ return ret;
+ /* agc2 */
+ ret = si2165_writereg8(state, 0x016e, 0x41);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x016c, 0x0e);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x016d, 0x10);
+ if (ret < 0)
+ return ret;
+ /* agc */
+ ret = si2165_writereg8(state, 0x015b, 0x03);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x0150, 0x78);
+ if (ret < 0)
+ return ret;
+ /* agc */
+ ret = si2165_writereg8(state, 0x01a0, 0x78);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x01c8, 0x68);
+ if (ret < 0)
+ return ret;
+ /* freq_sync_range */
+ ret = si2165_writereg16(state, 0x030c, 0x0064);
+ if (ret < 0)
+ return ret;
+ /* gp_reg0 */
+ ret = si2165_readreg8(state, 0x0387, val);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x0387, 0x00);
+ if (ret < 0)
+ return ret;
+ /* dsp_addr_jump */
+ ret = si2165_writereg32(state, 0x0348, 0xf4000000);
+ if (ret < 0)
+ return ret;
+
+ if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe);
+
+ /* recalc if_freq_shift if IF might has changed */
+ fe->ops.tuner_ops.get_if_frequency(fe, &IF);
+ ret = si2165_set_if_freq_shift(state, IF);
+ if (ret < 0)
+ return ret;
+
+ /* boot/wdog status */
+ ret = si2165_readreg8(state, 0x0341, val);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x0341, 0x00);
+ if (ret < 0)
+ return ret;
+ /* reset all */
+ ret = si2165_writereg8(state, 0x00c0, 0x00);
+ if (ret < 0)
+ return ret;
+ /* gp_reg0 */
+ ret = si2165_writereg32(state, 0x0384, 0x00000000);
+ if (ret < 0)
+ return ret;
+ /* start_synchro */
+ ret = si2165_writereg8(state, 0x02e0, 0x01);
+ if (ret < 0)
+ return ret;
+ /* boot/wdog status */
+ ret = si2165_readreg8(state, 0x0341, val);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static void si2165_release(struct dvb_frontend *fe)
+{
+ struct si2165_state *state = fe->demodulator_priv;
+
+ dprintk("%s: called\n", __func__);
+ kfree(state);
+}
+
+static struct dvb_frontend_ops si2165_ops = {
+ .info = {
+ .name = "Silicon Labs Si2165",
+ .caps = FE_CAN_FEC_1_2 |
+ FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 |
+ FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK |
+ FE_CAN_QAM_16 |
+ FE_CAN_QAM_32 |
+ FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 |
+ FE_CAN_QAM_256 |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO |
+ FE_CAN_MUTE_TS |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_RECOVER
+ },
+
+ .get_tune_settings = si2165_get_tune_settings,
+
+ .init = si2165_init,
+ .sleep = si2165_sleep,
+
+ .set_frontend = si2165_set_parameters,
+ .read_status = si2165_read_status,
+
+ .release = si2165_release,
+};
+
+struct dvb_frontend *si2165_attach(const struct si2165_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct si2165_state *state = NULL;
+ int n;
+ int io_ret;
+ u8 val;
+
+ if (config == NULL || i2c == NULL)
+ goto error;
+
+ /* allocate memory for the internal state */
+ state = kzalloc(sizeof(struct si2165_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* setup the state */
+ state->i2c = i2c;
+ state->config = *config;
+
+ if (state->config.ref_freq_Hz < 4000000
+ || state->config.ref_freq_Hz > 27000000) {
+ dev_err(&state->i2c->dev, "%s: ref_freq of %d Hz not supported by this driver\n",
+ KBUILD_MODNAME, state->config.ref_freq_Hz);
+ goto error;
+ }
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &si2165_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
+ /* powerup */
+ io_ret = si2165_writereg8(state, 0x0000, state->config.chip_mode);
+ if (io_ret < 0)
+ goto error;
+
+ io_ret = si2165_readreg8(state, 0x0000, &val);
+ if (io_ret < 0)
+ goto error;
+ if (val != state->config.chip_mode)
+ goto error;
+
+ io_ret = si2165_readreg8(state, 0x0023 , &state->revcode);
+ if (io_ret < 0)
+ goto error;
+
+ io_ret = si2165_readreg8(state, 0x0118, &state->chip_type);
+ if (io_ret < 0)
+ goto error;
+
+ /* powerdown */
+ io_ret = si2165_writereg8(state, 0x0000, SI2165_MODE_OFF);
+ if (io_ret < 0)
+ goto error;
+
+ dev_info(&state->i2c->dev, "%s: hardware revision 0x%02x, chip type 0x%02x\n",
+ KBUILD_MODNAME, state->revcode, state->chip_type);
+
+ /* It is a guess that register 0x0118 (chip type?) can be used to
+ * differ between si2161, si2163 and si2165
+ * Only si2165 has been tested.
+ */
+ if (state->revcode == 0x03 && state->chip_type == 0x07) {
+ state->has_dvbt = true;
+ state->has_dvbc = true;
+ } else {
+ dev_err(&state->i2c->dev, "%s: Unsupported chip.\n",
+ KBUILD_MODNAME);
+ goto error;
+ }
+
+ n = 0;
+ if (state->has_dvbt) {
+ state->frontend.ops.delsys[n++] = SYS_DVBT;
+ strlcat(state->frontend.ops.info.name, " DVB-T",
+ sizeof(state->frontend.ops.info.name));
+ }
+ if (state->has_dvbc)
+ dev_warn(&state->i2c->dev, "%s: DVB-C is not yet supported.\n",
+ KBUILD_MODNAME);
+
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(si2165_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Silicon Labs Si2165 DVB-C/-T Demodulator driver");
+MODULE_AUTHOR("Matthias Schwarzott <zzam@gentoo.org>");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(SI2165_FIRMWARE);
diff --git a/drivers/media/dvb-frontends/si2165.h b/drivers/media/dvb-frontends/si2165.h
new file mode 100644
index 0000000..3aae834
--- /dev/null
+++ b/drivers/media/dvb-frontends/si2165.h
@@ -0,0 +1,61 @@
+/*
+ Driver for Silicon Labs SI2165 DVB-C/-T Demodulator
+
+ Copyright (C) 2013-2014 Matthias Schwarzott <zzam@gentoo.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ References:
+ http://www.silabs.com/Support%20Documents/TechnicalDocs/Si2165-short.pdf
+*/
+
+#ifndef _DVB_SI2165_H
+#define _DVB_SI2165_H
+
+#include <linux/dvb/frontend.h>
+
+#if IS_ENABLED(CONFIG_DVB_SI2165)
+
+enum {
+ SI2165_MODE_OFF = 0x00,
+ SI2165_MODE_PLL_EXT = 0x20,
+ SI2165_MODE_PLL_XTAL = 0x21
+};
+
+struct si2165_config {
+ /* i2c addr
+ * possible values: 0x64,0x65,0x66,0x67 */
+ u8 i2c_addr;
+
+ /* external clock or XTAL */
+ u8 chip_mode;
+
+ /* frequency of external clock or xtal in Hz
+ * possible values: 4000000, 16000000, 20000000, 240000000, 27000000
+ */
+ u32 ref_freq_Hz;
+};
+
+/* Addresses: 0x64,0x65,0x66,0x67 */
+struct dvb_frontend *si2165_attach(
+ const struct si2165_config *config,
+ struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *si2165_attach(
+ const struct si2165_config *config,
+ struct i2c_adapter *i2c)
+{
+ pr_warn("%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_SI2165 */
+
+#endif /* _DVB_SI2165_H */
diff --git a/drivers/media/dvb-frontends/si2165_priv.h b/drivers/media/dvb-frontends/si2165_priv.h
new file mode 100644
index 0000000..d4cc93f
--- /dev/null
+++ b/drivers/media/dvb-frontends/si2165_priv.h
@@ -0,0 +1,23 @@
+/*
+ Driver for Silicon Labs SI2165 DVB-C/-T Demodulator
+
+ Copyright (C) 2013-2014 Matthias Schwarzott <zzam@gentoo.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef _DVB_SI2165_PRIV
+#define _DVB_SI2165_PRIV
+
+#define SI2165_FIRMWARE "dvb-demod-si2165.fw"
+
+#endif /* _DVB_SI2165_PRIV */
--
2.0.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/4] cx231xx: Add [2040:b130] Hauppauge WinTV 930C-hd 1113xx
2014-07-01 19:55 [PATCH 0/4] wintv 930c-hd: Add basic support Matthias Schwarzott
2014-07-01 19:55 ` [PATCH 1/4] get_dvb_firmware: Add firmware extractor for si2165 Matthias Schwarzott
2014-07-01 19:55 ` [PATCH 2/4] si2165: Add demod driver for DVB-T only Matthias Schwarzott
@ 2014-07-01 19:55 ` Matthias Schwarzott
2014-07-01 19:55 ` [PATCH 4/4] cx23885: Add si2165 support for HVR-5500 Matthias Schwarzott
2014-07-02 5:27 ` [PATCH 0/4] wintv 930c-hd: Add basic support Matthias Schwarzott
4 siblings, 0 replies; 6+ messages in thread
From: Matthias Schwarzott @ 2014-07-01 19:55 UTC (permalink / raw)
To: linux-media, crope; +Cc: Matthias Schwarzott
Reading eeprom works
TODO:
* Analog is untested
* after loading the driver the first open to dvb device node fails
Signed-off-by: Matthias Schwarzott <zzam@gentoo.org>
---
drivers/media/usb/cx231xx/Kconfig | 1 +
drivers/media/usb/cx231xx/cx231xx-avcore.c | 1 +
drivers/media/usb/cx231xx/cx231xx-cards.c | 92 ++++++++++++++++++++++++++++++
drivers/media/usb/cx231xx/cx231xx-core.c | 3 +
drivers/media/usb/cx231xx/cx231xx-dvb.c | 32 +++++++++++
drivers/media/usb/cx231xx/cx231xx.h | 1 +
6 files changed, 130 insertions(+)
diff --git a/drivers/media/usb/cx231xx/Kconfig b/drivers/media/usb/cx231xx/Kconfig
index f14c5e8..036454e 100644
--- a/drivers/media/usb/cx231xx/Kconfig
+++ b/drivers/media/usb/cx231xx/Kconfig
@@ -47,6 +47,7 @@ config VIDEO_CX231XX_DVB
select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT
select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_SI2165 if MEDIA_SUBDRV_AUTOSELECT
---help---
This adds support for DVB cards based on the
diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c
index 89de00b..a428c10 100644
--- a/drivers/media/usb/cx231xx/cx231xx-avcore.c
+++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c
@@ -352,6 +352,7 @@ int cx231xx_afe_update_power_control(struct cx231xx *dev,
case CX231XX_BOARD_CNXT_RDU_253S:
case CX231XX_BOARD_CNXT_VIDEO_GRABBER:
case CX231XX_BOARD_HAUPPAUGE_EXETER:
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx:
case CX231XX_BOARD_HAUPPAUGE_USBLIVE2:
case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index 2ee03e4..8b80f88 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -704,6 +704,45 @@ struct cx231xx_board cx231xx_boards[] = {
}
},
},
+ [CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx] = {
+ .name = "Hauppauge WinTV 930C-HD (1113xx)",
+ .tuner_type = TUNER_NXP_TDA18271,
+ .tuner_addr = 0x60,
+ .tuner_gpio = RDE250_XCV_TUNER,
+ .tuner_sif_gpio = 0x05,
+ .tuner_scl_gpio = 0x1a,
+ .tuner_sda_gpio = 0x1b,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x0c,
+ .gpio_pin_status_mask = 0x4001000,
+ .tuner_i2c_master = 1,
+ .demod_i2c_master = 2,
+ .has_dvb = 1,
+ .demod_addr = 0x0e,
+ .norm = V4L2_STD_PAL,
+
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_3_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ } },
+ },
};
const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
@@ -733,6 +772,8 @@ struct usb_device_id cx231xx_id_table[] = {
.driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC},
{USB_DEVICE(0x2040, 0xb120),
.driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
+ {USB_DEVICE(0x2040, 0xb130),
+ .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx},
{USB_DEVICE(0x2040, 0xb140),
.driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
{USB_DEVICE(0x2040, 0xc200),
@@ -886,6 +927,43 @@ static void cx231xx_config_tuner(struct cx231xx *dev)
}
+static int read_eeprom(struct cx231xx *dev, u8 *eedata, int len)
+{
+ int ret = 0;
+ u8 addr = 0xa0 >> 1;
+ u8 start_offset = 0;
+ int len_todo = len;
+ u8 *eedata_cur = eedata;
+ int i;
+ struct i2c_msg msg_write = { .addr = addr, .flags = 0,
+ .buf = &start_offset, .len = 1 };
+ struct i2c_msg msg_read = { .addr = addr, .flags = I2C_M_RD };
+
+ /* mutex_lock(&dev->i2c_lock); */
+ cx231xx_enable_i2c_port_3(dev, false);
+
+ /* start reading at offset 0 */
+ ret = i2c_transfer(&dev->i2c_bus[1].i2c_adap, &msg_write, 1);
+
+ while (len_todo > 0) {
+ msg_read.len = (len_todo > 64) ? 64 : len_todo;
+ msg_read.buf = eedata_cur;
+
+ ret = i2c_transfer(&dev->i2c_bus[1].i2c_adap, &msg_read, 1);
+
+ eedata_cur += msg_read.len;
+ len_todo -= msg_read.len;
+ }
+
+ cx231xx_enable_i2c_port_3(dev, true);
+ /* mutex_unlock(&dev->i2c_lock); */
+
+ for (i = 0; i + 15 < len; i += 16)
+ cx231xx_info("i2c eeprom %02x: %*ph\n", i, 16, &eedata[i]);
+
+ return 0;
+}
+
void cx231xx_card_setup(struct cx231xx *dev)
{
@@ -917,6 +995,20 @@ void cx231xx_card_setup(struct cx231xx *dev)
else
cx231xx_config_tuner(dev);
}
+
+ switch (dev->model) {
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx:
+ {
+ struct tveeprom tvee;
+ static u8 eeprom[256];
+
+ read_eeprom(dev, eeprom, sizeof(eeprom));
+ tveeprom_hauppauge_analog(&dev->i2c_bus[1].i2c_client,
+ &tvee, eeprom + 0xc0);
+ break;
+ }
+ }
+
}
/*
diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c
index 4ba3ce0..513194a 100644
--- a/drivers/media/usb/cx231xx/cx231xx-core.c
+++ b/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -726,6 +726,7 @@ int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode)
errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1);
break;
case CX231XX_BOARD_HAUPPAUGE_EXETER:
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx:
errCode = cx231xx_set_power_mode(dev,
POLARIS_AVMODE_DIGITAL);
break;
@@ -744,6 +745,7 @@ int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode)
case CX231XX_BOARD_CNXT_RDE_253S:
case CX231XX_BOARD_CNXT_RDU_253S:
case CX231XX_BOARD_HAUPPAUGE_EXETER:
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx:
case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
@@ -1379,6 +1381,7 @@ int cx231xx_dev_init(struct cx231xx *dev)
case CX231XX_BOARD_CNXT_RDE_253S:
case CX231XX_BOARD_CNXT_RDU_253S:
case CX231XX_BOARD_HAUPPAUGE_EXETER:
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx:
case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index 4504bc6..cbc63e7 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -32,6 +32,7 @@
#include "tda18271.h"
#include "s5h1411.h"
#include "lgdt3305.h"
+#include "si2165.h"
#include "mb86a20s.h"
MODULE_DESCRIPTION("driver for cx231xx based DVB cards");
@@ -151,6 +152,12 @@ static struct tda18271_config pv_tda18271_config = {
.small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
};
+static const struct si2165_config hauppauge_930C_HD_1113xx_si2165_config = {
+ .i2c_addr = 0x64,
+ .chip_mode = SI2165_MODE_PLL_XTAL,
+ .ref_freq_Hz = 16000000,
+};
+
static inline void print_err_status(struct cx231xx *dev, int packet, int status)
{
char *errmsg = "Unknown";
@@ -704,6 +711,31 @@ static int dvb_init(struct cx231xx *dev)
&hcw_tda18271_config);
break;
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx:
+
+ dev->dvb->frontend = dvb_attach(si2165_attach,
+ &hauppauge_930C_HD_1113xx_si2165_config,
+ &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap
+ );
+
+ if (dev->dvb->frontend == NULL) {
+ printk(DRIVER_NAME
+ ": Failed to attach SI2165 front end\n");
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ dev->dvb->frontend->ops.i2c_gate_ctrl = 0;
+
+ /* define general-purpose callback pointer */
+ dvb->frontend->callback = cx231xx_tuner_callback;
+
+ dvb_attach(tda18271_attach, dev->dvb->frontend,
+ 0x60,
+ &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ &hcw_tda18271_config);
+ break;
+
case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
case CX231XX_BOARD_KWORLD_UB430_USB_HYBRID:
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index babca7f..a6373ba 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -73,6 +73,7 @@
#define CX231XX_BOARD_ELGATO_VIDEO_CAPTURE_V2 16
#define CX231XX_BOARD_OTG102 17
#define CX231XX_BOARD_KWORLD_UB445_USB_HYBRID 18
+#define CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx 19
/* Limits minimum and default number of buffers */
#define CX231XX_MIN_BUF 4
--
2.0.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 4/4] cx23885: Add si2165 support for HVR-5500
2014-07-01 19:55 [PATCH 0/4] wintv 930c-hd: Add basic support Matthias Schwarzott
` (2 preceding siblings ...)
2014-07-01 19:55 ` [PATCH 3/4] cx231xx: Add [2040:b130] Hauppauge WinTV 930C-hd 1113xx Matthias Schwarzott
@ 2014-07-01 19:55 ` Matthias Schwarzott
2014-07-02 5:27 ` [PATCH 0/4] wintv 930c-hd: Add basic support Matthias Schwarzott
4 siblings, 0 replies; 6+ messages in thread
From: Matthias Schwarzott @ 2014-07-01 19:55 UTC (permalink / raw)
To: linux-media, crope; +Cc: Matthias Schwarzott
The same card entry is used for HVR-4400 and HVR-5500.
Only HVR-5500 has been tested.
Signed-off-by: Matthias Schwarzott <zzam@gentoo.org>
---
drivers/media/pci/cx23885/Kconfig | 1 +
drivers/media/pci/cx23885/cx23885-cards.c | 17 +++++++++---
drivers/media/pci/cx23885/cx23885-dvb.c | 43 +++++++++++++++++++++++++++----
3 files changed, 53 insertions(+), 8 deletions(-)
diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig
index d1dcb1d..6cd1db2 100644
--- a/drivers/media/pci/cx23885/Kconfig
+++ b/drivers/media/pci/cx23885/Kconfig
@@ -31,6 +31,7 @@ config VIDEO_CX23885
select DVB_TDA10071 if MEDIA_SUBDRV_AUTOSELECT
select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT
select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_SI2165 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c
index 79f20c8..6ed0551 100644
--- a/drivers/media/pci/cx23885/cx23885-cards.c
+++ b/drivers/media/pci/cx23885/cx23885-cards.c
@@ -619,7 +619,12 @@ struct cx23885_board cx23885_boards[] = {
},
[CX23885_BOARD_HAUPPAUGE_HVR4400] = {
.name = "Hauppauge WinTV-HVR4400",
+ .porta = CX23885_ANALOG_VIDEO,
.portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ .tuner_type = TUNER_NXP_TDA18271,
+ .tuner_addr = 0x60, /* 0xc0 >> 1 */
+ .tuner_bus = 1,
},
[CX23885_BOARD_AVERMEDIA_HC81R] = {
.name = "AVerTV Hybrid Express Slim HC81R",
@@ -1449,13 +1454,16 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
break;
case CX23885_BOARD_HAUPPAUGE_HVR4400:
/* GPIO-8 tda10071 demod reset */
+ /* GPIO-9 si2165 demod reset */
/* Put the parts into reset and back */
- cx23885_gpio_enable(dev, GPIO_8, 1);
- cx23885_gpio_clear(dev, GPIO_8);
+ cx23885_gpio_enable(dev, GPIO_8 | GPIO_9, 1);
+
+ cx23885_gpio_clear(dev, GPIO_8 | GPIO_9);
mdelay(100);
- cx23885_gpio_set(dev, GPIO_8);
+ cx23885_gpio_set(dev, GPIO_8 | GPIO_9);
mdelay(100);
+
break;
case CX23885_BOARD_AVERMEDIA_HC81R:
cx_clear(MC417_CTL, 1);
@@ -1799,6 +1807,9 @@ void cx23885_card_setup(struct cx23885_dev *dev)
ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
break;
case CX23885_BOARD_HAUPPAUGE_HVR1250:
case CX23885_BOARD_HAUPPAUGE_HVR1500:
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index d037459..4822776 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -71,6 +71,7 @@
#include "tda10071.h"
#include "a8293.h"
#include "mb86a20s.h"
+#include "si2165.h"
static unsigned int debug;
@@ -302,6 +303,11 @@ static struct tda18271_config hauppauge_hvr1210_tuner_config = {
.output_opt = TDA18271_OUTPUT_LT_OFF,
};
+static struct tda18271_config hauppauge_hvr4400_tuner_config = {
+ .gate = TDA18271_GATE_DIGITAL,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
static struct tda18271_std_map hauppauge_hvr127x_std_map = {
.atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4,
.if_lvl = 1, .rfagc_top = 0x58 },
@@ -702,6 +708,12 @@ static const struct a8293_config hauppauge_a8293_config = {
.i2c_addr = 0x0b,
};
+static const struct si2165_config hauppauge_hvr4400_si2165_config = {
+ .i2c_addr = 0x64,
+ .chip_mode = SI2165_MODE_PLL_XTAL,
+ .ref_freq_Hz = 16000000,
+};
+
static int netup_altera_fpga_rw(void *device, int flag, int data, int read)
{
struct cx23885_dev *dev = (struct cx23885_dev *)device;
@@ -1335,13 +1347,34 @@ static int dvb_register(struct cx23885_tsport *port)
break;
case CX23885_BOARD_HAUPPAUGE_HVR4400:
i2c_bus = &dev->i2c_bus[0];
- fe0->dvb.frontend = dvb_attach(tda10071_attach,
+ i2c_bus2 = &dev->i2c_bus[1];
+ switch (port->nr) {
+ /* port b */
+ case 1:
+ fe0->dvb.frontend = dvb_attach(tda10071_attach,
&hauppauge_tda10071_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(a8293_attach, fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- &hauppauge_a8293_config);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(a8293_attach, fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &hauppauge_a8293_config))
+ goto frontend_detach;
+ }
+ break;
+ /* port c */
+ case 2:
+ fe0->dvb.frontend = dvb_attach(si2165_attach,
+ &hauppauge_hvr4400_si2165_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = 0;
+ if (!dvb_attach(tda18271_attach,
+ fe0->dvb.frontend,
+ 0x60, &i2c_bus2->i2c_adap,
+ &hauppauge_hvr4400_tuner_config))
+ goto frontend_detach;
+ }
+ break;
}
break;
default:
--
2.0.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 0/4] wintv 930c-hd: Add basic support
2014-07-01 19:55 [PATCH 0/4] wintv 930c-hd: Add basic support Matthias Schwarzott
` (3 preceding siblings ...)
2014-07-01 19:55 ` [PATCH 4/4] cx23885: Add si2165 support for HVR-5500 Matthias Schwarzott
@ 2014-07-02 5:27 ` Matthias Schwarzott
4 siblings, 0 replies; 6+ messages in thread
From: Matthias Schwarzott @ 2014-07-02 5:27 UTC (permalink / raw)
To: linux-media, crope
On 01.07.2014 21:55, Matthias Schwarzott wrote:
> This patch series is the third version of my si2165 driver.
> It supports only DVB-T and was tested on 8MHz channels in germany.
>
> Maybe the si2165 driver also works on other si2165/si2163/si2161 based cards.
>
I forgot to mention, that support for HVR-5500 is also added.
The card entry is shared with HVR-4400.
It would be interesting to hear what happens when testing this on a
HVR-4400 card, because as far as I know there is an si2161 chip (that
has only DVB-T instead of DVB-T and DVB-C support).
Most likely only some numbers are to be adjusted and it could work also.
The driver should also work for the PCTV QuatroStick 521e - only the usb
ids are not yet added.
Regards
Matthias
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2014-07-02 5:27 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-07-01 19:55 [PATCH 0/4] wintv 930c-hd: Add basic support Matthias Schwarzott
2014-07-01 19:55 ` [PATCH 1/4] get_dvb_firmware: Add firmware extractor for si2165 Matthias Schwarzott
2014-07-01 19:55 ` [PATCH 2/4] si2165: Add demod driver for DVB-T only Matthias Schwarzott
2014-07-01 19:55 ` [PATCH 3/4] cx231xx: Add [2040:b130] Hauppauge WinTV 930C-hd 1113xx Matthias Schwarzott
2014-07-01 19:55 ` [PATCH 4/4] cx23885: Add si2165 support for HVR-5500 Matthias Schwarzott
2014-07-02 5:27 ` [PATCH 0/4] wintv 930c-hd: Add basic support Matthias Schwarzott
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).