aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMalcolm Priestley <tvboxspy@gmail.com>2012-03-07 16:11:03 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-03-19 13:52:59 -0400
commitae8dc8ee2b84d31306766d87cc5b2bb42e216f57 (patch)
treeea32352866653fd9c92f528f529814e493d03f7c /drivers
parent77c2402dc6c900a2d60587cd83bc1ee3dd39c460 (diff)
[media] m88rs2000 1.12 v2 DVB-S frontend and tuner module
Support for m88rs2000 chip used in lmedm04 driver. Note there are still lock problems. Slow channel change due to the large block of registers sent in set_frontend. Version 2 differences. Front end is completely shut down when in sleep mode. This allow user to regain control of device. Kaffeine scan problem solved by removing register calls from get_frontend. Kaffeine seems to call get_frontend when updating signal data. This can happen in the middle of a tune stalling the driver. Change calculations to those in the DS3000 driver. Signed-off-by: Malcolm Priestley <tvboxspy@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/dvb/frontends/Kconfig8
-rw-r--r--drivers/media/dvb/frontends/Makefile1
-rw-r--r--drivers/media/dvb/frontends/m88rs2000.c906
-rw-r--r--drivers/media/dvb/frontends/m88rs2000.h66
4 files changed, 981 insertions, 0 deletions
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 2995204c3355..21246707fbfb 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -705,6 +705,14 @@ config DVB_IT913X_FE
705 A DVB-T tuner module. 705 A DVB-T tuner module.
706 Say Y when you want to support this frontend. 706 Say Y when you want to support this frontend.
707 707
708config DVB_M88RS2000
709 tristate "M88RS2000 DVB-S demodulator and tuner"
710 depends on DVB_CORE && I2C
711 default m if DVB_FE_CUSTOMISE
712 help
713 A DVB-S tuner module.
714 Say Y when you want to support this frontend.
715
708comment "Tools to develop new frontends" 716comment "Tools to develop new frontends"
709 717
710config DVB_DUMMY_FE 718config DVB_DUMMY_FE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 17519dc027d8..86fa808bf589 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -97,4 +97,5 @@ obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o
97obj-$(CONFIG_DVB_A8293) += a8293.o 97obj-$(CONFIG_DVB_A8293) += a8293.o
98obj-$(CONFIG_DVB_TDA10071) += tda10071.o 98obj-$(CONFIG_DVB_TDA10071) += tda10071.o
99obj-$(CONFIG_DVB_RTL2830) += rtl2830.o 99obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
100obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
100 101
diff --git a/drivers/media/dvb/frontends/m88rs2000.c b/drivers/media/dvb/frontends/m88rs2000.c
new file mode 100644
index 000000000000..c9a34358128b
--- /dev/null
+++ b/drivers/media/dvb/frontends/m88rs2000.c
@@ -0,0 +1,906 @@
1/*
2 Driver for M88RS2000 demodulator and tuner
3
4 Copyright (C) 2012 Malcolm Priestley (tvboxspy@gmail.com)
5 Beta Driver
6
7 Include various calculation code from DS3000 driver.
8 Copyright (C) 2009 Konstantin Dimitrov.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
24*/
25#include <linux/init.h>
26#include <linux/module.h>
27#include <linux/device.h>
28#include <linux/jiffies.h>
29#include <linux/string.h>
30#include <linux/slab.h>
31#include <linux/types.h>
32
33
34#include "dvb_frontend.h"
35#include "m88rs2000.h"
36
37struct m88rs2000_state {
38 struct i2c_adapter *i2c;
39 const struct m88rs2000_config *config;
40 struct dvb_frontend frontend;
41 u8 no_lock_count;
42 u32 tuner_frequency;
43 u32 symbol_rate;
44 fe_code_rate_t fec_inner;
45 u8 tuner_level;
46 int errmode;
47};
48
49static int m88rs2000_debug;
50
51module_param_named(debug, m88rs2000_debug, int, 0644);
52MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
53
54#define dprintk(level, args...) do { \
55 if (level & m88rs2000_debug) \
56 printk(KERN_DEBUG "m88rs2000-fe: " args); \
57} while (0)
58
59#define deb_info(args...) dprintk(0x01, args)
60#define info(format, arg...) \
61 printk(KERN_INFO "m88rs2000-fe: " format "\n" , ## arg)
62
63static int m88rs2000_writereg(struct m88rs2000_state *state, u8 tuner,
64 u8 reg, u8 data)
65{
66 int ret;
67 u8 addr = (tuner == 0) ? state->config->tuner_addr :
68 state->config->demod_addr;
69 u8 buf[] = { reg, data };
70 struct i2c_msg msg = {
71 .addr = addr,
72 .flags = 0,
73 .buf = buf,
74 .len = 2
75 };
76
77 ret = i2c_transfer(state->i2c, &msg, 1);
78
79 if (ret != 1)
80 deb_info("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
81 "ret == %i)\n", __func__, reg, data, ret);
82
83 return (ret != 1) ? -EREMOTEIO : 0;
84}
85
86static int m88rs2000_demod_write(struct m88rs2000_state *state, u8 reg, u8 data)
87{
88 return m88rs2000_writereg(state, 1, reg, data);
89}
90
91static int m88rs2000_tuner_write(struct m88rs2000_state *state, u8 reg, u8 data)
92{
93 m88rs2000_demod_write(state, 0x81, 0x84);
94 udelay(10);
95 return m88rs2000_writereg(state, 0, reg, data);
96
97}
98
99static int m88rs2000_write(struct dvb_frontend *fe, const u8 buf[], int len)
100{
101 struct m88rs2000_state *state = fe->demodulator_priv;
102
103 if (len != 2)
104 return -EINVAL;
105
106 return m88rs2000_writereg(state, 1, buf[0], buf[1]);
107}
108
109static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 tuner, u8 reg)
110{
111 int ret;
112 u8 b0[] = { reg };
113 u8 b1[] = { 0 };
114 u8 addr = (tuner == 0) ? state->config->tuner_addr :
115 state->config->demod_addr;
116 struct i2c_msg msg[] = {
117 {
118 .addr = addr,
119 .flags = 0,
120 .buf = b0,
121 .len = 1
122 }, {
123 .addr = addr,
124 .flags = I2C_M_RD,
125 .buf = b1,
126 .len = 1
127 }
128 };
129
130 ret = i2c_transfer(state->i2c, msg, 2);
131
132 if (ret != 2)
133 deb_info("%s: readreg error (reg == 0x%02x, ret == %i)\n",
134 __func__, reg, ret);
135
136 return b1[0];
137}
138
139static u8 m88rs2000_demod_read(struct m88rs2000_state *state, u8 reg)
140{
141 return m88rs2000_readreg(state, 1, reg);
142}
143
144static u8 m88rs2000_tuner_read(struct m88rs2000_state *state, u8 reg)
145{
146 m88rs2000_demod_write(state, 0x81, 0x85);
147 udelay(10);
148 return m88rs2000_readreg(state, 0, reg);
149}
150
151static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate)
152{
153 struct m88rs2000_state *state = fe->demodulator_priv;
154 int ret;
155 u32 temp;
156 u8 b[3];
157
158 if ((srate < 1000000) || (srate > 45000000))
159 return -EINVAL;
160
161 temp = srate / 1000;
162 temp *= 11831;
163 temp /= 68;
164 temp -= 3;
165
166 b[0] = (u8) (temp >> 16) & 0xff;
167 b[1] = (u8) (temp >> 8) & 0xff;
168 b[2] = (u8) temp & 0xff;
169 ret = m88rs2000_demod_write(state, 0x93, b[2]);
170 ret |= m88rs2000_demod_write(state, 0x94, b[1]);
171 ret |= m88rs2000_demod_write(state, 0x95, b[0]);
172
173 deb_info("m88rs2000: m88rs2000_set_symbolrate\n");
174 return ret;
175}
176
177static int m88rs2000_send_diseqc_msg(struct dvb_frontend *fe,
178 struct dvb_diseqc_master_cmd *m)
179{
180 struct m88rs2000_state *state = fe->demodulator_priv;
181
182 int i;
183 u8 reg;
184 deb_info("%s\n", __func__);
185 m88rs2000_demod_write(state, 0x9a, 0x30);
186 reg = m88rs2000_demod_read(state, 0xb2);
187 reg &= 0x3f;
188 m88rs2000_demod_write(state, 0xb2, reg);
189 for (i = 0; i < m->msg_len; i++)
190 m88rs2000_demod_write(state, 0xb3 + i, m->msg[i]);
191
192 reg = m88rs2000_demod_read(state, 0xb1);
193 reg &= 0x87;
194 reg |= ((m->msg_len - 1) << 3) | 0x07;
195 reg &= 0x7f;
196 m88rs2000_demod_write(state, 0xb1, reg);
197
198 for (i = 0; i < 15; i++) {
199 if ((m88rs2000_demod_read(state, 0xb1) & 0x40) == 0x0)
200 break;
201 msleep(20);
202 }
203
204 reg = m88rs2000_demod_read(state, 0xb1);
205 if ((reg & 0x40) > 0x0) {
206 reg &= 0x7f;
207 reg |= 0x40;
208 m88rs2000_demod_write(state, 0xb1, reg);
209 }
210
211 reg = m88rs2000_demod_read(state, 0xb2);
212 reg &= 0x3f;
213 reg |= 0x80;
214 m88rs2000_demod_write(state, 0xb2, reg);
215 m88rs2000_demod_write(state, 0x9a, 0xb0);
216
217
218 return 0;
219}
220
221static int m88rs2000_send_diseqc_burst(struct dvb_frontend *fe,
222 fe_sec_mini_cmd_t burst)
223{
224 struct m88rs2000_state *state = fe->demodulator_priv;
225 u8 reg0, reg1;
226 deb_info("%s\n", __func__);
227 m88rs2000_demod_write(state, 0x9a, 0x30);
228 msleep(50);
229 reg0 = m88rs2000_demod_read(state, 0xb1);
230 reg1 = m88rs2000_demod_read(state, 0xb2);
231 if (burst == SEC_MINI_B)
232 reg1 |= 0x1;
233 m88rs2000_demod_write(state, 0xb2, reg1);
234 m88rs2000_demod_write(state, 0xb1, reg0);
235 m88rs2000_demod_write(state, 0x9a, 0xb0);
236
237 return 0;
238}
239
240static int m88rs2000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
241{
242 struct m88rs2000_state *state = fe->demodulator_priv;
243 u8 reg0, reg1;
244 m88rs2000_demod_write(state, 0x9a, 0x30);
245 reg0 = m88rs2000_demod_read(state, 0xb1);
246 reg1 = m88rs2000_demod_read(state, 0xb2);
247
248 reg1 &= 0x3f;
249
250 switch (tone) {
251 case SEC_TONE_ON:
252 reg0 |= 0x4;
253 reg0 &= 0xbc;
254 break;
255 case SEC_TONE_OFF:
256 reg1 |= 0x80;
257 break;
258
259 default:
260 return -EINVAL;
261 }
262 m88rs2000_demod_write(state, 0xb2, reg1);
263 m88rs2000_demod_write(state, 0xb1, reg0);
264 m88rs2000_demod_write(state, 0x9a, 0xb0);
265 return 0;
266}
267
268struct inittab {
269 u8 cmd;
270 u8 reg;
271 u8 val;
272};
273
274struct inittab m88rs2000_setup[] = {
275 {DEMOD_WRITE, 0x9a, 0x30},
276 {DEMOD_WRITE, 0x00, 0x01},
277 {WRITE_DELAY, 0x19, 0x00},
278 {DEMOD_WRITE, 0x00, 0x00},
279 {DEMOD_WRITE, 0x9a, 0xb0},
280 {DEMOD_WRITE, 0x81, 0xc1},
281 {TUNER_WRITE, 0x42, 0x73},
282 {TUNER_WRITE, 0x05, 0x07},
283 {TUNER_WRITE, 0x20, 0x27},
284 {TUNER_WRITE, 0x07, 0x02},
285 {TUNER_WRITE, 0x11, 0xff},
286 {TUNER_WRITE, 0x60, 0xf9},
287 {TUNER_WRITE, 0x08, 0x01},
288 {TUNER_WRITE, 0x00, 0x41},
289 {DEMOD_WRITE, 0x81, 0x81},
290 {DEMOD_WRITE, 0x86, 0xc6},
291 {DEMOD_WRITE, 0x9a, 0x30},
292 {DEMOD_WRITE, 0xf0, 0x22},
293 {DEMOD_WRITE, 0xf1, 0xbf},
294 {DEMOD_WRITE, 0xb0, 0x45},
295 {DEMOD_WRITE, 0x9a, 0xb0},
296 {0xff, 0xaa, 0xff}
297};
298
299struct inittab m88rs2000_shutdown[] = {
300 {DEMOD_WRITE, 0x9a, 0x30},
301 {DEMOD_WRITE, 0xb0, 0x00},
302 {DEMOD_WRITE, 0xf1, 0x89},
303 {DEMOD_WRITE, 0x00, 0x01},
304 {DEMOD_WRITE, 0x9a, 0xb0},
305 {TUNER_WRITE, 0x00, 0x40},
306 {DEMOD_WRITE, 0x81, 0x81},
307 {0xff, 0xaa, 0xff}
308};
309
310struct inittab tuner_reset[] = {
311 {TUNER_WRITE, 0x42, 0x73},
312 {TUNER_WRITE, 0x05, 0x07},
313 {TUNER_WRITE, 0x20, 0x27},
314 {TUNER_WRITE, 0x07, 0x02},
315 {TUNER_WRITE, 0x11, 0xff},
316 {TUNER_WRITE, 0x60, 0xf9},
317 {TUNER_WRITE, 0x08, 0x01},
318 {TUNER_WRITE, 0x00, 0x41},
319 {0xff, 0xaa, 0xff}
320};
321
322struct inittab fe_reset[] = {
323 {DEMOD_WRITE, 0x00, 0x01},
324 {DEMOD_WRITE, 0xf1, 0xbf},
325 {DEMOD_WRITE, 0x00, 0x01},
326 {DEMOD_WRITE, 0x20, 0x81},
327 {DEMOD_WRITE, 0x21, 0x80},
328 {DEMOD_WRITE, 0x10, 0x33},
329 {DEMOD_WRITE, 0x11, 0x44},
330 {DEMOD_WRITE, 0x12, 0x07},
331 {DEMOD_WRITE, 0x18, 0x20},
332 {DEMOD_WRITE, 0x28, 0x04},
333 {DEMOD_WRITE, 0x29, 0x8e},
334 {DEMOD_WRITE, 0x3b, 0xff},
335 {DEMOD_WRITE, 0x32, 0x10},
336 {DEMOD_WRITE, 0x33, 0x02},
337 {DEMOD_WRITE, 0x34, 0x30},
338 {DEMOD_WRITE, 0x35, 0xff},
339 {DEMOD_WRITE, 0x38, 0x50},
340 {DEMOD_WRITE, 0x39, 0x68},
341 {DEMOD_WRITE, 0x3c, 0x7f},
342 {DEMOD_WRITE, 0x3d, 0x0f},
343 {DEMOD_WRITE, 0x45, 0x20},
344 {DEMOD_WRITE, 0x46, 0x24},
345 {DEMOD_WRITE, 0x47, 0x7c},
346 {DEMOD_WRITE, 0x48, 0x16},
347 {DEMOD_WRITE, 0x49, 0x04},
348 {DEMOD_WRITE, 0x4a, 0x01},
349 {DEMOD_WRITE, 0x4b, 0x78},
350 {DEMOD_WRITE, 0X4d, 0xd2},
351 {DEMOD_WRITE, 0x4e, 0x6d},
352 {DEMOD_WRITE, 0x50, 0x30},
353 {DEMOD_WRITE, 0x51, 0x30},
354 {DEMOD_WRITE, 0x54, 0x7b},
355 {DEMOD_WRITE, 0x56, 0x09},
356 {DEMOD_WRITE, 0x58, 0x59},
357 {DEMOD_WRITE, 0x59, 0x37},
358 {DEMOD_WRITE, 0x63, 0xfa},
359 {0xff, 0xaa, 0xff}
360};
361
362struct inittab fe_trigger[] = {
363 {DEMOD_WRITE, 0x97, 0x04},
364 {DEMOD_WRITE, 0x99, 0x77},
365 {DEMOD_WRITE, 0x9b, 0x64},
366 {DEMOD_WRITE, 0x9e, 0x00},
367 {DEMOD_WRITE, 0x9f, 0xf8},
368 {DEMOD_WRITE, 0xa0, 0x20},
369 {DEMOD_WRITE, 0xa1, 0xe0},
370 {DEMOD_WRITE, 0xa3, 0x38},
371 {DEMOD_WRITE, 0x98, 0xff},
372 {DEMOD_WRITE, 0xc0, 0x0f},
373 {DEMOD_WRITE, 0x89, 0x01},
374 {DEMOD_WRITE, 0x00, 0x00},
375 {WRITE_DELAY, 0x0a, 0x00},
376 {DEMOD_WRITE, 0x00, 0x01},
377 {DEMOD_WRITE, 0x00, 0x00},
378 {DEMOD_WRITE, 0x9a, 0xb0},
379 {0xff, 0xaa, 0xff}
380};
381
382static int m88rs2000_tab_set(struct m88rs2000_state *state,
383 struct inittab *tab)
384{
385 int ret = 0;
386 u8 i;
387 if (tab == NULL)
388 return -EINVAL;
389
390 for (i = 0; i < 255; i++) {
391 switch (tab[i].cmd) {
392 case 0x01:
393 ret = m88rs2000_demod_write(state, tab[i].reg,
394 tab[i].val);
395 break;
396 case 0x02:
397 ret = m88rs2000_tuner_write(state, tab[i].reg,
398 tab[i].val);
399 break;
400 case 0x10:
401 if (tab[i].reg > 0)
402 mdelay(tab[i].reg);
403 break;
404 case 0xff:
405 if (tab[i].reg == 0xaa && tab[i].val == 0xff)
406 return 0;
407 case 0x00:
408 break;
409 default:
410 return -EINVAL;
411 }
412 if (ret < 0)
413 return -ENODEV;
414 }
415 return 0;
416}
417
418static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
419{
420 deb_info("%s: %s\n", __func__,
421 volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
422 volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
423
424 return 0;
425}
426
427static int m88rs2000_startup(struct m88rs2000_state *state)
428{
429 int ret = 0;
430 u8 reg;
431
432 reg = m88rs2000_tuner_read(state, 0x00);
433 if ((reg & 0x40) == 0)
434 ret = -ENODEV;
435
436 return ret;
437}
438
439static int m88rs2000_init(struct dvb_frontend *fe)
440{
441 struct m88rs2000_state *state = fe->demodulator_priv;
442 int ret;
443
444 deb_info("m88rs2000: init chip\n");
445 /* Setup frontend from shutdown/cold */
446 ret = m88rs2000_tab_set(state, m88rs2000_setup);
447
448 return ret;
449}
450
451static int m88rs2000_sleep(struct dvb_frontend *fe)
452{
453 struct m88rs2000_state *state = fe->demodulator_priv;
454 int ret;
455 /* Shutdown the frondend */
456 ret = m88rs2000_tab_set(state, m88rs2000_shutdown);
457 return ret;
458}
459
460static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status)
461{
462 struct m88rs2000_state *state = fe->demodulator_priv;
463 u8 reg = m88rs2000_demod_read(state, 0x8c);
464
465 *status = 0;
466
467 if ((reg & 0x7) == 0x7) {
468 *status = FE_HAS_CARRIER | FE_HAS_SIGNAL | FE_HAS_VITERBI
469 | FE_HAS_LOCK;
470 if (state->config->set_ts_params)
471 state->config->set_ts_params(fe, CALL_IS_READ);
472 }
473 return 0;
474}
475
476/* Extact code for these unknown but lmedm04 driver uses interupt callbacks */
477
478static int m88rs2000_read_ber(struct dvb_frontend *fe, u32 *ber)
479{
480 deb_info("m88rs2000_read_ber %d\n", *ber);
481 *ber = 0;
482 return 0;
483}
484
485static int m88rs2000_read_signal_strength(struct dvb_frontend *fe,
486 u16 *strength)
487{
488 *strength = 0;
489 return 0;
490}
491
492static int m88rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
493{
494 deb_info("m88rs2000_read_snr %d\n", *snr);
495 *snr = 0;
496 return 0;
497}
498
499static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
500{
501 deb_info("m88rs2000_read_ber %d\n", *ucblocks);
502 *ucblocks = 0;
503 return 0;
504}
505
506static int m88rs2000_tuner_gate_ctrl(struct m88rs2000_state *state, u8 offset)
507{
508 int ret;
509 ret = m88rs2000_tuner_write(state, 0x51, 0x1f - offset);
510 ret |= m88rs2000_tuner_write(state, 0x51, 0x1f);
511 ret |= m88rs2000_tuner_write(state, 0x50, offset);
512 ret |= m88rs2000_tuner_write(state, 0x50, 0x00);
513 msleep(20);
514 return ret;
515}
516
517static int m88rs2000_set_tuner_rf(struct dvb_frontend *fe)
518{
519 struct m88rs2000_state *state = fe->demodulator_priv;
520 int reg;
521 reg = m88rs2000_tuner_read(state, 0x3d);
522 reg &= 0x7f;
523 if (reg < 0x17)
524 reg = 0xa1;
525 else if (reg < 0x16)
526 reg = 0x99;
527 else
528 reg = 0xf9;
529
530 m88rs2000_tuner_write(state, 0x60, reg);
531 reg = m88rs2000_tuner_gate_ctrl(state, 0x08);
532
533 if (fe->ops.i2c_gate_ctrl)
534 fe->ops.i2c_gate_ctrl(fe, 0);
535 return reg;
536}
537
538static int m88rs2000_set_tuner(struct dvb_frontend *fe, u16 *offset)
539{
540 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
541 struct m88rs2000_state *state = fe->demodulator_priv;
542 int ret;
543 u32 frequency = c->frequency;
544 s32 offset_khz;
545 s32 tmp;
546 u32 symbol_rate = (c->symbol_rate / 1000);
547 u32 f3db, gdiv28;
548 u16 value, ndiv, lpf_coeff;
549 u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf;
550 u8 lo = 0x01, div4 = 0x0;
551
552 /* Reset Tuner */
553 ret = m88rs2000_tab_set(state, tuner_reset);
554
555 /* Calculate frequency divider */
556 if (frequency < 1060000) {
557 lo |= 0x10;
558 div4 = 0x1;
559 ndiv = (frequency * 14 * 4) / FE_CRYSTAL_KHZ;
560 } else
561 ndiv = (frequency * 14 * 2) / FE_CRYSTAL_KHZ;
562 ndiv = ndiv + ndiv % 2;
563 ndiv = ndiv - 1024;
564
565 ret = m88rs2000_tuner_write(state, 0x10, 0x80 | lo);
566
567 /* Set frequency divider */
568 ret |= m88rs2000_tuner_write(state, 0x01, (ndiv >> 8) & 0xf);
569 ret |= m88rs2000_tuner_write(state, 0x02, ndiv & 0xff);
570
571 ret |= m88rs2000_tuner_write(state, 0x03, 0x06);
572 ret |= m88rs2000_tuner_gate_ctrl(state, 0x10);
573 if (ret < 0)
574 return -ENODEV;
575
576 /* Tuner Frequency Range */
577 ret = m88rs2000_tuner_write(state, 0x10, lo);
578
579 ret |= m88rs2000_tuner_gate_ctrl(state, 0x08);
580
581 /* Tuner RF */
582 ret |= m88rs2000_set_tuner_rf(fe);
583
584 gdiv28 = (FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000;
585 ret |= m88rs2000_tuner_write(state, 0x04, gdiv28 & 0xff);
586 ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
587 if (ret < 0)
588 return -ENODEV;
589
590 value = m88rs2000_tuner_read(state, 0x26);
591
592 f3db = (symbol_rate * 135) / 200 + 2000;
593 f3db += FREQ_OFFSET_LOW_SYM_RATE;
594 if (f3db < 7000)
595 f3db = 7000;
596 if (f3db > 40000)
597 f3db = 40000;
598
599 gdiv28 = gdiv28 * 207 / (value * 2 + 151);
600 mlpf_max = gdiv28 * 135 / 100;
601 mlpf_min = gdiv28 * 78 / 100;
602 if (mlpf_max > 63)
603 mlpf_max = 63;
604
605 lpf_coeff = 2766;
606
607 nlpf = (f3db * gdiv28 * 2 / lpf_coeff /
608 (FE_CRYSTAL_KHZ / 1000) + 1) / 2;
609 if (nlpf > 23)
610 nlpf = 23;
611 if (nlpf < 1)
612 nlpf = 1;
613
614 lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000)
615 * lpf_coeff * 2 / f3db + 1) / 2;
616
617 if (lpf_mxdiv < mlpf_min) {
618 nlpf++;
619 lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000)
620 * lpf_coeff * 2 / f3db + 1) / 2;
621 }
622
623 if (lpf_mxdiv > mlpf_max)
624 lpf_mxdiv = mlpf_max;
625
626 ret = m88rs2000_tuner_write(state, 0x04, lpf_mxdiv);
627 ret |= m88rs2000_tuner_write(state, 0x06, nlpf);
628
629 ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
630
631 ret |= m88rs2000_tuner_gate_ctrl(state, 0x01);
632
633 msleep(80);
634 /* calculate offset assuming 96000kHz*/
635 offset_khz = (ndiv - ndiv % 2 + 1024) * FE_CRYSTAL_KHZ
636 / 14 / (div4 + 1) / 2;
637
638 offset_khz -= frequency;
639
640 tmp = offset_khz;
641 tmp *= 65536;
642
643 tmp = (2 * tmp + 96000) / (2 * 96000);
644 if (tmp < 0)
645 tmp += 65536;
646
647 *offset = tmp & 0xffff;
648
649 if (fe->ops.i2c_gate_ctrl)
650 fe->ops.i2c_gate_ctrl(fe, 0);
651
652 return (ret < 0) ? -EINVAL : 0;
653}
654
655static int m88rs2000_set_fec(struct m88rs2000_state *state,
656 fe_code_rate_t fec)
657{
658 int ret;
659 u16 fec_set;
660 switch (fec) {
661 /* This is not confirmed kept for reference */
662/* case FEC_1_2:
663 fec_set = 0x88;
664 break;
665 case FEC_2_3:
666 fec_set = 0x68;
667 break;
668 case FEC_3_4:
669 fec_set = 0x48;
670 break;
671 case FEC_5_6:
672 fec_set = 0x28;
673 break;
674 case FEC_7_8:
675 fec_set = 0x18;
676 break; */
677 case FEC_AUTO:
678 default:
679 fec_set = 0x08;
680 }
681 ret = m88rs2000_demod_write(state, 0x76, fec_set);
682
683 return 0;
684}
685
686
687static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state)
688{
689 u8 reg;
690 m88rs2000_demod_write(state, 0x9a, 0x30);
691 reg = m88rs2000_demod_read(state, 0x76);
692 m88rs2000_demod_write(state, 0x9a, 0xb0);
693
694 switch (reg) {
695 case 0x88:
696 return FEC_1_2;
697 case 0x68:
698 return FEC_2_3;
699 case 0x48:
700 return FEC_3_4;
701 case 0x28:
702 return FEC_5_6;
703 case 0x18:
704 return FEC_7_8;
705 case 0x08:
706 default:
707 break;
708 }
709
710 return FEC_AUTO;
711}
712
713static int m88rs2000_set_frontend(struct dvb_frontend *fe)
714{
715 struct m88rs2000_state *state = fe->demodulator_priv;
716 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
717 fe_status_t status;
718 int i, ret;
719 u16 offset = 0;
720 u8 reg;
721
722 state->no_lock_count = 0;
723
724 if (c->delivery_system != SYS_DVBS) {
725 deb_info("%s: unsupported delivery "
726 "system selected (%d)\n",
727 __func__, c->delivery_system);
728 return -EOPNOTSUPP;
729 }
730
731 /* Set Tuner */
732 ret = m88rs2000_set_tuner(fe, &offset);
733 if (ret < 0)
734 return -ENODEV;
735
736 ret = m88rs2000_demod_write(state, 0x9a, 0x30);
737 /* Unknown usually 0xc6 sometimes 0xc1 */
738 reg = m88rs2000_demod_read(state, 0x86);
739 ret |= m88rs2000_demod_write(state, 0x86, reg);
740 /* Offset lower nibble always 0 */
741 ret |= m88rs2000_demod_write(state, 0x9c, (offset >> 8));
742 ret |= m88rs2000_demod_write(state, 0x9d, offset & 0xf0);
743
744
745 /* Reset Demod */
746 ret = m88rs2000_tab_set(state, fe_reset);
747 if (ret < 0)
748 return -ENODEV;
749
750 /* Unknown */
751 reg = m88rs2000_demod_read(state, 0x70);
752 ret = m88rs2000_demod_write(state, 0x70, reg);
753
754 /* Set FEC */
755 ret |= m88rs2000_set_fec(state, c->fec_inner);
756 ret |= m88rs2000_demod_write(state, 0x85, 0x1);
757 ret |= m88rs2000_demod_write(state, 0x8a, 0xbf);
758 ret |= m88rs2000_demod_write(state, 0x8d, 0x1e);
759 ret |= m88rs2000_demod_write(state, 0x90, 0xf1);
760 ret |= m88rs2000_demod_write(state, 0x91, 0x08);
761
762 if (ret < 0)
763 return -ENODEV;
764
765 /* Set Symbol Rate */
766 ret = m88rs2000_set_symbolrate(fe, c->symbol_rate);
767 if (ret < 0)
768 return -ENODEV;
769
770 /* Set up Demod */
771 ret = m88rs2000_tab_set(state, fe_trigger);
772 if (ret < 0)
773 return -ENODEV;
774
775 for (i = 0; i < 25; i++) {
776 u8 reg = m88rs2000_demod_read(state, 0x8c);
777 if ((reg & 0x7) == 0x7) {
778 status = FE_HAS_LOCK;
779 break;
780 }
781 state->no_lock_count++;
782 if (state->no_lock_count > 15) {
783 reg = m88rs2000_demod_read(state, 0x70);
784 reg ^= 0x4;
785 m88rs2000_demod_write(state, 0x70, reg);
786 state->no_lock_count = 0;
787 }
788 if (state->no_lock_count == 20)
789 m88rs2000_set_tuner_rf(fe);
790 msleep(20);
791 }
792
793 if (status & FE_HAS_LOCK) {
794 state->fec_inner = m88rs2000_get_fec(state);
795 /* Uknown suspect SNR level */
796 reg = m88rs2000_demod_read(state, 0x65);
797 }
798
799 state->tuner_frequency = c->frequency;
800 state->symbol_rate = c->symbol_rate;
801 return 0;
802}
803
804static int m88rs2000_get_frontend(struct dvb_frontend *fe)
805{
806 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
807 struct m88rs2000_state *state = fe->demodulator_priv;
808 c->fec_inner = state->fec_inner;
809 c->frequency = state->tuner_frequency;
810 c->symbol_rate = state->symbol_rate;
811 return 0;
812}
813
814static int m88rs2000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
815{
816 struct m88rs2000_state *state = fe->demodulator_priv;
817
818 if (enable)
819 m88rs2000_demod_write(state, 0x81, 0x84);
820 else
821 m88rs2000_demod_write(state, 0x81, 0x81);
822 udelay(10);
823 return 0;
824}
825
826static void m88rs2000_release(struct dvb_frontend *fe)
827{
828 struct m88rs2000_state *state = fe->demodulator_priv;
829 kfree(state);
830}
831
832static struct dvb_frontend_ops m88rs2000_ops = {
833 .delsys = { SYS_DVBS },
834 .info = {
835 .name = "M88RS2000 DVB-S",
836 .type = FE_QPSK,
837 .frequency_min = 950000,
838 .frequency_max = 2150000,
839 .frequency_stepsize = 1000, /* kHz for QPSK frontends */
840 .frequency_tolerance = 5000,
841 .symbol_rate_min = 1000000,
842 .symbol_rate_max = 45000000,
843 .symbol_rate_tolerance = 500, /* ppm */
844 .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
845 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
846 FE_CAN_QPSK |
847 FE_CAN_FEC_AUTO
848 },
849
850 .release = m88rs2000_release,
851 .init = m88rs2000_init,
852 .sleep = m88rs2000_sleep,
853 .write = m88rs2000_write,
854 .i2c_gate_ctrl = m88rs2000_i2c_gate_ctrl,
855 .read_status = m88rs2000_read_status,
856 .read_ber = m88rs2000_read_ber,
857 .read_signal_strength = m88rs2000_read_signal_strength,
858 .read_snr = m88rs2000_read_snr,
859 .read_ucblocks = m88rs2000_read_ucblocks,
860 .diseqc_send_master_cmd = m88rs2000_send_diseqc_msg,
861 .diseqc_send_burst = m88rs2000_send_diseqc_burst,
862 .set_tone = m88rs2000_set_tone,
863 .set_voltage = m88rs2000_set_voltage,
864
865 .set_frontend = m88rs2000_set_frontend,
866 .get_frontend = m88rs2000_get_frontend,
867};
868
869struct dvb_frontend *m88rs2000_attach(const struct m88rs2000_config *config,
870 struct i2c_adapter *i2c)
871{
872 struct m88rs2000_state *state = NULL;
873
874 /* allocate memory for the internal state */
875 state = kzalloc(sizeof(struct m88rs2000_state), GFP_KERNEL);
876 if (state == NULL)
877 goto error;
878
879 /* setup the state */
880 state->config = config;
881 state->i2c = i2c;
882 state->tuner_frequency = 0;
883 state->symbol_rate = 0;
884 state->fec_inner = 0;
885
886 if (m88rs2000_startup(state) < 0)
887 goto error;
888
889 /* create dvb_frontend */
890 memcpy(&state->frontend.ops, &m88rs2000_ops,
891 sizeof(struct dvb_frontend_ops));
892 state->frontend.demodulator_priv = state;
893 return &state->frontend;
894
895error:
896 kfree(state);
897
898 return NULL;
899}
900EXPORT_SYMBOL(m88rs2000_attach);
901
902MODULE_DESCRIPTION("M88RS2000 DVB-S Demodulator driver");
903MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
904MODULE_LICENSE("GPL");
905MODULE_VERSION("1.12");
906
diff --git a/drivers/media/dvb/frontends/m88rs2000.h b/drivers/media/dvb/frontends/m88rs2000.h
new file mode 100644
index 000000000000..59acdb696873
--- /dev/null
+++ b/drivers/media/dvb/frontends/m88rs2000.h
@@ -0,0 +1,66 @@
1/*
2 Driver for M88RS2000 demodulator
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18*/
19
20#ifndef M88RS2000_H
21#define M88RS2000_H
22
23#include <linux/dvb/frontend.h>
24#include "dvb_frontend.h"
25
26struct m88rs2000_config {
27 /* Demodulator i2c address */
28 u8 demod_addr;
29 /* Tuner address */
30 u8 tuner_addr;
31
32 u8 *inittab;
33
34 /* minimum delay before retuning */
35 int min_delay_ms;
36
37 int (*set_ts_params)(struct dvb_frontend *, int);
38};
39
40enum {
41 CALL_IS_SET_FRONTEND = 0x0,
42 CALL_IS_READ,
43};
44
45#if defined(CONFIG_DVB_M88RS2000) || (defined(CONFIG_DVB_M88RS2000_MODULE) && \
46 defined(MODULE))
47extern struct dvb_frontend *m88rs2000_attach(
48 const struct m88rs2000_config *config, struct i2c_adapter *i2c);
49#else
50static inline struct dvb_frontend *m88rs2000_attach(
51 const struct m88rs2000_config *config, struct i2c_adapter *i2c)
52{
53 printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
54 return NULL;
55}
56#endif /* CONFIG_DVB_M88RS2000 */
57
58#define FE_CRYSTAL_KHZ 27000
59#define FREQ_OFFSET_LOW_SYM_RATE 3000
60
61enum {
62 DEMOD_WRITE = 0x1,
63 TUNER_WRITE,
64 WRITE_DELAY = 0x10,
65};
66#endif /* M88RS2000_H */