blob: 655db8272268d56ef882393923515f8577bc3962 [file] [log] [blame]
Thomas Gleixner74ba9202019-05-20 09:19:02 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 Driver for Spase SP8870 demodulator
4
5 Copyright (C) 1999 Juergen Peitz
6
Linus Torvalds1da177e2005-04-16 15:20:36 -07007
8*/
9/*
10 * This driver needs external firmware. Please use the command
Mauro Carvalho Chehabfe63a1a2018-05-08 18:10:05 -030011 * "<kerneldir>/scripts/get_dvb_firmware alps_tdlb7" to
Ville Skytt\รค12e66f62006-01-09 15:25:38 -020012 * download/extract it, and then copy it to /usr/lib/hotplug/firmware
13 * or /lib/firmware (depending on configuration of firmware hotplug).
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 */
15#define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw"
16
17#include <linux/init.h>
18#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/device.h>
20#include <linux/firmware.h>
21#include <linux/delay.h>
Tim Schmielau4e57b682005-10-30 15:03:48 -080022#include <linux/string.h>
23#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
Mauro Carvalho Chehabfada1932017-12-28 13:03:51 -050025#include <media/dvb_frontend.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include "sp8870.h"
27
28
29struct sp8870_state {
30
31 struct i2c_adapter* i2c;
32
Linus Torvalds1da177e2005-04-16 15:20:36 -070033 const struct sp8870_config* config;
34
35 struct dvb_frontend frontend;
36
37 /* demodulator private data */
38 u8 initialised:1;
39};
40
41static int debug;
42#define dprintk(args...) \
43 do { \
44 if (debug) printk(KERN_DEBUG "sp8870: " args); \
45 } while (0)
46
47/* firmware size for sp8870 */
48#define SP8870_FIRMWARE_SIZE 16382
49
50/* starting point for firmware in file 'Sc_main.mc' */
51#define SP8870_FIRMWARE_OFFSET 0x0A
52
53static int sp8870_writereg (struct sp8870_state* state, u16 reg, u16 data)
54{
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -080055 u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff };
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 4 };
57 int err;
58
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -080059 if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
Harvey Harrison271ddbf2008-04-08 23:20:00 -030060 dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 return -EREMOTEIO;
62 }
63
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -080064 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065}
66
67static int sp8870_readreg (struct sp8870_state* state, u16 reg)
68{
69 int ret;
70 u8 b0 [] = { reg >> 8 , reg & 0xff };
71 u8 b1 [] = { 0, 0 };
72 struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
73 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
74
75 ret = i2c_transfer (state->i2c, msg, 2);
76
77 if (ret != 2) {
Harvey Harrison271ddbf2008-04-08 23:20:00 -030078 dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 return -1;
80 }
81
82 return (b1[0] << 8 | b1[1]);
83}
84
85static int sp8870_firmware_upload (struct sp8870_state* state, const struct firmware *fw)
86{
87 struct i2c_msg msg;
David Woodhousebc179152008-05-24 00:12:23 +010088 const char *fw_buf = fw->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 int fw_pos;
90 u8 tx_buf[255];
91 int tx_len;
92 int err = 0;
93
Harvey Harrison271ddbf2008-04-08 23:20:00 -030094 dprintk ("%s: ...\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96 if (fw->size < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET)
97 return -EINVAL;
98
99 // system controller stop
100 sp8870_writereg(state, 0x0F00, 0x0000);
101
102 // instruction RAM register hiword
103 sp8870_writereg(state, 0x8F08, ((SP8870_FIRMWARE_SIZE / 2) & 0xFFFF));
104
105 // instruction RAM MWR
106 sp8870_writereg(state, 0x8F0A, ((SP8870_FIRMWARE_SIZE / 2) >> 16));
107
108 // do firmware upload
109 fw_pos = SP8870_FIRMWARE_OFFSET;
110 while (fw_pos < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET){
111 tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - 252) ? 252 : SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - fw_pos;
112 // write register 0xCF0A
113 tx_buf[0] = 0xCF;
114 tx_buf[1] = 0x0A;
115 memcpy(&tx_buf[2], fw_buf + fw_pos, tx_len);
116 msg.addr = state->config->demod_address;
117 msg.flags = 0;
118 msg.buf = tx_buf;
119 msg.len = tx_len + 2;
120 if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300121 printk("%s: firmware upload failed!\n", __func__);
122 printk ("%s: i2c error (err == %i)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 return err;
124 }
125 fw_pos += tx_len;
126 }
127
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300128 dprintk ("%s: done!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 return 0;
130};
131
132static void sp8870_microcontroller_stop (struct sp8870_state* state)
133{
134 sp8870_writereg(state, 0x0F08, 0x000);
135 sp8870_writereg(state, 0x0F09, 0x000);
136
137 // microcontroller STOP
138 sp8870_writereg(state, 0x0F00, 0x000);
139}
140
141static void sp8870_microcontroller_start (struct sp8870_state* state)
142{
143 sp8870_writereg(state, 0x0F08, 0x000);
144 sp8870_writereg(state, 0x0F09, 0x000);
145
146 // microcontroller START
147 sp8870_writereg(state, 0x0F00, 0x001);
148 // not documented but if we don't read 0x0D01 out here
149 // we don't get a correct data valid signal
150 sp8870_readreg(state, 0x0D01);
151}
152
153static int sp8870_read_data_valid_signal(struct sp8870_state* state)
154{
155 return (sp8870_readreg(state, 0x0D02) > 0);
156}
157
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300158static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159{
160 int known_parameters = 1;
161
162 *reg0xc05 = 0x000;
163
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300164 switch (p->modulation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 case QPSK:
166 break;
167 case QAM_16:
168 *reg0xc05 |= (1 << 10);
169 break;
170 case QAM_64:
171 *reg0xc05 |= (2 << 10);
172 break;
173 case QAM_AUTO:
174 known_parameters = 0;
175 break;
176 default:
177 return -EINVAL;
Peter Senna Tschudina6224d42012-09-06 12:09:12 -0300178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300180 switch (p->hierarchy) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 case HIERARCHY_NONE:
182 break;
183 case HIERARCHY_1:
184 *reg0xc05 |= (1 << 7);
185 break;
186 case HIERARCHY_2:
187 *reg0xc05 |= (2 << 7);
188 break;
189 case HIERARCHY_4:
190 *reg0xc05 |= (3 << 7);
191 break;
192 case HIERARCHY_AUTO:
193 known_parameters = 0;
194 break;
195 default:
196 return -EINVAL;
Peter Senna Tschudina6224d42012-09-06 12:09:12 -0300197 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300199 switch (p->code_rate_HP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 case FEC_1_2:
201 break;
202 case FEC_2_3:
203 *reg0xc05 |= (1 << 3);
204 break;
205 case FEC_3_4:
206 *reg0xc05 |= (2 << 3);
207 break;
208 case FEC_5_6:
209 *reg0xc05 |= (3 << 3);
210 break;
211 case FEC_7_8:
212 *reg0xc05 |= (4 << 3);
213 break;
214 case FEC_AUTO:
215 known_parameters = 0;
216 break;
217 default:
218 return -EINVAL;
Peter Senna Tschudina6224d42012-09-06 12:09:12 -0300219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
221 if (known_parameters)
222 *reg0xc05 |= (2 << 1); /* use specified parameters */
223 else
224 *reg0xc05 |= (1 << 1); /* enable autoprobing */
225
226 return 0;
227}
228
229static int sp8870_wake_up(struct sp8870_state* state)
230{
231 // enable TS output and interface pins
232 return sp8870_writereg(state, 0xC18, 0x00D);
233}
234
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300235static int sp8870_set_frontend_parameters(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236{
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300237 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700238 struct sp8870_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 int err;
240 u16 reg0xc05;
241
242 if ((err = configure_reg0xc05(p, &reg0xc05)))
243 return err;
244
245 // system controller stop
246 sp8870_microcontroller_stop(state);
247
248 // set tuner parameters
Patrick Boettcherdea74862006-05-14 05:01:31 -0300249 if (fe->ops.tuner_ops.set_params) {
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -0300250 fe->ops.tuner_ops.set_params(fe);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300251 if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
Andrew de Quinceye9f9c0d2006-04-18 17:47:10 -0300252 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
254 // sample rate correction bit [23..17]
255 sp8870_writereg(state, 0x0319, 0x000A);
256
257 // sample rate correction bit [16..0]
258 sp8870_writereg(state, 0x031A, 0x0AAB);
259
260 // integer carrier offset
261 sp8870_writereg(state, 0x0309, 0x0400);
262
263 // fractional carrier offset
264 sp8870_writereg(state, 0x030A, 0x0000);
265
266 // filter for 6/7/8 Mhz channel
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300267 if (p->bandwidth_hz == 6000000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 sp8870_writereg(state, 0x0311, 0x0002);
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300269 else if (p->bandwidth_hz == 7000000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 sp8870_writereg(state, 0x0311, 0x0001);
271 else
272 sp8870_writereg(state, 0x0311, 0x0000);
273
274 // scan order: 2k first = 0x0000, 8k first = 0x0001
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300275 if (p->transmission_mode == TRANSMISSION_MODE_2K)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 sp8870_writereg(state, 0x0338, 0x0000);
277 else
278 sp8870_writereg(state, 0x0338, 0x0001);
279
280 sp8870_writereg(state, 0xc05, reg0xc05);
281
282 // read status reg in order to clear pending irqs
Aditya Pakki467a37f2018-12-27 13:58:01 -0500283 err = sp8870_readreg(state, 0x200);
284 if (err)
285 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287 // system controller start
288 sp8870_microcontroller_start(state);
289
290 return 0;
291}
292
293static int sp8870_init (struct dvb_frontend* fe)
294{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700295 struct sp8870_state* state = fe->demodulator_priv;
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800296 const struct firmware *fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298 sp8870_wake_up(state);
299 if (state->initialised) return 0;
300 state->initialised = 1;
301
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300302 dprintk ("%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
304
305 /* request the firmware, this will block until someone uploads it */
306 printk("sp8870: waiting for firmware upload (%s)...\n", SP8870_DEFAULT_FIRMWARE);
307 if (state->config->request_firmware(fe, &fw, SP8870_DEFAULT_FIRMWARE)) {
308 printk("sp8870: no firmware upload (timeout or file not found?)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 return -EIO;
310 }
311
312 if (sp8870_firmware_upload(state, fw)) {
313 printk("sp8870: writing firmware to device failed\n");
314 release_firmware(fw);
315 return -EIO;
316 }
Magnus Damm73ca66b2006-07-10 04:44:09 -0700317 release_firmware(fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 printk("sp8870: firmware upload complete\n");
319
320 /* enable TS output and interface pins */
321 sp8870_writereg(state, 0xc18, 0x00d);
322
323 // system controller stop
324 sp8870_microcontroller_stop(state);
325
326 // ADC mode
327 sp8870_writereg(state, 0x0301, 0x0003);
328
329 // Reed Solomon parity bytes passed to output
330 sp8870_writereg(state, 0x0C13, 0x0001);
331
332 // MPEG clock is suppressed if no valid data
333 sp8870_writereg(state, 0x0C14, 0x0001);
334
335 /* bit 0x010: enable data valid signal */
336 sp8870_writereg(state, 0x0D00, 0x010);
337 sp8870_writereg(state, 0x0D01, 0x000);
338
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 return 0;
340}
341
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -0300342static int sp8870_read_status(struct dvb_frontend *fe,
343 enum fe_status *fe_status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700345 struct sp8870_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 int status;
347 int signal;
348
349 *fe_status = 0;
350
351 status = sp8870_readreg (state, 0x0200);
352 if (status < 0)
353 return -EIO;
354
355 signal = sp8870_readreg (state, 0x0303);
356 if (signal < 0)
357 return -EIO;
358
359 if (signal > 0x0F)
360 *fe_status |= FE_HAS_SIGNAL;
361 if (status & 0x08)
362 *fe_status |= FE_HAS_SYNC;
363 if (status & 0x04)
364 *fe_status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_VITERBI;
365
366 return 0;
367}
368
369static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber)
370{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700371 struct sp8870_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 int ret;
373 u32 tmp;
374
375 *ber = 0;
376
377 ret = sp8870_readreg(state, 0xC08);
378 if (ret < 0)
379 return -EIO;
380
381 tmp = ret & 0x3F;
382
383 ret = sp8870_readreg(state, 0xC07);
384 if (ret < 0)
385 return -EIO;
386
Mauro Carvalho Chehaba16ae7d2014-09-03 19:13:59 -0300387 tmp = ret << 6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 if (tmp >= 0x3FFF0)
389 tmp = ~0;
390
391 *ber = tmp;
392
393 return 0;
394}
395
396static int sp8870_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
397{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700398 struct sp8870_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 int ret;
400 u16 tmp;
401
402 *signal = 0;
403
404 ret = sp8870_readreg (state, 0x306);
405 if (ret < 0)
406 return -EIO;
407
408 tmp = ret << 8;
409
410 ret = sp8870_readreg (state, 0x303);
411 if (ret < 0)
412 return -EIO;
413
414 tmp |= ret;
415
416 if (tmp)
417 *signal = 0xFFFF - tmp;
418
419 return 0;
420}
421
422static int sp8870_read_uncorrected_blocks (struct dvb_frontend* fe, u32* ublocks)
423{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700424 struct sp8870_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 int ret;
426
427 *ublocks = 0;
428
429 ret = sp8870_readreg(state, 0xC0C);
430 if (ret < 0)
431 return -EIO;
432
433 if (ret == 0xFFFF)
434 ret = ~0;
435
436 *ublocks = ret;
437
438 return 0;
439}
440
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -0300441/* number of trials to recover from lockup */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442#define MAXTRIALS 5
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -0300443/* maximum checks for data valid signal */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444#define MAXCHECKS 100
445
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -0300446/* only for debugging: counter for detected lockups */
447static int lockups;
448/* only for debugging: counter for channel switches */
449static int switches;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300451static int sp8870_set_frontend(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452{
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300453 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700454 struct sp8870_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
456 /*
457 The firmware of the sp8870 sometimes locks up after setting frontend parameters.
458 We try to detect this by checking the data valid signal.
459 If it is not set after MAXCHECKS we try to recover the lockup by setting
460 the frontend parameters again.
461 */
462
463 int err = 0;
464 int valid = 0;
465 int trials = 0;
466 int check_count = 0;
467
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300468 dprintk("%s: frequency = %i\n", __func__, p->frequency);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
470 for (trials = 1; trials <= MAXTRIALS; trials++) {
471
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300472 err = sp8870_set_frontend_parameters(fe);
473 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 return err;
475
476 for (check_count = 0; check_count < MAXCHECKS; check_count++) {
477// valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0);
478 valid = sp8870_read_data_valid_signal(state);
479 if (valid) {
480 dprintk("%s: delay = %i usec\n",
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300481 __func__, check_count * 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 break;
483 }
484 udelay(10);
485 }
486 if (valid)
487 break;
488 }
489
490 if (!valid) {
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300491 printk("%s: firmware crash!!!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 return -EIO;
493 }
494
495 if (debug) {
496 if (valid) {
497 if (trials > 1) {
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300498 printk("%s: firmware lockup!!!\n", __func__);
499 printk("%s: recovered after %i trial(s))\n", __func__, trials - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 lockups++;
501 }
502 }
503 switches++;
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300504 printk("%s: switches = %i lockups = %i\n", __func__, switches, lockups);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 }
506
507 return 0;
508}
509
510static int sp8870_sleep(struct dvb_frontend* fe)
511{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700512 struct sp8870_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
514 // tristate TS output and disable interface pins
515 return sp8870_writereg(state, 0xC18, 0x000);
516}
517
518static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
519{
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800520 fesettings->min_delay_ms = 350;
521 fesettings->step_size = 0;
522 fesettings->max_drift = 0;
523 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524}
525
Andrew de Quinceye9f9c0d2006-04-18 17:47:10 -0300526static int sp8870_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
527{
528 struct sp8870_state* state = fe->demodulator_priv;
529
530 if (enable) {
531 return sp8870_writereg(state, 0x206, 0x001);
532 } else {
533 return sp8870_writereg(state, 0x206, 0x000);
534 }
535}
536
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537static void sp8870_release(struct dvb_frontend* fe)
538{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700539 struct sp8870_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 kfree(state);
541}
542
Max Kellermannbd336e62016-08-09 18:32:21 -0300543static const struct dvb_frontend_ops sp8870_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
545struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
546 struct i2c_adapter* i2c)
547{
548 struct sp8870_state* state = NULL;
549
550 /* allocate memory for the internal state */
Matthias Schwarzott084e24a2009-08-10 22:51:01 -0300551 state = kzalloc(sizeof(struct sp8870_state), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 if (state == NULL) goto error;
553
554 /* setup the state */
555 state->config = config;
556 state->i2c = i2c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 state->initialised = 0;
558
559 /* check if the demod is there */
560 if (sp8870_readreg(state, 0x0200) < 0) goto error;
561
562 /* create dvb_frontend */
Patrick Boettcherdea74862006-05-14 05:01:31 -0300563 memcpy(&state->frontend.ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 state->frontend.demodulator_priv = state;
565 return &state->frontend;
566
567error:
568 kfree(state);
569 return NULL;
570}
571
Max Kellermannbd336e62016-08-09 18:32:21 -0300572static const struct dvb_frontend_ops sp8870_ops = {
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300573 .delsys = { SYS_DVBT },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 .info = {
575 .name = "Spase SP8870 DVB-T",
Mauro Carvalho Chehabf1b1eab2018-07-05 18:59:36 -0400576 .frequency_min_hz = 470 * MHz,
577 .frequency_max_hz = 860 * MHz,
578 .frequency_stepsize_hz = 166666,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
580 FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
581 FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
582 FE_CAN_QPSK | FE_CAN_QAM_16 |
583 FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
584 FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER
585 },
586
587 .release = sp8870_release,
588
589 .init = sp8870_init,
590 .sleep = sp8870_sleep,
Andrew de Quinceye9f9c0d2006-04-18 17:47:10 -0300591 .i2c_gate_ctrl = sp8870_i2c_gate_ctrl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
Mauro Carvalho Chehabdcc9a122011-12-26 12:37:59 -0300593 .set_frontend = sp8870_set_frontend,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 .get_tune_settings = sp8870_get_tune_settings,
595
596 .read_status = sp8870_read_status,
597 .read_ber = sp8870_read_ber,
598 .read_signal_strength = sp8870_read_signal_strength,
599 .read_ucblocks = sp8870_read_uncorrected_blocks,
600};
601
602module_param(debug, int, 0644);
603MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
604
605MODULE_DESCRIPTION("Spase SP8870 DVB-T Demodulator driver");
606MODULE_AUTHOR("Juergen Peitz");
607MODULE_LICENSE("GPL");
608
609EXPORT_SYMBOL(sp8870_attach);