[go: nahoru, domu]

18d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri/*
28d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *  Driver for Xceive XC4000 "QAM/8VSB single chip tuner"
38d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *
48d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *  Copyright (c) 2007 Xceive Corporation
58d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
68d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *  Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
78d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *  Copyright (c) 2009 Davide Ferri <d.ferri@zero11.it>
8341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu *  Copyright (c) 2010 Istvan Varga <istvan_v@mailbox.hu>
98d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *
108d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *  This program is free software; you can redistribute it and/or modify
118d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *  it under the terms of the GNU General Public License as published by
128d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *  the Free Software Foundation; either version 2 of the License, or
138d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *  (at your option) any later version.
148d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *
158d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *  This program is distributed in the hope that it will be useful,
168d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *  but WITHOUT ANY WARRANTY; without even the implied warranty of
178d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
188d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *  GNU General Public License for more details.
198d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *
208d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *  You should have received a copy of the GNU General Public License
218d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *  along with this program; if not, write to the Free Software
228d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
238d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri */
248d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
258d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#include <linux/module.h>
268d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#include <linux/moduleparam.h>
278d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#include <linux/videodev2.h>
288d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#include <linux/delay.h>
298d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#include <linux/dvb/frontend.h>
308d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#include <linux/i2c.h>
315614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga#include <linux/mutex.h>
3211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller#include <asm/unaligned.h>
338d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
348d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#include "dvb_frontend.h"
358d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
368d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#include "xc4000.h"
378d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#include "tuner-i2c.h"
3811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller#include "tuner-xc2028-types.h"
398d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
404922cec59a1b37d49b3e01577ab2f779a13b3ae6Devin Heitmuellerstatic int debug;
418d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferrimodule_param(debug, int, 0644);
42341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.huMODULE_PARM_DESC(debug, "Debugging level (0 to 2, default: 0 (off)).");
438d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
448d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int no_poweroff;
458d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferrimodule_param(no_poweroff, int, 0644);
46341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.huMODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, "
47341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	"0 (default): use device-specific default mode).");
48923137a4037d1b9f19d175708eeced209dff9320Istvan Varga
49923137a4037d1b9f19d175708eeced209dff9320Istvan Vargastatic int audio_std;
50923137a4037d1b9f19d175708eeced209dff9320Istvan Vargamodule_param(audio_std, int, 0644);
51341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.huMODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly "
52341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	"needs to know what audio standard is needed for some video standards "
53341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	"with audio A2 or NICAM. The valid settings are a sum of:\n"
54341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	" 1: use NICAM/B or A2/B instead of NICAM/A or A2/A\n"
55341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	" 2: use A2 instead of NICAM or BTSC\n"
56341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	" 4: use SECAM/K3 instead of K1\n"
57341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	" 8: use PAL-D/K audio for SECAM-D/K\n"
58341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	"16: use FM radio input 1 instead of input 2\n"
59341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	"32: use mono audio (the lower three bits are ignored)");
60fa285bc1bf5a2ebe3252523454def096d86a064bIstvan Varga
61fa285bc1bf5a2ebe3252523454def096d86a064bIstvan Vargastatic char firmware_name[30];
62fa285bc1bf5a2ebe3252523454def096d86a064bIstvan Vargamodule_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
63341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.huMODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
64341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	"default firmware name.");
65fa285bc1bf5a2ebe3252523454def096d86a064bIstvan Varga
668d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic DEFINE_MUTEX(xc4000_list_mutex);
678d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic LIST_HEAD(hybrid_tuner_instance_list);
688d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
698d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define dprintk(level, fmt, arg...) if (debug >= level) \
708d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	printk(KERN_INFO "%s: " fmt, "xc4000", ## arg)
718d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
7211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller/* struct for storing firmware table */
7311091a31fbf7496294795ca72d69db0233857d94Devin Heitmuellerstruct firmware_description {
7411091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	unsigned int  type;
7511091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	v4l2_std_id   id;
7611091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	__u16         int_freq;
7711091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	unsigned char *ptr;
7811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	unsigned int  size;
7911091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller};
8011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
8111091a31fbf7496294795ca72d69db0233857d94Devin Heitmuellerstruct firmware_properties {
8211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	unsigned int	type;
8311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	v4l2_std_id	id;
8411091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	v4l2_std_id	std_req;
8511091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	__u16		int_freq;
8611091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	unsigned int	scode_table;
87e3bb7c607f5ca87030692ad4dab653b4a8d1571aMauro Carvalho Chehab	int		scode_nr;
8811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller};
898d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
908d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristruct xc4000_priv {
918d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	struct tuner_i2c_props i2c_props;
928d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	struct list_head hybrid_tuner_instance_list;
9311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	struct firmware_description *firm;
94fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	int	firm_size;
95fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	u32	if_khz;
964c07e32884ab69574cfd9eb4de3334233c938071Mauro Carvalho Chehab	u32	freq_hz, freq_offset;
97fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	u32	bandwidth;
98fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	u8	video_standard;
99fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	u8	rf_mode;
1008edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu	u8	default_pm;
1018edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu	u8	dvb_amplitude;
1028edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu	u8	set_smoothedcvbs;
103fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	u8	ignore_i2c_write_errors;
1048edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu	__u16	firm_version;
105d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	struct firmware_properties cur_fw;
106fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	__u16	hwmodel;
107fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	__u16	hwvers;
1085614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga	struct mutex	lock;
1098d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri};
1108d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
111341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu#define XC4000_AUDIO_STD_B		 1
112341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu#define XC4000_AUDIO_STD_A2		 2
113341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu#define XC4000_AUDIO_STD_K3		 4
114341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu#define XC4000_AUDIO_STD_L		 8
115341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu#define XC4000_AUDIO_STD_INPUT1		16
116341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu#define XC4000_AUDIO_STD_MONO		32
117341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu
118341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu#define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.fw"
119da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab#define XC4000_DEFAULT_FIRMWARE_NEW "dvb-fe-xc4000-1.4.1.fw"
120341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu
1218d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri/* Misc Defines */
1224911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga#define MAX_TV_STANDARD			24
1238d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XC_MAX_I2C_WRITE_LENGTH		64
1245272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga#define XC_POWERED_DOWN			0x80000000U
1258d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1268d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri/* Signal Types */
1278d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XC_RF_MODE_AIR			0
1288d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XC_RF_MODE_CABLE		1
1298d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1308d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri/* Product id */
1318d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XC_PRODUCT_ID_FW_NOT_LOADED	0x2000
1327db98fe66be035494912b6b2c4e9c1e3abfedfe5Istvan Varga#define XC_PRODUCT_ID_XC4000		0x0FA0
1337db98fe66be035494912b6b2c4e9c1e3abfedfe5Istvan Varga#define XC_PRODUCT_ID_XC4100		0x1004
1348d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
135ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller/* Registers (Write-only) */
1368d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XREG_INIT         0x00
1378d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XREG_VIDEO_MODE   0x01
1388d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XREG_AUDIO_MODE   0x02
1398d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XREG_RF_FREQ      0x03
1408d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XREG_D_CODE       0x04
141ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller#define XREG_DIRECTSITTING_MODE 0x05
142ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller#define XREG_SEEK_MODE    0x06
143ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller#define XREG_POWER_DOWN   0x08
144ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller#define XREG_SIGNALSOURCE 0x0A
14530f544ec56eefc628e73e23324dc18105ad13012Istvan Varga#define XREG_SMOOTHEDCVBS 0x0E
146ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller#define XREG_AMPLITUDE    0x10
1478d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
148ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller/* Registers (Read-only) */
1498d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XREG_ADC_ENV      0x00
1508d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XREG_QUALITY      0x01
1518d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XREG_FRAME_LINES  0x02
1528d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XREG_HSYNC_FREQ   0x03
1538d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XREG_LOCK         0x04
1548d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XREG_FREQ_ERROR   0x05
1558d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XREG_SNR          0x06
1568d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XREG_VERSION      0x07
1578d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri#define XREG_PRODUCT_ID   0x08
1588a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen#define XREG_SIGNAL_LEVEL 0x0A
1598a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen#define XREG_NOISE_LEVEL  0x0B
1608d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1618d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri/*
1628d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   Basic firmware description. This will remain with
1638d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   the driver for documentation purposes.
1648d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1658d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   This represents an I2C firmware file encoded as a
1668d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   string of unsigned char. Format is as follows:
1678d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1688d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   char[0  ]=len0_MSB  -> len = len_MSB * 256 + len_LSB
1698d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   char[1  ]=len0_LSB  -> length of first write transaction
1708d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   char[2  ]=data0 -> first byte to be sent
1718d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   char[3  ]=data1
1728d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   char[4  ]=data2
1738d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   char[   ]=...
1748d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   char[M  ]=dataN  -> last byte to be sent
1758d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   char[M+1]=len1_MSB  -> len = len_MSB * 256 + len_LSB
1768d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   char[M+2]=len1_LSB  -> length of second write transaction
1778d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   char[M+3]=data0
1788d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   char[M+4]=data1
1798d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   ...
1808d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   etc.
1818d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1828d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   The [len] value should be interpreted as follows:
1838d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1848d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   len= len_MSB _ len_LSB
1858d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   len=1111_1111_1111_1111   : End of I2C_SEQUENCE
1868d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   len=0000_0000_0000_0000   : Reset command: Do hardware reset
1878d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   len=0NNN_NNNN_NNNN_NNNN   : Normal transaction: number of bytes = {1:32767)
1888d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   len=1WWW_WWWW_WWWW_WWWW   : Wait command: wait for {1:32767} ms
1898d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1908d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   For the RESET and WAIT commands, the two following bytes will contain
1918d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri   immediately the length of the following transaction.
1928d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri*/
193fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga
1948d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristruct XC_TV_STANDARD {
195fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	const char  *Name;
196341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	u16	    audio_mode;
197341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	u16	    video_mode;
1984911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	u16	    int_freq;
1998d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri};
2008d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
2018d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri/* Tuner standards */
202ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller#define XC4000_MN_NTSC_PAL_BTSC		0
203ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller#define XC4000_MN_NTSC_PAL_A2		1
204ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller#define XC4000_MN_NTSC_PAL_EIAJ		2
205ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller#define XC4000_MN_NTSC_PAL_Mono		3
206ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller#define XC4000_BG_PAL_A2		4
207ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller#define XC4000_BG_PAL_NICAM		5
208ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller#define XC4000_BG_PAL_MONO		6
209ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller#define XC4000_I_PAL_NICAM		7
210ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller#define XC4000_I_PAL_NICAM_MONO		8
211ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller#define XC4000_DK_PAL_A2		9
212ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller#define XC4000_DK_PAL_NICAM		10
213ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller#define XC4000_DK_PAL_MONO		11
214ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller#define XC4000_DK_SECAM_A2DK1		12
215e3bb7c607f5ca87030692ad4dab653b4a8d1571aMauro Carvalho Chehab#define XC4000_DK_SECAM_A2LDK3		13
216e3bb7c607f5ca87030692ad4dab653b4a8d1571aMauro Carvalho Chehab#define XC4000_DK_SECAM_A2MONO		14
2174911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga#define XC4000_DK_SECAM_NICAM		15
2184911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga#define XC4000_L_SECAM_NICAM		16
2194911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga#define XC4000_LC_SECAM_NICAM		17
2204911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga#define XC4000_DTV6			18
2214911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga#define XC4000_DTV8			19
2224911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga#define XC4000_DTV7_8			20
2234911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga#define XC4000_DTV7			21
2244911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga#define XC4000_FM_Radio_INPUT2		22
2254911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga#define XC4000_FM_Radio_INPUT1		23
2268d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
227341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hustatic struct XC_TV_STANDARD xc4000_standard[MAX_TV_STANDARD] = {
2284911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"M/N-NTSC/PAL-BTSC",	0x0000, 0x80A0, 4500},
2294911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"M/N-NTSC/PAL-A2",	0x0000, 0x80A0, 4600},
2304911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"M/N-NTSC/PAL-EIAJ",	0x0040, 0x80A0, 4500},
2314911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"M/N-NTSC/PAL-Mono",	0x0078, 0x80A0, 4500},
2324911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"B/G-PAL-A2",		0x0000, 0x8159, 5640},
2334911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"B/G-PAL-NICAM",	0x0004, 0x8159, 5740},
2344911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"B/G-PAL-MONO",	0x0078, 0x8159, 5500},
2354911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"I-PAL-NICAM",		0x0080, 0x8049, 6240},
2364911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"I-PAL-NICAM-MONO",	0x0078, 0x8049, 6000},
2374911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"D/K-PAL-A2",		0x0000, 0x8049, 6380},
2384911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"D/K-PAL-NICAM",	0x0080, 0x8049, 6200},
2394911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"D/K-PAL-MONO",	0x0078, 0x8049, 6500},
2404911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"D/K-SECAM-A2 DK1",	0x0000, 0x8049, 6340},
2414911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"D/K-SECAM-A2 L/DK3",	0x0000, 0x8049, 6000},
2424911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"D/K-SECAM-A2 MONO",	0x0078, 0x8049, 6500},
2434911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"D/K-SECAM-NICAM",	0x0080, 0x8049, 6200},
2444911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"L-SECAM-NICAM",	0x8080, 0x0009, 6200},
2454911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"L'-SECAM-NICAM",	0x8080, 0x4009, 6200},
2464911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"DTV6",		0x00C0, 0x8002,    0},
2474911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"DTV8",		0x00C0, 0x800B,    0},
2484911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"DTV7/8",		0x00C0, 0x801B,    0},
2494911085fa3342d2ccb04f84c2987305b86785ebfIstvan Varga	{"DTV7",		0x00C0, 0x8007,    0},
250941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab	{"FM Radio-INPUT2",	0x0008, 0x9800, 10700},
251941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab	{"FM Radio-INPUT1",	0x0008, 0x9000, 10700}
2528d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri};
2538d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
2548d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val);
255341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hustatic int xc4000_tuner_reset(struct dvb_frontend *fe);
256f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Vargastatic void xc_debug_dump(struct xc4000_priv *priv);
2578d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
2588d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc_send_i2c_data(struct xc4000_priv *priv, u8 *buf, int len)
2598d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
2608d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	struct i2c_msg msg = { .addr = priv->i2c_props.addr,
2618d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			       .flags = 0, .buf = buf, .len = len };
2628d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
263799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller		if (priv->ignore_i2c_write_errors == 0) {
264799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller			printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n",
265799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller			       len);
266799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller			if (len == 4) {
267c6480cccdbaf1e9f3d1489c0530f011543cca90bAndy Shevchenko				printk(KERN_ERR "bytes %*ph\n", 4, buf);
268799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller			}
269341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu			return -EREMOTEIO;
270799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller		}
2718d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
272341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	return 0;
2738d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
2748d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
275341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hustatic int xc4000_tuner_reset(struct dvb_frontend *fe)
2768d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
2778d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	struct xc4000_priv *priv = fe->tuner_priv;
2788d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	int ret;
2798d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
2808d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	dprintk(1, "%s()\n", __func__);
2818d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
2828d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	if (fe->callback) {
2838d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
2848d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri					   fe->dvb->priv :
2858d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri					   priv->i2c_props.adap->algo_data,
2868d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri					   DVB_FRONTEND_COMPONENT_TUNER,
2878d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri					   XC4000_TUNER_RESET, 0);
2888d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		if (ret) {
2898d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			printk(KERN_ERR "xc4000: reset failed\n");
290341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu			return -EREMOTEIO;
2918d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		}
2928d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	} else {
293341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		printk(KERN_ERR "xc4000: no tuner reset callback function, "
294341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu				"fatal\n");
295341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		return -EINVAL;
2968d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
297341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	return 0;
2988d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
2998d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
3008d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc_write_reg(struct xc4000_priv *priv, u16 regAddr, u16 i2cData)
3018d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
3028d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	u8 buf[4];
3038d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	int result;
3048d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
3058d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	buf[0] = (regAddr >> 8) & 0xFF;
3068d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	buf[1] = regAddr & 0xFF;
3078d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	buf[2] = (i2cData >> 8) & 0xFF;
3088d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	buf[3] = i2cData & 0xFF;
3098d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	result = xc_send_i2c_data(priv, buf, 4);
3108d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
3118d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return result;
3128d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
3138d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
3148d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
3158d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
3168d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	struct xc4000_priv *priv = fe->tuner_priv;
3178d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
3188d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	int i, nbytes_to_send, result;
3198d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	unsigned int len, pos, index;
3208d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	u8 buf[XC_MAX_I2C_WRITE_LENGTH];
3218d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
3228d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	index = 0;
3238d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	while ((i2c_sequence[index] != 0xFF) ||
3248d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		(i2c_sequence[index + 1] != 0xFF)) {
3258d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
3268d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		if (len == 0x0000) {
3278d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			/* RESET command */
328341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu			/* NOTE: this is ignored, as the reset callback was */
329341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu			/* already called by check_firmware() */
3308d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			index += 2;
3318d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		} else if (len & 0x8000) {
3328d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			/* WAIT command */
333341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu			msleep(len & 0x7FFF);
3348d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			index += 2;
3358d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		} else {
3368d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			/* Send i2c data whilst ensuring individual transactions
3378d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			 * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
3388d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			 */
3398d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			index += 2;
3408d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			buf[0] = i2c_sequence[index];
3418d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			buf[1] = i2c_sequence[index + 1];
3428d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			pos = 2;
3438d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			while (pos < len) {
3448d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri				if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2)
3458d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri					nbytes_to_send =
3468d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri						XC_MAX_I2C_WRITE_LENGTH;
3478d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri				else
3488d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri					nbytes_to_send = (len - pos + 2);
3498d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri				for (i = 2; i < nbytes_to_send; i++) {
3508d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri					buf[i] = i2c_sequence[index + pos +
3518d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri						i - 2];
3528d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri				}
3538d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri				result = xc_send_i2c_data(priv, buf,
3548d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri					nbytes_to_send);
3558d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
356341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu				if (result != 0)
3578d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri					return result;
3588d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
3598d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri				pos += nbytes_to_send - 2;
3608d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			}
3618d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			index += len;
3628d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		}
3638d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
364341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	return 0;
3658d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
3668d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
367341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hustatic int xc_set_tv_standard(struct xc4000_priv *priv,
368341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	u16 video_mode, u16 audio_mode)
3698d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
3708d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	int ret;
371341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode);
3728d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	dprintk(1, "%s() Standard = %s\n",
3738d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		__func__,
374341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		xc4000_standard[priv->video_standard].Name);
3758d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
376799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller	/* Don't complain when the request fails because of i2c stretching */
377799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller	priv->ignore_i2c_write_errors = 1;
378799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller
379341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode);
380341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	if (ret == 0)
381341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode);
3828d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
383799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller	priv->ignore_i2c_write_errors = 0;
384799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller
3858d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return ret;
3868d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
3878d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
388341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hustatic int xc_set_signal_source(struct xc4000_priv *priv, u16 rf_mode)
3898d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
3908d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
3918d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
3928d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
3938d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) {
3948d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		rf_mode = XC_RF_MODE_CABLE;
3958d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		printk(KERN_ERR
3968d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			"%s(), Invalid mode, defaulting to CABLE",
3978d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			__func__);
3988d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
3998d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
4008d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
4018d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4028d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic const struct dvb_tuner_ops xc4000_tuner_ops;
4038d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
404341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hustatic int xc_set_rf_frequency(struct xc4000_priv *priv, u32 freq_hz)
4058d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
4068d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	u16 freq_code;
4078d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4088d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	dprintk(1, "%s(%u)\n", __func__, freq_hz);
4098d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4108d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	if ((freq_hz > xc4000_tuner_ops.info.frequency_max) ||
411341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	    (freq_hz < xc4000_tuner_ops.info.frequency_min))
412341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		return -EINVAL;
4138d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4148d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	freq_code = (u16)(freq_hz / 15625);
4158d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4168d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	/* WAS: Starting in firmware version 1.1.44, Xceive recommends using the
4178d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	   FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
4188d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	   only be used for fast scanning for channel lock) */
419341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	/* WAS: XREG_FINERFREQ */
420341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
4218d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
4228d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
423341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hustatic int xc_get_adc_envelope(struct xc4000_priv *priv, u16 *adc_envelope)
4248d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
4258d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return xc4000_readreg(priv, XREG_ADC_ENV, adc_envelope);
4268d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
4278d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4288d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc_get_frequency_error(struct xc4000_priv *priv, u32 *freq_error_hz)
4298d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
4308d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	int result;
4318d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	u16 regData;
4328d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	u32 tmp;
4338d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4348d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	result = xc4000_readreg(priv, XREG_FREQ_ERROR, &regData);
435341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	if (result != 0)
4368d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		return result;
4378d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4381368ceb266990af58a72cdb0e121eb4ff22bde6fIstvan Varga	tmp = (u32)regData & 0xFFFFU;
4391368ceb266990af58a72cdb0e121eb4ff22bde6fIstvan Varga	tmp = (tmp < 0x8000U ? tmp : 0x10000U - tmp);
4401368ceb266990af58a72cdb0e121eb4ff22bde6fIstvan Varga	(*freq_error_hz) = tmp * 15625;
4418d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return result;
4428d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
4438d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4448d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc_get_lock_status(struct xc4000_priv *priv, u16 *lock_status)
4458d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
4468d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return xc4000_readreg(priv, XREG_LOCK, lock_status);
4478d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
4488d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4498d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc_get_version(struct xc4000_priv *priv,
4508d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	u8 *hw_majorversion, u8 *hw_minorversion,
4518d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	u8 *fw_majorversion, u8 *fw_minorversion)
4528d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
4538d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	u16 data;
4548d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	int result;
4558d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4568d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	result = xc4000_readreg(priv, XREG_VERSION, &data);
457341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	if (result != 0)
4588d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		return result;
4598d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4608d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	(*hw_majorversion) = (data >> 12) & 0x0F;
4618d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	(*hw_minorversion) = (data >>  8) & 0x0F;
4628d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	(*fw_majorversion) = (data >>  4) & 0x0F;
4638d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	(*fw_minorversion) = data & 0x0F;
4648d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4658d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return 0;
4668d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
4678d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4688d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc_get_hsync_freq(struct xc4000_priv *priv, u32 *hsync_freq_hz)
4698d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
4708d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	u16 regData;
4718d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	int result;
4728d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4738d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	result = xc4000_readreg(priv, XREG_HSYNC_FREQ, &regData);
474341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	if (result != 0)
4758d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		return result;
4768d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4778d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	(*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
4788d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return result;
4798d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
4808d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4818d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc_get_frame_lines(struct xc4000_priv *priv, u16 *frame_lines)
4828d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
4838d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return xc4000_readreg(priv, XREG_FRAME_LINES, frame_lines);
4848d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
4858d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4868d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc_get_quality(struct xc4000_priv *priv, u16 *quality)
4878d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
4888d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return xc4000_readreg(priv, XREG_QUALITY, quality);
4898d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
4908d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
4918a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugenstatic int xc_get_signal_level(struct xc4000_priv *priv, u16 *signal)
4928a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen{
4938a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	return xc4000_readreg(priv, XREG_SIGNAL_LEVEL, signal);
4948a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen}
4958a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen
4968a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugenstatic int xc_get_noise_level(struct xc4000_priv *priv, u16 *noise)
4978a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen{
4988a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	return xc4000_readreg(priv, XREG_NOISE_LEVEL, noise);
4998a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen}
5008a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen
501341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hustatic u16 xc_wait_for_lock(struct xc4000_priv *priv)
5028d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
503341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	u16	lock_state = 0;
504341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	int	watchdog_count = 40;
505341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu
506341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	while ((lock_state == 0) && (watchdog_count > 0)) {
507341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		xc_get_lock_status(priv, &lock_state);
508341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		if (lock_state != 1) {
509341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu			msleep(5);
510341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu			watchdog_count--;
5118d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		}
5128d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
513341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	return lock_state;
5148d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
5158d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
516e75873c1f80380f190d0270fec566410f59c4829Istvan Vargastatic int xc_tune_channel(struct xc4000_priv *priv, u32 freq_hz)
5178d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
518e75873c1f80380f190d0270fec566410f59c4829Istvan Varga	int	found = 1;
519e75873c1f80380f190d0270fec566410f59c4829Istvan Varga	int	result;
5208d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
5218d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	dprintk(1, "%s(%u)\n", __func__, freq_hz);
5228d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
523799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller	/* Don't complain when the request fails because of i2c stretching */
524799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller	priv->ignore_i2c_write_errors = 1;
525341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	result = xc_set_rf_frequency(priv, freq_hz);
526799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller	priv->ignore_i2c_write_errors = 0;
527799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller
528341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	if (result != 0)
5298d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		return 0;
5308d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
531e75873c1f80380f190d0270fec566410f59c4829Istvan Varga	/* wait for lock only in analog TV mode */
532e75873c1f80380f190d0270fec566410f59c4829Istvan Varga	if ((priv->cur_fw.type & (FM | DTV6 | DTV7 | DTV78 | DTV8)) == 0) {
533341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		if (xc_wait_for_lock(priv) != 1)
534e75873c1f80380f190d0270fec566410f59c4829Istvan Varga			found = 0;
5358d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
5368d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
537f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga	/* Wait for stats to stabilize.
538f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga	 * Frame Lines needs two frame times after initial lock
539f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga	 * before it is valid.
540f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga	 */
541341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	msleep(debug ? 100 : 10);
542f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga
543f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga	if (debug)
544f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga		xc_debug_dump(priv);
545f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga
5468d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return found;
5478d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
5488d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
5498d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val)
5508d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
5518d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	u8 buf[2] = { reg >> 8, reg & 0xff };
5528d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	u8 bval[2] = { 0, 0 };
5538d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	struct i2c_msg msg[2] = {
5548d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		{ .addr = priv->i2c_props.addr,
5558d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			.flags = 0, .buf = &buf[0], .len = 2 },
5568d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		{ .addr = priv->i2c_props.addr,
5578d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
5588d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	};
5598d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
5608d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
561941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_ERR "xc4000: I2C read failed\n");
5628d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		return -EREMOTEIO;
5638d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
5648d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
5658d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	*val = (bval[0] << 8) | bval[1];
566341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	return 0;
5678d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
5688d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
569e3bb7c607f5ca87030692ad4dab653b4a8d1571aMauro Carvalho Chehab#define dump_firm_type(t)	dump_firm_type_and_int_freq(t, 0)
570d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmuellerstatic void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
571d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller{
57297e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & BASE)
573941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "BASE ");
57497e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & INIT1)
575941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "INIT1 ");
57697e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & F8MHZ)
577941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "F8MHZ ");
57897e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & MTS)
579941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "MTS ");
58097e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & D2620)
581941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "D2620 ");
58297e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & D2633)
583941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "D2633 ");
58497e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & DTV6)
585941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "DTV6 ");
58697e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & QAM)
587941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "QAM ");
58897e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & DTV7)
589941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "DTV7 ");
59097e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & DTV78)
591941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "DTV78 ");
59297e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & DTV8)
593941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "DTV8 ");
59497e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & FM)
595941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "FM ");
59697e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & INPUT1)
597941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "INPUT1 ");
59897e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & LCD)
599941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "LCD ");
60097e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & NOGD)
601941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "NOGD ");
60297e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & MONO)
603941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "MONO ");
60497e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & ATSC)
605941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "ATSC ");
60697e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & IF)
607941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "IF ");
60897e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & LG60)
609941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "LG60 ");
61097e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & ATI638)
611941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "ATI638 ");
61297e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & OREN538)
613941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "OREN538 ");
61497e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & OREN36)
615941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "OREN36 ");
61697e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & TOYOTA388)
617941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "TOYOTA388 ");
61897e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & TOYOTA794)
619941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "TOYOTA794 ");
62097e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & DIBCOM52)
621941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "DIBCOM52 ");
62297e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & ZARLINK456)
623941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "ZARLINK456 ");
62497e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & CHINA)
625941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "CHINA ");
62697e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & F6MHZ)
627941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "F6MHZ ");
62897e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & INPUT2)
629941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "INPUT2 ");
63097e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & SCODE)
631941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "SCODE ");
63297e0e1e867952d369f245fce0d6791eacb40b2bbMauro Carvalho Chehab	if (type & HAS_IF)
633941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "HAS_IF_%d ", int_freq);
634d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller}
635d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
63611091a31fbf7496294795ca72d69db0233857d94Devin Heitmuellerstatic int seek_firmware(struct dvb_frontend *fe, unsigned int type,
63711091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller			 v4l2_std_id *id)
63811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller{
63911091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	struct xc4000_priv *priv = fe->tuner_priv;
6403db9570482f368cd2f62c258802da21667ec6198Istvan Varga	int		i, best_i = -1;
6413db9570482f368cd2f62c258802da21667ec6198Istvan Varga	unsigned int	best_nr_diffs = 255U;
64211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
64311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	if (!priv->firm) {
644341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		printk(KERN_ERR "Error! firmware not loaded\n");
64511091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		return -EINVAL;
64611091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	}
64711091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
64811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	if (((type & ~SCODE) == 0) && (*id == 0))
64911091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		*id = V4L2_STD_PAL;
65011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
65111091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	/* Seek for generic video standard match */
65211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	for (i = 0; i < priv->firm_size; i++) {
6533db9570482f368cd2f62c258802da21667ec6198Istvan Varga		v4l2_std_id	id_diff_mask =
6543db9570482f368cd2f62c258802da21667ec6198Istvan Varga			(priv->firm[i].id ^ (*id)) & (*id);
6553db9570482f368cd2f62c258802da21667ec6198Istvan Varga		unsigned int	type_diff_mask =
6563db9570482f368cd2f62c258802da21667ec6198Istvan Varga			(priv->firm[i].type ^ type)
6573db9570482f368cd2f62c258802da21667ec6198Istvan Varga			& (BASE_TYPES | DTV_TYPES | LCD | NOGD | MONO | SCODE);
6583db9570482f368cd2f62c258802da21667ec6198Istvan Varga		unsigned int	nr_diffs;
6593db9570482f368cd2f62c258802da21667ec6198Istvan Varga
6603db9570482f368cd2f62c258802da21667ec6198Istvan Varga		if (type_diff_mask
6613db9570482f368cd2f62c258802da21667ec6198Istvan Varga		    & (BASE | INIT1 | FM | DTV6 | DTV7 | DTV78 | DTV8 | SCODE))
66211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller			continue;
66311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
6643db9570482f368cd2f62c258802da21667ec6198Istvan Varga		nr_diffs = hweight64(id_diff_mask) + hweight32(type_diff_mask);
6653db9570482f368cd2f62c258802da21667ec6198Istvan Varga		if (!nr_diffs)	/* Supports all the requested standards */
6663db9570482f368cd2f62c258802da21667ec6198Istvan Varga			goto found;
66711091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
6683db9570482f368cd2f62c258802da21667ec6198Istvan Varga		if (nr_diffs < best_nr_diffs) {
6693db9570482f368cd2f62c258802da21667ec6198Istvan Varga			best_nr_diffs = nr_diffs;
67011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller			best_i = i;
67111091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		}
67211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	}
67311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
6743db9570482f368cd2f62c258802da21667ec6198Istvan Varga	/* FIXME: Would make sense to seek for type "hint" match ? */
6753db9570482f368cd2f62c258802da21667ec6198Istvan Varga	if (best_i < 0) {
6763db9570482f368cd2f62c258802da21667ec6198Istvan Varga		i = -ENOENT;
6773db9570482f368cd2f62c258802da21667ec6198Istvan Varga		goto ret;
6783db9570482f368cd2f62c258802da21667ec6198Istvan Varga	}
6793db9570482f368cd2f62c258802da21667ec6198Istvan Varga
6803db9570482f368cd2f62c258802da21667ec6198Istvan Varga	if (best_nr_diffs > 0U) {
681941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_WARNING
682941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		       "Selecting best matching firmware (%u bits differ) for "
683341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		       "type=(%x), id %016llx:\n",
684341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		       best_nr_diffs, type, (unsigned long long)*id);
68511091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		i = best_i;
68611091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	}
68711091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
68811091a31fbf7496294795ca72d69db0233857d94Devin Heitmuellerfound:
68911091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	*id = priv->firm[i].id;
69011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
69111091a31fbf7496294795ca72d69db0233857d94Devin Heitmuellerret:
69211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	if (debug) {
693941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_DEBUG "%s firmware for type=",
694341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		       (i < 0) ? "Can't find" : "Found");
695d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		dump_firm_type(type);
696941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_DEBUG "(%x), id %016llx.\n", type, (unsigned long long)*id);
69711091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	}
69811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	return i;
69911091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller}
70011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
70111091a31fbf7496294795ca72d69db0233857d94Devin Heitmuellerstatic int load_firmware(struct dvb_frontend *fe, unsigned int type,
70211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller			 v4l2_std_id *id)
70311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller{
70411091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	struct xc4000_priv *priv = fe->tuner_priv;
70511091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	int                pos, rc;
70631f880e2b99a780a4ee5fb6199e489b62e0a76ecDevin Heitmueller	unsigned char      *p;
70711091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
70811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	pos = seek_firmware(fe, type, id);
70911091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	if (pos < 0)
71011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		return pos;
71111091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
71211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	p = priv->firm[pos].ptr;
71311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
714799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller	/* Don't complain when the request fails because of i2c stretching */
715799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller	priv->ignore_i2c_write_errors = 1;
716799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller
71731f880e2b99a780a4ee5fb6199e489b62e0a76ecDevin Heitmueller	rc = xc_load_i2c_sequence(fe, p);
71811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
719799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller	priv->ignore_i2c_write_errors = 0;
720799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller
72131f880e2b99a780a4ee5fb6199e489b62e0a76ecDevin Heitmueller	return rc;
72211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller}
72311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
7248d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc4000_fwupload(struct dvb_frontend *fe)
7258d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
7268d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	struct xc4000_priv *priv = fe->tuner_priv;
72711091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	const struct firmware *fw   = NULL;
72811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	const unsigned char   *p, *endp;
72911091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	int                   rc = 0;
73011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	int		      n, n_array;
73111091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	char		      name[33];
732fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	const char	      *fname;
73311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
734da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab	if (firmware_name[0] != '\0') {
735fa285bc1bf5a2ebe3252523454def096d86a064bIstvan Varga		fname = firmware_name;
73611091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
737da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab		dprintk(1, "Reading custom firmware %s\n", fname);
738da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab		rc = request_firmware(&fw, fname,
739da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab				      priv->i2c_props.adap->dev.parent);
740da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab	} else {
741da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab		fname = XC4000_DEFAULT_FIRMWARE_NEW;
742da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab		dprintk(1, "Trying to read firmware %s\n", fname);
743da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab		rc = request_firmware(&fw, fname,
744da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab				      priv->i2c_props.adap->dev.parent);
745da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab		if (rc == -ENOENT) {
746da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab			fname = XC4000_DEFAULT_FIRMWARE;
747da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab			dprintk(1, "Trying to read firmware %s\n", fname);
748da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab			rc = request_firmware(&fw, fname,
749da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab					      priv->i2c_props.adap->dev.parent);
750da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab		}
751da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab	}
752da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab
75311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	if (rc < 0) {
75411091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		if (rc == -ENOENT)
755941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab			printk(KERN_ERR "Error: firmware %s not found.\n", fname);
75611091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		else
757941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab			printk(KERN_ERR "Error %d while requesting firmware %s\n",
758341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu			       rc, fname);
7598d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
76011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		return rc;
76111091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	}
762da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab	dprintk(1, "Loading Firmware: %s\n", fname);
763da7bfa2c5df3221c7b63be05d5110e21a11118dcMauro Carvalho Chehab
76411091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	p = fw->data;
76511091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	endp = p + fw->size;
7668d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
76711091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	if (fw->size < sizeof(name) - 1 + 2 + 2) {
768941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_ERR "Error: firmware file %s has invalid size!\n",
769941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		       fname);
77011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		goto corrupt;
7718d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
7728d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
77311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	memcpy(name, p, sizeof(name) - 1);
774341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	name[sizeof(name) - 1] = '\0';
77511091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	p += sizeof(name) - 1;
77611091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
77711091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	priv->firm_version = get_unaligned_le16(p);
77811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	p += 2;
77911091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
78011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	n_array = get_unaligned_le16(p);
78111091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	p += 2;
78211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
783b6cdb5bea31c86645782950d84745bb2f95ec9caDevin Heitmueller	dprintk(1, "Loading %d firmware images from %s, type: %s, ver %d.%d\n",
784b6cdb5bea31c86645782950d84745bb2f95ec9caDevin Heitmueller		n_array, fname, name,
785b6cdb5bea31c86645782950d84745bb2f95ec9caDevin Heitmueller		priv->firm_version >> 8, priv->firm_version & 0xff);
78611091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
7871b7acf0ccd61b814032668d1d21740cfae3304e3Thomas Meyer	priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL);
78811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	if (priv->firm == NULL) {
789941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_ERR "Not enough memory to load firmware file.\n");
79011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		rc = -ENOMEM;
791941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		goto done;
79211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	}
79311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	priv->firm_size = n_array;
79411091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
79511091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	n = -1;
79611091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	while (p < endp) {
79711091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		__u32 type, size;
79811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		v4l2_std_id id;
79911091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		__u16 int_freq = 0;
80011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
80111091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		n++;
80211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		if (n >= n_array) {
803941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab			printk(KERN_ERR "More firmware images in file than "
804fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga			       "were expected!\n");
80511091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller			goto corrupt;
80611091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		}
80711091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
80811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		/* Checks if there's enough bytes to read */
80911091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		if (endp - p < sizeof(type) + sizeof(id) + sizeof(size))
81011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller			goto header;
81111091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
81211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		type = get_unaligned_le32(p);
81311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		p += sizeof(type);
81411091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
81511091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		id = get_unaligned_le64(p);
81611091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		p += sizeof(id);
81711091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
81811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		if (type & HAS_IF) {
81911091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller			int_freq = get_unaligned_le16(p);
82011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller			p += sizeof(int_freq);
82111091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller			if (endp - p < sizeof(size))
82211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller				goto header;
82311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		}
82411091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
82511091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		size = get_unaligned_le32(p);
82611091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		p += sizeof(size);
82711091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
82811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		if (!size || size > endp - p) {
829941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab			printk(KERN_ERR "Firmware type (%x), id %llx is corrupted (size=%d, expected %d)\n",
83011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller			       type, (unsigned long long)id,
83111091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller			       (unsigned)(endp - p), size);
83211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller			goto corrupt;
83311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		}
83411091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
83511091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		priv->firm[n].ptr = kzalloc(size, GFP_KERNEL);
83611091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		if (priv->firm[n].ptr == NULL) {
837941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab			printk(KERN_ERR "Not enough memory to load firmware file.\n");
83811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller			rc = -ENOMEM;
839941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab			goto done;
84011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		}
841d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
84211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		if (debug) {
843941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab			printk(KERN_DEBUG "Reading firmware type ");
844d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller			dump_firm_type_and_int_freq(type, int_freq);
845941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab			printk(KERN_DEBUG "(%x), id %llx, size=%d.\n",
84611091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller			       type, (unsigned long long)id, size);
84711091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		}
84811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
84911091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		memcpy(priv->firm[n].ptr, p, size);
85011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		priv->firm[n].type = type;
85111091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		priv->firm[n].id   = id;
85211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		priv->firm[n].size = size;
85311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		priv->firm[n].int_freq = int_freq;
85411091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
85511091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		p += size;
8568d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
8578d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
85811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	if (n + 1 != priv->firm_size) {
859941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_ERR "Firmware file is incomplete!\n");
86011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller		goto corrupt;
86111091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	}
86211091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
86311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	goto done;
86411091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
86511091a31fbf7496294795ca72d69db0233857d94Devin Heitmuellerheader:
866941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab	printk(KERN_ERR "Firmware header is incomplete!\n");
86711091a31fbf7496294795ca72d69db0233857d94Devin Heitmuellercorrupt:
86811091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	rc = -EINVAL;
869941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab	printk(KERN_ERR "Error: firmware file is corrupted!\n");
87011091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
87111091a31fbf7496294795ca72d69db0233857d94Devin Heitmuellerdone:
8728d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	release_firmware(fw);
87311091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	if (rc == 0)
874b6cdb5bea31c86645782950d84745bb2f95ec9caDevin Heitmueller		dprintk(1, "Firmware files loaded.\n");
87511091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
87611091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller	return rc;
8778d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
8788d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
879d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmuellerstatic int load_scode(struct dvb_frontend *fe, unsigned int type,
880d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller			 v4l2_std_id *id, __u16 int_freq, int scode)
881d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller{
882d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	struct xc4000_priv *priv = fe->tuner_priv;
883ffce6266c8be9076947462c688ad3a3099c83eebIstvan Varga	int		pos, rc;
884ffce6266c8be9076947462c688ad3a3099c83eebIstvan Varga	unsigned char	*p;
885ffce6266c8be9076947462c688ad3a3099c83eebIstvan Varga	u8		scode_buf[13];
886ffce6266c8be9076947462c688ad3a3099c83eebIstvan Varga	u8		indirect_mode[5];
887d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
888fe8303647640e1183640a9b85cd60c4a981c7b4bDevin Heitmueller	dprintk(1, "%s called int_freq=%d\n", __func__, int_freq);
889d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
890d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	if (!int_freq) {
891d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		pos = seek_firmware(fe, type, id);
892d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		if (pos < 0)
893d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller			return pos;
894d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	} else {
895d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		for (pos = 0; pos < priv->firm_size; pos++) {
896d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller			if ((priv->firm[pos].int_freq == int_freq) &&
897d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller			    (priv->firm[pos].type & HAS_IF))
898d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller				break;
899d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		}
900d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		if (pos == priv->firm_size)
901d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller			return -ENOENT;
902d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	}
903d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
904d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	p = priv->firm[pos].ptr;
905d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
906ffce6266c8be9076947462c688ad3a3099c83eebIstvan Varga	if (priv->firm[pos].size != 12 * 16 || scode >= 16)
907ffce6266c8be9076947462c688ad3a3099c83eebIstvan Varga		return -EINVAL;
908ffce6266c8be9076947462c688ad3a3099c83eebIstvan Varga	p += 12 * scode;
909d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
910941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab	if (debug) {
911941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		tuner_info("Loading SCODE for type=");
912941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		dump_firm_type_and_int_freq(priv->firm[pos].type,
913941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab					    priv->firm[pos].int_freq);
914941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type,
915941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		       (unsigned long long)*id);
916941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab	}
917d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
918ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller	scode_buf[0] = 0x00;
919ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller	memcpy(&scode_buf[1], p, 12);
920d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
921d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	/* Enter direct-mode */
922ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller	rc = xc_write_reg(priv, XREG_DIRECTSITTING_MODE, 0);
923ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller	if (rc < 0) {
924941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_ERR "failed to put device into direct mode!\n");
925d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		return -EIO;
926ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller	}
927d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
928ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller	rc = xc_send_i2c_data(priv, scode_buf, 13);
929341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	if (rc != 0) {
930ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller		/* Even if the send failed, make sure we set back to indirect
931ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller		   mode */
932941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_ERR "Failed to set scode %d\n", rc);
933ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller	}
934d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
935d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	/* Switch back to indirect-mode */
936d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	memset(indirect_mode, 0, sizeof(indirect_mode));
937d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	indirect_mode[4] = 0x88;
938ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller	xc_send_i2c_data(priv, indirect_mode, sizeof(indirect_mode));
939ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller	msleep(10);
940d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
941d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	return 0;
942d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller}
943d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
944d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmuellerstatic int check_firmware(struct dvb_frontend *fe, unsigned int type,
945d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller			  v4l2_std_id std, __u16 int_freq)
946d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller{
947d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	struct xc4000_priv         *priv = fe->tuner_priv;
948d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	struct firmware_properties new_fw;
949d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	int			   rc = 0, is_retry = 0;
95009f4634293f2d48a9619f51b104bef8e6cc6d559istvan_v@mailbox.hu	u16			   hwmodel;
951d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	v4l2_std_id		   std0;
9520d0d76e5bcd70439b0e736a99539d7eef4f87bafMauro Carvalho Chehab	u8			   hw_major = 0, hw_minor = 0, fw_major = 0, fw_minor = 0;
953d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
954d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	dprintk(1, "%s called\n", __func__);
955d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
956d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	if (!priv->firm) {
957d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		rc = xc4000_fwupload(fe);
958d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		if (rc < 0)
959d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller			return rc;
960d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	}
961d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
962d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmuellerretry:
963d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	new_fw.type = type;
964d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	new_fw.id = std;
965d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	new_fw.std_req = std;
966341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	new_fw.scode_table = SCODE;
967d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	new_fw.scode_nr = 0;
968d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	new_fw.int_freq = int_freq;
969d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
970d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	dprintk(1, "checking firmware, user requested type=");
971d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	if (debug) {
972d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		dump_firm_type(new_fw.type);
973941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_CONT "(%x), id %016llx, ", new_fw.type,
974d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		       (unsigned long long)new_fw.std_req);
975341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		if (!int_freq)
976341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu			printk(KERN_CONT "scode_tbl ");
977341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		else
978341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu			printk(KERN_CONT "int_freq %d, ", new_fw.int_freq);
979341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr);
980d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	}
981d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
982d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	/* No need to reload base firmware if it matches */
983595a83f49a7536f43a68cab78098d5ad11d1c51fIstvan Varga	if (priv->cur_fw.type & BASE) {
984d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		dprintk(1, "BASE firmware not changed.\n");
985d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		goto skip_base;
986d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	}
987d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
988d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	/* Updating BASE - forget about all currently loaded firmware */
989d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
990d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
991d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	/* Reset is needed before loading firmware */
992341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	rc = xc4000_tuner_reset(fe);
993d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	if (rc < 0)
994d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		goto fail;
995d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
996d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	/* BASE firmwares are all std0 */
997d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	std0 = 0;
998595a83f49a7536f43a68cab78098d5ad11d1c51fIstvan Varga	rc = load_firmware(fe, BASE, &std0);
999d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	if (rc < 0) {
1000941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_ERR "Error %d while loading base firmware\n", rc);
1001d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		goto fail;
1002d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	}
1003d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
1004d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	/* Load INIT1, if needed */
1005d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	dprintk(1, "Load init1 firmware, if exists\n");
1006d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
1007595a83f49a7536f43a68cab78098d5ad11d1c51fIstvan Varga	rc = load_firmware(fe, BASE | INIT1, &std0);
1008d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	if (rc == -ENOENT)
1009595a83f49a7536f43a68cab78098d5ad11d1c51fIstvan Varga		rc = load_firmware(fe, BASE | INIT1, &std0);
1010d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	if (rc < 0 && rc != -ENOENT) {
1011d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		tuner_err("Error %d while loading init1 firmware\n",
1012d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller			  rc);
1013d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		goto fail;
1014d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	}
1015d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
1016d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmuellerskip_base:
1017d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	/*
1018d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	 * No need to reload standard specific firmware if base firmware
1019d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	 * was not reloaded and requested video standards have not changed.
1020d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	 */
1021d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	if (priv->cur_fw.type == (BASE | new_fw.type) &&
1022d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	    priv->cur_fw.std_req == std) {
1023d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		dprintk(1, "Std-specific firmware already loaded.\n");
1024d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		goto skip_std_specific;
1025d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	}
1026d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
1027d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	/* Reloading std-specific firmware forces a SCODE update */
1028d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	priv->cur_fw.scode_table = 0;
1029d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
1030ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller	/* Load the standard firmware */
1031d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	rc = load_firmware(fe, new_fw.type, &new_fw.id);
1032d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
1033d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	if (rc < 0)
1034d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		goto fail;
1035d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
1036d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmuellerskip_std_specific:
1037d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	if (priv->cur_fw.scode_table == new_fw.scode_table &&
1038d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	    priv->cur_fw.scode_nr == new_fw.scode_nr) {
1039d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		dprintk(1, "SCODE firmware already loaded.\n");
1040d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		goto check_device;
1041d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	}
1042d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
1043d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	/* Load SCODE firmware, if exists */
1044d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
1045d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller			new_fw.int_freq, new_fw.scode_nr);
1046341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	if (rc != 0)
1047ee4c3cd67b90cb42143e230485d3aad60768c551Devin Heitmueller		dprintk(1, "load scode failed %d\n", rc);
1048d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
1049d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmuellercheck_device:
1050d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	rc = xc4000_readreg(priv, XREG_PRODUCT_ID, &hwmodel);
1051d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
1052799ed11afe7694858584d1ed4e9ae2f9e48142ecDevin Heitmueller	if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major,
1053341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu			   &fw_minor) != 0) {
1054941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		printk(KERN_ERR "Unable to read tuner registers.\n");
1055d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		goto fail;
1056d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	}
1057d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
1058d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	dprintk(1, "Device is Xceive %d version %d.%d, "
1059d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		"firmware version %d.%d\n",
1060d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		hwmodel, hw_major, hw_minor, fw_major, fw_minor);
1061d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
1062d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	/* Check firmware version against what we downloaded. */
106309f4634293f2d48a9619f51b104bef8e6cc6d559istvan_v@mailbox.hu	if (priv->firm_version != ((fw_major << 8) | fw_minor)) {
106409f4634293f2d48a9619f51b104bef8e6cc6d559istvan_v@mailbox.hu		printk(KERN_WARNING
106509f4634293f2d48a9619f51b104bef8e6cc6d559istvan_v@mailbox.hu		       "Incorrect readback of firmware version %d.%d.\n",
106609f4634293f2d48a9619f51b104bef8e6cc6d559istvan_v@mailbox.hu		       fw_major, fw_minor);
1067d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		goto fail;
1068d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	}
1069d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
1070d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	/* Check that the tuner hardware model remains consistent over time. */
10717db98fe66be035494912b6b2c4e9c1e3abfedfe5Istvan Varga	if (priv->hwmodel == 0 &&
10727db98fe66be035494912b6b2c4e9c1e3abfedfe5Istvan Varga	    (hwmodel == XC_PRODUCT_ID_XC4000 ||
10737db98fe66be035494912b6b2c4e9c1e3abfedfe5Istvan Varga	     hwmodel == XC_PRODUCT_ID_XC4100)) {
1074d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		priv->hwmodel = hwmodel;
107509f4634293f2d48a9619f51b104bef8e6cc6d559istvan_v@mailbox.hu		priv->hwvers = (hw_major << 8) | hw_minor;
1076d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	} else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
107709f4634293f2d48a9619f51b104bef8e6cc6d559istvan_v@mailbox.hu		   priv->hwvers != ((hw_major << 8) | hw_minor)) {
107809f4634293f2d48a9619f51b104bef8e6cc6d559istvan_v@mailbox.hu		printk(KERN_WARNING
107909f4634293f2d48a9619f51b104bef8e6cc6d559istvan_v@mailbox.hu		       "Read invalid device hardware information - tuner "
1080fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga		       "hung?\n");
1081d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		goto fail;
1082d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	}
1083d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
108436628731ec9ef46393d25d2fbdac40cc70c4d27aEzequiel Garcia	priv->cur_fw = new_fw;
1085d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
1086d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	/*
1087d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	 * By setting BASE in cur_fw.type only after successfully loading all
1088d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	 * firmwares, we can:
1089d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	 * 1. Identify that BASE firmware with type=0 has been loaded;
1090d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	 * 2. Tell whether BASE firmware was just changed the next time through.
1091d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	 */
1092d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	priv->cur_fw.type |= BASE;
1093d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
1094d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	return 0;
1095d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
1096d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmuellerfail:
1097d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
1098d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	if (!is_retry) {
1099d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		msleep(50);
1100d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		is_retry = 1;
1101d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		dprintk(1, "Retrying firmware load\n");
1102d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		goto retry;
1103d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	}
1104d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller
1105d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	if (rc == -ENOENT)
1106d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller		rc = -EINVAL;
1107d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller	return rc;
1108d0962382cf6ca55e5a33413b39a10fe2f56bae78Devin Heitmueller}
110911091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
11108d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic void xc_debug_dump(struct xc4000_priv *priv)
11118d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
1112fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	u16	adc_envelope;
1113fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	u32	freq_error_hz = 0;
1114fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	u16	lock_status;
1115fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	u32	hsync_freq_hz = 0;
1116fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	u16	frame_lines;
1117fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	u16	quality;
11188a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	u16	signal = 0;
11198a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	u16	noise = 0;
1120fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	u8	hw_majorversion = 0, hw_minorversion = 0;
1121fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	u8	fw_majorversion = 0, fw_minorversion = 0;
11228d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1123341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	xc_get_adc_envelope(priv, &adc_envelope);
11248d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
11258d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
11268d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	xc_get_frequency_error(priv, &freq_error_hz);
11278d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
11288d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1129fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	xc_get_lock_status(priv, &lock_status);
11308d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
11318d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		lock_status);
11328d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1133fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	xc_get_version(priv, &hw_majorversion, &hw_minorversion,
1134fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga		       &fw_majorversion, &fw_minorversion);
11358d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
11368d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		hw_majorversion, hw_minorversion,
11378d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		fw_majorversion, fw_minorversion);
11388d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1139f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga	if (priv->video_standard < XC4000_DTV6) {
1140f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga		xc_get_hsync_freq(priv, &hsync_freq_hz);
1141f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga		dprintk(1, "*** Horizontal sync frequency = %d Hz\n",
1142f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga			hsync_freq_hz);
11438d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1144f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga		xc_get_frame_lines(priv, &frame_lines);
1145f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga		dprintk(1, "*** Frame lines = %d\n", frame_lines);
1146f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga	}
11478d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1148fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	xc_get_quality(priv, &quality);
11498d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
11508a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen
11518a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	xc_get_signal_level(priv, &signal);
11528a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	dprintk(1, "*** Signal level = -%ddB (%d)\n", signal >> 8, signal);
11538a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen
11548a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	xc_get_noise_level(priv, &noise);
11558a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	dprintk(1, "*** Noise level = %ddB (%d)\n", noise >> 8, noise);
11568d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
11578d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
115814d24d148c7521b2b88b396652e36f55d061e195Mauro Carvalho Chehabstatic int xc4000_set_params(struct dvb_frontend *fe)
11598d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
116040d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
116140d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab	u32 delsys = c->delivery_system;
116240d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab	u32 bw = c->bandwidth_hz;
11638d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	struct xc4000_priv *priv = fe->tuner_priv;
1164ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller	unsigned int type;
11655614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga	int	ret = -EREMOTEIO;
11668d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
116740d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab	dprintk(1, "%s() frequency=%d (Hz)\n", __func__, c->frequency);
11688d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
11695614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga	mutex_lock(&priv->lock);
11705614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga
117140d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab	switch (delsys) {
117240d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab	case SYS_ATSC:
117340d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab		dprintk(1, "%s() VSB modulation\n", __func__);
117440d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab		priv->rf_mode = XC_RF_MODE_AIR;
11754c07e32884ab69574cfd9eb4de3334233c938071Mauro Carvalho Chehab		priv->freq_offset = 1750000;
117640d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab		priv->video_standard = XC4000_DTV6;
117740d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab		type = DTV6;
117840d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab		break;
117940d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab	case SYS_DVBC_ANNEX_B:
118040d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab		dprintk(1, "%s() QAM modulation\n", __func__);
118140d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab		priv->rf_mode = XC_RF_MODE_CABLE;
11824c07e32884ab69574cfd9eb4de3334233c938071Mauro Carvalho Chehab		priv->freq_offset = 1750000;
118340d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab		priv->video_standard = XC4000_DTV6;
118440d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab		type = DTV6;
118540d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab		break;
118640d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab	case SYS_DVBT:
118740d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab	case SYS_DVBT2:
11888d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		dprintk(1, "%s() OFDM\n", __func__);
118940d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab		if (bw == 0) {
119040d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab			if (c->frequency < 400000000) {
11914c07e32884ab69574cfd9eb4de3334233c938071Mauro Carvalho Chehab				priv->freq_offset = 2250000;
119240d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab			} else {
11934c07e32884ab69574cfd9eb4de3334233c938071Mauro Carvalho Chehab				priv->freq_offset = 2750000;
119440d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab			}
119540d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab			priv->video_standard = XC4000_DTV7_8;
119640d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab			type = DTV78;
119740d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab		} else if (bw <= 6000000) {
1198ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller			priv->video_standard = XC4000_DTV6;
11994c07e32884ab69574cfd9eb4de3334233c938071Mauro Carvalho Chehab			priv->freq_offset = 1750000;
1200ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller			type = DTV6;
120140d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab		} else if (bw <= 7000000) {
1202f0ef7c88ca919912011593d2392a59c2fde04748Istvan Varga			priv->video_standard = XC4000_DTV7;
12034c07e32884ab69574cfd9eb4de3334233c938071Mauro Carvalho Chehab			priv->freq_offset = 2250000;
1204ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller			type = DTV7;
120540d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab		} else {
1206ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller			priv->video_standard = XC4000_DTV8;
12074c07e32884ab69574cfd9eb4de3334233c938071Mauro Carvalho Chehab			priv->freq_offset = 2750000;
1208ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller			type = DTV8;
12098d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		}
12108d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		priv->rf_mode = XC_RF_MODE_AIR;
121140d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab		break;
121240d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab	default:
121340d6f2b83788cfc125867c8c7a7a0b32c72d9e54Mauro Carvalho Chehab		printk(KERN_ERR "xc4000 delivery system not supported!\n");
12145614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga		ret = -EINVAL;
12155614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga		goto fail;
12168d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
12178d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
12184c07e32884ab69574cfd9eb4de3334233c938071Mauro Carvalho Chehab	priv->freq_hz = c->frequency - priv->freq_offset;
12194c07e32884ab69574cfd9eb4de3334233c938071Mauro Carvalho Chehab
12208d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	dprintk(1, "%s() frequency=%d (compensated)\n",
12218d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		__func__, priv->freq_hz);
12228d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1223ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller	/* Make sure the correct firmware type is loaded */
1224341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	if (check_firmware(fe, type, 0, priv->if_khz) != 0)
12255614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga		goto fail;
1226ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller
1227c6f56e7d794cba022353d464dfa3383d1b3e0125Mauro Carvalho Chehab	priv->bandwidth = c->bandwidth_hz;
1228c6f56e7d794cba022353d464dfa3383d1b3e0125Mauro Carvalho Chehab
1229341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	ret = xc_set_signal_source(priv, priv->rf_mode);
1230341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	if (ret != 0) {
1231341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n",
12325614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga		       priv->rf_mode);
12335614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga		goto fail;
123430f544ec56eefc628e73e23324dc18105ad13012Istvan Varga	} else {
123530f544ec56eefc628e73e23324dc18105ad13012Istvan Varga		u16	video_mode, audio_mode;
1236341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		video_mode = xc4000_standard[priv->video_standard].video_mode;
1237341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		audio_mode = xc4000_standard[priv->video_standard].audio_mode;
123830f544ec56eefc628e73e23324dc18105ad13012Istvan Varga		if (type == DTV6 && priv->firm_version != 0x0102)
123930f544ec56eefc628e73e23324dc18105ad13012Istvan Varga			video_mode |= 0x0001;
1240341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		ret = xc_set_tv_standard(priv, video_mode, audio_mode);
1241341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		if (ret != 0) {
1242341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu			printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n");
124330f544ec56eefc628e73e23324dc18105ad13012Istvan Varga			/* DJH - do not return when it fails... */
124430f544ec56eefc628e73e23324dc18105ad13012Istvan Varga			/* goto fail; */
124530f544ec56eefc628e73e23324dc18105ad13012Istvan Varga		}
12468d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
12478d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
12488edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu	if (xc_write_reg(priv, XREG_D_CODE, 0) == 0)
12498edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu		ret = 0;
12508edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu	if (priv->dvb_amplitude != 0) {
125130f544ec56eefc628e73e23324dc18105ad13012Istvan Varga		if (xc_write_reg(priv, XREG_AMPLITUDE,
12528edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu				 (priv->firm_version != 0x0102 ||
12538edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu				  priv->dvb_amplitude != 134 ?
12548edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu				  priv->dvb_amplitude : 132)) != 0)
125530f544ec56eefc628e73e23324dc18105ad13012Istvan Varga			ret = -EREMOTEIO;
12568edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu	}
12578edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu	if (priv->set_smoothedcvbs != 0) {
125830f544ec56eefc628e73e23324dc18105ad13012Istvan Varga		if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0)
125930f544ec56eefc628e73e23324dc18105ad13012Istvan Varga			ret = -EREMOTEIO;
12608edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu	}
12618edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu	if (ret != 0) {
12628edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu		printk(KERN_ERR "xc4000: setting registers failed\n");
12638edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu		/* goto fail; */
12648d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
126530f544ec56eefc628e73e23324dc18105ad13012Istvan Varga
1266e75873c1f80380f190d0270fec566410f59c4829Istvan Varga	xc_tune_channel(priv, priv->freq_hz);
12678d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
12685614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga	ret = 0;
12695614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga
12705614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Vargafail:
12715614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga	mutex_unlock(&priv->lock);
12725614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga
12735614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga	return ret;
12748d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
12758d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
12768d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc4000_set_analog_params(struct dvb_frontend *fe,
12778d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	struct analog_parameters *params)
12788d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
12798d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	struct xc4000_priv *priv = fe->tuner_priv;
1280818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga	unsigned int type = 0;
12815614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga	int	ret = -EREMOTEIO;
12828d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1283818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga	if (params->mode == V4L2_TUNER_RADIO) {
1284818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		dprintk(1, "%s() frequency=%d (in units of 62.5Hz)\n",
1285818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			__func__, params->frequency);
1286818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga
1287818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		mutex_lock(&priv->lock);
1288818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga
1289818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		params->std = 0;
1290818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		priv->freq_hz = params->frequency * 125L / 2;
1291818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga
1292818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		if (audio_std & XC4000_AUDIO_STD_INPUT1) {
1293818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			priv->video_standard = XC4000_FM_Radio_INPUT1;
1294818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			type = FM | INPUT1;
1295818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		} else {
1296818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			priv->video_standard = XC4000_FM_Radio_INPUT2;
1297818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			type = FM | INPUT2;
1298818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		}
1299818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga
1300818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		goto tune_channel;
1301818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga	}
1302818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga
13038d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
13048d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		__func__, params->frequency);
13058d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
13065614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga	mutex_lock(&priv->lock);
13075614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga
13088d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	/* params->frequency is in units of 62.5khz */
13098d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	priv->freq_hz = params->frequency * 62500;
13108d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1311818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga	params->std &= V4L2_STD_ALL;
1312818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga	/* if std is not defined, choose one */
1313818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga	if (!params->std)
1314818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		params->std = V4L2_STD_PAL_BG;
1315818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga
1316818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga	if (audio_std & XC4000_AUDIO_STD_MONO)
1317818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		type = MONO;
1318818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga
13198d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	if (params->std & V4L2_STD_MN) {
1320818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		params->std = V4L2_STD_MN;
1321818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		if (audio_std & XC4000_AUDIO_STD_MONO) {
1322818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			priv->video_standard = XC4000_MN_NTSC_PAL_Mono;
1323818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		} else if (audio_std & XC4000_AUDIO_STD_A2) {
1324818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			params->std |= V4L2_STD_A2;
1325818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			priv->video_standard = XC4000_MN_NTSC_PAL_A2;
1326818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		} else {
1327818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			params->std |= V4L2_STD_BTSC;
1328818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			priv->video_standard = XC4000_MN_NTSC_PAL_BTSC;
1329818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		}
13308d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		goto tune_channel;
13318d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
13328d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
13338d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	if (params->std & V4L2_STD_PAL_BG) {
1334818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		params->std = V4L2_STD_PAL_BG;
1335818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		if (audio_std & XC4000_AUDIO_STD_MONO) {
1336818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			priv->video_standard = XC4000_BG_PAL_MONO;
1337818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		} else if (!(audio_std & XC4000_AUDIO_STD_A2)) {
1338818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			if (!(audio_std & XC4000_AUDIO_STD_B)) {
1339818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga				params->std |= V4L2_STD_NICAM_A;
1340818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga				priv->video_standard = XC4000_BG_PAL_NICAM;
1341818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			} else {
1342818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga				params->std |= V4L2_STD_NICAM_B;
1343818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga				priv->video_standard = XC4000_BG_PAL_NICAM;
1344818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			}
1345818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		} else {
1346818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			if (!(audio_std & XC4000_AUDIO_STD_B)) {
1347818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga				params->std |= V4L2_STD_A2_A;
1348818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga				priv->video_standard = XC4000_BG_PAL_A2;
1349818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			} else {
1350818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga				params->std |= V4L2_STD_A2_B;
1351818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga				priv->video_standard = XC4000_BG_PAL_A2;
1352818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			}
1353818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		}
13548d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		goto tune_channel;
13558d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
13568d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
13578d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	if (params->std & V4L2_STD_PAL_I) {
13588d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		/* default to NICAM audio standard */
1359818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		params->std = V4L2_STD_PAL_I | V4L2_STD_NICAM;
1360941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		if (audio_std & XC4000_AUDIO_STD_MONO)
1361818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			priv->video_standard = XC4000_I_PAL_NICAM_MONO;
1362941830c9278a72e31389eb04cdfc397f66866de0Mauro Carvalho Chehab		else
1363818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			priv->video_standard = XC4000_I_PAL_NICAM;
13648d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		goto tune_channel;
13658d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
13668d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
13678d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	if (params->std & V4L2_STD_PAL_DK) {
1368818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		params->std = V4L2_STD_PAL_DK;
1369818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		if (audio_std & XC4000_AUDIO_STD_MONO) {
1370818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			priv->video_standard = XC4000_DK_PAL_MONO;
1371818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		} else if (audio_std & XC4000_AUDIO_STD_A2) {
1372818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			params->std |= V4L2_STD_A2;
1373818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			priv->video_standard = XC4000_DK_PAL_A2;
1374818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		} else {
1375818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			params->std |= V4L2_STD_NICAM;
1376818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			priv->video_standard = XC4000_DK_PAL_NICAM;
1377818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		}
13788d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		goto tune_channel;
13798d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
13808d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
13818d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	if (params->std & V4L2_STD_SECAM_DK) {
1382818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		/* default to A2 audio standard */
1383818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		params->std = V4L2_STD_SECAM_DK | V4L2_STD_A2;
1384818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		if (audio_std & XC4000_AUDIO_STD_L) {
1385818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			type = 0;
1386818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			priv->video_standard = XC4000_DK_SECAM_NICAM;
1387818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		} else if (audio_std & XC4000_AUDIO_STD_MONO) {
1388818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			priv->video_standard = XC4000_DK_SECAM_A2MONO;
1389818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		} else if (audio_std & XC4000_AUDIO_STD_K3) {
1390818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			params->std |= V4L2_STD_SECAM_K3;
1391818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			priv->video_standard = XC4000_DK_SECAM_A2LDK3;
1392818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		} else {
1393818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga			priv->video_standard = XC4000_DK_SECAM_A2DK1;
1394818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		}
13958d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		goto tune_channel;
13968d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
13978d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
13988d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	if (params->std & V4L2_STD_SECAM_L) {
1399818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		/* default to NICAM audio standard */
1400818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		type = 0;
1401818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		params->std = V4L2_STD_SECAM_L | V4L2_STD_NICAM;
1402ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller		priv->video_standard = XC4000_L_SECAM_NICAM;
14038d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		goto tune_channel;
14048d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
14058d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
14068d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	if (params->std & V4L2_STD_SECAM_LC) {
1407818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		/* default to NICAM audio standard */
1408818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		type = 0;
1409818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga		params->std = V4L2_STD_SECAM_LC | V4L2_STD_NICAM;
1410ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller		priv->video_standard = XC4000_LC_SECAM_NICAM;
14118d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		goto tune_channel;
14128d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
14138d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
14148d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferritune_channel:
1415341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	/* FIXME: it could be air. */
1416818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga	priv->rf_mode = XC_RF_MODE_CABLE;
1417ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller
1418818a1776a45c230c4f230c8e4e2d0c7bdf5f8fa3Istvan Varga	if (check_firmware(fe, type, params->std,
1419341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu			   xc4000_standard[priv->video_standard].int_freq) != 0)
14205614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga		goto fail;
1421ed23db32271997e03ea59d31839a40470a1c434bDevin Heitmueller
1422341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	ret = xc_set_signal_source(priv, priv->rf_mode);
1423341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	if (ret != 0) {
14248d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		printk(KERN_ERR
1425341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		       "xc4000: xc_set_signal_source(%d) failed\n",
14265614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga		       priv->rf_mode);
14275614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga		goto fail;
142830f544ec56eefc628e73e23324dc18105ad13012Istvan Varga	} else {
142930f544ec56eefc628e73e23324dc18105ad13012Istvan Varga		u16	video_mode, audio_mode;
1430341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		video_mode = xc4000_standard[priv->video_standard].video_mode;
1431341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		audio_mode = xc4000_standard[priv->video_standard].audio_mode;
143230f544ec56eefc628e73e23324dc18105ad13012Istvan Varga		if (priv->video_standard < XC4000_BG_PAL_A2) {
1433341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu			if (type & NOGD)
143430f544ec56eefc628e73e23324dc18105ad13012Istvan Varga				video_mode &= 0xFF7F;
143530f544ec56eefc628e73e23324dc18105ad13012Istvan Varga		} else if (priv->video_standard < XC4000_I_PAL_NICAM) {
14368edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu			if (priv->firm_version == 0x0102)
143730f544ec56eefc628e73e23324dc18105ad13012Istvan Varga				video_mode &= 0xFEFF;
1438923137a4037d1b9f19d175708eeced209dff9320Istvan Varga			if (audio_std & XC4000_AUDIO_STD_B)
1439923137a4037d1b9f19d175708eeced209dff9320Istvan Varga				video_mode |= 0x0080;
144030f544ec56eefc628e73e23324dc18105ad13012Istvan Varga		}
1441341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		ret = xc_set_tv_standard(priv, video_mode, audio_mode);
1442341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		if (ret != 0) {
1443341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu			printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n");
144430f544ec56eefc628e73e23324dc18105ad13012Istvan Varga			goto fail;
144530f544ec56eefc628e73e23324dc18105ad13012Istvan Varga		}
14468d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
14478d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
14488edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu	if (xc_write_reg(priv, XREG_D_CODE, 0) == 0)
14498edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu		ret = 0;
14508edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu	if (xc_write_reg(priv, XREG_AMPLITUDE, 1) != 0)
14518edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu		ret = -EREMOTEIO;
14528edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu	if (priv->set_smoothedcvbs != 0) {
145330f544ec56eefc628e73e23324dc18105ad13012Istvan Varga		if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0)
145430f544ec56eefc628e73e23324dc18105ad13012Istvan Varga			ret = -EREMOTEIO;
14558edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu	}
14568edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu	if (ret != 0) {
14578edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu		printk(KERN_ERR "xc4000: setting registers failed\n");
14588edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu		goto fail;
14598d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
14608d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1461e75873c1f80380f190d0270fec566410f59c4829Istvan Varga	xc_tune_channel(priv, priv->freq_hz);
14628d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
14635614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga	ret = 0;
14645614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga
14655614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Vargafail:
14665614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga	mutex_unlock(&priv->lock);
14675614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga
14685614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga	return ret;
14698d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
14708d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
14718a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugenstatic int xc4000_get_signal(struct dvb_frontend *fe, u16 *strength)
14728a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen{
14738a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	struct xc4000_priv *priv = fe->tuner_priv;
14748a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	u16 value = 0;
14758a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	int rc;
14768a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen
14778a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	mutex_lock(&priv->lock);
14788a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	rc = xc4000_readreg(priv, XREG_SIGNAL_LEVEL, &value);
14798a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	mutex_unlock(&priv->lock);
14808a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen
14818a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	if (rc < 0)
14828a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen		goto ret;
14838a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen
14848a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	/* Informations from real testing of DVB-T and radio part,
14858a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	   coeficient for one dB is 0xff.
14868a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	 */
14878a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	tuner_dbg("Signal strength: -%ddB (%05d)\n", value >> 8, value);
14888a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen
14898a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	/* all known digital modes */
14908a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	if ((priv->video_standard == XC4000_DTV6) ||
14918a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	    (priv->video_standard == XC4000_DTV7) ||
14928a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	    (priv->video_standard == XC4000_DTV7_8) ||
14938a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	    (priv->video_standard == XC4000_DTV8))
14948a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen		goto digital;
14958a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen
14968a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	/* Analog mode has NOISE LEVEL important, signal
14978a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	   depends only on gain of antenna and amplifiers,
14988a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	   but it doesn't tell anything about real quality
14998a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	   of reception.
15008a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	 */
15018a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	mutex_lock(&priv->lock);
15028a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	rc = xc4000_readreg(priv, XREG_NOISE_LEVEL, &value);
15038a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	mutex_unlock(&priv->lock);
15048a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen
15058a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	tuner_dbg("Noise level: %ddB (%05d)\n", value >> 8, value);
15068a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen
15078a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	/* highest noise level: 32dB */
15088a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	if (value >= 0x2000) {
15098a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen		value = 0;
15108a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	} else {
15118a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen		value = ~value << 3;
15128a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	}
15138a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen
15148a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	goto ret;
15158a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen
15168a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	/* Digital mode has SIGNAL LEVEL important and real
15178a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	   noise level is stored in demodulator registers.
15188a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	 */
15198a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugendigital:
15208a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	/* best signal: -50dB */
15218a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	if (value <= 0x3200) {
15228a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen		value = 0xffff;
15238a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	/* minimum: -114dB - should be 0x7200 but real zero is 0x713A */
15248a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	} else if (value >= 0x713A) {
15258a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen		value = 0;
15268a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	} else {
15278a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen		value = ~(value - 0x3200) << 2;
15288a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	}
15298a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen
15308a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugenret:
15318a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	*strength = value;
15328a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen
15338a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	return rc;
15348a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen}
15358a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen
15368d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq)
15378d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
15388d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	struct xc4000_priv *priv = fe->tuner_priv;
1539f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga
15404c07e32884ab69574cfd9eb4de3334233c938071Mauro Carvalho Chehab	*freq = priv->freq_hz + priv->freq_offset;
1541f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga
1542f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga	if (debug) {
1543f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga		mutex_lock(&priv->lock);
1544f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga		if ((priv->cur_fw.type
1545f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga		     & (BASE | FM | DTV6 | DTV7 | DTV78 | DTV8)) == BASE) {
1546f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga			u16	snr = 0;
1547f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga			if (xc4000_readreg(priv, XREG_SNR, &snr) == 0) {
1548f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga				mutex_unlock(&priv->lock);
1549f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga				dprintk(1, "%s() freq = %u, SNR = %d\n",
1550f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga					__func__, *freq, snr);
1551f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga				return 0;
1552f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga			}
1553f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga		}
1554f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga		mutex_unlock(&priv->lock);
1555f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga	}
1556f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga
1557f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga	dprintk(1, "%s()\n", __func__);
1558f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga
15598d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return 0;
15608d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
15618d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
15628d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc4000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
15638d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
15648d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	struct xc4000_priv *priv = fe->tuner_priv;
15658d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	dprintk(1, "%s()\n", __func__);
15668d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
15678d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	*bw = priv->bandwidth;
15688d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return 0;
15698d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
15708d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
15718d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc4000_get_status(struct dvb_frontend *fe, u32 *status)
15728d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
15738d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	struct xc4000_priv *priv = fe->tuner_priv;
1574fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	u16	lock_status = 0;
15758d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
15765614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga	mutex_lock(&priv->lock);
15775614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga
1578f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga	if (priv->cur_fw.type & BASE)
1579f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga		xc_get_lock_status(priv, &lock_status);
15808d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1581f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga	*status = (lock_status == 1 ?
1582f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga		   TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO : 0);
1583f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga	if (priv->cur_fw.type & (DTV6 | DTV7 | DTV78 | DTV8))
1584f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga		*status &= (~TUNER_STATUS_STEREO);
15855614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga
1586f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga	mutex_unlock(&priv->lock);
15878d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1588f4312e2fd4ca44e1defad1637d054bbe11a4ade6Istvan Varga	dprintk(2, "%s() lock_status = %d\n", __func__, lock_status);
15898d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
15908d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return 0;
15918d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
15928d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
15938d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc4000_sleep(struct dvb_frontend *fe)
15948d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
15955272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga	struct xc4000_priv *priv = fe->tuner_priv;
1596341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu	int	ret = 0;
15975272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga
15985272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga	dprintk(1, "%s()\n", __func__);
15995272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga
16005272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga	mutex_lock(&priv->lock);
16015272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga
16025272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga	/* Avoid firmware reload on slow devices */
16035272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga	if ((no_poweroff == 2 ||
16048edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu	     (no_poweroff == 0 && priv->default_pm != 0)) &&
16055272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga	    (priv->cur_fw.type & BASE) != 0) {
16065272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga		/* force reset and firmware reload */
16075272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga		priv->cur_fw.type = XC_POWERED_DOWN;
16085272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga
1609341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		if (xc_write_reg(priv, XREG_POWER_DOWN, 0) != 0) {
16105272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga			printk(KERN_ERR
16115272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga			       "xc4000: %s() unable to shutdown tuner\n",
16125272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga			       __func__);
16135272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga			ret = -EREMOTEIO;
16145272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga		}
1615341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		msleep(20);
16165272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga	}
16175272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga
16185272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga	mutex_unlock(&priv->lock);
16195272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga
16205272f6b1f423d4ce636dc90f190e245897bdb045Istvan Varga	return ret;
16218d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
16228d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
16238d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc4000_init(struct dvb_frontend *fe)
16248d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
16258d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	dprintk(1, "%s()\n", __func__);
16268d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
16278d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return 0;
16288d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
16298d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
16308d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic int xc4000_release(struct dvb_frontend *fe)
16318d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
16328d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	struct xc4000_priv *priv = fe->tuner_priv;
16338d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
16348d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	dprintk(1, "%s()\n", __func__);
16358d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
16368d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	mutex_lock(&xc4000_list_mutex);
16378d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
16388d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	if (priv)
16398d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		hybrid_tuner_release_state(priv);
16408d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
16418d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	mutex_unlock(&xc4000_list_mutex);
16428d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
16438d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	fe->tuner_priv = NULL;
16448d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
16458d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return 0;
16468d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
16478d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
16488d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristatic const struct dvb_tuner_ops xc4000_tuner_ops = {
16498d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	.info = {
16508d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		.name           = "Xceive XC4000",
16518d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		.frequency_min  =    1000000,
16528d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		.frequency_max  = 1023000000,
16538d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		.frequency_step =      50000,
16548d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	},
16558d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
16568d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	.release	   = xc4000_release,
16578d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	.init		   = xc4000_init,
16588d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	.sleep		   = xc4000_sleep,
16598d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
16608d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	.set_params	   = xc4000_set_params,
16618d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	.set_analog_params = xc4000_set_analog_params,
16628d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	.get_frequency	   = xc4000_get_frequency,
16638a538a8855aa95e5a12ae232a140e6b30c56d0c5Miroslav Slugen	.get_rf_strength   = xc4000_get_signal,
16648d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	.get_bandwidth	   = xc4000_get_bandwidth,
16658d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	.get_status	   = xc4000_get_status
16668d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri};
16678d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
16688d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferristruct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
16698d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri				   struct i2c_adapter *i2c,
16708d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri				   struct xc4000_config *cfg)
16718d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri{
16728d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	struct xc4000_priv *priv = NULL;
1673fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	int	instance;
1674fbe4a29f2f6523b8b839debb19baa49461a302beIstvan Varga	u16	id = 0;
16758d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
16768d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	dprintk(1, "%s(%d-%04x)\n", __func__,
16778d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		i2c ? i2c_adapter_id(i2c) : -1,
16788d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		cfg ? cfg->i2c_address : -1);
16798d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
16808d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	mutex_lock(&xc4000_list_mutex);
16818d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
16828d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	instance = hybrid_tuner_request_state(struct xc4000_priv, priv,
16838d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri					      hybrid_tuner_instance_list,
16848d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri					      i2c, cfg->i2c_address, "xc4000");
16858d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	switch (instance) {
16868d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	case 0:
16878d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		goto fail;
16888d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	case 1:
16898d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		/* new tuner instance */
1690c6f56e7d794cba022353d464dfa3383d1b3e0125Mauro Carvalho Chehab		priv->bandwidth = 6000000;
16918edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu		/* set default configuration */
16928edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu		priv->if_khz = 4560;
16938edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu		priv->default_pm = 0;
16948edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu		priv->dvb_amplitude = 134;
16958edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu		priv->set_smoothedcvbs = 1;
16965614942bb06f5620d0d6eb67bc0268c76c5dd921Istvan Varga		mutex_init(&priv->lock);
16978d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		fe->tuner_priv = priv;
16988d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		break;
16998d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	default:
17008d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		/* existing tuner instance */
17018d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		fe->tuner_priv = priv;
17028d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		break;
17038d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
17048d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
17050b4021321c0536a3368746497686ce56e5bcf3e5Istvan Varga	if (cfg->if_khz != 0) {
17068edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu		/* copy configuration if provided by the caller */
17078d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		priv->if_khz = cfg->if_khz;
17088edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu		priv->default_pm = cfg->default_pm;
17098edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu		priv->dvb_amplitude = cfg->dvb_amplitude;
17108edeb6eb1ae113b8f25a79e5076c1a1ec93538d0istvan_v@mailbox.hu		priv->set_smoothedcvbs = cfg->set_smoothedcvbs;
17118d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
17128d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
17138d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	/* Check if firmware has been loaded. It is possible that another
17148d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	   instance of the driver has loaded the firmware.
17158d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	 */
17168d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1717027fd361860e40736c0ad093a8f4194d727afb63Istvan Varga	if (instance == 1) {
1718341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		if (xc4000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
17198d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			goto fail;
1720027fd361860e40736c0ad093a8f4194d727afb63Istvan Varga	} else {
1721027fd361860e40736c0ad093a8f4194d727afb63Istvan Varga		id = ((priv->cur_fw.type & BASE) != 0 ?
1722027fd361860e40736c0ad093a8f4194d727afb63Istvan Varga		      priv->hwmodel : XC_PRODUCT_ID_FW_NOT_LOADED);
1723027fd361860e40736c0ad093a8f4194d727afb63Istvan Varga	}
17248d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
17258d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	switch (id) {
17267db98fe66be035494912b6b2c4e9c1e3abfedfe5Istvan Varga	case XC_PRODUCT_ID_XC4000:
17277db98fe66be035494912b6b2c4e9c1e3abfedfe5Istvan Varga	case XC_PRODUCT_ID_XC4100:
17288d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		printk(KERN_INFO
17298d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			"xc4000: Successfully identified at address 0x%02x\n",
17308d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			cfg->i2c_address);
17318d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		printk(KERN_INFO
17328d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			"xc4000: Firmware has been loaded previously\n");
17338d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		break;
17348d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	case XC_PRODUCT_ID_FW_NOT_LOADED:
17358d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		printk(KERN_INFO
17368d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			"xc4000: Successfully identified at address 0x%02x\n",
17378d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			cfg->i2c_address);
17388d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		printk(KERN_INFO
17398d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			"xc4000: Firmware has not been loaded previously\n");
17408d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		break;
17418d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	default:
17428d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		printk(KERN_ERR
17438d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			"xc4000: Device not found at addr 0x%02x (0x%x)\n",
17448d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri			cfg->i2c_address, id);
17458d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		goto fail;
17468d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	}
17478d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
17488d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	mutex_unlock(&xc4000_list_mutex);
17498d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
17508d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops,
17518d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri		sizeof(struct dvb_tuner_ops));
17528d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
1753027fd361860e40736c0ad093a8f4194d727afb63Istvan Varga	if (instance == 1) {
1754027fd361860e40736c0ad093a8f4194d727afb63Istvan Varga		int	ret;
1755027fd361860e40736c0ad093a8f4194d727afb63Istvan Varga		mutex_lock(&priv->lock);
1756027fd361860e40736c0ad093a8f4194d727afb63Istvan Varga		ret = xc4000_fwupload(fe);
1757027fd361860e40736c0ad093a8f4194d727afb63Istvan Varga		mutex_unlock(&priv->lock);
1758341747bef5dd2e2f56647ba30ea2180752905fa0istvan_v@mailbox.hu		if (ret != 0)
1759027fd361860e40736c0ad093a8f4194d727afb63Istvan Varga			goto fail2;
1760027fd361860e40736c0ad093a8f4194d727afb63Istvan Varga	}
176111091a31fbf7496294795ca72d69db0233857d94Devin Heitmueller
17628d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return fe;
17638d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferrifail:
17648d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	mutex_unlock(&xc4000_list_mutex);
1765027fd361860e40736c0ad093a8f4194d727afb63Istvan Vargafail2:
17668d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	xc4000_release(fe);
17678d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri	return NULL;
17688d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri}
17698d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide FerriEXPORT_SYMBOL(xc4000_attach);
17708d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide Ferri
17718d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide FerriMODULE_AUTHOR("Steven Toth, Davide Ferri");
17728d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide FerriMODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver");
17738d009a0c41475a482aca17d2a9fc8e6965f2fdf9Davide FerriMODULE_LICENSE("GPL");
1774612ae142ac02e8b187f23b8c9f1cc9cd8c6a078dMauro Carvalho ChehabMODULE_FIRMWARE(XC4000_DEFAULT_FIRMWARE_NEW);
1775612ae142ac02e8b187f23b8c9f1cc9cd8c6a078dMauro Carvalho ChehabMODULE_FIRMWARE(XC4000_DEFAULT_FIRMWARE);
1776