blob: 73b47cc6a13b3b8c2f6ca85d0ee1d9eee71120c1 [file] [log] [blame]
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -03001/* DVB compliant Linux driver for the DVB-S si2109/2110 demodulator
2*
3* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
4*
5* This program is free software; you can redistribute it and/or modify
6* it under the terms of the GNU General Public License as published by
7* the Free Software Foundation; either version 2 of the License, or
8* (at your option) any later version.
9*
10*/
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -030011#include <linux/init.h>
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/string.h>
15#include <linux/slab.h>
16#include <linux/jiffies.h>
17#include <asm/div64.h>
18
19#include "dvb_frontend.h"
20#include "si21xx.h"
21
22#define REVISION_REG 0x00
23#define SYSTEM_MODE_REG 0x01
24#define TS_CTRL_REG_1 0x02
25#define TS_CTRL_REG_2 0x03
26#define PIN_CTRL_REG_1 0x04
27#define PIN_CTRL_REG_2 0x05
28#define LOCK_STATUS_REG_1 0x0f
29#define LOCK_STATUS_REG_2 0x10
30#define ACQ_STATUS_REG 0x11
31#define ACQ_CTRL_REG_1 0x13
32#define ACQ_CTRL_REG_2 0x14
33#define PLL_DIVISOR_REG 0x15
34#define COARSE_TUNE_REG 0x16
35#define FINE_TUNE_REG_L 0x17
36#define FINE_TUNE_REG_H 0x18
37
38#define ANALOG_AGC_POWER_LEVEL_REG 0x28
39#define CFO_ESTIMATOR_CTRL_REG_1 0x29
40#define CFO_ESTIMATOR_CTRL_REG_2 0x2a
41#define CFO_ESTIMATOR_CTRL_REG_3 0x2b
42
43#define SYM_RATE_ESTIMATE_REG_L 0x31
44#define SYM_RATE_ESTIMATE_REG_M 0x32
45#define SYM_RATE_ESTIMATE_REG_H 0x33
46
47#define CFO_ESTIMATOR_OFFSET_REG_L 0x36
48#define CFO_ESTIMATOR_OFFSET_REG_H 0x37
49#define CFO_ERROR_REG_L 0x38
50#define CFO_ERROR_REG_H 0x39
51#define SYM_RATE_ESTIMATOR_CTRL_REG 0x3a
52
53#define SYM_RATE_REG_L 0x3f
54#define SYM_RATE_REG_M 0x40
55#define SYM_RATE_REG_H 0x41
56#define SYM_RATE_ESTIMATOR_MAXIMUM_REG 0x42
57#define SYM_RATE_ESTIMATOR_MINIMUM_REG 0x43
58
59#define C_N_ESTIMATOR_CTRL_REG 0x7c
60#define C_N_ESTIMATOR_THRSHLD_REG 0x7d
61#define C_N_ESTIMATOR_LEVEL_REG_L 0x7e
62#define C_N_ESTIMATOR_LEVEL_REG_H 0x7f
63
64#define BLIND_SCAN_CTRL_REG 0x80
65
66#define LSA_CTRL_REG_1 0x8D
67#define SPCTRM_TILT_CORR_THRSHLD_REG 0x8f
68#define ONE_DB_BNDWDTH_THRSHLD_REG 0x90
69#define TWO_DB_BNDWDTH_THRSHLD_REG 0x91
70#define THREE_DB_BNDWDTH_THRSHLD_REG 0x92
71#define INBAND_POWER_THRSHLD_REG 0x93
72#define REF_NOISE_LVL_MRGN_THRSHLD_REG 0x94
73
74#define VIT_SRCH_CTRL_REG_1 0xa0
75#define VIT_SRCH_CTRL_REG_2 0xa1
76#define VIT_SRCH_CTRL_REG_3 0xa2
77#define VIT_SRCH_STATUS_REG 0xa3
78#define VITERBI_BER_COUNT_REG_L 0xab
79#define REED_SOLOMON_CTRL_REG 0xb0
80#define REED_SOLOMON_ERROR_COUNT_REG_L 0xb1
81#define PRBS_CTRL_REG 0xb5
82
83#define LNB_CTRL_REG_1 0xc0
84#define LNB_CTRL_REG_2 0xc1
85#define LNB_CTRL_REG_3 0xc2
86#define LNB_CTRL_REG_4 0xc3
87#define LNB_CTRL_STATUS_REG 0xc4
88#define LNB_FIFO_REGS_0 0xc5
89#define LNB_FIFO_REGS_1 0xc6
90#define LNB_FIFO_REGS_2 0xc7
91#define LNB_FIFO_REGS_3 0xc8
92#define LNB_FIFO_REGS_4 0xc9
93#define LNB_FIFO_REGS_5 0xca
94#define LNB_SUPPLY_CTRL_REG_1 0xcb
95#define LNB_SUPPLY_CTRL_REG_2 0xcc
96#define LNB_SUPPLY_CTRL_REG_3 0xcd
97#define LNB_SUPPLY_CTRL_REG_4 0xce
98#define LNB_SUPPLY_STATUS_REG 0xcf
99
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -0300100#define FAIL -1
101#define PASS 0
102
103#define ALLOWABLE_FS_COUNT 10
104#define STATUS_BER 0
105#define STATUS_UCBLOCKS 1
106
107static int debug;
108#define dprintk(args...) \
109 do { \
110 if (debug) \
111 printk(KERN_DEBUG "si21xx: " args); \
112 } while (0)
113
114enum {
115 ACTIVE_HIGH,
116 ACTIVE_LOW
117};
118enum {
119 BYTE_WIDE,
120 BIT_WIDE
121};
122enum {
123 CLK_GAPPED_MODE,
124 CLK_CONTINUOUS_MODE
125};
126enum {
127 RISING_EDGE,
128 FALLING_EDGE
129};
130enum {
131 MSB_FIRST,
132 LSB_FIRST
133};
134enum {
135 SERIAL,
136 PARALLEL
137};
138
139struct si21xx_state {
140 struct i2c_adapter *i2c;
141 const struct si21xx_config *config;
142 struct dvb_frontend frontend;
143 u8 initialised:1;
144 int errmode;
145 int fs; /*Sampling rate of the ADC in MHz*/
146};
147
148/* register default initialization */
149static u8 serit_sp1511lhb_inittab[] = {
150 0x01, 0x28, /* set i2c_inc_disable */
151 0x20, 0x03,
152 0x27, 0x20,
153 0xe0, 0x45,
154 0xe1, 0x08,
155 0xfe, 0x01,
156 0x01, 0x28,
157 0x89, 0x09,
158 0x04, 0x80,
159 0x05, 0x01,
160 0x06, 0x00,
161 0x20, 0x03,
162 0x24, 0x88,
163 0x29, 0x09,
164 0x2a, 0x0f,
165 0x2c, 0x10,
166 0x2d, 0x19,
167 0x2e, 0x08,
168 0x2f, 0x10,
169 0x30, 0x19,
170 0x34, 0x20,
171 0x35, 0x03,
172 0x45, 0x02,
173 0x46, 0x45,
174 0x47, 0xd0,
175 0x48, 0x00,
176 0x49, 0x40,
177 0x4a, 0x03,
178 0x4c, 0xfd,
179 0x4f, 0x2e,
180 0x50, 0x2e,
181 0x51, 0x10,
182 0x52, 0x10,
183 0x56, 0x92,
184 0x59, 0x00,
185 0x5a, 0x2d,
186 0x5b, 0x33,
187 0x5c, 0x1f,
188 0x5f, 0x76,
189 0x62, 0xc0,
190 0x63, 0xc0,
191 0x64, 0xf3,
192 0x65, 0xf3,
193 0x79, 0x40,
194 0x6a, 0x40,
195 0x6b, 0x0a,
196 0x6c, 0x80,
197 0x6d, 0x27,
198 0x71, 0x06,
199 0x75, 0x60,
200 0x78, 0x00,
201 0x79, 0xb5,
202 0x7c, 0x05,
203 0x7d, 0x1a,
204 0x87, 0x55,
205 0x88, 0x72,
206 0x8f, 0x08,
207 0x90, 0xe0,
208 0x94, 0x40,
209 0xa0, 0x3f,
210 0xa1, 0xc0,
211 0xa4, 0xcc,
212 0xa5, 0x66,
213 0xa6, 0x66,
214 0xa7, 0x7b,
215 0xa8, 0x7b,
216 0xa9, 0x7b,
217 0xaa, 0x9a,
218 0xed, 0x04,
219 0xad, 0x00,
220 0xae, 0x03,
221 0xcc, 0xab,
222 0x01, 0x08,
223 0xff, 0xff
224};
225
226/* low level read/writes */
227static int si21_writeregs(struct si21xx_state *state, u8 reg1,
228 u8 *data, int len)
229{
230 int ret;
231 u8 buf[60];/* = { reg1, data };*/
232 struct i2c_msg msg = {
233 .addr = state->config->demod_address,
234 .flags = 0,
235 .buf = buf,
236 .len = len + 1
237 };
238
239 msg.buf[0] = reg1;
240 memcpy(msg.buf + 1, data, len);
241
242 ret = i2c_transfer(state->i2c, &msg, 1);
243
244 if (ret != 1)
245 dprintk("%s: writereg error (reg1 == 0x%02x, data == 0x%02x, "
246 "ret == %i)\n", __func__, reg1, data[0], ret);
247
248 return (ret != 1) ? -EREMOTEIO : 0;
249}
250
251static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data)
252{
253 int ret;
254 u8 buf[] = { reg, data };
255 struct i2c_msg msg = {
256 .addr = state->config->demod_address,
257 .flags = 0,
258 .buf = buf,
259 .len = 2
260 };
261
262 ret = i2c_transfer(state->i2c, &msg, 1);
263
264 if (ret != 1)
265 dprintk("%s: writereg error (reg == 0x%02x, data == 0x%02x, "
266 "ret == %i)\n", __func__, reg, data, ret);
267
268 return (ret != 1) ? -EREMOTEIO : 0;
269}
270
lawrence rust2e4e98e2010-08-25 09:50:20 -0300271static int si21_write(struct dvb_frontend *fe, const u8 buf[], int len)
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -0300272{
273 struct si21xx_state *state = fe->demodulator_priv;
274
275 if (len != 2)
276 return -EINVAL;
277
278 return si21_writereg(state, buf[0], buf[1]);
279}
280
281static u8 si21_readreg(struct si21xx_state *state, u8 reg)
282{
283 int ret;
284 u8 b0[] = { reg };
285 u8 b1[] = { 0 };
286 struct i2c_msg msg[] = {
287 {
288 .addr = state->config->demod_address,
289 .flags = 0,
290 .buf = b0,
291 .len = 1
292 }, {
293 .addr = state->config->demod_address,
294 .flags = I2C_M_RD,
295 .buf = b1,
296 .len = 1
297 }
298 };
299
300 ret = i2c_transfer(state->i2c, msg, 2);
301
302 if (ret != 2)
303 dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
304 __func__, reg, ret);
305
306 return b1[0];
307}
308
309static int si21_readregs(struct si21xx_state *state, u8 reg1, u8 *b, u8 len)
310{
311 int ret;
312 struct i2c_msg msg[] = {
313 {
314 .addr = state->config->demod_address,
315 .flags = 0,
316 .buf = &reg1,
317 .len = 1
318 }, {
319 .addr = state->config->demod_address,
320 .flags = I2C_M_RD,
321 .buf = b,
322 .len = len
323 }
324 };
325
326 ret = i2c_transfer(state->i2c, msg, 2);
327
328 if (ret != 2)
329 dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
330
331 return ret == 2 ? 0 : -1;
332}
333
334static int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout)
335{
336 unsigned long start = jiffies;
337
338 dprintk("%s\n", __func__);
339
340 while ((si21_readreg(state, LNB_CTRL_REG_1) & 0x8) == 8) {
341 if (jiffies - start > timeout) {
342 dprintk("%s: timeout!!\n", __func__);
343 return -ETIMEDOUT;
344 }
345 msleep(10);
Peter Senna Tschudinc2c1b412012-09-28 05:37:22 -0300346 }
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -0300347
348 return 0;
349}
350
351static int si21xx_set_symbolrate(struct dvb_frontend *fe, u32 srate)
352{
353 struct si21xx_state *state = fe->demodulator_priv;
354 u32 sym_rate, data_rate;
355 int i;
356 u8 sym_rate_bytes[3];
357
358 dprintk("%s : srate = %i\n", __func__ , srate);
359
360 if ((srate < 1000000) || (srate > 45000000))
361 return -EINVAL;
362
363 data_rate = srate;
364 sym_rate = 0;
365
366 for (i = 0; i < 4; ++i) {
367 sym_rate /= 100;
368 sym_rate = sym_rate + ((data_rate % 100) * 0x800000) /
369 state->fs;
370 data_rate /= 100;
371 }
372 for (i = 0; i < 3; ++i)
373 sym_rate_bytes[i] = (u8)((sym_rate >> (i * 8)) & 0xff);
374
375 si21_writeregs(state, SYM_RATE_REG_L, sym_rate_bytes, 0x03);
376
377 return 0;
378}
379
380static int si21xx_send_diseqc_msg(struct dvb_frontend *fe,
381 struct dvb_diseqc_master_cmd *m)
382{
383 struct si21xx_state *state = fe->demodulator_priv;
384 u8 lnb_status;
385 u8 LNB_CTRL_1;
386 int status;
387
388 dprintk("%s\n", __func__);
389
390 status = PASS;
391 LNB_CTRL_1 = 0;
392
393 status |= si21_readregs(state, LNB_CTRL_STATUS_REG, &lnb_status, 0x01);
394 status |= si21_readregs(state, LNB_CTRL_REG_1, &lnb_status, 0x01);
395
396 /*fill the FIFO*/
397 status |= si21_writeregs(state, LNB_FIFO_REGS_0, m->msg, m->msg_len);
398
399 LNB_CTRL_1 = (lnb_status & 0x70);
400 LNB_CTRL_1 |= m->msg_len;
401
402 LNB_CTRL_1 |= 0x80; /* begin LNB signaling */
403
404 status |= si21_writeregs(state, LNB_CTRL_REG_1, &LNB_CTRL_1, 0x01);
405
406 return status;
407}
408
409static int si21xx_send_diseqc_burst(struct dvb_frontend *fe,
410 fe_sec_mini_cmd_t burst)
411{
412 struct si21xx_state *state = fe->demodulator_priv;
413 u8 val;
414
415 dprintk("%s\n", __func__);
416
417 if (si21xx_wait_diseqc_idle(state, 100) < 0)
418 return -ETIMEDOUT;
419
420 val = (0x80 | si21_readreg(state, 0xc1));
421 if (si21_writereg(state, LNB_CTRL_REG_1,
422 burst == SEC_MINI_A ? (val & ~0x10) : (val | 0x10)))
423 return -EREMOTEIO;
424
425 if (si21xx_wait_diseqc_idle(state, 100) < 0)
426 return -ETIMEDOUT;
427
428 if (si21_writereg(state, LNB_CTRL_REG_1, val))
429 return -EREMOTEIO;
430
431 return 0;
432}
433/* 30.06.2008 */
434static int si21xx_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
435{
436 struct si21xx_state *state = fe->demodulator_priv;
437 u8 val;
438
439 dprintk("%s\n", __func__);
440 val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1));
441
442 switch (tone) {
443 case SEC_TONE_ON:
444 return si21_writereg(state, LNB_CTRL_REG_1, val | 0x20);
445
446 case SEC_TONE_OFF:
447 return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x20));
448
449 default:
450 return -EINVAL;
451 }
452}
453
454static int si21xx_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
455{
456 struct si21xx_state *state = fe->demodulator_priv;
457
458 u8 val;
459 dprintk("%s: %s\n", __func__,
460 volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
461 volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
462
463
464 val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1));
465
466 switch (volt) {
467 case SEC_VOLTAGE_18:
468 return si21_writereg(state, LNB_CTRL_REG_1, val | 0x40);
469 break;
470 case SEC_VOLTAGE_13:
471 return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x40));
472 break;
473 default:
474 return -EINVAL;
Peter Senna Tschudinc2c1b412012-09-28 05:37:22 -0300475 }
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -0300476}
477
478static int si21xx_init(struct dvb_frontend *fe)
479{
480 struct si21xx_state *state = fe->demodulator_priv;
481 int i;
482 int status = 0;
483 u8 reg1;
484 u8 val;
485 u8 reg2[2];
486
487 dprintk("%s\n", __func__);
488
489 for (i = 0; ; i += 2) {
490 reg1 = serit_sp1511lhb_inittab[i];
491 val = serit_sp1511lhb_inittab[i+1];
492 if (reg1 == 0xff && val == 0xff)
493 break;
494 si21_writeregs(state, reg1, &val, 1);
495 }
496
497 /*DVB QPSK SYSTEM MODE REG*/
498 reg1 = 0x08;
499 si21_writeregs(state, SYSTEM_MODE_REG, &reg1, 0x01);
500
501 /*transport stream config*/
502 /*
503 mode = PARALLEL;
504 sdata_form = LSB_FIRST;
505 clk_edge = FALLING_EDGE;
506 clk_mode = CLK_GAPPED_MODE;
507 strt_len = BYTE_WIDE;
508 sync_pol = ACTIVE_HIGH;
509 val_pol = ACTIVE_HIGH;
510 err_pol = ACTIVE_HIGH;
511 sclk_rate = 0x00;
512 parity = 0x00 ;
513 data_delay = 0x00;
514 clk_delay = 0x00;
515 pclk_smooth = 0x00;
516 */
517 reg2[0] =
518 PARALLEL + (LSB_FIRST << 1)
519 + (FALLING_EDGE << 2) + (CLK_GAPPED_MODE << 3)
520 + (BYTE_WIDE << 4) + (ACTIVE_HIGH << 5)
521 + (ACTIVE_HIGH << 6) + (ACTIVE_HIGH << 7);
522
523 reg2[1] = 0;
524 /* sclk_rate + (parity << 2)
525 + (data_delay << 3) + (clk_delay << 4)
526 + (pclk_smooth << 5);
527 */
528 status |= si21_writeregs(state, TS_CTRL_REG_1, reg2, 0x02);
529 if (status != 0)
530 dprintk(" %s : TS Set Error\n", __func__);
531
532 return 0;
533
534}
535
536static int si21_read_status(struct dvb_frontend *fe, fe_status_t *status)
537{
538 struct si21xx_state *state = fe->demodulator_priv;
539 u8 regs_read[2];
540 u8 reg_read;
541 u8 i;
542 u8 lock;
543 u8 signal = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG);
544
545 si21_readregs(state, LOCK_STATUS_REG_1, regs_read, 0x02);
546 reg_read = 0;
547
548 for (i = 0; i < 7; ++i)
549 reg_read |= ((regs_read[0] >> i) & 0x01) << (6 - i);
550
551 lock = ((reg_read & 0x7f) | (regs_read[1] & 0x80));
552
553 dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, lock);
554 *status = 0;
555
556 if (signal > 10)
557 *status |= FE_HAS_SIGNAL;
558
559 if (lock & 0x2)
560 *status |= FE_HAS_CARRIER;
561
562 if (lock & 0x20)
563 *status |= FE_HAS_VITERBI;
564
565 if (lock & 0x40)
566 *status |= FE_HAS_SYNC;
567
568 if ((lock & 0x7b) == 0x7b)
569 *status |= FE_HAS_LOCK;
570
571 return 0;
572}
573
574static int si21_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
575{
576 struct si21xx_state *state = fe->demodulator_priv;
577
578 /*status = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG,
579 (u8*)agclevel, 0x01);*/
580
581 u16 signal = (3 * si21_readreg(state, 0x27) *
582 si21_readreg(state, 0x28));
583
584 dprintk("%s : AGCPWR: 0x%02x%02x, signal=0x%04x\n", __func__,
585 si21_readreg(state, 0x27),
586 si21_readreg(state, 0x28), (int) signal);
587
588 signal <<= 4;
589 *strength = signal;
590
591 return 0;
592}
593
594static int si21_read_ber(struct dvb_frontend *fe, u32 *ber)
595{
596 struct si21xx_state *state = fe->demodulator_priv;
597
598 dprintk("%s\n", __func__);
599
600 if (state->errmode != STATUS_BER)
601 return 0;
602
603 *ber = (si21_readreg(state, 0x1d) << 8) |
604 si21_readreg(state, 0x1e);
605
606 return 0;
607}
608
609static int si21_read_snr(struct dvb_frontend *fe, u16 *snr)
610{
611 struct si21xx_state *state = fe->demodulator_priv;
612
613 s32 xsnr = 0xffff - ((si21_readreg(state, 0x24) << 8) |
614 si21_readreg(state, 0x25));
615 xsnr = 3 * (xsnr - 0xa100);
616 *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
617
618 dprintk("%s\n", __func__);
619
620 return 0;
621}
622
623static int si21_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
624{
625 struct si21xx_state *state = fe->demodulator_priv;
626
627 dprintk("%s\n", __func__);
628
629 if (state->errmode != STATUS_UCBLOCKS)
630 *ucblocks = 0;
631 else
632 *ucblocks = (si21_readreg(state, 0x1d) << 8) |
633 si21_readreg(state, 0x1e);
634
635 return 0;
636}
637
638/* initiates a channel acquisition sequence
639 using the specified symbol rate and code rate */
640static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate,
641 fe_code_rate_t crate)
642{
643
644 struct si21xx_state *state = fe->demodulator_priv;
645 u8 coderates[] = {
646 0x0, 0x01, 0x02, 0x04, 0x00,
647 0x8, 0x10, 0x20, 0x00, 0x3f
648 };
649
650 u8 coderate_ptr;
651 int status;
652 u8 start_acq = 0x80;
653 u8 reg, regs[3];
654
655 dprintk("%s\n", __func__);
656
657 status = PASS;
658 coderate_ptr = coderates[crate];
659
660 si21xx_set_symbolrate(fe, symbrate);
661
662 /* write code rates to use in the Viterbi search */
663 status |= si21_writeregs(state,
664 VIT_SRCH_CTRL_REG_1,
665 &coderate_ptr, 0x01);
666
667 /* clear acq_start bit */
668 status |= si21_readregs(state, ACQ_CTRL_REG_2, &reg, 0x01);
669 reg &= ~start_acq;
670 status |= si21_writeregs(state, ACQ_CTRL_REG_2, &reg, 0x01);
671
672 /* use new Carrier Frequency Offset Estimator (QuickLock) */
673 regs[0] = 0xCB;
674 regs[1] = 0x40;
675 regs[2] = 0xCB;
676
677 status |= si21_writeregs(state,
678 TWO_DB_BNDWDTH_THRSHLD_REG,
679 &regs[0], 0x03);
680 reg = 0x56;
681 status |= si21_writeregs(state,
682 LSA_CTRL_REG_1, &reg, 1);
683 reg = 0x05;
684 status |= si21_writeregs(state,
685 BLIND_SCAN_CTRL_REG, &reg, 1);
686 /* start automatic acq */
687 status |= si21_writeregs(state,
688 ACQ_CTRL_REG_2, &start_acq, 0x01);
689
690 return status;
691}
692
Mauro Carvalho Chehab14e3dcc2011-12-26 14:11:35 -0300693static int si21xx_set_frontend(struct dvb_frontend *fe)
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -0300694{
695 struct si21xx_state *state = fe->demodulator_priv;
696 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
697
698 /* freq Channel carrier frequency in KHz (i.e. 1550000 KHz)
699 datarate Channel symbol rate in Sps (i.e. 22500000 Sps)*/
700
701 /* in MHz */
702 unsigned char coarse_tune_freq;
703 int fine_tune_freq;
704 unsigned char sample_rate = 0;
705 /* boolean */
Joe Perches42a39e02010-01-13 03:59:15 -0300706 bool inband_interferer_ind;
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -0300707
708 /* INTERMEDIATE VALUES */
709 int icoarse_tune_freq; /* MHz */
710 int ifine_tune_freq; /* MHz */
711 unsigned int band_high;
712 unsigned int band_low;
713 unsigned int x1;
714 unsigned int x2;
715 int i;
Joe Perches42a39e02010-01-13 03:59:15 -0300716 bool inband_interferer_div2[ALLOWABLE_FS_COUNT];
717 bool inband_interferer_div4[ALLOWABLE_FS_COUNT];
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -0300718 int status;
719
720 /* allowable sample rates for ADC in MHz */
721 int afs[ALLOWABLE_FS_COUNT] = { 200, 192, 193, 194, 195,
722 196, 204, 205, 206, 207
723 };
724 /* in MHz */
725 int if_limit_high;
726 int if_limit_low;
727 int lnb_lo;
728 int lnb_uncertanity;
729
730 int rf_freq;
731 int data_rate;
732 unsigned char regs[4];
733
734 dprintk("%s : FE_SET_FRONTEND\n", __func__);
735
736 if (c->delivery_system != SYS_DVBS) {
737 dprintk("%s: unsupported delivery system selected (%d)\n",
738 __func__, c->delivery_system);
739 return -EOPNOTSUPP;
740 }
741
742 for (i = 0; i < ALLOWABLE_FS_COUNT; ++i)
Joe Perches42a39e02010-01-13 03:59:15 -0300743 inband_interferer_div2[i] = inband_interferer_div4[i] = false;
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -0300744
745 if_limit_high = -700000;
746 if_limit_low = -100000;
747 /* in MHz */
748 lnb_lo = 0;
749 lnb_uncertanity = 0;
750
751 rf_freq = 10 * c->frequency ;
752 data_rate = c->symbol_rate / 100;
753
754 status = PASS;
755
756 band_low = (rf_freq - lnb_lo) - ((lnb_uncertanity * 200)
757 + (data_rate * 135)) / 200;
758
759 band_high = (rf_freq - lnb_lo) + ((lnb_uncertanity * 200)
760 + (data_rate * 135)) / 200;
761
762
763 icoarse_tune_freq = 100000 *
764 (((rf_freq - lnb_lo) -
765 (if_limit_low + if_limit_high) / 2)
766 / 100000);
767
768 ifine_tune_freq = (rf_freq - lnb_lo) - icoarse_tune_freq ;
769
770 for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
771 x1 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) *
772 (afs[i] * 2500) + afs[i] * 2500;
773
774 x2 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) *
775 (afs[i] * 2500);
776
777 if (((band_low < x1) && (x1 < band_high)) ||
778 ((band_low < x2) && (x2 < band_high)))
Joe Perches42a39e02010-01-13 03:59:15 -0300779 inband_interferer_div4[i] = true;
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -0300780
781 }
782
783 for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
784 x1 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) *
785 (afs[i] * 5000) + afs[i] * 5000;
786
787 x2 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) *
788 (afs[i] * 5000);
789
790 if (((band_low < x1) && (x1 < band_high)) ||
791 ((band_low < x2) && (x2 < band_high)))
Joe Perches42a39e02010-01-13 03:59:15 -0300792 inband_interferer_div2[i] = true;
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -0300793 }
794
Joe Perches42a39e02010-01-13 03:59:15 -0300795 inband_interferer_ind = true;
796 for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
797 if (inband_interferer_div2[i] || inband_interferer_div4[i]) {
798 inband_interferer_ind = false;
799 break;
800 }
801 }
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -0300802
803 if (inband_interferer_ind) {
804 for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
Joe Perches42a39e02010-01-13 03:59:15 -0300805 if (!inband_interferer_div2[i]) {
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -0300806 sample_rate = (u8) afs[i];
807 break;
808 }
809 }
810 } else {
811 for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
Joe Perches42a39e02010-01-13 03:59:15 -0300812 if ((inband_interferer_div2[i] ||
813 !inband_interferer_div4[i])) {
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -0300814 sample_rate = (u8) afs[i];
815 break;
816 }
817 }
818
819 }
820
821 if (sample_rate > 207 || sample_rate < 192)
822 sample_rate = 200;
823
824 fine_tune_freq = ((0x4000 * (ifine_tune_freq / 10)) /
825 ((sample_rate) * 1000));
826
827 coarse_tune_freq = (u8)(icoarse_tune_freq / 100000);
828
829 regs[0] = sample_rate;
830 regs[1] = coarse_tune_freq;
831 regs[2] = fine_tune_freq & 0xFF;
832 regs[3] = fine_tune_freq >> 8 & 0xFF;
833
834 status |= si21_writeregs(state, PLL_DIVISOR_REG, &regs[0], 0x04);
835
836 state->fs = sample_rate;/*ADC MHz*/
837 si21xx_setacquire(fe, c->symbol_rate, c->fec_inner);
838
839 return 0;
840}
841
842static int si21xx_sleep(struct dvb_frontend *fe)
843{
844 struct si21xx_state *state = fe->demodulator_priv;
845 u8 regdata;
846
847 dprintk("%s\n", __func__);
848
849 si21_readregs(state, SYSTEM_MODE_REG, &regdata, 0x01);
850 regdata |= 1 << 6;
851 si21_writeregs(state, SYSTEM_MODE_REG, &regdata, 0x01);
852 state->initialised = 0;
853
854 return 0;
855}
856
857static void si21xx_release(struct dvb_frontend *fe)
858{
859 struct si21xx_state *state = fe->demodulator_priv;
860
861 dprintk("%s\n", __func__);
862
863 kfree(state);
864}
865
866static struct dvb_frontend_ops si21xx_ops = {
Mauro Carvalho Chehab14e3dcc2011-12-26 14:11:35 -0300867 .delsys = { SYS_DVBS },
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -0300868 .info = {
869 .name = "SL SI21XX DVB-S",
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -0300870 .frequency_min = 950000,
871 .frequency_max = 2150000,
872 .frequency_stepsize = 125, /* kHz for QPSK frontends */
873 .frequency_tolerance = 0,
874 .symbol_rate_min = 1000000,
875 .symbol_rate_max = 45000000,
876 .symbol_rate_tolerance = 500, /* ppm */
877 .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
878 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
879 FE_CAN_QPSK |
880 FE_CAN_FEC_AUTO
881 },
882
883 .release = si21xx_release,
884 .init = si21xx_init,
885 .sleep = si21xx_sleep,
886 .write = si21_write,
887 .read_status = si21_read_status,
888 .read_ber = si21_read_ber,
889 .read_signal_strength = si21_read_signal_strength,
890 .read_snr = si21_read_snr,
891 .read_ucblocks = si21_read_ucblocks,
892 .diseqc_send_master_cmd = si21xx_send_diseqc_msg,
893 .diseqc_send_burst = si21xx_send_diseqc_burst,
894 .set_tone = si21xx_set_tone,
895 .set_voltage = si21xx_set_voltage,
896
Mauro Carvalho Chehab14e3dcc2011-12-26 14:11:35 -0300897 .set_frontend = si21xx_set_frontend,
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -0300898};
899
900struct dvb_frontend *si21xx_attach(const struct si21xx_config *config,
901 struct i2c_adapter *i2c)
902{
903 struct si21xx_state *state = NULL;
904 int id;
905
906 dprintk("%s\n", __func__);
907
908 /* allocate memory for the internal state */
Matthias Schwarzott084e24a2009-08-10 22:51:01 -0300909 state = kzalloc(sizeof(struct si21xx_state), GFP_KERNEL);
Igor M. Liplianin04ad28c2008-09-16 18:21:11 -0300910 if (state == NULL)
911 goto error;
912
913 /* setup the state */
914 state->config = config;
915 state->i2c = i2c;
916 state->initialised = 0;
917 state->errmode = STATUS_BER;
918
919 /* check if the demod is there */
920 id = si21_readreg(state, SYSTEM_MODE_REG);
921 si21_writereg(state, SYSTEM_MODE_REG, id | 0x40); /* standby off */
922 msleep(200);
923 id = si21_readreg(state, 0x00);
924
925 /* register 0x00 contains:
926 0x34 for SI2107
927 0x24 for SI2108
928 0x14 for SI2109
929 0x04 for SI2110
930 */
931 if (id != 0x04 && id != 0x14)
932 goto error;
933
934 /* create dvb_frontend */
935 memcpy(&state->frontend.ops, &si21xx_ops,
936 sizeof(struct dvb_frontend_ops));
937 state->frontend.demodulator_priv = state;
938 return &state->frontend;
939
940error:
941 kfree(state);
942 return NULL;
943}
944EXPORT_SYMBOL(si21xx_attach);
945
946module_param(debug, int, 0644);
947MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
948
949MODULE_DESCRIPTION("SL SI21XX DVB Demodulator driver");
950MODULE_AUTHOR("Igor M. Liplianin");
951MODULE_LICENSE("GPL");