blob: 57dc2abaa87bc7d5e0cf881d3b30e3065a6dfc26 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 Driver for Spase SP8870 demodulator
3
4 Copyright (C) 1999 Juergen Peitz
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 * This driver needs external firmware. Please use the command
24 * "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to
Ville Skytt\รค12e66f62006-01-09 15:25:38 -020025 * download/extract it, and then copy it to /usr/lib/hotplug/firmware
26 * or /lib/firmware (depending on configuration of firmware hotplug).
Linus Torvalds1da177e2005-04-16 15:20:36 -070027 */
28#define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw"
29
30#include <linux/init.h>
31#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/device.h>
33#include <linux/firmware.h>
34#include <linux/delay.h>
Tim Schmielau4e57b682005-10-30 15:03:48 -080035#include <linux/string.h>
36#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
38#include "dvb_frontend.h"
39#include "sp8870.h"
40
41
42struct sp8870_state {
43
44 struct i2c_adapter* i2c;
45
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 const struct sp8870_config* config;
47
48 struct dvb_frontend frontend;
49
50 /* demodulator private data */
51 u8 initialised:1;
52};
53
54static int debug;
55#define dprintk(args...) \
56 do { \
57 if (debug) printk(KERN_DEBUG "sp8870: " args); \
58 } while (0)
59
60/* firmware size for sp8870 */
61#define SP8870_FIRMWARE_SIZE 16382
62
63/* starting point for firmware in file 'Sc_main.mc' */
64#define SP8870_FIRMWARE_OFFSET 0x0A
65
66static int sp8870_writereg (struct sp8870_state* state, u16 reg, u16 data)
67{
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -080068 u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff };
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 4 };
70 int err;
71
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -080072 if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
Harvey Harrison271ddbf2008-04-08 23:20:00 -030073 dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 return -EREMOTEIO;
75 }
76
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -080077 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078}
79
80static int sp8870_readreg (struct sp8870_state* state, u16 reg)
81{
82 int ret;
83 u8 b0 [] = { reg >> 8 , reg & 0xff };
84 u8 b1 [] = { 0, 0 };
85 struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
86 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
87
88 ret = i2c_transfer (state->i2c, msg, 2);
89
90 if (ret != 2) {
Harvey Harrison271ddbf2008-04-08 23:20:00 -030091 dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 return -1;
93 }
94
95 return (b1[0] << 8 | b1[1]);
96}
97
98static int sp8870_firmware_upload (struct sp8870_state* state, const struct firmware *fw)
99{
100 struct i2c_msg msg;
David Woodhousebc179152008-05-24 00:12:23 +0100101 const char *fw_buf = fw->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 int fw_pos;
103 u8 tx_buf[255];
104 int tx_len;
105 int err = 0;
106
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300107 dprintk ("%s: ...\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
109 if (fw->size < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET)
110 return -EINVAL;
111
112 // system controller stop
113 sp8870_writereg(state, 0x0F00, 0x0000);
114
115 // instruction RAM register hiword
116 sp8870_writereg(state, 0x8F08, ((SP8870_FIRMWARE_SIZE / 2) & 0xFFFF));
117
118 // instruction RAM MWR
119 sp8870_writereg(state, 0x8F0A, ((SP8870_FIRMWARE_SIZE / 2) >> 16));
120
121 // do firmware upload
122 fw_pos = SP8870_FIRMWARE_OFFSET;
123 while (fw_pos < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET){
124 tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - 252) ? 252 : SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - fw_pos;
125 // write register 0xCF0A
126 tx_buf[0] = 0xCF;
127 tx_buf[1] = 0x0A;
128 memcpy(&tx_buf[2], fw_buf + fw_pos, tx_len);
129 msg.addr = state->config->demod_address;
130 msg.flags = 0;
131 msg.buf = tx_buf;
132 msg.len = tx_len + 2;
133 if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300134 printk("%s: firmware upload failed!\n", __func__);
135 printk ("%s: i2c error (err == %i)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 return err;
137 }
138 fw_pos += tx_len;
139 }
140
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300141 dprintk ("%s: done!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 return 0;
143};
144
145static void sp8870_microcontroller_stop (struct sp8870_state* state)
146{
147 sp8870_writereg(state, 0x0F08, 0x000);
148 sp8870_writereg(state, 0x0F09, 0x000);
149
150 // microcontroller STOP
151 sp8870_writereg(state, 0x0F00, 0x000);
152}
153
154static void sp8870_microcontroller_start (struct sp8870_state* state)
155{
156 sp8870_writereg(state, 0x0F08, 0x000);
157 sp8870_writereg(state, 0x0F09, 0x000);
158
159 // microcontroller START
160 sp8870_writereg(state, 0x0F00, 0x001);
161 // not documented but if we don't read 0x0D01 out here
162 // we don't get a correct data valid signal
163 sp8870_readreg(state, 0x0D01);
164}
165
166static int sp8870_read_data_valid_signal(struct sp8870_state* state)
167{
168 return (sp8870_readreg(state, 0x0D02) > 0);
169}
170
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300171static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172{
173 int known_parameters = 1;
174
175 *reg0xc05 = 0x000;
176
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300177 switch (p->modulation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 case QPSK:
179 break;
180 case QAM_16:
181 *reg0xc05 |= (1 << 10);
182 break;
183 case QAM_64:
184 *reg0xc05 |= (2 << 10);
185 break;
186 case QAM_AUTO:
187 known_parameters = 0;
188 break;
189 default:
190 return -EINVAL;
Peter Senna Tschudina6224d42012-09-06 12:09:12 -0300191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300193 switch (p->hierarchy) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 case HIERARCHY_NONE:
195 break;
196 case HIERARCHY_1:
197 *reg0xc05 |= (1 << 7);
198 break;
199 case HIERARCHY_2:
200 *reg0xc05 |= (2 << 7);
201 break;
202 case HIERARCHY_4:
203 *reg0xc05 |= (3 << 7);
204 break;
205 case HIERARCHY_AUTO:
206 known_parameters = 0;
207 break;
208 default:
209 return -EINVAL;
Peter Senna Tschudina6224d42012-09-06 12:09:12 -0300210 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300212 switch (p->code_rate_HP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 case FEC_1_2:
214 break;
215 case FEC_2_3:
216 *reg0xc05 |= (1 << 3);
217 break;
218 case FEC_3_4:
219 *reg0xc05 |= (2 << 3);
220 break;
221 case FEC_5_6:
222 *reg0xc05 |= (3 << 3);
223 break;
224 case FEC_7_8:
225 *reg0xc05 |= (4 << 3);
226 break;
227 case FEC_AUTO:
228 known_parameters = 0;
229 break;
230 default:
231 return -EINVAL;
Peter Senna Tschudina6224d42012-09-06 12:09:12 -0300232 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
234 if (known_parameters)
235 *reg0xc05 |= (2 << 1); /* use specified parameters */
236 else
237 *reg0xc05 |= (1 << 1); /* enable autoprobing */
238
239 return 0;
240}
241
242static int sp8870_wake_up(struct sp8870_state* state)
243{
244 // enable TS output and interface pins
245 return sp8870_writereg(state, 0xC18, 0x00D);
246}
247
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300248static int sp8870_set_frontend_parameters(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249{
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300250 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700251 struct sp8870_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 int err;
253 u16 reg0xc05;
254
255 if ((err = configure_reg0xc05(p, &reg0xc05)))
256 return err;
257
258 // system controller stop
259 sp8870_microcontroller_stop(state);
260
261 // set tuner parameters
Patrick Boettcherdea74862006-05-14 05:01:31 -0300262 if (fe->ops.tuner_ops.set_params) {
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -0300263 fe->ops.tuner_ops.set_params(fe);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300264 if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
Andrew de Quinceye9f9c0d2006-04-18 17:47:10 -0300265 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
267 // sample rate correction bit [23..17]
268 sp8870_writereg(state, 0x0319, 0x000A);
269
270 // sample rate correction bit [16..0]
271 sp8870_writereg(state, 0x031A, 0x0AAB);
272
273 // integer carrier offset
274 sp8870_writereg(state, 0x0309, 0x0400);
275
276 // fractional carrier offset
277 sp8870_writereg(state, 0x030A, 0x0000);
278
279 // filter for 6/7/8 Mhz channel
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300280 if (p->bandwidth_hz == 6000000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 sp8870_writereg(state, 0x0311, 0x0002);
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300282 else if (p->bandwidth_hz == 7000000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 sp8870_writereg(state, 0x0311, 0x0001);
284 else
285 sp8870_writereg(state, 0x0311, 0x0000);
286
287 // scan order: 2k first = 0x0000, 8k first = 0x0001
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300288 if (p->transmission_mode == TRANSMISSION_MODE_2K)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 sp8870_writereg(state, 0x0338, 0x0000);
290 else
291 sp8870_writereg(state, 0x0338, 0x0001);
292
293 sp8870_writereg(state, 0xc05, reg0xc05);
294
295 // read status reg in order to clear pending irqs
296 sp8870_readreg(state, 0x200);
297
298 // system controller start
299 sp8870_microcontroller_start(state);
300
301 return 0;
302}
303
304static int sp8870_init (struct dvb_frontend* fe)
305{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700306 struct sp8870_state* state = fe->demodulator_priv;
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800307 const struct firmware *fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309 sp8870_wake_up(state);
310 if (state->initialised) return 0;
311 state->initialised = 1;
312
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300313 dprintk ("%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
315
316 /* request the firmware, this will block until someone uploads it */
317 printk("sp8870: waiting for firmware upload (%s)...\n", SP8870_DEFAULT_FIRMWARE);
318 if (state->config->request_firmware(fe, &fw, SP8870_DEFAULT_FIRMWARE)) {
319 printk("sp8870: no firmware upload (timeout or file not found?)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 return -EIO;
321 }
322
323 if (sp8870_firmware_upload(state, fw)) {
324 printk("sp8870: writing firmware to device failed\n");
325 release_firmware(fw);
326 return -EIO;
327 }
Magnus Damm73ca66b2006-07-10 04:44:09 -0700328 release_firmware(fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 printk("sp8870: firmware upload complete\n");
330
331 /* enable TS output and interface pins */
332 sp8870_writereg(state, 0xc18, 0x00d);
333
334 // system controller stop
335 sp8870_microcontroller_stop(state);
336
337 // ADC mode
338 sp8870_writereg(state, 0x0301, 0x0003);
339
340 // Reed Solomon parity bytes passed to output
341 sp8870_writereg(state, 0x0C13, 0x0001);
342
343 // MPEG clock is suppressed if no valid data
344 sp8870_writereg(state, 0x0C14, 0x0001);
345
346 /* bit 0x010: enable data valid signal */
347 sp8870_writereg(state, 0x0D00, 0x010);
348 sp8870_writereg(state, 0x0D01, 0x000);
349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 return 0;
351}
352
353static int sp8870_read_status (struct dvb_frontend* fe, fe_status_t * fe_status)
354{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700355 struct sp8870_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 int status;
357 int signal;
358
359 *fe_status = 0;
360
361 status = sp8870_readreg (state, 0x0200);
362 if (status < 0)
363 return -EIO;
364
365 signal = sp8870_readreg (state, 0x0303);
366 if (signal < 0)
367 return -EIO;
368
369 if (signal > 0x0F)
370 *fe_status |= FE_HAS_SIGNAL;
371 if (status & 0x08)
372 *fe_status |= FE_HAS_SYNC;
373 if (status & 0x04)
374 *fe_status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_VITERBI;
375
376 return 0;
377}
378
379static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber)
380{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700381 struct sp8870_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 int ret;
383 u32 tmp;
384
385 *ber = 0;
386
387 ret = sp8870_readreg(state, 0xC08);
388 if (ret < 0)
389 return -EIO;
390
391 tmp = ret & 0x3F;
392
393 ret = sp8870_readreg(state, 0xC07);
394 if (ret < 0)
395 return -EIO;
396
Mauro Carvalho Chehaba16ae7d2014-09-03 19:13:59 -0300397 tmp = ret << 6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 if (tmp >= 0x3FFF0)
399 tmp = ~0;
400
401 *ber = tmp;
402
403 return 0;
404}
405
406static int sp8870_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
407{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700408 struct sp8870_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 int ret;
410 u16 tmp;
411
412 *signal = 0;
413
414 ret = sp8870_readreg (state, 0x306);
415 if (ret < 0)
416 return -EIO;
417
418 tmp = ret << 8;
419
420 ret = sp8870_readreg (state, 0x303);
421 if (ret < 0)
422 return -EIO;
423
424 tmp |= ret;
425
426 if (tmp)
427 *signal = 0xFFFF - tmp;
428
429 return 0;
430}
431
432static int sp8870_read_uncorrected_blocks (struct dvb_frontend* fe, u32* ublocks)
433{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700434 struct sp8870_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 int ret;
436
437 *ublocks = 0;
438
439 ret = sp8870_readreg(state, 0xC0C);
440 if (ret < 0)
441 return -EIO;
442
443 if (ret == 0xFFFF)
444 ret = ~0;
445
446 *ublocks = ret;
447
448 return 0;
449}
450
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -0300451/* number of trials to recover from lockup */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452#define MAXTRIALS 5
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -0300453/* maximum checks for data valid signal */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454#define MAXCHECKS 100
455
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -0300456/* only for debugging: counter for detected lockups */
457static int lockups;
458/* only for debugging: counter for channel switches */
459static int switches;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300461static int sp8870_set_frontend(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462{
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300463 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700464 struct sp8870_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
466 /*
467 The firmware of the sp8870 sometimes locks up after setting frontend parameters.
468 We try to detect this by checking the data valid signal.
469 If it is not set after MAXCHECKS we try to recover the lockup by setting
470 the frontend parameters again.
471 */
472
473 int err = 0;
474 int valid = 0;
475 int trials = 0;
476 int check_count = 0;
477
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300478 dprintk("%s: frequency = %i\n", __func__, p->frequency);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
480 for (trials = 1; trials <= MAXTRIALS; trials++) {
481
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300482 err = sp8870_set_frontend_parameters(fe);
483 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 return err;
485
486 for (check_count = 0; check_count < MAXCHECKS; check_count++) {
487// valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0);
488 valid = sp8870_read_data_valid_signal(state);
489 if (valid) {
490 dprintk("%s: delay = %i usec\n",
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300491 __func__, check_count * 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 break;
493 }
494 udelay(10);
495 }
496 if (valid)
497 break;
498 }
499
500 if (!valid) {
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300501 printk("%s: firmware crash!!!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 return -EIO;
503 }
504
505 if (debug) {
506 if (valid) {
507 if (trials > 1) {
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300508 printk("%s: firmware lockup!!!\n", __func__);
509 printk("%s: recovered after %i trial(s))\n", __func__, trials - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 lockups++;
511 }
512 }
513 switches++;
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300514 printk("%s: switches = %i lockups = %i\n", __func__, switches, lockups);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 }
516
517 return 0;
518}
519
520static int sp8870_sleep(struct dvb_frontend* fe)
521{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700522 struct sp8870_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
524 // tristate TS output and disable interface pins
525 return sp8870_writereg(state, 0xC18, 0x000);
526}
527
528static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
529{
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800530 fesettings->min_delay_ms = 350;
531 fesettings->step_size = 0;
532 fesettings->max_drift = 0;
533 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534}
535
Andrew de Quinceye9f9c0d2006-04-18 17:47:10 -0300536static int sp8870_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
537{
538 struct sp8870_state* state = fe->demodulator_priv;
539
540 if (enable) {
541 return sp8870_writereg(state, 0x206, 0x001);
542 } else {
543 return sp8870_writereg(state, 0x206, 0x000);
544 }
545}
546
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547static void sp8870_release(struct dvb_frontend* fe)
548{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700549 struct sp8870_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 kfree(state);
551}
552
553static struct dvb_frontend_ops sp8870_ops;
554
555struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
556 struct i2c_adapter* i2c)
557{
558 struct sp8870_state* state = NULL;
559
560 /* allocate memory for the internal state */
Matthias Schwarzott084e24a2009-08-10 22:51:01 -0300561 state = kzalloc(sizeof(struct sp8870_state), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 if (state == NULL) goto error;
563
564 /* setup the state */
565 state->config = config;
566 state->i2c = i2c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 state->initialised = 0;
568
569 /* check if the demod is there */
570 if (sp8870_readreg(state, 0x0200) < 0) goto error;
571
572 /* create dvb_frontend */
Patrick Boettcherdea74862006-05-14 05:01:31 -0300573 memcpy(&state->frontend.ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 state->frontend.demodulator_priv = state;
575 return &state->frontend;
576
577error:
578 kfree(state);
579 return NULL;
580}
581
582static struct dvb_frontend_ops sp8870_ops = {
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300583 .delsys = { SYS_DVBT },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 .info = {
585 .name = "Spase SP8870 DVB-T",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 .frequency_min = 470000000,
587 .frequency_max = 860000000,
588 .frequency_stepsize = 166666,
589 .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
590 FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
591 FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
592 FE_CAN_QPSK | FE_CAN_QAM_16 |
593 FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
594 FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER
595 },
596
597 .release = sp8870_release,
598
599 .init = sp8870_init,
600 .sleep = sp8870_sleep,
Andrew de Quinceye9f9c0d2006-04-18 17:47:10 -0300601 .i2c_gate_ctrl = sp8870_i2c_gate_ctrl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300603 .set_frontend = sp8870_set_frontend,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 .get_tune_settings = sp8870_get_tune_settings,
605
606 .read_status = sp8870_read_status,
607 .read_ber = sp8870_read_ber,
608 .read_signal_strength = sp8870_read_signal_strength,
609 .read_ucblocks = sp8870_read_uncorrected_blocks,
610};
611
612module_param(debug, int, 0644);
613MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
614
615MODULE_DESCRIPTION("Spase SP8870 DVB-T Demodulator driver");
616MODULE_AUTHOR("Juergen Peitz");
617MODULE_LICENSE("GPL");
618
619EXPORT_SYMBOL(sp8870_attach);