[PATCH 2/2] [media for 3.5] Add support for TBS-Tech ISDB-T Full Seg DTB08: Modifications for frontend mb86a20s

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Driver for TBS-Tech ISDB-T USB2.0 Receiver (DTB08 Full Seg).

The device used as a reference is described in the link
http://linuxtv.org/wiki/index.php/JH_Full_HD_Digital_TV_Receiver

Modifications to allow use the mb86a20s frontend.


Signed-off-by: Manoel Pinheiro <pinusdtv@xxxxxxxxxxx>
---
 drivers/media/dvb/dvb-usb/tbs-dtb08-fe.c |  570 ++++++++++++++++++++++++++++++
 drivers/media/dvb/dvb-usb/tbs-dtb08-fe.h |   60 ++++
 2 files changed, 630 insertions(+)
 create mode 100644 drivers/media/dvb/dvb-usb/tbs-dtb08-fe.c
 create mode 100644 drivers/media/dvb/dvb-usb/tbs-dtb08-fe.h

diff --git a/drivers/media/dvb/dvb-usb/tbs-dtb08-fe.c b/drivers/media/dvb/dvb-usb/tbs-dtb08-fe.c
new file mode 100644
index 0000000..955de70
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/tbs-dtb08-fe.c
@@ -0,0 +1,570 @@
+/*
+ *   TBS-Tech ISDB-T Full Seg DTB08 device driver
+ *
+ *   Copyright (C) 2010-2012 Manoel Pinheiro <pinusdtv@xxxxxxxxxxx>
+ *
+ *   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.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* This file is part of tbs-dtb08 module and can be removed in the future. */
+
+#include "tbs-dtb08-fe.h"
+
+struct dtb08_a20s_reg_subreg_val {
+	u8 reg;
+	u8 subreg;
+	u8 type;	/* 0=8 bits wo/sub, 1=8 bits w/sub
+			 * 2=16 bits wo/sub, 3=16 bits w/sub, 4=24 bits */
+	u32 val;
+};
+
+static struct dtb08_a20s_reg_subreg_val dtb08_a20s_regs_val[] = {
+	{ 0x70, 0x00, 0x00, 0x0f },
+	{ 0x70, 0x00, 0x00, 0xff },
+	{ 0x08, 0x00, 0x00, 0x01 },
+	{ 0x09, 0x00, 0x00, 0x3e },
+	{ 0x50, 0xd1, 0x01, 0x22 },
+	{ 0x39, 0x00, 0x00, 0x01 },
+	{ 0x71, 0x00, 0x00, 0x00 },
+	{ 0x28, 0x2a, 0x04, 0xff80 },
+	{ 0x28, 0x20, 0x04, 0x33dfa9 },
+	{ 0x28, 0x22, 0x04, 0x1ff0 },
+	{ 0x3b, 0x00, 0x00, 0x21 },
+	{ 0x3c, 0x00, 0x00, 0x3a },
+	{ 0x01, 0x00, 0x00, 0x0d },
+	{ 0x04, 0x08, 0x01, 0x05 },
+	{ 0x04, 0x0e, 0x03, 0x0014 },
+	{ 0x04, 0x0b, 0x01, 0x8c },
+	{ 0x04, 0x00, 0x03, 0x0007 },
+	{ 0x04, 0x02, 0x03, 0x0fa0 },
+	{ 0x04, 0x09, 0x01, 0x00 },
+	{ 0x04, 0x0a, 0x01, 0xff },
+	{ 0x04, 0x27, 0x01, 0x64 },
+	{ 0x04, 0x28, 0x01, 0x00 },
+	{ 0x04, 0x1e, 0x01, 0xff },
+	{ 0x04, 0x29, 0x01, 0x0a },
+	{ 0x04, 0x32, 0x01, 0x0a },
+	{ 0x04, 0x14, 0x01, 0x02 },
+	{ 0x04, 0x04, 0x03, 0x0022 },
+	{ 0x04, 0x06, 0x03, 0x0ed8 },
+	{ 0x04, 0x12, 0x01, 0x00 },
+	{ 0x04, 0x13, 0x01, 0xff },
+	{ 0x04, 0x15, 0x01, 0x4e },
+	{ 0x04, 0x16, 0x01, 0x20 },
+	{ 0x52, 0x00, 0x00, 0x01 },
+	{ 0x50, 0xa7, 0x04, 0xffff },
+	{ 0x50, 0xaa, 0x04, 0xffff },
+	{ 0x50, 0xad, 0x04, 0xffff },
+	{ 0x5e, 0x00, 0x00, 0x07 },
+	{ 0x50, 0xdc, 0x03, 0x01f4 },
+	{ 0x50, 0xde, 0x03, 0x01f4 },
+	{ 0x50, 0xe0, 0x03, 0x01f4 },
+	{ 0x50, 0xb0, 0x01, 0x07 },
+	{ 0x50, 0xb2, 0x03, 0xffff },
+	{ 0x50, 0xb4, 0x03, 0xffff },
+	{ 0x50, 0xb6, 0x03, 0xffff },
+	{ 0x50, 0x50, 0x01, 0x02 },
+	{ 0x50, 0x51, 0x01, 0x04 },
+	{ 0x45, 0x00, 0x00, 0x04 },
+	{ 0x48, 0x00, 0x00, 0x04 },
+	{ 0x50, 0xd5, 0x01, 0x01 },
+	{ 0x50, 0xd6, 0x01, 0x1f },
+	{ 0x50, 0xd2, 0x01, 0x03 },
+	{ 0x50, 0xd7, 0x01, 0x3f },
+	{ 0x28, 0x74, 0x04, 0x0040 },
+	{ 0x28, 0x46, 0x04, 0x2c0c },
+	{ 0x04, 0x40, 0x01, 0x01 },
+	{ 0x28, 0x00, 0x01, 0x10 },
+	{ 0x28, 0x05, 0x01, 0x02 },
+	{ 0x1c, 0x00, 0x00, 0x01 },
+	{ 0x28, 0x06, 0x04, 0x0003 },
+	{ 0x28, 0x07, 0x04, 0x000d },
+	{ 0x28, 0x08, 0x04, 0x0002 },
+	{ 0x28, 0x09, 0x04, 0x0001 },
+	{ 0x28, 0x0a, 0x04, 0x0021 },
+	{ 0x28, 0x0b, 0x04, 0x0029 },
+	{ 0x28, 0x0c, 0x04, 0x0016 },
+	{ 0x28, 0x0d, 0x04, 0x0031 },
+	{ 0x28, 0x0e, 0x04, 0x000e },
+	{ 0x28, 0x0f, 0x04, 0x004e },
+	{ 0x28, 0x10, 0x04, 0x0046 },
+	{ 0x28, 0x11, 0x04, 0x000f },
+	{ 0x28, 0x12, 0x04, 0x0056 },
+	{ 0x28, 0x13, 0x04, 0x0035 },
+	{ 0x28, 0x14, 0x04, 0x01be },
+	{ 0x28, 0x15, 0x04, 0x0184 },
+	{ 0x28, 0x16, 0x04, 0x03ee },
+	{ 0x28, 0x17, 0x04, 0x0098 },
+	{ 0x28, 0x18, 0x04, 0x009f },
+	{ 0x28, 0x19, 0x04, 0x07b2 },
+	{ 0x28, 0x1a, 0x04, 0x06c2 },
+	{ 0x28, 0x1b, 0x04, 0x074a },
+	{ 0x28, 0x1c, 0x04, 0x01bc },
+	{ 0x28, 0x1d, 0x04, 0x04ba },
+	{ 0x28, 0x1e, 0x04, 0x0614 },
+	{ 0x50, 0x1e, 0x01, 0x5d },
+	{ 0x50, 0x22, 0x01, 0x00 },
+	{ 0x50, 0x23, 0x01, 0xc8 },
+	{ 0x50, 0x24, 0x01, 0x00 },
+	{ 0x50, 0x25, 0x01, 0xf0 },
+	{ 0x50, 0x26, 0x01, 0x00 },
+	{ 0x50, 0x27, 0x01, 0xc3 },
+	{ 0x50, 0x39, 0x01, 0x02 },
+	{ 0x28, 0x6a, 0x04, 0x0000 }
+};
+
+static u8 dtb08_a20s_soft_reset[] = {
+	0x70, 0xf0, 0x70, 0xff, 0x08, 0x01, 0x08, 0x00
+};
+
+int dtb08_a20s_read_reg(struct dtb08_a20s_state *state, u8 reg, u8 *val)
+{
+	int ret;
+	*val = 0;
+	ret = state->i2c_read(state->udev, state->demod_addr, reg, val, 1);
+	return (ret < 0) ? ret : 0;
+}
+
+int dtb08_a20s_write_reg(struct dtb08_a20s_state *state, u8 reg, u8 val)
+{
+	int ret;
+	ret = state->i2c_write(state->udev, state->demod_addr, reg, &val, 1);
+	return (ret < 0) ? ret : 0;
+}
+
+int dtb08_a20s_read_subreg(struct dtb08_a20s_state *state,
+			   u8 reg, u8 subreg, u8 *val)
+{
+	int ret;
+
+	*val = 0;
+	ret = dtb08_a20s_write_reg(state, reg, subreg);
+	if (ret < 0)
+		return ret;
+	return dtb08_a20s_read_reg(state, reg + 1, val);
+}
+
+static u32 get_config_reg_val(struct dtb08_a20s_state *state,
+			      struct dtb08_a20s_reg_subreg_val *reg_val)
+{
+	struct dtb08_a20s_reg_subreg_config *config_regs;
+	int i;
+
+	if (!reg_val)
+		return 0;
+	if (!state || !state->config_regs)
+		return reg_val->val;
+
+	config_regs = state->config_regs;
+	for (i = 0; i < state->config_size; i++) {
+		if (config_regs->reg == reg_val->reg &&
+		    config_regs->subreg == reg_val->subreg)
+			return config_regs->val;
+		config_regs++;
+	}
+	return reg_val->val;
+}
+
+static int dtb08_a20s_init_regs(struct dtb08_a20s_state *state)
+{
+	u8 *buf;
+	u32 val;
+	int i, i2, count, ret = 0;
+
+	state->need_init = true;
+	buf = kmalloc(12 , GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(dtb08_a20s_regs_val); i++) {
+		struct dtb08_a20s_reg_subreg_val *reg_val;
+
+		reg_val = &dtb08_a20s_regs_val[i];
+		val = get_config_reg_val(state, reg_val);
+		buf[0] = reg_val->reg;
+		count = 1;
+		switch (reg_val->type) {
+		case 1:
+			buf[count++] = reg_val->subreg;
+			if (buf[0] == 0x28)
+				buf[count++] = 0x2b;
+			else
+				buf[count++] = buf[0] + 1;
+			break;
+		case 2:
+			buf[count++] = (u8)(val >> 0x08);
+			buf[count++] = buf[0] + 1;
+			buf[count++] = (u8)val;
+			break;
+		case 3:
+			buf[count++] = reg_val->subreg;
+			buf[count++] = buf[0] + 1;
+			buf[count++] = (u8)(val >> 0x08);
+			buf[count++] = buf[0];
+			buf[count++] = reg_val->subreg + 1;
+			buf[count++] = buf[0] + 1;
+			break;
+		case 4:
+			if (buf[0] == 0x28) {
+				buf[count++] = reg_val->subreg;
+				buf[count++] = 0x29;
+				buf[count++] = (u8)(val >> 0x10);
+				buf[count++] = 0x2a;
+				buf[count++] = (u8)(val >> 0x08);
+				buf[count++] = 0x2b;
+			} else if (buf[0] == 0x50) {
+				buf[count++] = reg_val->subreg;
+				buf[count++] = 0x51;
+				buf[count++] = (u8)(val >> 0x10);
+				buf[count++] = 0x50;
+				buf[count++] = reg_val->subreg + 1;
+				buf[count++] = 0x51;
+				buf[count++] = (u8)(val >> 0x08);
+				buf[count++] = 0x50;
+				buf[count++] = reg_val->subreg + 2;
+				buf[count++] = 0x51;
+			} else {
+				ret = -1;
+				goto ret_err;
+			}
+			break;
+		}
+		buf[count++] = (u8)val;
+		i2 = 0;
+		while (i2 < count) {
+			ret = dtb08_a20s_write_reg(state, buf[i2], buf[i2 + 1]);
+			if (ret < 0)
+				goto ret_err;
+			i2 += 2;
+		}
+	}
+	state->need_init = false;
+	kfree(buf);
+	return 0;
+
+ret_err:
+	err("%s: dtb08_a20s init failed.", __func__);
+	kfree(buf);
+	return ret;
+}
+
+static int dtb08_a20s_init_fe(struct dvb_frontend *fe)
+{
+	int n;
+	struct dtb08_a20s_state *state = fe->sec_priv;
+
+	fe->dtv_property_cache.delivery_system = SYS_ISDBT;
+
+	n = dtb08_a20s_init_regs(state);
+	if (n < 0)
+		return n;
+	else
+		return 0;
+}
+
+static int dtb08_a20s_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct dtb08_a20s_state *state = fe->sec_priv;
+	u8 val = 1;
+
+	/*
+	 * In the document "OFDM-LSI for Digital Terrestrial Broadcasting
+	 * Reception MB86A20S" says:
+	 * I2C bus and I2C bus for tuner control
+	 * This product realizes I2C bus for register setup in the main
+	 * unit and I2C bus for tuner control to shut off the bus noise from
+	 * the tuner by connecting the tuner to the I2C bus line only when
+	 * it is controlled.
+	 */
+
+	if (!state->tuner_ctrl)
+		return 0;
+
+	if (enable)
+		val = 0;
+
+	/* Enable/Disable I2C bus for tuner control */
+	return dtb08_a20s_write_reg(state, 0xfe, val);
+}
+
+static int dtb08_a20s_sleep(struct dvb_frontend *fe)
+{
+	struct dtb08_a20s_state *state = fe->sec_priv;
+
+	if (state->led_control)
+		state->led_control(state->udev, 0);
+	state->current_frequency = 0;
+	state->need_init = 1;
+	return 0;
+}
+
+static int dtb08_a20s_set_frontend(struct dvb_frontend *fe)
+{
+	int i, ret;
+	u8 val;
+	struct dtb08_a20s_state *state = fe->sec_priv;
+	struct dtv_frontend_properties *dpc = &fe->dtv_property_cache;
+
+	if (time_before(jiffies, state->next_set_frontend_check) &&
+		state->current_frequency == dpc->frequency)
+			return 0;
+
+	state->current_frequency = dpc->frequency;
+	state->next_set_frontend_check = jiffies + msecs_to_jiffies(200);
+
+	/* turn off the led */
+	if (state->led_control)
+		state->led_control(state->udev, 0);
+
+	if (state->need_init) {
+		ret = dtb08_a20s_init_regs(state);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* program tuner */
+	if (fe->ops.tuner_ops.set_params) {
+		state->tuner_ctrl = true;
+		fe->ops.tuner_ops.set_params(fe);
+		/* disable I2C bus tuner control */
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+		state->tuner_ctrl = false;
+		msleep(100);
+	}
+
+	for (i = 0; i < sizeof(dtb08_a20s_soft_reset); i += 2) {
+		ret = dtb08_a20s_write_reg(state, dtb08_a20s_soft_reset[i],
+					dtb08_a20s_soft_reset[i+1]);
+		if (ret < 0)
+			return ret;
+	}
+
+	for (i = 0; i < 10; i++) {
+		ret = dtb08_a20s_read_reg(state, 0x0a, &val);
+		if (ret == 0 && val >= 2)
+			break;
+		msleep(100);
+	}
+
+	/* turn on the led */
+	if (state->led_control)
+		state->led_control(state->udev, 1);
+
+	return 0;
+}
+
+static int dtb08_a20s_get_tune_settings(struct dvb_frontend *fe,
+				struct dvb_frontend_tune_settings *feset)
+{
+	feset->min_delay_ms = 600;
+	feset->step_size = 0;
+	feset->max_drift = 0;
+
+	return 0;
+}
+
+static int dtb08_a20s_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	int i;
+	u8 val = 0;
+	struct dtb08_a20s_state *state = fe->sec_priv;
+
+	if (time_before(jiffies, state->next_status_check)) {
+		*status = state->status;
+		return 0;
+	}
+
+	state->next_status_check = jiffies + msecs_to_jiffies(100);
+	for (i = 0; i < 10; i++) {
+		dtb08_a20s_read_reg(state, 0x0a, &val);
+		if (val >= 2)
+			break;
+		msleep(10);
+	}
+
+	*status = 0;
+
+	if (val >= 2)
+		*status |= FE_HAS_SIGNAL;
+	if (val >= 4)
+		*status |= FE_HAS_CARRIER;
+	if (val >= 5)
+		*status |= FE_HAS_VITERBI;
+	if (val >= 7)
+		*status |= FE_HAS_SYNC;
+	if (val >= 8)
+		*status |= FE_HAS_LOCK;
+
+	state->status = *status;
+
+	return 0;
+}
+
+static int dtb08_a20s_get_property(struct dvb_frontend *fe,
+				 struct dtv_property *tvp)
+{
+	struct dtv_frontend_properties *dpc = &fe->dtv_property_cache;
+
+	switch (tvp->cmd) {
+	case DTV_DELIVERY_SYSTEM:
+		tvp->u.data = dpc->delivery_system = SYS_ISDBT;
+		break;
+	}
+	return 0;
+}
+
+static int dtb08_a20s_read_signal_strength(struct dvb_frontend *fe,
+					   u16 *strength)
+{
+	struct dtb08_a20s_state *state = fe->sec_priv;
+	int i, n;
+
+	if (time_before(jiffies, state->next_strength_check)) {
+		*strength = state->strength;
+		return 0;
+	}
+	state->next_strength_check = jiffies + msecs_to_jiffies(100);
+	*strength = state->strength = 0;
+	for (i = 0; i < 10; i++) {
+		u8 val = 0;
+		dtb08_a20s_read_reg(state, 0x0a, &val);
+		if (val < 2)
+			goto next;
+#if 0
+		if (dtb08_a20s_read_subreg(state, 0x04, 0x3a, &val) < 0)
+			goto next;
+		n = ((255 - val) * 10000) / 255;
+		state->strength = *strength = (u16)((65535 * n) / 10000);
+
+		info("%s: val=%d, n=%d, strength=%d %d%%",
+			__func__, val, n, *strength, (255-val) * 100 / 255);
+		return 0;
+#else
+		if (dtb08_a20s_read_subreg(state, 0x04, 0x25, &val) < 0)
+			goto next;
+		n = val;
+		if (dtb08_a20s_read_subreg(state, 0x04, 0x26, &val) < 0)
+			goto next;
+		n = (((n << 8) | val) * 0x100100) >> 16;
+		*strength = state->strength = n ;
+		return 0;
+#endif
+next:
+		msleep(20);
+	}
+
+	return 0;
+}
+
+static int dtb08_a20s_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct dtb08_a20s_state *state = fe->sec_priv;
+	int i, n, cnr;
+
+	if (time_before(jiffies, state->next_snr_check)) {
+		*snr = state->snr;
+		return 0;
+	}
+
+	state->next_snr_check = jiffies + msecs_to_jiffies(100);
+	*snr = state->snr = 0;
+	for (i = 0; i < 10; i++) {
+		u8 val = 0;
+		n = dtb08_a20s_read_reg(state, 0x0a, &val);
+		if (n < 0 || val < 2)
+			goto next;
+		if (dtb08_a20s_read_reg(state, 0x45, &val) < 0)
+			goto next;
+		/* read cnr_flag */
+		if (((val >> 6) & 1) != 0) {
+			if (dtb08_a20s_read_reg(state, 0x46, &val) < 0)
+				goto next;
+			n = val;
+			if (dtb08_a20s_read_reg(state, 0x47, &val) < 0)
+				goto next;
+			cnr = (n << 0x08) | val;
+			/* reset cnr_counter */
+			dtb08_a20s_read_reg(state, 0x45, &val);
+			val |= 0x10;
+			dtb08_a20s_write_reg(state, 0x45, val);
+			msleep(5);
+			val &= 0x6f; /* FIXME: or 0xef ? */
+			dtb08_a20s_write_reg(state, 0x45, val);
+			if (cnr > 0x4cc0)
+				cnr = 0x4cc0;
+			n = ((0x4cc0 - cnr) * 10000) / 0x4cc0;
+			n = (65535 * n) / 10000;
+			*snr = state->snr = n;
+			return 0;
+		}
+next:
+		msleep(20);
+	}
+
+	return 0;
+}
+
+static int dtb08_a20s_tune(struct dvb_frontend *fe, bool re_tune,
+			   unsigned int mode_flags, unsigned int *delay,
+			   fe_status_t *status)
+{
+	int ret = 0;
+
+	if (re_tune) {
+		ret = dtb08_a20s_set_frontend(fe);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
+		ret = dtb08_a20s_read_status(fe, status);
+
+	return ret;
+}
+
+int dtb08_a20s_frontend_attach(struct dtb08_a20s_state *state,
+			       struct dvb_usb_adapter *adap,
+			       const struct mb86a20s_config *config)
+{
+	struct dvb_frontend *fe;
+
+	if (!state->i2c_read || !state->i2c_write)
+		return -EOPNOTSUPP;
+
+	if (dtb08_a20s_init_regs(state) != 0)
+		return -ENODEV;
+
+	fe = dvb_attach(mb86a20s_attach, config, &adap->dev->i2c_adap);
+	if (!fe)
+		return -ENODEV;
+
+	state->need_init = true;
+	adap->fe_adap[0].fe = fe;
+
+	fe->sec_priv = state;
+	fe->ops.init = dtb08_a20s_init_fe;
+	fe->ops.sleep = dtb08_a20s_sleep;
+	fe->ops.set_frontend = dtb08_a20s_set_frontend;
+	fe->ops.read_status = dtb08_a20s_read_status;
+	fe->ops.read_signal_strength = dtb08_a20s_read_signal_strength;
+	fe->ops.read_snr = dtb08_a20s_read_snr;
+	fe->ops.get_tune_settings = dtb08_a20s_get_tune_settings;
+	fe->ops.get_property = dtb08_a20s_get_property;
+	fe->ops.i2c_gate_ctrl = dtb08_a20s_i2c_gate_ctrl;
+	fe->ops.tune = dtb08_a20s_tune;
+
+	return 0;
+}
diff --git a/drivers/media/dvb/dvb-usb/tbs-dtb08-fe.h b/drivers/media/dvb/dvb-usb/tbs-dtb08-fe.h
new file mode 100644
index 0000000..6cd82f7
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/tbs-dtb08-fe.h
@@ -0,0 +1,60 @@
+/*
+ *   TBS-Tech ISDB-T Full Seg DTB08 device driver
+ *
+ *   Copyright (C) 2010-2012 Manoel Pinheiro <pinusdtv@xxxxxxxxxxx>
+ *
+ *   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.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/dvb/frontend.h>
+
+#ifndef DVB_USB_LOG_PREFIX
+#define DVB_USB_LOG_PREFIX "tbs_dtb08-fe"
+#endif
+
+#include "dvb-usb.h"
+#include "mb86a20s.h"
+
+struct dtb08_a20s_reg_subreg_config {
+	u8 reg;
+	u8 subreg;
+	u32 val;
+};
+
+struct dtb08_a20s_state {
+	struct usb_device *udev;
+	int demod_addr;
+	u32 current_frequency;
+	fe_status_t status;
+	u16 snr;
+	u16 strength;
+	unsigned long next_snr_check;
+	unsigned long next_strength_check;
+	unsigned long next_set_frontend_check;
+	unsigned long next_status_check;
+	int config_size;
+	struct dtb08_a20s_reg_subreg_config *config_regs;
+	int (*i2c_read)(struct usb_device *udev,
+			u8 addr, u8 reg, u8 *data, u8 len);
+	int (*i2c_write)(struct usb_device *udev,
+			 u8 addr, u8 reg, u8 *data, u8 len);
+	int (*led_control)(struct usb_device *udev, int onoff);
+	bool need_init;
+	bool tuner_ctrl;
+};
+
+int dtb08_a20s_frontend_attach(struct dtb08_a20s_state *state,
+			       struct dvb_usb_adapter *adap,
+			       const struct mb86a20s_config *config);
-- 
1.7.10

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux