18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci	Frontend/Card driver for TwinHan DST Frontend
48c2ecf20Sopenharmony_ci	Copyright (C) 2003 Jamie Honan
58c2ecf20Sopenharmony_ci	Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci*/
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/string.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
178c2ecf20Sopenharmony_ci#include <linux/delay.h>
188c2ecf20Sopenharmony_ci#include <asm/div64.h>
198c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h>
208c2ecf20Sopenharmony_ci#include "dst_priv.h"
218c2ecf20Sopenharmony_ci#include "dst_common.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic unsigned int verbose;
248c2ecf20Sopenharmony_cimodule_param(verbose, int, 0644);
258c2ecf20Sopenharmony_ciMODULE_PARM_DESC(verbose, "verbosity level (0 to 3)");
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic unsigned int dst_addons;
288c2ecf20Sopenharmony_cimodule_param(dst_addons, int, 0644);
298c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)");
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic unsigned int dst_algo;
328c2ecf20Sopenharmony_cimodule_param(dst_algo, int, 0644);
338c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)");
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define HAS_LOCK		1
368c2ecf20Sopenharmony_ci#define ATTEMPT_TUNE		2
378c2ecf20Sopenharmony_ci#define HAS_POWER		4
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define dprintk(level, fmt, arg...) do {				\
408c2ecf20Sopenharmony_ci	if (level >= verbose)						\
418c2ecf20Sopenharmony_ci		printk(KERN_DEBUG pr_fmt("%s: " fmt),			\
428c2ecf20Sopenharmony_ci		       __func__, ##arg);				\
438c2ecf20Sopenharmony_ci} while(0)
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic int dst_command(struct dst_state *state, u8 *data, u8 len);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic void dst_packsize(struct dst_state *state, int psize)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	union dst_gpio_packet bits;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	bits.psize = psize;
528c2ecf20Sopenharmony_ci	bt878_device_control(state->bt, DST_IG_TS, &bits);
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb,
568c2ecf20Sopenharmony_ci			 u32 outhigh, int delay)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	union dst_gpio_packet enb;
598c2ecf20Sopenharmony_ci	union dst_gpio_packet bits;
608c2ecf20Sopenharmony_ci	int err;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	enb.enb.mask = mask;
638c2ecf20Sopenharmony_ci	enb.enb.enable = enbb;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	dprintk(2, "mask=[%04x], enbb=[%04x], outhigh=[%04x]\n",
668c2ecf20Sopenharmony_ci		mask, enbb, outhigh);
678c2ecf20Sopenharmony_ci	if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) {
688c2ecf20Sopenharmony_ci		dprintk(2, "dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)\n",
698c2ecf20Sopenharmony_ci			err, mask, enbb);
708c2ecf20Sopenharmony_ci		return -EREMOTEIO;
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci	udelay(1000);
738c2ecf20Sopenharmony_ci	/* because complete disabling means no output, no need to do output packet */
748c2ecf20Sopenharmony_ci	if (enbb == 0)
758c2ecf20Sopenharmony_ci		return 0;
768c2ecf20Sopenharmony_ci	if (delay)
778c2ecf20Sopenharmony_ci		msleep(10);
788c2ecf20Sopenharmony_ci	bits.outp.mask = enbb;
798c2ecf20Sopenharmony_ci	bits.outp.highvals = outhigh;
808c2ecf20Sopenharmony_ci	if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) {
818c2ecf20Sopenharmony_ci		dprintk(2, "dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)\n",
828c2ecf20Sopenharmony_ci			err, enbb, outhigh);
838c2ecf20Sopenharmony_ci		return -EREMOTEIO;
848c2ecf20Sopenharmony_ci	}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	return 0;
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic int dst_gpio_inb(struct dst_state *state, u8 *result)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	union dst_gpio_packet rd_packet;
928c2ecf20Sopenharmony_ci	int err;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	*result = 0;
958c2ecf20Sopenharmony_ci	if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) {
968c2ecf20Sopenharmony_ci		pr_err("dst_gpio_inb error (err == %i)\n", err);
978c2ecf20Sopenharmony_ci		return -EREMOTEIO;
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci	*result = (u8) rd_packet.rd.value;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	return 0;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ciint rdc_reset_state(struct dst_state *state)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	dprintk(2, "Resetting state machine\n");
1078c2ecf20Sopenharmony_ci	if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, 0, NO_DELAY) < 0) {
1088c2ecf20Sopenharmony_ci		pr_err("dst_gpio_outb ERROR !\n");
1098c2ecf20Sopenharmony_ci		return -1;
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci	msleep(10);
1128c2ecf20Sopenharmony_ci	if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, RDC_8820_INT, NO_DELAY) < 0) {
1138c2ecf20Sopenharmony_ci		pr_err("dst_gpio_outb ERROR !\n");
1148c2ecf20Sopenharmony_ci		msleep(10);
1158c2ecf20Sopenharmony_ci		return -1;
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	return 0;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rdc_reset_state);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic int rdc_8820_reset(struct dst_state *state)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	dprintk(3, "Resetting DST\n");
1258c2ecf20Sopenharmony_ci	if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) {
1268c2ecf20Sopenharmony_ci		pr_err("dst_gpio_outb ERROR !\n");
1278c2ecf20Sopenharmony_ci		return -1;
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci	udelay(1000);
1308c2ecf20Sopenharmony_ci	if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, RDC_8820_RESET, DELAY) < 0) {
1318c2ecf20Sopenharmony_ci		pr_err("dst_gpio_outb ERROR !\n");
1328c2ecf20Sopenharmony_ci		return -1;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	return 0;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic int dst_pio_enable(struct dst_state *state)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) {
1418c2ecf20Sopenharmony_ci		pr_err("dst_gpio_outb ERROR !\n");
1428c2ecf20Sopenharmony_ci		return -1;
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci	udelay(1000);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	return 0;
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ciint dst_pio_disable(struct dst_state *state)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_DISABLE, RDC_8820_PIO_0_DISABLE, NO_DELAY) < 0) {
1528c2ecf20Sopenharmony_ci		pr_err("dst_gpio_outb ERROR !\n");
1538c2ecf20Sopenharmony_ci		return -1;
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci	if (state->type_flags & DST_TYPE_HAS_FW_1)
1568c2ecf20Sopenharmony_ci		udelay(1000);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	return 0;
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dst_pio_disable);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ciint dst_wait_dst_ready(struct dst_state *state, u8 delay_mode)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	u8 reply;
1658c2ecf20Sopenharmony_ci	int i;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	for (i = 0; i < 200; i++) {
1688c2ecf20Sopenharmony_ci		if (dst_gpio_inb(state, &reply) < 0) {
1698c2ecf20Sopenharmony_ci			pr_err("dst_gpio_inb ERROR !\n");
1708c2ecf20Sopenharmony_ci			return -1;
1718c2ecf20Sopenharmony_ci		}
1728c2ecf20Sopenharmony_ci		if ((reply & RDC_8820_PIO_0_ENABLE) == 0) {
1738c2ecf20Sopenharmony_ci			dprintk(2, "dst wait ready after %d\n", i);
1748c2ecf20Sopenharmony_ci			return 1;
1758c2ecf20Sopenharmony_ci		}
1768c2ecf20Sopenharmony_ci		msleep(10);
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci	dprintk(1, "dst wait NOT ready after %d\n", i);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	return 0;
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dst_wait_dst_ready);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ciint dst_error_recovery(struct dst_state *state)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	dprintk(1, "Trying to return from previous errors.\n");
1878c2ecf20Sopenharmony_ci	dst_pio_disable(state);
1888c2ecf20Sopenharmony_ci	msleep(10);
1898c2ecf20Sopenharmony_ci	dst_pio_enable(state);
1908c2ecf20Sopenharmony_ci	msleep(10);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	return 0;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dst_error_recovery);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ciint dst_error_bailout(struct dst_state *state)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	dprintk(2, "Trying to bailout from previous error.\n");
1998c2ecf20Sopenharmony_ci	rdc_8820_reset(state);
2008c2ecf20Sopenharmony_ci	dst_pio_disable(state);
2018c2ecf20Sopenharmony_ci	msleep(10);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	return 0;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dst_error_bailout);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ciint dst_comm_init(struct dst_state *state)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	dprintk(2, "Initializing DST.\n");
2108c2ecf20Sopenharmony_ci	if ((dst_pio_enable(state)) < 0) {
2118c2ecf20Sopenharmony_ci		pr_err("PIO Enable Failed\n");
2128c2ecf20Sopenharmony_ci		return -1;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci	if ((rdc_reset_state(state)) < 0) {
2158c2ecf20Sopenharmony_ci		pr_err("RDC 8820 State RESET Failed.\n");
2168c2ecf20Sopenharmony_ci		return -1;
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci	if (state->type_flags & DST_TYPE_HAS_FW_1)
2198c2ecf20Sopenharmony_ci		msleep(100);
2208c2ecf20Sopenharmony_ci	else
2218c2ecf20Sopenharmony_ci		msleep(5);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	return 0;
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dst_comm_init);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ciint write_dst(struct dst_state *state, u8 *data, u8 len)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	struct i2c_msg msg = {
2308c2ecf20Sopenharmony_ci		.addr = state->config->demod_address,
2318c2ecf20Sopenharmony_ci		.flags = 0,
2328c2ecf20Sopenharmony_ci		.buf = data,
2338c2ecf20Sopenharmony_ci		.len = len
2348c2ecf20Sopenharmony_ci	};
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	int err;
2378c2ecf20Sopenharmony_ci	u8 cnt;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	dprintk(1, "writing [ %*ph ]\n", len, data);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	for (cnt = 0; cnt < 2; cnt++) {
2428c2ecf20Sopenharmony_ci		if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) {
2438c2ecf20Sopenharmony_ci			dprintk(2, "_write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n",
2448c2ecf20Sopenharmony_ci				err, len, data[0]);
2458c2ecf20Sopenharmony_ci			dst_error_recovery(state);
2468c2ecf20Sopenharmony_ci			continue;
2478c2ecf20Sopenharmony_ci		} else
2488c2ecf20Sopenharmony_ci			break;
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci	if (cnt >= 2) {
2518c2ecf20Sopenharmony_ci		dprintk(2, "RDC 8820 RESET\n");
2528c2ecf20Sopenharmony_ci		dst_error_bailout(state);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci		return -1;
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	return 0;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(write_dst);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ciint read_dst(struct dst_state *state, u8 *ret, u8 len)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct i2c_msg msg = {
2648c2ecf20Sopenharmony_ci		.addr = state->config->demod_address,
2658c2ecf20Sopenharmony_ci		.flags = I2C_M_RD,
2668c2ecf20Sopenharmony_ci		.buf = ret,
2678c2ecf20Sopenharmony_ci		.len = len
2688c2ecf20Sopenharmony_ci	};
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	int err;
2718c2ecf20Sopenharmony_ci	int cnt;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	for (cnt = 0; cnt < 2; cnt++) {
2748c2ecf20Sopenharmony_ci		if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) {
2758c2ecf20Sopenharmony_ci			dprintk(2, "read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n",
2768c2ecf20Sopenharmony_ci				err, len, ret[0]);
2778c2ecf20Sopenharmony_ci			dst_error_recovery(state);
2788c2ecf20Sopenharmony_ci			continue;
2798c2ecf20Sopenharmony_ci		} else
2808c2ecf20Sopenharmony_ci			break;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci	if (cnt >= 2) {
2838c2ecf20Sopenharmony_ci		dprintk(2, "RDC 8820 RESET\n");
2848c2ecf20Sopenharmony_ci		dst_error_bailout(state);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci		return -1;
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci	dprintk(3, "reply is %*ph\n", len, ret);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	return 0;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(read_dst);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic int dst_set_polarization(struct dst_state *state)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	switch (state->voltage) {
2978c2ecf20Sopenharmony_ci	case SEC_VOLTAGE_13:	/*	Vertical	*/
2988c2ecf20Sopenharmony_ci		dprintk(2, "Polarization=[Vertical]\n");
2998c2ecf20Sopenharmony_ci		state->tx_tuna[8] &= ~0x40;
3008c2ecf20Sopenharmony_ci		break;
3018c2ecf20Sopenharmony_ci	case SEC_VOLTAGE_18:	/*	Horizontal	*/
3028c2ecf20Sopenharmony_ci		dprintk(2, "Polarization=[Horizontal]\n");
3038c2ecf20Sopenharmony_ci		state->tx_tuna[8] |= 0x40;
3048c2ecf20Sopenharmony_ci		break;
3058c2ecf20Sopenharmony_ci	case SEC_VOLTAGE_OFF:
3068c2ecf20Sopenharmony_ci		break;
3078c2ecf20Sopenharmony_ci	}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	return 0;
3108c2ecf20Sopenharmony_ci}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_cistatic int dst_set_freq(struct dst_state *state, u32 freq)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	state->frequency = freq;
3158c2ecf20Sopenharmony_ci	dprintk(2, "set Frequency %u\n", freq);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if (state->dst_type == DST_TYPE_IS_SAT) {
3188c2ecf20Sopenharmony_ci		freq = freq / 1000;
3198c2ecf20Sopenharmony_ci		if (freq < 950 || freq > 2150)
3208c2ecf20Sopenharmony_ci			return -EINVAL;
3218c2ecf20Sopenharmony_ci		state->tx_tuna[2] = (freq >> 8);
3228c2ecf20Sopenharmony_ci		state->tx_tuna[3] = (u8) freq;
3238c2ecf20Sopenharmony_ci		state->tx_tuna[4] = 0x01;
3248c2ecf20Sopenharmony_ci		state->tx_tuna[8] &= ~0x04;
3258c2ecf20Sopenharmony_ci		if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
3268c2ecf20Sopenharmony_ci			if (freq < 1531)
3278c2ecf20Sopenharmony_ci				state->tx_tuna[8] |= 0x04;
3288c2ecf20Sopenharmony_ci		}
3298c2ecf20Sopenharmony_ci	} else if (state->dst_type == DST_TYPE_IS_TERR) {
3308c2ecf20Sopenharmony_ci		freq = freq / 1000;
3318c2ecf20Sopenharmony_ci		if (freq < 137000 || freq > 858000)
3328c2ecf20Sopenharmony_ci			return -EINVAL;
3338c2ecf20Sopenharmony_ci		state->tx_tuna[2] = (freq >> 16) & 0xff;
3348c2ecf20Sopenharmony_ci		state->tx_tuna[3] = (freq >> 8) & 0xff;
3358c2ecf20Sopenharmony_ci		state->tx_tuna[4] = (u8) freq;
3368c2ecf20Sopenharmony_ci	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
3378c2ecf20Sopenharmony_ci		freq = freq / 1000;
3388c2ecf20Sopenharmony_ci		state->tx_tuna[2] = (freq >> 16) & 0xff;
3398c2ecf20Sopenharmony_ci		state->tx_tuna[3] = (freq >> 8) & 0xff;
3408c2ecf20Sopenharmony_ci		state->tx_tuna[4] = (u8) freq;
3418c2ecf20Sopenharmony_ci	} else if (state->dst_type == DST_TYPE_IS_ATSC) {
3428c2ecf20Sopenharmony_ci		freq = freq / 1000;
3438c2ecf20Sopenharmony_ci		if (freq < 51000 || freq > 858000)
3448c2ecf20Sopenharmony_ci			return -EINVAL;
3458c2ecf20Sopenharmony_ci		state->tx_tuna[2] = (freq >> 16) & 0xff;
3468c2ecf20Sopenharmony_ci		state->tx_tuna[3] = (freq >>  8) & 0xff;
3478c2ecf20Sopenharmony_ci		state->tx_tuna[4] = (u8) freq;
3488c2ecf20Sopenharmony_ci		state->tx_tuna[5] = 0x00;		/*	ATSC	*/
3498c2ecf20Sopenharmony_ci		state->tx_tuna[6] = 0x00;
3508c2ecf20Sopenharmony_ci		if (state->dst_hw_cap & DST_TYPE_HAS_ANALOG)
3518c2ecf20Sopenharmony_ci			state->tx_tuna[7] = 0x00;	/*	Digital	*/
3528c2ecf20Sopenharmony_ci	} else
3538c2ecf20Sopenharmony_ci		return -EINVAL;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	return 0;
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic int dst_set_bandwidth(struct dst_state *state, u32 bandwidth)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	state->bandwidth = bandwidth;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	if (state->dst_type != DST_TYPE_IS_TERR)
3638c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	switch (bandwidth) {
3668c2ecf20Sopenharmony_ci	case 6000000:
3678c2ecf20Sopenharmony_ci		if (state->dst_hw_cap & DST_TYPE_HAS_CA)
3688c2ecf20Sopenharmony_ci			state->tx_tuna[7] = 0x06;
3698c2ecf20Sopenharmony_ci		else {
3708c2ecf20Sopenharmony_ci			state->tx_tuna[6] = 0x06;
3718c2ecf20Sopenharmony_ci			state->tx_tuna[7] = 0x00;
3728c2ecf20Sopenharmony_ci		}
3738c2ecf20Sopenharmony_ci		break;
3748c2ecf20Sopenharmony_ci	case 7000000:
3758c2ecf20Sopenharmony_ci		if (state->dst_hw_cap & DST_TYPE_HAS_CA)
3768c2ecf20Sopenharmony_ci			state->tx_tuna[7] = 0x07;
3778c2ecf20Sopenharmony_ci		else {
3788c2ecf20Sopenharmony_ci			state->tx_tuna[6] = 0x07;
3798c2ecf20Sopenharmony_ci			state->tx_tuna[7] = 0x00;
3808c2ecf20Sopenharmony_ci		}
3818c2ecf20Sopenharmony_ci		break;
3828c2ecf20Sopenharmony_ci	case 8000000:
3838c2ecf20Sopenharmony_ci		if (state->dst_hw_cap & DST_TYPE_HAS_CA)
3848c2ecf20Sopenharmony_ci			state->tx_tuna[7] = 0x08;
3858c2ecf20Sopenharmony_ci		else {
3868c2ecf20Sopenharmony_ci			state->tx_tuna[6] = 0x08;
3878c2ecf20Sopenharmony_ci			state->tx_tuna[7] = 0x00;
3888c2ecf20Sopenharmony_ci		}
3898c2ecf20Sopenharmony_ci		break;
3908c2ecf20Sopenharmony_ci	default:
3918c2ecf20Sopenharmony_ci		return -EINVAL;
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	return 0;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic int dst_set_inversion(struct dst_state *state,
3988c2ecf20Sopenharmony_ci			     enum fe_spectral_inversion inversion)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	state->inversion = inversion;
4018c2ecf20Sopenharmony_ci	switch (inversion) {
4028c2ecf20Sopenharmony_ci	case INVERSION_OFF:	/*	Inversion = Normal	*/
4038c2ecf20Sopenharmony_ci		state->tx_tuna[8] &= ~0x80;
4048c2ecf20Sopenharmony_ci		break;
4058c2ecf20Sopenharmony_ci	case INVERSION_ON:
4068c2ecf20Sopenharmony_ci		state->tx_tuna[8] |= 0x80;
4078c2ecf20Sopenharmony_ci		break;
4088c2ecf20Sopenharmony_ci	default:
4098c2ecf20Sopenharmony_ci		return -EINVAL;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	return 0;
4138c2ecf20Sopenharmony_ci}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cistatic int dst_set_fec(struct dst_state *state, enum fe_code_rate fec)
4168c2ecf20Sopenharmony_ci{
4178c2ecf20Sopenharmony_ci	state->fec = fec;
4188c2ecf20Sopenharmony_ci	return 0;
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistatic enum fe_code_rate dst_get_fec(struct dst_state *state)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	return state->fec;
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_cistatic int dst_set_symbolrate(struct dst_state *state, u32 srate)
4278c2ecf20Sopenharmony_ci{
4288c2ecf20Sopenharmony_ci	u32 symcalc;
4298c2ecf20Sopenharmony_ci	u64 sval;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	state->symbol_rate = srate;
4328c2ecf20Sopenharmony_ci	if (state->dst_type == DST_TYPE_IS_TERR) {
4338c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci	dprintk(2, "set symrate %u\n", srate);
4368c2ecf20Sopenharmony_ci	srate /= 1000;
4378c2ecf20Sopenharmony_ci	if (state->dst_type == DST_TYPE_IS_SAT) {
4388c2ecf20Sopenharmony_ci		if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
4398c2ecf20Sopenharmony_ci			sval = srate;
4408c2ecf20Sopenharmony_ci			sval <<= 20;
4418c2ecf20Sopenharmony_ci			do_div(sval, 88000);
4428c2ecf20Sopenharmony_ci			symcalc = (u32) sval;
4438c2ecf20Sopenharmony_ci			dprintk(2, "set symcalc %u\n", symcalc);
4448c2ecf20Sopenharmony_ci			state->tx_tuna[5] = (u8) (symcalc >> 12);
4458c2ecf20Sopenharmony_ci			state->tx_tuna[6] = (u8) (symcalc >> 4);
4468c2ecf20Sopenharmony_ci			state->tx_tuna[7] = (u8) (symcalc << 4);
4478c2ecf20Sopenharmony_ci		} else {
4488c2ecf20Sopenharmony_ci			state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f;
4498c2ecf20Sopenharmony_ci			state->tx_tuna[6] = (u8) (srate >> 8);
4508c2ecf20Sopenharmony_ci			state->tx_tuna[7] = (u8) srate;
4518c2ecf20Sopenharmony_ci		}
4528c2ecf20Sopenharmony_ci		state->tx_tuna[8] &= ~0x20;
4538c2ecf20Sopenharmony_ci		if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
4548c2ecf20Sopenharmony_ci			if (srate > 8000)
4558c2ecf20Sopenharmony_ci				state->tx_tuna[8] |= 0x20;
4568c2ecf20Sopenharmony_ci		}
4578c2ecf20Sopenharmony_ci	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
4588c2ecf20Sopenharmony_ci		dprintk(3, "%s\n", state->fw_name);
4598c2ecf20Sopenharmony_ci		if (!strncmp(state->fw_name, "DCTNEW", 6)) {
4608c2ecf20Sopenharmony_ci			state->tx_tuna[5] = (u8) (srate >> 8);
4618c2ecf20Sopenharmony_ci			state->tx_tuna[6] = (u8) srate;
4628c2ecf20Sopenharmony_ci			state->tx_tuna[7] = 0x00;
4638c2ecf20Sopenharmony_ci		} else if (!strncmp(state->fw_name, "DCT-CI", 6)) {
4648c2ecf20Sopenharmony_ci			state->tx_tuna[5] = 0x00;
4658c2ecf20Sopenharmony_ci			state->tx_tuna[6] = (u8) (srate >> 8);
4668c2ecf20Sopenharmony_ci			state->tx_tuna[7] = (u8) srate;
4678c2ecf20Sopenharmony_ci		}
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci	return 0;
4708c2ecf20Sopenharmony_ci}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_cistatic int dst_set_modulation(struct dst_state *state,
4738c2ecf20Sopenharmony_ci			      enum fe_modulation modulation)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	if (state->dst_type != DST_TYPE_IS_CABLE)
4768c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	state->modulation = modulation;
4798c2ecf20Sopenharmony_ci	switch (modulation) {
4808c2ecf20Sopenharmony_ci	case QAM_16:
4818c2ecf20Sopenharmony_ci		state->tx_tuna[8] = 0x10;
4828c2ecf20Sopenharmony_ci		break;
4838c2ecf20Sopenharmony_ci	case QAM_32:
4848c2ecf20Sopenharmony_ci		state->tx_tuna[8] = 0x20;
4858c2ecf20Sopenharmony_ci		break;
4868c2ecf20Sopenharmony_ci	case QAM_64:
4878c2ecf20Sopenharmony_ci		state->tx_tuna[8] = 0x40;
4888c2ecf20Sopenharmony_ci		break;
4898c2ecf20Sopenharmony_ci	case QAM_128:
4908c2ecf20Sopenharmony_ci		state->tx_tuna[8] = 0x80;
4918c2ecf20Sopenharmony_ci		break;
4928c2ecf20Sopenharmony_ci	case QAM_256:
4938c2ecf20Sopenharmony_ci		if (!strncmp(state->fw_name, "DCTNEW", 6))
4948c2ecf20Sopenharmony_ci			state->tx_tuna[8] = 0xff;
4958c2ecf20Sopenharmony_ci		else if (!strncmp(state->fw_name, "DCT-CI", 6))
4968c2ecf20Sopenharmony_ci			state->tx_tuna[8] = 0x00;
4978c2ecf20Sopenharmony_ci		break;
4988c2ecf20Sopenharmony_ci	case QPSK:
4998c2ecf20Sopenharmony_ci	case QAM_AUTO:
5008c2ecf20Sopenharmony_ci	case VSB_8:
5018c2ecf20Sopenharmony_ci	case VSB_16:
5028c2ecf20Sopenharmony_ci	default:
5038c2ecf20Sopenharmony_ci		return -EINVAL;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	return 0;
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic enum fe_modulation dst_get_modulation(struct dst_state *state)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	return state->modulation;
5138c2ecf20Sopenharmony_ci}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ciu8 dst_check_sum(u8 *buf, u32 len)
5178c2ecf20Sopenharmony_ci{
5188c2ecf20Sopenharmony_ci	u32 i;
5198c2ecf20Sopenharmony_ci	u8 val = 0;
5208c2ecf20Sopenharmony_ci	if (!len)
5218c2ecf20Sopenharmony_ci		return 0;
5228c2ecf20Sopenharmony_ci	for (i = 0; i < len; i++) {
5238c2ecf20Sopenharmony_ci		val += buf[i];
5248c2ecf20Sopenharmony_ci	}
5258c2ecf20Sopenharmony_ci	return ((~val) + 1);
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dst_check_sum);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_cistatic void dst_type_flags_print(struct dst_state *state)
5308c2ecf20Sopenharmony_ci{
5318c2ecf20Sopenharmony_ci	u32 type_flags = state->type_flags;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	pr_err("DST type flags :\n");
5348c2ecf20Sopenharmony_ci	if (type_flags & DST_TYPE_HAS_TS188)
5358c2ecf20Sopenharmony_ci		pr_err(" 0x%x newtuner\n", DST_TYPE_HAS_TS188);
5368c2ecf20Sopenharmony_ci	if (type_flags & DST_TYPE_HAS_NEWTUNE_2)
5378c2ecf20Sopenharmony_ci		pr_err(" 0x%x newtuner 2\n", DST_TYPE_HAS_NEWTUNE_2);
5388c2ecf20Sopenharmony_ci	if (type_flags & DST_TYPE_HAS_TS204)
5398c2ecf20Sopenharmony_ci		pr_err(" 0x%x ts204\n", DST_TYPE_HAS_TS204);
5408c2ecf20Sopenharmony_ci	if (type_flags & DST_TYPE_HAS_VLF)
5418c2ecf20Sopenharmony_ci		pr_err(" 0x%x VLF\n", DST_TYPE_HAS_VLF);
5428c2ecf20Sopenharmony_ci	if (type_flags & DST_TYPE_HAS_SYMDIV)
5438c2ecf20Sopenharmony_ci		pr_err(" 0x%x symdiv\n", DST_TYPE_HAS_SYMDIV);
5448c2ecf20Sopenharmony_ci	if (type_flags & DST_TYPE_HAS_FW_1)
5458c2ecf20Sopenharmony_ci		pr_err(" 0x%x firmware version = 1\n", DST_TYPE_HAS_FW_1);
5468c2ecf20Sopenharmony_ci	if (type_flags & DST_TYPE_HAS_FW_2)
5478c2ecf20Sopenharmony_ci		pr_err(" 0x%x firmware version = 2\n", DST_TYPE_HAS_FW_2);
5488c2ecf20Sopenharmony_ci	if (type_flags & DST_TYPE_HAS_FW_3)
5498c2ecf20Sopenharmony_ci		pr_err(" 0x%x firmware version = 3\n", DST_TYPE_HAS_FW_3);
5508c2ecf20Sopenharmony_ci	pr_err("\n");
5518c2ecf20Sopenharmony_ci}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_cistatic int dst_type_print(struct dst_state *state, u8 type)
5558c2ecf20Sopenharmony_ci{
5568c2ecf20Sopenharmony_ci	char *otype;
5578c2ecf20Sopenharmony_ci	switch (type) {
5588c2ecf20Sopenharmony_ci	case DST_TYPE_IS_SAT:
5598c2ecf20Sopenharmony_ci		otype = "satellite";
5608c2ecf20Sopenharmony_ci		break;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	case DST_TYPE_IS_TERR:
5638c2ecf20Sopenharmony_ci		otype = "terrestrial";
5648c2ecf20Sopenharmony_ci		break;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	case DST_TYPE_IS_CABLE:
5678c2ecf20Sopenharmony_ci		otype = "cable";
5688c2ecf20Sopenharmony_ci		break;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	case DST_TYPE_IS_ATSC:
5718c2ecf20Sopenharmony_ci		otype = "atsc";
5728c2ecf20Sopenharmony_ci		break;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	default:
5758c2ecf20Sopenharmony_ci		dprintk(2, "invalid dst type %d\n", type);
5768c2ecf20Sopenharmony_ci		return -EINVAL;
5778c2ecf20Sopenharmony_ci	}
5788c2ecf20Sopenharmony_ci	dprintk(2, "DST type: %s\n", otype);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	return 0;
5818c2ecf20Sopenharmony_ci}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_cistatic struct tuner_types tuner_list[] = {
5848c2ecf20Sopenharmony_ci	{
5858c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_L64724,
5868c2ecf20Sopenharmony_ci		.tuner_name = "L 64724",
5878c2ecf20Sopenharmony_ci		.board_name = "UNKNOWN",
5888c2ecf20Sopenharmony_ci		.fw_name    = "UNKNOWN"
5898c2ecf20Sopenharmony_ci	},
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	{
5928c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_STV0299,
5938c2ecf20Sopenharmony_ci		.tuner_name = "STV 0299",
5948c2ecf20Sopenharmony_ci		.board_name = "VP1020",
5958c2ecf20Sopenharmony_ci		.fw_name    = "DST-MOT"
5968c2ecf20Sopenharmony_ci	},
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	{
5998c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_STV0299,
6008c2ecf20Sopenharmony_ci		.tuner_name = "STV 0299",
6018c2ecf20Sopenharmony_ci		.board_name = "VP1020",
6028c2ecf20Sopenharmony_ci		.fw_name    = "DST-03T"
6038c2ecf20Sopenharmony_ci	},
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	{
6068c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_MB86A15,
6078c2ecf20Sopenharmony_ci		.tuner_name = "MB 86A15",
6088c2ecf20Sopenharmony_ci		.board_name = "VP1022",
6098c2ecf20Sopenharmony_ci		.fw_name    = "DST-03T"
6108c2ecf20Sopenharmony_ci	},
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	{
6138c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_MB86A15,
6148c2ecf20Sopenharmony_ci		.tuner_name = "MB 86A15",
6158c2ecf20Sopenharmony_ci		.board_name = "VP1025",
6168c2ecf20Sopenharmony_ci		.fw_name    = "DST-03T"
6178c2ecf20Sopenharmony_ci	},
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	{
6208c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_STV0299,
6218c2ecf20Sopenharmony_ci		.tuner_name = "STV 0299",
6228c2ecf20Sopenharmony_ci		.board_name = "VP1030",
6238c2ecf20Sopenharmony_ci		.fw_name    = "DST-CI"
6248c2ecf20Sopenharmony_ci	},
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	{
6278c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_STV0299,
6288c2ecf20Sopenharmony_ci		.tuner_name = "STV 0299",
6298c2ecf20Sopenharmony_ci		.board_name = "VP1030",
6308c2ecf20Sopenharmony_ci		.fw_name    = "DSTMCI"
6318c2ecf20Sopenharmony_ci	},
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	{
6348c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_UNKNOWN,
6358c2ecf20Sopenharmony_ci		.tuner_name = "UNKNOWN",
6368c2ecf20Sopenharmony_ci		.board_name = "VP2021",
6378c2ecf20Sopenharmony_ci		.fw_name    = "DCTNEW"
6388c2ecf20Sopenharmony_ci	},
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	{
6418c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_UNKNOWN,
6428c2ecf20Sopenharmony_ci		.tuner_name = "UNKNOWN",
6438c2ecf20Sopenharmony_ci		.board_name = "VP2030",
6448c2ecf20Sopenharmony_ci		.fw_name    = "DCT-CI"
6458c2ecf20Sopenharmony_ci	},
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	{
6488c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_UNKNOWN,
6498c2ecf20Sopenharmony_ci		.tuner_name = "UNKNOWN",
6508c2ecf20Sopenharmony_ci		.board_name = "VP2031",
6518c2ecf20Sopenharmony_ci		.fw_name    = "DCT-CI"
6528c2ecf20Sopenharmony_ci	},
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	{
6558c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_UNKNOWN,
6568c2ecf20Sopenharmony_ci		.tuner_name = "UNKNOWN",
6578c2ecf20Sopenharmony_ci		.board_name = "VP2040",
6588c2ecf20Sopenharmony_ci		.fw_name    = "DCT-CI"
6598c2ecf20Sopenharmony_ci	},
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	{
6628c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_UNKNOWN,
6638c2ecf20Sopenharmony_ci		.tuner_name = "UNKNOWN",
6648c2ecf20Sopenharmony_ci		.board_name = "VP3020",
6658c2ecf20Sopenharmony_ci		.fw_name    = "DTTFTA"
6668c2ecf20Sopenharmony_ci	},
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	{
6698c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_UNKNOWN,
6708c2ecf20Sopenharmony_ci		.tuner_name = "UNKNOWN",
6718c2ecf20Sopenharmony_ci		.board_name = "VP3021",
6728c2ecf20Sopenharmony_ci		.fw_name    = "DTTFTA"
6738c2ecf20Sopenharmony_ci	},
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	{
6768c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_TDA10046,
6778c2ecf20Sopenharmony_ci		.tuner_name = "TDA10046",
6788c2ecf20Sopenharmony_ci		.board_name = "VP3040",
6798c2ecf20Sopenharmony_ci		.fw_name    = "DTT-CI"
6808c2ecf20Sopenharmony_ci	},
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	{
6838c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_UNKNOWN,
6848c2ecf20Sopenharmony_ci		.tuner_name = "UNKNOWN",
6858c2ecf20Sopenharmony_ci		.board_name = "VP3051",
6868c2ecf20Sopenharmony_ci		.fw_name    = "DTTNXT"
6878c2ecf20Sopenharmony_ci	},
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	{
6908c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_NXT200x,
6918c2ecf20Sopenharmony_ci		.tuner_name = "NXT200x",
6928c2ecf20Sopenharmony_ci		.board_name = "VP3220",
6938c2ecf20Sopenharmony_ci		.fw_name    = "ATSCDI"
6948c2ecf20Sopenharmony_ci	},
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	{
6978c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_NXT200x,
6988c2ecf20Sopenharmony_ci		.tuner_name = "NXT200x",
6998c2ecf20Sopenharmony_ci		.board_name = "VP3250",
7008c2ecf20Sopenharmony_ci		.fw_name    = "ATSCAD"
7018c2ecf20Sopenharmony_ci	},
7028c2ecf20Sopenharmony_ci};
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci/*
7058c2ecf20Sopenharmony_ci	Known cards list
7068c2ecf20Sopenharmony_ci	Satellite
7078c2ecf20Sopenharmony_ci	-------------------
7088c2ecf20Sopenharmony_ci		  200103A
7098c2ecf20Sopenharmony_ci	VP-1020   DST-MOT	LG(old), TS=188
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	VP-1020   DST-03T	LG(new), TS=204
7128c2ecf20Sopenharmony_ci	VP-1022   DST-03T	LG(new), TS=204
7138c2ecf20Sopenharmony_ci	VP-1025   DST-03T	LG(new), TS=204
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	VP-1030   DSTMCI,	LG(new), TS=188
7168c2ecf20Sopenharmony_ci	VP-1032   DSTMCI,	LG(new), TS=188
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	Cable
7198c2ecf20Sopenharmony_ci	-------------------
7208c2ecf20Sopenharmony_ci	VP-2030   DCT-CI,	Samsung, TS=204
7218c2ecf20Sopenharmony_ci	VP-2021   DCT-CI,	Unknown, TS=204
7228c2ecf20Sopenharmony_ci	VP-2031   DCT-CI,	Philips, TS=188
7238c2ecf20Sopenharmony_ci	VP-2040   DCT-CI,	Philips, TS=188, with CA daughter board
7248c2ecf20Sopenharmony_ci	VP-2040   DCT-CI,	Philips, TS=204, without CA daughter board
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	Terrestrial
7278c2ecf20Sopenharmony_ci	-------------------
7288c2ecf20Sopenharmony_ci	VP-3050  DTTNXT			 TS=188
7298c2ecf20Sopenharmony_ci	VP-3040  DTT-CI,	Philips, TS=188
7308c2ecf20Sopenharmony_ci	VP-3040  DTT-CI,	Philips, TS=204
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	ATSC
7338c2ecf20Sopenharmony_ci	-------------------
7348c2ecf20Sopenharmony_ci	VP-3220  ATSCDI,		 TS=188
7358c2ecf20Sopenharmony_ci	VP-3250  ATSCAD,		 TS=188
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci*/
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_cistatic struct dst_types dst_tlist[] = {
7408c2ecf20Sopenharmony_ci	{
7418c2ecf20Sopenharmony_ci		.device_id = "200103A",
7428c2ecf20Sopenharmony_ci		.offset = 0,
7438c2ecf20Sopenharmony_ci		.dst_type =  DST_TYPE_IS_SAT,
7448c2ecf20Sopenharmony_ci		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS,
7458c2ecf20Sopenharmony_ci		.dst_feature = 0,
7468c2ecf20Sopenharmony_ci		.tuner_type = 0
7478c2ecf20Sopenharmony_ci	},	/*	obsolete	*/
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	{
7508c2ecf20Sopenharmony_ci		.device_id = "DST-020",
7518c2ecf20Sopenharmony_ci		.offset = 0,
7528c2ecf20Sopenharmony_ci		.dst_type =  DST_TYPE_IS_SAT,
7538c2ecf20Sopenharmony_ci		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
7548c2ecf20Sopenharmony_ci		.dst_feature = 0,
7558c2ecf20Sopenharmony_ci		.tuner_type = 0
7568c2ecf20Sopenharmony_ci	},	/*	obsolete	*/
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	{
7598c2ecf20Sopenharmony_ci		.device_id = "DST-030",
7608c2ecf20Sopenharmony_ci		.offset =  0,
7618c2ecf20Sopenharmony_ci		.dst_type = DST_TYPE_IS_SAT,
7628c2ecf20Sopenharmony_ci		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
7638c2ecf20Sopenharmony_ci		.dst_feature = 0,
7648c2ecf20Sopenharmony_ci		.tuner_type = 0
7658c2ecf20Sopenharmony_ci	},	/*	obsolete	*/
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	{
7688c2ecf20Sopenharmony_ci		.device_id = "DST-03T",
7698c2ecf20Sopenharmony_ci		.offset = 0,
7708c2ecf20Sopenharmony_ci		.dst_type = DST_TYPE_IS_SAT,
7718c2ecf20Sopenharmony_ci		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2,
7728c2ecf20Sopenharmony_ci		.dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5
7738c2ecf20Sopenharmony_ci							 | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO,
7748c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_MULTI
7758c2ecf20Sopenharmony_ci	 },
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	{
7788c2ecf20Sopenharmony_ci		.device_id = "DST-MOT",
7798c2ecf20Sopenharmony_ci		.offset =  0,
7808c2ecf20Sopenharmony_ci		.dst_type = DST_TYPE_IS_SAT,
7818c2ecf20Sopenharmony_ci		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
7828c2ecf20Sopenharmony_ci		.dst_feature = 0,
7838c2ecf20Sopenharmony_ci		.tuner_type = 0
7848c2ecf20Sopenharmony_ci	},	/*	obsolete	*/
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	{
7878c2ecf20Sopenharmony_ci		.device_id = "DST-CI",
7888c2ecf20Sopenharmony_ci		.offset = 1,
7898c2ecf20Sopenharmony_ci		.dst_type = DST_TYPE_IS_SAT,
7908c2ecf20Sopenharmony_ci		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_1,
7918c2ecf20Sopenharmony_ci		.dst_feature = DST_TYPE_HAS_CA,
7928c2ecf20Sopenharmony_ci		.tuner_type = 0
7938c2ecf20Sopenharmony_ci	},	/*	An OEM board	*/
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	{
7968c2ecf20Sopenharmony_ci		.device_id = "DSTMCI",
7978c2ecf20Sopenharmony_ci		.offset = 1,
7988c2ecf20Sopenharmony_ci		.dst_type = DST_TYPE_IS_SAT,
7998c2ecf20Sopenharmony_ci		.type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT | DST_TYPE_HAS_VLF,
8008c2ecf20Sopenharmony_ci		.dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4
8018c2ecf20Sopenharmony_ci							| DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC,
8028c2ecf20Sopenharmony_ci		.tuner_type = TUNER_TYPE_MULTI
8038c2ecf20Sopenharmony_ci	},
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	{
8068c2ecf20Sopenharmony_ci		.device_id = "DSTFCI",
8078c2ecf20Sopenharmony_ci		.offset = 1,
8088c2ecf20Sopenharmony_ci		.dst_type = DST_TYPE_IS_SAT,
8098c2ecf20Sopenharmony_ci		.type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
8108c2ecf20Sopenharmony_ci		.dst_feature = 0,
8118c2ecf20Sopenharmony_ci		.tuner_type = 0
8128c2ecf20Sopenharmony_ci	},	/* unknown to vendor	*/
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	{
8158c2ecf20Sopenharmony_ci		.device_id = "DCT-CI",
8168c2ecf20Sopenharmony_ci		.offset = 1,
8178c2ecf20Sopenharmony_ci		.dst_type = DST_TYPE_IS_CABLE,
8188c2ecf20Sopenharmony_ci		.type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_1	| DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_VLF,
8198c2ecf20Sopenharmony_ci		.dst_feature = DST_TYPE_HAS_CA,
8208c2ecf20Sopenharmony_ci		.tuner_type = 0
8218c2ecf20Sopenharmony_ci	},
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	{
8248c2ecf20Sopenharmony_ci		.device_id = "DCTNEW",
8258c2ecf20Sopenharmony_ci		.offset = 1,
8268c2ecf20Sopenharmony_ci		.dst_type = DST_TYPE_IS_CABLE,
8278c2ecf20Sopenharmony_ci		.type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_MULTI_FE,
8288c2ecf20Sopenharmony_ci		.dst_feature = 0,
8298c2ecf20Sopenharmony_ci		.tuner_type = 0
8308c2ecf20Sopenharmony_ci	},
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	{
8338c2ecf20Sopenharmony_ci		.device_id = "DTT-CI",
8348c2ecf20Sopenharmony_ci		.offset = 1,
8358c2ecf20Sopenharmony_ci		.dst_type = DST_TYPE_IS_TERR,
8368c2ecf20Sopenharmony_ci		.type_flags = DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_VLF,
8378c2ecf20Sopenharmony_ci		.dst_feature = DST_TYPE_HAS_CA,
8388c2ecf20Sopenharmony_ci		.tuner_type = 0
8398c2ecf20Sopenharmony_ci	},
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	{
8428c2ecf20Sopenharmony_ci		.device_id = "DTTDIG",
8438c2ecf20Sopenharmony_ci		.offset = 1,
8448c2ecf20Sopenharmony_ci		.dst_type = DST_TYPE_IS_TERR,
8458c2ecf20Sopenharmony_ci		.type_flags = DST_TYPE_HAS_FW_2,
8468c2ecf20Sopenharmony_ci		.dst_feature = 0,
8478c2ecf20Sopenharmony_ci		.tuner_type = 0
8488c2ecf20Sopenharmony_ci	},
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	{
8518c2ecf20Sopenharmony_ci		.device_id = "DTTNXT",
8528c2ecf20Sopenharmony_ci		.offset = 1,
8538c2ecf20Sopenharmony_ci		.dst_type = DST_TYPE_IS_TERR,
8548c2ecf20Sopenharmony_ci		.type_flags = DST_TYPE_HAS_FW_2,
8558c2ecf20Sopenharmony_ci		.dst_feature = DST_TYPE_HAS_ANALOG,
8568c2ecf20Sopenharmony_ci		.tuner_type = 0
8578c2ecf20Sopenharmony_ci	},
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	{
8608c2ecf20Sopenharmony_ci		.device_id = "ATSCDI",
8618c2ecf20Sopenharmony_ci		.offset = 1,
8628c2ecf20Sopenharmony_ci		.dst_type = DST_TYPE_IS_ATSC,
8638c2ecf20Sopenharmony_ci		.type_flags = DST_TYPE_HAS_FW_2,
8648c2ecf20Sopenharmony_ci		.dst_feature = 0,
8658c2ecf20Sopenharmony_ci		.tuner_type = 0
8668c2ecf20Sopenharmony_ci	},
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	{
8698c2ecf20Sopenharmony_ci		.device_id = "ATSCAD",
8708c2ecf20Sopenharmony_ci		.offset = 1,
8718c2ecf20Sopenharmony_ci		.dst_type = DST_TYPE_IS_ATSC,
8728c2ecf20Sopenharmony_ci		.type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD,
8738c2ecf20Sopenharmony_ci		.dst_feature = DST_TYPE_HAS_MAC | DST_TYPE_HAS_ANALOG,
8748c2ecf20Sopenharmony_ci		.tuner_type = 0
8758c2ecf20Sopenharmony_ci	},
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	{ }
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci};
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_cistatic int dst_get_mac(struct dst_state *state)
8828c2ecf20Sopenharmony_ci{
8838c2ecf20Sopenharmony_ci	u8 get_mac[] = { 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
8848c2ecf20Sopenharmony_ci	get_mac[7] = dst_check_sum(get_mac, 7);
8858c2ecf20Sopenharmony_ci	if (dst_command(state, get_mac, 8) < 0) {
8868c2ecf20Sopenharmony_ci		dprintk(2, "Unsupported Command\n");
8878c2ecf20Sopenharmony_ci		return -1;
8888c2ecf20Sopenharmony_ci	}
8898c2ecf20Sopenharmony_ci	memset(&state->mac_address, '\0', 8);
8908c2ecf20Sopenharmony_ci	memcpy(&state->mac_address, &state->rxbuffer, 6);
8918c2ecf20Sopenharmony_ci	pr_err("MAC Address=[%pM]\n", state->mac_address);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	return 0;
8948c2ecf20Sopenharmony_ci}
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_cistatic int dst_fw_ver(struct dst_state *state)
8978c2ecf20Sopenharmony_ci{
8988c2ecf20Sopenharmony_ci	u8 get_ver[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
8998c2ecf20Sopenharmony_ci	get_ver[7] = dst_check_sum(get_ver, 7);
9008c2ecf20Sopenharmony_ci	if (dst_command(state, get_ver, 8) < 0) {
9018c2ecf20Sopenharmony_ci		dprintk(2, "Unsupported Command\n");
9028c2ecf20Sopenharmony_ci		return -1;
9038c2ecf20Sopenharmony_ci	}
9048c2ecf20Sopenharmony_ci	memcpy(&state->fw_version, &state->rxbuffer, 8);
9058c2ecf20Sopenharmony_ci	pr_err("Firmware Ver = %x.%x Build = %02x, on %x:%x, %x-%x-20%02x\n",
9068c2ecf20Sopenharmony_ci		state->fw_version[0] >> 4, state->fw_version[0] & 0x0f,
9078c2ecf20Sopenharmony_ci		state->fw_version[1],
9088c2ecf20Sopenharmony_ci		state->fw_version[5], state->fw_version[6],
9098c2ecf20Sopenharmony_ci		state->fw_version[4], state->fw_version[3], state->fw_version[2]);
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	return 0;
9128c2ecf20Sopenharmony_ci}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_cistatic int dst_card_type(struct dst_state *state)
9158c2ecf20Sopenharmony_ci{
9168c2ecf20Sopenharmony_ci	int j;
9178c2ecf20Sopenharmony_ci	struct tuner_types *p_tuner_list = NULL;
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
9208c2ecf20Sopenharmony_ci	get_type[7] = dst_check_sum(get_type, 7);
9218c2ecf20Sopenharmony_ci	if (dst_command(state, get_type, 8) < 0) {
9228c2ecf20Sopenharmony_ci		dprintk(2, "Unsupported Command\n");
9238c2ecf20Sopenharmony_ci		return -1;
9248c2ecf20Sopenharmony_ci	}
9258c2ecf20Sopenharmony_ci	memset(&state->card_info, '\0', 8);
9268c2ecf20Sopenharmony_ci	memcpy(&state->card_info, &state->rxbuffer, 7);
9278c2ecf20Sopenharmony_ci	pr_err("Device Model=[%s]\n", &state->card_info[0]);
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
9308c2ecf20Sopenharmony_ci		if (!strcmp(&state->card_info[0], p_tuner_list->board_name)) {
9318c2ecf20Sopenharmony_ci			state->tuner_type = p_tuner_list->tuner_type;
9328c2ecf20Sopenharmony_ci			pr_err("DST has [%s] tuner, tuner type=[%d]\n",
9338c2ecf20Sopenharmony_ci				p_tuner_list->tuner_name, p_tuner_list->tuner_type);
9348c2ecf20Sopenharmony_ci		}
9358c2ecf20Sopenharmony_ci	}
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	return 0;
9388c2ecf20Sopenharmony_ci}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_cistatic int dst_get_vendor(struct dst_state *state)
9418c2ecf20Sopenharmony_ci{
9428c2ecf20Sopenharmony_ci	u8 get_vendor[] = { 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
9438c2ecf20Sopenharmony_ci	get_vendor[7] = dst_check_sum(get_vendor, 7);
9448c2ecf20Sopenharmony_ci	if (dst_command(state, get_vendor, 8) < 0) {
9458c2ecf20Sopenharmony_ci		dprintk(2, "Unsupported Command\n");
9468c2ecf20Sopenharmony_ci		return -1;
9478c2ecf20Sopenharmony_ci	}
9488c2ecf20Sopenharmony_ci	memset(&state->vendor, '\0', 8);
9498c2ecf20Sopenharmony_ci	memcpy(&state->vendor, &state->rxbuffer, 7);
9508c2ecf20Sopenharmony_ci	pr_err("Vendor=[%s]\n", &state->vendor[0]);
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	return 0;
9538c2ecf20Sopenharmony_ci}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_cistatic void debug_dst_buffer(struct dst_state *state)
9568c2ecf20Sopenharmony_ci{
9578c2ecf20Sopenharmony_ci	dprintk(3, "%s: [ %*ph ]\n", __func__, 8, state->rxbuffer);
9588c2ecf20Sopenharmony_ci}
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_cistatic int dst_check_stv0299(struct dst_state *state)
9618c2ecf20Sopenharmony_ci{
9628c2ecf20Sopenharmony_ci	u8 check_stv0299[] = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	check_stv0299[7] = dst_check_sum(check_stv0299, 7);
9658c2ecf20Sopenharmony_ci	if (dst_command(state, check_stv0299, 8) < 0) {
9668c2ecf20Sopenharmony_ci		pr_err("Cmd=[0x04] failed\n");
9678c2ecf20Sopenharmony_ci		return -1;
9688c2ecf20Sopenharmony_ci	}
9698c2ecf20Sopenharmony_ci	debug_dst_buffer(state);
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	if (memcmp(&check_stv0299, &state->rxbuffer, 8)) {
9728c2ecf20Sopenharmony_ci		pr_err("Found a STV0299 NIM\n");
9738c2ecf20Sopenharmony_ci		state->tuner_type = TUNER_TYPE_STV0299;
9748c2ecf20Sopenharmony_ci		return 0;
9758c2ecf20Sopenharmony_ci	}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	return -1;
9788c2ecf20Sopenharmony_ci}
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_cistatic int dst_check_mb86a15(struct dst_state *state)
9818c2ecf20Sopenharmony_ci{
9828c2ecf20Sopenharmony_ci	u8 check_mb86a15[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	check_mb86a15[7] = dst_check_sum(check_mb86a15, 7);
9858c2ecf20Sopenharmony_ci	if (dst_command(state, check_mb86a15, 8) < 0) {
9868c2ecf20Sopenharmony_ci		pr_err("Cmd=[0x10], failed\n");
9878c2ecf20Sopenharmony_ci		return -1;
9888c2ecf20Sopenharmony_ci	}
9898c2ecf20Sopenharmony_ci	debug_dst_buffer(state);
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	if (memcmp(&check_mb86a15, &state->rxbuffer, 8) < 0) {
9928c2ecf20Sopenharmony_ci		pr_err("Found a MB86A15 NIM\n");
9938c2ecf20Sopenharmony_ci		state->tuner_type = TUNER_TYPE_MB86A15;
9948c2ecf20Sopenharmony_ci		return 0;
9958c2ecf20Sopenharmony_ci	}
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	return -1;
9988c2ecf20Sopenharmony_ci}
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_cistatic int dst_get_tuner_info(struct dst_state *state)
10018c2ecf20Sopenharmony_ci{
10028c2ecf20Sopenharmony_ci	u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
10038c2ecf20Sopenharmony_ci	u8 get_tuner_2[] = { 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	get_tuner_1[7] = dst_check_sum(get_tuner_1, 7);
10068c2ecf20Sopenharmony_ci	get_tuner_2[7] = dst_check_sum(get_tuner_2, 7);
10078c2ecf20Sopenharmony_ci	pr_err("DST TYpe = MULTI FE\n");
10088c2ecf20Sopenharmony_ci	if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
10098c2ecf20Sopenharmony_ci		if (dst_command(state, get_tuner_1, 8) < 0) {
10108c2ecf20Sopenharmony_ci			dprintk(2, "Cmd=[0x13], Unsupported\n");
10118c2ecf20Sopenharmony_ci			goto force;
10128c2ecf20Sopenharmony_ci		}
10138c2ecf20Sopenharmony_ci	} else {
10148c2ecf20Sopenharmony_ci		if (dst_command(state, get_tuner_2, 8) < 0) {
10158c2ecf20Sopenharmony_ci			dprintk(2, "Cmd=[0xb], Unsupported\n");
10168c2ecf20Sopenharmony_ci			goto force;
10178c2ecf20Sopenharmony_ci		}
10188c2ecf20Sopenharmony_ci	}
10198c2ecf20Sopenharmony_ci	memcpy(&state->board_info, &state->rxbuffer, 8);
10208c2ecf20Sopenharmony_ci	if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
10218c2ecf20Sopenharmony_ci		pr_err("DST type has TS=188\n");
10228c2ecf20Sopenharmony_ci	}
10238c2ecf20Sopenharmony_ci	if (state->board_info[0] == 0xbc) {
10248c2ecf20Sopenharmony_ci		if (state->dst_type != DST_TYPE_IS_ATSC)
10258c2ecf20Sopenharmony_ci			state->type_flags |= DST_TYPE_HAS_TS188;
10268c2ecf20Sopenharmony_ci		else
10278c2ecf20Sopenharmony_ci			state->type_flags |= DST_TYPE_HAS_NEWTUNE_2;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci		if (state->board_info[1] == 0x01) {
10308c2ecf20Sopenharmony_ci			state->dst_hw_cap |= DST_TYPE_HAS_DBOARD;
10318c2ecf20Sopenharmony_ci			pr_err("DST has Daughterboard\n");
10328c2ecf20Sopenharmony_ci		}
10338c2ecf20Sopenharmony_ci	}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	return 0;
10368c2ecf20Sopenharmony_ciforce:
10378c2ecf20Sopenharmony_ci	if (!strncmp(state->fw_name, "DCT-CI", 6)) {
10388c2ecf20Sopenharmony_ci		state->type_flags |= DST_TYPE_HAS_TS204;
10398c2ecf20Sopenharmony_ci		pr_err("Forcing [%s] to TS188\n", state->fw_name);
10408c2ecf20Sopenharmony_ci	}
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	return -1;
10438c2ecf20Sopenharmony_ci}
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_cistatic int dst_get_device_id(struct dst_state *state)
10468c2ecf20Sopenharmony_ci{
10478c2ecf20Sopenharmony_ci	u8 reply;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	int i, j;
10508c2ecf20Sopenharmony_ci	struct dst_types *p_dst_type = NULL;
10518c2ecf20Sopenharmony_ci	struct tuner_types *p_tuner_list = NULL;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	u8 use_dst_type = 0;
10548c2ecf20Sopenharmony_ci	u32 use_type_flags = 0;
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	state->tuner_type = 0;
10598c2ecf20Sopenharmony_ci	device_type[7] = dst_check_sum(device_type, 7);
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	if (write_dst(state, device_type, FIXED_COMM))
10628c2ecf20Sopenharmony_ci		return -1;		/*	Write failed		*/
10638c2ecf20Sopenharmony_ci	if ((dst_pio_disable(state)) < 0)
10648c2ecf20Sopenharmony_ci		return -1;
10658c2ecf20Sopenharmony_ci	if (read_dst(state, &reply, GET_ACK))
10668c2ecf20Sopenharmony_ci		return -1;		/*	Read failure		*/
10678c2ecf20Sopenharmony_ci	if (reply != ACK) {
10688c2ecf20Sopenharmony_ci		dprintk(2, "Write not Acknowledged! [Reply=0x%02x]\n", reply);
10698c2ecf20Sopenharmony_ci		return -1;		/*	Unack'd write		*/
10708c2ecf20Sopenharmony_ci	}
10718c2ecf20Sopenharmony_ci	if (!dst_wait_dst_ready(state, DEVICE_INIT))
10728c2ecf20Sopenharmony_ci		return -1;		/*	DST not ready yet	*/
10738c2ecf20Sopenharmony_ci	if (read_dst(state, state->rxbuffer, FIXED_COMM))
10748c2ecf20Sopenharmony_ci		return -1;
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	dst_pio_disable(state);
10778c2ecf20Sopenharmony_ci	if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) {
10788c2ecf20Sopenharmony_ci		dprintk(2, "Checksum failure!\n");
10798c2ecf20Sopenharmony_ci		return -1;		/*	Checksum failure	*/
10808c2ecf20Sopenharmony_ci	}
10818c2ecf20Sopenharmony_ci	state->rxbuffer[7] = '\0';
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	for (i = 0, p_dst_type = dst_tlist; i < ARRAY_SIZE(dst_tlist); i++, p_dst_type++) {
10848c2ecf20Sopenharmony_ci		if (!strncmp (&state->rxbuffer[p_dst_type->offset], p_dst_type->device_id, strlen (p_dst_type->device_id))) {
10858c2ecf20Sopenharmony_ci			use_type_flags = p_dst_type->type_flags;
10868c2ecf20Sopenharmony_ci			use_dst_type = p_dst_type->dst_type;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci			/*	Card capabilities	*/
10898c2ecf20Sopenharmony_ci			state->dst_hw_cap = p_dst_type->dst_feature;
10908c2ecf20Sopenharmony_ci			pr_err("Recognise [%s]\n", p_dst_type->device_id);
10918c2ecf20Sopenharmony_ci			strscpy(state->fw_name, p_dst_type->device_id,
10928c2ecf20Sopenharmony_ci			        sizeof(state->fw_name));
10938c2ecf20Sopenharmony_ci			/*	Multiple tuners		*/
10948c2ecf20Sopenharmony_ci			if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) {
10958c2ecf20Sopenharmony_ci				switch (use_dst_type) {
10968c2ecf20Sopenharmony_ci				case DST_TYPE_IS_SAT:
10978c2ecf20Sopenharmony_ci					/*	STV0299 check	*/
10988c2ecf20Sopenharmony_ci					if (dst_check_stv0299(state) < 0) {
10998c2ecf20Sopenharmony_ci						pr_err("Unsupported\n");
11008c2ecf20Sopenharmony_ci						state->tuner_type = TUNER_TYPE_MB86A15;
11018c2ecf20Sopenharmony_ci					}
11028c2ecf20Sopenharmony_ci					break;
11038c2ecf20Sopenharmony_ci				default:
11048c2ecf20Sopenharmony_ci					break;
11058c2ecf20Sopenharmony_ci				}
11068c2ecf20Sopenharmony_ci				if (dst_check_mb86a15(state) < 0)
11078c2ecf20Sopenharmony_ci					pr_err("Unsupported\n");
11088c2ecf20Sopenharmony_ci			/*	Single tuner		*/
11098c2ecf20Sopenharmony_ci			} else {
11108c2ecf20Sopenharmony_ci				state->tuner_type = p_dst_type->tuner_type;
11118c2ecf20Sopenharmony_ci			}
11128c2ecf20Sopenharmony_ci			for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
11138c2ecf20Sopenharmony_ci				if (!(strncmp(p_dst_type->device_id, p_tuner_list->fw_name, 7)) &&
11148c2ecf20Sopenharmony_ci					p_tuner_list->tuner_type == state->tuner_type) {
11158c2ecf20Sopenharmony_ci					pr_err("[%s] has a [%s]\n",
11168c2ecf20Sopenharmony_ci						p_dst_type->device_id, p_tuner_list->tuner_name);
11178c2ecf20Sopenharmony_ci				}
11188c2ecf20Sopenharmony_ci			}
11198c2ecf20Sopenharmony_ci			break;
11208c2ecf20Sopenharmony_ci		}
11218c2ecf20Sopenharmony_ci	}
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci	if (i >= ARRAY_SIZE(dst_tlist)) {
11248c2ecf20Sopenharmony_ci		pr_err("Unable to recognize %s or %s\n", &state->rxbuffer[0], &state->rxbuffer[1]);
11258c2ecf20Sopenharmony_ci		pr_err("please email linux-dvb@linuxtv.org with this type in");
11268c2ecf20Sopenharmony_ci		use_dst_type = DST_TYPE_IS_SAT;
11278c2ecf20Sopenharmony_ci		use_type_flags = DST_TYPE_HAS_SYMDIV;
11288c2ecf20Sopenharmony_ci	}
11298c2ecf20Sopenharmony_ci	dst_type_print(state, use_dst_type);
11308c2ecf20Sopenharmony_ci	state->type_flags = use_type_flags;
11318c2ecf20Sopenharmony_ci	state->dst_type = use_dst_type;
11328c2ecf20Sopenharmony_ci	dst_type_flags_print(state);
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	return 0;
11358c2ecf20Sopenharmony_ci}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_cistatic int dst_probe(struct dst_state *state)
11388c2ecf20Sopenharmony_ci{
11398c2ecf20Sopenharmony_ci	mutex_init(&state->dst_mutex);
11408c2ecf20Sopenharmony_ci	if (dst_addons & DST_TYPE_HAS_CA) {
11418c2ecf20Sopenharmony_ci		if ((rdc_8820_reset(state)) < 0) {
11428c2ecf20Sopenharmony_ci			pr_err("RDC 8820 RESET Failed.\n");
11438c2ecf20Sopenharmony_ci			return -1;
11448c2ecf20Sopenharmony_ci		}
11458c2ecf20Sopenharmony_ci		msleep(4000);
11468c2ecf20Sopenharmony_ci	} else {
11478c2ecf20Sopenharmony_ci		msleep(100);
11488c2ecf20Sopenharmony_ci	}
11498c2ecf20Sopenharmony_ci	if ((dst_comm_init(state)) < 0) {
11508c2ecf20Sopenharmony_ci		pr_err("DST Initialization Failed.\n");
11518c2ecf20Sopenharmony_ci		return -1;
11528c2ecf20Sopenharmony_ci	}
11538c2ecf20Sopenharmony_ci	msleep(100);
11548c2ecf20Sopenharmony_ci	if (dst_get_device_id(state) < 0) {
11558c2ecf20Sopenharmony_ci		pr_err("unknown device.\n");
11568c2ecf20Sopenharmony_ci		return -1;
11578c2ecf20Sopenharmony_ci	}
11588c2ecf20Sopenharmony_ci	if (dst_get_mac(state) < 0) {
11598c2ecf20Sopenharmony_ci		dprintk(2, "MAC: Unsupported command\n");
11608c2ecf20Sopenharmony_ci	}
11618c2ecf20Sopenharmony_ci	if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) {
11628c2ecf20Sopenharmony_ci		if (dst_get_tuner_info(state) < 0)
11638c2ecf20Sopenharmony_ci			dprintk(2, "Tuner: Unsupported command\n");
11648c2ecf20Sopenharmony_ci	}
11658c2ecf20Sopenharmony_ci	if (state->type_flags & DST_TYPE_HAS_TS204) {
11668c2ecf20Sopenharmony_ci		dst_packsize(state, 204);
11678c2ecf20Sopenharmony_ci	}
11688c2ecf20Sopenharmony_ci	if (state->type_flags & DST_TYPE_HAS_FW_BUILD) {
11698c2ecf20Sopenharmony_ci		if (dst_fw_ver(state) < 0) {
11708c2ecf20Sopenharmony_ci			dprintk(2, "FW: Unsupported command\n");
11718c2ecf20Sopenharmony_ci			return 0;
11728c2ecf20Sopenharmony_ci		}
11738c2ecf20Sopenharmony_ci		if (dst_card_type(state) < 0) {
11748c2ecf20Sopenharmony_ci			dprintk(2, "Card: Unsupported command\n");
11758c2ecf20Sopenharmony_ci			return 0;
11768c2ecf20Sopenharmony_ci		}
11778c2ecf20Sopenharmony_ci		if (dst_get_vendor(state) < 0) {
11788c2ecf20Sopenharmony_ci			dprintk(2, "Vendor: Unsupported command\n");
11798c2ecf20Sopenharmony_ci			return 0;
11808c2ecf20Sopenharmony_ci		}
11818c2ecf20Sopenharmony_ci	}
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	return 0;
11848c2ecf20Sopenharmony_ci}
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_cistatic int dst_command(struct dst_state *state, u8 *data, u8 len)
11878c2ecf20Sopenharmony_ci{
11888c2ecf20Sopenharmony_ci	u8 reply;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	mutex_lock(&state->dst_mutex);
11918c2ecf20Sopenharmony_ci	if ((dst_comm_init(state)) < 0) {
11928c2ecf20Sopenharmony_ci		dprintk(1, "DST Communication Initialization Failed.\n");
11938c2ecf20Sopenharmony_ci		goto error;
11948c2ecf20Sopenharmony_ci	}
11958c2ecf20Sopenharmony_ci	if (write_dst(state, data, len)) {
11968c2ecf20Sopenharmony_ci		dprintk(2, "Trying to recover..\n");
11978c2ecf20Sopenharmony_ci		if ((dst_error_recovery(state)) < 0) {
11988c2ecf20Sopenharmony_ci			pr_err("Recovery Failed.\n");
11998c2ecf20Sopenharmony_ci			goto error;
12008c2ecf20Sopenharmony_ci		}
12018c2ecf20Sopenharmony_ci		goto error;
12028c2ecf20Sopenharmony_ci	}
12038c2ecf20Sopenharmony_ci	if ((dst_pio_disable(state)) < 0) {
12048c2ecf20Sopenharmony_ci		pr_err("PIO Disable Failed.\n");
12058c2ecf20Sopenharmony_ci		goto error;
12068c2ecf20Sopenharmony_ci	}
12078c2ecf20Sopenharmony_ci	if (state->type_flags & DST_TYPE_HAS_FW_1)
12088c2ecf20Sopenharmony_ci		mdelay(3);
12098c2ecf20Sopenharmony_ci	if (read_dst(state, &reply, GET_ACK)) {
12108c2ecf20Sopenharmony_ci		dprintk(3, "Trying to recover..\n");
12118c2ecf20Sopenharmony_ci		if ((dst_error_recovery(state)) < 0) {
12128c2ecf20Sopenharmony_ci			dprintk(2, "Recovery Failed.\n");
12138c2ecf20Sopenharmony_ci			goto error;
12148c2ecf20Sopenharmony_ci		}
12158c2ecf20Sopenharmony_ci		goto error;
12168c2ecf20Sopenharmony_ci	}
12178c2ecf20Sopenharmony_ci	if (reply != ACK) {
12188c2ecf20Sopenharmony_ci		dprintk(2, "write not acknowledged 0x%02x\n", reply);
12198c2ecf20Sopenharmony_ci		goto error;
12208c2ecf20Sopenharmony_ci	}
12218c2ecf20Sopenharmony_ci	if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3))
12228c2ecf20Sopenharmony_ci		goto error;
12238c2ecf20Sopenharmony_ci	if (state->type_flags & DST_TYPE_HAS_FW_1)
12248c2ecf20Sopenharmony_ci		mdelay(3);
12258c2ecf20Sopenharmony_ci	else
12268c2ecf20Sopenharmony_ci		udelay(2000);
12278c2ecf20Sopenharmony_ci	if (!dst_wait_dst_ready(state, NO_DELAY))
12288c2ecf20Sopenharmony_ci		goto error;
12298c2ecf20Sopenharmony_ci	if (read_dst(state, state->rxbuffer, FIXED_COMM)) {
12308c2ecf20Sopenharmony_ci		dprintk(3, "Trying to recover..\n");
12318c2ecf20Sopenharmony_ci		if ((dst_error_recovery(state)) < 0) {
12328c2ecf20Sopenharmony_ci			dprintk(2, "Recovery failed.\n");
12338c2ecf20Sopenharmony_ci			goto error;
12348c2ecf20Sopenharmony_ci		}
12358c2ecf20Sopenharmony_ci		goto error;
12368c2ecf20Sopenharmony_ci	}
12378c2ecf20Sopenharmony_ci	if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) {
12388c2ecf20Sopenharmony_ci		dprintk(2, "checksum failure\n");
12398c2ecf20Sopenharmony_ci		goto error;
12408c2ecf20Sopenharmony_ci	}
12418c2ecf20Sopenharmony_ci	mutex_unlock(&state->dst_mutex);
12428c2ecf20Sopenharmony_ci	return 0;
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_cierror:
12458c2ecf20Sopenharmony_ci	mutex_unlock(&state->dst_mutex);
12468c2ecf20Sopenharmony_ci	return -EIO;
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci}
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_cistatic int dst_get_signal(struct dst_state *state)
12518c2ecf20Sopenharmony_ci{
12528c2ecf20Sopenharmony_ci	int retval;
12538c2ecf20Sopenharmony_ci	u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb };
12548c2ecf20Sopenharmony_ci	//dprintk("%s: Getting Signal strength and other parameters\n", __func__);
12558c2ecf20Sopenharmony_ci	if ((state->diseq_flags & ATTEMPT_TUNE) == 0) {
12568c2ecf20Sopenharmony_ci		state->decode_lock = state->decode_strength = state->decode_snr = 0;
12578c2ecf20Sopenharmony_ci		return 0;
12588c2ecf20Sopenharmony_ci	}
12598c2ecf20Sopenharmony_ci	if (0 == (state->diseq_flags & HAS_LOCK)) {
12608c2ecf20Sopenharmony_ci		state->decode_lock = state->decode_strength = state->decode_snr = 0;
12618c2ecf20Sopenharmony_ci		return 0;
12628c2ecf20Sopenharmony_ci	}
12638c2ecf20Sopenharmony_ci	if (time_after_eq(jiffies, state->cur_jiff + (HZ / 5))) {
12648c2ecf20Sopenharmony_ci		retval = dst_command(state, get_signal, 8);
12658c2ecf20Sopenharmony_ci		if (retval < 0)
12668c2ecf20Sopenharmony_ci			return retval;
12678c2ecf20Sopenharmony_ci		if (state->dst_type == DST_TYPE_IS_SAT) {
12688c2ecf20Sopenharmony_ci			state->decode_lock = ((state->rxbuffer[6] & 0x10) == 0) ? 1 : 0;
12698c2ecf20Sopenharmony_ci			state->decode_strength = state->rxbuffer[5] << 8;
12708c2ecf20Sopenharmony_ci			state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3];
12718c2ecf20Sopenharmony_ci		} else if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) {
12728c2ecf20Sopenharmony_ci			state->decode_lock = (state->rxbuffer[1]) ? 1 : 0;
12738c2ecf20Sopenharmony_ci			state->decode_strength = state->rxbuffer[4] << 8;
12748c2ecf20Sopenharmony_ci			state->decode_snr = state->rxbuffer[3] << 8;
12758c2ecf20Sopenharmony_ci		} else if (state->dst_type == DST_TYPE_IS_ATSC) {
12768c2ecf20Sopenharmony_ci			state->decode_lock = (state->rxbuffer[6] == 0x00) ? 1 : 0;
12778c2ecf20Sopenharmony_ci			state->decode_strength = state->rxbuffer[4] << 8;
12788c2ecf20Sopenharmony_ci			state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3];
12798c2ecf20Sopenharmony_ci		}
12808c2ecf20Sopenharmony_ci		state->cur_jiff = jiffies;
12818c2ecf20Sopenharmony_ci	}
12828c2ecf20Sopenharmony_ci	return 0;
12838c2ecf20Sopenharmony_ci}
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_cistatic int dst_tone_power_cmd(struct dst_state *state)
12868c2ecf20Sopenharmony_ci{
12878c2ecf20Sopenharmony_ci	u8 packet[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 };
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	if (state->dst_type != DST_TYPE_IS_SAT)
12908c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
12918c2ecf20Sopenharmony_ci	packet[4] = state->tx_tuna[4];
12928c2ecf20Sopenharmony_ci	packet[2] = state->tx_tuna[2];
12938c2ecf20Sopenharmony_ci	packet[3] = state->tx_tuna[3];
12948c2ecf20Sopenharmony_ci	packet[7] = dst_check_sum (packet, 7);
12958c2ecf20Sopenharmony_ci	return dst_command(state, packet, 8);
12968c2ecf20Sopenharmony_ci}
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_cistatic int dst_get_tuna(struct dst_state *state)
12998c2ecf20Sopenharmony_ci{
13008c2ecf20Sopenharmony_ci	int retval;
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	if ((state->diseq_flags & ATTEMPT_TUNE) == 0)
13038c2ecf20Sopenharmony_ci		return 0;
13048c2ecf20Sopenharmony_ci	state->diseq_flags &= ~(HAS_LOCK);
13058c2ecf20Sopenharmony_ci	if (!dst_wait_dst_ready(state, NO_DELAY))
13068c2ecf20Sopenharmony_ci		return -EIO;
13078c2ecf20Sopenharmony_ci	if ((state->type_flags & DST_TYPE_HAS_VLF) &&
13088c2ecf20Sopenharmony_ci		!(state->dst_type == DST_TYPE_IS_ATSC))
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci		retval = read_dst(state, state->rx_tuna, 10);
13118c2ecf20Sopenharmony_ci	else
13128c2ecf20Sopenharmony_ci		retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM);
13138c2ecf20Sopenharmony_ci	if (retval < 0) {
13148c2ecf20Sopenharmony_ci		dprintk(3, "read not successful\n");
13158c2ecf20Sopenharmony_ci		return retval;
13168c2ecf20Sopenharmony_ci	}
13178c2ecf20Sopenharmony_ci	if ((state->type_flags & DST_TYPE_HAS_VLF) &&
13188c2ecf20Sopenharmony_ci	   !(state->dst_type == DST_TYPE_IS_ATSC)) {
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci		if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
13218c2ecf20Sopenharmony_ci			dprintk(2, "checksum failure ?\n");
13228c2ecf20Sopenharmony_ci			return -EIO;
13238c2ecf20Sopenharmony_ci		}
13248c2ecf20Sopenharmony_ci	} else {
13258c2ecf20Sopenharmony_ci		if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) {
13268c2ecf20Sopenharmony_ci			dprintk(2, "checksum failure?\n");
13278c2ecf20Sopenharmony_ci			return -EIO;
13288c2ecf20Sopenharmony_ci		}
13298c2ecf20Sopenharmony_ci	}
13308c2ecf20Sopenharmony_ci	if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0)
13318c2ecf20Sopenharmony_ci		return 0;
13328c2ecf20Sopenharmony_ci	if (state->dst_type == DST_TYPE_IS_SAT) {
13338c2ecf20Sopenharmony_ci		state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3];
13348c2ecf20Sopenharmony_ci	} else {
13358c2ecf20Sopenharmony_ci		state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 16) + (state->rx_tuna[3] << 8) + state->rx_tuna[4];
13368c2ecf20Sopenharmony_ci	}
13378c2ecf20Sopenharmony_ci	state->decode_freq = state->decode_freq * 1000;
13388c2ecf20Sopenharmony_ci	state->decode_lock = 1;
13398c2ecf20Sopenharmony_ci	state->diseq_flags |= HAS_LOCK;
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	return 1;
13428c2ecf20Sopenharmony_ci}
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_cistatic int dst_set_voltage(struct dvb_frontend *fe,
13458c2ecf20Sopenharmony_ci			   enum fe_sec_voltage voltage);
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_cistatic int dst_write_tuna(struct dvb_frontend *fe)
13488c2ecf20Sopenharmony_ci{
13498c2ecf20Sopenharmony_ci	struct dst_state *state = fe->demodulator_priv;
13508c2ecf20Sopenharmony_ci	int retval;
13518c2ecf20Sopenharmony_ci	u8 reply;
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	dprintk(2, "type_flags 0x%x\n", state->type_flags);
13548c2ecf20Sopenharmony_ci	state->decode_freq = 0;
13558c2ecf20Sopenharmony_ci	state->decode_lock = state->decode_strength = state->decode_snr = 0;
13568c2ecf20Sopenharmony_ci	if (state->dst_type == DST_TYPE_IS_SAT) {
13578c2ecf20Sopenharmony_ci		if (!(state->diseq_flags & HAS_POWER))
13588c2ecf20Sopenharmony_ci			dst_set_voltage(fe, SEC_VOLTAGE_13);
13598c2ecf20Sopenharmony_ci	}
13608c2ecf20Sopenharmony_ci	state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
13618c2ecf20Sopenharmony_ci	mutex_lock(&state->dst_mutex);
13628c2ecf20Sopenharmony_ci	if ((dst_comm_init(state)) < 0) {
13638c2ecf20Sopenharmony_ci		dprintk(3, "DST Communication initialization failed.\n");
13648c2ecf20Sopenharmony_ci		goto error;
13658c2ecf20Sopenharmony_ci	}
13668c2ecf20Sopenharmony_ci//	if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
13678c2ecf20Sopenharmony_ci	if ((state->type_flags & DST_TYPE_HAS_VLF) &&
13688c2ecf20Sopenharmony_ci		(!(state->dst_type == DST_TYPE_IS_ATSC))) {
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci		state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9);
13718c2ecf20Sopenharmony_ci		retval = write_dst(state, &state->tx_tuna[0], 10);
13728c2ecf20Sopenharmony_ci	} else {
13738c2ecf20Sopenharmony_ci		state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7);
13748c2ecf20Sopenharmony_ci		retval = write_dst(state, &state->tx_tuna[2], FIXED_COMM);
13758c2ecf20Sopenharmony_ci	}
13768c2ecf20Sopenharmony_ci	if (retval < 0) {
13778c2ecf20Sopenharmony_ci		dst_pio_disable(state);
13788c2ecf20Sopenharmony_ci		dprintk(3, "write not successful\n");
13798c2ecf20Sopenharmony_ci		goto werr;
13808c2ecf20Sopenharmony_ci	}
13818c2ecf20Sopenharmony_ci	if ((dst_pio_disable(state)) < 0) {
13828c2ecf20Sopenharmony_ci		dprintk(3, "DST PIO disable failed !\n");
13838c2ecf20Sopenharmony_ci		goto error;
13848c2ecf20Sopenharmony_ci	}
13858c2ecf20Sopenharmony_ci	if ((read_dst(state, &reply, GET_ACK) < 0)) {
13868c2ecf20Sopenharmony_ci		dprintk(3, "read verify not successful.\n");
13878c2ecf20Sopenharmony_ci		goto error;
13888c2ecf20Sopenharmony_ci	}
13898c2ecf20Sopenharmony_ci	if (reply != ACK) {
13908c2ecf20Sopenharmony_ci		dprintk(3, "write not acknowledged 0x%02x\n", reply);
13918c2ecf20Sopenharmony_ci		goto error;
13928c2ecf20Sopenharmony_ci	}
13938c2ecf20Sopenharmony_ci	state->diseq_flags |= ATTEMPT_TUNE;
13948c2ecf20Sopenharmony_ci	retval = dst_get_tuna(state);
13958c2ecf20Sopenharmony_ciwerr:
13968c2ecf20Sopenharmony_ci	mutex_unlock(&state->dst_mutex);
13978c2ecf20Sopenharmony_ci	return retval;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_cierror:
14008c2ecf20Sopenharmony_ci	mutex_unlock(&state->dst_mutex);
14018c2ecf20Sopenharmony_ci	return -EIO;
14028c2ecf20Sopenharmony_ci}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci/*
14058c2ecf20Sopenharmony_ci * line22k0    0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00
14068c2ecf20Sopenharmony_ci * line22k1    0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00
14078c2ecf20Sopenharmony_ci * line22k2    0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00
14088c2ecf20Sopenharmony_ci * tone        0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00
14098c2ecf20Sopenharmony_ci * data        0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00
14108c2ecf20Sopenharmony_ci * power_off   0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00
14118c2ecf20Sopenharmony_ci * power_on    0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00
14128c2ecf20Sopenharmony_ci * Diseqc 1    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec
14138c2ecf20Sopenharmony_ci * Diseqc 2    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8
14148c2ecf20Sopenharmony_ci * Diseqc 3    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4
14158c2ecf20Sopenharmony_ci * Diseqc 4    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0
14168c2ecf20Sopenharmony_ci */
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_cistatic int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd)
14198c2ecf20Sopenharmony_ci{
14208c2ecf20Sopenharmony_ci	struct dst_state *state = fe->demodulator_priv;
14218c2ecf20Sopenharmony_ci	u8 packet[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec };
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	if (state->dst_type != DST_TYPE_IS_SAT)
14248c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
14258c2ecf20Sopenharmony_ci	if (cmd->msg_len > 0 && cmd->msg_len < 5)
14268c2ecf20Sopenharmony_ci		memcpy(&packet[3], cmd->msg, cmd->msg_len);
14278c2ecf20Sopenharmony_ci	else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5)
14288c2ecf20Sopenharmony_ci		memcpy(&packet[2], cmd->msg, cmd->msg_len);
14298c2ecf20Sopenharmony_ci	else
14308c2ecf20Sopenharmony_ci		return -EINVAL;
14318c2ecf20Sopenharmony_ci	packet[7] = dst_check_sum(&packet[0], 7);
14328c2ecf20Sopenharmony_ci	return dst_command(state, packet, 8);
14338c2ecf20Sopenharmony_ci}
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_cistatic int dst_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage)
14368c2ecf20Sopenharmony_ci{
14378c2ecf20Sopenharmony_ci	int need_cmd, retval = 0;
14388c2ecf20Sopenharmony_ci	struct dst_state *state = fe->demodulator_priv;
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	state->voltage = voltage;
14418c2ecf20Sopenharmony_ci	if (state->dst_type != DST_TYPE_IS_SAT)
14428c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	need_cmd = 0;
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci	switch (voltage) {
14478c2ecf20Sopenharmony_ci	case SEC_VOLTAGE_13:
14488c2ecf20Sopenharmony_ci	case SEC_VOLTAGE_18:
14498c2ecf20Sopenharmony_ci		if ((state->diseq_flags & HAS_POWER) == 0)
14508c2ecf20Sopenharmony_ci			need_cmd = 1;
14518c2ecf20Sopenharmony_ci		state->diseq_flags |= HAS_POWER;
14528c2ecf20Sopenharmony_ci		state->tx_tuna[4] = 0x01;
14538c2ecf20Sopenharmony_ci		break;
14548c2ecf20Sopenharmony_ci	case SEC_VOLTAGE_OFF:
14558c2ecf20Sopenharmony_ci		need_cmd = 1;
14568c2ecf20Sopenharmony_ci		state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE);
14578c2ecf20Sopenharmony_ci		state->tx_tuna[4] = 0x00;
14588c2ecf20Sopenharmony_ci		break;
14598c2ecf20Sopenharmony_ci	default:
14608c2ecf20Sopenharmony_ci		return -EINVAL;
14618c2ecf20Sopenharmony_ci	}
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	if (need_cmd)
14648c2ecf20Sopenharmony_ci		retval = dst_tone_power_cmd(state);
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci	return retval;
14678c2ecf20Sopenharmony_ci}
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_cistatic int dst_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone)
14708c2ecf20Sopenharmony_ci{
14718c2ecf20Sopenharmony_ci	struct dst_state *state = fe->demodulator_priv;
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	state->tone = tone;
14748c2ecf20Sopenharmony_ci	if (state->dst_type != DST_TYPE_IS_SAT)
14758c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	switch (tone) {
14788c2ecf20Sopenharmony_ci	case SEC_TONE_OFF:
14798c2ecf20Sopenharmony_ci		if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
14808c2ecf20Sopenharmony_ci		    state->tx_tuna[2] = 0x00;
14818c2ecf20Sopenharmony_ci		else
14828c2ecf20Sopenharmony_ci		    state->tx_tuna[2] = 0xff;
14838c2ecf20Sopenharmony_ci		break;
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_ci	case SEC_TONE_ON:
14868c2ecf20Sopenharmony_ci		state->tx_tuna[2] = 0x02;
14878c2ecf20Sopenharmony_ci		break;
14888c2ecf20Sopenharmony_ci	default:
14898c2ecf20Sopenharmony_ci		return -EINVAL;
14908c2ecf20Sopenharmony_ci	}
14918c2ecf20Sopenharmony_ci	return dst_tone_power_cmd(state);
14928c2ecf20Sopenharmony_ci}
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_cistatic int dst_send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd minicmd)
14958c2ecf20Sopenharmony_ci{
14968c2ecf20Sopenharmony_ci	struct dst_state *state = fe->demodulator_priv;
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	if (state->dst_type != DST_TYPE_IS_SAT)
14998c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
15008c2ecf20Sopenharmony_ci	state->minicmd = minicmd;
15018c2ecf20Sopenharmony_ci	switch (minicmd) {
15028c2ecf20Sopenharmony_ci	case SEC_MINI_A:
15038c2ecf20Sopenharmony_ci		state->tx_tuna[3] = 0x02;
15048c2ecf20Sopenharmony_ci		break;
15058c2ecf20Sopenharmony_ci	case SEC_MINI_B:
15068c2ecf20Sopenharmony_ci		state->tx_tuna[3] = 0xff;
15078c2ecf20Sopenharmony_ci		break;
15088c2ecf20Sopenharmony_ci	}
15098c2ecf20Sopenharmony_ci	return dst_tone_power_cmd(state);
15108c2ecf20Sopenharmony_ci}
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_cistatic int bt8xx_dst_init(struct dvb_frontend *fe)
15148c2ecf20Sopenharmony_ci{
15158c2ecf20Sopenharmony_ci	struct dst_state *state = fe->demodulator_priv;
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	static u8 sat_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x00, 0x73, 0x21, 0x00, 0x00 };
15188c2ecf20Sopenharmony_ci	static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 };
15198c2ecf20Sopenharmony_ci	static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
15208c2ecf20Sopenharmony_ci	static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
15218c2ecf20Sopenharmony_ci	static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
15228c2ecf20Sopenharmony_ci	static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
15238c2ecf20Sopenharmony_ci	static u8 atsc_tuner[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci	state->inversion = INVERSION_OFF;
15268c2ecf20Sopenharmony_ci	state->voltage = SEC_VOLTAGE_13;
15278c2ecf20Sopenharmony_ci	state->tone = SEC_TONE_OFF;
15288c2ecf20Sopenharmony_ci	state->diseq_flags = 0;
15298c2ecf20Sopenharmony_ci	state->k22 = 0x02;
15308c2ecf20Sopenharmony_ci	state->bandwidth = 7000000;
15318c2ecf20Sopenharmony_ci	state->cur_jiff = jiffies;
15328c2ecf20Sopenharmony_ci	if (state->dst_type == DST_TYPE_IS_SAT)
15338c2ecf20Sopenharmony_ci		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204));
15348c2ecf20Sopenharmony_ci	else if (state->dst_type == DST_TYPE_IS_TERR)
15358c2ecf20Sopenharmony_ci		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204));
15368c2ecf20Sopenharmony_ci	else if (state->dst_type == DST_TYPE_IS_CABLE)
15378c2ecf20Sopenharmony_ci		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204));
15388c2ecf20Sopenharmony_ci	else if (state->dst_type == DST_TYPE_IS_ATSC)
15398c2ecf20Sopenharmony_ci		memcpy(state->tx_tuna, atsc_tuner, sizeof (atsc_tuner));
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	return 0;
15428c2ecf20Sopenharmony_ci}
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_cistatic int dst_read_status(struct dvb_frontend *fe, enum fe_status *status)
15458c2ecf20Sopenharmony_ci{
15468c2ecf20Sopenharmony_ci	struct dst_state *state = fe->demodulator_priv;
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	*status = 0;
15498c2ecf20Sopenharmony_ci	if (state->diseq_flags & HAS_LOCK) {
15508c2ecf20Sopenharmony_ci//		dst_get_signal(state);	// don't require(?) to ask MCU
15518c2ecf20Sopenharmony_ci		if (state->decode_lock)
15528c2ecf20Sopenharmony_ci			*status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI;
15538c2ecf20Sopenharmony_ci	}
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	return 0;
15568c2ecf20Sopenharmony_ci}
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_cistatic int dst_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
15598c2ecf20Sopenharmony_ci{
15608c2ecf20Sopenharmony_ci	struct dst_state *state = fe->demodulator_priv;
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	int retval = dst_get_signal(state);
15638c2ecf20Sopenharmony_ci	*strength = state->decode_strength;
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci	return retval;
15668c2ecf20Sopenharmony_ci}
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_cistatic int dst_read_snr(struct dvb_frontend *fe, u16 *snr)
15698c2ecf20Sopenharmony_ci{
15708c2ecf20Sopenharmony_ci	struct dst_state *state = fe->demodulator_priv;
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	int retval = dst_get_signal(state);
15738c2ecf20Sopenharmony_ci	*snr = state->decode_snr;
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	return retval;
15768c2ecf20Sopenharmony_ci}
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_cistatic int dst_set_frontend(struct dvb_frontend *fe)
15798c2ecf20Sopenharmony_ci{
15808c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
15818c2ecf20Sopenharmony_ci	int retval = -EINVAL;
15828c2ecf20Sopenharmony_ci	struct dst_state *state = fe->demodulator_priv;
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	if (p != NULL) {
15858c2ecf20Sopenharmony_ci		retval = dst_set_freq(state, p->frequency);
15868c2ecf20Sopenharmony_ci		if(retval != 0)
15878c2ecf20Sopenharmony_ci			return retval;
15888c2ecf20Sopenharmony_ci		dprintk(3, "Set Frequency=[%d]\n", p->frequency);
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci		if (state->dst_type == DST_TYPE_IS_SAT) {
15918c2ecf20Sopenharmony_ci			if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
15928c2ecf20Sopenharmony_ci				dst_set_inversion(state, p->inversion);
15938c2ecf20Sopenharmony_ci			dst_set_fec(state, p->fec_inner);
15948c2ecf20Sopenharmony_ci			dst_set_symbolrate(state, p->symbol_rate);
15958c2ecf20Sopenharmony_ci			dst_set_polarization(state);
15968c2ecf20Sopenharmony_ci			dprintk(3, "Set Symbolrate=[%d]\n", p->symbol_rate);
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci		} else if (state->dst_type == DST_TYPE_IS_TERR)
15998c2ecf20Sopenharmony_ci			dst_set_bandwidth(state, p->bandwidth_hz);
16008c2ecf20Sopenharmony_ci		else if (state->dst_type == DST_TYPE_IS_CABLE) {
16018c2ecf20Sopenharmony_ci			dst_set_fec(state, p->fec_inner);
16028c2ecf20Sopenharmony_ci			dst_set_symbolrate(state, p->symbol_rate);
16038c2ecf20Sopenharmony_ci			dst_set_modulation(state, p->modulation);
16048c2ecf20Sopenharmony_ci		}
16058c2ecf20Sopenharmony_ci		retval = dst_write_tuna(fe);
16068c2ecf20Sopenharmony_ci	}
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	return retval;
16098c2ecf20Sopenharmony_ci}
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_cistatic int dst_tune_frontend(struct dvb_frontend* fe,
16128c2ecf20Sopenharmony_ci			    bool re_tune,
16138c2ecf20Sopenharmony_ci			    unsigned int mode_flags,
16148c2ecf20Sopenharmony_ci			    unsigned int *delay,
16158c2ecf20Sopenharmony_ci			    enum fe_status *status)
16168c2ecf20Sopenharmony_ci{
16178c2ecf20Sopenharmony_ci	struct dst_state *state = fe->demodulator_priv;
16188c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	if (re_tune) {
16218c2ecf20Sopenharmony_ci		dst_set_freq(state, p->frequency);
16228c2ecf20Sopenharmony_ci		dprintk(3, "Set Frequency=[%d]\n", p->frequency);
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci		if (state->dst_type == DST_TYPE_IS_SAT) {
16258c2ecf20Sopenharmony_ci			if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
16268c2ecf20Sopenharmony_ci				dst_set_inversion(state, p->inversion);
16278c2ecf20Sopenharmony_ci			dst_set_fec(state, p->fec_inner);
16288c2ecf20Sopenharmony_ci			dst_set_symbolrate(state, p->symbol_rate);
16298c2ecf20Sopenharmony_ci			dst_set_polarization(state);
16308c2ecf20Sopenharmony_ci			dprintk(3, "Set Symbolrate=[%d]\n", p->symbol_rate);
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci		} else if (state->dst_type == DST_TYPE_IS_TERR)
16338c2ecf20Sopenharmony_ci			dst_set_bandwidth(state, p->bandwidth_hz);
16348c2ecf20Sopenharmony_ci		else if (state->dst_type == DST_TYPE_IS_CABLE) {
16358c2ecf20Sopenharmony_ci			dst_set_fec(state, p->fec_inner);
16368c2ecf20Sopenharmony_ci			dst_set_symbolrate(state, p->symbol_rate);
16378c2ecf20Sopenharmony_ci			dst_set_modulation(state, p->modulation);
16388c2ecf20Sopenharmony_ci		}
16398c2ecf20Sopenharmony_ci		dst_write_tuna(fe);
16408c2ecf20Sopenharmony_ci	}
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci	if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
16438c2ecf20Sopenharmony_ci		dst_read_status(fe, status);
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci	*delay = HZ/10;
16468c2ecf20Sopenharmony_ci	return 0;
16478c2ecf20Sopenharmony_ci}
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_cistatic enum dvbfe_algo dst_get_tuning_algo(struct dvb_frontend *fe)
16508c2ecf20Sopenharmony_ci{
16518c2ecf20Sopenharmony_ci	return dst_algo ? DVBFE_ALGO_HW : DVBFE_ALGO_SW;
16528c2ecf20Sopenharmony_ci}
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_cistatic int dst_get_frontend(struct dvb_frontend *fe,
16558c2ecf20Sopenharmony_ci			    struct dtv_frontend_properties *p)
16568c2ecf20Sopenharmony_ci{
16578c2ecf20Sopenharmony_ci	struct dst_state *state = fe->demodulator_priv;
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	p->frequency = state->decode_freq;
16608c2ecf20Sopenharmony_ci	if (state->dst_type == DST_TYPE_IS_SAT) {
16618c2ecf20Sopenharmony_ci		if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
16628c2ecf20Sopenharmony_ci			p->inversion = state->inversion;
16638c2ecf20Sopenharmony_ci		p->symbol_rate = state->symbol_rate;
16648c2ecf20Sopenharmony_ci		p->fec_inner = dst_get_fec(state);
16658c2ecf20Sopenharmony_ci	} else if (state->dst_type == DST_TYPE_IS_TERR) {
16668c2ecf20Sopenharmony_ci		p->bandwidth_hz = state->bandwidth;
16678c2ecf20Sopenharmony_ci	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
16688c2ecf20Sopenharmony_ci		p->symbol_rate = state->symbol_rate;
16698c2ecf20Sopenharmony_ci		p->fec_inner = dst_get_fec(state);
16708c2ecf20Sopenharmony_ci		p->modulation = dst_get_modulation(state);
16718c2ecf20Sopenharmony_ci	}
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	return 0;
16748c2ecf20Sopenharmony_ci}
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_cistatic void bt8xx_dst_release(struct dvb_frontend *fe)
16778c2ecf20Sopenharmony_ci{
16788c2ecf20Sopenharmony_ci	struct dst_state *state = fe->demodulator_priv;
16798c2ecf20Sopenharmony_ci	if (state->dst_ca) {
16808c2ecf20Sopenharmony_ci		dvb_unregister_device(state->dst_ca);
16818c2ecf20Sopenharmony_ci#ifdef CONFIG_MEDIA_ATTACH
16828c2ecf20Sopenharmony_ci		symbol_put(dst_ca_attach);
16838c2ecf20Sopenharmony_ci#endif
16848c2ecf20Sopenharmony_ci	}
16858c2ecf20Sopenharmony_ci	kfree(state);
16868c2ecf20Sopenharmony_ci}
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dst_dvbt_ops;
16898c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dst_dvbs_ops;
16908c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dst_dvbc_ops;
16918c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dst_atsc_ops;
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_cistruct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter)
16948c2ecf20Sopenharmony_ci{
16958c2ecf20Sopenharmony_ci	/* check if the ASIC is there */
16968c2ecf20Sopenharmony_ci	if (dst_probe(state) < 0) {
16978c2ecf20Sopenharmony_ci		kfree(state);
16988c2ecf20Sopenharmony_ci		return NULL;
16998c2ecf20Sopenharmony_ci	}
17008c2ecf20Sopenharmony_ci	/* determine settings based on type */
17018c2ecf20Sopenharmony_ci	/* create dvb_frontend */
17028c2ecf20Sopenharmony_ci	switch (state->dst_type) {
17038c2ecf20Sopenharmony_ci	case DST_TYPE_IS_TERR:
17048c2ecf20Sopenharmony_ci		memcpy(&state->frontend.ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
17058c2ecf20Sopenharmony_ci		break;
17068c2ecf20Sopenharmony_ci	case DST_TYPE_IS_CABLE:
17078c2ecf20Sopenharmony_ci		memcpy(&state->frontend.ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
17088c2ecf20Sopenharmony_ci		break;
17098c2ecf20Sopenharmony_ci	case DST_TYPE_IS_SAT:
17108c2ecf20Sopenharmony_ci		memcpy(&state->frontend.ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
17118c2ecf20Sopenharmony_ci		break;
17128c2ecf20Sopenharmony_ci	case DST_TYPE_IS_ATSC:
17138c2ecf20Sopenharmony_ci		memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops));
17148c2ecf20Sopenharmony_ci		break;
17158c2ecf20Sopenharmony_ci	default:
17168c2ecf20Sopenharmony_ci		pr_err("unknown DST type. please report to the LinuxTV.org DVB mailinglist.\n");
17178c2ecf20Sopenharmony_ci		kfree(state);
17188c2ecf20Sopenharmony_ci		return NULL;
17198c2ecf20Sopenharmony_ci	}
17208c2ecf20Sopenharmony_ci	state->frontend.demodulator_priv = state;
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	return state;				/*	Manu (DST is a card not a frontend)	*/
17238c2ecf20Sopenharmony_ci}
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dst_attach);
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dst_dvbt_ops = {
17288c2ecf20Sopenharmony_ci	.delsys = { SYS_DVBT },
17298c2ecf20Sopenharmony_ci	.info = {
17308c2ecf20Sopenharmony_ci		.name = "DST DVB-T",
17318c2ecf20Sopenharmony_ci		.frequency_min_hz = 137 * MHz,
17328c2ecf20Sopenharmony_ci		.frequency_max_hz = 858 * MHz,
17338c2ecf20Sopenharmony_ci		.frequency_stepsize_hz = 166667,
17348c2ecf20Sopenharmony_ci		.caps = FE_CAN_FEC_AUTO			|
17358c2ecf20Sopenharmony_ci			FE_CAN_QAM_AUTO			|
17368c2ecf20Sopenharmony_ci			FE_CAN_QAM_16			|
17378c2ecf20Sopenharmony_ci			FE_CAN_QAM_32			|
17388c2ecf20Sopenharmony_ci			FE_CAN_QAM_64			|
17398c2ecf20Sopenharmony_ci			FE_CAN_QAM_128			|
17408c2ecf20Sopenharmony_ci			FE_CAN_QAM_256			|
17418c2ecf20Sopenharmony_ci			FE_CAN_TRANSMISSION_MODE_AUTO	|
17428c2ecf20Sopenharmony_ci			FE_CAN_GUARD_INTERVAL_AUTO
17438c2ecf20Sopenharmony_ci	},
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	.release = bt8xx_dst_release,
17468c2ecf20Sopenharmony_ci	.init = bt8xx_dst_init,
17478c2ecf20Sopenharmony_ci	.tune = dst_tune_frontend,
17488c2ecf20Sopenharmony_ci	.set_frontend = dst_set_frontend,
17498c2ecf20Sopenharmony_ci	.get_frontend = dst_get_frontend,
17508c2ecf20Sopenharmony_ci	.get_frontend_algo = dst_get_tuning_algo,
17518c2ecf20Sopenharmony_ci	.read_status = dst_read_status,
17528c2ecf20Sopenharmony_ci	.read_signal_strength = dst_read_signal_strength,
17538c2ecf20Sopenharmony_ci	.read_snr = dst_read_snr,
17548c2ecf20Sopenharmony_ci};
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dst_dvbs_ops = {
17578c2ecf20Sopenharmony_ci	.delsys = { SYS_DVBS },
17588c2ecf20Sopenharmony_ci	.info = {
17598c2ecf20Sopenharmony_ci		.name = "DST DVB-S",
17608c2ecf20Sopenharmony_ci		.frequency_min_hz   =  950 * MHz,
17618c2ecf20Sopenharmony_ci		.frequency_max_hz   = 2150 * MHz,
17628c2ecf20Sopenharmony_ci		.frequency_stepsize_hz = 1 * MHz,
17638c2ecf20Sopenharmony_ci		.frequency_tolerance_hz = 29500 * kHz,
17648c2ecf20Sopenharmony_ci		.symbol_rate_min = 1000000,
17658c2ecf20Sopenharmony_ci		.symbol_rate_max = 45000000,
17668c2ecf20Sopenharmony_ci	/*     . symbol_rate_tolerance	=	???,*/
17678c2ecf20Sopenharmony_ci		.caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK
17688c2ecf20Sopenharmony_ci	},
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci	.release = bt8xx_dst_release,
17718c2ecf20Sopenharmony_ci	.init = bt8xx_dst_init,
17728c2ecf20Sopenharmony_ci	.tune = dst_tune_frontend,
17738c2ecf20Sopenharmony_ci	.set_frontend = dst_set_frontend,
17748c2ecf20Sopenharmony_ci	.get_frontend = dst_get_frontend,
17758c2ecf20Sopenharmony_ci	.get_frontend_algo = dst_get_tuning_algo,
17768c2ecf20Sopenharmony_ci	.read_status = dst_read_status,
17778c2ecf20Sopenharmony_ci	.read_signal_strength = dst_read_signal_strength,
17788c2ecf20Sopenharmony_ci	.read_snr = dst_read_snr,
17798c2ecf20Sopenharmony_ci	.diseqc_send_burst = dst_send_burst,
17808c2ecf20Sopenharmony_ci	.diseqc_send_master_cmd = dst_set_diseqc,
17818c2ecf20Sopenharmony_ci	.set_voltage = dst_set_voltage,
17828c2ecf20Sopenharmony_ci	.set_tone = dst_set_tone,
17838c2ecf20Sopenharmony_ci};
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dst_dvbc_ops = {
17868c2ecf20Sopenharmony_ci	.delsys = { SYS_DVBC_ANNEX_A },
17878c2ecf20Sopenharmony_ci	.info = {
17888c2ecf20Sopenharmony_ci		.name = "DST DVB-C",
17898c2ecf20Sopenharmony_ci		.frequency_min_hz =  51 * MHz,
17908c2ecf20Sopenharmony_ci		.frequency_max_hz = 858 * MHz,
17918c2ecf20Sopenharmony_ci		.frequency_stepsize_hz = 62500,
17928c2ecf20Sopenharmony_ci		.symbol_rate_min = 1000000,
17938c2ecf20Sopenharmony_ci		.symbol_rate_max = 45000000,
17948c2ecf20Sopenharmony_ci		.caps = FE_CAN_FEC_AUTO |
17958c2ecf20Sopenharmony_ci			FE_CAN_QAM_AUTO |
17968c2ecf20Sopenharmony_ci			FE_CAN_QAM_16	|
17978c2ecf20Sopenharmony_ci			FE_CAN_QAM_32	|
17988c2ecf20Sopenharmony_ci			FE_CAN_QAM_64	|
17998c2ecf20Sopenharmony_ci			FE_CAN_QAM_128	|
18008c2ecf20Sopenharmony_ci			FE_CAN_QAM_256
18018c2ecf20Sopenharmony_ci	},
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	.release = bt8xx_dst_release,
18048c2ecf20Sopenharmony_ci	.init = bt8xx_dst_init,
18058c2ecf20Sopenharmony_ci	.tune = dst_tune_frontend,
18068c2ecf20Sopenharmony_ci	.set_frontend = dst_set_frontend,
18078c2ecf20Sopenharmony_ci	.get_frontend = dst_get_frontend,
18088c2ecf20Sopenharmony_ci	.get_frontend_algo = dst_get_tuning_algo,
18098c2ecf20Sopenharmony_ci	.read_status = dst_read_status,
18108c2ecf20Sopenharmony_ci	.read_signal_strength = dst_read_signal_strength,
18118c2ecf20Sopenharmony_ci	.read_snr = dst_read_snr,
18128c2ecf20Sopenharmony_ci};
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dst_atsc_ops = {
18158c2ecf20Sopenharmony_ci	.delsys = { SYS_ATSC },
18168c2ecf20Sopenharmony_ci	.info = {
18178c2ecf20Sopenharmony_ci		.name = "DST ATSC",
18188c2ecf20Sopenharmony_ci		.frequency_min_hz = 510 * MHz,
18198c2ecf20Sopenharmony_ci		.frequency_max_hz = 858 * MHz,
18208c2ecf20Sopenharmony_ci		.frequency_stepsize_hz = 62500,
18218c2ecf20Sopenharmony_ci		.symbol_rate_min = 1000000,
18228c2ecf20Sopenharmony_ci		.symbol_rate_max = 45000000,
18238c2ecf20Sopenharmony_ci		.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
18248c2ecf20Sopenharmony_ci	},
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ci	.release = bt8xx_dst_release,
18278c2ecf20Sopenharmony_ci	.init = bt8xx_dst_init,
18288c2ecf20Sopenharmony_ci	.tune = dst_tune_frontend,
18298c2ecf20Sopenharmony_ci	.set_frontend = dst_set_frontend,
18308c2ecf20Sopenharmony_ci	.get_frontend = dst_get_frontend,
18318c2ecf20Sopenharmony_ci	.get_frontend_algo = dst_get_tuning_algo,
18328c2ecf20Sopenharmony_ci	.read_status = dst_read_status,
18338c2ecf20Sopenharmony_ci	.read_signal_strength = dst_read_signal_strength,
18348c2ecf20Sopenharmony_ci	.read_snr = dst_read_snr,
18358c2ecf20Sopenharmony_ci};
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DST DVB-S/T/C/ATSC Combo Frontend driver");
18388c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jamie Honan, Manu Abraham");
18398c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1840