[go: nahoru, domu]

1360a0cab50414ee30924917159066e69ee4b38d3Rob Herring/*
2360a0cab50414ee30924917159066e69ee4b38d3Rob Herring    Driver for VES1893 and VES1993 QPSK Demodulators
3ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD
4c84ca7ce3ae5d80622c1cc1cfe21011f9cc15be7Joachim Eastwood    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
5c84ca7ce3ae5d80622c1cc1cfe21011f9cc15be7Joachim Eastwood    Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de>
658dc5b53e1c1467e54bbbc47d56a4d5f8c478a31Joachim Eastwood    Copyright (C) 2002 Dennis Noermann <dennis.noermann@noernet.de>
7ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD    Copyright (C) 2002-2003 Andreas Oberritter <obi@linuxtv.org>
8ad8a15d99cf2c8ab8ac1ab28402c49ec2548358dJean-Christophe PLAGNIOL-VILLARD
9e91a5555df5883bbc204b0e1f8e0489d3f7f3f2eJean-Christophe PLAGNIOL-VILLARD    This program is free software; you can redistribute it and/or modify
10ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD    it under the terms of the GNU General Public License as published by
11ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD    the Free Software Foundation; either version 2 of the License, or
12ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD    (at your option) any later version.
13ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD
14ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD    This program is distributed in the hope that it will be useful,
15ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD    but WITHOUT ANY WARRANTY; without even the implied warranty of
16ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD
18ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD    GNU General Public License for more details.
19ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD
202515e8bbc5dca415c5a810b8d5c6aa6acec1903cDouglas Gilbert    You should have received a copy of the GNU General Public License
21ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD    along with this program; if not, write to the Free Software
22ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD
24ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD*/
25ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD
26d5c669f13759e790caf158d319641757768713beJean-Christophe PLAGNIOL-VILLARD#include <linux/kernel.h>
27ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD#include <linux/module.h>
28ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD#include <linux/init.h>
29ee867d8eab1ffba8ace677eb6b62fba8c45d2e85Jean-Christophe PLAGNIOL-VILLARD#include <linux/string.h>
30ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD#include <linux/slab.h>
31ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD#include <linux/delay.h>
32ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD
330d67c9e81351a2269f3ae0e8072cb1d463bf5bc6Douglas Gilbert#include "dvb_frontend.h"
34470e891b06b2971037b38020cb4b9e7e496500e6Rodolfo Giometti#include "ves1x93.h"
35ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD
36ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD
37ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARDstruct ves1x93_state {
38ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD	struct i2c_adapter* i2c;
39ec6754a7b9e90a1eba7f3b2812003bb51d3dcf30Jean-Christophe PLAGNIOL-VILLARD	/* configuration settings */
40655ff266998ae4b3c8e8565bf30f60ceebe39b54Ludovic Desroches	const struct ves1x93_config* config;
41b7c2b6157079811586180d13c44a1095b57c2d47Nicolas Ferre	struct dvb_frontend frontend;
42655ff266998ae4b3c8e8565bf30f60ceebe39b54Ludovic Desroches
43655ff266998ae4b3c8e8565bf30f60ceebe39b54Ludovic Desroches	/* previous uncorrected block counter */
44655ff266998ae4b3c8e8565bf30f60ceebe39b54Ludovic Desroches	fe_spectral_inversion_t inversion;
45655ff266998ae4b3c8e8565bf30f60ceebe39b54Ludovic Desroches	u8 *init_1x93_tab;
46b32313c614268ee1fac37d63eceb33413b2d84c0Josh Wu	u8 *init_1x93_wtab;
47b32313c614268ee1fac37d63eceb33413b2d84c0Josh Wu	u8 tab_size;
483349a4b9019b57876b25c694025d96f519b795bcBarry Song	u8 demod_type;
4985594df2bad0dddb36aa8aa242f4d15e6f122f02Olof Johansson	u32 frequency;
50a4412050149fb314420ecec8f9b9f8b3c9515ecfChristian Daudt};
5128ea3f3649b2adbfd96fdf66a2a25acc8c0e17ebMarkus Mayer
52a4412050149fb314420ecec8f9b9f8b3c9515ecfChristian Daudtstatic int debug;
532440946c29a37ee616a92152972a3772bd2f293cSebastian Hesselbarth#define dprintk	if (debug) printk
54a90921185fe5db3e02aecf473f0c54343ae17191Sebastian Hesselbarth
55a90921185fe5db3e02aecf473f0c54343ae17191Sebastian Hesselbarth#define DEMOD_VES1893		0
563fcdc0555f5043eded6312efce14cd8dd66f30f8Olof Johansson#define DEMOD_VES1993		1
573fcdc0555f5043eded6312efce14cd8dd66f30f8Olof Johansson
58b014487044161b83010a9cbe336dbc41d2c38a0bOlof Johanssonstatic u8 init_1893_tab [] = {
59b014487044161b83010a9cbe336dbc41d2c38a0bOlof Johansson	0x01, 0xa4, 0x35, 0x80, 0x2a, 0x0b, 0x55, 0xc4,
605e9eaadb0b3fa8c12715d9761158ec328d7e9523Sebastian Hesselbarth	0x09, 0x69, 0x00, 0x86, 0x4c, 0x28, 0x7f, 0x00,
6137078732998e51c2645db99e7434ccc6774dafedSebastian Hesselbarth	0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62b014487044161b83010a9cbe336dbc41d2c38a0bOlof Johansson	0x80, 0x00, 0x21, 0xb0, 0x14, 0x00, 0xdc, 0x00,
63ef43eff3447f30b4a3cfc61813902c2e57c20245Uwe Kleine-König	0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	0x00, 0x55, 0x00, 0x00, 0x7f, 0x00
669cd11c0c47b8690b47e7573311ce5c483cb344edLinus Torvalds};
67765d012c2389cc0481f04dcccd3949f1ba0969baTomasz Figa
68800974ac0420f8f81cd7ad4d33bdf179b890b282Dongjin Kimstatic u8 init_1993_tab [] = {
692107673e16e4a20a14fd25505fa1a81e273f9983Thomas Abraham	0x00, 0x9c, 0x35, 0x80, 0x6a, 0x09, 0x72, 0x8c,
70a94f56abae464e5fb6cd327d52de005dc9b96ee2Kukjin Kim	0x09, 0x6b, 0x00, 0x00, 0x4c, 0x08, 0x00, 0x00,
71b67a55125f1413902f7db6d167a8d9e4154386bfAlex Ling	0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7215dfdfad2d4a7e99c005854090274d03f7bacd27Tomasz Figa	0x80, 0x40, 0x21, 0xb0, 0x00, 0x00, 0x00, 0x10,
73e88d5ae61a00b602cdd6a6c07f9fe6fbcaad06d7Girish K S	0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7495e82941b73b4a8811299ad7b639157822c8c59dDoug Anderson	0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
757e65df3899cef3193ec44a7870f9bdc1ee6af833Kukjin Kim	0x00, 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03,
769dd51c9f778199d343ae55db8a7d084e27501211Sachin Kamat	0x00, 0x00, 0x0e, 0x80, 0x00
7734dcedfbf97bc1c91c20f341e4ff4f70e53a0644Chander Kashyap};
78a94f56abae464e5fb6cd327d52de005dc9b96ee2Kukjin Kim
797e65df3899cef3193ec44a7870f9bdc1ee6af833Kukjin Kimstatic u8 init_1893_wtab[] =
800cfb1c8bec551c8eb7c6b263baebc9537d2b910cHaojian Zhuang{
817d6ab9b8620bbca6718b36242113f4f069840641Rob Herring	1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
827d6ab9b8620bbca6718b36242113f4f069840641Rob Herring	0,1,0,0,0,0,0,0, 1,0,1,1,0,0,0,1,
8317bfcd3adc2c2002c1fdf990640bc36aec6a90b3Linus Walleij	1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0,
8417bfcd3adc2c2002c1fdf990640bc36aec6a90b3Linus Walleij	1,1,1,0,1,1
85360a0cab50414ee30924917159066e69ee4b38d3Rob Herring};
8698d4f2acb91ac4a839eab6b92f02f57986af2197Simon Guinot
870d0632f523fa040b307688ae421a1debf79af2d7Thomas Petazzonistatic u8 init_1993_wtab[] =
880d0632f523fa040b307688ae421a1debf79af2d7Thomas Petazzoni{
8998d4f2acb91ac4a839eab6b92f02f57986af2197Simon Guinot	1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
90360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	0,1,0,0,0,0,0,0, 1,1,1,1,0,0,0,1,
91b014487044161b83010a9cbe336dbc41d2c38a0bOlof Johansson	1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0,
92360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	1,1,1,0,1,1,1,1, 1,1,1,1,1
93360a0cab50414ee30924917159066e69ee4b38d3Rob Herring};
949b47a4fb7760fabfbbc33b7d7703454684f36782Willy Tarreau
95360a0cab50414ee30924917159066e69ee4b38d3Rob Herringstatic int ves1x93_writereg (struct ves1x93_state* state, u8 reg, u8 data)
96360a0cab50414ee30924917159066e69ee4b38d3Rob Herring{
97b014487044161b83010a9cbe336dbc41d2c38a0bOlof Johansson	u8 buf [] = { 0x00, reg, data };
98ecee1e47ab42ba3907d6bde7b2981e1006382071Simon Guinot	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 };
99b014487044161b83010a9cbe336dbc41d2c38a0bOlof Johansson	int err;
1002cc64b5655da65bbb6a760a722b5ab1f53f92cf7Maxime Hadjinlian
101360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
102360a0cab50414ee30924917159066e69ee4b38d3Rob Herring		dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
1035492a1108bbd40e14a895c07b6a4952022e82f7cStefan Peter		return -EREMOTEIO;
10437ae08c9395420dc1479bca17158a649a771831dThomas Petazzoni	}
105f236f5aabe8ebd7824590ae82d701402ead237e7Arnaud Ebalard
10646ca506c43d64e11257a0a113701e9bcccf52416Arnaud Ebalard	return 0;
107ecee1e47ab42ba3907d6bde7b2981e1006382071Simon Guinot}
108ca7d94524ab3554b08f13de91674d570cb4a09b6Simon Guinot
109ecee1e47ab42ba3907d6bde7b2981e1006382071Simon Guinotstatic u8 ves1x93_readreg (struct ves1x93_state* state, u8 reg)
1107f9871d9d30f25891e0c4da4c6284d9e66e702f5Simon Guinot{
111afcad884252b171ff6f2ac78eb43c2f5db612dd0Tero Jaasko	int ret;
112eee47b7c6eb44861fe9a6c7052fd8243a4beaea6Andrew Lunn	u8 b0 [] = { 0x00, reg };
113f24b56cbcd9d39cb2ed45b4b451f8614f9494c17Thomas Petazzoni	u8 b1 [] = { 0 };
114f24b56cbcd9d39cb2ed45b4b451f8614f9494c17Thomas Petazzoni	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
115ee514b381e17958fde5b99cba506f31ea6589c0bSimon Baatz			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
116ee514b381e17958fde5b99cba506f31ea6589c0bSimon Baatz
117767fc1ea92f70b5a97d43b79c146c2bee3eb6e83Jason Cooper	ret = i2c_transfer (state->i2c, msg, 2);
118360a0cab50414ee30924917159066e69ee4b38d3Rob Herring
119f24b56cbcd9d39cb2ed45b4b451f8614f9494c17Thomas Petazzoni	if (ret != 2) return ret;
1204898de3d15d8ba34aa7a1b0f753a476d52ebdf92Barry Song
121448e7edefa929104c77fe1a1cce4aa8ffc77d291Jonas Jensen	return b1[0];
12281cf1e061d001fab44dbaa85fc4fbfb6da6713a1Kumar Gala}
1239857a7531ffcf35442f9ef707e4e0d94a7a7fb18Rohit Vaswani
1249857a7531ffcf35442f9ef707e4e0d94a7a7fb18Rohit Vaswanistatic int ves1x93_clr_bit (struct ves1x93_state* state)
125360a0cab50414ee30924917159066e69ee4b38d3Rob Herring{
126e3e37bcab910a68616bc33145ed5c333825053acGregory CLEMENT	msleep(10);
1272344a29a923b95bb28609da4038590c4131160ccArnaud Ebalard	ves1x93_writereg (state, 0, state->init_1x93_tab[0] & 0xfe);
12845e8815fc1b7ed66729bbbc9464228ee1769b580Arnaud Ebalard	ves1x93_writereg (state, 0, state->init_1x93_tab[0]);
129491221451b9998cf182770f2b5f8b3a8b141dd81Florian Fainelli	msleep(50);
130c7841473f7ecbff624809f31f36aab0df5041ef9Thomas Petazzoni	return 0;
13119b85c086019e54c1976fdaf56e8923f7e568091Thomas Petazzoni}
132568fc0a321a7f3ae1c3626a4f471d49ff005779cGregory CLEMENT
1338aa0b019fe1400cc8861ead9ff4cd0ba9f4e11ceArnaud Ebalardstatic int ves1x93_set_inversion (struct ves1x93_state* state, fe_spectral_inversion_t inversion)
1347837feff0d881835309fced7a7c4b5f32866d632Thomas Petazzoni{
13519b85c086019e54c1976fdaf56e8923f7e568091Thomas Petazzoni	u8 val;
1368ba472357a87503df2214ddc0270706ae34da4a1Shawn Guo
1378ba472357a87503df2214ddc0270706ae34da4a1Shawn Guo	/*
138860c06f6c0620307b595aacb3ead9c439e9dd785Fabio Estevam	 * inversion on/off are interchanged because i and q seem to
1398ba472357a87503df2214ddc0270706ae34da4a1Shawn Guo	 * be swapped on the hardware
14000ba2459f6d5f9caee01cf5628df553ace50cbcdGwenhael Goavec-Merou	 */
1418ba472357a87503df2214ddc0270706ae34da4a1Shawn Guo
14242a56fc6febad79f16a94391d89c617c140d6e7eAlexander Shiyan	switch (inversion) {
143c05c1bf5739cb7adaa955503fc819d077bc46d25Alexander Shiyan	case INVERSION_OFF:
144db890dad41d538f774e0e1f2f10613b1b083a96bMarkus Pargmann		val = 0xc0;
145db890dad41d538f774e0e1f2f10613b1b083a96bMarkus Pargmann		break;
1468ba472357a87503df2214ddc0270706ae34da4a1Shawn Guo	case INVERSION_ON:
1471982d5b6c1b78363b5142eb0cb81c38d7604fc61Laurent Cans		val = 0x80;
148e910b45c9d6413c057fc0aaf8616683446bdda7dGwenhael Goavec-Merou		break;
1499c9651cd7412032657e4949dd5cbdd8f1364befdFabio Estevam	case INVERSION_AUTO:
150360a0cab50414ee30924917159066e69ee4b38d3Rob Herring		val = 0x00;
151360a0cab50414ee30924917159066e69ee4b38d3Rob Herring		break;
152051124e596869ddf3efa7a2dc2f8209401e55d09Marek Vasut	default:
153be3a568d77fac942bbc7fb5ed77963bc254e60ffSteffen Trumtrar		return -EINVAL;
154360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	}
155360a0cab50414ee30924917159066e69ee4b38d3Rob Herring
156971488f1149f09fd2fad0e7973780b752809b9f6Russell King	return ves1x93_writereg (state, 0x0c, (state->init_1x93_tab[0x0c] & 0x3f) | val);
157208d7baf8085ed639ec896274f1679d4718f2ff3Russell King}
1581aa8b3e06f5fcc294b54fe2c35b2e34b09048e94Shawn Guo
1599a8d6d55f6989961298b995e3ef91eb90e034cf2Shawn Guostatic int ves1x93_set_fec (struct ves1x93_state* state, fe_code_rate_t fec)
16089b82915c4b5afa9e51e09636f7919bbb6f9cc1bFabio Estevam{
161360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	if (fec == FEC_AUTO)
162971488f1149f09fd2fad0e7973780b752809b9f6Russell King		return ves1x93_writereg (state, 0x0d, 0x08);
1633180f956668ee04d35d77b32a6a1be10fb251d9dChristian Hemp	else if (fec < FEC_1_2 || fec > FEC_8_9)
1645c70cb01b89895189025f8de8ee2823f516eab6aFabio Estevam		return -EINVAL;
165360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	else
1668593a1a2e88a0b23d3bd626eee6519de9ee55938Pavel Machek		return ves1x93_writereg (state, 0x0d, fec - FEC_1_2);
167117ccd553a02a69aff41083f8b59a38927ccf002Shawn Guo}
16840cdaa542cf0c570600c29b006b782631d07d052Fabio Estevam
1692688a32f98774573d42a2a5cf024fd6caca00619Fabio Estevamstatic fe_code_rate_t ves1x93_get_fec (struct ves1x93_state* state)
170e77b74ee6c4115a0fe1fdb673dbf25ffe1277205Jingchang Lu{
171931398ecd51bc7d6f3a22561c31bfd34d030c94aMatt Porter	return FEC_1_2 + ((ves1x93_readreg (state, 0x0d) >> 4) & 0x7);
172e77b74ee6c4115a0fe1fdb673dbf25ffe1277205Jingchang Lu}
173360a0cab50414ee30924917159066e69ee4b38d3Rob Herring
174360a0cab50414ee30924917159066e69ee4b38d3Rob Herringstatic int ves1x93_set_symbolrate (struct ves1x93_state* state, u32 srate)
175360a0cab50414ee30924917159066e69ee4b38d3Rob Herring{
176a957fdca4feb7fbc51f9c7c6a152a86f35ca7751Julien Boibessot	u32 BDR;
177414b41536c4564db696d5fb18d8baf695491cd02Gwenhael Goavec-Merou	u32 ratio;
178360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	u8  ADCONF, FCONF, FNR, AGCR;
179360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	u32 BDRI;
180e0f7d905242f5eedc4801ce588f7f588f4ec57cbMaxime Ripard	u32 tmp;
1815ae8d15f686f93d2ac60a7b16d8ddfbfdfc7c00fOlof Johansson	u32 FIN;
182ed138c368d95095de522db98b8b6929874bed403Brian Lilly
183f6cd16f1d2dae4e31aba8bb6a3cac21aba1416ceBrian Lilly	dprintk("%s: srate == %d\n", __func__, (unsigned int) srate);
184d75f3d92e86e65b3cb9725e65f7278cc303511dbBrian Lilly
1859567832223f0aaa5ffed02307c2dc099a6640da8Brian Lilly	if (srate > state->config->xin/2)
186360a0cab50414ee30924917159066e69ee4b38d3Rob Herring		srate = state->config->xin/2;
187e0ec2f39ef9905a24d5d88238eda3dabb8d591e0Marek Vasut
188360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	if (srate < 500000)
189160d5f27605f5acac8f426d862e8f8a499eef2b5Marek Vasut		srate = 500000;
190360a0cab50414ee30924917159066e69ee4b38d3Rob Herring
191f8635abd38776a413d1e84c79353693b8ecf45c9Linus Walleij#define MUL (1UL<<26)
192d907849e0dbaeacb34e0a6a3b49ebeaf8c49355eDaniel Tang
193d907849e0dbaeacb34e0a6a3b49ebeaf8c49355eDaniel Tang	FIN = (state->config->xin + 6000) >> 4;
194d907849e0dbaeacb34e0a6a3b49ebeaf8c49355eDaniel Tang
19585594df2bad0dddb36aa8aa242f4d15e6f122f02Olof Johansson	tmp = srate << 6;
19604a25dfb7956284029b486b5c72657ebbf7b8c85Tony Lindgren	ratio = tmp / FIN;
197a900f51646f5e77b5a7fc164bfb10eed55497861Tony Lindgren
198a900f51646f5e77b5a7fc164bfb10eed55497861Tony Lindgren	tmp = (tmp % FIN) << 8;
199a900f51646f5e77b5a7fc164bfb10eed55497861Tony Lindgren	ratio = (ratio << 8) + tmp / FIN;
200678fac41938299d33b980ad0e7b81438d3d88836Jon Hunter
2015a8095e9d02da19f3bab738e82c0520ecd62d6afJon Hunter	tmp = (tmp % FIN) << 8;
2020f0cfc69547ea3e26f53e50eae2f25fe6ea1a77dTony Lindgren	ratio = (ratio << 8) + tmp / FIN;
2030f0cfc69547ea3e26f53e50eae2f25fe6ea1a77dTony Lindgren
2044bfe6341d4bfcb68c083b3109b6a4997cd287262Anil Kumar	FNR = 0xff;
20585594df2bad0dddb36aa8aa242f4d15e6f122f02Olof Johansson
20685594df2bad0dddb36aa8aa242f4d15e6f122f02Olof Johansson	if (ratio < MUL/3)	     FNR = 0;
2075992234bc5f34f3069d0457090d87865ec31fe13Tony Lindgren	if (ratio < (MUL*11)/50)     FNR = 1;
208bd5fc6fa657cfe4b2de6e0f6e4daae41217392bdTony Lindgren	if (ratio < MUL/6)	     FNR = 2;
209a4d4b15363ea31236e557c471d9aa95202fed88aPavel Machek	if (ratio < MUL/9)	     FNR = 3;
210df01318850d5c687533c6e2460d1df65944d0d4bAaro Koskinen	if (ratio < MUL/12)	     FNR = 4;
211df01318850d5c687533c6e2460d1df65944d0d4bAaro Koskinen	if (ratio < (MUL*11)/200)    FNR = 5;
21285594df2bad0dddb36aa8aa242f4d15e6f122f02Olof Johansson	if (ratio < MUL/24)	     FNR = 6;
213adfe1473bda5bfb8d344a94fb17c0a929fcbd852Marek Belisko	if (ratio < (MUL*27)/1000)   FNR = 7;
214cb5e191e96953965aab8aa3bf4c0aee01faaaf79Javier Martinez Canillas	if (ratio < MUL/48)	     FNR = 8;
2159ad1df2b15b0f1952a57c3407996450cc64bc976Javier Martinez Canillas	if (ratio < (MUL*137)/10000) FNR = 9;
216c482525659effc9fadc0cef88cffdb6f8c63d2b6Tony Lindgren
21785594df2bad0dddb36aa8aa242f4d15e6f122f02Olof Johansson	if (FNR == 0xff) {
21830a6998ef4474b18d81d8c459f2cbd9e49ff0736Jon Hunter		ADCONF = 0x89;
21900cbdce75b62a56bf3e6baca68b5ddb5474495a2Benoit Cousson		FCONF  = 0x80;
22000cbdce75b62a56bf3e6baca68b5ddb5474495a2Benoit Cousson		FNR	= 0;
22185594df2bad0dddb36aa8aa242f4d15e6f122f02Olof Johansson	} else {
22244b5b2d2d405c148545bef910d953e2323769a7cFlorian Vaussard		ADCONF = 0x81;
223fa63d037283a6bd0db96078d87192d1aaa073f3cSricharan R		FCONF  = 0x88 | (FNR >> 1) | ((FNR & 0x01) << 5);
224f0cfa981cec09e6e353295e0f8dc36bc10289996Vaibhav Hiremath		/*FCONF	 = 0x80 | ((FNR & 0x01) << 5) | (((FNR > 1) & 0x03) << 3) | ((FNR >> 1) & 0x07);*/
2257340dd530c5f72e63201953677b42c9e5fdb2b3dBenoit Cousson	}
22644b5b2d2d405c148545bef910d953e2323769a7cFlorian Vaussard
2272ba3549352277514a8e4790adff77a783ee1b9e2Koen Kooi	BDR = (( (ratio << (FNR >> 1)) >> 4) + 1) >> 1;
228c351e29018eeb2fa3151e09a9102e223519c34d5Mark Jackson	BDRI = ( ((FIN << 8) / ((srate << (FNR >> 1)) >> 2)) + 1) >> 1;
2295cda1620f457459240176ab6abc9431a1ad6684aEnric Balletbo i Serra
23044b5b2d2d405c148545bef910d953e2323769a7cFlorian Vaussard	dprintk("FNR= %d\n", FNR);
2314730bcfb067a92bd446b4ffd149e0768572c7f19Afzal Mohammed	dprintk("ratio= %08x\n", (unsigned int) ratio);
2326e58b8f1daaf1af340fb9309907e5ffa473c7affR Sricharan	dprintk("BDR= %08x\n", (unsigned int) BDR);
2336e58b8f1daaf1af340fb9309907e5ffa473c7affR Sricharan	dprintk("BDRI= %02x\n", (unsigned int) BDRI);
23407f645df9ff2550749b806af626576d5ad418215Thomas Petazzoni
23585594df2bad0dddb36aa8aa242f4d15e6f122f02Olof Johansson	if (BDRI > 0xff)
2362ce05a14bb379bd81ba3ad12cc08b2c4bda83480Linus Walleij		BDRI = 0xff;
23701dc909fa1be6259cdbbc9fd6933df4fbe26ea5aLinus Walleij
23801dc909fa1be6259cdbbc9fd6933df4fbe26ea5aLinus Walleij	ves1x93_writereg (state, 0x06, 0xff & BDR);
23901dc909fa1be6259cdbbc9fd6933df4fbe26ea5aLinus Walleij	ves1x93_writereg (state, 0x07, 0xff & (BDR >> 8));
24001dc909fa1be6259cdbbc9fd6933df4fbe26ea5aLinus Walleij	ves1x93_writereg (state, 0x08, 0x0f & (BDR >> 16));
2412ce05a14bb379bd81ba3ad12cc08b2c4bda83480Linus Walleij
2422ce05a14bb379bd81ba3ad12cc08b2c4bda83480Linus Walleij	ves1x93_writereg (state, 0x09, BDRI);
24335aca36450e6c3fb3b3fe9ea60a7c4689a219a87Heiko Stuebner	ves1x93_writereg (state, 0x20, ADCONF);
2442ec35a4252eae3d5277af041bd1b5ae4f6183cadTomasz Figa	ves1x93_writereg (state, 0x21, FCONF);
2452ec35a4252eae3d5277af041bd1b5ae4f6183cadTomasz Figa
246bf98c1eac1d4a6bcf00532e4fa41d8126cd6c187Laurent Pinchart	AGCR = state->init_1x93_tab[0x05];
247a4ed412ed5934127ba88ba007b9a00617ae47f75Magnus Damm	if (state->config->invert_pwm)
248495e06d1daff7f59b511c27c95d2601c1d9dad49Magnus Damm		AGCR |= 0x20;
24985594df2bad0dddb36aa8aa242f4d15e6f122f02Olof Johansson
25053e42c2974feaa269bc485267d0a4df0ef55e549Kuninori Morimoto	if (srate < 6000000)
251cfa66a81621d0e85ac03c0de25adc7edd7f2649eKuninori Morimoto		AGCR |= 0x80;
25276b92b4043f2303b443645b5609a8867e8a8b5d7Bastian Hecht	else
253d6b51d6b6a33974dfa7b091f61e7a2bedd62f298Simon Horman		AGCR &= ~0x80;
25473d6a69e3b3ae168fcb8d797e427c1b5fe132a40Simon Horman
2551f52c65975ba16cdba1830ba216776111197a3eeHisashi Nakamura	ves1x93_writereg (state, 0x05, AGCR);
2563cc828fdb32281cc8166d3a40bee32b90ce3cad8Magnus Damm
2570ce53cdc5c7e28f378e480363a0b0c2ed7e7eaf9Nobuhiro Iwamatsu	/* ves1993 hates this, will lose lock */
258b8b82b2983e5b7bccca3a037c886e2aad86aaeeaSimon Horman	if (state->demod_type != DEMOD_VES1993)
25978ded16886f539830ed58d9bc043656c1785a082Magnus Damm		ves1x93_clr_bit (state);
26069f366615e950cb0d5af89da228796af5208ad8fGuennadi Liakhovetski
2610ce53cdc5c7e28f378e480363a0b0c2ed7e7eaf9Nobuhiro Iwamatsu	return 0;
2626d75bc6439ec3f4ae45db1e501177382d0582591Magnus Damm}
2637d91c4691207a302c50308ab38706b8a3d6039cdMagnus Damm
2641d2bdbc3a8f93b8c1dfc95b2df89c266dd6ce9d0Laurent Pinchartstatic int ves1x93_init (struct dvb_frontend* fe)
2651d2bdbc3a8f93b8c1dfc95b2df89c266dd6ce9d0Laurent Pinchart{
266163a036468c2eb8f30658dff6c0de6c959f79b0dDinh Nguyen	struct ves1x93_state* state = fe->demodulator_priv;
267163a036468c2eb8f30658dff6c0de6c959f79b0dDinh Nguyen	int i;
26847ba5c815a341899035a35f7b58fbe1f1deee880Steffen Trumtrar	int val;
26990c294557d411100d3557bc2762a98a93f989430Dinh Nguyen
270360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	dprintk("%s: init chip\n", __func__);
271360a0cab50414ee30924917159066e69ee4b38d3Rob Herring
272360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	for (i = 0; i < state->tab_size; i++) {
273360a0cab50414ee30924917159066e69ee4b38d3Rob Herring		if (state->init_1x93_wtab[i]) {
274e2eb69183ec4156eb814e67672e492bf902bbcd2Shiraz Hashim			val = state->init_1x93_tab[i];
275e2eb69183ec4156eb814e67672e492bf902bbcd2Shiraz Hashim
276360a0cab50414ee30924917159066e69ee4b38d3Rob Herring			if (state->config->invert_pwm && (i == 0x05)) val |= 0x20; /* invert PWM */
277f1148dba64f3bf3a346e1eb7cdfac0e5f70660c8Srinivas Kandagatla			ves1x93_writereg (state, i, val);
27840e3e6725370481b7b81d969dbde056f50d870aeSrinivas Kandagatla		}
27940e3e6725370481b7b81d969dbde056f50d870aeSrinivas Kandagatla	}
28040e3e6725370481b7b81d969dbde056f50d870aeSrinivas Kandagatla
281d34c671debe3d327424a9951a5c3a81065d0474dMaxime Ripard	return 0;
282629ae88e9cebc6281bc54be743a33eca47b7228cEmilio López}
283d34c671debe3d327424a9951a5c3a81065d0474dMaxime Ripard
284d34c671debe3d327424a9951a5c3a81065d0474dMaxime Ripardstatic int ves1x93_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
285a9d281cab72cbb45fcde8be3e20b7494f573ac9dMaxime Ripard{
286d0f2677be5b49a1c1de59fe94faa96b7808be95fMaxime Ripard	struct ves1x93_state* state = fe->demodulator_priv;
2870bef900b7fae00f2f58bffdeac3fd4dbae78c117Maxime Ripard
28852e86b37b1d3f7c02938def3a036e0bb0f723964Hans de Goede	switch (voltage) {
289e476ac8b483de4ce1d8570509be343afc7cd3bafMaxime Ripard	case SEC_VOLTAGE_13:
29082abe5294aeadc42508c7944f3a9aec0eece214cMaxime Ripard		return ves1x93_writereg (state, 0x1f, 0x20);
29101ed6632a554dfdf4a9fc3c593ce4ff7255ed161Oliver Schinagl	case SEC_VOLTAGE_18:
292e476ac8b483de4ce1d8570509be343afc7cd3bafMaxime Ripard		return ves1x93_writereg (state, 0x1f, 0x30);
293360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	case SEC_VOLTAGE_OFF:
294bf5fcc76d31418950b214542440d5de6e48c7998Lucas Stach		return ves1x93_writereg (state, 0x1f, 0x00);
2955ae8d15f686f93d2ac60a7b16d8ddfbfdfc7c00fOlof Johansson	default:
296360a0cab50414ee30924917159066e69ee4b38d3Rob Herring		return -EINVAL;
2975ae8d15f686f93d2ac60a7b16d8ddfbfdfc7c00fOlof Johansson	}
298360a0cab50414ee30924917159066e69ee4b38d3Rob Herring}
2995ae8d15f686f93d2ac60a7b16d8ddfbfdfc7c00fOlof Johansson
300360a0cab50414ee30924917159066e69ee4b38d3Rob Herringstatic int ves1x93_read_status(struct dvb_frontend* fe, fe_status_t* status)
301360a0cab50414ee30924917159066e69ee4b38d3Rob Herring{
302360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	struct ves1x93_state* state = fe->demodulator_priv;
303d7df69fe256587c5f78961c4d69a95d4a5b12c71Bryan Wu
3045ae8d15f686f93d2ac60a7b16d8ddfbfdfc7c00fOlof Johansson	u8 sync = ves1x93_readreg (state, 0x0e);
305a71c03e7fd6a4027f750e2951830669244a8dad6Hiroshi Doyu
306a1425d428f39e5b95663f3f8037f372e86f2676fJoseph Lo	/*
307a1425d428f39e5b95663f3f8037f372e86f2676fJoseph Lo	 * The ves1893 sometimes returns sync values that make no sense,
308cc8e9ad88487004372cae87718ff593d0a2fdc3aRob Herring	 * because, e.g., the SIGNAL bit is 0, while some of the higher
309cc8e9ad88487004372cae87718ff593d0a2fdc3aRob Herring	 * bits are 1 (and how can there be a CARRIER w/o a SIGNAL?).
310978577ea21fb05c12511c25b71e493859e36892fLinus Walleij	 * Tests showed that the VITERBI and SYNC bits are returned
311360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	 * reliably, while the SIGNAL and CARRIER bits ar sometimes wrong.
312360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	 * If such a case occurs, we read the value again, until we get a
313360a0cab50414ee30924917159066e69ee4b38d3Rob Herring	 * valid value.
314cc3d7f70c37641ca417f4c02ecaf12cd9772ffa6Stefano Stabellini	 */
315cc3d7f70c37641ca417f4c02ecaf12cd9772ffa6Stefano Stabellini	int maxtry = 10; /* just for safety - let's not get stuck here */
316ed304be1b222398cd15954724e95787bb42e3b37Tony Prisk	while ((sync & 0x03) != 0x03 && (sync & 0x0c) && maxtry--) {
317ed304be1b222398cd15954724e95787bb42e3b37Tony Prisk		msleep(10);
318def4d6c044ea1f5f58ed6d422e6797fb0b1cfb63Tony Prisk		sync = ves1x93_readreg (state, 0x0e);
3194606c48051db62db14756e1085fe0f8821a0e116Tony Prisk	}
320def4d6c044ea1f5f58ed6d422e6797fb0b1cfb63Tony Prisk
3214bda2670e4759b99f725176dd31caa612ea098b6Soren Brinkmann	*status = 0;
32250dbb4cfbc264b074759e8fb5d8e0c0496a1b072Soren Brinkmann
32350dbb4cfbc264b074759e8fb5d8e0c0496a1b072Soren Brinkmann	if (sync & 1)
324360a0cab50414ee30924917159066e69ee4b38d3Rob Herring		*status |= FE_HAS_SIGNAL;
325499cd8298628eeabf0eb5eb6525d4faa0eec80d8Grant Likely
3261ab3681271c84b7f926be9ae3be1d769b7e933e9Stephen Warren	if (sync & 2)
327360a0cab50414ee30924917159066e69ee4b38d3Rob Herring		*status |= FE_HAS_CARRIER;
328499cd8298628eeabf0eb5eb6525d4faa0eec80d8Grant Likely
329499cd8298628eeabf0eb5eb6525d4faa0eec80d8Grant Likely	if (sync & 4)
330499cd8298628eeabf0eb5eb6525d4faa0eec80d8Grant Likely		*status |= FE_HAS_VITERBI;
331499cd8298628eeabf0eb5eb6525d4faa0eec80d8Grant Likely
332499cd8298628eeabf0eb5eb6525d4faa0eec80d8Grant Likely	if (sync & 8)
333499cd8298628eeabf0eb5eb6525d4faa0eec80d8Grant Likely		*status |= FE_HAS_SYNC;
334499cd8298628eeabf0eb5eb6525d4faa0eec80d8Grant Likely
335	if ((sync & 0x1f) == 0x1f)
336		*status |= FE_HAS_LOCK;
337
338	return 0;
339}
340
341static int ves1x93_read_ber(struct dvb_frontend* fe, u32* ber)
342{
343	struct ves1x93_state* state = fe->demodulator_priv;
344
345	*ber = ves1x93_readreg (state, 0x15);
346	*ber |= (ves1x93_readreg (state, 0x16) << 8);
347	*ber |= ((ves1x93_readreg (state, 0x17) & 0x0F) << 16);
348	*ber *= 10;
349
350	return 0;
351}
352
353static int ves1x93_read_signal_strength(struct dvb_frontend* fe, u16* strength)
354{
355	struct ves1x93_state* state = fe->demodulator_priv;
356
357	u8 signal = ~ves1x93_readreg (state, 0x0b);
358	*strength = (signal << 8) | signal;
359
360	return 0;
361}
362
363static int ves1x93_read_snr(struct dvb_frontend* fe, u16* snr)
364{
365	struct ves1x93_state* state = fe->demodulator_priv;
366
367	u8 _snr = ~ves1x93_readreg (state, 0x1c);
368	*snr = (_snr << 8) | _snr;
369
370	return 0;
371}
372
373static int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
374{
375	struct ves1x93_state* state = fe->demodulator_priv;
376
377	*ucblocks = ves1x93_readreg (state, 0x18) & 0x7f;
378
379	if (*ucblocks == 0x7f)
380		*ucblocks = 0xffffffff;   /* counter overflow... */
381
382	ves1x93_writereg (state, 0x18, 0x00);  /* reset the counter */
383	ves1x93_writereg (state, 0x18, 0x80);  /* dto. */
384
385	return 0;
386}
387
388static int ves1x93_set_frontend(struct dvb_frontend *fe)
389{
390	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
391	struct ves1x93_state* state = fe->demodulator_priv;
392
393	if (fe->ops.tuner_ops.set_params) {
394		fe->ops.tuner_ops.set_params(fe);
395		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
396	}
397	ves1x93_set_inversion (state, p->inversion);
398	ves1x93_set_fec(state, p->fec_inner);
399	ves1x93_set_symbolrate(state, p->symbol_rate);
400	state->inversion = p->inversion;
401	state->frequency = p->frequency;
402
403	return 0;
404}
405
406static int ves1x93_get_frontend(struct dvb_frontend *fe)
407{
408	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
409	struct ves1x93_state* state = fe->demodulator_priv;
410	int afc;
411
412	afc = ((int)((char)(ves1x93_readreg (state, 0x0a) << 1)))/2;
413	afc = (afc * (int)(p->symbol_rate/1000/8))/16;
414
415	p->frequency = state->frequency - afc;
416
417	/*
418	 * inversion indicator is only valid
419	 * if auto inversion was used
420	 */
421	if (state->inversion == INVERSION_AUTO)
422		p->inversion = (ves1x93_readreg (state, 0x0f) & 2) ?
423				INVERSION_OFF : INVERSION_ON;
424	p->fec_inner = ves1x93_get_fec(state);
425	/*  XXX FIXME: timing offset !! */
426
427	return 0;
428}
429
430static int ves1x93_sleep(struct dvb_frontend* fe)
431{
432	struct ves1x93_state* state = fe->demodulator_priv;
433
434	return ves1x93_writereg (state, 0x00, 0x08);
435}
436
437static void ves1x93_release(struct dvb_frontend* fe)
438{
439	struct ves1x93_state* state = fe->demodulator_priv;
440	kfree(state);
441}
442
443static int ves1x93_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
444{
445	struct ves1x93_state* state = fe->demodulator_priv;
446
447	if (enable) {
448		return ves1x93_writereg(state, 0x00, 0x11);
449	} else {
450		return ves1x93_writereg(state, 0x00, 0x01);
451	}
452}
453
454static struct dvb_frontend_ops ves1x93_ops;
455
456struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
457				    struct i2c_adapter* i2c)
458{
459	struct ves1x93_state* state = NULL;
460	u8 identity;
461
462	/* allocate memory for the internal state */
463	state = kzalloc(sizeof(struct ves1x93_state), GFP_KERNEL);
464	if (state == NULL) goto error;
465
466	/* setup the state */
467	state->config = config;
468	state->i2c = i2c;
469	state->inversion = INVERSION_OFF;
470
471	/* check if the demod is there + identify it */
472	identity = ves1x93_readreg(state, 0x1e);
473	switch (identity) {
474	case 0xdc: /* VES1893A rev1 */
475		printk("ves1x93: Detected ves1893a rev1\n");
476		state->demod_type = DEMOD_VES1893;
477		state->init_1x93_tab = init_1893_tab;
478		state->init_1x93_wtab = init_1893_wtab;
479		state->tab_size = sizeof(init_1893_tab);
480		break;
481
482	case 0xdd: /* VES1893A rev2 */
483		printk("ves1x93: Detected ves1893a rev2\n");
484		state->demod_type = DEMOD_VES1893;
485		state->init_1x93_tab = init_1893_tab;
486		state->init_1x93_wtab = init_1893_wtab;
487		state->tab_size = sizeof(init_1893_tab);
488		break;
489
490	case 0xde: /* VES1993 */
491		printk("ves1x93: Detected ves1993\n");
492		state->demod_type = DEMOD_VES1993;
493		state->init_1x93_tab = init_1993_tab;
494		state->init_1x93_wtab = init_1993_wtab;
495		state->tab_size = sizeof(init_1993_tab);
496		break;
497
498	default:
499		goto error;
500	}
501
502	/* create dvb_frontend */
503	memcpy(&state->frontend.ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
504	state->frontend.demodulator_priv = state;
505	return &state->frontend;
506
507error:
508	kfree(state);
509	return NULL;
510}
511
512static struct dvb_frontend_ops ves1x93_ops = {
513	.delsys = { SYS_DVBS },
514	.info = {
515		.name			= "VLSI VES1x93 DVB-S",
516		.frequency_min		= 950000,
517		.frequency_max		= 2150000,
518		.frequency_stepsize	= 125,		 /* kHz for QPSK frontends */
519		.frequency_tolerance	= 29500,
520		.symbol_rate_min	= 1000000,
521		.symbol_rate_max	= 45000000,
522	/*	.symbol_rate_tolerance	=	???,*/
523		.caps = FE_CAN_INVERSION_AUTO |
524			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
525			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
526			FE_CAN_QPSK
527	},
528
529	.release = ves1x93_release,
530
531	.init = ves1x93_init,
532	.sleep = ves1x93_sleep,
533	.i2c_gate_ctrl = ves1x93_i2c_gate_ctrl,
534
535	.set_frontend = ves1x93_set_frontend,
536	.get_frontend = ves1x93_get_frontend,
537
538	.read_status = ves1x93_read_status,
539	.read_ber = ves1x93_read_ber,
540	.read_signal_strength = ves1x93_read_signal_strength,
541	.read_snr = ves1x93_read_snr,
542	.read_ucblocks = ves1x93_read_ucblocks,
543
544	.set_voltage = ves1x93_set_voltage,
545};
546
547module_param(debug, int, 0644);
548
549MODULE_DESCRIPTION("VLSI VES1x93 DVB-S Demodulator driver");
550MODULE_AUTHOR("Ralph Metzler");
551MODULE_LICENSE("GPL");
552
553EXPORT_SYMBOL(ves1x93_attach);
554