aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAndrew de Quincey <adq_dvb@lidskialf.net>2005-07-07 20:57:53 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-07-07 21:23:57 -0400
commit96bf2f2b549aab918f4225841df54c3d58896822 (patch)
tree4dc2e28fb2b346ef7d4892c7a3c54d28a8d0fa5c /drivers
parent771e71570ce4da549fe89978de0a29e3299d7fb7 (diff)
[PATCH] dvb: ttpci: add support for Technotrend/Hauppauge DVB-S SE
Add support for s5h1420 frontend (new Technotrend/Hauppauge DVB-S SE). Signed-off-by: Andrew de Quincey <adq_dvb@lidskialf.net> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/dvb/frontends/Kconfig6
-rw-r--r--drivers/media/dvb/frontends/Makefile1
-rw-r--r--drivers/media/dvb/frontends/s5h1420.c800
-rw-r--r--drivers/media/dvb/frontends/s5h1420.h41
-rw-r--r--drivers/media/dvb/ttpci/Kconfig9
-rw-r--r--drivers/media/dvb/ttpci/budget.c99
6 files changed, 952 insertions, 4 deletions
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index b4fddf513ebe..5c695937e2ad 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -40,6 +40,12 @@ config DVB_VES1X93
40 help 40 help
41 A DVB-S tuner module. Say Y when you want to support this frontend. 41 A DVB-S tuner module. Say Y when you want to support this frontend.
42 42
43config DVB_S5H1420
44 tristate "Samsung S5H1420 based"
45 depends on DVB_CORE
46 help
47 A DVB-S tuner module. Say Y when you want to support this frontend.
48
43comment "DVB-T (terrestrial) frontends" 49comment "DVB-T (terrestrial) frontends"
44 depends on DVB_CORE 50 depends on DVB_CORE
45 51
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 91d6d3576d3d..8d46dd721f45 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -29,3 +29,4 @@ obj-$(CONFIG_DVB_NXT2002) += nxt2002.o
29obj-$(CONFIG_DVB_OR51211) += or51211.o 29obj-$(CONFIG_DVB_OR51211) += or51211.o
30obj-$(CONFIG_DVB_OR51132) += or51132.o 30obj-$(CONFIG_DVB_OR51132) += or51132.o
31obj-$(CONFIG_DVB_BCM3510) += bcm3510.o 31obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
32obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
new file mode 100644
index 000000000000..4f396ac8de77
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -0,0 +1,800 @@
1/*
2Driver for Samsung S5H1420 QPSK Demodulator
3
4Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program; if not, write to the Free Software
19Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21*/
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/init.h>
26#include <linux/string.h>
27#include <linux/slab.h>
28#include <linux/delay.h>
29
30#include "dvb_frontend.h"
31#include "s5h1420.h"
32
33
34
35#define TONE_FREQ 22000
36
37struct s5h1420_state {
38 struct i2c_adapter* i2c;
39 struct dvb_frontend_ops ops;
40 const struct s5h1420_config* config;
41 struct dvb_frontend frontend;
42
43 u8 postlocked:1;
44 u32 fclk;
45 u32 tunedfreq;
46 fe_code_rate_t fec_inner;
47 u32 symbol_rate;
48};
49
50static u32 s5h1420_getsymbolrate(struct s5h1420_state* state);
51static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings);
52
53
54static int debug = 0;
55#define dprintk if (debug) printk
56
57static int s5h1420_writereg (struct s5h1420_state* state, u8 reg, u8 data)
58{
59 u8 buf [] = { reg, data };
60 struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
61 int err;
62
63 if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
64 dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
65 return -EREMOTEIO;
66 }
67
68 return 0;
69}
70
71static u8 s5h1420_readreg (struct s5h1420_state* state, u8 reg)
72{
73 int ret;
74 u8 b0 [] = { reg };
75 u8 b1 [] = { 0 };
76 struct i2c_msg msg1 = { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 };
77 struct i2c_msg msg2 = { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 };
78
79 if ((ret = i2c_transfer (state->i2c, &msg1, 1)) != 1)
80 return ret;
81
82 if ((ret = i2c_transfer (state->i2c, &msg2, 1)) != 1)
83 return ret;
84
85 return b1[0];
86}
87
88static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
89{
90 struct s5h1420_state* state = fe->demodulator_priv;
91
92 switch(voltage) {
93 case SEC_VOLTAGE_13:
94 s5h1420_writereg(state, 0x3c, (s5h1420_readreg(state, 0x3c) & 0xfe) | 0x02);
95 break;
96
97 case SEC_VOLTAGE_18:
98 s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) | 0x03);
99 break;
100
101 case SEC_VOLTAGE_OFF:
102 s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) & 0xfd);
103 break;
104 }
105
106 return 0;
107}
108
109static int s5h1420_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
110{
111 struct s5h1420_state* state = fe->demodulator_priv;
112
113 switch(tone) {
114 case SEC_TONE_ON:
115 s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x74) | 0x08);
116 break;
117
118 case SEC_TONE_OFF:
119 s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01);
120 break;
121 }
122
123 return 0;
124}
125
126static int s5h1420_send_master_cmd (struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
127{
128 struct s5h1420_state* state = fe->demodulator_priv;
129 u8 val;
130 int i;
131 unsigned long timeout;
132 int result = 0;
133
134 /* setup for DISEQC */
135 val = s5h1420_readreg(state, 0x3b);
136 s5h1420_writereg(state, 0x3b, 0x02);
137 msleep(15);
138
139 /* write the DISEQC command bytes */
140 for(i=0; i< cmd->msg_len; i++) {
141 s5h1420_writereg(state, 0x3c + i, cmd->msg[i]);
142 }
143
144 /* kick off transmission */
145 s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | ((cmd->msg_len-1) << 4) | 0x08);
146
147 /* wait for transmission to complete */
148 timeout = jiffies + ((100*HZ) / 1000);
149 while(time_before(jiffies, timeout)) {
150 if (s5h1420_readreg(state, 0x3b) & 0x08)
151 break;
152
153 msleep(5);
154 }
155 if (time_after(jiffies, timeout))
156 result = -ETIMEDOUT;
157
158 /* restore original settings */
159 s5h1420_writereg(state, 0x3b, val);
160 msleep(15);
161 return result;
162}
163
164static int s5h1420_recv_slave_reply (struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply)
165{
166 struct s5h1420_state* state = fe->demodulator_priv;
167 u8 val;
168 int i;
169 int length;
170 unsigned long timeout;
171 int result = 0;
172
173 /* setup for DISEQC recieve */
174 val = s5h1420_readreg(state, 0x3b);
175 s5h1420_writereg(state, 0x3b, 0x82); /* FIXME: guess - do we need to set DIS_RDY(0x08) in receive mode? */
176 msleep(15);
177
178 /* wait for reception to complete */
179 timeout = jiffies + ((reply->timeout*HZ) / 1000);
180 while(time_before(jiffies, timeout)) {
181 if (!(s5h1420_readreg(state, 0x3b) & 0x80)) /* FIXME: do we test DIS_RDY(0x08) or RCV_EN(0x80)? */
182 break;
183
184 msleep(5);
185 }
186 if (time_after(jiffies, timeout)) {
187 result = -ETIMEDOUT;
188 goto exit;
189 }
190
191 /* check error flag - FIXME: not sure what this does - docs do not describe
192 * beyond "error flag for diseqc receive data :( */
193 if (s5h1420_readreg(state, 0x49)) {
194 result = -EIO;
195 goto exit;
196 }
197
198 /* check length */
199 length = (s5h1420_readreg(state, 0x3b) & 0x70) >> 4;
200 if (length > sizeof(reply->msg)) {
201 result = -EOVERFLOW;
202 goto exit;
203 }
204 reply->msg_len = length;
205
206 /* extract data */
207 for(i=0; i< length; i++) {
208 reply->msg[i] = s5h1420_readreg(state, 0x3c + i);
209 }
210
211exit:
212 /* restore original settings */
213 s5h1420_writereg(state, 0x3b, val);
214 msleep(15);
215 return result;
216}
217
218static int s5h1420_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
219{
220 struct s5h1420_state* state = fe->demodulator_priv;
221 u8 val;
222 int result = 0;
223 unsigned long timeout;
224
225 /* setup for tone burst */
226 val = s5h1420_readreg(state, 0x3b);
227 s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x70) | 0x01);
228
229 /* set value for B position if requested */
230 if (minicmd == SEC_MINI_B) {
231 s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x04);
232 }
233 msleep(15);
234
235 /* start transmission */
236 s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x08);
237
238 /* wait for transmission to complete */
239 timeout = jiffies + ((20*HZ) / 1000);
240 while(time_before(jiffies, timeout)) {
241 if (!(s5h1420_readreg(state, 0x3b) & 0x08))
242 break;
243
244 msleep(5);
245 }
246 if (time_after(jiffies, timeout))
247 result = -ETIMEDOUT;
248
249 /* restore original settings */
250 s5h1420_writereg(state, 0x3b, val);
251 msleep(15);
252 return result;
253}
254
255static fe_status_t s5h1420_get_status_bits(struct s5h1420_state* state)
256{
257 u8 val;
258 fe_status_t status = 0;
259
260 val = s5h1420_readreg(state, 0x14);
261 if (val & 0x02)
262 status |= FE_HAS_SIGNAL; // FIXME: not sure if this is right
263 if (val & 0x01)
264 status |= FE_HAS_CARRIER; // FIXME: not sure if this is right
265 val = s5h1420_readreg(state, 0x36);
266 if (val & 0x01)
267 status |= FE_HAS_VITERBI;
268 if (val & 0x20)
269 status |= FE_HAS_SYNC;
270 if (status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI|FE_HAS_SYNC))
271 status |= FE_HAS_LOCK;
272
273 return status;
274}
275
276static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status)
277{
278 struct s5h1420_state* state = fe->demodulator_priv;
279 u8 val;
280
281 if (status == NULL)
282 return -EINVAL;
283
284 /* determine lock state */
285 *status = s5h1420_get_status_bits(state);
286
287 /* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert the inversion,
288 wait a bit and check again */
289 if (*status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI)) {
290 val = s5h1420_readreg(state, 0x32);
291 if ((val & 0x07) == 0x03) {
292 if (val & 0x08)
293 s5h1420_writereg(state, 0x31, 0x13);
294 else
295 s5h1420_writereg(state, 0x31, 0x1b);
296
297 /* wait a bit then update lock status */
298 mdelay(200);
299 *status = s5h1420_get_status_bits(state);
300 }
301 }
302
303 /* perform post lock setup */
304 if ((*status & FE_HAS_LOCK) && (!state->postlocked)) {
305
306 /* calculate the data rate */
307 u32 tmp = s5h1420_getsymbolrate(state);
308 switch(s5h1420_readreg(state, 0x32) & 0x07) {
309 case 0:
310 tmp = (tmp * 2 * 1) / 2;
311 break;
312
313 case 1:
314 tmp = (tmp * 2 * 2) / 3;
315 break;
316
317 case 2:
318 tmp = (tmp * 2 * 3) / 4;
319 break;
320
321 case 3:
322 tmp = (tmp * 2 * 5) / 6;
323 break;
324
325 case 4:
326 tmp = (tmp * 2 * 6) / 7;
327 break;
328
329 case 5:
330 tmp = (tmp * 2 * 7) / 8;
331 break;
332 }
333 tmp = state->fclk / tmp;
334
335 /* set the MPEG_CLK_INTL for the calculated data rate */
336 if (tmp < 4)
337 val = 0x00;
338 else if (tmp < 8)
339 val = 0x01;
340 else if (tmp < 12)
341 val = 0x02;
342 else if (tmp < 16)
343 val = 0x03;
344 else if (tmp < 24)
345 val = 0x04;
346 else if (tmp < 32)
347 val = 0x05;
348 else
349 val = 0x06;
350 s5h1420_writereg(state, 0x22, val);
351
352 /* DC freeze */
353 s5h1420_writereg(state, 0x1f, s5h1420_readreg(state, 0x1f) | 0x01);
354
355 /* kicker disable + remove DC offset */
356 s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) & 0x6f);
357
358 /* post-lock processing has been done! */
359 state->postlocked = 1;
360 }
361
362 return 0;
363}
364
365static int s5h1420_read_ber(struct dvb_frontend* fe, u32* ber)
366{
367 struct s5h1420_state* state = fe->demodulator_priv;
368
369 s5h1420_writereg(state, 0x46, 0x1d);
370 mdelay(25);
371 return (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47);
372}
373
374static int s5h1420_read_signal_strength(struct dvb_frontend* fe, u16* strength)
375{
376 struct s5h1420_state* state = fe->demodulator_priv;
377
378 u8 val = 0xff - s5h1420_readreg(state, 0x15);
379
380 return (int) ((val << 8) | val);
381}
382
383static int s5h1420_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
384{
385 struct s5h1420_state* state = fe->demodulator_priv;
386
387 s5h1420_writereg(state, 0x46, 0x1f);
388 mdelay(25);
389 return (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47);
390}
391
392static void s5h1420_reset(struct s5h1420_state* state)
393{
394 s5h1420_writereg (state, 0x01, 0x08);
395 s5h1420_writereg (state, 0x01, 0x00);
396 udelay(10);
397}
398
399static void s5h1420_setsymbolrate(struct s5h1420_state* state, struct dvb_frontend_parameters *p)
400{
401 u64 val;
402
403 val = (p->u.qpsk.symbol_rate / 1000) * (1<<24);
404 if (p->u.qpsk.symbol_rate <= 21000000) {
405 val *= 2;
406 }
407 do_div(val, (state->fclk / 1000));
408
409 s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0x7f);
410 s5h1420_writereg(state, 0x11, val >> 16);
411 s5h1420_writereg(state, 0x12, val >> 8);
412 s5h1420_writereg(state, 0x13, val & 0xff);
413 s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x80);
414}
415
416static u32 s5h1420_getsymbolrate(struct s5h1420_state* state)
417{
418 u64 val;
419 int sampling = 2;
420
421 if (s5h1420_readreg(state, 0x05) & 0x2)
422 sampling = 1;
423
424 s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08);
425 val = s5h1420_readreg(state, 0x11) << 16;
426 val |= s5h1420_readreg(state, 0x12) << 8;
427 val |= s5h1420_readreg(state, 0x13);
428 s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7);
429
430 val *= (state->fclk / 1000);
431 do_div(val, ((1<<24) * sampling));
432
433 return (u32) (val * 1000);
434}
435
436static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset)
437{
438 int val;
439
440 /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so
441 * divide fclk by 1000000 to get the correct value. */
442 val = -(int) ((freqoffset * (1<<24)) / (state->fclk / 1000000));
443
444 s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0xbf);
445 s5h1420_writereg(state, 0x0e, val >> 16);
446 s5h1420_writereg(state, 0x0f, val >> 8);
447 s5h1420_writereg(state, 0x10, val & 0xff);
448 s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x40);
449}
450
451static int s5h1420_getfreqoffset(struct s5h1420_state* state)
452{
453 int val;
454
455 s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08);
456 val = s5h1420_readreg(state, 0x0e) << 16;
457 val |= s5h1420_readreg(state, 0x0f) << 8;
458 val |= s5h1420_readreg(state, 0x10);
459 s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7);
460
461 if (val & 0x800000)
462 val |= 0xff000000;
463
464 /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so
465 * divide fclk by 1000000 to get the correct value. */
466 val = - ((val * (state->fclk/1000000)) / (1<<24));
467
468 return val;
469}
470
471static void s5h1420_setfec(struct s5h1420_state* state, struct dvb_frontend_parameters *p)
472{
473 if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {
474 s5h1420_writereg(state, 0x31, 0x00);
475 s5h1420_writereg(state, 0x30, 0x3f);
476 } else {
477 switch(p->u.qpsk.fec_inner) {
478 case FEC_1_2:
479 s5h1420_writereg(state, 0x31, 0x10);
480 s5h1420_writereg(state, 0x30, 0x01);
481 break;
482
483 case FEC_2_3:
484 s5h1420_writereg(state, 0x31, 0x11);
485 s5h1420_writereg(state, 0x30, 0x02);
486 break;
487
488 case FEC_3_4:
489 s5h1420_writereg(state, 0x31, 0x12);
490 s5h1420_writereg(state, 0x30, 0x04);
491 break;
492
493 case FEC_5_6:
494 s5h1420_writereg(state, 0x31, 0x13);
495 s5h1420_writereg(state, 0x30, 0x08);
496 break;
497
498 case FEC_6_7:
499 s5h1420_writereg(state, 0x31, 0x14);
500 s5h1420_writereg(state, 0x30, 0x10);
501 break;
502
503 case FEC_7_8:
504 s5h1420_writereg(state, 0x31, 0x15);
505 s5h1420_writereg(state, 0x30, 0x20);
506 break;
507
508 default:
509 return;
510 }
511 }
512}
513
514static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state)
515{
516 switch(s5h1420_readreg(state, 0x32) & 0x07) {
517 case 0:
518 return FEC_1_2;
519
520 case 1:
521 return FEC_2_3;
522
523 case 2:
524 return FEC_3_4;
525
526 case 3:
527 return FEC_5_6;
528
529 case 4:
530 return FEC_6_7;
531
532 case 5:
533 return FEC_7_8;
534 }
535
536 return FEC_NONE;
537}
538
539static void s5h1420_setinversion(struct s5h1420_state* state, struct dvb_frontend_parameters *p)
540{
541 if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {
542 s5h1420_writereg(state, 0x31, 0x00);
543 s5h1420_writereg(state, 0x30, 0x3f);
544 } else {
545 u8 tmp = s5h1420_readreg(state, 0x31) & 0xf7;
546 tmp |= 0x10;
547
548 if (p->inversion == INVERSION_ON)
549 tmp |= 0x80;
550
551 s5h1420_writereg(state, 0x31, tmp);
552 }
553}
554
555static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state)
556{
557 if (s5h1420_readreg(state, 0x32) & 0x08)
558 return INVERSION_ON;
559
560 return INVERSION_OFF;
561}
562
563static int s5h1420_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
564{
565 struct s5h1420_state* state = fe->demodulator_priv;
566 u32 frequency_delta;
567 struct dvb_frontend_tune_settings fesettings;
568
569 /* check if we should do a fast-tune */
570 memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters));
571 s5h1420_get_tune_settings(fe, &fesettings);
572 frequency_delta = p->frequency - state->tunedfreq;
573 if ((frequency_delta > -fesettings.max_drift) && (frequency_delta < fesettings.max_drift) &&
574 (frequency_delta != 0) &&
575 (state->fec_inner == p->u.qpsk.fec_inner) &&
576 (state->symbol_rate == p->u.qpsk.symbol_rate)) {
577
578 s5h1420_setfreqoffset(state, frequency_delta);
579 return 0;
580 }
581
582 /* first of all, software reset */
583 s5h1420_reset(state);
584
585 /* set tuner PLL */
586 if (state->config->pll_set) {
587 s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
588 state->config->pll_set(fe, p, &state->tunedfreq);
589 s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
590 }
591
592 /* set s5h1420 fclk PLL according to desired symbol rate */
593 if (p->u.qpsk.symbol_rate > 28000000) {
594 state->fclk = 88000000;
595 s5h1420_writereg(state, 0x03, 0x50);
596 s5h1420_writereg(state, 0x04, 0x40);
597 s5h1420_writereg(state, 0x05, 0xae);
598 } else if (p->u.qpsk.symbol_rate > 21000000) {
599 state->fclk = 59000000;
600 s5h1420_writereg(state, 0x03, 0x33);
601 s5h1420_writereg(state, 0x04, 0x40);
602 s5h1420_writereg(state, 0x05, 0xae);
603 } else {
604 state->fclk = 88000000;
605 s5h1420_writereg(state, 0x03, 0x50);
606 s5h1420_writereg(state, 0x04, 0x40);
607 s5h1420_writereg(state, 0x05, 0xac);
608 }
609
610 /* set misc registers */
611 s5h1420_writereg(state, 0x02, 0x00);
612 s5h1420_writereg(state, 0x07, 0xb0);
613 s5h1420_writereg(state, 0x0a, 0x67);
614 s5h1420_writereg(state, 0x0b, 0x78);
615 s5h1420_writereg(state, 0x0c, 0x48);
616 s5h1420_writereg(state, 0x0d, 0x6b);
617 s5h1420_writereg(state, 0x2e, 0x8e);
618 s5h1420_writereg(state, 0x35, 0x33);
619 s5h1420_writereg(state, 0x38, 0x01);
620 s5h1420_writereg(state, 0x39, 0x7d);
621 s5h1420_writereg(state, 0x3a, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
622 s5h1420_writereg(state, 0x3c, 0x00);
623 s5h1420_writereg(state, 0x45, 0x61);
624 s5h1420_writereg(state, 0x46, 0x1d);
625
626 /* start QPSK */
627 s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1);
628
629 /* set the frequency offset to adjust for PLL inaccuracy */
630 s5h1420_setfreqoffset(state, p->frequency - state->tunedfreq);
631
632 /* set the reset of the parameters */
633 s5h1420_setsymbolrate(state, p);
634 s5h1420_setinversion(state, p);
635 s5h1420_setfec(state, p);
636
637 state->fec_inner = p->u.qpsk.fec_inner;
638 state->symbol_rate = p->u.qpsk.symbol_rate;
639 state->postlocked = 0;
640 return 0;
641}
642
643static int s5h1420_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
644{
645 struct s5h1420_state* state = fe->demodulator_priv;
646
647 p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state);
648 p->inversion = s5h1420_getinversion(state);
649 p->u.qpsk.symbol_rate = s5h1420_getsymbolrate(state);
650 p->u.qpsk.fec_inner = s5h1420_getfec(state);
651
652 return 0;
653}
654
655static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
656{
657 if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) {
658 fesettings->min_delay_ms = 50;
659 fesettings->step_size = 2000;
660 fesettings->max_drift = 8000;
661 } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) {
662 fesettings->min_delay_ms = 100;
663 fesettings->step_size = 1500;
664 fesettings->max_drift = 9000;
665 } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) {
666 fesettings->min_delay_ms = 100;
667 fesettings->step_size = 1000;
668 fesettings->max_drift = 8000;
669 } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) {
670 fesettings->min_delay_ms = 100;
671 fesettings->step_size = 500;
672 fesettings->max_drift = 7000;
673 } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) {
674 fesettings->min_delay_ms = 200;
675 fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
676 fesettings->max_drift = 14 * fesettings->step_size;
677 } else {
678 fesettings->min_delay_ms = 200;
679 fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
680 fesettings->max_drift = 18 * fesettings->step_size;
681 }
682
683 return 0;
684}
685
686static int s5h1420_init (struct dvb_frontend* fe)
687{
688 struct s5h1420_state* state = fe->demodulator_priv;
689
690 /* disable power down and do reset */
691 s5h1420_writereg(state, 0x02, 0x10);
692 msleep(10);
693 s5h1420_reset(state);
694
695 /* init PLL */
696 if (state->config->pll_init) {
697 s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
698 state->config->pll_init(fe);
699 s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
700 }
701
702 return 0;
703}
704
705static int s5h1420_sleep(struct dvb_frontend* fe)
706{
707 struct s5h1420_state* state = fe->demodulator_priv;
708
709 return s5h1420_writereg(state, 0x02, 0x12);
710}
711
712static void s5h1420_release(struct dvb_frontend* fe)
713{
714 struct s5h1420_state* state = fe->demodulator_priv;
715 kfree(state);
716}
717
718static struct dvb_frontend_ops s5h1420_ops;
719
720struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, struct i2c_adapter* i2c)
721{
722 struct s5h1420_state* state = NULL;
723 u8 identity;
724
725 /* allocate memory for the internal state */
726 state = kmalloc(sizeof(struct s5h1420_state), GFP_KERNEL);
727 if (state == NULL)
728 goto error;
729
730 /* setup the state */
731 state->config = config;
732 state->i2c = i2c;
733 memcpy(&state->ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
734 state->postlocked = 0;
735 state->fclk = 88000000;
736 state->tunedfreq = 0;
737 state->fec_inner = FEC_NONE;
738 state->symbol_rate = 0;
739
740 /* check if the demod is there + identify it */
741 identity = s5h1420_readreg(state, 0x00);
742 if (identity != 0x03)
743 goto error;
744
745 /* create dvb_frontend */
746 state->frontend.ops = &state->ops;
747 state->frontend.demodulator_priv = state;
748 return &state->frontend;
749
750error:
751 kfree(state);
752 return NULL;
753}
754
755static struct dvb_frontend_ops s5h1420_ops = {
756
757 .info = {
758 .name = "Samsung S5H1420 DVB-S",
759 .type = FE_QPSK,
760 .frequency_min = 950000,
761 .frequency_max = 2150000,
762 .frequency_stepsize = 125, /* kHz for QPSK frontends */
763 .frequency_tolerance = 29500,
764 .symbol_rate_min = 1000000,
765 .symbol_rate_max = 45000000,
766 /* .symbol_rate_tolerance = ???,*/
767 .caps = FE_CAN_INVERSION_AUTO |
768 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
769 FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
770 FE_CAN_QPSK
771 },
772
773 .release = s5h1420_release,
774
775 .init = s5h1420_init,
776 .sleep = s5h1420_sleep,
777
778 .set_frontend = s5h1420_set_frontend,
779 .get_frontend = s5h1420_get_frontend,
780 .get_tune_settings = s5h1420_get_tune_settings,
781
782 .read_status = s5h1420_read_status,
783 .read_ber = s5h1420_read_ber,
784 .read_signal_strength = s5h1420_read_signal_strength,
785 .read_ucblocks = s5h1420_read_ucblocks,
786
787 .diseqc_send_master_cmd = s5h1420_send_master_cmd,
788 .diseqc_recv_slave_reply = s5h1420_recv_slave_reply,
789 .diseqc_send_burst = s5h1420_send_burst,
790 .set_tone = s5h1420_set_tone,
791 .set_voltage = s5h1420_set_voltage,
792};
793
794module_param(debug, int, 0644);
795
796MODULE_DESCRIPTION("Samsung S5H1420 DVB-S Demodulator driver");
797MODULE_AUTHOR("Andrew de Quincey");
798MODULE_LICENSE("GPL");
799
800EXPORT_SYMBOL(s5h1420_attach);
diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h
new file mode 100644
index 000000000000..b687fc77ceb3
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1420.h
@@ -0,0 +1,41 @@
1/*
2 Driver for S5H1420 QPSK Demodulators
3
4 Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21*/
22
23#ifndef S5H1420_H
24#define S5H1420_H
25
26#include <linux/dvb/frontend.h>
27
28struct s5h1420_config
29{
30 /* the demodulator's i2c address */
31 u8 demod_address;
32
33 /* PLL maintenance */
34 int (*pll_init)(struct dvb_frontend* fe);
35 int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout);
36};
37
38extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
39 struct i2c_adapter* i2c);
40
41#endif // S5H1420_H
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 7ffa2c7315b3..bf3c011d2cfb 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -12,7 +12,7 @@ config DVB_AV7110
12 select DVB_STV0297 12 select DVB_STV0297
13 select DVB_L64781 13 select DVB_L64781
14 help 14 help
15 Support for SAA7146 and AV7110 based DVB cards as produced 15 Support for SAA7146 and AV7110 based DVB cards as produced
16 by Fujitsu-Siemens, Technotrend, Hauppauge and others. 16 by Fujitsu-Siemens, Technotrend, Hauppauge and others.
17 17
18 This driver only supports the fullfeatured cards with 18 This driver only supports the fullfeatured cards with
@@ -33,7 +33,7 @@ config DVB_AV7110_FIRMWARE
33 If you want to compile the firmware into the driver you need to say 33 If you want to compile the firmware into the driver you need to say
34 Y here and provide the correct path of the firmware. You need this 34 Y here and provide the correct path of the firmware. You need this
35 option if you want to compile the whole driver statically into the 35 option if you want to compile the whole driver statically into the
36 kernel. 36 kernel.
37 37
38 All other people say N. 38 All other people say N.
39 39
@@ -66,6 +66,7 @@ config DVB_BUDGET
66 select DVB_L64781 66 select DVB_L64781
67 select DVB_TDA8083 67 select DVB_TDA8083
68 select DVB_TDA10021 68 select DVB_TDA10021
69 select DVB_S5H1420
69 help 70 help
70 Support for simple SAA7146 based DVB cards 71 Support for simple SAA7146 based DVB cards
71 (so called Budget- or Nova-PCI cards) without onboard 72 (so called Budget- or Nova-PCI cards) without onboard
@@ -119,9 +120,9 @@ config DVB_BUDGET_PATCH
119 select DVB_VES1X93 120 select DVB_VES1X93
120 select DVB_TDA8083 121 select DVB_TDA8083
121 help 122 help
122 Support for Budget Patch (full TS) modification on 123 Support for Budget Patch (full TS) modification on
123 SAA7146+AV7110 based cards (DVB-S cards). This 124 SAA7146+AV7110 based cards (DVB-S cards). This
124 driver doesn't use onboard MPEG2 decoder. The 125 driver doesn't use onboard MPEG2 decoder. The
125 card is driven in Budget-only mode. Card is 126 card is driven in Budget-only mode. Card is
126 required to have loaded firmware to tune properly. 127 required to have loaded firmware to tune properly.
127 Firmware can be loaded by insertion and removal of 128 Firmware can be loaded by insertion and removal of
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 083fd44e5f90..9961917e8a7f 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -40,6 +40,7 @@
40#include "ves1820.h" 40#include "ves1820.h"
41#include "l64781.h" 41#include "l64781.h"
42#include "tda8083.h" 42#include "tda8083.h"
43#include "s5h1420.h"
43 44
44static void Set22K (struct budget *budget, int state) 45static void Set22K (struct budget *budget, int state)
45{ 46{
@@ -177,6 +178,62 @@ static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t m
177 return 0; 178 return 0;
178} 179}
179 180
181static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
182{
183 struct budget* budget = (struct budget*) fe->dvb->priv;
184 u8 buf;
185 struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) };
186
187 if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
188
189 switch(voltage) {
190 case SEC_VOLTAGE_13:
191 buf = (buf & 0xf7) | 0x04;
192 break;
193
194 case SEC_VOLTAGE_18:
195 buf = (buf & 0xf7) | 0x0c;
196 break;
197
198 case SEC_VOLTAGE_OFF:
199 buf = buf & 0xf0;
200 break;
201 }
202
203 msg.flags = 0;
204 if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
205
206 return 0;
207}
208
209static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, int arg)
210{
211 struct budget* budget = (struct budget*) fe->dvb->priv;
212 u8 buf;
213 struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) };
214
215 if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
216
217 if (arg) {
218 buf = buf | 0x10;
219 } else {
220 buf = buf & 0xef;
221 }
222
223 msg.flags = 0;
224 if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
225
226 return 0;
227}
228
229static void lnbp21_init(struct budget* budget)
230{
231 u8 buf = 0x00;
232 struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = &buf, .len = sizeof(buf) };
233
234 i2c_transfer (&budget->i2c_adap, &msg, 1);
235}
236
180static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) 237static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
181{ 238{
182 struct budget* budget = (struct budget*) fe->dvb->priv; 239 struct budget* budget = (struct budget*) fe->dvb->priv;
@@ -395,6 +452,38 @@ static struct tda8083_config grundig_29504_451_config = {
395 .pll_set = grundig_29504_451_pll_set, 452 .pll_set = grundig_29504_451_pll_set,
396}; 453};
397 454
455static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout)
456{
457 struct budget* budget = (struct budget*) fe->dvb->priv;
458 u32 div;
459 u8 data[4];
460 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
461
462 div = params->frequency / 1000;
463 data[0] = (div >> 8) & 0x7f;
464 data[1] = div & 0xff;
465 data[2] = 0xc2;
466
467 if (div < 1450)
468 data[3] = 0x00;
469 else if (div < 1850)
470 data[3] = 0x40;
471 else if (div < 2000)
472 data[3] = 0x80;
473 else
474 data[3] = 0xc0;
475
476 if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
477
478 *freqout = div * 1000;
479 return 0;
480}
481
482static struct s5h1420_config s5h1420_config = {
483 .demod_address = 0x53,
484 .pll_set = s5h1420_pll_set,
485};
486
398static u8 read_pwm(struct budget* budget) 487static u8 read_pwm(struct budget* budget)
399{ 488{
400 u8 b = 0xff; 489 u8 b = 0xff;
@@ -459,6 +548,15 @@ static void frontend_init(struct budget *budget)
459 break; 548 break;
460 } 549 }
461 break; 550 break;
551
552 case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
553 budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap);
554 if (budget->dvb_frontend) {
555 budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
556 budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
557 lnbp21_init(budget);
558 break;
559 }
462 } 560 }
463 561
464 if (budget->dvb_frontend == NULL) { 562 if (budget->dvb_frontend == NULL) {
@@ -532,6 +630,7 @@ static struct pci_device_id pci_tbl[] = {
532 MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004), 630 MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004),
533 MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005), 631 MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005),
534 MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), 632 MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
633 MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016),
535 MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60), 634 MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
536 MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61), 635 MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
537 { 636 {