blob: 38d2322cbaf690bbf832ce5403329be6acfbcbf6 [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 Boettcherb6884a12007-07-27 10:08:51 -03004 * Copyright (C) 2004-7 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 Boettcherb6884a12007-07-27 10:08:51 -030029#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0)
Patrick Boettcherb7571f82006-08-08 15:48:10 -030030
31struct dib3000mc_state {
32 struct dvb_frontend demod;
33 struct dib3000mc_config *cfg;
34
35 u8 i2c_addr;
36 struct i2c_adapter *i2c_adap;
37
38 struct dibx000_i2c_master i2c_master;
39
Patrick Boettcher01b4bf32006-09-19 12:51:53 -030040 u32 timf;
41
Patrick Boettcherb7571f82006-08-08 15:48:10 -030042 fe_bandwidth_t current_bandwidth;
43
44 u16 dev_id;
45};
46
47static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070048{
Patrick Boettcherb7571f82006-08-08 15:48:10 -030049 u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff };
50 u8 rb[2];
51 struct i2c_msg msg[2] = {
52 { .addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2 },
53 { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
54 };
55
56 if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
57 dprintk("i2c read error on %d\n",reg);
58
59 return (rb[0] << 8) | rb[1];
60}
61
62static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val)
63{
64 u8 b[4] = {
65 (reg >> 8) & 0xff, reg & 0xff,
66 (val >> 8) & 0xff, val & 0xff,
67 };
68 struct i2c_msg msg = {
69 .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
70 };
71 return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
72}
73
Patrick Boettcherb7571f82006-08-08 15:48:10 -030074static int dib3000mc_identify(struct dib3000mc_state *state)
75{
76 u16 value;
77 if ((value = dib3000mc_read_word(state, 1025)) != 0x01b3) {
78 dprintk("-E- DiB3000MC/P: wrong Vendor ID (read=0x%x)\n",value);
79 return -EREMOTEIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 }
81
Patrick Boettcherb7571f82006-08-08 15:48:10 -030082 value = dib3000mc_read_word(state, 1026);
83 if (value != 0x3001 && value != 0x3002) {
84 dprintk("-E- DiB3000MC/P: wrong Device ID (%x)\n",value);
85 return -EREMOTEIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -030087 state->dev_id = value;
88
89 dprintk("-I- found DiB3000MC/P: %x\n",state->dev_id);
90
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 return 0;
92}
93
Patrick Boettcherb6884a12007-07-27 10:08:51 -030094static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070095{
Patrick Boettcher01b4bf32006-09-19 12:51:53 -030096 u32 timf;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Patrick Boettcher01b4bf32006-09-19 12:51:53 -030098 if (state->timf == 0) {
99 timf = 1384402; // default value for 8MHz
100 if (update_offset)
101 msleep(200); // first time we do an update
102 } else
103 timf = state->timf;
104
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300105 timf *= (bw / 1000);
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300106
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300107 if (update_offset) {
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300108 s16 tim_offs = dib3000mc_read_word(state, 416);
109
110 if (tim_offs & 0x2000)
111 tim_offs -= 0x4000;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300112
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300113 if (nfft == TRANSMISSION_MODE_2K)
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300114 tim_offs *= 4;
115
116 timf += tim_offs;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300117 state->timf = timf / (bw / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300119
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300120 dprintk("timf: %d\n", timf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300122 dib3000mc_write_word(state, 23, (u16) (timf >> 16));
123 dib3000mc_write_word(state, 24, (u16) (timf ) & 0xffff);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300124
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 return 0;
126}
127
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300128static int dib3000mc_setup_pwm_state(struct dib3000mc_state *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129{
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300130 u16 reg_51, reg_52 = state->cfg->agc->setup & 0xfefb;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300131 if (state->cfg->pwm3_inversion) {
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300132 reg_51 = (2 << 14) | (0 << 10) | (7 << 6) | (2 << 2) | (2 << 0);
133 reg_52 |= (1 << 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 } else {
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300135 reg_51 = (2 << 14) | (4 << 10) | (7 << 6) | (2 << 2) | (2 << 0);
136 reg_52 |= (1 << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 }
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300138 dib3000mc_write_word(state, 51, reg_51);
139 dib3000mc_write_word(state, 52, reg_52);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300140
141 if (state->cfg->use_pwm3)
142 dib3000mc_write_word(state, 245, (1 << 3) | (1 << 0));
143 else
144 dib3000mc_write_word(state, 245, 0);
145
146 dib3000mc_write_word(state, 1040, 0x3);
147 return 0;
148}
149
150static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode)
151{
152 int ret = 0;
153 u16 fifo_threshold = 1792;
154 u16 outreg = 0;
155 u16 outmode = 0;
156 u16 elecout = 1;
Patrick Boettcherfb6065b2006-08-21 08:21:52 -0300157 u16 smo_reg = dib3000mc_read_word(state, 206) & 0x0010; /* keep the pid_parse bit */
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300158
159 dprintk("-I- Setting output mode for demod %p to %d\n",
160 &state->demod, mode);
161
162 switch (mode) {
163 case OUTMODE_HIGH_Z: // disable
164 elecout = 0;
165 break;
166 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
167 outmode = 0;
168 break;
169 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
170 outmode = 1;
171 break;
172 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
173 outmode = 2;
174 break;
175 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
176 elecout = 3;
177 /*ADDR @ 206 :
178 P_smo_error_discard [1;6:6] = 0
179 P_smo_rs_discard [1;5:5] = 0
180 P_smo_pid_parse [1;4:4] = 0
181 P_smo_fifo_flush [1;3:3] = 0
182 P_smo_mode [2;2:1] = 11
183 P_smo_ovf_prot [1;0:0] = 0
184 */
Patrick Boettcherfb6065b2006-08-21 08:21:52 -0300185 smo_reg |= 3 << 1;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300186 fifo_threshold = 512;
187 outmode = 5;
188 break;
189 case OUTMODE_DIVERSITY:
190 outmode = 4;
191 elecout = 1;
192 break;
193 default:
194 dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
195 outmode = 0;
196 break;
197 }
198
199 if ((state->cfg->output_mpeg2_in_188_bytes))
Patrick Boettcher559463b2006-08-19 16:13:53 -0300200 smo_reg |= (1 << 5); // P_smo_rs_discard [1;5:5] = 1
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300201
202 outreg = dib3000mc_read_word(state, 244) & 0x07FF;
203 outreg |= (outmode << 11);
204 ret |= dib3000mc_write_word(state, 244, outreg);
205 ret |= dib3000mc_write_word(state, 206, smo_reg); /*smo_ mode*/
206 ret |= dib3000mc_write_word(state, 207, fifo_threshold); /* synchronous fread */
207 ret |= dib3000mc_write_word(state, 1040, elecout); /* P_out_cfg */
208 return ret;
209}
210
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300211static int dib3000mc_set_bandwidth(struct dib3000mc_state *state, u32 bw)
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300212{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300213 u16 bw_cfg[6] = { 0 };
214 u16 imp_bw_cfg[3] = { 0 };
215 u16 reg;
216
217/* settings here are for 27.7MHz */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 switch (bw) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300219 case 8000:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300220 bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20;
221 imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 break;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300223
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300224 case 7000:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300225 bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7;
226 imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 break;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300228
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300229 case 6000:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300230 bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5;
231 imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 break;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300233
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300234 case 5000:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300235 bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500;
236 imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072;
237 break;
238
239 default: return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300241
242 for (reg = 6; reg < 12; reg++)
243 dib3000mc_write_word(state, reg, bw_cfg[reg - 6]);
244 dib3000mc_write_word(state, 12, 0x0000);
245 dib3000mc_write_word(state, 13, 0x03e8);
246 dib3000mc_write_word(state, 14, 0x0000);
247 dib3000mc_write_word(state, 15, 0x03f2);
248 dib3000mc_write_word(state, 16, 0x0001);
249 dib3000mc_write_word(state, 17, 0xb0d0);
250 // P_sec_len
251 dib3000mc_write_word(state, 18, 0x0393);
252 dib3000mc_write_word(state, 19, 0x8700);
253
254 for (reg = 55; reg < 58; reg++)
255 dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]);
256
257 // Timing configuration
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300258 dib3000mc_set_timing(state, TRANSMISSION_MODE_2K, bw, 0);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300259
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 return 0;
261}
262
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300263static u16 impulse_noise_val[29] =
264
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300266 0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c, 0x3ffe, 0x7f3,
267 0x2d94, 0x76, 0x53d, 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3, 0x3feb, 0x7d2,
268 0x365e, 0x76, 0x48c, 0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0000, 0xd
269};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300271static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, s16 nfft)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300273 u16 i;
274 for (i = 58; i < 87; i++)
275 dib3000mc_write_word(state, i, impulse_noise_val[i-58]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300277 if (nfft == TRANSMISSION_MODE_8K) {
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300278 dib3000mc_write_word(state, 58, 0x3b);
279 dib3000mc_write_word(state, 84, 0x00);
280 dib3000mc_write_word(state, 85, 0x8200);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 }
282
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300283 dib3000mc_write_word(state, 34, 0x1294);
284 dib3000mc_write_word(state, 35, 0x1ff8);
285 if (mode == 1)
286 dib3000mc_write_word(state, 55, dib3000mc_read_word(state, 55) | (1 << 10));
287}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300289static int dib3000mc_init(struct dvb_frontend *demod)
290{
291 struct dib3000mc_state *state = demod->demodulator_priv;
292 struct dibx000_agc_config *agc = state->cfg->agc;
293
294 // Restart Configuration
295 dib3000mc_write_word(state, 1027, 0x8000);
296 dib3000mc_write_word(state, 1027, 0x0000);
297
298 // power up the demod + mobility configuration
299 dib3000mc_write_word(state, 140, 0x0000);
300 dib3000mc_write_word(state, 1031, 0);
301
302 if (state->cfg->mobile_mode) {
303 dib3000mc_write_word(state, 139, 0x0000);
304 dib3000mc_write_word(state, 141, 0x0000);
305 dib3000mc_write_word(state, 175, 0x0002);
306 dib3000mc_write_word(state, 1032, 0x0000);
307 } else {
308 dib3000mc_write_word(state, 139, 0x0001);
309 dib3000mc_write_word(state, 141, 0x0000);
310 dib3000mc_write_word(state, 175, 0x0000);
311 dib3000mc_write_word(state, 1032, 0x012C);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 }
Patrick Boettcher303cbea2006-09-19 12:51:56 -0300313 dib3000mc_write_word(state, 1033, 0x0000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300315 // P_clk_cfg
Patrick Boettcher303cbea2006-09-19 12:51:56 -0300316 dib3000mc_write_word(state, 1037, 0x3130);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300318 // other configurations
319
320 // P_ctrl_sfreq
321 dib3000mc_write_word(state, 33, (5 << 0));
322 dib3000mc_write_word(state, 88, (1 << 10) | (0x10 << 0));
323
324 // Phase noise control
325 // P_fft_phacor_inh, P_fft_phacor_cpe, P_fft_powrange
326 dib3000mc_write_word(state, 99, (1 << 9) | (0x20 << 0));
327
328 if (state->cfg->phase_noise_mode == 0)
329 dib3000mc_write_word(state, 111, 0x00);
330 else
331 dib3000mc_write_word(state, 111, 0x02);
332
333 // P_agc_global
334 dib3000mc_write_word(state, 50, 0x8000);
335
336 // agc setup misc
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300337 dib3000mc_setup_pwm_state(state);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300338
339 // P_agc_counter_lock
340 dib3000mc_write_word(state, 53, 0x87);
341 // P_agc_counter_unlock
342 dib3000mc_write_word(state, 54, 0x87);
343
344 /* agc */
345 dib3000mc_write_word(state, 36, state->cfg->max_time);
Patrick Boettcher5570dd02006-10-13 11:35:12 -0300346 dib3000mc_write_word(state, 37, (state->cfg->agc_command1 << 13) | (state->cfg->agc_command2 << 12) | (0x1d << 0));
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300347 dib3000mc_write_word(state, 38, state->cfg->pwm3_value);
348 dib3000mc_write_word(state, 39, state->cfg->ln_adc_level);
349
350 // set_agc_loop_Bw
351 dib3000mc_write_word(state, 40, 0x0179);
352 dib3000mc_write_word(state, 41, 0x03f0);
353
354 dib3000mc_write_word(state, 42, agc->agc1_max);
355 dib3000mc_write_word(state, 43, agc->agc1_min);
356 dib3000mc_write_word(state, 44, agc->agc2_max);
357 dib3000mc_write_word(state, 45, agc->agc2_min);
358 dib3000mc_write_word(state, 46, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
359 dib3000mc_write_word(state, 47, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
360 dib3000mc_write_word(state, 48, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
361 dib3000mc_write_word(state, 49, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
362
363// Begin: TimeOut registers
364 // P_pha3_thres
365 dib3000mc_write_word(state, 110, 3277);
366 // P_timf_alpha = 6, P_corm_alpha = 6, P_corm_thres = 0x80
367 dib3000mc_write_word(state, 26, 0x6680);
368 // lock_mask0
369 dib3000mc_write_word(state, 1, 4);
370 // lock_mask1
371 dib3000mc_write_word(state, 2, 4);
372 // lock_mask2
373 dib3000mc_write_word(state, 3, 0x1000);
374 // P_search_maxtrial=1
375 dib3000mc_write_word(state, 5, 1);
376
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300377 dib3000mc_set_bandwidth(state, 8000);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300378
379 // div_lock_mask
380 dib3000mc_write_word(state, 4, 0x814);
381
382 dib3000mc_write_word(state, 21, (1 << 9) | 0x164);
383 dib3000mc_write_word(state, 22, 0x463d);
384
385 // Spurious rm cfg
386 // P_cspu_regul, P_cspu_win_cut
387 dib3000mc_write_word(state, 120, 0x200f);
388 // P_adp_selec_monit
389 dib3000mc_write_word(state, 134, 0);
390
391 // Fec cfg
392 dib3000mc_write_word(state, 195, 0x10);
393
394 // diversity register: P_dvsy_sync_wait..
395 dib3000mc_write_word(state, 180, 0x2FF0);
396
397 // Impulse noise configuration
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300398 dib3000mc_set_impulse_noise(state, 0, TRANSMISSION_MODE_8K);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300399
400 // output mode set-up
401 dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
402
403 /* close the i2c-gate */
404 dib3000mc_write_word(state, 769, (1 << 7) );
405
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 return 0;
407}
408
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300409static int dib3000mc_sleep(struct dvb_frontend *demod)
410{
411 struct dib3000mc_state *state = demod->demodulator_priv;
412
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300413 dib3000mc_write_word(state, 1031, 0xFFFF);
414 dib3000mc_write_word(state, 1032, 0xFFFF);
Patrick Boettcher303cbea2006-09-19 12:51:56 -0300415 dib3000mc_write_word(state, 1033, 0xFFF0);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300416
417 return 0;
418}
419
420static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
421{
422 u16 cfg[4] = { 0 },reg;
423 switch (qam) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300424 case QPSK:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300425 cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0;
426 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300427 case QAM_16:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300428 cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0;
429 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300430 case QAM_64:
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300431 cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8;
432 break;
433 }
434 for (reg = 129; reg < 133; reg++)
435 dib3000mc_write_word(state, reg, cfg[reg - 129]);
436}
437
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300438static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq)
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300439{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300440 u16 value;
441 dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
442 dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300443
444// if (boost)
445// dib3000mc_write_word(state, 100, (11 << 6) + 6);
446// else
447 dib3000mc_write_word(state, 100, (16 << 6) + 9);
448
449 dib3000mc_write_word(state, 1027, 0x0800);
450 dib3000mc_write_word(state, 1027, 0x0000);
451
452 //Default cfg isi offset adp
453 dib3000mc_write_word(state, 26, 0x6680);
454 dib3000mc_write_word(state, 29, 0x1273);
455 dib3000mc_write_word(state, 33, 5);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300456 dib3000mc_set_adp_cfg(state, QAM_16);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300457 dib3000mc_write_word(state, 133, 15564);
458
459 dib3000mc_write_word(state, 12 , 0x0);
460 dib3000mc_write_word(state, 13 , 0x3e8);
461 dib3000mc_write_word(state, 14 , 0x0);
462 dib3000mc_write_word(state, 15 , 0x3f2);
463
464 dib3000mc_write_word(state, 93,0);
465 dib3000mc_write_word(state, 94,0);
466 dib3000mc_write_word(state, 95,0);
467 dib3000mc_write_word(state, 96,0);
468 dib3000mc_write_word(state, 97,0);
469 dib3000mc_write_word(state, 98,0);
470
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300471 dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300472
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300473 value = 0;
474 switch (ch->u.ofdm.transmission_mode) {
475 case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
476 default:
477 case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
478 }
479 switch (ch->u.ofdm.guard_interval) {
480 case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
481 case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
482 case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
483 default:
484 case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
485 }
486 switch (ch->u.ofdm.constellation) {
487 case QPSK: value |= (0 << 3); break;
488 case QAM_16: value |= (1 << 3); break;
489 default:
490 case QAM_64: value |= (2 << 3); break;
491 }
492 switch (HIERARCHY_1) {
493 case HIERARCHY_2: value |= 2; break;
494 case HIERARCHY_4: value |= 4; break;
495 default:
496 case HIERARCHY_1: value |= 1; break;
497 }
498 dib3000mc_write_word(state, 0, value);
Mario Rossie3ab2fd2006-12-20 10:54:30 -0300499 dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4));
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300500
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300501 value = 0;
502 if (ch->u.ofdm.hierarchy_information == 1)
503 value |= (1 << 4);
504 if (1 == 1)
505 value |= 1;
506 switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
507 case FEC_2_3: value |= (2 << 1); break;
508 case FEC_3_4: value |= (3 << 1); break;
509 case FEC_5_6: value |= (5 << 1); break;
510 case FEC_7_8: value |= (7 << 1); break;
511 default:
512 case FEC_1_2: value |= (1 << 1); break;
513 }
514 dib3000mc_write_word(state, 181, value);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300515
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300516 // diversity synchro delay add 50% SFN margin
517 switch (ch->u.ofdm.transmission_mode) {
518 case TRANSMISSION_MODE_8K: value = 256; break;
519 case TRANSMISSION_MODE_2K:
520 default: value = 64; break;
521 }
522 switch (ch->u.ofdm.guard_interval) {
523 case GUARD_INTERVAL_1_16: value *= 2; break;
524 case GUARD_INTERVAL_1_8: value *= 4; break;
525 case GUARD_INTERVAL_1_4: value *= 8; break;
526 default:
527 case GUARD_INTERVAL_1_32: value *= 1; break;
528 }
529 value <<= 4;
530 value |= dib3000mc_read_word(state, 180) & 0x000f;
531 dib3000mc_write_word(state, 180, value);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300532
533 // restart demod
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300534 value = dib3000mc_read_word(state, 0);
535 dib3000mc_write_word(state, 0, value | (1 << 9));
536 dib3000mc_write_word(state, 0, value);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300537
538 msleep(30);
539
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300540 dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300541}
542
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300543static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan)
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300544{
545 struct dib3000mc_state *state = demod->demodulator_priv;
546 u16 reg;
547// u32 val;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300548 struct dvb_frontend_parameters schan;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300549
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300550 schan = *chan;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300551
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300552 /* TODO what is that ? */
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300553
554 /* a channel for autosearch */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300555 schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
556 schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
557 schan.u.ofdm.constellation = QAM_64;
558 schan.u.ofdm.code_rate_HP = FEC_2_3;
559 schan.u.ofdm.code_rate_LP = FEC_2_3;
560 schan.u.ofdm.hierarchy_information = 0;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300561
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300562 dib3000mc_set_channel_cfg(state, &schan, 11);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300563
564 reg = dib3000mc_read_word(state, 0);
565 dib3000mc_write_word(state, 0, reg | (1 << 8));
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300566 dib3000mc_read_word(state, 511);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300567 dib3000mc_write_word(state, 0, reg);
568
569 return 0;
570}
571
572static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod)
573{
574 struct dib3000mc_state *state = demod->demodulator_priv;
575 u16 irq_pending = dib3000mc_read_word(state, 511);
576
577 if (irq_pending & 0x1) // failed
578 return 1;
579
580 if (irq_pending & 0x2) // succeeded
581 return 2;
582
583 return 0; // still pending
584}
585
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300586static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300587{
588 struct dib3000mc_state *state = demod->demodulator_priv;
589
590 // ** configure demod **
591 dib3000mc_set_channel_cfg(state, ch, 0);
592
593 // activates isi
594 dib3000mc_write_word(state, 29, 0x1073);
595
Patrick Boettcher01373a52007-07-30 12:49:04 -0300596 dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300597 if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) {
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300598 dib3000mc_write_word(state, 26, 38528);
599 dib3000mc_write_word(state, 33, 8);
600 } else {
601 dib3000mc_write_word(state, 26, 30336);
602 dib3000mc_write_word(state, 33, 6);
603 }
604
Patrick Boettcher01b4bf32006-09-19 12:51:53 -0300605 if (dib3000mc_read_word(state, 509) & 0x80)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300606 dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300607
608 return 0;
609}
610
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300611struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating)
612{
613 struct dib3000mc_state *st = demod->demodulator_priv;
614 return dibx000_get_i2c_adapter(&st->i2c_master, DIBX000_I2C_INTERFACE_TUNER, gating);
615}
616
617EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master);
618
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619static int dib3000mc_get_frontend(struct dvb_frontend* fe,
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300620 struct dvb_frontend_parameters *fep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300622 struct dib3000mc_state *state = fe->demodulator_priv;
623 u16 tps = dib3000mc_read_word(state,458);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300625 fep->inversion = INVERSION_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300627 fep->u.ofdm.bandwidth = state->current_bandwidth;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300629 switch ((tps >> 8) & 0x1) {
630 case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
631 case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 }
633
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300634 switch (tps & 0x3) {
635 case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
636 case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
637 case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
638 case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 }
640
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300641 switch ((tps >> 13) & 0x3) {
642 case 0: fep->u.ofdm.constellation = QPSK; break;
643 case 1: fep->u.ofdm.constellation = QAM_16; break;
644 case 2:
645 default: fep->u.ofdm.constellation = QAM_64; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 }
647
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300648 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
649 /* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */
650
651 fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
652 switch ((tps >> 5) & 0x7) {
653 case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
654 case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
655 case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
656 case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
657 case 7:
658 default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
659
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 }
661
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300662 switch ((tps >> 2) & 0x7) {
663 case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
664 case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
665 case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
666 case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
667 case 7:
668 default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
671 return 0;
672}
673
674static int dib3000mc_set_frontend(struct dvb_frontend* fe,
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300675 struct dvb_frontend_parameters *fep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300677 struct dib3000mc_state *state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300679 state->current_bandwidth = fep->u.ofdm.bandwidth;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300680 dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300682 if (fe->ops.tuner_ops.set_params) {
683 fe->ops.tuner_ops.set_params(fe, fep);
684 msleep(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300686
687 if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
688 fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
689 fep->u.ofdm.constellation == QAM_AUTO ||
690 fep->u.ofdm.code_rate_HP == FEC_AUTO) {
691 int i = 100, found;
692
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300693 dib3000mc_autosearch_start(fe, fep);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300694 do {
695 msleep(1);
696 found = dib3000mc_autosearch_is_irq(fe);
697 } while (found == 0 && i--);
698
699 dprintk("autosearch returns: %d\n",found);
700 if (found == 0 || found == 1)
701 return 0; // no channel found
702
703 dib3000mc_get_frontend(fe, fep);
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300704 }
705
706 /* make this a config parameter */
707 dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
708
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300709 return dib3000mc_tune(fe, fep);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710}
711
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300712static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300714 struct dib3000mc_state *state = fe->demodulator_priv;
715 u16 lock = dib3000mc_read_word(state, 509);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
717 *stat = 0;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300718
719 if (lock & 0x8000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 *stat |= FE_HAS_SIGNAL;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300721 if (lock & 0x3000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 *stat |= FE_HAS_CARRIER;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300723 if (lock & 0x0100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 *stat |= FE_HAS_VITERBI;
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300725 if (lock & 0x0010)
726 *stat |= FE_HAS_SYNC;
727 if (lock & 0x0008)
728 *stat |= FE_HAS_LOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
730 return 0;
731}
732
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300733static int dib3000mc_read_ber(struct dvb_frontend *fe, u32 *ber)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300735 struct dib3000mc_state *state = fe->demodulator_priv;
736 *ber = (dib3000mc_read_word(state, 500) << 16) | dib3000mc_read_word(state, 501);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 return 0;
738}
739
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300740static int dib3000mc_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300742 struct dib3000mc_state *state = fe->demodulator_priv;
743 *unc = dib3000mc_read_word(state, 508);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 return 0;
745}
746
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300747static int dib3000mc_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300749 struct dib3000mc_state *state = fe->demodulator_priv;
750 u16 val = dib3000mc_read_word(state, 392);
751 *strength = 65535 - val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 return 0;
753}
754
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr)
756{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300757 *snr = 0x0000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 return 0;
759}
760
761static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
762{
Johannes Stezenbach776338e2005-06-23 22:02:35 -0700763 tune->min_delay_ms = 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 return 0;
765}
766
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300767static void dib3000mc_release(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300769 struct dib3000mc_state *state = fe->demodulator_priv;
770 dibx000_exit_i2c_master(&state->i2c_master);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 kfree(state);
772}
773
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300774int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300776 struct dib3000mc_state *state = fe->demodulator_priv;
777 dib3000mc_write_word(state, 212 + index, onoff ? (1 << 13) | pid : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 return 0;
779}
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300780EXPORT_SYMBOL(dib3000mc_pid_control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300782int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300784 struct dib3000mc_state *state = fe->demodulator_priv;
785 u16 tmp = dib3000mc_read_word(state, 206) & ~(1 << 4);
786 tmp |= (onoff << 4);
787 return dib3000mc_write_word(state, 206, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788}
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300789EXPORT_SYMBOL(dib3000mc_pid_parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300791void dib3000mc_set_config(struct dvb_frontend *fe, struct dib3000mc_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792{
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300793 struct dib3000mc_state *state = fe->demodulator_priv;
794 state->cfg = cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795}
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300796EXPORT_SYMBOL(dib3000mc_set_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300798int 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 -0700799{
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300800 struct dib3000mc_state st = { .i2c_adap = i2c };
801 int k;
802 u8 new_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300804 static u8 DIB3000MC_I2C_ADDRESS[] = {20,22,24,26};
805
806 for (k = no_of_demods-1; k >= 0; k--) {
807 st.cfg = &cfg[k];
808
809 /* designated i2c address */
810 new_addr = DIB3000MC_I2C_ADDRESS[k];
811 st.i2c_addr = new_addr;
812 if (dib3000mc_identify(&st) != 0) {
813 st.i2c_addr = default_addr;
814 if (dib3000mc_identify(&st) != 0) {
815 dprintk("-E- DiB3000P/MC #%d: not identified\n", k);
816 return -ENODEV;
817 }
818 }
819
820 dib3000mc_set_output_mode(&st, OUTMODE_MPEG2_PAR_CONT_CLK);
821
822 // set new i2c address and force divstr (Bit 1) to value 0 (Bit 0)
823 dib3000mc_write_word(&st, 1024, (new_addr << 3) | 0x1);
824 st.i2c_addr = new_addr;
825 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300827 for (k = 0; k < no_of_demods; k++) {
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300828 st.cfg = &cfg[k];
829 st.i2c_addr = DIB3000MC_I2C_ADDRESS[k];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300831 dib3000mc_write_word(&st, 1024, st.i2c_addr << 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300833 /* turn off data output */
834 dib3000mc_set_output_mode(&st, OUTMODE_HIGH_Z);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 }
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300836 return 0;
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300837}
838EXPORT_SYMBOL(dib3000mc_i2c_enumeration);
839
840static struct dvb_frontend_ops dib3000mc_ops;
841
842struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg)
843{
844 struct dvb_frontend *demod;
845 struct dib3000mc_state *st;
846 st = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);
847 if (st == NULL)
848 return NULL;
849
850 st->cfg = cfg;
851 st->i2c_adap = i2c_adap;
Patrick Boettcher6958eff2006-09-19 12:51:40 -0300852 st->i2c_addr = i2c_addr;
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300853
854 demod = &st->demod;
855 demod->demodulator_priv = st;
856 memcpy(&st->demod.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
857
858 if (dib3000mc_identify(st) != 0)
859 goto error;
860
861 dibx000_init_i2c_master(&st->i2c_master, DIB3000MC, st->i2c_adap, st->i2c_addr);
862
Patrick Boettcher303cbea2006-09-19 12:51:56 -0300863 dib3000mc_write_word(st, 1037, 0x3130);
864
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300865 return demod;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
867error:
Patrick Boettcher136cafb2006-09-19 12:51:33 -0300868 kfree(st);
869 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870}
Patrick Boettchere4d6c1f2006-08-08 15:48:09 -0300871EXPORT_SYMBOL(dib3000mc_attach);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
873static struct dvb_frontend_ops dib3000mc_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 .info = {
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300875 .name = "DiBcom 3000MC/P",
876 .type = FE_OFDM,
877 .frequency_min = 44250000,
878 .frequency_max = 867250000,
879 .frequency_stepsize = 62500,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 .caps = FE_CAN_INVERSION_AUTO |
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300881 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
882 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
883 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
884 FE_CAN_TRANSMISSION_MODE_AUTO |
885 FE_CAN_GUARD_INTERVAL_AUTO |
886 FE_CAN_RECOVER |
887 FE_CAN_HIERARCHY_AUTO,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 },
889
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300890 .release = dib3000mc_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300892 .init = dib3000mc_init,
893 .sleep = dib3000mc_sleep,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300895 .set_frontend = dib3000mc_set_frontend,
896 .get_tune_settings = dib3000mc_fe_get_tune_settings,
897 .get_frontend = dib3000mc_get_frontend,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300899 .read_status = dib3000mc_read_status,
900 .read_ber = dib3000mc_read_ber,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 .read_signal_strength = dib3000mc_read_signal_strength,
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300902 .read_snr = dib3000mc_read_snr,
903 .read_ucblocks = dib3000mc_read_unc_blocks,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904};
905
Patrick Boettcherb7571f82006-08-08 15:48:10 -0300906MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
907MODULE_DESCRIPTION("Driver for the DiBcom 3000MC/P COFDM demodulator");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908MODULE_LICENSE("GPL");