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