xref: /linux/drivers/media/dvb-frontends/ds3000.c (revision 58e16d792a6a8c6b750f637a4649967fcac853dc)
1*74ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
209ea33e5SIgor M. Liplianin /*
3c1965eaeSKonstantin Dimitrov     Montage Technology DS3000 - DVBS/S2 Demodulator driver
4c1965eaeSKonstantin Dimitrov     Copyright (C) 2009-2012 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
509ea33e5SIgor M. Liplianin 
6c1965eaeSKonstantin Dimitrov     Copyright (C) 2009-2012 TurboSight.com
709ea33e5SIgor M. Liplianin 
809ea33e5SIgor M. Liplianin  */
909ea33e5SIgor M. Liplianin 
1009ea33e5SIgor M. Liplianin #include <linux/slab.h>
1109ea33e5SIgor M. Liplianin #include <linux/kernel.h>
1209ea33e5SIgor M. Liplianin #include <linux/module.h>
1309ea33e5SIgor M. Liplianin #include <linux/moduleparam.h>
1409ea33e5SIgor M. Liplianin #include <linux/init.h>
1509ea33e5SIgor M. Liplianin #include <linux/firmware.h>
1609ea33e5SIgor M. Liplianin 
17fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
1873f0af44SKonstantin Dimitrov #include "ts2020.h"
1909ea33e5SIgor M. Liplianin #include "ds3000.h"
2009ea33e5SIgor M. Liplianin 
2109ea33e5SIgor M. Liplianin static int debug;
2209ea33e5SIgor M. Liplianin 
2309ea33e5SIgor M. Liplianin #define dprintk(args...) \
2409ea33e5SIgor M. Liplianin 	do { \
2509ea33e5SIgor M. Liplianin 		if (debug) \
2609ea33e5SIgor M. Liplianin 			printk(args); \
2709ea33e5SIgor M. Liplianin 	} while (0)
2809ea33e5SIgor M. Liplianin 
2909ea33e5SIgor M. Liplianin /* as of March 2009 current DS3000 firmware version is 1.78 */
3009ea33e5SIgor M. Liplianin /* DS3000 FW v1.78 MD5: a32d17910c4f370073f9346e71d34b80 */
3109ea33e5SIgor M. Liplianin #define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds3000.fw"
3209ea33e5SIgor M. Liplianin 
3309ea33e5SIgor M. Liplianin #define DS3000_SAMPLE_RATE 96000 /* in kHz */
3409ea33e5SIgor M. Liplianin 
3509ea33e5SIgor M. Liplianin /* Register values to initialise the demod in DVB-S mode */
3609ea33e5SIgor M. Liplianin static u8 ds3000_dvbs_init_tab[] = {
3709ea33e5SIgor M. Liplianin 	0x23, 0x05,
3809ea33e5SIgor M. Liplianin 	0x08, 0x03,
3909ea33e5SIgor M. Liplianin 	0x0c, 0x00,
4009ea33e5SIgor M. Liplianin 	0x21, 0x54,
4109ea33e5SIgor M. Liplianin 	0x25, 0x82,
4209ea33e5SIgor M. Liplianin 	0x27, 0x31,
4309ea33e5SIgor M. Liplianin 	0x30, 0x08,
4409ea33e5SIgor M. Liplianin 	0x31, 0x40,
4509ea33e5SIgor M. Liplianin 	0x32, 0x32,
4609ea33e5SIgor M. Liplianin 	0x33, 0x35,
4709ea33e5SIgor M. Liplianin 	0x35, 0xff,
4809ea33e5SIgor M. Liplianin 	0x3a, 0x00,
4909ea33e5SIgor M. Liplianin 	0x37, 0x10,
5009ea33e5SIgor M. Liplianin 	0x38, 0x10,
5109ea33e5SIgor M. Liplianin 	0x39, 0x02,
5209ea33e5SIgor M. Liplianin 	0x42, 0x60,
5309ea33e5SIgor M. Liplianin 	0x4a, 0x40,
5409ea33e5SIgor M. Liplianin 	0x4b, 0x04,
5509ea33e5SIgor M. Liplianin 	0x4d, 0x91,
5609ea33e5SIgor M. Liplianin 	0x5d, 0xc8,
5709ea33e5SIgor M. Liplianin 	0x50, 0x77,
5809ea33e5SIgor M. Liplianin 	0x51, 0x77,
5909ea33e5SIgor M. Liplianin 	0x52, 0x36,
6009ea33e5SIgor M. Liplianin 	0x53, 0x36,
6109ea33e5SIgor M. Liplianin 	0x56, 0x01,
6209ea33e5SIgor M. Liplianin 	0x63, 0x43,
6309ea33e5SIgor M. Liplianin 	0x64, 0x30,
6409ea33e5SIgor M. Liplianin 	0x65, 0x40,
6509ea33e5SIgor M. Liplianin 	0x68, 0x26,
6609ea33e5SIgor M. Liplianin 	0x69, 0x4c,
6709ea33e5SIgor M. Liplianin 	0x70, 0x20,
6809ea33e5SIgor M. Liplianin 	0x71, 0x70,
6909ea33e5SIgor M. Liplianin 	0x72, 0x04,
7009ea33e5SIgor M. Liplianin 	0x73, 0x00,
7109ea33e5SIgor M. Liplianin 	0x70, 0x40,
7209ea33e5SIgor M. Liplianin 	0x71, 0x70,
7309ea33e5SIgor M. Liplianin 	0x72, 0x04,
7409ea33e5SIgor M. Liplianin 	0x73, 0x00,
7509ea33e5SIgor M. Liplianin 	0x70, 0x60,
7609ea33e5SIgor M. Liplianin 	0x71, 0x70,
7709ea33e5SIgor M. Liplianin 	0x72, 0x04,
7809ea33e5SIgor M. Liplianin 	0x73, 0x00,
7909ea33e5SIgor M. Liplianin 	0x70, 0x80,
8009ea33e5SIgor M. Liplianin 	0x71, 0x70,
8109ea33e5SIgor M. Liplianin 	0x72, 0x04,
8209ea33e5SIgor M. Liplianin 	0x73, 0x00,
8309ea33e5SIgor M. Liplianin 	0x70, 0xa0,
8409ea33e5SIgor M. Liplianin 	0x71, 0x70,
8509ea33e5SIgor M. Liplianin 	0x72, 0x04,
8609ea33e5SIgor M. Liplianin 	0x73, 0x00,
8709ea33e5SIgor M. Liplianin 	0x70, 0x1f,
8809ea33e5SIgor M. Liplianin 	0x76, 0x00,
8909ea33e5SIgor M. Liplianin 	0x77, 0xd1,
9009ea33e5SIgor M. Liplianin 	0x78, 0x0c,
9109ea33e5SIgor M. Liplianin 	0x79, 0x80,
9209ea33e5SIgor M. Liplianin 	0x7f, 0x04,
9309ea33e5SIgor M. Liplianin 	0x7c, 0x00,
9409ea33e5SIgor M. Liplianin 	0x80, 0x86,
9509ea33e5SIgor M. Liplianin 	0x81, 0xa6,
9609ea33e5SIgor M. Liplianin 	0x85, 0x04,
9709ea33e5SIgor M. Liplianin 	0xcd, 0xf4,
9809ea33e5SIgor M. Liplianin 	0x90, 0x33,
9909ea33e5SIgor M. Liplianin 	0xa0, 0x44,
10009ea33e5SIgor M. Liplianin 	0xc0, 0x18,
10109ea33e5SIgor M. Liplianin 	0xc3, 0x10,
10209ea33e5SIgor M. Liplianin 	0xc4, 0x08,
10309ea33e5SIgor M. Liplianin 	0xc5, 0x80,
10409ea33e5SIgor M. Liplianin 	0xc6, 0x80,
10509ea33e5SIgor M. Liplianin 	0xc7, 0x0a,
10609ea33e5SIgor M. Liplianin 	0xc8, 0x1a,
10709ea33e5SIgor M. Liplianin 	0xc9, 0x80,
10809ea33e5SIgor M. Liplianin 	0xfe, 0x92,
10909ea33e5SIgor M. Liplianin 	0xe0, 0xf8,
11009ea33e5SIgor M. Liplianin 	0xe6, 0x8b,
11109ea33e5SIgor M. Liplianin 	0xd0, 0x40,
11209ea33e5SIgor M. Liplianin 	0xf8, 0x20,
11309ea33e5SIgor M. Liplianin 	0xfa, 0x0f,
11409ea33e5SIgor M. Liplianin 	0xfd, 0x20,
11509ea33e5SIgor M. Liplianin 	0xad, 0x20,
11609ea33e5SIgor M. Liplianin 	0xae, 0x07,
11709ea33e5SIgor M. Liplianin 	0xb8, 0x00,
11809ea33e5SIgor M. Liplianin };
11909ea33e5SIgor M. Liplianin 
12009ea33e5SIgor M. Liplianin /* Register values to initialise the demod in DVB-S2 mode */
12109ea33e5SIgor M. Liplianin static u8 ds3000_dvbs2_init_tab[] = {
12209ea33e5SIgor M. Liplianin 	0x23, 0x0f,
12309ea33e5SIgor M. Liplianin 	0x08, 0x07,
12409ea33e5SIgor M. Liplianin 	0x0c, 0x00,
12509ea33e5SIgor M. Liplianin 	0x21, 0x54,
12609ea33e5SIgor M. Liplianin 	0x25, 0x82,
12709ea33e5SIgor M. Liplianin 	0x27, 0x31,
12809ea33e5SIgor M. Liplianin 	0x30, 0x08,
12909ea33e5SIgor M. Liplianin 	0x31, 0x32,
13009ea33e5SIgor M. Liplianin 	0x32, 0x32,
13109ea33e5SIgor M. Liplianin 	0x33, 0x35,
13209ea33e5SIgor M. Liplianin 	0x35, 0xff,
13309ea33e5SIgor M. Liplianin 	0x3a, 0x00,
13409ea33e5SIgor M. Liplianin 	0x37, 0x10,
13509ea33e5SIgor M. Liplianin 	0x38, 0x10,
13609ea33e5SIgor M. Liplianin 	0x39, 0x02,
13709ea33e5SIgor M. Liplianin 	0x42, 0x60,
13809ea33e5SIgor M. Liplianin 	0x4a, 0x80,
13909ea33e5SIgor M. Liplianin 	0x4b, 0x04,
14009ea33e5SIgor M. Liplianin 	0x4d, 0x81,
14109ea33e5SIgor M. Liplianin 	0x5d, 0x88,
14209ea33e5SIgor M. Liplianin 	0x50, 0x36,
14309ea33e5SIgor M. Liplianin 	0x51, 0x36,
14409ea33e5SIgor M. Liplianin 	0x52, 0x36,
14509ea33e5SIgor M. Liplianin 	0x53, 0x36,
14609ea33e5SIgor M. Liplianin 	0x63, 0x60,
14709ea33e5SIgor M. Liplianin 	0x64, 0x10,
14809ea33e5SIgor M. Liplianin 	0x65, 0x10,
14909ea33e5SIgor M. Liplianin 	0x68, 0x04,
15009ea33e5SIgor M. Liplianin 	0x69, 0x29,
15109ea33e5SIgor M. Liplianin 	0x70, 0x20,
15209ea33e5SIgor M. Liplianin 	0x71, 0x70,
15309ea33e5SIgor M. Liplianin 	0x72, 0x04,
15409ea33e5SIgor M. Liplianin 	0x73, 0x00,
15509ea33e5SIgor M. Liplianin 	0x70, 0x40,
15609ea33e5SIgor M. Liplianin 	0x71, 0x70,
15709ea33e5SIgor M. Liplianin 	0x72, 0x04,
15809ea33e5SIgor M. Liplianin 	0x73, 0x00,
15909ea33e5SIgor M. Liplianin 	0x70, 0x60,
16009ea33e5SIgor M. Liplianin 	0x71, 0x70,
16109ea33e5SIgor M. Liplianin 	0x72, 0x04,
16209ea33e5SIgor M. Liplianin 	0x73, 0x00,
16309ea33e5SIgor M. Liplianin 	0x70, 0x80,
16409ea33e5SIgor M. Liplianin 	0x71, 0x70,
16509ea33e5SIgor M. Liplianin 	0x72, 0x04,
16609ea33e5SIgor M. Liplianin 	0x73, 0x00,
16709ea33e5SIgor M. Liplianin 	0x70, 0xa0,
16809ea33e5SIgor M. Liplianin 	0x71, 0x70,
16909ea33e5SIgor M. Liplianin 	0x72, 0x04,
17009ea33e5SIgor M. Liplianin 	0x73, 0x00,
17109ea33e5SIgor M. Liplianin 	0x70, 0x1f,
17209ea33e5SIgor M. Liplianin 	0xa0, 0x44,
17309ea33e5SIgor M. Liplianin 	0xc0, 0x08,
17409ea33e5SIgor M. Liplianin 	0xc1, 0x10,
17509ea33e5SIgor M. Liplianin 	0xc2, 0x08,
17609ea33e5SIgor M. Liplianin 	0xc3, 0x10,
17709ea33e5SIgor M. Liplianin 	0xc4, 0x08,
17809ea33e5SIgor M. Liplianin 	0xc5, 0xf0,
17909ea33e5SIgor M. Liplianin 	0xc6, 0xf0,
18009ea33e5SIgor M. Liplianin 	0xc7, 0x0a,
18109ea33e5SIgor M. Liplianin 	0xc8, 0x1a,
18209ea33e5SIgor M. Liplianin 	0xc9, 0x80,
18309ea33e5SIgor M. Liplianin 	0xca, 0x23,
18409ea33e5SIgor M. Liplianin 	0xcb, 0x24,
18509ea33e5SIgor M. Liplianin 	0xce, 0x74,
18609ea33e5SIgor M. Liplianin 	0x90, 0x03,
18709ea33e5SIgor M. Liplianin 	0x76, 0x80,
18809ea33e5SIgor M. Liplianin 	0x77, 0x42,
18909ea33e5SIgor M. Liplianin 	0x78, 0x0a,
19009ea33e5SIgor M. Liplianin 	0x79, 0x80,
19109ea33e5SIgor M. Liplianin 	0xad, 0x40,
19209ea33e5SIgor M. Liplianin 	0xae, 0x07,
19309ea33e5SIgor M. Liplianin 	0x7f, 0xd4,
19409ea33e5SIgor M. Liplianin 	0x7c, 0x00,
19509ea33e5SIgor M. Liplianin 	0x80, 0xa8,
19609ea33e5SIgor M. Liplianin 	0x81, 0xda,
19709ea33e5SIgor M. Liplianin 	0x7c, 0x01,
19809ea33e5SIgor M. Liplianin 	0x80, 0xda,
19909ea33e5SIgor M. Liplianin 	0x81, 0xec,
20009ea33e5SIgor M. Liplianin 	0x7c, 0x02,
20109ea33e5SIgor M. Liplianin 	0x80, 0xca,
20209ea33e5SIgor M. Liplianin 	0x81, 0xeb,
20309ea33e5SIgor M. Liplianin 	0x7c, 0x03,
20409ea33e5SIgor M. Liplianin 	0x80, 0xba,
20509ea33e5SIgor M. Liplianin 	0x81, 0xdb,
20609ea33e5SIgor M. Liplianin 	0x85, 0x08,
20709ea33e5SIgor M. Liplianin 	0x86, 0x00,
20809ea33e5SIgor M. Liplianin 	0x87, 0x02,
20909ea33e5SIgor M. Liplianin 	0x89, 0x80,
21009ea33e5SIgor M. Liplianin 	0x8b, 0x44,
21109ea33e5SIgor M. Liplianin 	0x8c, 0xaa,
21209ea33e5SIgor M. Liplianin 	0x8a, 0x10,
21309ea33e5SIgor M. Liplianin 	0xba, 0x00,
21409ea33e5SIgor M. Liplianin 	0xf5, 0x04,
21509ea33e5SIgor M. Liplianin 	0xfe, 0x44,
21609ea33e5SIgor M. Liplianin 	0xd2, 0x32,
21709ea33e5SIgor M. Liplianin 	0xb8, 0x00,
21809ea33e5SIgor M. Liplianin };
21909ea33e5SIgor M. Liplianin 
22009ea33e5SIgor M. Liplianin struct ds3000_state {
22109ea33e5SIgor M. Liplianin 	struct i2c_adapter *i2c;
22209ea33e5SIgor M. Liplianin 	const struct ds3000_config *config;
22309ea33e5SIgor M. Liplianin 	struct dvb_frontend frontend;
22409ea33e5SIgor M. Liplianin 	/* previous uncorrected block counter for DVB-S2 */
22509ea33e5SIgor M. Liplianin 	u16 prevUCBS2;
22609ea33e5SIgor M. Liplianin };
22709ea33e5SIgor M. Liplianin 
22809ea33e5SIgor M. Liplianin static int ds3000_writereg(struct ds3000_state *state, int reg, int data)
22909ea33e5SIgor M. Liplianin {
23009ea33e5SIgor M. Liplianin 	u8 buf[] = { reg, data };
23109ea33e5SIgor M. Liplianin 	struct i2c_msg msg = { .addr = state->config->demod_address,
23209ea33e5SIgor M. Liplianin 		.flags = 0, .buf = buf, .len = 2 };
23309ea33e5SIgor M. Liplianin 	int err;
23409ea33e5SIgor M. Liplianin 
23509ea33e5SIgor M. Liplianin 	dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data);
23609ea33e5SIgor M. Liplianin 
23709ea33e5SIgor M. Liplianin 	err = i2c_transfer(state->i2c, &msg, 1);
23809ea33e5SIgor M. Liplianin 	if (err != 1) {
2394bd69e7bSMauro Carvalho Chehab 		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x, value == 0x%02x)\n",
2404bd69e7bSMauro Carvalho Chehab 		       __func__, err, reg, data);
24109ea33e5SIgor M. Liplianin 		return -EREMOTEIO;
24209ea33e5SIgor M. Liplianin 	}
24309ea33e5SIgor M. Liplianin 
24409ea33e5SIgor M. Liplianin 	return 0;
24509ea33e5SIgor M. Liplianin }
24609ea33e5SIgor M. Liplianin 
247c1965eaeSKonstantin Dimitrov static int ds3000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
24809ea33e5SIgor M. Liplianin {
249c1965eaeSKonstantin Dimitrov 	struct ds3000_state *state = fe->demodulator_priv;
25009ea33e5SIgor M. Liplianin 
251c1965eaeSKonstantin Dimitrov 	if (enable)
252c1965eaeSKonstantin Dimitrov 		ds3000_writereg(state, 0x03, 0x12);
253c1965eaeSKonstantin Dimitrov 	else
254c1965eaeSKonstantin Dimitrov 		ds3000_writereg(state, 0x03, 0x02);
25509ea33e5SIgor M. Liplianin 
25609ea33e5SIgor M. Liplianin 	return 0;
25709ea33e5SIgor M. Liplianin }
25809ea33e5SIgor M. Liplianin 
25909ea33e5SIgor M. Liplianin /* I2C write for 8k firmware load */
26009ea33e5SIgor M. Liplianin static int ds3000_writeFW(struct ds3000_state *state, int reg,
26109ea33e5SIgor M. Liplianin 				const u8 *data, u16 len)
26209ea33e5SIgor M. Liplianin {
263d58f4f27SRémi Cardona 	int i, ret = 0;
26409ea33e5SIgor M. Liplianin 	struct i2c_msg msg;
26509ea33e5SIgor M. Liplianin 	u8 *buf;
26609ea33e5SIgor M. Liplianin 
267caa687c8SIgor M. Liplianin 	buf = kmalloc(33, GFP_KERNEL);
268c38e8657SMarkus Elfring 	if (!buf)
269d58f4f27SRémi Cardona 		return -ENOMEM;
27009ea33e5SIgor M. Liplianin 
27109ea33e5SIgor M. Liplianin 	*(buf) = reg;
27209ea33e5SIgor M. Liplianin 
27309ea33e5SIgor M. Liplianin 	msg.addr = state->config->demod_address;
27409ea33e5SIgor M. Liplianin 	msg.flags = 0;
27509ea33e5SIgor M. Liplianin 	msg.buf = buf;
276caa687c8SIgor M. Liplianin 	msg.len = 33;
27709ea33e5SIgor M. Liplianin 
278caa687c8SIgor M. Liplianin 	for (i = 0; i < len; i += 32) {
279caa687c8SIgor M. Liplianin 		memcpy(buf + 1, data + i, 32);
28009ea33e5SIgor M. Liplianin 
28109ea33e5SIgor M. Liplianin 		dprintk("%s: write reg 0x%02x, len = %d\n", __func__, reg, len);
28209ea33e5SIgor M. Liplianin 
28309ea33e5SIgor M. Liplianin 		ret = i2c_transfer(state->i2c, &msg, 1);
28409ea33e5SIgor M. Liplianin 		if (ret != 1) {
2854bd69e7bSMauro Carvalho Chehab 			printk(KERN_ERR "%s: write error(err == %i, reg == 0x%02x\n",
2864bd69e7bSMauro Carvalho Chehab 			       __func__, ret, reg);
28709ea33e5SIgor M. Liplianin 			ret = -EREMOTEIO;
288d58f4f27SRémi Cardona 			goto error;
28909ea33e5SIgor M. Liplianin 		}
29009ea33e5SIgor M. Liplianin 	}
291d58f4f27SRémi Cardona 	ret = 0;
29209ea33e5SIgor M. Liplianin 
29309ea33e5SIgor M. Liplianin error:
29409ea33e5SIgor M. Liplianin 	kfree(buf);
29509ea33e5SIgor M. Liplianin 
29609ea33e5SIgor M. Liplianin 	return ret;
29709ea33e5SIgor M. Liplianin }
29809ea33e5SIgor M. Liplianin 
29909ea33e5SIgor M. Liplianin static int ds3000_readreg(struct ds3000_state *state, u8 reg)
30009ea33e5SIgor M. Liplianin {
30109ea33e5SIgor M. Liplianin 	int ret;
30209ea33e5SIgor M. Liplianin 	u8 b0[] = { reg };
30309ea33e5SIgor M. Liplianin 	u8 b1[] = { 0 };
30409ea33e5SIgor M. Liplianin 	struct i2c_msg msg[] = {
30509ea33e5SIgor M. Liplianin 		{
30609ea33e5SIgor M. Liplianin 			.addr = state->config->demod_address,
30709ea33e5SIgor M. Liplianin 			.flags = 0,
30809ea33e5SIgor M. Liplianin 			.buf = b0,
30909ea33e5SIgor M. Liplianin 			.len = 1
31009ea33e5SIgor M. Liplianin 		}, {
31109ea33e5SIgor M. Liplianin 			.addr = state->config->demod_address,
31209ea33e5SIgor M. Liplianin 			.flags = I2C_M_RD,
31309ea33e5SIgor M. Liplianin 			.buf = b1,
31409ea33e5SIgor M. Liplianin 			.len = 1
31509ea33e5SIgor M. Liplianin 		}
31609ea33e5SIgor M. Liplianin 	};
31709ea33e5SIgor M. Liplianin 
31809ea33e5SIgor M. Liplianin 	ret = i2c_transfer(state->i2c, msg, 2);
31909ea33e5SIgor M. Liplianin 
32009ea33e5SIgor M. Liplianin 	if (ret != 2) {
32109ea33e5SIgor M. Liplianin 		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
32209ea33e5SIgor M. Liplianin 		return ret;
32309ea33e5SIgor M. Liplianin 	}
32409ea33e5SIgor M. Liplianin 
32509ea33e5SIgor M. Liplianin 	dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]);
32609ea33e5SIgor M. Liplianin 
32709ea33e5SIgor M. Liplianin 	return b1[0];
32809ea33e5SIgor M. Liplianin }
32909ea33e5SIgor M. Liplianin 
33009ea33e5SIgor M. Liplianin static int ds3000_load_firmware(struct dvb_frontend *fe,
33109ea33e5SIgor M. Liplianin 					const struct firmware *fw);
33209ea33e5SIgor M. Liplianin 
33309ea33e5SIgor M. Liplianin static int ds3000_firmware_ondemand(struct dvb_frontend *fe)
33409ea33e5SIgor M. Liplianin {
33509ea33e5SIgor M. Liplianin 	struct ds3000_state *state = fe->demodulator_priv;
33609ea33e5SIgor M. Liplianin 	const struct firmware *fw;
33709ea33e5SIgor M. Liplianin 	int ret = 0;
33809ea33e5SIgor M. Liplianin 
33909ea33e5SIgor M. Liplianin 	dprintk("%s()\n", __func__);
34009ea33e5SIgor M. Liplianin 
341034351ffSRémi Cardona 	ret = ds3000_readreg(state, 0xb2);
342034351ffSRémi Cardona 	if (ret < 0)
34309ea33e5SIgor M. Liplianin 		return ret;
34409ea33e5SIgor M. Liplianin 
34509ea33e5SIgor M. Liplianin 	/* Load firmware */
34609ea33e5SIgor M. Liplianin 	/* request the firmware, this will block until someone uploads it */
34709ea33e5SIgor M. Liplianin 	printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
34809ea33e5SIgor M. Liplianin 				DS3000_DEFAULT_FIRMWARE);
34909ea33e5SIgor M. Liplianin 	ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE,
35009ea33e5SIgor M. Liplianin 				state->i2c->dev.parent);
35109ea33e5SIgor M. Liplianin 	printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__);
35209ea33e5SIgor M. Liplianin 	if (ret) {
3534bd69e7bSMauro Carvalho Chehab 		printk(KERN_ERR "%s: No firmware uploaded (timeout or file not found?)\n",
3544bd69e7bSMauro Carvalho Chehab 		       __func__);
35509ea33e5SIgor M. Liplianin 		return ret;
35609ea33e5SIgor M. Liplianin 	}
35709ea33e5SIgor M. Liplianin 
35809ea33e5SIgor M. Liplianin 	ret = ds3000_load_firmware(fe, fw);
35909ea33e5SIgor M. Liplianin 	if (ret)
36009ea33e5SIgor M. Liplianin 		printk("%s: Writing firmware to device failed\n", __func__);
36109ea33e5SIgor M. Liplianin 
36209ea33e5SIgor M. Liplianin 	release_firmware(fw);
36309ea33e5SIgor M. Liplianin 
36409ea33e5SIgor M. Liplianin 	dprintk("%s: Firmware upload %s\n", __func__,
36509ea33e5SIgor M. Liplianin 			ret == 0 ? "complete" : "failed");
36609ea33e5SIgor M. Liplianin 
36709ea33e5SIgor M. Liplianin 	return ret;
36809ea33e5SIgor M. Liplianin }
36909ea33e5SIgor M. Liplianin 
37009ea33e5SIgor M. Liplianin static int ds3000_load_firmware(struct dvb_frontend *fe,
37109ea33e5SIgor M. Liplianin 					const struct firmware *fw)
37209ea33e5SIgor M. Liplianin {
37309ea33e5SIgor M. Liplianin 	struct ds3000_state *state = fe->demodulator_priv;
374d58f4f27SRémi Cardona 	int ret = 0;
37509ea33e5SIgor M. Liplianin 
37609ea33e5SIgor M. Liplianin 	dprintk("%s\n", __func__);
37709ea33e5SIgor M. Liplianin 	dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
37809ea33e5SIgor M. Liplianin 			fw->size,
37909ea33e5SIgor M. Liplianin 			fw->data[0],
38009ea33e5SIgor M. Liplianin 			fw->data[1],
38109ea33e5SIgor M. Liplianin 			fw->data[fw->size - 2],
38209ea33e5SIgor M. Liplianin 			fw->data[fw->size - 1]);
38309ea33e5SIgor M. Liplianin 
38409ea33e5SIgor M. Liplianin 	/* Begin the firmware load process */
38509ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0xb2, 0x01);
38609ea33e5SIgor M. Liplianin 	/* write the entire firmware */
387d58f4f27SRémi Cardona 	ret = ds3000_writeFW(state, 0xb0, fw->data, fw->size);
38809ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0xb2, 0x00);
38909ea33e5SIgor M. Liplianin 
390d58f4f27SRémi Cardona 	return ret;
39109ea33e5SIgor M. Liplianin }
39209ea33e5SIgor M. Liplianin 
3930df289a2SMauro Carvalho Chehab static int ds3000_set_voltage(struct dvb_frontend *fe,
3940df289a2SMauro Carvalho Chehab 			      enum fe_sec_voltage voltage)
395d2ffc447SIgor M. Liplianin {
396d2ffc447SIgor M. Liplianin 	struct ds3000_state *state = fe->demodulator_priv;
397d2ffc447SIgor M. Liplianin 	u8 data;
398d2ffc447SIgor M. Liplianin 
399d2ffc447SIgor M. Liplianin 	dprintk("%s(%d)\n", __func__, voltage);
400d2ffc447SIgor M. Liplianin 
401d2ffc447SIgor M. Liplianin 	data = ds3000_readreg(state, 0xa2);
402d2ffc447SIgor M. Liplianin 	data |= 0x03; /* bit0 V/H, bit1 off/on */
403d2ffc447SIgor M. Liplianin 
404d2ffc447SIgor M. Liplianin 	switch (voltage) {
405d2ffc447SIgor M. Liplianin 	case SEC_VOLTAGE_18:
406d2ffc447SIgor M. Liplianin 		data &= ~0x03;
407d2ffc447SIgor M. Liplianin 		break;
408d2ffc447SIgor M. Liplianin 	case SEC_VOLTAGE_13:
409d2ffc447SIgor M. Liplianin 		data &= ~0x03;
410d2ffc447SIgor M. Liplianin 		data |= 0x01;
411d2ffc447SIgor M. Liplianin 		break;
412d2ffc447SIgor M. Liplianin 	case SEC_VOLTAGE_OFF:
413d2ffc447SIgor M. Liplianin 		break;
414d2ffc447SIgor M. Liplianin 	}
415d2ffc447SIgor M. Liplianin 
416d2ffc447SIgor M. Liplianin 	ds3000_writereg(state, 0xa2, data);
417d2ffc447SIgor M. Liplianin 
418d2ffc447SIgor M. Liplianin 	return 0;
419d2ffc447SIgor M. Liplianin }
420d2ffc447SIgor M. Liplianin 
4210df289a2SMauro Carvalho Chehab static int ds3000_read_status(struct dvb_frontend *fe, enum fe_status *status)
42209ea33e5SIgor M. Liplianin {
42309ea33e5SIgor M. Liplianin 	struct ds3000_state *state = fe->demodulator_priv;
42409ea33e5SIgor M. Liplianin 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
42509ea33e5SIgor M. Liplianin 	int lock;
42609ea33e5SIgor M. Liplianin 
42709ea33e5SIgor M. Liplianin 	*status = 0;
42809ea33e5SIgor M. Liplianin 
42909ea33e5SIgor M. Liplianin 	switch (c->delivery_system) {
43009ea33e5SIgor M. Liplianin 	case SYS_DVBS:
43109ea33e5SIgor M. Liplianin 		lock = ds3000_readreg(state, 0xd1);
43209ea33e5SIgor M. Liplianin 		if ((lock & 0x07) == 0x07)
43309ea33e5SIgor M. Liplianin 			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
43409ea33e5SIgor M. Liplianin 				FE_HAS_VITERBI | FE_HAS_SYNC |
43509ea33e5SIgor M. Liplianin 				FE_HAS_LOCK;
43609ea33e5SIgor M. Liplianin 
43709ea33e5SIgor M. Liplianin 		break;
43809ea33e5SIgor M. Liplianin 	case SYS_DVBS2:
43909ea33e5SIgor M. Liplianin 		lock = ds3000_readreg(state, 0x0d);
44009ea33e5SIgor M. Liplianin 		if ((lock & 0x8f) == 0x8f)
44109ea33e5SIgor M. Liplianin 			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
44209ea33e5SIgor M. Liplianin 				FE_HAS_VITERBI | FE_HAS_SYNC |
44309ea33e5SIgor M. Liplianin 				FE_HAS_LOCK;
44409ea33e5SIgor M. Liplianin 
44509ea33e5SIgor M. Liplianin 		break;
44609ea33e5SIgor M. Liplianin 	default:
44727924dccSOlli Salonen 		return -EINVAL;
44809ea33e5SIgor M. Liplianin 	}
44909ea33e5SIgor M. Liplianin 
45043385c8aSIgor M. Liplianin 	if (state->config->set_lock_led)
45143385c8aSIgor M. Liplianin 		state->config->set_lock_led(fe, *status == 0 ? 0 : 1);
45243385c8aSIgor M. Liplianin 
45309ea33e5SIgor M. Liplianin 	dprintk("%s: status = 0x%02x\n", __func__, lock);
45409ea33e5SIgor M. Liplianin 
45509ea33e5SIgor M. Liplianin 	return 0;
45609ea33e5SIgor M. Liplianin }
45709ea33e5SIgor M. Liplianin 
45809ea33e5SIgor M. Liplianin /* read DS3000 BER value */
45909ea33e5SIgor M. Liplianin static int ds3000_read_ber(struct dvb_frontend *fe, u32* ber)
46009ea33e5SIgor M. Liplianin {
46109ea33e5SIgor M. Liplianin 	struct ds3000_state *state = fe->demodulator_priv;
46209ea33e5SIgor M. Liplianin 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
46309ea33e5SIgor M. Liplianin 	u8 data;
46409ea33e5SIgor M. Liplianin 	u32 ber_reading, lpdc_frames;
46509ea33e5SIgor M. Liplianin 
46609ea33e5SIgor M. Liplianin 	dprintk("%s()\n", __func__);
46709ea33e5SIgor M. Liplianin 
46809ea33e5SIgor M. Liplianin 	switch (c->delivery_system) {
46909ea33e5SIgor M. Liplianin 	case SYS_DVBS:
47009ea33e5SIgor M. Liplianin 		/* set the number of bytes checked during
47109ea33e5SIgor M. Liplianin 		BER estimation */
47209ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xf9, 0x04);
47309ea33e5SIgor M. Liplianin 		/* read BER estimation status */
47409ea33e5SIgor M. Liplianin 		data = ds3000_readreg(state, 0xf8);
47509ea33e5SIgor M. Liplianin 		/* check if BER estimation is ready */
47609ea33e5SIgor M. Liplianin 		if ((data & 0x10) == 0) {
47709ea33e5SIgor M. Liplianin 			/* this is the number of error bits,
47809ea33e5SIgor M. Liplianin 			to calculate the bit error rate
47909ea33e5SIgor M. Liplianin 			divide to 8388608 */
48009ea33e5SIgor M. Liplianin 			*ber = (ds3000_readreg(state, 0xf7) << 8) |
48109ea33e5SIgor M. Liplianin 				ds3000_readreg(state, 0xf6);
48209ea33e5SIgor M. Liplianin 			/* start counting error bits */
48309ea33e5SIgor M. Liplianin 			/* need to be set twice
48409ea33e5SIgor M. Liplianin 			otherwise it fails sometimes */
48509ea33e5SIgor M. Liplianin 			data |= 0x10;
48609ea33e5SIgor M. Liplianin 			ds3000_writereg(state, 0xf8, data);
48709ea33e5SIgor M. Liplianin 			ds3000_writereg(state, 0xf8, data);
48809ea33e5SIgor M. Liplianin 		} else
48909ea33e5SIgor M. Liplianin 			/* used to indicate that BER estimation
49009ea33e5SIgor M. Liplianin 			is not ready, i.e. BER is unknown */
49109ea33e5SIgor M. Liplianin 			*ber = 0xffffffff;
49209ea33e5SIgor M. Liplianin 		break;
49309ea33e5SIgor M. Liplianin 	case SYS_DVBS2:
49409ea33e5SIgor M. Liplianin 		/* read the number of LPDC decoded frames */
49509ea33e5SIgor M. Liplianin 		lpdc_frames = (ds3000_readreg(state, 0xd7) << 16) |
49609ea33e5SIgor M. Liplianin 				(ds3000_readreg(state, 0xd6) << 8) |
49709ea33e5SIgor M. Liplianin 				ds3000_readreg(state, 0xd5);
49809ea33e5SIgor M. Liplianin 		/* read the number of packets with bad CRC */
49909ea33e5SIgor M. Liplianin 		ber_reading = (ds3000_readreg(state, 0xf8) << 8) |
50009ea33e5SIgor M. Liplianin 				ds3000_readreg(state, 0xf7);
50109ea33e5SIgor M. Liplianin 		if (lpdc_frames > 750) {
50209ea33e5SIgor M. Liplianin 			/* clear LPDC frame counters */
50309ea33e5SIgor M. Liplianin 			ds3000_writereg(state, 0xd1, 0x01);
50409ea33e5SIgor M. Liplianin 			/* clear bad packets counter */
50509ea33e5SIgor M. Liplianin 			ds3000_writereg(state, 0xf9, 0x01);
50609ea33e5SIgor M. Liplianin 			/* enable bad packets counter */
50709ea33e5SIgor M. Liplianin 			ds3000_writereg(state, 0xf9, 0x00);
50809ea33e5SIgor M. Liplianin 			/* enable LPDC frame counters */
50909ea33e5SIgor M. Liplianin 			ds3000_writereg(state, 0xd1, 0x00);
51009ea33e5SIgor M. Liplianin 			*ber = ber_reading;
51109ea33e5SIgor M. Liplianin 		} else
51209ea33e5SIgor M. Liplianin 			/* used to indicate that BER estimation is not ready,
51309ea33e5SIgor M. Liplianin 			i.e. BER is unknown */
51409ea33e5SIgor M. Liplianin 			*ber = 0xffffffff;
51509ea33e5SIgor M. Liplianin 		break;
51609ea33e5SIgor M. Liplianin 	default:
51727924dccSOlli Salonen 		return -EINVAL;
51809ea33e5SIgor M. Liplianin 	}
51909ea33e5SIgor M. Liplianin 
52009ea33e5SIgor M. Liplianin 	return 0;
52109ea33e5SIgor M. Liplianin }
52209ea33e5SIgor M. Liplianin 
523a0a030bdSMalcolm Priestley static int ds3000_read_signal_strength(struct dvb_frontend *fe,
524a0a030bdSMalcolm Priestley 						u16 *signal_strength)
525a0a030bdSMalcolm Priestley {
526a0a030bdSMalcolm Priestley 	if (fe->ops.tuner_ops.get_rf_strength)
527a0a030bdSMalcolm Priestley 		fe->ops.tuner_ops.get_rf_strength(fe, signal_strength);
528a0a030bdSMalcolm Priestley 
529a0a030bdSMalcolm Priestley 	return 0;
530a0a030bdSMalcolm Priestley }
531a0a030bdSMalcolm Priestley 
53209ea33e5SIgor M. Liplianin /* calculate DS3000 snr value in dB */
53309ea33e5SIgor M. Liplianin static int ds3000_read_snr(struct dvb_frontend *fe, u16 *snr)
53409ea33e5SIgor M. Liplianin {
53509ea33e5SIgor M. Liplianin 	struct ds3000_state *state = fe->demodulator_priv;
53609ea33e5SIgor M. Liplianin 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
53709ea33e5SIgor M. Liplianin 	u8 snr_reading, snr_value;
53809ea33e5SIgor M. Liplianin 	u32 dvbs2_signal_reading, dvbs2_noise_reading, tmp;
53909ea33e5SIgor M. Liplianin 	static const u16 dvbs_snr_tab[] = { /* 20 x Table (rounded up) */
54009ea33e5SIgor M. Liplianin 		0x0000, 0x1b13, 0x2aea, 0x3627, 0x3ede, 0x45fe, 0x4c03,
54109ea33e5SIgor M. Liplianin 		0x513a, 0x55d4, 0x59f2, 0x5dab, 0x6111, 0x6431, 0x6717,
54209ea33e5SIgor M. Liplianin 		0x69c9, 0x6c4e, 0x6eac, 0x70e8, 0x7304, 0x7505
54309ea33e5SIgor M. Liplianin 	};
54409ea33e5SIgor M. Liplianin 	static const u16 dvbs2_snr_tab[] = { /* 80 x Table (rounded up) */
54509ea33e5SIgor M. Liplianin 		0x0000, 0x0bc2, 0x12a3, 0x1785, 0x1b4e, 0x1e65, 0x2103,
54609ea33e5SIgor M. Liplianin 		0x2347, 0x2546, 0x2710, 0x28ae, 0x2a28, 0x2b83, 0x2cc5,
54709ea33e5SIgor M. Liplianin 		0x2df1, 0x2f09, 0x3010, 0x3109, 0x31f4, 0x32d2, 0x33a6,
54809ea33e5SIgor M. Liplianin 		0x3470, 0x3531, 0x35ea, 0x369b, 0x3746, 0x37ea, 0x3888,
54909ea33e5SIgor M. Liplianin 		0x3920, 0x39b3, 0x3a42, 0x3acc, 0x3b51, 0x3bd3, 0x3c51,
55009ea33e5SIgor M. Liplianin 		0x3ccb, 0x3d42, 0x3db6, 0x3e27, 0x3e95, 0x3f00, 0x3f68,
55109ea33e5SIgor M. Liplianin 		0x3fcf, 0x4033, 0x4094, 0x40f4, 0x4151, 0x41ac, 0x4206,
55209ea33e5SIgor M. Liplianin 		0x425e, 0x42b4, 0x4308, 0x435b, 0x43ac, 0x43fc, 0x444a,
55309ea33e5SIgor M. Liplianin 		0x4497, 0x44e2, 0x452d, 0x4576, 0x45bd, 0x4604, 0x4649,
55409ea33e5SIgor M. Liplianin 		0x468e, 0x46d1, 0x4713, 0x4755, 0x4795, 0x47d4, 0x4813,
55509ea33e5SIgor M. Liplianin 		0x4851, 0x488d, 0x48c9, 0x4904, 0x493f, 0x4978, 0x49b1,
55609ea33e5SIgor M. Liplianin 		0x49e9, 0x4a20, 0x4a57
55709ea33e5SIgor M. Liplianin 	};
55809ea33e5SIgor M. Liplianin 
55909ea33e5SIgor M. Liplianin 	dprintk("%s()\n", __func__);
56009ea33e5SIgor M. Liplianin 
56109ea33e5SIgor M. Liplianin 	switch (c->delivery_system) {
56209ea33e5SIgor M. Liplianin 	case SYS_DVBS:
56309ea33e5SIgor M. Liplianin 		snr_reading = ds3000_readreg(state, 0xff);
56409ea33e5SIgor M. Liplianin 		snr_reading /= 8;
56509ea33e5SIgor M. Liplianin 		if (snr_reading == 0)
56609ea33e5SIgor M. Liplianin 			*snr = 0x0000;
56709ea33e5SIgor M. Liplianin 		else {
56809ea33e5SIgor M. Liplianin 			if (snr_reading > 20)
56909ea33e5SIgor M. Liplianin 				snr_reading = 20;
57009ea33e5SIgor M. Liplianin 			snr_value = dvbs_snr_tab[snr_reading - 1] * 10 / 23026;
57109ea33e5SIgor M. Liplianin 			/* cook the value to be suitable for szap-s2
57209ea33e5SIgor M. Liplianin 			human readable output */
57309ea33e5SIgor M. Liplianin 			*snr = snr_value * 8 * 655;
57409ea33e5SIgor M. Liplianin 		}
57509ea33e5SIgor M. Liplianin 		dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
57609ea33e5SIgor M. Liplianin 				snr_reading, *snr);
57709ea33e5SIgor M. Liplianin 		break;
57809ea33e5SIgor M. Liplianin 	case SYS_DVBS2:
57909ea33e5SIgor M. Liplianin 		dvbs2_noise_reading = (ds3000_readreg(state, 0x8c) & 0x3f) +
58009ea33e5SIgor M. Liplianin 				(ds3000_readreg(state, 0x8d) << 4);
58109ea33e5SIgor M. Liplianin 		dvbs2_signal_reading = ds3000_readreg(state, 0x8e);
58209ea33e5SIgor M. Liplianin 		tmp = dvbs2_signal_reading * dvbs2_signal_reading >> 1;
583450df222SNicolas Noirbent 		if (tmp == 0) {
58409ea33e5SIgor M. Liplianin 			*snr = 0x0000;
58509ea33e5SIgor M. Liplianin 			return 0;
58609ea33e5SIgor M. Liplianin 		}
58709ea33e5SIgor M. Liplianin 		if (dvbs2_noise_reading == 0) {
58809ea33e5SIgor M. Liplianin 			snr_value = 0x0013;
58909ea33e5SIgor M. Liplianin 			/* cook the value to be suitable for szap-s2
59009ea33e5SIgor M. Liplianin 			human readable output */
59109ea33e5SIgor M. Liplianin 			*snr = 0xffff;
59209ea33e5SIgor M. Liplianin 			return 0;
59309ea33e5SIgor M. Liplianin 		}
59409ea33e5SIgor M. Liplianin 		if (tmp > dvbs2_noise_reading) {
59509ea33e5SIgor M. Liplianin 			snr_reading = tmp / dvbs2_noise_reading;
59609ea33e5SIgor M. Liplianin 			if (snr_reading > 80)
59709ea33e5SIgor M. Liplianin 				snr_reading = 80;
59809ea33e5SIgor M. Liplianin 			snr_value = dvbs2_snr_tab[snr_reading - 1] / 1000;
59909ea33e5SIgor M. Liplianin 			/* cook the value to be suitable for szap-s2
60009ea33e5SIgor M. Liplianin 			human readable output */
60109ea33e5SIgor M. Liplianin 			*snr = snr_value * 5 * 655;
60209ea33e5SIgor M. Liplianin 		} else {
60309ea33e5SIgor M. Liplianin 			snr_reading = dvbs2_noise_reading / tmp;
60409ea33e5SIgor M. Liplianin 			if (snr_reading > 80)
60509ea33e5SIgor M. Liplianin 				snr_reading = 80;
606b59de95bSHeinrich Schuchardt 			*snr = -(dvbs2_snr_tab[snr_reading - 1] / 1000);
60709ea33e5SIgor M. Liplianin 		}
60809ea33e5SIgor M. Liplianin 		dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
60909ea33e5SIgor M. Liplianin 				snr_reading, *snr);
61009ea33e5SIgor M. Liplianin 		break;
61109ea33e5SIgor M. Liplianin 	default:
61227924dccSOlli Salonen 		return -EINVAL;
61309ea33e5SIgor M. Liplianin 	}
61409ea33e5SIgor M. Liplianin 
61509ea33e5SIgor M. Liplianin 	return 0;
61609ea33e5SIgor M. Liplianin }
61709ea33e5SIgor M. Liplianin 
61809ea33e5SIgor M. Liplianin /* read DS3000 uncorrected blocks */
61909ea33e5SIgor M. Liplianin static int ds3000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
62009ea33e5SIgor M. Liplianin {
62109ea33e5SIgor M. Liplianin 	struct ds3000_state *state = fe->demodulator_priv;
62209ea33e5SIgor M. Liplianin 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
62309ea33e5SIgor M. Liplianin 	u8 data;
62409ea33e5SIgor M. Liplianin 	u16 _ucblocks;
62509ea33e5SIgor M. Liplianin 
62609ea33e5SIgor M. Liplianin 	dprintk("%s()\n", __func__);
62709ea33e5SIgor M. Liplianin 
62809ea33e5SIgor M. Liplianin 	switch (c->delivery_system) {
62909ea33e5SIgor M. Liplianin 	case SYS_DVBS:
63009ea33e5SIgor M. Liplianin 		*ucblocks = (ds3000_readreg(state, 0xf5) << 8) |
63109ea33e5SIgor M. Liplianin 				ds3000_readreg(state, 0xf4);
63209ea33e5SIgor M. Liplianin 		data = ds3000_readreg(state, 0xf8);
63309ea33e5SIgor M. Liplianin 		/* clear packet counters */
63409ea33e5SIgor M. Liplianin 		data &= ~0x20;
63509ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xf8, data);
63609ea33e5SIgor M. Liplianin 		/* enable packet counters */
63709ea33e5SIgor M. Liplianin 		data |= 0x20;
63809ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xf8, data);
63909ea33e5SIgor M. Liplianin 		break;
64009ea33e5SIgor M. Liplianin 	case SYS_DVBS2:
64109ea33e5SIgor M. Liplianin 		_ucblocks = (ds3000_readreg(state, 0xe2) << 8) |
64209ea33e5SIgor M. Liplianin 				ds3000_readreg(state, 0xe1);
64309ea33e5SIgor M. Liplianin 		if (_ucblocks > state->prevUCBS2)
64409ea33e5SIgor M. Liplianin 			*ucblocks = _ucblocks - state->prevUCBS2;
64509ea33e5SIgor M. Liplianin 		else
64609ea33e5SIgor M. Liplianin 			*ucblocks = state->prevUCBS2 - _ucblocks;
64709ea33e5SIgor M. Liplianin 		state->prevUCBS2 = _ucblocks;
64809ea33e5SIgor M. Liplianin 		break;
64909ea33e5SIgor M. Liplianin 	default:
65027924dccSOlli Salonen 		return -EINVAL;
65109ea33e5SIgor M. Liplianin 	}
65209ea33e5SIgor M. Liplianin 
65309ea33e5SIgor M. Liplianin 	return 0;
65409ea33e5SIgor M. Liplianin }
65509ea33e5SIgor M. Liplianin 
6560df289a2SMauro Carvalho Chehab static int ds3000_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone)
65709ea33e5SIgor M. Liplianin {
65809ea33e5SIgor M. Liplianin 	struct ds3000_state *state = fe->demodulator_priv;
65909ea33e5SIgor M. Liplianin 	u8 data;
66009ea33e5SIgor M. Liplianin 
66109ea33e5SIgor M. Liplianin 	dprintk("%s(%d)\n", __func__, tone);
66209ea33e5SIgor M. Liplianin 	if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
66309ea33e5SIgor M. Liplianin 		printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
66409ea33e5SIgor M. Liplianin 		return -EINVAL;
66509ea33e5SIgor M. Liplianin 	}
66609ea33e5SIgor M. Liplianin 
66709ea33e5SIgor M. Liplianin 	data = ds3000_readreg(state, 0xa2);
66809ea33e5SIgor M. Liplianin 	data &= ~0xc0;
66909ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0xa2, data);
67009ea33e5SIgor M. Liplianin 
67109ea33e5SIgor M. Liplianin 	switch (tone) {
67209ea33e5SIgor M. Liplianin 	case SEC_TONE_ON:
67309ea33e5SIgor M. Liplianin 		dprintk("%s: setting tone on\n", __func__);
67409ea33e5SIgor M. Liplianin 		data = ds3000_readreg(state, 0xa1);
67509ea33e5SIgor M. Liplianin 		data &= ~0x43;
67609ea33e5SIgor M. Liplianin 		data |= 0x04;
67709ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xa1, data);
67809ea33e5SIgor M. Liplianin 		break;
67909ea33e5SIgor M. Liplianin 	case SEC_TONE_OFF:
68009ea33e5SIgor M. Liplianin 		dprintk("%s: setting tone off\n", __func__);
68109ea33e5SIgor M. Liplianin 		data = ds3000_readreg(state, 0xa2);
68209ea33e5SIgor M. Liplianin 		data |= 0x80;
68309ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xa2, data);
68409ea33e5SIgor M. Liplianin 		break;
68509ea33e5SIgor M. Liplianin 	}
68609ea33e5SIgor M. Liplianin 
68709ea33e5SIgor M. Liplianin 	return 0;
68809ea33e5SIgor M. Liplianin }
68909ea33e5SIgor M. Liplianin 
69009ea33e5SIgor M. Liplianin static int ds3000_send_diseqc_msg(struct dvb_frontend *fe,
69109ea33e5SIgor M. Liplianin 				struct dvb_diseqc_master_cmd *d)
69209ea33e5SIgor M. Liplianin {
69309ea33e5SIgor M. Liplianin 	struct ds3000_state *state = fe->demodulator_priv;
69409ea33e5SIgor M. Liplianin 	int i;
69509ea33e5SIgor M. Liplianin 	u8 data;
69609ea33e5SIgor M. Liplianin 
69709ea33e5SIgor M. Liplianin 	/* Dump DiSEqC message */
69809ea33e5SIgor M. Liplianin 	dprintk("%s(", __func__);
69909ea33e5SIgor M. Liplianin 	for (i = 0 ; i < d->msg_len;) {
70009ea33e5SIgor M. Liplianin 		dprintk("0x%02x", d->msg[i]);
70109ea33e5SIgor M. Liplianin 		if (++i < d->msg_len)
70209ea33e5SIgor M. Liplianin 			dprintk(", ");
70309ea33e5SIgor M. Liplianin 	}
70409ea33e5SIgor M. Liplianin 
70509ea33e5SIgor M. Liplianin 	/* enable DiSEqC message send pin */
70609ea33e5SIgor M. Liplianin 	data = ds3000_readreg(state, 0xa2);
70709ea33e5SIgor M. Liplianin 	data &= ~0xc0;
70809ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0xa2, data);
70909ea33e5SIgor M. Liplianin 
71009ea33e5SIgor M. Liplianin 	/* DiSEqC message */
71109ea33e5SIgor M. Liplianin 	for (i = 0; i < d->msg_len; i++)
71209ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xa3 + i, d->msg[i]);
71309ea33e5SIgor M. Liplianin 
71409ea33e5SIgor M. Liplianin 	data = ds3000_readreg(state, 0xa1);
71509ea33e5SIgor M. Liplianin 	/* clear DiSEqC message length and status,
71609ea33e5SIgor M. Liplianin 	enable DiSEqC message send */
71709ea33e5SIgor M. Liplianin 	data &= ~0xf8;
71809ea33e5SIgor M. Liplianin 	/* set DiSEqC mode, modulation active during 33 pulses,
71909ea33e5SIgor M. Liplianin 	set DiSEqC message length */
72009ea33e5SIgor M. Liplianin 	data |= ((d->msg_len - 1) << 3) | 0x07;
72109ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0xa1, data);
72209ea33e5SIgor M. Liplianin 
72309ea33e5SIgor M. Liplianin 	/* wait up to 150ms for DiSEqC transmission to complete */
72409ea33e5SIgor M. Liplianin 	for (i = 0; i < 15; i++) {
72509ea33e5SIgor M. Liplianin 		data = ds3000_readreg(state, 0xa1);
72609ea33e5SIgor M. Liplianin 		if ((data & 0x40) == 0)
72709ea33e5SIgor M. Liplianin 			break;
72809ea33e5SIgor M. Liplianin 		msleep(10);
72909ea33e5SIgor M. Liplianin 	}
73009ea33e5SIgor M. Liplianin 
73109ea33e5SIgor M. Liplianin 	/* DiSEqC timeout after 150ms */
73209ea33e5SIgor M. Liplianin 	if (i == 15) {
73309ea33e5SIgor M. Liplianin 		data = ds3000_readreg(state, 0xa1);
73409ea33e5SIgor M. Liplianin 		data &= ~0x80;
73509ea33e5SIgor M. Liplianin 		data |= 0x40;
73609ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xa1, data);
73709ea33e5SIgor M. Liplianin 
73809ea33e5SIgor M. Liplianin 		data = ds3000_readreg(state, 0xa2);
73909ea33e5SIgor M. Liplianin 		data &= ~0xc0;
74009ea33e5SIgor M. Liplianin 		data |= 0x80;
74109ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xa2, data);
74209ea33e5SIgor M. Liplianin 
74327924dccSOlli Salonen 		return -ETIMEDOUT;
74409ea33e5SIgor M. Liplianin 	}
74509ea33e5SIgor M. Liplianin 
74609ea33e5SIgor M. Liplianin 	data = ds3000_readreg(state, 0xa2);
74709ea33e5SIgor M. Liplianin 	data &= ~0xc0;
74809ea33e5SIgor M. Liplianin 	data |= 0x80;
74909ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0xa2, data);
75009ea33e5SIgor M. Liplianin 
75109ea33e5SIgor M. Liplianin 	return 0;
75209ea33e5SIgor M. Liplianin }
75309ea33e5SIgor M. Liplianin 
75409ea33e5SIgor M. Liplianin /* Send DiSEqC burst */
75509ea33e5SIgor M. Liplianin static int ds3000_diseqc_send_burst(struct dvb_frontend *fe,
7560df289a2SMauro Carvalho Chehab 				    enum fe_sec_mini_cmd burst)
75709ea33e5SIgor M. Liplianin {
75809ea33e5SIgor M. Liplianin 	struct ds3000_state *state = fe->demodulator_priv;
75909ea33e5SIgor M. Liplianin 	int i;
76009ea33e5SIgor M. Liplianin 	u8 data;
76109ea33e5SIgor M. Liplianin 
76209ea33e5SIgor M. Liplianin 	dprintk("%s()\n", __func__);
76309ea33e5SIgor M. Liplianin 
76409ea33e5SIgor M. Liplianin 	data = ds3000_readreg(state, 0xa2);
76509ea33e5SIgor M. Liplianin 	data &= ~0xc0;
76609ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0xa2, data);
76709ea33e5SIgor M. Liplianin 
76809ea33e5SIgor M. Liplianin 	/* DiSEqC burst */
76909ea33e5SIgor M. Liplianin 	if (burst == SEC_MINI_A)
77009ea33e5SIgor M. Liplianin 		/* Unmodulated tone burst */
77109ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xa1, 0x02);
77209ea33e5SIgor M. Liplianin 	else if (burst == SEC_MINI_B)
77309ea33e5SIgor M. Liplianin 		/* Modulated tone burst */
77409ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xa1, 0x01);
77509ea33e5SIgor M. Liplianin 	else
77609ea33e5SIgor M. Liplianin 		return -EINVAL;
77709ea33e5SIgor M. Liplianin 
77809ea33e5SIgor M. Liplianin 	msleep(13);
77909ea33e5SIgor M. Liplianin 	for (i = 0; i < 5; i++) {
78009ea33e5SIgor M. Liplianin 		data = ds3000_readreg(state, 0xa1);
78109ea33e5SIgor M. Liplianin 		if ((data & 0x40) == 0)
78209ea33e5SIgor M. Liplianin 			break;
78309ea33e5SIgor M. Liplianin 		msleep(1);
78409ea33e5SIgor M. Liplianin 	}
78509ea33e5SIgor M. Liplianin 
78609ea33e5SIgor M. Liplianin 	if (i == 5) {
78709ea33e5SIgor M. Liplianin 		data = ds3000_readreg(state, 0xa1);
78809ea33e5SIgor M. Liplianin 		data &= ~0x80;
78909ea33e5SIgor M. Liplianin 		data |= 0x40;
79009ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xa1, data);
79109ea33e5SIgor M. Liplianin 
79209ea33e5SIgor M. Liplianin 		data = ds3000_readreg(state, 0xa2);
79309ea33e5SIgor M. Liplianin 		data &= ~0xc0;
79409ea33e5SIgor M. Liplianin 		data |= 0x80;
79509ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xa2, data);
79609ea33e5SIgor M. Liplianin 
79727924dccSOlli Salonen 		return -ETIMEDOUT;
79809ea33e5SIgor M. Liplianin 	}
79909ea33e5SIgor M. Liplianin 
80009ea33e5SIgor M. Liplianin 	data = ds3000_readreg(state, 0xa2);
80109ea33e5SIgor M. Liplianin 	data &= ~0xc0;
80209ea33e5SIgor M. Liplianin 	data |= 0x80;
80309ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0xa2, data);
80409ea33e5SIgor M. Liplianin 
80509ea33e5SIgor M. Liplianin 	return 0;
80609ea33e5SIgor M. Liplianin }
80709ea33e5SIgor M. Liplianin 
80809ea33e5SIgor M. Liplianin static void ds3000_release(struct dvb_frontend *fe)
80909ea33e5SIgor M. Liplianin {
81009ea33e5SIgor M. Liplianin 	struct ds3000_state *state = fe->demodulator_priv;
81143385c8aSIgor M. Liplianin 
81243385c8aSIgor M. Liplianin 	if (state->config->set_lock_led)
81343385c8aSIgor M. Liplianin 		state->config->set_lock_led(fe, 0);
81443385c8aSIgor M. Liplianin 
81509ea33e5SIgor M. Liplianin 	dprintk("%s\n", __func__);
81609ea33e5SIgor M. Liplianin 	kfree(state);
81709ea33e5SIgor M. Liplianin }
81809ea33e5SIgor M. Liplianin 
819bd336e63SMax Kellermann static const struct dvb_frontend_ops ds3000_ops;
82009ea33e5SIgor M. Liplianin 
82109ea33e5SIgor M. Liplianin struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
82209ea33e5SIgor M. Liplianin 				    struct i2c_adapter *i2c)
82309ea33e5SIgor M. Liplianin {
824d303b7c5SMarkus Elfring 	struct ds3000_state *state;
82509ea33e5SIgor M. Liplianin 	int ret;
82609ea33e5SIgor M. Liplianin 
82709ea33e5SIgor M. Liplianin 	dprintk("%s\n", __func__);
82809ea33e5SIgor M. Liplianin 
82909ea33e5SIgor M. Liplianin 	/* allocate memory for the internal state */
8302d3da59fSMarkus Elfring 	state = kzalloc(sizeof(*state), GFP_KERNEL);
831c38e8657SMarkus Elfring 	if (!state)
8329722e569SMarkus Elfring 		return NULL;
83309ea33e5SIgor M. Liplianin 
83409ea33e5SIgor M. Liplianin 	state->config = config;
83509ea33e5SIgor M. Liplianin 	state->i2c = i2c;
83609ea33e5SIgor M. Liplianin 	state->prevUCBS2 = 0;
83709ea33e5SIgor M. Liplianin 
83809ea33e5SIgor M. Liplianin 	/* check if the demod is present */
83909ea33e5SIgor M. Liplianin 	ret = ds3000_readreg(state, 0x00) & 0xfe;
84009ea33e5SIgor M. Liplianin 	if (ret != 0xe0) {
8419722e569SMarkus Elfring 		kfree(state);
84209ea33e5SIgor M. Liplianin 		printk(KERN_ERR "Invalid probe, probably not a DS3000\n");
8439722e569SMarkus Elfring 		return NULL;
84409ea33e5SIgor M. Liplianin 	}
84509ea33e5SIgor M. Liplianin 
84609ea33e5SIgor M. Liplianin 	printk(KERN_INFO "DS3000 chip version: %d.%d attached.\n",
84709ea33e5SIgor M. Liplianin 			ds3000_readreg(state, 0x02),
84809ea33e5SIgor M. Liplianin 			ds3000_readreg(state, 0x01));
84909ea33e5SIgor M. Liplianin 
85009ea33e5SIgor M. Liplianin 	memcpy(&state->frontend.ops, &ds3000_ops,
85109ea33e5SIgor M. Liplianin 			sizeof(struct dvb_frontend_ops));
85209ea33e5SIgor M. Liplianin 	state->frontend.demodulator_priv = state;
8538c5bcdedSUlrich Eckhardt 
8548c5bcdedSUlrich Eckhardt 	/*
8558c5bcdedSUlrich Eckhardt 	 * Some devices like T480 starts with voltage on. Be sure
8568c5bcdedSUlrich Eckhardt 	 * to turn voltage off during init, as this can otherwise
8578c5bcdedSUlrich Eckhardt 	 * interfere with Unicable SCR systems.
8588c5bcdedSUlrich Eckhardt 	 */
8598c5bcdedSUlrich Eckhardt 	ds3000_set_voltage(&state->frontend, SEC_VOLTAGE_OFF);
86009ea33e5SIgor M. Liplianin 	return &state->frontend;
86109ea33e5SIgor M. Liplianin }
86209ea33e5SIgor M. Liplianin EXPORT_SYMBOL(ds3000_attach);
86309ea33e5SIgor M. Liplianin 
864a5bf834bSIgor M. Liplianin static int ds3000_set_carrier_offset(struct dvb_frontend *fe,
865a5bf834bSIgor M. Liplianin 					s32 carrier_offset_khz)
866a5bf834bSIgor M. Liplianin {
867a5bf834bSIgor M. Liplianin 	struct ds3000_state *state = fe->demodulator_priv;
868a5bf834bSIgor M. Liplianin 	s32 tmp;
869a5bf834bSIgor M. Liplianin 
870a5bf834bSIgor M. Liplianin 	tmp = carrier_offset_khz;
871a5bf834bSIgor M. Liplianin 	tmp *= 65536;
872a5bf834bSIgor M. Liplianin 	tmp = (2 * tmp + DS3000_SAMPLE_RATE) / (2 * DS3000_SAMPLE_RATE);
873a5bf834bSIgor M. Liplianin 
874a5bf834bSIgor M. Liplianin 	if (tmp < 0)
875a5bf834bSIgor M. Liplianin 		tmp += 65536;
876a5bf834bSIgor M. Liplianin 
877a5bf834bSIgor M. Liplianin 	ds3000_writereg(state, 0x5f, tmp >> 8);
878a5bf834bSIgor M. Liplianin 	ds3000_writereg(state, 0x5e, tmp & 0xff);
879a5bf834bSIgor M. Liplianin 
880a5bf834bSIgor M. Liplianin 	return 0;
881a5bf834bSIgor M. Liplianin }
882a5bf834bSIgor M. Liplianin 
8839fe33018SMauro Carvalho Chehab static int ds3000_set_frontend(struct dvb_frontend *fe)
88409ea33e5SIgor M. Liplianin {
88509ea33e5SIgor M. Liplianin 	struct ds3000_state *state = fe->demodulator_priv;
88609ea33e5SIgor M. Liplianin 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
88709ea33e5SIgor M. Liplianin 
88818a73f36SIgor M. Liplianin 	int i;
8890df289a2SMauro Carvalho Chehab 	enum fe_status status;
890a5bf834bSIgor M. Liplianin 	s32 offset_khz;
891c1965eaeSKonstantin Dimitrov 	u32 frequency;
892c1965eaeSKonstantin Dimitrov 	u16 value;
89309ea33e5SIgor M. Liplianin 
89409ea33e5SIgor M. Liplianin 	dprintk("%s() ", __func__);
89509ea33e5SIgor M. Liplianin 
8960cb73639SIgor M. Liplianin 	if (state->config->set_ts_params)
8970cb73639SIgor M. Liplianin 		state->config->set_ts_params(fe, 0);
89809ea33e5SIgor M. Liplianin 	/* Tune */
899c1965eaeSKonstantin Dimitrov 	if (fe->ops.tuner_ops.set_params)
900c1965eaeSKonstantin Dimitrov 		fe->ops.tuner_ops.set_params(fe);
901a5bf834bSIgor M. Liplianin 
90209ea33e5SIgor M. Liplianin 	/* ds3000 global reset */
90309ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0x07, 0x80);
90409ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0x07, 0x00);
905868c9a17SMauro Carvalho Chehab 	/* ds3000 built-in uC reset */
90609ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0xb2, 0x01);
90709ea33e5SIgor M. Liplianin 	/* ds3000 software reset */
90809ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0x00, 0x01);
90909ea33e5SIgor M. Liplianin 
91009ea33e5SIgor M. Liplianin 	switch (c->delivery_system) {
91109ea33e5SIgor M. Liplianin 	case SYS_DVBS:
91209ea33e5SIgor M. Liplianin 		/* initialise the demod in DVB-S mode */
91309ea33e5SIgor M. Liplianin 		for (i = 0; i < sizeof(ds3000_dvbs_init_tab); i += 2)
91409ea33e5SIgor M. Liplianin 			ds3000_writereg(state,
91509ea33e5SIgor M. Liplianin 				ds3000_dvbs_init_tab[i],
91609ea33e5SIgor M. Liplianin 				ds3000_dvbs_init_tab[i + 1]);
91709ea33e5SIgor M. Liplianin 		value = ds3000_readreg(state, 0xfe);
91809ea33e5SIgor M. Liplianin 		value &= 0xc0;
91909ea33e5SIgor M. Liplianin 		value |= 0x1b;
92009ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xfe, value);
92109ea33e5SIgor M. Liplianin 		break;
92209ea33e5SIgor M. Liplianin 	case SYS_DVBS2:
92309ea33e5SIgor M. Liplianin 		/* initialise the demod in DVB-S2 mode */
92409ea33e5SIgor M. Liplianin 		for (i = 0; i < sizeof(ds3000_dvbs2_init_tab); i += 2)
92509ea33e5SIgor M. Liplianin 			ds3000_writereg(state,
92609ea33e5SIgor M. Liplianin 				ds3000_dvbs2_init_tab[i],
92709ea33e5SIgor M. Liplianin 				ds3000_dvbs2_init_tab[i + 1]);
9287b134e85SIgor M. Liplianin 		if (c->symbol_rate >= 30000000)
9297b134e85SIgor M. Liplianin 			ds3000_writereg(state, 0xfe, 0x54);
9307b134e85SIgor M. Liplianin 		else
9312a66bf37SIgor M. Liplianin 			ds3000_writereg(state, 0xfe, 0x98);
93209ea33e5SIgor M. Liplianin 		break;
93309ea33e5SIgor M. Liplianin 	default:
93427924dccSOlli Salonen 		return -EINVAL;
93509ea33e5SIgor M. Liplianin 	}
93609ea33e5SIgor M. Liplianin 
93709ea33e5SIgor M. Liplianin 	/* enable 27MHz clock output */
93809ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0x29, 0x80);
93909ea33e5SIgor M. Liplianin 	/* enable ac coupling */
94009ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0x25, 0x8a);
94109ea33e5SIgor M. Liplianin 
942212fa081SOlli Salonen 	if ((c->symbol_rate < ds3000_ops.info.symbol_rate_min) ||
943212fa081SOlli Salonen 			(c->symbol_rate > ds3000_ops.info.symbol_rate_max)) {
944212fa081SOlli Salonen 		dprintk("%s() symbol_rate %u out of range (%u ... %u)\n",
945212fa081SOlli Salonen 				__func__, c->symbol_rate,
946212fa081SOlli Salonen 				ds3000_ops.info.symbol_rate_min,
947212fa081SOlli Salonen 				ds3000_ops.info.symbol_rate_max);
948212fa081SOlli Salonen 		return -EINVAL;
949212fa081SOlli Salonen 	}
950212fa081SOlli Salonen 
95109ea33e5SIgor M. Liplianin 	/* enhance symbol rate performance */
952cb8f74daSIgor M. Liplianin 	if ((c->symbol_rate / 1000) <= 5000) {
953cb8f74daSIgor M. Liplianin 		value = 29777 / (c->symbol_rate / 1000) + 1;
95409ea33e5SIgor M. Liplianin 		if (value % 2 != 0)
95509ea33e5SIgor M. Liplianin 			value++;
95609ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xc3, 0x0d);
95709ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xc8, value);
95809ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xc4, 0x10);
95909ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xc7, 0x0e);
960cb8f74daSIgor M. Liplianin 	} else if ((c->symbol_rate / 1000) <= 10000) {
961cb8f74daSIgor M. Liplianin 		value = 92166 / (c->symbol_rate / 1000) + 1;
96209ea33e5SIgor M. Liplianin 		if (value % 2 != 0)
96309ea33e5SIgor M. Liplianin 			value++;
96409ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xc3, 0x07);
96509ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xc8, value);
96609ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xc4, 0x09);
96709ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xc7, 0x12);
968cb8f74daSIgor M. Liplianin 	} else if ((c->symbol_rate / 1000) <= 20000) {
969cb8f74daSIgor M. Liplianin 		value = 64516 / (c->symbol_rate / 1000) + 1;
97009ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xc3, value);
97109ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xc8, 0x0e);
97209ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xc4, 0x07);
97309ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xc7, 0x18);
97409ea33e5SIgor M. Liplianin 	} else {
975cb8f74daSIgor M. Liplianin 		value = 129032 / (c->symbol_rate / 1000) + 1;
97609ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xc3, value);
97709ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xc8, 0x0a);
97809ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xc4, 0x05);
97909ea33e5SIgor M. Liplianin 		ds3000_writereg(state, 0xc7, 0x24);
98009ea33e5SIgor M. Liplianin 	}
98109ea33e5SIgor M. Liplianin 
98209ea33e5SIgor M. Liplianin 	/* normalized symbol rate rounded to the closest integer */
983cb8f74daSIgor M. Liplianin 	value = (((c->symbol_rate / 1000) << 16) +
98409ea33e5SIgor M. Liplianin 			(DS3000_SAMPLE_RATE / 2)) / DS3000_SAMPLE_RATE;
98509ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0x61, value & 0x00ff);
98609ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0x62, (value & 0xff00) >> 8);
98709ea33e5SIgor M. Liplianin 
98809ea33e5SIgor M. Liplianin 	/* co-channel interference cancellation disabled */
98909ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0x56, 0x00);
99009ea33e5SIgor M. Liplianin 
99109ea33e5SIgor M. Liplianin 	/* equalizer disabled */
99209ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0x76, 0x00);
99309ea33e5SIgor M. Liplianin 
99409ea33e5SIgor M. Liplianin 	/*ds3000_writereg(state, 0x08, 0x03);
99509ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0xfd, 0x22);
99609ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0x08, 0x07);
99709ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0xfd, 0x42);
99809ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0x08, 0x07);*/
99909ea33e5SIgor M. Liplianin 
1000d2ffc447SIgor M. Liplianin 	if (state->config->ci_mode) {
1001d2ffc447SIgor M. Liplianin 		switch (c->delivery_system) {
1002d2ffc447SIgor M. Liplianin 		case SYS_DVBS:
1003d2ffc447SIgor M. Liplianin 		default:
1004d2ffc447SIgor M. Liplianin 			ds3000_writereg(state, 0xfd, 0x80);
1005d2ffc447SIgor M. Liplianin 		break;
1006d2ffc447SIgor M. Liplianin 		case SYS_DVBS2:
1007d2ffc447SIgor M. Liplianin 			ds3000_writereg(state, 0xfd, 0x01);
1008d2ffc447SIgor M. Liplianin 			break;
1009d2ffc447SIgor M. Liplianin 		}
1010d2ffc447SIgor M. Liplianin 	}
1011d2ffc447SIgor M. Liplianin 
101209ea33e5SIgor M. Liplianin 	/* ds3000 out of software reset */
101309ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0x00, 0x00);
1014868c9a17SMauro Carvalho Chehab 	/* start ds3000 built-in uC */
101509ea33e5SIgor M. Liplianin 	ds3000_writereg(state, 0xb2, 0x00);
101609ea33e5SIgor M. Liplianin 
1017c1965eaeSKonstantin Dimitrov 	if (fe->ops.tuner_ops.get_frequency) {
1018c1965eaeSKonstantin Dimitrov 		fe->ops.tuner_ops.get_frequency(fe, &frequency);
1019c1965eaeSKonstantin Dimitrov 		offset_khz = frequency - c->frequency;
1020a5bf834bSIgor M. Liplianin 		ds3000_set_carrier_offset(fe, offset_khz);
1021c1965eaeSKonstantin Dimitrov 	}
102209ea33e5SIgor M. Liplianin 
102309ea33e5SIgor M. Liplianin 	for (i = 0; i < 30 ; i++) {
102418a73f36SIgor M. Liplianin 		ds3000_read_status(fe, &status);
10253a9888f9SDan Carpenter 		if (status & FE_HAS_LOCK)
102618a73f36SIgor M. Liplianin 			break;
102718a73f36SIgor M. Liplianin 
102818a73f36SIgor M. Liplianin 		msleep(10);
102909ea33e5SIgor M. Liplianin 	}
103009ea33e5SIgor M. Liplianin 
103118a73f36SIgor M. Liplianin 	return 0;
103209ea33e5SIgor M. Liplianin }
103309ea33e5SIgor M. Liplianin 
1034dcc8a122SIgor M. Liplianin static int ds3000_tune(struct dvb_frontend *fe,
10357e072221SMauro Carvalho Chehab 			bool re_tune,
1036738e8ff9SIgor M. Liplianin 			unsigned int mode_flags,
1037738e8ff9SIgor M. Liplianin 			unsigned int *delay,
10380df289a2SMauro Carvalho Chehab 			enum fe_status *status)
1039dcc8a122SIgor M. Liplianin {
10407e072221SMauro Carvalho Chehab 	if (re_tune) {
10419fe33018SMauro Carvalho Chehab 		int ret = ds3000_set_frontend(fe);
1042738e8ff9SIgor M. Liplianin 		if (ret)
1043738e8ff9SIgor M. Liplianin 			return ret;
1044738e8ff9SIgor M. Liplianin 	}
1045738e8ff9SIgor M. Liplianin 
1046738e8ff9SIgor M. Liplianin 	*delay = HZ / 5;
1047738e8ff9SIgor M. Liplianin 
1048738e8ff9SIgor M. Liplianin 	return ds3000_read_status(fe, status);
1049dcc8a122SIgor M. Liplianin }
1050dcc8a122SIgor M. Liplianin 
105109ea33e5SIgor M. Liplianin static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe)
105209ea33e5SIgor M. Liplianin {
105343385c8aSIgor M. Liplianin 	struct ds3000_state *state = fe->demodulator_priv;
105443385c8aSIgor M. Liplianin 
105543385c8aSIgor M. Liplianin 	if (state->config->set_lock_led)
105643385c8aSIgor M. Liplianin 		state->config->set_lock_led(fe, 0);
105743385c8aSIgor M. Liplianin 
105809ea33e5SIgor M. Liplianin 	dprintk("%s()\n", __func__);
1059dcc8a122SIgor M. Liplianin 	return DVBFE_ALGO_HW;
106009ea33e5SIgor M. Liplianin }
106109ea33e5SIgor M. Liplianin 
106209ea33e5SIgor M. Liplianin /*
106309ea33e5SIgor M. Liplianin  * Initialise or wake up device
106409ea33e5SIgor M. Liplianin  *
106509ea33e5SIgor M. Liplianin  * Power config will reset and load initial firmware if required
106609ea33e5SIgor M. Liplianin  */
106709ea33e5SIgor M. Liplianin static int ds3000_initfe(struct dvb_frontend *fe)
106809ea33e5SIgor M. Liplianin {
1069a0ea298dSIgor M. Liplianin 	struct ds3000_state *state = fe->demodulator_priv;
1070a0ea298dSIgor M. Liplianin 	int ret;
1071a0ea298dSIgor M. Liplianin 
107209ea33e5SIgor M. Liplianin 	dprintk("%s()\n", __func__);
1073a0ea298dSIgor M. Liplianin 	/* hard reset */
1074a0ea298dSIgor M. Liplianin 	ds3000_writereg(state, 0x08, 0x01 | ds3000_readreg(state, 0x08));
1075a0ea298dSIgor M. Liplianin 	msleep(1);
1076a0ea298dSIgor M. Liplianin 
1077b9bf2eafSIgor M. Liplianin 	/* Load the firmware if required */
1078b9bf2eafSIgor M. Liplianin 	ret = ds3000_firmware_ondemand(fe);
1079b9bf2eafSIgor M. Liplianin 	if (ret != 0) {
1080b9bf2eafSIgor M. Liplianin 		printk(KERN_ERR "%s: Unable initialize firmware\n", __func__);
1081b9bf2eafSIgor M. Liplianin 		return ret;
1082b9bf2eafSIgor M. Liplianin 	}
1083a0ea298dSIgor M. Liplianin 
108409ea33e5SIgor M. Liplianin 	return 0;
108509ea33e5SIgor M. Liplianin }
108609ea33e5SIgor M. Liplianin 
1087bd336e63SMax Kellermann static const struct dvb_frontend_ops ds3000_ops = {
10889fe33018SMauro Carvalho Chehab 	.delsys = { SYS_DVBS, SYS_DVBS2 },
108909ea33e5SIgor M. Liplianin 	.info = {
1090c1965eaeSKonstantin Dimitrov 		.name = "Montage Technology DS3000",
1091f1b1eabfSMauro Carvalho Chehab 		.frequency_min_hz =  950 * MHz,
1092f1b1eabfSMauro Carvalho Chehab 		.frequency_max_hz = 2150 * MHz,
1093f1b1eabfSMauro Carvalho Chehab 		.frequency_stepsize_hz = 1011 * kHz,
1094f1b1eabfSMauro Carvalho Chehab 		.frequency_tolerance_hz = 5 * MHz,
109509ea33e5SIgor M. Liplianin 		.symbol_rate_min = 1000000,
109609ea33e5SIgor M. Liplianin 		.symbol_rate_max = 45000000,
109709ea33e5SIgor M. Liplianin 		.caps = FE_CAN_INVERSION_AUTO |
109809ea33e5SIgor M. Liplianin 			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
109909ea33e5SIgor M. Liplianin 			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
110009ea33e5SIgor M. Liplianin 			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
110109ea33e5SIgor M. Liplianin 			FE_CAN_2G_MODULATION |
110209ea33e5SIgor M. Liplianin 			FE_CAN_QPSK | FE_CAN_RECOVER
110309ea33e5SIgor M. Liplianin 	},
110409ea33e5SIgor M. Liplianin 
110509ea33e5SIgor M. Liplianin 	.release = ds3000_release,
110609ea33e5SIgor M. Liplianin 
110709ea33e5SIgor M. Liplianin 	.init = ds3000_initfe,
1108c1965eaeSKonstantin Dimitrov 	.i2c_gate_ctrl = ds3000_i2c_gate_ctrl,
110909ea33e5SIgor M. Liplianin 	.read_status = ds3000_read_status,
111009ea33e5SIgor M. Liplianin 	.read_ber = ds3000_read_ber,
1111a0a030bdSMalcolm Priestley 	.read_signal_strength = ds3000_read_signal_strength,
111209ea33e5SIgor M. Liplianin 	.read_snr = ds3000_read_snr,
111309ea33e5SIgor M. Liplianin 	.read_ucblocks = ds3000_read_ucblocks,
1114d2ffc447SIgor M. Liplianin 	.set_voltage = ds3000_set_voltage,
111509ea33e5SIgor M. Liplianin 	.set_tone = ds3000_set_tone,
111609ea33e5SIgor M. Liplianin 	.diseqc_send_master_cmd = ds3000_send_diseqc_msg,
111709ea33e5SIgor M. Liplianin 	.diseqc_send_burst = ds3000_diseqc_send_burst,
111809ea33e5SIgor M. Liplianin 	.get_frontend_algo = ds3000_get_algo,
111909ea33e5SIgor M. Liplianin 
11209fe33018SMauro Carvalho Chehab 	.set_frontend = ds3000_set_frontend,
1121dcc8a122SIgor M. Liplianin 	.tune = ds3000_tune,
112209ea33e5SIgor M. Liplianin };
112309ea33e5SIgor M. Liplianin 
112409ea33e5SIgor M. Liplianin module_param(debug, int, 0644);
112509ea33e5SIgor M. Liplianin MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
112609ea33e5SIgor M. Liplianin 
11274bd69e7bSMauro Carvalho Chehab MODULE_DESCRIPTION("DVB Frontend module for Montage Technology DS3000 hardware");
1128c1965eaeSKonstantin Dimitrov MODULE_AUTHOR("Konstantin Dimitrov <kosio.dimitrov@gmail.com>");
112909ea33e5SIgor M. Liplianin MODULE_LICENSE("GPL");
1130feadd7d3SRémi Cardona MODULE_FIRMWARE(DS3000_DEFAULT_FIRMWARE);
1131