blob: cc41c6bcdaf6e5089d0bf14f7c18a6a01b2c0a68 [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
72static void dump_fep(struct dibx000_ofdm_channel *cd)
73{
74 printk(KERN_DEBUG "DiB3000MC: ");
75 switch (cd->nfft) {
76 case 1: printk("8K "); break;
77 case 2: printk("4K "); break;
78 case 0: printk("2K "); break;
79 default: printk("FFT_UNK "); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 }
81
Patrick Boettcherb7571f82006-08-08 15:48:10 -030082 printk("1/%i ", 32 / (1 << cd->guard));
83 switch (cd->nqam) {
84 case 0: printk("QPSK "); break;
85 case 1: printk("16QAM "); break;
86 case 2: printk("64QAM "); break;
87 default: printk("QAM_UNK "); break;
88 }
89 printk("ALPHA %i ", cd->vit_alpha);
90 printk("Code Rate HP %i/%i ", cd->vit_code_rate_hp, cd->vit_code_rate_hp + 1);
91 printk("Code Rate LP %i/%i ", cd->vit_code_rate_lp, cd->vit_code_rate_lp + 1);
92 printk("HRCH %i\n", cd->vit_hrch);
93}
94
95
96static int dib3000mc_identify(struct dib3000mc_state *state)
97{
98 u16 value;
99 if ((value = dib3000mc_read_word(state, 1025)) != 0x01b3) {
100 dprintk("-E- DiB3000MC/P: wrong Vendor ID (read=0x%x)\n",value);
101 return -EREMOTEIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 }
103
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300104 value = dib3000mc_read_word(state, 1026);
105 if (value != 0x3001 && value != 0x3002) {
106 dprintk("-E- DiB3000MC/P: wrong Device ID (%x)\n",value);
107 return -EREMOTEIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300109 state->dev_id = value;
110
111 dprintk("-I- found DiB3000MC/P: %x\n",state->dev_id);
112
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 return 0;
114}
115
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300116static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, u8 update_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300118/*
119 u32 timf_msb, timf_lsb, i;
120 int tim_sgn ;
121 LUInt comp1, comp2, comp ;
122// u32 tim_offset ;
123 comp = 27700 * BW_INDEX_TO_KHZ(bw) / 1000;
124 timf_msb = (comp >> 16) & 0x00FF;
125 timf_lsb = comp & 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127 // Update the timing offset ;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300128 if (update_offset) {
129 if (state->timing_offset_comp_done == 0) {
130 usleep(200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 state->timing_offset_comp_done = 1;
132 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300133 tim_offset = dib3000mc_read_word(state, 416);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 if ((tim_offset & 0x2000) == 0x2000)
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300135 tim_offset |= 0xC000; // PB: This only works if tim_offset is s16 - weird
136
137 if (nfft == 0)
138 tim_offset = tim_offset << 2; // PB: Do not store the offset for different things in one variable
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 state->timing_offset += tim_offset;
140 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 tim_offset = state->timing_offset;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300142
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 if (tim_offset < 0) {
144 tim_sgn = 1;
145 tim_offset = -tim_offset;
146 } else
147 tim_sgn = 0;
148
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300149 comp1 = tim_offset * timf_lsb;
150 comp2 = tim_offset * timf_msb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 comp = ((comp1 >> 16) + comp2) >> 7;
152
153 if (tim_sgn == 0)
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300154 comp = timf_msb * (1<<16) + timf_lsb + comp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 else
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300156 comp = timf_msb * (1<<16) + timf_lsb - comp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300158 timf_msb = (comp>>16)&0xFF ;
159 timf_lsb = comp&0xFFFF;
160*/
161 u32 timf = 1384402 * (BW_INDEX_TO_KHZ(bw) / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300163 dib3000mc_write_word(state, 23, timf >> 16);
164 dib3000mc_write_word(state, 24, timf & 0xffff);
165
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 return 0;
167}
168
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300169static int dib3000mc_setup_pwm3_state(struct dib3000mc_state *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300171 if (state->cfg->pwm3_inversion) {
172 dib3000mc_write_word(state, 51, (2 << 14) | (0 << 10) | (7 << 6) | (2 << 2) | (2 << 0));
173 dib3000mc_write_word(state, 52, (0 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (2 << 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 } else {
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300175 dib3000mc_write_word(state, 51, (2 << 14) | (4 << 10) | (7 << 6) | (2 << 2) | (2 << 0));
176 dib3000mc_write_word(state, 52, (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300178
179 if (state->cfg->use_pwm3)
180 dib3000mc_write_word(state, 245, (1 << 3) | (1 << 0));
181 else
182 dib3000mc_write_word(state, 245, 0);
183
184 dib3000mc_write_word(state, 1040, 0x3);
185 return 0;
186}
187
188static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode)
189{
190 int ret = 0;
191 u16 fifo_threshold = 1792;
192 u16 outreg = 0;
193 u16 outmode = 0;
194 u16 elecout = 1;
195 u16 smo_reg = (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (1 << 1) | 0 ; //smo_mode = 1
196
197 dprintk("-I- Setting output mode for demod %p to %d\n",
198 &state->demod, mode);
199
200 switch (mode) {
201 case OUTMODE_HIGH_Z: // disable
202 elecout = 0;
203 break;
204 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
205 outmode = 0;
206 break;
207 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
208 outmode = 1;
209 break;
210 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
211 outmode = 2;
212 break;
213 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
214 elecout = 3;
215 /*ADDR @ 206 :
216 P_smo_error_discard [1;6:6] = 0
217 P_smo_rs_discard [1;5:5] = 0
218 P_smo_pid_parse [1;4:4] = 0
219 P_smo_fifo_flush [1;3:3] = 0
220 P_smo_mode [2;2:1] = 11
221 P_smo_ovf_prot [1;0:0] = 0
222 */
223 smo_reg = (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) |(3 << 1) | 0;
224 fifo_threshold = 512;
225 outmode = 5;
226 break;
227 case OUTMODE_DIVERSITY:
228 outmode = 4;
229 elecout = 1;
230 break;
231 default:
232 dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
233 outmode = 0;
234 break;
235 }
236
237 if ((state->cfg->output_mpeg2_in_188_bytes))
238 smo_reg |= (1 << 5) ; //P_smo_rs_discard [1;5:5] = 1
239
240 outreg = dib3000mc_read_word(state, 244) & 0x07FF;
241 outreg |= (outmode << 11);
242 ret |= dib3000mc_write_word(state, 244, outreg);
243 ret |= dib3000mc_write_word(state, 206, smo_reg); /*smo_ mode*/
244 ret |= dib3000mc_write_word(state, 207, fifo_threshold); /* synchronous fread */
245 ret |= dib3000mc_write_word(state, 1040, elecout); /* P_out_cfg */
246 return ret;
247}
248
249static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw)
250{
251 struct dib3000mc_state *state = demod->demodulator_priv;
252 u16 bw_cfg[6] = { 0 };
253 u16 imp_bw_cfg[3] = { 0 };
254 u16 reg;
255
256/* settings here are for 27.7MHz */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 switch (bw) {
258 case BANDWIDTH_8_MHZ:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300259 bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20;
260 imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 break;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300262
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 case BANDWIDTH_7_MHZ:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300264 bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7;
265 imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 break;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300267
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 case BANDWIDTH_6_MHZ:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300269 bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5;
270 imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 break;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300272
273 case 255 /* BANDWIDTH_5_MHZ */:
274 bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500;
275 imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072;
276 break;
277
278 default: return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300280
281 for (reg = 6; reg < 12; reg++)
282 dib3000mc_write_word(state, reg, bw_cfg[reg - 6]);
283 dib3000mc_write_word(state, 12, 0x0000);
284 dib3000mc_write_word(state, 13, 0x03e8);
285 dib3000mc_write_word(state, 14, 0x0000);
286 dib3000mc_write_word(state, 15, 0x03f2);
287 dib3000mc_write_word(state, 16, 0x0001);
288 dib3000mc_write_word(state, 17, 0xb0d0);
289 // P_sec_len
290 dib3000mc_write_word(state, 18, 0x0393);
291 dib3000mc_write_word(state, 19, 0x8700);
292
293 for (reg = 55; reg < 58; reg++)
294 dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]);
295
296 // Timing configuration
297 dib3000mc_set_timing(state, 0, bw, 0);
298
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 return 0;
300}
301
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300302static u16 impulse_noise_val[29] =
303
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300305 0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c, 0x3ffe, 0x7f3,
306 0x2d94, 0x76, 0x53d, 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3, 0x3feb, 0x7d2,
307 0x365e, 0x76, 0x48c, 0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0000, 0xd
308};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300310static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, s16 nfft)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300312 u16 i;
313 for (i = 58; i < 87; i++)
314 dib3000mc_write_word(state, i, impulse_noise_val[i-58]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300316 if (nfft == 1) {
317 dib3000mc_write_word(state, 58, 0x3b);
318 dib3000mc_write_word(state, 84, 0x00);
319 dib3000mc_write_word(state, 85, 0x8200);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 }
321
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300322 dib3000mc_write_word(state, 34, 0x1294);
323 dib3000mc_write_word(state, 35, 0x1ff8);
324 if (mode == 1)
325 dib3000mc_write_word(state, 55, dib3000mc_read_word(state, 55) | (1 << 10));
326}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300328static int dib3000mc_init(struct dvb_frontend *demod)
329{
330 struct dib3000mc_state *state = demod->demodulator_priv;
331 struct dibx000_agc_config *agc = state->cfg->agc;
332
333 // Restart Configuration
334 dib3000mc_write_word(state, 1027, 0x8000);
335 dib3000mc_write_word(state, 1027, 0x0000);
336
337 // power up the demod + mobility configuration
338 dib3000mc_write_word(state, 140, 0x0000);
339 dib3000mc_write_word(state, 1031, 0);
340
341 if (state->cfg->mobile_mode) {
342 dib3000mc_write_word(state, 139, 0x0000);
343 dib3000mc_write_word(state, 141, 0x0000);
344 dib3000mc_write_word(state, 175, 0x0002);
345 dib3000mc_write_word(state, 1032, 0x0000);
346 } else {
347 dib3000mc_write_word(state, 139, 0x0001);
348 dib3000mc_write_word(state, 141, 0x0000);
349 dib3000mc_write_word(state, 175, 0x0000);
350 dib3000mc_write_word(state, 1032, 0x012C);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300352 dib3000mc_write_word(state, 1033, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300354 // P_clk_cfg
355 dib3000mc_write_word(state, 1037, 12592);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300357 // other configurations
358
359 // P_ctrl_sfreq
360 dib3000mc_write_word(state, 33, (5 << 0));
361 dib3000mc_write_word(state, 88, (1 << 10) | (0x10 << 0));
362
363 // Phase noise control
364 // P_fft_phacor_inh, P_fft_phacor_cpe, P_fft_powrange
365 dib3000mc_write_word(state, 99, (1 << 9) | (0x20 << 0));
366
367 if (state->cfg->phase_noise_mode == 0)
368 dib3000mc_write_word(state, 111, 0x00);
369 else
370 dib3000mc_write_word(state, 111, 0x02);
371
372 // P_agc_global
373 dib3000mc_write_word(state, 50, 0x8000);
374
375 // agc setup misc
376 dib3000mc_setup_pwm3_state(state);
377
378 // P_agc_counter_lock
379 dib3000mc_write_word(state, 53, 0x87);
380 // P_agc_counter_unlock
381 dib3000mc_write_word(state, 54, 0x87);
382
383 /* agc */
384 dib3000mc_write_word(state, 36, state->cfg->max_time);
385 dib3000mc_write_word(state, 37, agc->setup);
386 dib3000mc_write_word(state, 38, state->cfg->pwm3_value);
387 dib3000mc_write_word(state, 39, state->cfg->ln_adc_level);
388
389 // set_agc_loop_Bw
390 dib3000mc_write_word(state, 40, 0x0179);
391 dib3000mc_write_word(state, 41, 0x03f0);
392
393 dib3000mc_write_word(state, 42, agc->agc1_max);
394 dib3000mc_write_word(state, 43, agc->agc1_min);
395 dib3000mc_write_word(state, 44, agc->agc2_max);
396 dib3000mc_write_word(state, 45, agc->agc2_min);
397 dib3000mc_write_word(state, 46, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
398 dib3000mc_write_word(state, 47, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
399 dib3000mc_write_word(state, 48, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
400 dib3000mc_write_word(state, 49, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
401
402// Begin: TimeOut registers
403 // P_pha3_thres
404 dib3000mc_write_word(state, 110, 3277);
405 // P_timf_alpha = 6, P_corm_alpha = 6, P_corm_thres = 0x80
406 dib3000mc_write_word(state, 26, 0x6680);
407 // lock_mask0
408 dib3000mc_write_word(state, 1, 4);
409 // lock_mask1
410 dib3000mc_write_word(state, 2, 4);
411 // lock_mask2
412 dib3000mc_write_word(state, 3, 0x1000);
413 // P_search_maxtrial=1
414 dib3000mc_write_word(state, 5, 1);
415
416 dib3000mc_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
417
418 // div_lock_mask
419 dib3000mc_write_word(state, 4, 0x814);
420
421 dib3000mc_write_word(state, 21, (1 << 9) | 0x164);
422 dib3000mc_write_word(state, 22, 0x463d);
423
424 // Spurious rm cfg
425 // P_cspu_regul, P_cspu_win_cut
426 dib3000mc_write_word(state, 120, 0x200f);
427 // P_adp_selec_monit
428 dib3000mc_write_word(state, 134, 0);
429
430 // Fec cfg
431 dib3000mc_write_word(state, 195, 0x10);
432
433 // diversity register: P_dvsy_sync_wait..
434 dib3000mc_write_word(state, 180, 0x2FF0);
435
436 // Impulse noise configuration
437 dib3000mc_set_impulse_noise(state, 0, 1);
438
439 // output mode set-up
440 dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
441
442 /* close the i2c-gate */
443 dib3000mc_write_word(state, 769, (1 << 7) );
444
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 return 0;
446}
447
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300448static int dib3000mc_sleep(struct dvb_frontend *demod)
449{
450 struct dib3000mc_state *state = demod->demodulator_priv;
451
452 dib3000mc_write_word(state, 1037, dib3000mc_read_word(state, 1037) | 0x0003);
453 dib3000mc_write_word(state, 1031, 0xFFFF);
454 dib3000mc_write_word(state, 1032, 0xFFFF);
455 dib3000mc_write_word(state, 1033, 0xFFF4); // **** Bin2
456
457 return 0;
458}
459
460static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
461{
462 u16 cfg[4] = { 0 },reg;
463 switch (qam) {
464 case 0:
465 cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0;
466 break;
467 case 1:
468 cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0;
469 break;
470 case 2:
471 cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8;
472 break;
473 }
474 for (reg = 129; reg < 133; reg++)
475 dib3000mc_write_word(state, reg, cfg[reg - 129]);
476}
477
478static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx000_ofdm_channel *chan, u16 seq)
479{
480 u16 tmp;
481
482 dib3000mc_set_timing(state, chan->nfft, chan->Bw, 0);
483
484// if (boost)
485// dib3000mc_write_word(state, 100, (11 << 6) + 6);
486// else
487 dib3000mc_write_word(state, 100, (16 << 6) + 9);
488
489 dib3000mc_write_word(state, 1027, 0x0800);
490 dib3000mc_write_word(state, 1027, 0x0000);
491
492 //Default cfg isi offset adp
493 dib3000mc_write_word(state, 26, 0x6680);
494 dib3000mc_write_word(state, 29, 0x1273);
495 dib3000mc_write_word(state, 33, 5);
496 dib3000mc_set_adp_cfg(state, 1);
497 dib3000mc_write_word(state, 133, 15564);
498
499 dib3000mc_write_word(state, 12 , 0x0);
500 dib3000mc_write_word(state, 13 , 0x3e8);
501 dib3000mc_write_word(state, 14 , 0x0);
502 dib3000mc_write_word(state, 15 , 0x3f2);
503
504 dib3000mc_write_word(state, 93,0);
505 dib3000mc_write_word(state, 94,0);
506 dib3000mc_write_word(state, 95,0);
507 dib3000mc_write_word(state, 96,0);
508 dib3000mc_write_word(state, 97,0);
509 dib3000mc_write_word(state, 98,0);
510
511 dib3000mc_set_impulse_noise(state, 0, chan->nfft);
512
513 tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha;
514 dib3000mc_write_word(state, 0, tmp);
515
516 dib3000mc_write_word(state, 5, seq);
517
518 tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp);
519 if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp))
520 tmp |= chan->vit_code_rate_hp << 1;
521 else
522 tmp |= chan->vit_code_rate_lp << 1;
523 dib3000mc_write_word(state, 181, tmp);
524
525 // diversity synchro delay
526 tmp = dib3000mc_read_word(state, 180) & 0x000f;
527 tmp |= ((chan->nfft == 0) ? 64 : 256) * ((1 << (chan->guard)) * 3 / 2) << 4; // add 50% SFN margin
528 dib3000mc_write_word(state, 180, tmp);
529
530 // restart demod
531 tmp = dib3000mc_read_word(state, 0);
532 dib3000mc_write_word(state, 0, tmp | (1 << 9));
533 dib3000mc_write_word(state, 0, tmp);
534
535 msleep(30);
536
537 dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, chan->nfft);
538}
539
540static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *chan)
541{
542 struct dib3000mc_state *state = demod->demodulator_priv;
543 u16 reg;
544// u32 val;
545 struct dibx000_ofdm_channel fchan;
546
547 INIT_OFDM_CHANNEL(&fchan);
548 fchan = *chan;
549
550
551 /* a channel for autosearch */
552 reg = 0;
553 if (chan->nfft == -1 && chan->guard == -1) reg = 7;
554 if (chan->nfft == -1 && chan->guard != -1) reg = 2;
555 if (chan->nfft != -1 && chan->guard == -1) reg = 3;
556
557 fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2;
558 fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2;
559 fchan.vit_hrch = 0; fchan.vit_select_hp = 1;
560
561 dib3000mc_set_channel_cfg(state, &fchan, reg);
562
563 reg = dib3000mc_read_word(state, 0);
564 dib3000mc_write_word(state, 0, reg | (1 << 8));
565 dib3000mc_write_word(state, 0, reg);
566
567 return 0;
568}
569
570static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod)
571{
572 struct dib3000mc_state *state = demod->demodulator_priv;
573 u16 irq_pending = dib3000mc_read_word(state, 511);
574
575 if (irq_pending & 0x1) // failed
576 return 1;
577
578 if (irq_pending & 0x2) // succeeded
579 return 2;
580
581 return 0; // still pending
582}
583
584static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
585{
586 struct dib3000mc_state *state = demod->demodulator_priv;
587
588 // ** configure demod **
589 dib3000mc_set_channel_cfg(state, ch, 0);
590
591 // activates isi
592 dib3000mc_write_word(state, 29, 0x1073);
593
594 dib3000mc_set_adp_cfg(state, (u8)ch->nqam);
595
596 if (ch->nfft == 1) {
597 dib3000mc_write_word(state, 26, 38528);
598 dib3000mc_write_word(state, 33, 8);
599 } else {
600 dib3000mc_write_word(state, 26, 30336);
601 dib3000mc_write_word(state, 33, 6);
602 }
603
604 // if (lock)
605 // dib3000mc_set_timing(state, ch->nfft, ch->Bw, 1);
606
607 return 0;
608}
609
610static int dib3000mc_demod_output_mode(struct dvb_frontend *demod, int mode)
611{
612 struct dib3000mc_state *state = demod->demodulator_priv;
613 return dib3000mc_set_output_mode(state, mode);
614}
615
616static int dib3000mc_i2c_enumeration(struct dvb_frontend *demod[], int no_of_demods, u8 default_addr)
617{
618 struct dib3000mc_state *st;
619 int k,ret=0;
620 u8 new_addr;
621
622 static u8 DIB3000MC_I2C_ADDRESS[] = {20,22,24,26};
623
624 for (k = no_of_demods-1; k >= 0; k--) {
625 st = demod[k]->demodulator_priv;
626
627 /* designated i2c address */
628 new_addr = DIB3000MC_I2C_ADDRESS[k];
629
630 st->i2c_addr = new_addr;
631 if (dib3000mc_identify(st) != 0) {
632 st->i2c_addr = default_addr;
633 if (dib3000mc_identify(st) != 0) {
634 dprintk("-E- DiB3000P/MC #%d: not identified\n", k);
635 return -EINVAL;
636 }
637 }
638
639 /* turn on div_out */
640 dib3000mc_demod_output_mode(demod[k], OUTMODE_MPEG2_PAR_CONT_CLK);
641
642 // set new i2c address and force divstr (Bit 1) to value 0 (Bit 0)
643 ret |= dib3000mc_write_word(st, 1024, (new_addr << 3) | 0x1);
644 st->i2c_addr = new_addr;
645 }
646
647 for (k = 0; k < no_of_demods; k++) {
648 st = demod[k]->demodulator_priv;
649
650 ret |= dib3000mc_write_word(st, 1024, st->i2c_addr << 3);
651
652 /* turn off data output */
653 dib3000mc_demod_output_mode(demod[k],OUTMODE_HIGH_Z);
654 dib3000mc_write_word(st, 769, (1 << 7) );
655
656 }
657 return 0;
658}
659
660struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating)
661{
662 struct dib3000mc_state *st = demod->demodulator_priv;
663 return dibx000_get_i2c_adapter(&st->i2c_master, DIBX000_I2C_INTERFACE_TUNER, gating);
664}
665
666EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master);
667
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668static int dib3000mc_get_frontend(struct dvb_frontend* fe,
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300669 struct dvb_frontend_parameters *fep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300671 struct dib3000mc_state *state = fe->demodulator_priv;
672 u16 tps = dib3000mc_read_word(state,458);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300674 fep->inversion = INVERSION_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300676 fep->u.ofdm.bandwidth = state->current_bandwidth;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300678 switch ((tps >> 8) & 0x1) {
679 case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
680 case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 }
682
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300683 switch (tps & 0x3) {
684 case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
685 case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
686 case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
687 case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 }
689
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300690 switch ((tps >> 13) & 0x3) {
691 case 0: fep->u.ofdm.constellation = QPSK; break;
692 case 1: fep->u.ofdm.constellation = QAM_16; break;
693 case 2:
694 default: fep->u.ofdm.constellation = QAM_64; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 }
696
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300697 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
698 /* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */
699
700 fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
701 switch ((tps >> 5) & 0x7) {
702 case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
703 case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
704 case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
705 case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
706 case 7:
707 default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
708
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 }
710
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300711 switch ((tps >> 2) & 0x7) {
712 case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
713 case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
714 case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
715 case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
716 case 7:
717 default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720 return 0;
721}
722
723static int dib3000mc_set_frontend(struct dvb_frontend* fe,
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300724 struct dvb_frontend_parameters *fep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300726 struct dib3000mc_state *state = fe->demodulator_priv;
727 struct dibx000_ofdm_channel ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300729 INIT_OFDM_CHANNEL(&ch);
730 FEP2DIB(fep,&ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300732 dump_fep(&ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300734 state->current_bandwidth = fep->u.ofdm.bandwidth;
735 dib3000mc_set_bandwidth(fe, fep->u.ofdm.bandwidth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300737 if (fe->ops.tuner_ops.set_params) {
738 fe->ops.tuner_ops.set_params(fe, fep);
739 msleep(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300741
742 if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
743 fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
744 fep->u.ofdm.constellation == QAM_AUTO ||
745 fep->u.ofdm.code_rate_HP == FEC_AUTO) {
746 int i = 100, found;
747
748 dib3000mc_autosearch_start(fe, &ch);
749 do {
750 msleep(1);
751 found = dib3000mc_autosearch_is_irq(fe);
752 } while (found == 0 && i--);
753
754 dprintk("autosearch returns: %d\n",found);
755 if (found == 0 || found == 1)
756 return 0; // no channel found
757
758 dib3000mc_get_frontend(fe, fep);
759 FEP2DIB(fep,&ch);
760 }
761
762 /* make this a config parameter */
763 dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
764
765 return dib3000mc_tune(fe, &ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766}
767
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300768static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300770 struct dib3000mc_state *state = fe->demodulator_priv;
771 u16 lock = dib3000mc_read_word(state, 509);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
773 *stat = 0;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300774
775 if (lock & 0x8000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 *stat |= FE_HAS_SIGNAL;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300777 if (lock & 0x3000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 *stat |= FE_HAS_CARRIER;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300779 if (lock & 0x0100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 *stat |= FE_HAS_VITERBI;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300781 if (lock & 0x0010)
782 *stat |= FE_HAS_SYNC;
783 if (lock & 0x0008)
784 *stat |= FE_HAS_LOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
786 return 0;
787}
788
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300789static int dib3000mc_read_ber(struct dvb_frontend *fe, u32 *ber)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300791 struct dib3000mc_state *state = fe->demodulator_priv;
792 *ber = (dib3000mc_read_word(state, 500) << 16) | dib3000mc_read_word(state, 501);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 return 0;
794}
795
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300796static int dib3000mc_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300798 struct dib3000mc_state *state = fe->demodulator_priv;
799 *unc = dib3000mc_read_word(state, 508);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 return 0;
801}
802
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300803static int dib3000mc_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300805 struct dib3000mc_state *state = fe->demodulator_priv;
806 u16 val = dib3000mc_read_word(state, 392);
807 *strength = 65535 - val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 return 0;
809}
810
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr)
812{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300813 *snr = 0x0000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 return 0;
815}
816
817static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
818{
Johannes Stezenbach776338e2005-06-23 22:02:35 -0700819 tune->min_delay_ms = 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 return 0;
821}
822
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300823static void dib3000mc_release(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300825 struct dib3000mc_state *state = fe->demodulator_priv;
826 dibx000_exit_i2c_master(&state->i2c_master);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 kfree(state);
828}
829
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300830int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300832 struct dib3000mc_state *state = fe->demodulator_priv;
833 dib3000mc_write_word(state, 212 + index, onoff ? (1 << 13) | pid : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 return 0;
835}
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300836EXPORT_SYMBOL(dib3000mc_pid_control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300838int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300840 struct dib3000mc_state *state = fe->demodulator_priv;
841 u16 tmp = dib3000mc_read_word(state, 206) & ~(1 << 4);
842 tmp |= (onoff << 4);
843 return dib3000mc_write_word(state, 206, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844}
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300845EXPORT_SYMBOL(dib3000mc_pid_parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300847void dib3000mc_set_config(struct dvb_frontend *fe, struct dib3000mc_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300849 struct dib3000mc_state *state = fe->demodulator_priv;
850 state->cfg = cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851}
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300852EXPORT_SYMBOL(dib3000mc_set_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853
854static struct dvb_frontend_ops dib3000mc_ops;
855
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300856int dib3000mc_attach(struct i2c_adapter *i2c_adap, int no_of_demods, u8 default_addr, u8 do_i2c_enum, struct dib3000mc_config cfg[], struct dvb_frontend *demod[])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300858 struct dib3000mc_state *st;
859 int k, num=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300861 if (no_of_demods < 1)
862 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300864 for (k = 0; k < no_of_demods; k++) {
865 st = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);
866 if (st == NULL)
867 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300869 num++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300871 st->cfg = &cfg[k];
872 // st->gpio_val = cfg[k].gpio_val;
873 // st->gpio_dir = cfg[k].gpio_dir;
874 st->i2c_adap = i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300876 demod[k] = &st->demod;
877 demod[k]->demodulator_priv = st;
878 memcpy(&st->demod.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
879
880// INIT_COMPONENT_REGISTER_ACCESS(&st->register_access, 12, 16, dib7000p_register_read, dib7000p_register_write, st);
881// demod[k]->register_access = &st->register_access;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 }
883
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300884 if (do_i2c_enum) {
885 if (dib3000mc_i2c_enumeration(demod,no_of_demods,default_addr) != 0)
886 goto error;
887 } else {
888 st = demod[0]->demodulator_priv;
889 st->i2c_addr = default_addr;
890 if (dib3000mc_identify(st) != 0)
891 goto error;
892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300894 for (k = 0; k < num; k++) {
895 st = demod[k]->demodulator_priv;
896 dibx000_init_i2c_master(&st->i2c_master, DIB3000MC, st->i2c_adap, st->i2c_addr);
897 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300899 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
901error:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300902 for (k = 0; k < num; k++)
903 kfree(demod[k]->demodulator_priv);
904
905 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906}
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300907
Patrick Boettchere4d6c1f2006-08-08 15:48:09 -0300908EXPORT_SYMBOL(dib3000mc_attach);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
910static struct dvb_frontend_ops dib3000mc_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 .info = {
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300912 .name = "DiBcom 3000MC/P",
913 .type = FE_OFDM,
914 .frequency_min = 44250000,
915 .frequency_max = 867250000,
916 .frequency_stepsize = 62500,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 .caps = FE_CAN_INVERSION_AUTO |
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300918 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
919 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
920 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
921 FE_CAN_TRANSMISSION_MODE_AUTO |
922 FE_CAN_GUARD_INTERVAL_AUTO |
923 FE_CAN_RECOVER |
924 FE_CAN_HIERARCHY_AUTO,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 },
926
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300927 .release = dib3000mc_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300929 .init = dib3000mc_init,
930 .sleep = dib3000mc_sleep,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300932 .set_frontend = dib3000mc_set_frontend,
933 .get_tune_settings = dib3000mc_fe_get_tune_settings,
934 .get_frontend = dib3000mc_get_frontend,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300936 .read_status = dib3000mc_read_status,
937 .read_ber = dib3000mc_read_ber,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 .read_signal_strength = dib3000mc_read_signal_strength,
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300939 .read_snr = dib3000mc_read_snr,
940 .read_ucblocks = dib3000mc_read_unc_blocks,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941};
942
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300943MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
944MODULE_DESCRIPTION("Driver for the DiBcom 3000MC/P COFDM demodulator");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945MODULE_LICENSE("GPL");