blob: 60e10dba36844f60a8c0584cfd29adef0f7bfb21 [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
40 fe_bandwidth_t current_bandwidth;
41
42 u16 dev_id;
43};
44
45static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070046{
Patrick Boettcherb7571f82006-08-08 15:48:10 -030047 u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff };
48 u8 rb[2];
49 struct i2c_msg msg[2] = {
50 { .addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2 },
51 { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
52 };
53
54 if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
55 dprintk("i2c read error on %d\n",reg);
56
57 return (rb[0] << 8) | rb[1];
58}
59
60static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val)
61{
62 u8 b[4] = {
63 (reg >> 8) & 0xff, reg & 0xff,
64 (val >> 8) & 0xff, val & 0xff,
65 };
66 struct i2c_msg msg = {
67 .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
68 };
69 return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
70}
71
Patrick Boettcherb7571f82006-08-08 15:48:10 -030072
73static int dib3000mc_identify(struct dib3000mc_state *state)
74{
75 u16 value;
76 if ((value = dib3000mc_read_word(state, 1025)) != 0x01b3) {
77 dprintk("-E- DiB3000MC/P: wrong Vendor ID (read=0x%x)\n",value);
78 return -EREMOTEIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 }
80
Patrick Boettcherb7571f82006-08-08 15:48:10 -030081 value = dib3000mc_read_word(state, 1026);
82 if (value != 0x3001 && value != 0x3002) {
83 dprintk("-E- DiB3000MC/P: wrong Device ID (%x)\n",value);
84 return -EREMOTEIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -030086 state->dev_id = value;
87
88 dprintk("-I- found DiB3000MC/P: %x\n",state->dev_id);
89
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 return 0;
91}
92
Patrick Boettcherb7571f82006-08-08 15:48:10 -030093static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, u8 update_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070094{
Patrick Boettcherb7571f82006-08-08 15:48:10 -030095/*
96 u32 timf_msb, timf_lsb, i;
97 int tim_sgn ;
98 LUInt comp1, comp2, comp ;
99// u32 tim_offset ;
100 comp = 27700 * BW_INDEX_TO_KHZ(bw) / 1000;
101 timf_msb = (comp >> 16) & 0x00FF;
102 timf_lsb = comp & 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
104 // Update the timing offset ;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300105 if (update_offset) {
106 if (state->timing_offset_comp_done == 0) {
107 usleep(200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 state->timing_offset_comp_done = 1;
109 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300110 tim_offset = dib3000mc_read_word(state, 416);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 if ((tim_offset & 0x2000) == 0x2000)
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300112 tim_offset |= 0xC000; // PB: This only works if tim_offset is s16 - weird
113
114 if (nfft == 0)
115 tim_offset = tim_offset << 2; // PB: Do not store the offset for different things in one variable
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 state->timing_offset += tim_offset;
117 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 tim_offset = state->timing_offset;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 if (tim_offset < 0) {
121 tim_sgn = 1;
122 tim_offset = -tim_offset;
123 } else
124 tim_sgn = 0;
125
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300126 comp1 = tim_offset * timf_lsb;
127 comp2 = tim_offset * timf_msb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 comp = ((comp1 >> 16) + comp2) >> 7;
129
130 if (tim_sgn == 0)
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300131 comp = timf_msb * (1<<16) + timf_lsb + comp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 else
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300133 comp = timf_msb * (1<<16) + timf_lsb - comp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300135 timf_msb = (comp>>16)&0xFF ;
136 timf_lsb = comp&0xFFFF;
137*/
138 u32 timf = 1384402 * (BW_INDEX_TO_KHZ(bw) / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300140 dib3000mc_write_word(state, 23, timf >> 16);
141 dib3000mc_write_word(state, 24, timf & 0xffff);
142
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 return 0;
144}
145
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300146static int dib3000mc_setup_pwm3_state(struct dib3000mc_state *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300148 if (state->cfg->pwm3_inversion) {
149 dib3000mc_write_word(state, 51, (2 << 14) | (0 << 10) | (7 << 6) | (2 << 2) | (2 << 0));
150 dib3000mc_write_word(state, 52, (0 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (2 << 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 } else {
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300152 dib3000mc_write_word(state, 51, (2 << 14) | (4 << 10) | (7 << 6) | (2 << 2) | (2 << 0));
153 dib3000mc_write_word(state, 52, (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300155
156 if (state->cfg->use_pwm3)
157 dib3000mc_write_word(state, 245, (1 << 3) | (1 << 0));
158 else
159 dib3000mc_write_word(state, 245, 0);
160
161 dib3000mc_write_word(state, 1040, 0x3);
162 return 0;
163}
164
165static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode)
166{
167 int ret = 0;
168 u16 fifo_threshold = 1792;
169 u16 outreg = 0;
170 u16 outmode = 0;
171 u16 elecout = 1;
Patrick Boettcherfb6065b2006-08-21 08:21:52 -0300172 u16 smo_reg = dib3000mc_read_word(state, 206) & 0x0010; /* keep the pid_parse bit */
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300173
174 dprintk("-I- Setting output mode for demod %p to %d\n",
175 &state->demod, mode);
176
177 switch (mode) {
178 case OUTMODE_HIGH_Z: // disable
179 elecout = 0;
180 break;
181 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
182 outmode = 0;
183 break;
184 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
185 outmode = 1;
186 break;
187 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
188 outmode = 2;
189 break;
190 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
191 elecout = 3;
192 /*ADDR @ 206 :
193 P_smo_error_discard [1;6:6] = 0
194 P_smo_rs_discard [1;5:5] = 0
195 P_smo_pid_parse [1;4:4] = 0
196 P_smo_fifo_flush [1;3:3] = 0
197 P_smo_mode [2;2:1] = 11
198 P_smo_ovf_prot [1;0:0] = 0
199 */
Patrick Boettcherfb6065b2006-08-21 08:21:52 -0300200 smo_reg |= 3 << 1;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300201 fifo_threshold = 512;
202 outmode = 5;
203 break;
204 case OUTMODE_DIVERSITY:
205 outmode = 4;
206 elecout = 1;
207 break;
208 default:
209 dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
210 outmode = 0;
211 break;
212 }
213
214 if ((state->cfg->output_mpeg2_in_188_bytes))
Patrick Boettcher559463b2006-08-19 16:13:53 -0300215 smo_reg |= (1 << 5); // P_smo_rs_discard [1;5:5] = 1
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300216
217 outreg = dib3000mc_read_word(state, 244) & 0x07FF;
218 outreg |= (outmode << 11);
219 ret |= dib3000mc_write_word(state, 244, outreg);
220 ret |= dib3000mc_write_word(state, 206, smo_reg); /*smo_ mode*/
221 ret |= dib3000mc_write_word(state, 207, fifo_threshold); /* synchronous fread */
222 ret |= dib3000mc_write_word(state, 1040, elecout); /* P_out_cfg */
223 return ret;
224}
225
226static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw)
227{
228 struct dib3000mc_state *state = demod->demodulator_priv;
229 u16 bw_cfg[6] = { 0 };
230 u16 imp_bw_cfg[3] = { 0 };
231 u16 reg;
232
233/* settings here are for 27.7MHz */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 switch (bw) {
235 case BANDWIDTH_8_MHZ:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300236 bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20;
237 imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 break;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300239
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 case BANDWIDTH_7_MHZ:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300241 bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7;
242 imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 break;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300244
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 case BANDWIDTH_6_MHZ:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300246 bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5;
247 imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 break;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300249
250 case 255 /* BANDWIDTH_5_MHZ */:
251 bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500;
252 imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072;
253 break;
254
255 default: return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300257
258 for (reg = 6; reg < 12; reg++)
259 dib3000mc_write_word(state, reg, bw_cfg[reg - 6]);
260 dib3000mc_write_word(state, 12, 0x0000);
261 dib3000mc_write_word(state, 13, 0x03e8);
262 dib3000mc_write_word(state, 14, 0x0000);
263 dib3000mc_write_word(state, 15, 0x03f2);
264 dib3000mc_write_word(state, 16, 0x0001);
265 dib3000mc_write_word(state, 17, 0xb0d0);
266 // P_sec_len
267 dib3000mc_write_word(state, 18, 0x0393);
268 dib3000mc_write_word(state, 19, 0x8700);
269
270 for (reg = 55; reg < 58; reg++)
271 dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]);
272
273 // Timing configuration
274 dib3000mc_set_timing(state, 0, bw, 0);
275
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 return 0;
277}
278
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300279static u16 impulse_noise_val[29] =
280
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300282 0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c, 0x3ffe, 0x7f3,
283 0x2d94, 0x76, 0x53d, 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3, 0x3feb, 0x7d2,
284 0x365e, 0x76, 0x48c, 0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0000, 0xd
285};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300287static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, s16 nfft)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300289 u16 i;
290 for (i = 58; i < 87; i++)
291 dib3000mc_write_word(state, i, impulse_noise_val[i-58]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300293 if (nfft == 1) {
294 dib3000mc_write_word(state, 58, 0x3b);
295 dib3000mc_write_word(state, 84, 0x00);
296 dib3000mc_write_word(state, 85, 0x8200);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 }
298
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300299 dib3000mc_write_word(state, 34, 0x1294);
300 dib3000mc_write_word(state, 35, 0x1ff8);
301 if (mode == 1)
302 dib3000mc_write_word(state, 55, dib3000mc_read_word(state, 55) | (1 << 10));
303}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300305static int dib3000mc_init(struct dvb_frontend *demod)
306{
307 struct dib3000mc_state *state = demod->demodulator_priv;
308 struct dibx000_agc_config *agc = state->cfg->agc;
309
310 // Restart Configuration
311 dib3000mc_write_word(state, 1027, 0x8000);
312 dib3000mc_write_word(state, 1027, 0x0000);
313
314 // power up the demod + mobility configuration
315 dib3000mc_write_word(state, 140, 0x0000);
316 dib3000mc_write_word(state, 1031, 0);
317
318 if (state->cfg->mobile_mode) {
319 dib3000mc_write_word(state, 139, 0x0000);
320 dib3000mc_write_word(state, 141, 0x0000);
321 dib3000mc_write_word(state, 175, 0x0002);
322 dib3000mc_write_word(state, 1032, 0x0000);
323 } else {
324 dib3000mc_write_word(state, 139, 0x0001);
325 dib3000mc_write_word(state, 141, 0x0000);
326 dib3000mc_write_word(state, 175, 0x0000);
327 dib3000mc_write_word(state, 1032, 0x012C);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300329 dib3000mc_write_word(state, 1033, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300331 // P_clk_cfg
332 dib3000mc_write_word(state, 1037, 12592);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300334 // other configurations
335
336 // P_ctrl_sfreq
337 dib3000mc_write_word(state, 33, (5 << 0));
338 dib3000mc_write_word(state, 88, (1 << 10) | (0x10 << 0));
339
340 // Phase noise control
341 // P_fft_phacor_inh, P_fft_phacor_cpe, P_fft_powrange
342 dib3000mc_write_word(state, 99, (1 << 9) | (0x20 << 0));
343
344 if (state->cfg->phase_noise_mode == 0)
345 dib3000mc_write_word(state, 111, 0x00);
346 else
347 dib3000mc_write_word(state, 111, 0x02);
348
349 // P_agc_global
350 dib3000mc_write_word(state, 50, 0x8000);
351
352 // agc setup misc
353 dib3000mc_setup_pwm3_state(state);
354
355 // P_agc_counter_lock
356 dib3000mc_write_word(state, 53, 0x87);
357 // P_agc_counter_unlock
358 dib3000mc_write_word(state, 54, 0x87);
359
360 /* agc */
361 dib3000mc_write_word(state, 36, state->cfg->max_time);
362 dib3000mc_write_word(state, 37, agc->setup);
363 dib3000mc_write_word(state, 38, state->cfg->pwm3_value);
364 dib3000mc_write_word(state, 39, state->cfg->ln_adc_level);
365
366 // set_agc_loop_Bw
367 dib3000mc_write_word(state, 40, 0x0179);
368 dib3000mc_write_word(state, 41, 0x03f0);
369
370 dib3000mc_write_word(state, 42, agc->agc1_max);
371 dib3000mc_write_word(state, 43, agc->agc1_min);
372 dib3000mc_write_word(state, 44, agc->agc2_max);
373 dib3000mc_write_word(state, 45, agc->agc2_min);
374 dib3000mc_write_word(state, 46, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
375 dib3000mc_write_word(state, 47, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
376 dib3000mc_write_word(state, 48, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
377 dib3000mc_write_word(state, 49, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
378
379// Begin: TimeOut registers
380 // P_pha3_thres
381 dib3000mc_write_word(state, 110, 3277);
382 // P_timf_alpha = 6, P_corm_alpha = 6, P_corm_thres = 0x80
383 dib3000mc_write_word(state, 26, 0x6680);
384 // lock_mask0
385 dib3000mc_write_word(state, 1, 4);
386 // lock_mask1
387 dib3000mc_write_word(state, 2, 4);
388 // lock_mask2
389 dib3000mc_write_word(state, 3, 0x1000);
390 // P_search_maxtrial=1
391 dib3000mc_write_word(state, 5, 1);
392
393 dib3000mc_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
394
395 // div_lock_mask
396 dib3000mc_write_word(state, 4, 0x814);
397
398 dib3000mc_write_word(state, 21, (1 << 9) | 0x164);
399 dib3000mc_write_word(state, 22, 0x463d);
400
401 // Spurious rm cfg
402 // P_cspu_regul, P_cspu_win_cut
403 dib3000mc_write_word(state, 120, 0x200f);
404 // P_adp_selec_monit
405 dib3000mc_write_word(state, 134, 0);
406
407 // Fec cfg
408 dib3000mc_write_word(state, 195, 0x10);
409
410 // diversity register: P_dvsy_sync_wait..
411 dib3000mc_write_word(state, 180, 0x2FF0);
412
413 // Impulse noise configuration
414 dib3000mc_set_impulse_noise(state, 0, 1);
415
416 // output mode set-up
417 dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
418
419 /* close the i2c-gate */
420 dib3000mc_write_word(state, 769, (1 << 7) );
421
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 return 0;
423}
424
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300425static int dib3000mc_sleep(struct dvb_frontend *demod)
426{
427 struct dib3000mc_state *state = demod->demodulator_priv;
428
429 dib3000mc_write_word(state, 1037, dib3000mc_read_word(state, 1037) | 0x0003);
430 dib3000mc_write_word(state, 1031, 0xFFFF);
431 dib3000mc_write_word(state, 1032, 0xFFFF);
432 dib3000mc_write_word(state, 1033, 0xFFF4); // **** Bin2
433
434 return 0;
435}
436
437static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
438{
439 u16 cfg[4] = { 0 },reg;
440 switch (qam) {
441 case 0:
442 cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0;
443 break;
444 case 1:
445 cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0;
446 break;
447 case 2:
448 cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8;
449 break;
450 }
451 for (reg = 129; reg < 133; reg++)
452 dib3000mc_write_word(state, reg, cfg[reg - 129]);
453}
454
455static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx000_ofdm_channel *chan, u16 seq)
456{
457 u16 tmp;
458
459 dib3000mc_set_timing(state, chan->nfft, chan->Bw, 0);
460
461// if (boost)
462// dib3000mc_write_word(state, 100, (11 << 6) + 6);
463// else
464 dib3000mc_write_word(state, 100, (16 << 6) + 9);
465
466 dib3000mc_write_word(state, 1027, 0x0800);
467 dib3000mc_write_word(state, 1027, 0x0000);
468
469 //Default cfg isi offset adp
470 dib3000mc_write_word(state, 26, 0x6680);
471 dib3000mc_write_word(state, 29, 0x1273);
472 dib3000mc_write_word(state, 33, 5);
473 dib3000mc_set_adp_cfg(state, 1);
474 dib3000mc_write_word(state, 133, 15564);
475
476 dib3000mc_write_word(state, 12 , 0x0);
477 dib3000mc_write_word(state, 13 , 0x3e8);
478 dib3000mc_write_word(state, 14 , 0x0);
479 dib3000mc_write_word(state, 15 , 0x3f2);
480
481 dib3000mc_write_word(state, 93,0);
482 dib3000mc_write_word(state, 94,0);
483 dib3000mc_write_word(state, 95,0);
484 dib3000mc_write_word(state, 96,0);
485 dib3000mc_write_word(state, 97,0);
486 dib3000mc_write_word(state, 98,0);
487
488 dib3000mc_set_impulse_noise(state, 0, chan->nfft);
489
490 tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha;
491 dib3000mc_write_word(state, 0, tmp);
492
493 dib3000mc_write_word(state, 5, seq);
494
495 tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp);
496 if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp))
497 tmp |= chan->vit_code_rate_hp << 1;
498 else
499 tmp |= chan->vit_code_rate_lp << 1;
500 dib3000mc_write_word(state, 181, tmp);
501
502 // diversity synchro delay
503 tmp = dib3000mc_read_word(state, 180) & 0x000f;
504 tmp |= ((chan->nfft == 0) ? 64 : 256) * ((1 << (chan->guard)) * 3 / 2) << 4; // add 50% SFN margin
505 dib3000mc_write_word(state, 180, tmp);
506
507 // restart demod
508 tmp = dib3000mc_read_word(state, 0);
509 dib3000mc_write_word(state, 0, tmp | (1 << 9));
510 dib3000mc_write_word(state, 0, tmp);
511
512 msleep(30);
513
514 dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, chan->nfft);
515}
516
517static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *chan)
518{
519 struct dib3000mc_state *state = demod->demodulator_priv;
520 u16 reg;
521// u32 val;
522 struct dibx000_ofdm_channel fchan;
523
524 INIT_OFDM_CHANNEL(&fchan);
525 fchan = *chan;
526
527
528 /* a channel for autosearch */
529 reg = 0;
530 if (chan->nfft == -1 && chan->guard == -1) reg = 7;
531 if (chan->nfft == -1 && chan->guard != -1) reg = 2;
532 if (chan->nfft != -1 && chan->guard == -1) reg = 3;
533
534 fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2;
535 fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2;
536 fchan.vit_hrch = 0; fchan.vit_select_hp = 1;
537
538 dib3000mc_set_channel_cfg(state, &fchan, reg);
539
540 reg = dib3000mc_read_word(state, 0);
541 dib3000mc_write_word(state, 0, reg | (1 << 8));
542 dib3000mc_write_word(state, 0, reg);
543
544 return 0;
545}
546
547static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod)
548{
549 struct dib3000mc_state *state = demod->demodulator_priv;
550 u16 irq_pending = dib3000mc_read_word(state, 511);
551
552 if (irq_pending & 0x1) // failed
553 return 1;
554
555 if (irq_pending & 0x2) // succeeded
556 return 2;
557
558 return 0; // still pending
559}
560
561static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
562{
563 struct dib3000mc_state *state = demod->demodulator_priv;
564
565 // ** configure demod **
566 dib3000mc_set_channel_cfg(state, ch, 0);
567
568 // activates isi
569 dib3000mc_write_word(state, 29, 0x1073);
570
571 dib3000mc_set_adp_cfg(state, (u8)ch->nqam);
572
573 if (ch->nfft == 1) {
574 dib3000mc_write_word(state, 26, 38528);
575 dib3000mc_write_word(state, 33, 8);
576 } else {
577 dib3000mc_write_word(state, 26, 30336);
578 dib3000mc_write_word(state, 33, 6);
579 }
580
581 // if (lock)
582 // dib3000mc_set_timing(state, ch->nfft, ch->Bw, 1);
583
584 return 0;
585}
586
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300587struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating)
588{
589 struct dib3000mc_state *st = demod->demodulator_priv;
590 return dibx000_get_i2c_adapter(&st->i2c_master, DIBX000_I2C_INTERFACE_TUNER, gating);
591}
592
593EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master);
594
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595static int dib3000mc_get_frontend(struct dvb_frontend* fe,
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300596 struct dvb_frontend_parameters *fep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300598 struct dib3000mc_state *state = fe->demodulator_priv;
599 u16 tps = dib3000mc_read_word(state,458);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300601 fep->inversion = INVERSION_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300603 fep->u.ofdm.bandwidth = state->current_bandwidth;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300605 switch ((tps >> 8) & 0x1) {
606 case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
607 case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 }
609
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300610 switch (tps & 0x3) {
611 case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
612 case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
613 case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
614 case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 }
616
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300617 switch ((tps >> 13) & 0x3) {
618 case 0: fep->u.ofdm.constellation = QPSK; break;
619 case 1: fep->u.ofdm.constellation = QAM_16; break;
620 case 2:
621 default: fep->u.ofdm.constellation = QAM_64; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 }
623
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300624 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
625 /* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */
626
627 fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
628 switch ((tps >> 5) & 0x7) {
629 case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
630 case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
631 case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
632 case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
633 case 7:
634 default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
635
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 }
637
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300638 switch ((tps >> 2) & 0x7) {
639 case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
640 case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
641 case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
642 case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
643 case 7:
644 default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
647 return 0;
648}
649
650static int dib3000mc_set_frontend(struct dvb_frontend* fe,
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300651 struct dvb_frontend_parameters *fep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300653 struct dib3000mc_state *state = fe->demodulator_priv;
654 struct dibx000_ofdm_channel ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300656 INIT_OFDM_CHANNEL(&ch);
657 FEP2DIB(fep,&ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300659 state->current_bandwidth = fep->u.ofdm.bandwidth;
660 dib3000mc_set_bandwidth(fe, fep->u.ofdm.bandwidth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300662 if (fe->ops.tuner_ops.set_params) {
663 fe->ops.tuner_ops.set_params(fe, fep);
664 msleep(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300666
667 if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
668 fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
669 fep->u.ofdm.constellation == QAM_AUTO ||
670 fep->u.ofdm.code_rate_HP == FEC_AUTO) {
671 int i = 100, found;
672
673 dib3000mc_autosearch_start(fe, &ch);
674 do {
675 msleep(1);
676 found = dib3000mc_autosearch_is_irq(fe);
677 } while (found == 0 && i--);
678
679 dprintk("autosearch returns: %d\n",found);
680 if (found == 0 || found == 1)
681 return 0; // no channel found
682
683 dib3000mc_get_frontend(fe, fep);
684 FEP2DIB(fep,&ch);
685 }
686
687 /* make this a config parameter */
688 dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
689
690 return dib3000mc_tune(fe, &ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691}
692
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300693static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300695 struct dib3000mc_state *state = fe->demodulator_priv;
696 u16 lock = dib3000mc_read_word(state, 509);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
698 *stat = 0;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300699
700 if (lock & 0x8000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 *stat |= FE_HAS_SIGNAL;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300702 if (lock & 0x3000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 *stat |= FE_HAS_CARRIER;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300704 if (lock & 0x0100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 *stat |= FE_HAS_VITERBI;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300706 if (lock & 0x0010)
707 *stat |= FE_HAS_SYNC;
708 if (lock & 0x0008)
709 *stat |= FE_HAS_LOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
711 return 0;
712}
713
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300714static int dib3000mc_read_ber(struct dvb_frontend *fe, u32 *ber)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300716 struct dib3000mc_state *state = fe->demodulator_priv;
717 *ber = (dib3000mc_read_word(state, 500) << 16) | dib3000mc_read_word(state, 501);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 return 0;
719}
720
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300721static int dib3000mc_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300723 struct dib3000mc_state *state = fe->demodulator_priv;
724 *unc = dib3000mc_read_word(state, 508);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 return 0;
726}
727
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300728static int dib3000mc_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300730 struct dib3000mc_state *state = fe->demodulator_priv;
731 u16 val = dib3000mc_read_word(state, 392);
732 *strength = 65535 - val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 return 0;
734}
735
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr)
737{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300738 *snr = 0x0000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 return 0;
740}
741
742static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
743{
Johannes Stezenbach776338e2005-06-23 22:02:35 -0700744 tune->min_delay_ms = 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 return 0;
746}
747
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300748static void dib3000mc_release(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300750 struct dib3000mc_state *state = fe->demodulator_priv;
751 dibx000_exit_i2c_master(&state->i2c_master);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 kfree(state);
753}
754
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300755int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300757 struct dib3000mc_state *state = fe->demodulator_priv;
758 dib3000mc_write_word(state, 212 + index, onoff ? (1 << 13) | pid : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 return 0;
760}
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300761EXPORT_SYMBOL(dib3000mc_pid_control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300763int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300765 struct dib3000mc_state *state = fe->demodulator_priv;
766 u16 tmp = dib3000mc_read_word(state, 206) & ~(1 << 4);
767 tmp |= (onoff << 4);
768 return dib3000mc_write_word(state, 206, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769}
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300770EXPORT_SYMBOL(dib3000mc_pid_parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300772void dib3000mc_set_config(struct dvb_frontend *fe, struct dib3000mc_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300774 struct dib3000mc_state *state = fe->demodulator_priv;
775 state->cfg = cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776}
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300777EXPORT_SYMBOL(dib3000mc_set_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300779int 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 -0700780{
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300781 struct dib3000mc_state st = { .i2c_adap = i2c };
782 int k;
783 u8 new_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300785 static u8 DIB3000MC_I2C_ADDRESS[] = {20,22,24,26};
786
787 for (k = no_of_demods-1; k >= 0; k--) {
788 st.cfg = &cfg[k];
789
790 /* designated i2c address */
791 new_addr = DIB3000MC_I2C_ADDRESS[k];
792 st.i2c_addr = new_addr;
793 if (dib3000mc_identify(&st) != 0) {
794 st.i2c_addr = default_addr;
795 if (dib3000mc_identify(&st) != 0) {
796 dprintk("-E- DiB3000P/MC #%d: not identified\n", k);
797 return -ENODEV;
798 }
799 }
800
801 dib3000mc_set_output_mode(&st, OUTMODE_MPEG2_PAR_CONT_CLK);
802
803 // set new i2c address and force divstr (Bit 1) to value 0 (Bit 0)
804 dib3000mc_write_word(&st, 1024, (new_addr << 3) | 0x1);
805 st.i2c_addr = new_addr;
806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300808 for (k = 0; k < no_of_demods; k++) {
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300809 st.cfg = &cfg[k];
810 st.i2c_addr = DIB3000MC_I2C_ADDRESS[k];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300812 dib3000mc_write_word(&st, 1024, st.i2c_addr << 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300814 /* turn off data output */
815 dib3000mc_set_output_mode(&st, OUTMODE_HIGH_Z);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300817 return 0;
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300818}
819EXPORT_SYMBOL(dib3000mc_i2c_enumeration);
820
821static struct dvb_frontend_ops dib3000mc_ops;
822
823struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg)
824{
825 struct dvb_frontend *demod;
826 struct dib3000mc_state *st;
827 st = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);
828 if (st == NULL)
829 return NULL;
830
831 st->cfg = cfg;
832 st->i2c_adap = i2c_adap;
Patrick Boettcher6958eff2006-09-19 12:51:40 -0300833 st->i2c_addr = i2c_addr;
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300834
835 demod = &st->demod;
836 demod->demodulator_priv = st;
837 memcpy(&st->demod.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
838
839 if (dib3000mc_identify(st) != 0)
840 goto error;
841
842 dibx000_init_i2c_master(&st->i2c_master, DIB3000MC, st->i2c_adap, st->i2c_addr);
843
844 return demod;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
846error:
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300847 kfree(st);
848 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849}
Patrick Boettchere4d6c1f2006-08-08 15:48:09 -0300850EXPORT_SYMBOL(dib3000mc_attach);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851
852static struct dvb_frontend_ops dib3000mc_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 .info = {
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300854 .name = "DiBcom 3000MC/P",
855 .type = FE_OFDM,
856 .frequency_min = 44250000,
857 .frequency_max = 867250000,
858 .frequency_stepsize = 62500,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 .caps = FE_CAN_INVERSION_AUTO |
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300860 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
861 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
862 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
863 FE_CAN_TRANSMISSION_MODE_AUTO |
864 FE_CAN_GUARD_INTERVAL_AUTO |
865 FE_CAN_RECOVER |
866 FE_CAN_HIERARCHY_AUTO,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 },
868
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300869 .release = dib3000mc_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300871 .init = dib3000mc_init,
872 .sleep = dib3000mc_sleep,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300874 .set_frontend = dib3000mc_set_frontend,
875 .get_tune_settings = dib3000mc_fe_get_tune_settings,
876 .get_frontend = dib3000mc_get_frontend,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300878 .read_status = dib3000mc_read_status,
879 .read_ber = dib3000mc_read_ber,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 .read_signal_strength = dib3000mc_read_signal_strength,
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300881 .read_snr = dib3000mc_read_snr,
882 .read_ucblocks = dib3000mc_read_unc_blocks,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883};
884
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300885MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
886MODULE_DESCRIPTION("Driver for the DiBcom 3000MC/P COFDM demodulator");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887MODULE_LICENSE("GPL");