blob: 0b051c7d5cd7a8f5882acfeea78c11713e1d3a63 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Patrick Boettcherb7571f82006-08-08 15:48:10 -03002 * Driver for DiBcom DiB3000MC/P-demodulator.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
Patrick Boettcherb7571f82006-08-08 15:48:10 -03004 * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
6 *
Patrick Boettcherb7571f82006-08-08 15:48:10 -03007 * This code is partially based on the previous dib3000mc.c .
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
Patrick Boettcherb7571f82006-08-08 15:48:10 -03009 * This program is free software; you can redistribute it and/or
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation, version 2.
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 */
Patrick Boettcherb7571f82006-08-08 15:48:10 -030013
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/kernel.h>
Patrick Boettcherb7571f82006-08-08 15:48:10 -030015#include <linux/i2c.h>
16//#include <linux/init.h>
17//#include <linux/delay.h>
18//#include <linux/string.h>
19//#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
Patrick Boettcherb7571f82006-08-08 15:48:10 -030021#include "dvb_frontend.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
Patrick Boettcherb7571f82006-08-08 15:48:10 -030023#include "dib3000mc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
Linus Torvalds1da177e2005-04-16 15:20:36 -070025static int debug;
26module_param(debug, int, 0644);
Patrick Boettcherb7571f82006-08-08 15:48:10 -030027MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Patrick Boettcherb7571f82006-08-08 15:48:10 -030029#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); } } while (0)
30
31struct dib3000mc_state {
32 struct dvb_frontend demod;
33 struct dib3000mc_config *cfg;
34
35 u8 i2c_addr;
36 struct i2c_adapter *i2c_adap;
37
38 struct dibx000_i2c_master i2c_master;
39
Patrick Boettcher01b4bf32006-09-19 12:51:53 -030040 u32 timf;
41
Patrick Boettcherb7571f82006-08-08 15:48:10 -030042 fe_bandwidth_t current_bandwidth;
43
44 u16 dev_id;
45};
46
47static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070048{
Patrick Boettcherb7571f82006-08-08 15:48:10 -030049 u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff };
50 u8 rb[2];
51 struct i2c_msg msg[2] = {
52 { .addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2 },
53 { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
54 };
55
56 if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
57 dprintk("i2c read error on %d\n",reg);
58
59 return (rb[0] << 8) | rb[1];
60}
61
62static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val)
63{
64 u8 b[4] = {
65 (reg >> 8) & 0xff, reg & 0xff,
66 (val >> 8) & 0xff, val & 0xff,
67 };
68 struct i2c_msg msg = {
69 .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
70 };
71 return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
72}
73
Patrick Boettcherb7571f82006-08-08 15:48:10 -030074
75static int dib3000mc_identify(struct dib3000mc_state *state)
76{
77 u16 value;
78 if ((value = dib3000mc_read_word(state, 1025)) != 0x01b3) {
79 dprintk("-E- DiB3000MC/P: wrong Vendor ID (read=0x%x)\n",value);
80 return -EREMOTEIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 }
82
Patrick Boettcherb7571f82006-08-08 15:48:10 -030083 value = dib3000mc_read_word(state, 1026);
84 if (value != 0x3001 && value != 0x3002) {
85 dprintk("-E- DiB3000MC/P: wrong Device ID (%x)\n",value);
86 return -EREMOTEIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -030088 state->dev_id = value;
89
90 dprintk("-I- found DiB3000MC/P: %x\n",state->dev_id);
91
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 return 0;
93}
94
Patrick Boettcherb7571f82006-08-08 15:48:10 -030095static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, u8 update_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096{
Patrick Boettcher01b4bf32006-09-19 12:51:53 -030097 u32 timf;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
Patrick Boettcher01b4bf32006-09-19 12:51:53 -030099 if (state->timf == 0) {
100 timf = 1384402; // default value for 8MHz
101 if (update_offset)
102 msleep(200); // first time we do an update
103 } else
104 timf = state->timf;
105
106 timf *= (BW_INDEX_TO_KHZ(bw) / 1000);
107
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300108 if (update_offset) {
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300109 s16 tim_offs = dib3000mc_read_word(state, 416);
110
111 if (tim_offs & 0x2000)
112 tim_offs -= 0x4000;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300113
114 if (nfft == 0)
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300115 tim_offs *= 4;
116
117 timf += tim_offs;
118 state->timf = timf / (BW_INDEX_TO_KHZ(bw) / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300120
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300121 dprintk("timf: %d\n", timf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300123 dib3000mc_write_word(state, 23, timf >> 16);
124 dib3000mc_write_word(state, 24, timf & 0xffff);
125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 return 0;
127}
128
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300129static int dib3000mc_setup_pwm_state(struct dib3000mc_state *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130{
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300131 u16 reg_51, reg_52 = state->cfg->agc->setup & 0xfefb;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300132 if (state->cfg->pwm3_inversion) {
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300133 reg_51 = (2 << 14) | (0 << 10) | (7 << 6) | (2 << 2) | (2 << 0);
134 reg_52 |= (1 << 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 } else {
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300136 reg_51 = (2 << 14) | (4 << 10) | (7 << 6) | (2 << 2) | (2 << 0);
137 reg_52 |= (1 << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 }
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300139 dib3000mc_write_word(state, 51, reg_51);
140 dib3000mc_write_word(state, 52, reg_52);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300141
142 if (state->cfg->use_pwm3)
143 dib3000mc_write_word(state, 245, (1 << 3) | (1 << 0));
144 else
145 dib3000mc_write_word(state, 245, 0);
146
147 dib3000mc_write_word(state, 1040, 0x3);
148 return 0;
149}
150
151static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode)
152{
153 int ret = 0;
154 u16 fifo_threshold = 1792;
155 u16 outreg = 0;
156 u16 outmode = 0;
157 u16 elecout = 1;
Patrick Boettcherfb6065b2006-08-21 08:21:52 -0300158 u16 smo_reg = dib3000mc_read_word(state, 206) & 0x0010; /* keep the pid_parse bit */
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300159
160 dprintk("-I- Setting output mode for demod %p to %d\n",
161 &state->demod, mode);
162
163 switch (mode) {
164 case OUTMODE_HIGH_Z: // disable
165 elecout = 0;
166 break;
167 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
168 outmode = 0;
169 break;
170 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
171 outmode = 1;
172 break;
173 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
174 outmode = 2;
175 break;
176 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
177 elecout = 3;
178 /*ADDR @ 206 :
179 P_smo_error_discard [1;6:6] = 0
180 P_smo_rs_discard [1;5:5] = 0
181 P_smo_pid_parse [1;4:4] = 0
182 P_smo_fifo_flush [1;3:3] = 0
183 P_smo_mode [2;2:1] = 11
184 P_smo_ovf_prot [1;0:0] = 0
185 */
Patrick Boettcherfb6065b2006-08-21 08:21:52 -0300186 smo_reg |= 3 << 1;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300187 fifo_threshold = 512;
188 outmode = 5;
189 break;
190 case OUTMODE_DIVERSITY:
191 outmode = 4;
192 elecout = 1;
193 break;
194 default:
195 dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
196 outmode = 0;
197 break;
198 }
199
200 if ((state->cfg->output_mpeg2_in_188_bytes))
Patrick Boettcher559463b2006-08-19 16:13:53 -0300201 smo_reg |= (1 << 5); // P_smo_rs_discard [1;5:5] = 1
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300202
203 outreg = dib3000mc_read_word(state, 244) & 0x07FF;
204 outreg |= (outmode << 11);
205 ret |= dib3000mc_write_word(state, 244, outreg);
206 ret |= dib3000mc_write_word(state, 206, smo_reg); /*smo_ mode*/
207 ret |= dib3000mc_write_word(state, 207, fifo_threshold); /* synchronous fread */
208 ret |= dib3000mc_write_word(state, 1040, elecout); /* P_out_cfg */
209 return ret;
210}
211
212static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw)
213{
214 struct dib3000mc_state *state = demod->demodulator_priv;
215 u16 bw_cfg[6] = { 0 };
216 u16 imp_bw_cfg[3] = { 0 };
217 u16 reg;
218
219/* settings here are for 27.7MHz */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 switch (bw) {
221 case BANDWIDTH_8_MHZ:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300222 bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20;
223 imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 break;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300225
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 case BANDWIDTH_7_MHZ:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300227 bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7;
228 imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 break;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300230
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 case BANDWIDTH_6_MHZ:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300232 bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5;
233 imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 break;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300235
236 case 255 /* BANDWIDTH_5_MHZ */:
237 bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500;
238 imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072;
239 break;
240
241 default: return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300243
244 for (reg = 6; reg < 12; reg++)
245 dib3000mc_write_word(state, reg, bw_cfg[reg - 6]);
246 dib3000mc_write_word(state, 12, 0x0000);
247 dib3000mc_write_word(state, 13, 0x03e8);
248 dib3000mc_write_word(state, 14, 0x0000);
249 dib3000mc_write_word(state, 15, 0x03f2);
250 dib3000mc_write_word(state, 16, 0x0001);
251 dib3000mc_write_word(state, 17, 0xb0d0);
252 // P_sec_len
253 dib3000mc_write_word(state, 18, 0x0393);
254 dib3000mc_write_word(state, 19, 0x8700);
255
256 for (reg = 55; reg < 58; reg++)
257 dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]);
258
259 // Timing configuration
260 dib3000mc_set_timing(state, 0, bw, 0);
261
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 return 0;
263}
264
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300265static u16 impulse_noise_val[29] =
266
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300268 0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c, 0x3ffe, 0x7f3,
269 0x2d94, 0x76, 0x53d, 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3, 0x3feb, 0x7d2,
270 0x365e, 0x76, 0x48c, 0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0000, 0xd
271};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300273static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, s16 nfft)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300275 u16 i;
276 for (i = 58; i < 87; i++)
277 dib3000mc_write_word(state, i, impulse_noise_val[i-58]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300279 if (nfft == 1) {
280 dib3000mc_write_word(state, 58, 0x3b);
281 dib3000mc_write_word(state, 84, 0x00);
282 dib3000mc_write_word(state, 85, 0x8200);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 }
284
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300285 dib3000mc_write_word(state, 34, 0x1294);
286 dib3000mc_write_word(state, 35, 0x1ff8);
287 if (mode == 1)
288 dib3000mc_write_word(state, 55, dib3000mc_read_word(state, 55) | (1 << 10));
289}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300291static int dib3000mc_init(struct dvb_frontend *demod)
292{
293 struct dib3000mc_state *state = demod->demodulator_priv;
294 struct dibx000_agc_config *agc = state->cfg->agc;
295
296 // Restart Configuration
297 dib3000mc_write_word(state, 1027, 0x8000);
298 dib3000mc_write_word(state, 1027, 0x0000);
299
300 // power up the demod + mobility configuration
301 dib3000mc_write_word(state, 140, 0x0000);
302 dib3000mc_write_word(state, 1031, 0);
303
304 if (state->cfg->mobile_mode) {
305 dib3000mc_write_word(state, 139, 0x0000);
306 dib3000mc_write_word(state, 141, 0x0000);
307 dib3000mc_write_word(state, 175, 0x0002);
308 dib3000mc_write_word(state, 1032, 0x0000);
309 } else {
310 dib3000mc_write_word(state, 139, 0x0001);
311 dib3000mc_write_word(state, 141, 0x0000);
312 dib3000mc_write_word(state, 175, 0x0000);
313 dib3000mc_write_word(state, 1032, 0x012C);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300315 dib3000mc_write_word(state, 1033, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300317 // P_clk_cfg
318 dib3000mc_write_word(state, 1037, 12592);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300320 // other configurations
321
322 // P_ctrl_sfreq
323 dib3000mc_write_word(state, 33, (5 << 0));
324 dib3000mc_write_word(state, 88, (1 << 10) | (0x10 << 0));
325
326 // Phase noise control
327 // P_fft_phacor_inh, P_fft_phacor_cpe, P_fft_powrange
328 dib3000mc_write_word(state, 99, (1 << 9) | (0x20 << 0));
329
330 if (state->cfg->phase_noise_mode == 0)
331 dib3000mc_write_word(state, 111, 0x00);
332 else
333 dib3000mc_write_word(state, 111, 0x02);
334
335 // P_agc_global
336 dib3000mc_write_word(state, 50, 0x8000);
337
338 // agc setup misc
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300339 dib3000mc_setup_pwm_state(state);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300340
341 // P_agc_counter_lock
342 dib3000mc_write_word(state, 53, 0x87);
343 // P_agc_counter_unlock
344 dib3000mc_write_word(state, 54, 0x87);
345
346 /* agc */
347 dib3000mc_write_word(state, 36, state->cfg->max_time);
348 dib3000mc_write_word(state, 37, agc->setup);
349 dib3000mc_write_word(state, 38, state->cfg->pwm3_value);
350 dib3000mc_write_word(state, 39, state->cfg->ln_adc_level);
351
352 // set_agc_loop_Bw
353 dib3000mc_write_word(state, 40, 0x0179);
354 dib3000mc_write_word(state, 41, 0x03f0);
355
356 dib3000mc_write_word(state, 42, agc->agc1_max);
357 dib3000mc_write_word(state, 43, agc->agc1_min);
358 dib3000mc_write_word(state, 44, agc->agc2_max);
359 dib3000mc_write_word(state, 45, agc->agc2_min);
360 dib3000mc_write_word(state, 46, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
361 dib3000mc_write_word(state, 47, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
362 dib3000mc_write_word(state, 48, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
363 dib3000mc_write_word(state, 49, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
364
365// Begin: TimeOut registers
366 // P_pha3_thres
367 dib3000mc_write_word(state, 110, 3277);
368 // P_timf_alpha = 6, P_corm_alpha = 6, P_corm_thres = 0x80
369 dib3000mc_write_word(state, 26, 0x6680);
370 // lock_mask0
371 dib3000mc_write_word(state, 1, 4);
372 // lock_mask1
373 dib3000mc_write_word(state, 2, 4);
374 // lock_mask2
375 dib3000mc_write_word(state, 3, 0x1000);
376 // P_search_maxtrial=1
377 dib3000mc_write_word(state, 5, 1);
378
379 dib3000mc_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
380
381 // div_lock_mask
382 dib3000mc_write_word(state, 4, 0x814);
383
384 dib3000mc_write_word(state, 21, (1 << 9) | 0x164);
385 dib3000mc_write_word(state, 22, 0x463d);
386
387 // Spurious rm cfg
388 // P_cspu_regul, P_cspu_win_cut
389 dib3000mc_write_word(state, 120, 0x200f);
390 // P_adp_selec_monit
391 dib3000mc_write_word(state, 134, 0);
392
393 // Fec cfg
394 dib3000mc_write_word(state, 195, 0x10);
395
396 // diversity register: P_dvsy_sync_wait..
397 dib3000mc_write_word(state, 180, 0x2FF0);
398
399 // Impulse noise configuration
400 dib3000mc_set_impulse_noise(state, 0, 1);
401
402 // output mode set-up
403 dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
404
405 /* close the i2c-gate */
406 dib3000mc_write_word(state, 769, (1 << 7) );
407
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 return 0;
409}
410
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300411static int dib3000mc_sleep(struct dvb_frontend *demod)
412{
413 struct dib3000mc_state *state = demod->demodulator_priv;
414
415 dib3000mc_write_word(state, 1037, dib3000mc_read_word(state, 1037) | 0x0003);
416 dib3000mc_write_word(state, 1031, 0xFFFF);
417 dib3000mc_write_word(state, 1032, 0xFFFF);
418 dib3000mc_write_word(state, 1033, 0xFFF4); // **** Bin2
419
420 return 0;
421}
422
423static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
424{
425 u16 cfg[4] = { 0 },reg;
426 switch (qam) {
427 case 0:
428 cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0;
429 break;
430 case 1:
431 cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0;
432 break;
433 case 2:
434 cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8;
435 break;
436 }
437 for (reg = 129; reg < 133; reg++)
438 dib3000mc_write_word(state, reg, cfg[reg - 129]);
439}
440
441static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx000_ofdm_channel *chan, u16 seq)
442{
443 u16 tmp;
444
445 dib3000mc_set_timing(state, chan->nfft, chan->Bw, 0);
446
447// if (boost)
448// dib3000mc_write_word(state, 100, (11 << 6) + 6);
449// else
450 dib3000mc_write_word(state, 100, (16 << 6) + 9);
451
452 dib3000mc_write_word(state, 1027, 0x0800);
453 dib3000mc_write_word(state, 1027, 0x0000);
454
455 //Default cfg isi offset adp
456 dib3000mc_write_word(state, 26, 0x6680);
457 dib3000mc_write_word(state, 29, 0x1273);
458 dib3000mc_write_word(state, 33, 5);
459 dib3000mc_set_adp_cfg(state, 1);
460 dib3000mc_write_word(state, 133, 15564);
461
462 dib3000mc_write_word(state, 12 , 0x0);
463 dib3000mc_write_word(state, 13 , 0x3e8);
464 dib3000mc_write_word(state, 14 , 0x0);
465 dib3000mc_write_word(state, 15 , 0x3f2);
466
467 dib3000mc_write_word(state, 93,0);
468 dib3000mc_write_word(state, 94,0);
469 dib3000mc_write_word(state, 95,0);
470 dib3000mc_write_word(state, 96,0);
471 dib3000mc_write_word(state, 97,0);
472 dib3000mc_write_word(state, 98,0);
473
474 dib3000mc_set_impulse_noise(state, 0, chan->nfft);
475
476 tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha;
477 dib3000mc_write_word(state, 0, tmp);
478
479 dib3000mc_write_word(state, 5, seq);
480
481 tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp);
482 if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp))
483 tmp |= chan->vit_code_rate_hp << 1;
484 else
485 tmp |= chan->vit_code_rate_lp << 1;
486 dib3000mc_write_word(state, 181, tmp);
487
488 // diversity synchro delay
489 tmp = dib3000mc_read_word(state, 180) & 0x000f;
490 tmp |= ((chan->nfft == 0) ? 64 : 256) * ((1 << (chan->guard)) * 3 / 2) << 4; // add 50% SFN margin
491 dib3000mc_write_word(state, 180, tmp);
492
493 // restart demod
494 tmp = dib3000mc_read_word(state, 0);
495 dib3000mc_write_word(state, 0, tmp | (1 << 9));
496 dib3000mc_write_word(state, 0, tmp);
497
498 msleep(30);
499
500 dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, chan->nfft);
501}
502
503static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *chan)
504{
505 struct dib3000mc_state *state = demod->demodulator_priv;
506 u16 reg;
507// u32 val;
508 struct dibx000_ofdm_channel fchan;
509
510 INIT_OFDM_CHANNEL(&fchan);
511 fchan = *chan;
512
513
514 /* a channel for autosearch */
515 reg = 0;
516 if (chan->nfft == -1 && chan->guard == -1) reg = 7;
517 if (chan->nfft == -1 && chan->guard != -1) reg = 2;
518 if (chan->nfft != -1 && chan->guard == -1) reg = 3;
519
520 fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2;
521 fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2;
522 fchan.vit_hrch = 0; fchan.vit_select_hp = 1;
523
524 dib3000mc_set_channel_cfg(state, &fchan, reg);
525
526 reg = dib3000mc_read_word(state, 0);
527 dib3000mc_write_word(state, 0, reg | (1 << 8));
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300528 dib3000mc_read_word(state, 511);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300529 dib3000mc_write_word(state, 0, reg);
530
531 return 0;
532}
533
534static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod)
535{
536 struct dib3000mc_state *state = demod->demodulator_priv;
537 u16 irq_pending = dib3000mc_read_word(state, 511);
538
539 if (irq_pending & 0x1) // failed
540 return 1;
541
542 if (irq_pending & 0x2) // succeeded
543 return 2;
544
545 return 0; // still pending
546}
547
548static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
549{
550 struct dib3000mc_state *state = demod->demodulator_priv;
551
552 // ** configure demod **
553 dib3000mc_set_channel_cfg(state, ch, 0);
554
555 // activates isi
556 dib3000mc_write_word(state, 29, 0x1073);
557
558 dib3000mc_set_adp_cfg(state, (u8)ch->nqam);
559
560 if (ch->nfft == 1) {
561 dib3000mc_write_word(state, 26, 38528);
562 dib3000mc_write_word(state, 33, 8);
563 } else {
564 dib3000mc_write_word(state, 26, 30336);
565 dib3000mc_write_word(state, 33, 6);
566 }
567
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300568 if (dib3000mc_read_word(state, 509) & 0x80)
569 dib3000mc_set_timing(state, ch->nfft, ch->Bw, 1);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300570
571 return 0;
572}
573
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300574struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating)
575{
576 struct dib3000mc_state *st = demod->demodulator_priv;
577 return dibx000_get_i2c_adapter(&st->i2c_master, DIBX000_I2C_INTERFACE_TUNER, gating);
578}
579
580EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master);
581
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582static int dib3000mc_get_frontend(struct dvb_frontend* fe,
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300583 struct dvb_frontend_parameters *fep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300585 struct dib3000mc_state *state = fe->demodulator_priv;
586 u16 tps = dib3000mc_read_word(state,458);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300588 fep->inversion = INVERSION_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300590 fep->u.ofdm.bandwidth = state->current_bandwidth;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300592 switch ((tps >> 8) & 0x1) {
593 case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
594 case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 }
596
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300597 switch (tps & 0x3) {
598 case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
599 case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
600 case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
601 case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 }
603
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300604 switch ((tps >> 13) & 0x3) {
605 case 0: fep->u.ofdm.constellation = QPSK; break;
606 case 1: fep->u.ofdm.constellation = QAM_16; break;
607 case 2:
608 default: fep->u.ofdm.constellation = QAM_64; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 }
610
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300611 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
612 /* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */
613
614 fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
615 switch ((tps >> 5) & 0x7) {
616 case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
617 case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
618 case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
619 case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
620 case 7:
621 default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
622
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 }
624
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300625 switch ((tps >> 2) & 0x7) {
626 case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
627 case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
628 case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
629 case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
630 case 7:
631 default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
634 return 0;
635}
636
637static int dib3000mc_set_frontend(struct dvb_frontend* fe,
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300638 struct dvb_frontend_parameters *fep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300640 struct dib3000mc_state *state = fe->demodulator_priv;
641 struct dibx000_ofdm_channel ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300643 INIT_OFDM_CHANNEL(&ch);
644 FEP2DIB(fep,&ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300646 state->current_bandwidth = fep->u.ofdm.bandwidth;
647 dib3000mc_set_bandwidth(fe, fep->u.ofdm.bandwidth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300649 if (fe->ops.tuner_ops.set_params) {
650 fe->ops.tuner_ops.set_params(fe, fep);
651 msleep(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300653
654 if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
655 fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
656 fep->u.ofdm.constellation == QAM_AUTO ||
657 fep->u.ofdm.code_rate_HP == FEC_AUTO) {
658 int i = 100, found;
659
660 dib3000mc_autosearch_start(fe, &ch);
661 do {
662 msleep(1);
663 found = dib3000mc_autosearch_is_irq(fe);
664 } while (found == 0 && i--);
665
666 dprintk("autosearch returns: %d\n",found);
667 if (found == 0 || found == 1)
668 return 0; // no channel found
669
670 dib3000mc_get_frontend(fe, fep);
671 FEP2DIB(fep,&ch);
672 }
673
674 /* make this a config parameter */
675 dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
676
677 return dib3000mc_tune(fe, &ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678}
679
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300680static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300682 struct dib3000mc_state *state = fe->demodulator_priv;
683 u16 lock = dib3000mc_read_word(state, 509);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
685 *stat = 0;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300686
687 if (lock & 0x8000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 *stat |= FE_HAS_SIGNAL;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300689 if (lock & 0x3000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 *stat |= FE_HAS_CARRIER;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300691 if (lock & 0x0100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 *stat |= FE_HAS_VITERBI;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300693 if (lock & 0x0010)
694 *stat |= FE_HAS_SYNC;
695 if (lock & 0x0008)
696 *stat |= FE_HAS_LOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
698 return 0;
699}
700
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300701static int dib3000mc_read_ber(struct dvb_frontend *fe, u32 *ber)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300703 struct dib3000mc_state *state = fe->demodulator_priv;
704 *ber = (dib3000mc_read_word(state, 500) << 16) | dib3000mc_read_word(state, 501);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 return 0;
706}
707
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300708static int dib3000mc_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300710 struct dib3000mc_state *state = fe->demodulator_priv;
711 *unc = dib3000mc_read_word(state, 508);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 return 0;
713}
714
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300715static int dib3000mc_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300717 struct dib3000mc_state *state = fe->demodulator_priv;
718 u16 val = dib3000mc_read_word(state, 392);
719 *strength = 65535 - val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 return 0;
721}
722
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr)
724{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300725 *snr = 0x0000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 return 0;
727}
728
729static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
730{
Johannes Stezenbach776338e2005-06-23 22:02:35 -0700731 tune->min_delay_ms = 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 return 0;
733}
734
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300735static void dib3000mc_release(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300737 struct dib3000mc_state *state = fe->demodulator_priv;
738 dibx000_exit_i2c_master(&state->i2c_master);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 kfree(state);
740}
741
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300742int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300744 struct dib3000mc_state *state = fe->demodulator_priv;
745 dib3000mc_write_word(state, 212 + index, onoff ? (1 << 13) | pid : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 return 0;
747}
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300748EXPORT_SYMBOL(dib3000mc_pid_control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300750int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300752 struct dib3000mc_state *state = fe->demodulator_priv;
753 u16 tmp = dib3000mc_read_word(state, 206) & ~(1 << 4);
754 tmp |= (onoff << 4);
755 return dib3000mc_write_word(state, 206, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756}
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300757EXPORT_SYMBOL(dib3000mc_pid_parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300759void dib3000mc_set_config(struct dvb_frontend *fe, struct dib3000mc_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300761 struct dib3000mc_state *state = fe->demodulator_priv;
762 state->cfg = cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763}
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300764EXPORT_SYMBOL(dib3000mc_set_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300766int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib3000mc_config cfg[])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767{
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300768 struct dib3000mc_state st = { .i2c_adap = i2c };
769 int k;
770 u8 new_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300772 static u8 DIB3000MC_I2C_ADDRESS[] = {20,22,24,26};
773
774 for (k = no_of_demods-1; k >= 0; k--) {
775 st.cfg = &cfg[k];
776
777 /* designated i2c address */
778 new_addr = DIB3000MC_I2C_ADDRESS[k];
779 st.i2c_addr = new_addr;
780 if (dib3000mc_identify(&st) != 0) {
781 st.i2c_addr = default_addr;
782 if (dib3000mc_identify(&st) != 0) {
783 dprintk("-E- DiB3000P/MC #%d: not identified\n", k);
784 return -ENODEV;
785 }
786 }
787
788 dib3000mc_set_output_mode(&st, OUTMODE_MPEG2_PAR_CONT_CLK);
789
790 // set new i2c address and force divstr (Bit 1) to value 0 (Bit 0)
791 dib3000mc_write_word(&st, 1024, (new_addr << 3) | 0x1);
792 st.i2c_addr = new_addr;
793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300795 for (k = 0; k < no_of_demods; k++) {
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300796 st.cfg = &cfg[k];
797 st.i2c_addr = DIB3000MC_I2C_ADDRESS[k];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300799 dib3000mc_write_word(&st, 1024, st.i2c_addr << 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300801 /* turn off data output */
802 dib3000mc_set_output_mode(&st, OUTMODE_HIGH_Z);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300804 return 0;
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300805}
806EXPORT_SYMBOL(dib3000mc_i2c_enumeration);
807
808static struct dvb_frontend_ops dib3000mc_ops;
809
810struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg)
811{
812 struct dvb_frontend *demod;
813 struct dib3000mc_state *st;
814 st = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);
815 if (st == NULL)
816 return NULL;
817
818 st->cfg = cfg;
819 st->i2c_adap = i2c_adap;
Patrick Boettcher6958eff2006-09-19 12:51:40 -0300820 st->i2c_addr = i2c_addr;
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300821
822 demod = &st->demod;
823 demod->demodulator_priv = st;
824 memcpy(&st->demod.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
825
826 if (dib3000mc_identify(st) != 0)
827 goto error;
828
829 dibx000_init_i2c_master(&st->i2c_master, DIB3000MC, st->i2c_adap, st->i2c_addr);
830
831 return demod;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
833error:
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300834 kfree(st);
835 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836}
Patrick Boettchere4d6c1f2006-08-08 15:48:09 -0300837EXPORT_SYMBOL(dib3000mc_attach);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
839static struct dvb_frontend_ops dib3000mc_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 .info = {
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300841 .name = "DiBcom 3000MC/P",
842 .type = FE_OFDM,
843 .frequency_min = 44250000,
844 .frequency_max = 867250000,
845 .frequency_stepsize = 62500,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 .caps = FE_CAN_INVERSION_AUTO |
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300847 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
848 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
849 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
850 FE_CAN_TRANSMISSION_MODE_AUTO |
851 FE_CAN_GUARD_INTERVAL_AUTO |
852 FE_CAN_RECOVER |
853 FE_CAN_HIERARCHY_AUTO,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 },
855
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300856 .release = dib3000mc_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300858 .init = dib3000mc_init,
859 .sleep = dib3000mc_sleep,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300861 .set_frontend = dib3000mc_set_frontend,
862 .get_tune_settings = dib3000mc_fe_get_tune_settings,
863 .get_frontend = dib3000mc_get_frontend,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300865 .read_status = dib3000mc_read_status,
866 .read_ber = dib3000mc_read_ber,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 .read_signal_strength = dib3000mc_read_signal_strength,
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300868 .read_snr = dib3000mc_read_snr,
869 .read_ucblocks = dib3000mc_read_unc_blocks,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870};
871
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300872MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
873MODULE_DESCRIPTION("Driver for the DiBcom 3000MC/P COFDM demodulator");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874MODULE_LICENSE("GPL");