blob: 6d61237a450d74ad431613e8ad9869b959ac9ab1 [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 Boettcher559463b2006-08-19 16:13:53 -0300172 u16 smo_reg = (0 << 6) | (0 << 5) | (0 << 3) | (1 << 1) | 0 |
173 (dib3000mc_read_word(state, 206) & 0x0010); /* keep the pid_parse bit */
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300174
175 dprintk("-I- Setting output mode for demod %p to %d\n",
176 &state->demod, mode);
177
178 switch (mode) {
179 case OUTMODE_HIGH_Z: // disable
180 elecout = 0;
181 break;
182 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
183 outmode = 0;
184 break;
185 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
186 outmode = 1;
187 break;
188 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
189 outmode = 2;
190 break;
191 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
192 elecout = 3;
193 /*ADDR @ 206 :
194 P_smo_error_discard [1;6:6] = 0
195 P_smo_rs_discard [1;5:5] = 0
196 P_smo_pid_parse [1;4:4] = 0
197 P_smo_fifo_flush [1;3:3] = 0
198 P_smo_mode [2;2:1] = 11
199 P_smo_ovf_prot [1;0:0] = 0
200 */
Patrick Boettcher559463b2006-08-19 16:13:53 -0300201 smo_reg = (0 << 6) | (0 << 5) | (0 << 3) |(3 << 1) | 0;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300202 fifo_threshold = 512;
203 outmode = 5;
204 break;
205 case OUTMODE_DIVERSITY:
206 outmode = 4;
207 elecout = 1;
208 break;
209 default:
210 dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
211 outmode = 0;
212 break;
213 }
214
215 if ((state->cfg->output_mpeg2_in_188_bytes))
Patrick Boettcher559463b2006-08-19 16:13:53 -0300216 smo_reg |= (1 << 5); // P_smo_rs_discard [1;5:5] = 1
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300217
218 outreg = dib3000mc_read_word(state, 244) & 0x07FF;
219 outreg |= (outmode << 11);
220 ret |= dib3000mc_write_word(state, 244, outreg);
221 ret |= dib3000mc_write_word(state, 206, smo_reg); /*smo_ mode*/
222 ret |= dib3000mc_write_word(state, 207, fifo_threshold); /* synchronous fread */
223 ret |= dib3000mc_write_word(state, 1040, elecout); /* P_out_cfg */
224 return ret;
225}
226
227static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw)
228{
229 struct dib3000mc_state *state = demod->demodulator_priv;
230 u16 bw_cfg[6] = { 0 };
231 u16 imp_bw_cfg[3] = { 0 };
232 u16 reg;
233
234/* settings here are for 27.7MHz */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 switch (bw) {
236 case BANDWIDTH_8_MHZ:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300237 bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20;
238 imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 break;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300240
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 case BANDWIDTH_7_MHZ:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300242 bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7;
243 imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 break;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300245
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 case BANDWIDTH_6_MHZ:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300247 bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5;
248 imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 break;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300250
251 case 255 /* BANDWIDTH_5_MHZ */:
252 bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500;
253 imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072;
254 break;
255
256 default: return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300258
259 for (reg = 6; reg < 12; reg++)
260 dib3000mc_write_word(state, reg, bw_cfg[reg - 6]);
261 dib3000mc_write_word(state, 12, 0x0000);
262 dib3000mc_write_word(state, 13, 0x03e8);
263 dib3000mc_write_word(state, 14, 0x0000);
264 dib3000mc_write_word(state, 15, 0x03f2);
265 dib3000mc_write_word(state, 16, 0x0001);
266 dib3000mc_write_word(state, 17, 0xb0d0);
267 // P_sec_len
268 dib3000mc_write_word(state, 18, 0x0393);
269 dib3000mc_write_word(state, 19, 0x8700);
270
271 for (reg = 55; reg < 58; reg++)
272 dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]);
273
274 // Timing configuration
275 dib3000mc_set_timing(state, 0, bw, 0);
276
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 return 0;
278}
279
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300280static u16 impulse_noise_val[29] =
281
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300283 0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c, 0x3ffe, 0x7f3,
284 0x2d94, 0x76, 0x53d, 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3, 0x3feb, 0x7d2,
285 0x365e, 0x76, 0x48c, 0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0000, 0xd
286};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300288static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, s16 nfft)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300290 u16 i;
291 for (i = 58; i < 87; i++)
292 dib3000mc_write_word(state, i, impulse_noise_val[i-58]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300294 if (nfft == 1) {
295 dib3000mc_write_word(state, 58, 0x3b);
296 dib3000mc_write_word(state, 84, 0x00);
297 dib3000mc_write_word(state, 85, 0x8200);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 }
299
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300300 dib3000mc_write_word(state, 34, 0x1294);
301 dib3000mc_write_word(state, 35, 0x1ff8);
302 if (mode == 1)
303 dib3000mc_write_word(state, 55, dib3000mc_read_word(state, 55) | (1 << 10));
304}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300306static int dib3000mc_init(struct dvb_frontend *demod)
307{
308 struct dib3000mc_state *state = demod->demodulator_priv;
309 struct dibx000_agc_config *agc = state->cfg->agc;
310
311 // Restart Configuration
312 dib3000mc_write_word(state, 1027, 0x8000);
313 dib3000mc_write_word(state, 1027, 0x0000);
314
315 // power up the demod + mobility configuration
316 dib3000mc_write_word(state, 140, 0x0000);
317 dib3000mc_write_word(state, 1031, 0);
318
319 if (state->cfg->mobile_mode) {
320 dib3000mc_write_word(state, 139, 0x0000);
321 dib3000mc_write_word(state, 141, 0x0000);
322 dib3000mc_write_word(state, 175, 0x0002);
323 dib3000mc_write_word(state, 1032, 0x0000);
324 } else {
325 dib3000mc_write_word(state, 139, 0x0001);
326 dib3000mc_write_word(state, 141, 0x0000);
327 dib3000mc_write_word(state, 175, 0x0000);
328 dib3000mc_write_word(state, 1032, 0x012C);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300330 dib3000mc_write_word(state, 1033, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300332 // P_clk_cfg
333 dib3000mc_write_word(state, 1037, 12592);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300335 // other configurations
336
337 // P_ctrl_sfreq
338 dib3000mc_write_word(state, 33, (5 << 0));
339 dib3000mc_write_word(state, 88, (1 << 10) | (0x10 << 0));
340
341 // Phase noise control
342 // P_fft_phacor_inh, P_fft_phacor_cpe, P_fft_powrange
343 dib3000mc_write_word(state, 99, (1 << 9) | (0x20 << 0));
344
345 if (state->cfg->phase_noise_mode == 0)
346 dib3000mc_write_word(state, 111, 0x00);
347 else
348 dib3000mc_write_word(state, 111, 0x02);
349
350 // P_agc_global
351 dib3000mc_write_word(state, 50, 0x8000);
352
353 // agc setup misc
354 dib3000mc_setup_pwm3_state(state);
355
356 // P_agc_counter_lock
357 dib3000mc_write_word(state, 53, 0x87);
358 // P_agc_counter_unlock
359 dib3000mc_write_word(state, 54, 0x87);
360
361 /* agc */
362 dib3000mc_write_word(state, 36, state->cfg->max_time);
363 dib3000mc_write_word(state, 37, agc->setup);
364 dib3000mc_write_word(state, 38, state->cfg->pwm3_value);
365 dib3000mc_write_word(state, 39, state->cfg->ln_adc_level);
366
367 // set_agc_loop_Bw
368 dib3000mc_write_word(state, 40, 0x0179);
369 dib3000mc_write_word(state, 41, 0x03f0);
370
371 dib3000mc_write_word(state, 42, agc->agc1_max);
372 dib3000mc_write_word(state, 43, agc->agc1_min);
373 dib3000mc_write_word(state, 44, agc->agc2_max);
374 dib3000mc_write_word(state, 45, agc->agc2_min);
375 dib3000mc_write_word(state, 46, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
376 dib3000mc_write_word(state, 47, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
377 dib3000mc_write_word(state, 48, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
378 dib3000mc_write_word(state, 49, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
379
380// Begin: TimeOut registers
381 // P_pha3_thres
382 dib3000mc_write_word(state, 110, 3277);
383 // P_timf_alpha = 6, P_corm_alpha = 6, P_corm_thres = 0x80
384 dib3000mc_write_word(state, 26, 0x6680);
385 // lock_mask0
386 dib3000mc_write_word(state, 1, 4);
387 // lock_mask1
388 dib3000mc_write_word(state, 2, 4);
389 // lock_mask2
390 dib3000mc_write_word(state, 3, 0x1000);
391 // P_search_maxtrial=1
392 dib3000mc_write_word(state, 5, 1);
393
394 dib3000mc_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
395
396 // div_lock_mask
397 dib3000mc_write_word(state, 4, 0x814);
398
399 dib3000mc_write_word(state, 21, (1 << 9) | 0x164);
400 dib3000mc_write_word(state, 22, 0x463d);
401
402 // Spurious rm cfg
403 // P_cspu_regul, P_cspu_win_cut
404 dib3000mc_write_word(state, 120, 0x200f);
405 // P_adp_selec_monit
406 dib3000mc_write_word(state, 134, 0);
407
408 // Fec cfg
409 dib3000mc_write_word(state, 195, 0x10);
410
411 // diversity register: P_dvsy_sync_wait..
412 dib3000mc_write_word(state, 180, 0x2FF0);
413
414 // Impulse noise configuration
415 dib3000mc_set_impulse_noise(state, 0, 1);
416
417 // output mode set-up
418 dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
419
420 /* close the i2c-gate */
421 dib3000mc_write_word(state, 769, (1 << 7) );
422
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 return 0;
424}
425
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300426static int dib3000mc_sleep(struct dvb_frontend *demod)
427{
428 struct dib3000mc_state *state = demod->demodulator_priv;
429
430 dib3000mc_write_word(state, 1037, dib3000mc_read_word(state, 1037) | 0x0003);
431 dib3000mc_write_word(state, 1031, 0xFFFF);
432 dib3000mc_write_word(state, 1032, 0xFFFF);
433 dib3000mc_write_word(state, 1033, 0xFFF4); // **** Bin2
434
435 return 0;
436}
437
438static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
439{
440 u16 cfg[4] = { 0 },reg;
441 switch (qam) {
442 case 0:
443 cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0;
444 break;
445 case 1:
446 cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0;
447 break;
448 case 2:
449 cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8;
450 break;
451 }
452 for (reg = 129; reg < 133; reg++)
453 dib3000mc_write_word(state, reg, cfg[reg - 129]);
454}
455
456static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx000_ofdm_channel *chan, u16 seq)
457{
458 u16 tmp;
459
460 dib3000mc_set_timing(state, chan->nfft, chan->Bw, 0);
461
462// if (boost)
463// dib3000mc_write_word(state, 100, (11 << 6) + 6);
464// else
465 dib3000mc_write_word(state, 100, (16 << 6) + 9);
466
467 dib3000mc_write_word(state, 1027, 0x0800);
468 dib3000mc_write_word(state, 1027, 0x0000);
469
470 //Default cfg isi offset adp
471 dib3000mc_write_word(state, 26, 0x6680);
472 dib3000mc_write_word(state, 29, 0x1273);
473 dib3000mc_write_word(state, 33, 5);
474 dib3000mc_set_adp_cfg(state, 1);
475 dib3000mc_write_word(state, 133, 15564);
476
477 dib3000mc_write_word(state, 12 , 0x0);
478 dib3000mc_write_word(state, 13 , 0x3e8);
479 dib3000mc_write_word(state, 14 , 0x0);
480 dib3000mc_write_word(state, 15 , 0x3f2);
481
482 dib3000mc_write_word(state, 93,0);
483 dib3000mc_write_word(state, 94,0);
484 dib3000mc_write_word(state, 95,0);
485 dib3000mc_write_word(state, 96,0);
486 dib3000mc_write_word(state, 97,0);
487 dib3000mc_write_word(state, 98,0);
488
489 dib3000mc_set_impulse_noise(state, 0, chan->nfft);
490
491 tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha;
492 dib3000mc_write_word(state, 0, tmp);
493
494 dib3000mc_write_word(state, 5, seq);
495
496 tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp);
497 if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp))
498 tmp |= chan->vit_code_rate_hp << 1;
499 else
500 tmp |= chan->vit_code_rate_lp << 1;
501 dib3000mc_write_word(state, 181, tmp);
502
503 // diversity synchro delay
504 tmp = dib3000mc_read_word(state, 180) & 0x000f;
505 tmp |= ((chan->nfft == 0) ? 64 : 256) * ((1 << (chan->guard)) * 3 / 2) << 4; // add 50% SFN margin
506 dib3000mc_write_word(state, 180, tmp);
507
508 // restart demod
509 tmp = dib3000mc_read_word(state, 0);
510 dib3000mc_write_word(state, 0, tmp | (1 << 9));
511 dib3000mc_write_word(state, 0, tmp);
512
513 msleep(30);
514
515 dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, chan->nfft);
516}
517
518static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *chan)
519{
520 struct dib3000mc_state *state = demod->demodulator_priv;
521 u16 reg;
522// u32 val;
523 struct dibx000_ofdm_channel fchan;
524
525 INIT_OFDM_CHANNEL(&fchan);
526 fchan = *chan;
527
528
529 /* a channel for autosearch */
530 reg = 0;
531 if (chan->nfft == -1 && chan->guard == -1) reg = 7;
532 if (chan->nfft == -1 && chan->guard != -1) reg = 2;
533 if (chan->nfft != -1 && chan->guard == -1) reg = 3;
534
535 fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2;
536 fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2;
537 fchan.vit_hrch = 0; fchan.vit_select_hp = 1;
538
539 dib3000mc_set_channel_cfg(state, &fchan, reg);
540
541 reg = dib3000mc_read_word(state, 0);
542 dib3000mc_write_word(state, 0, reg | (1 << 8));
543 dib3000mc_write_word(state, 0, reg);
544
545 return 0;
546}
547
548static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod)
549{
550 struct dib3000mc_state *state = demod->demodulator_priv;
551 u16 irq_pending = dib3000mc_read_word(state, 511);
552
553 if (irq_pending & 0x1) // failed
554 return 1;
555
556 if (irq_pending & 0x2) // succeeded
557 return 2;
558
559 return 0; // still pending
560}
561
562static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
563{
564 struct dib3000mc_state *state = demod->demodulator_priv;
565
566 // ** configure demod **
567 dib3000mc_set_channel_cfg(state, ch, 0);
568
569 // activates isi
570 dib3000mc_write_word(state, 29, 0x1073);
571
572 dib3000mc_set_adp_cfg(state, (u8)ch->nqam);
573
574 if (ch->nfft == 1) {
575 dib3000mc_write_word(state, 26, 38528);
576 dib3000mc_write_word(state, 33, 8);
577 } else {
578 dib3000mc_write_word(state, 26, 30336);
579 dib3000mc_write_word(state, 33, 6);
580 }
581
582 // if (lock)
583 // dib3000mc_set_timing(state, ch->nfft, ch->Bw, 1);
584
585 return 0;
586}
587
588static int dib3000mc_demod_output_mode(struct dvb_frontend *demod, int mode)
589{
590 struct dib3000mc_state *state = demod->demodulator_priv;
591 return dib3000mc_set_output_mode(state, mode);
592}
593
594static int dib3000mc_i2c_enumeration(struct dvb_frontend *demod[], int no_of_demods, u8 default_addr)
595{
596 struct dib3000mc_state *st;
597 int k,ret=0;
598 u8 new_addr;
599
600 static u8 DIB3000MC_I2C_ADDRESS[] = {20,22,24,26};
601
602 for (k = no_of_demods-1; k >= 0; k--) {
603 st = demod[k]->demodulator_priv;
604
605 /* designated i2c address */
606 new_addr = DIB3000MC_I2C_ADDRESS[k];
607
608 st->i2c_addr = new_addr;
609 if (dib3000mc_identify(st) != 0) {
610 st->i2c_addr = default_addr;
611 if (dib3000mc_identify(st) != 0) {
612 dprintk("-E- DiB3000P/MC #%d: not identified\n", k);
613 return -EINVAL;
614 }
615 }
616
617 /* turn on div_out */
618 dib3000mc_demod_output_mode(demod[k], OUTMODE_MPEG2_PAR_CONT_CLK);
619
620 // set new i2c address and force divstr (Bit 1) to value 0 (Bit 0)
621 ret |= dib3000mc_write_word(st, 1024, (new_addr << 3) | 0x1);
622 st->i2c_addr = new_addr;
623 }
624
625 for (k = 0; k < no_of_demods; k++) {
626 st = demod[k]->demodulator_priv;
627
628 ret |= dib3000mc_write_word(st, 1024, st->i2c_addr << 3);
629
630 /* turn off data output */
631 dib3000mc_demod_output_mode(demod[k],OUTMODE_HIGH_Z);
632 dib3000mc_write_word(st, 769, (1 << 7) );
633
634 }
635 return 0;
636}
637
638struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating)
639{
640 struct dib3000mc_state *st = demod->demodulator_priv;
641 return dibx000_get_i2c_adapter(&st->i2c_master, DIBX000_I2C_INTERFACE_TUNER, gating);
642}
643
644EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master);
645
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646static int dib3000mc_get_frontend(struct dvb_frontend* fe,
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300647 struct dvb_frontend_parameters *fep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300649 struct dib3000mc_state *state = fe->demodulator_priv;
650 u16 tps = dib3000mc_read_word(state,458);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300652 fep->inversion = INVERSION_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300654 fep->u.ofdm.bandwidth = state->current_bandwidth;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300656 switch ((tps >> 8) & 0x1) {
657 case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
658 case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
660
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300661 switch (tps & 0x3) {
662 case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
663 case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
664 case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
665 case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 }
667
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300668 switch ((tps >> 13) & 0x3) {
669 case 0: fep->u.ofdm.constellation = QPSK; break;
670 case 1: fep->u.ofdm.constellation = QAM_16; break;
671 case 2:
672 default: fep->u.ofdm.constellation = QAM_64; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 }
674
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300675 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
676 /* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */
677
678 fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
679 switch ((tps >> 5) & 0x7) {
680 case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
681 case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
682 case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
683 case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
684 case 7:
685 default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
686
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 }
688
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300689 switch ((tps >> 2) & 0x7) {
690 case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
691 case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
692 case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
693 case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
694 case 7:
695 default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
698 return 0;
699}
700
701static int dib3000mc_set_frontend(struct dvb_frontend* fe,
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300702 struct dvb_frontend_parameters *fep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300704 struct dib3000mc_state *state = fe->demodulator_priv;
705 struct dibx000_ofdm_channel ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300707 INIT_OFDM_CHANNEL(&ch);
708 FEP2DIB(fep,&ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300710 state->current_bandwidth = fep->u.ofdm.bandwidth;
711 dib3000mc_set_bandwidth(fe, fep->u.ofdm.bandwidth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300713 if (fe->ops.tuner_ops.set_params) {
714 fe->ops.tuner_ops.set_params(fe, fep);
715 msleep(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300717
718 if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
719 fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
720 fep->u.ofdm.constellation == QAM_AUTO ||
721 fep->u.ofdm.code_rate_HP == FEC_AUTO) {
722 int i = 100, found;
723
724 dib3000mc_autosearch_start(fe, &ch);
725 do {
726 msleep(1);
727 found = dib3000mc_autosearch_is_irq(fe);
728 } while (found == 0 && i--);
729
730 dprintk("autosearch returns: %d\n",found);
731 if (found == 0 || found == 1)
732 return 0; // no channel found
733
734 dib3000mc_get_frontend(fe, fep);
735 FEP2DIB(fep,&ch);
736 }
737
738 /* make this a config parameter */
739 dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
740
741 return dib3000mc_tune(fe, &ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742}
743
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300744static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300746 struct dib3000mc_state *state = fe->demodulator_priv;
747 u16 lock = dib3000mc_read_word(state, 509);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
749 *stat = 0;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300750
751 if (lock & 0x8000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 *stat |= FE_HAS_SIGNAL;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300753 if (lock & 0x3000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 *stat |= FE_HAS_CARRIER;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300755 if (lock & 0x0100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 *stat |= FE_HAS_VITERBI;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300757 if (lock & 0x0010)
758 *stat |= FE_HAS_SYNC;
759 if (lock & 0x0008)
760 *stat |= FE_HAS_LOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
762 return 0;
763}
764
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300765static int dib3000mc_read_ber(struct dvb_frontend *fe, u32 *ber)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300767 struct dib3000mc_state *state = fe->demodulator_priv;
768 *ber = (dib3000mc_read_word(state, 500) << 16) | dib3000mc_read_word(state, 501);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 return 0;
770}
771
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300772static int dib3000mc_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300774 struct dib3000mc_state *state = fe->demodulator_priv;
775 *unc = dib3000mc_read_word(state, 508);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 return 0;
777}
778
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300779static int dib3000mc_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300781 struct dib3000mc_state *state = fe->demodulator_priv;
782 u16 val = dib3000mc_read_word(state, 392);
783 *strength = 65535 - val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 return 0;
785}
786
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr)
788{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300789 *snr = 0x0000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 return 0;
791}
792
793static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
794{
Johannes Stezenbach776338e2005-06-23 22:02:35 -0700795 tune->min_delay_ms = 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 return 0;
797}
798
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300799static void dib3000mc_release(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300801 struct dib3000mc_state *state = fe->demodulator_priv;
802 dibx000_exit_i2c_master(&state->i2c_master);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 kfree(state);
804}
805
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300806int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300808 struct dib3000mc_state *state = fe->demodulator_priv;
809 dib3000mc_write_word(state, 212 + index, onoff ? (1 << 13) | pid : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 return 0;
811}
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300812EXPORT_SYMBOL(dib3000mc_pid_control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300814int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300816 struct dib3000mc_state *state = fe->demodulator_priv;
817 u16 tmp = dib3000mc_read_word(state, 206) & ~(1 << 4);
818 tmp |= (onoff << 4);
819 return dib3000mc_write_word(state, 206, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820}
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300821EXPORT_SYMBOL(dib3000mc_pid_parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300823void dib3000mc_set_config(struct dvb_frontend *fe, struct dib3000mc_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300825 struct dib3000mc_state *state = fe->demodulator_priv;
826 state->cfg = cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827}
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300828EXPORT_SYMBOL(dib3000mc_set_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
830static struct dvb_frontend_ops dib3000mc_ops;
831
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300832int 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 -0700833{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300834 struct dib3000mc_state *st;
835 int k, num=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300837 if (no_of_demods < 1)
838 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300840 for (k = 0; k < no_of_demods; k++) {
841 st = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);
842 if (st == NULL)
843 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300845 num++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300847 st->cfg = &cfg[k];
848 // st->gpio_val = cfg[k].gpio_val;
849 // st->gpio_dir = cfg[k].gpio_dir;
850 st->i2c_adap = i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300852 demod[k] = &st->demod;
853 demod[k]->demodulator_priv = st;
854 memcpy(&st->demod.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
855
856// INIT_COMPONENT_REGISTER_ACCESS(&st->register_access, 12, 16, dib7000p_register_read, dib7000p_register_write, st);
857// demod[k]->register_access = &st->register_access;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 }
859
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300860 if (do_i2c_enum) {
861 if (dib3000mc_i2c_enumeration(demod,no_of_demods,default_addr) != 0)
862 goto error;
863 } else {
864 st = demod[0]->demodulator_priv;
865 st->i2c_addr = default_addr;
866 if (dib3000mc_identify(st) != 0)
867 goto error;
868 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300870 for (k = 0; k < num; k++) {
871 st = demod[k]->demodulator_priv;
872 dibx000_init_i2c_master(&st->i2c_master, DIB3000MC, st->i2c_adap, st->i2c_addr);
873 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300875 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876
877error:
Patrick Boettcher4e66c972006-08-08 15:48:11 -0300878 for (k = 0; k < num; k++) {
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300879 kfree(demod[k]->demodulator_priv);
Patrick Boettcher4e66c972006-08-08 15:48:11 -0300880 demod[k] = NULL;
881 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300882 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883}
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300884
Patrick Boettchere4d6c1f2006-08-08 15:48:09 -0300885EXPORT_SYMBOL(dib3000mc_attach);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886
887static struct dvb_frontend_ops dib3000mc_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 .info = {
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300889 .name = "DiBcom 3000MC/P",
890 .type = FE_OFDM,
891 .frequency_min = 44250000,
892 .frequency_max = 867250000,
893 .frequency_stepsize = 62500,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 .caps = FE_CAN_INVERSION_AUTO |
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300895 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
896 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
897 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
898 FE_CAN_TRANSMISSION_MODE_AUTO |
899 FE_CAN_GUARD_INTERVAL_AUTO |
900 FE_CAN_RECOVER |
901 FE_CAN_HIERARCHY_AUTO,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 },
903
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300904 .release = dib3000mc_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300906 .init = dib3000mc_init,
907 .sleep = dib3000mc_sleep,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300909 .set_frontend = dib3000mc_set_frontend,
910 .get_tune_settings = dib3000mc_fe_get_tune_settings,
911 .get_frontend = dib3000mc_get_frontend,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300913 .read_status = dib3000mc_read_status,
914 .read_ber = dib3000mc_read_ber,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 .read_signal_strength = dib3000mc_read_signal_strength,
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300916 .read_snr = dib3000mc_read_snr,
917 .read_ucblocks = dib3000mc_read_unc_blocks,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918};
919
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300920MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
921MODULE_DESCRIPTION("Driver for the DiBcom 3000MC/P COFDM demodulator");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922MODULE_LICENSE("GPL");