xref: /openbmc/linux/drivers/media/dvb-frontends/ds3000.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
29a0bf528SMauro Carvalho Chehab /*
3c1965eaeSKonstantin Dimitrov     Montage Technology DS3000 - DVBS/S2 Demodulator driver
4c1965eaeSKonstantin Dimitrov     Copyright (C) 2009-2012 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
59a0bf528SMauro Carvalho Chehab 
6c1965eaeSKonstantin Dimitrov     Copyright (C) 2009-2012 TurboSight.com
79a0bf528SMauro Carvalho Chehab 
89a0bf528SMauro Carvalho Chehab  */
99a0bf528SMauro Carvalho Chehab 
109a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
119a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
129a0bf528SMauro Carvalho Chehab #include <linux/module.h>
139a0bf528SMauro Carvalho Chehab #include <linux/moduleparam.h>
149a0bf528SMauro Carvalho Chehab #include <linux/init.h>
159a0bf528SMauro Carvalho Chehab #include <linux/firmware.h>
169a0bf528SMauro Carvalho Chehab 
17fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
1873f0af44SKonstantin Dimitrov #include "ts2020.h"
199a0bf528SMauro Carvalho Chehab #include "ds3000.h"
209a0bf528SMauro Carvalho Chehab 
219a0bf528SMauro Carvalho Chehab static int debug;
229a0bf528SMauro Carvalho Chehab 
239a0bf528SMauro Carvalho Chehab #define dprintk(args...) \
249a0bf528SMauro Carvalho Chehab 	do { \
259a0bf528SMauro Carvalho Chehab 		if (debug) \
269a0bf528SMauro Carvalho Chehab 			printk(args); \
279a0bf528SMauro Carvalho Chehab 	} while (0)
289a0bf528SMauro Carvalho Chehab 
299a0bf528SMauro Carvalho Chehab /* as of March 2009 current DS3000 firmware version is 1.78 */
309a0bf528SMauro Carvalho Chehab /* DS3000 FW v1.78 MD5: a32d17910c4f370073f9346e71d34b80 */
319a0bf528SMauro Carvalho Chehab #define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds3000.fw"
329a0bf528SMauro Carvalho Chehab 
339a0bf528SMauro Carvalho Chehab #define DS3000_SAMPLE_RATE 96000 /* in kHz */
349a0bf528SMauro Carvalho Chehab 
359a0bf528SMauro Carvalho Chehab /* Register values to initialise the demod in DVB-S mode */
369a0bf528SMauro Carvalho Chehab static u8 ds3000_dvbs_init_tab[] = {
379a0bf528SMauro Carvalho Chehab 	0x23, 0x05,
389a0bf528SMauro Carvalho Chehab 	0x08, 0x03,
399a0bf528SMauro Carvalho Chehab 	0x0c, 0x00,
409a0bf528SMauro Carvalho Chehab 	0x21, 0x54,
419a0bf528SMauro Carvalho Chehab 	0x25, 0x82,
429a0bf528SMauro Carvalho Chehab 	0x27, 0x31,
439a0bf528SMauro Carvalho Chehab 	0x30, 0x08,
449a0bf528SMauro Carvalho Chehab 	0x31, 0x40,
459a0bf528SMauro Carvalho Chehab 	0x32, 0x32,
469a0bf528SMauro Carvalho Chehab 	0x33, 0x35,
479a0bf528SMauro Carvalho Chehab 	0x35, 0xff,
489a0bf528SMauro Carvalho Chehab 	0x3a, 0x00,
499a0bf528SMauro Carvalho Chehab 	0x37, 0x10,
509a0bf528SMauro Carvalho Chehab 	0x38, 0x10,
519a0bf528SMauro Carvalho Chehab 	0x39, 0x02,
529a0bf528SMauro Carvalho Chehab 	0x42, 0x60,
539a0bf528SMauro Carvalho Chehab 	0x4a, 0x40,
549a0bf528SMauro Carvalho Chehab 	0x4b, 0x04,
559a0bf528SMauro Carvalho Chehab 	0x4d, 0x91,
569a0bf528SMauro Carvalho Chehab 	0x5d, 0xc8,
579a0bf528SMauro Carvalho Chehab 	0x50, 0x77,
589a0bf528SMauro Carvalho Chehab 	0x51, 0x77,
599a0bf528SMauro Carvalho Chehab 	0x52, 0x36,
609a0bf528SMauro Carvalho Chehab 	0x53, 0x36,
619a0bf528SMauro Carvalho Chehab 	0x56, 0x01,
629a0bf528SMauro Carvalho Chehab 	0x63, 0x43,
639a0bf528SMauro Carvalho Chehab 	0x64, 0x30,
649a0bf528SMauro Carvalho Chehab 	0x65, 0x40,
659a0bf528SMauro Carvalho Chehab 	0x68, 0x26,
669a0bf528SMauro Carvalho Chehab 	0x69, 0x4c,
679a0bf528SMauro Carvalho Chehab 	0x70, 0x20,
689a0bf528SMauro Carvalho Chehab 	0x71, 0x70,
699a0bf528SMauro Carvalho Chehab 	0x72, 0x04,
709a0bf528SMauro Carvalho Chehab 	0x73, 0x00,
719a0bf528SMauro Carvalho Chehab 	0x70, 0x40,
729a0bf528SMauro Carvalho Chehab 	0x71, 0x70,
739a0bf528SMauro Carvalho Chehab 	0x72, 0x04,
749a0bf528SMauro Carvalho Chehab 	0x73, 0x00,
759a0bf528SMauro Carvalho Chehab 	0x70, 0x60,
769a0bf528SMauro Carvalho Chehab 	0x71, 0x70,
779a0bf528SMauro Carvalho Chehab 	0x72, 0x04,
789a0bf528SMauro Carvalho Chehab 	0x73, 0x00,
799a0bf528SMauro Carvalho Chehab 	0x70, 0x80,
809a0bf528SMauro Carvalho Chehab 	0x71, 0x70,
819a0bf528SMauro Carvalho Chehab 	0x72, 0x04,
829a0bf528SMauro Carvalho Chehab 	0x73, 0x00,
839a0bf528SMauro Carvalho Chehab 	0x70, 0xa0,
849a0bf528SMauro Carvalho Chehab 	0x71, 0x70,
859a0bf528SMauro Carvalho Chehab 	0x72, 0x04,
869a0bf528SMauro Carvalho Chehab 	0x73, 0x00,
879a0bf528SMauro Carvalho Chehab 	0x70, 0x1f,
889a0bf528SMauro Carvalho Chehab 	0x76, 0x00,
899a0bf528SMauro Carvalho Chehab 	0x77, 0xd1,
909a0bf528SMauro Carvalho Chehab 	0x78, 0x0c,
919a0bf528SMauro Carvalho Chehab 	0x79, 0x80,
929a0bf528SMauro Carvalho Chehab 	0x7f, 0x04,
939a0bf528SMauro Carvalho Chehab 	0x7c, 0x00,
949a0bf528SMauro Carvalho Chehab 	0x80, 0x86,
959a0bf528SMauro Carvalho Chehab 	0x81, 0xa6,
969a0bf528SMauro Carvalho Chehab 	0x85, 0x04,
979a0bf528SMauro Carvalho Chehab 	0xcd, 0xf4,
989a0bf528SMauro Carvalho Chehab 	0x90, 0x33,
999a0bf528SMauro Carvalho Chehab 	0xa0, 0x44,
1009a0bf528SMauro Carvalho Chehab 	0xc0, 0x18,
1019a0bf528SMauro Carvalho Chehab 	0xc3, 0x10,
1029a0bf528SMauro Carvalho Chehab 	0xc4, 0x08,
1039a0bf528SMauro Carvalho Chehab 	0xc5, 0x80,
1049a0bf528SMauro Carvalho Chehab 	0xc6, 0x80,
1059a0bf528SMauro Carvalho Chehab 	0xc7, 0x0a,
1069a0bf528SMauro Carvalho Chehab 	0xc8, 0x1a,
1079a0bf528SMauro Carvalho Chehab 	0xc9, 0x80,
1089a0bf528SMauro Carvalho Chehab 	0xfe, 0x92,
1099a0bf528SMauro Carvalho Chehab 	0xe0, 0xf8,
1109a0bf528SMauro Carvalho Chehab 	0xe6, 0x8b,
1119a0bf528SMauro Carvalho Chehab 	0xd0, 0x40,
1129a0bf528SMauro Carvalho Chehab 	0xf8, 0x20,
1139a0bf528SMauro Carvalho Chehab 	0xfa, 0x0f,
1149a0bf528SMauro Carvalho Chehab 	0xfd, 0x20,
1159a0bf528SMauro Carvalho Chehab 	0xad, 0x20,
1169a0bf528SMauro Carvalho Chehab 	0xae, 0x07,
1179a0bf528SMauro Carvalho Chehab 	0xb8, 0x00,
1189a0bf528SMauro Carvalho Chehab };
1199a0bf528SMauro Carvalho Chehab 
1209a0bf528SMauro Carvalho Chehab /* Register values to initialise the demod in DVB-S2 mode */
1219a0bf528SMauro Carvalho Chehab static u8 ds3000_dvbs2_init_tab[] = {
1229a0bf528SMauro Carvalho Chehab 	0x23, 0x0f,
1239a0bf528SMauro Carvalho Chehab 	0x08, 0x07,
1249a0bf528SMauro Carvalho Chehab 	0x0c, 0x00,
1259a0bf528SMauro Carvalho Chehab 	0x21, 0x54,
1269a0bf528SMauro Carvalho Chehab 	0x25, 0x82,
1279a0bf528SMauro Carvalho Chehab 	0x27, 0x31,
1289a0bf528SMauro Carvalho Chehab 	0x30, 0x08,
1299a0bf528SMauro Carvalho Chehab 	0x31, 0x32,
1309a0bf528SMauro Carvalho Chehab 	0x32, 0x32,
1319a0bf528SMauro Carvalho Chehab 	0x33, 0x35,
1329a0bf528SMauro Carvalho Chehab 	0x35, 0xff,
1339a0bf528SMauro Carvalho Chehab 	0x3a, 0x00,
1349a0bf528SMauro Carvalho Chehab 	0x37, 0x10,
1359a0bf528SMauro Carvalho Chehab 	0x38, 0x10,
1369a0bf528SMauro Carvalho Chehab 	0x39, 0x02,
1379a0bf528SMauro Carvalho Chehab 	0x42, 0x60,
1389a0bf528SMauro Carvalho Chehab 	0x4a, 0x80,
1399a0bf528SMauro Carvalho Chehab 	0x4b, 0x04,
1409a0bf528SMauro Carvalho Chehab 	0x4d, 0x81,
1419a0bf528SMauro Carvalho Chehab 	0x5d, 0x88,
1429a0bf528SMauro Carvalho Chehab 	0x50, 0x36,
1439a0bf528SMauro Carvalho Chehab 	0x51, 0x36,
1449a0bf528SMauro Carvalho Chehab 	0x52, 0x36,
1459a0bf528SMauro Carvalho Chehab 	0x53, 0x36,
1469a0bf528SMauro Carvalho Chehab 	0x63, 0x60,
1479a0bf528SMauro Carvalho Chehab 	0x64, 0x10,
1489a0bf528SMauro Carvalho Chehab 	0x65, 0x10,
1499a0bf528SMauro Carvalho Chehab 	0x68, 0x04,
1509a0bf528SMauro Carvalho Chehab 	0x69, 0x29,
1519a0bf528SMauro Carvalho Chehab 	0x70, 0x20,
1529a0bf528SMauro Carvalho Chehab 	0x71, 0x70,
1539a0bf528SMauro Carvalho Chehab 	0x72, 0x04,
1549a0bf528SMauro Carvalho Chehab 	0x73, 0x00,
1559a0bf528SMauro Carvalho Chehab 	0x70, 0x40,
1569a0bf528SMauro Carvalho Chehab 	0x71, 0x70,
1579a0bf528SMauro Carvalho Chehab 	0x72, 0x04,
1589a0bf528SMauro Carvalho Chehab 	0x73, 0x00,
1599a0bf528SMauro Carvalho Chehab 	0x70, 0x60,
1609a0bf528SMauro Carvalho Chehab 	0x71, 0x70,
1619a0bf528SMauro Carvalho Chehab 	0x72, 0x04,
1629a0bf528SMauro Carvalho Chehab 	0x73, 0x00,
1639a0bf528SMauro Carvalho Chehab 	0x70, 0x80,
1649a0bf528SMauro Carvalho Chehab 	0x71, 0x70,
1659a0bf528SMauro Carvalho Chehab 	0x72, 0x04,
1669a0bf528SMauro Carvalho Chehab 	0x73, 0x00,
1679a0bf528SMauro Carvalho Chehab 	0x70, 0xa0,
1689a0bf528SMauro Carvalho Chehab 	0x71, 0x70,
1699a0bf528SMauro Carvalho Chehab 	0x72, 0x04,
1709a0bf528SMauro Carvalho Chehab 	0x73, 0x00,
1719a0bf528SMauro Carvalho Chehab 	0x70, 0x1f,
1729a0bf528SMauro Carvalho Chehab 	0xa0, 0x44,
1739a0bf528SMauro Carvalho Chehab 	0xc0, 0x08,
1749a0bf528SMauro Carvalho Chehab 	0xc1, 0x10,
1759a0bf528SMauro Carvalho Chehab 	0xc2, 0x08,
1769a0bf528SMauro Carvalho Chehab 	0xc3, 0x10,
1779a0bf528SMauro Carvalho Chehab 	0xc4, 0x08,
1789a0bf528SMauro Carvalho Chehab 	0xc5, 0xf0,
1799a0bf528SMauro Carvalho Chehab 	0xc6, 0xf0,
1809a0bf528SMauro Carvalho Chehab 	0xc7, 0x0a,
1819a0bf528SMauro Carvalho Chehab 	0xc8, 0x1a,
1829a0bf528SMauro Carvalho Chehab 	0xc9, 0x80,
1839a0bf528SMauro Carvalho Chehab 	0xca, 0x23,
1849a0bf528SMauro Carvalho Chehab 	0xcb, 0x24,
1859a0bf528SMauro Carvalho Chehab 	0xce, 0x74,
1869a0bf528SMauro Carvalho Chehab 	0x90, 0x03,
1879a0bf528SMauro Carvalho Chehab 	0x76, 0x80,
1889a0bf528SMauro Carvalho Chehab 	0x77, 0x42,
1899a0bf528SMauro Carvalho Chehab 	0x78, 0x0a,
1909a0bf528SMauro Carvalho Chehab 	0x79, 0x80,
1919a0bf528SMauro Carvalho Chehab 	0xad, 0x40,
1929a0bf528SMauro Carvalho Chehab 	0xae, 0x07,
1939a0bf528SMauro Carvalho Chehab 	0x7f, 0xd4,
1949a0bf528SMauro Carvalho Chehab 	0x7c, 0x00,
1959a0bf528SMauro Carvalho Chehab 	0x80, 0xa8,
1969a0bf528SMauro Carvalho Chehab 	0x81, 0xda,
1979a0bf528SMauro Carvalho Chehab 	0x7c, 0x01,
1989a0bf528SMauro Carvalho Chehab 	0x80, 0xda,
1999a0bf528SMauro Carvalho Chehab 	0x81, 0xec,
2009a0bf528SMauro Carvalho Chehab 	0x7c, 0x02,
2019a0bf528SMauro Carvalho Chehab 	0x80, 0xca,
2029a0bf528SMauro Carvalho Chehab 	0x81, 0xeb,
2039a0bf528SMauro Carvalho Chehab 	0x7c, 0x03,
2049a0bf528SMauro Carvalho Chehab 	0x80, 0xba,
2059a0bf528SMauro Carvalho Chehab 	0x81, 0xdb,
2069a0bf528SMauro Carvalho Chehab 	0x85, 0x08,
2079a0bf528SMauro Carvalho Chehab 	0x86, 0x00,
2089a0bf528SMauro Carvalho Chehab 	0x87, 0x02,
2099a0bf528SMauro Carvalho Chehab 	0x89, 0x80,
2109a0bf528SMauro Carvalho Chehab 	0x8b, 0x44,
2119a0bf528SMauro Carvalho Chehab 	0x8c, 0xaa,
2129a0bf528SMauro Carvalho Chehab 	0x8a, 0x10,
2139a0bf528SMauro Carvalho Chehab 	0xba, 0x00,
2149a0bf528SMauro Carvalho Chehab 	0xf5, 0x04,
2159a0bf528SMauro Carvalho Chehab 	0xfe, 0x44,
2169a0bf528SMauro Carvalho Chehab 	0xd2, 0x32,
2179a0bf528SMauro Carvalho Chehab 	0xb8, 0x00,
2189a0bf528SMauro Carvalho Chehab };
2199a0bf528SMauro Carvalho Chehab 
2209a0bf528SMauro Carvalho Chehab struct ds3000_state {
2219a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *i2c;
2229a0bf528SMauro Carvalho Chehab 	const struct ds3000_config *config;
2239a0bf528SMauro Carvalho Chehab 	struct dvb_frontend frontend;
2249a0bf528SMauro Carvalho Chehab 	/* previous uncorrected block counter for DVB-S2 */
2259a0bf528SMauro Carvalho Chehab 	u16 prevUCBS2;
2269a0bf528SMauro Carvalho Chehab };
2279a0bf528SMauro Carvalho Chehab 
ds3000_writereg(struct ds3000_state * state,int reg,int data)2289a0bf528SMauro Carvalho Chehab static int ds3000_writereg(struct ds3000_state *state, int reg, int data)
2299a0bf528SMauro Carvalho Chehab {
2309a0bf528SMauro Carvalho Chehab 	u8 buf[] = { reg, data };
2319a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg = { .addr = state->config->demod_address,
2329a0bf528SMauro Carvalho Chehab 		.flags = 0, .buf = buf, .len = 2 };
2339a0bf528SMauro Carvalho Chehab 	int err;
2349a0bf528SMauro Carvalho Chehab 
2359a0bf528SMauro Carvalho Chehab 	dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data);
2369a0bf528SMauro Carvalho Chehab 
2379a0bf528SMauro Carvalho Chehab 	err = i2c_transfer(state->i2c, &msg, 1);
2389a0bf528SMauro Carvalho Chehab 	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);
2419a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO;
2429a0bf528SMauro Carvalho Chehab 	}
2439a0bf528SMauro Carvalho Chehab 
2449a0bf528SMauro Carvalho Chehab 	return 0;
2459a0bf528SMauro Carvalho Chehab }
2469a0bf528SMauro Carvalho Chehab 
ds3000_i2c_gate_ctrl(struct dvb_frontend * fe,int enable)247c1965eaeSKonstantin Dimitrov static int ds3000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
2489a0bf528SMauro Carvalho Chehab {
249c1965eaeSKonstantin Dimitrov 	struct ds3000_state *state = fe->demodulator_priv;
2509a0bf528SMauro Carvalho Chehab 
251c1965eaeSKonstantin Dimitrov 	if (enable)
252c1965eaeSKonstantin Dimitrov 		ds3000_writereg(state, 0x03, 0x12);
253c1965eaeSKonstantin Dimitrov 	else
254c1965eaeSKonstantin Dimitrov 		ds3000_writereg(state, 0x03, 0x02);
2559a0bf528SMauro Carvalho Chehab 
2569a0bf528SMauro Carvalho Chehab 	return 0;
2579a0bf528SMauro Carvalho Chehab }
2589a0bf528SMauro Carvalho Chehab 
2599a0bf528SMauro Carvalho Chehab /* I2C write for 8k firmware load */
ds3000_writeFW(struct ds3000_state * state,int reg,const u8 * data,u16 len)2609a0bf528SMauro Carvalho Chehab static int ds3000_writeFW(struct ds3000_state *state, int reg,
2619a0bf528SMauro Carvalho Chehab 				const u8 *data, u16 len)
2629a0bf528SMauro Carvalho Chehab {
263d58f4f27SRémi Cardona 	int i, ret = 0;
2649a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg;
2659a0bf528SMauro Carvalho Chehab 	u8 *buf;
2669a0bf528SMauro Carvalho Chehab 
2679a0bf528SMauro Carvalho Chehab 	buf = kmalloc(33, GFP_KERNEL);
268c38e8657SMarkus Elfring 	if (!buf)
269d58f4f27SRémi Cardona 		return -ENOMEM;
2709a0bf528SMauro Carvalho Chehab 
2719a0bf528SMauro Carvalho Chehab 	*(buf) = reg;
2729a0bf528SMauro Carvalho Chehab 
2739a0bf528SMauro Carvalho Chehab 	msg.addr = state->config->demod_address;
2749a0bf528SMauro Carvalho Chehab 	msg.flags = 0;
2759a0bf528SMauro Carvalho Chehab 	msg.buf = buf;
2769a0bf528SMauro Carvalho Chehab 	msg.len = 33;
2779a0bf528SMauro Carvalho Chehab 
2789a0bf528SMauro Carvalho Chehab 	for (i = 0; i < len; i += 32) {
2799a0bf528SMauro Carvalho Chehab 		memcpy(buf + 1, data + i, 32);
2809a0bf528SMauro Carvalho Chehab 
2819a0bf528SMauro Carvalho Chehab 		dprintk("%s: write reg 0x%02x, len = %d\n", __func__, reg, len);
2829a0bf528SMauro Carvalho Chehab 
2839a0bf528SMauro Carvalho Chehab 		ret = i2c_transfer(state->i2c, &msg, 1);
2849a0bf528SMauro Carvalho Chehab 		if (ret != 1) {
2854bd69e7bSMauro Carvalho Chehab 			printk(KERN_ERR "%s: write error(err == %i, reg == 0x%02x\n",
2864bd69e7bSMauro Carvalho Chehab 			       __func__, ret, reg);
2879a0bf528SMauro Carvalho Chehab 			ret = -EREMOTEIO;
288d58f4f27SRémi Cardona 			goto error;
2899a0bf528SMauro Carvalho Chehab 		}
2909a0bf528SMauro Carvalho Chehab 	}
291d58f4f27SRémi Cardona 	ret = 0;
2929a0bf528SMauro Carvalho Chehab 
2939a0bf528SMauro Carvalho Chehab error:
2949a0bf528SMauro Carvalho Chehab 	kfree(buf);
2959a0bf528SMauro Carvalho Chehab 
2969a0bf528SMauro Carvalho Chehab 	return ret;
2979a0bf528SMauro Carvalho Chehab }
2989a0bf528SMauro Carvalho Chehab 
ds3000_readreg(struct ds3000_state * state,u8 reg)2999a0bf528SMauro Carvalho Chehab static int ds3000_readreg(struct ds3000_state *state, u8 reg)
3009a0bf528SMauro Carvalho Chehab {
3019a0bf528SMauro Carvalho Chehab 	int ret;
3029a0bf528SMauro Carvalho Chehab 	u8 b0[] = { reg };
3039a0bf528SMauro Carvalho Chehab 	u8 b1[] = { 0 };
3049a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[] = {
3059a0bf528SMauro Carvalho Chehab 		{
3069a0bf528SMauro Carvalho Chehab 			.addr = state->config->demod_address,
3079a0bf528SMauro Carvalho Chehab 			.flags = 0,
3089a0bf528SMauro Carvalho Chehab 			.buf = b0,
3099a0bf528SMauro Carvalho Chehab 			.len = 1
3109a0bf528SMauro Carvalho Chehab 		}, {
3119a0bf528SMauro Carvalho Chehab 			.addr = state->config->demod_address,
3129a0bf528SMauro Carvalho Chehab 			.flags = I2C_M_RD,
3139a0bf528SMauro Carvalho Chehab 			.buf = b1,
3149a0bf528SMauro Carvalho Chehab 			.len = 1
3159a0bf528SMauro Carvalho Chehab 		}
3169a0bf528SMauro Carvalho Chehab 	};
3179a0bf528SMauro Carvalho Chehab 
3189a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer(state->i2c, msg, 2);
3199a0bf528SMauro Carvalho Chehab 
3209a0bf528SMauro Carvalho Chehab 	if (ret != 2) {
3219a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
3229a0bf528SMauro Carvalho Chehab 		return ret;
3239a0bf528SMauro Carvalho Chehab 	}
3249a0bf528SMauro Carvalho Chehab 
3259a0bf528SMauro Carvalho Chehab 	dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]);
3269a0bf528SMauro Carvalho Chehab 
3279a0bf528SMauro Carvalho Chehab 	return b1[0];
3289a0bf528SMauro Carvalho Chehab }
3299a0bf528SMauro Carvalho Chehab 
3309a0bf528SMauro Carvalho Chehab static int ds3000_load_firmware(struct dvb_frontend *fe,
3319a0bf528SMauro Carvalho Chehab 					const struct firmware *fw);
3329a0bf528SMauro Carvalho Chehab 
ds3000_firmware_ondemand(struct dvb_frontend * fe)3339a0bf528SMauro Carvalho Chehab static int ds3000_firmware_ondemand(struct dvb_frontend *fe)
3349a0bf528SMauro Carvalho Chehab {
3359a0bf528SMauro Carvalho Chehab 	struct ds3000_state *state = fe->demodulator_priv;
3369a0bf528SMauro Carvalho Chehab 	const struct firmware *fw;
3379a0bf528SMauro Carvalho Chehab 	int ret = 0;
3389a0bf528SMauro Carvalho Chehab 
3399a0bf528SMauro Carvalho Chehab 	dprintk("%s()\n", __func__);
3409a0bf528SMauro Carvalho Chehab 
341034351ffSRémi Cardona 	ret = ds3000_readreg(state, 0xb2);
342034351ffSRémi Cardona 	if (ret < 0)
3439a0bf528SMauro Carvalho Chehab 		return ret;
3449a0bf528SMauro Carvalho Chehab 
3459a0bf528SMauro Carvalho Chehab 	/* Load firmware */
3469a0bf528SMauro Carvalho Chehab 	/* request the firmware, this will block until someone uploads it */
3479a0bf528SMauro Carvalho Chehab 	printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
3489a0bf528SMauro Carvalho Chehab 				DS3000_DEFAULT_FIRMWARE);
3499a0bf528SMauro Carvalho Chehab 	ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE,
3509a0bf528SMauro Carvalho Chehab 				state->i2c->dev.parent);
3519a0bf528SMauro Carvalho Chehab 	printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__);
3529a0bf528SMauro Carvalho Chehab 	if (ret) {
3534bd69e7bSMauro Carvalho Chehab 		printk(KERN_ERR "%s: No firmware uploaded (timeout or file not found?)\n",
3544bd69e7bSMauro Carvalho Chehab 		       __func__);
3559a0bf528SMauro Carvalho Chehab 		return ret;
3569a0bf528SMauro Carvalho Chehab 	}
3579a0bf528SMauro Carvalho Chehab 
3589a0bf528SMauro Carvalho Chehab 	ret = ds3000_load_firmware(fe, fw);
3599a0bf528SMauro Carvalho Chehab 	if (ret)
3609a0bf528SMauro Carvalho Chehab 		printk("%s: Writing firmware to device failed\n", __func__);
3619a0bf528SMauro Carvalho Chehab 
3629a0bf528SMauro Carvalho Chehab 	release_firmware(fw);
3639a0bf528SMauro Carvalho Chehab 
3649a0bf528SMauro Carvalho Chehab 	dprintk("%s: Firmware upload %s\n", __func__,
3659a0bf528SMauro Carvalho Chehab 			ret == 0 ? "complete" : "failed");
3669a0bf528SMauro Carvalho Chehab 
3679a0bf528SMauro Carvalho Chehab 	return ret;
3689a0bf528SMauro Carvalho Chehab }
3699a0bf528SMauro Carvalho Chehab 
ds3000_load_firmware(struct dvb_frontend * fe,const struct firmware * fw)3709a0bf528SMauro Carvalho Chehab static int ds3000_load_firmware(struct dvb_frontend *fe,
3719a0bf528SMauro Carvalho Chehab 					const struct firmware *fw)
3729a0bf528SMauro Carvalho Chehab {
3739a0bf528SMauro Carvalho Chehab 	struct ds3000_state *state = fe->demodulator_priv;
374d58f4f27SRémi Cardona 	int ret = 0;
3759a0bf528SMauro Carvalho Chehab 
3769a0bf528SMauro Carvalho Chehab 	dprintk("%s\n", __func__);
3779a0bf528SMauro Carvalho Chehab 	dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
3789a0bf528SMauro Carvalho Chehab 			fw->size,
3799a0bf528SMauro Carvalho Chehab 			fw->data[0],
3809a0bf528SMauro Carvalho Chehab 			fw->data[1],
3819a0bf528SMauro Carvalho Chehab 			fw->data[fw->size - 2],
3829a0bf528SMauro Carvalho Chehab 			fw->data[fw->size - 1]);
3839a0bf528SMauro Carvalho Chehab 
3849a0bf528SMauro Carvalho Chehab 	/* Begin the firmware load process */
3859a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0xb2, 0x01);
3869a0bf528SMauro Carvalho Chehab 	/* write the entire firmware */
387d58f4f27SRémi Cardona 	ret = ds3000_writeFW(state, 0xb0, fw->data, fw->size);
3889a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0xb2, 0x00);
3899a0bf528SMauro Carvalho Chehab 
390d58f4f27SRémi Cardona 	return ret;
3919a0bf528SMauro Carvalho Chehab }
3929a0bf528SMauro Carvalho Chehab 
ds3000_set_voltage(struct dvb_frontend * fe,enum fe_sec_voltage voltage)3930df289a2SMauro Carvalho Chehab static int ds3000_set_voltage(struct dvb_frontend *fe,
3940df289a2SMauro Carvalho Chehab 			      enum fe_sec_voltage voltage)
3959a0bf528SMauro Carvalho Chehab {
3969a0bf528SMauro Carvalho Chehab 	struct ds3000_state *state = fe->demodulator_priv;
3979a0bf528SMauro Carvalho Chehab 	u8 data;
3989a0bf528SMauro Carvalho Chehab 
3999a0bf528SMauro Carvalho Chehab 	dprintk("%s(%d)\n", __func__, voltage);
4009a0bf528SMauro Carvalho Chehab 
4019a0bf528SMauro Carvalho Chehab 	data = ds3000_readreg(state, 0xa2);
4029a0bf528SMauro Carvalho Chehab 	data |= 0x03; /* bit0 V/H, bit1 off/on */
4039a0bf528SMauro Carvalho Chehab 
4049a0bf528SMauro Carvalho Chehab 	switch (voltage) {
4059a0bf528SMauro Carvalho Chehab 	case SEC_VOLTAGE_18:
4069a0bf528SMauro Carvalho Chehab 		data &= ~0x03;
4079a0bf528SMauro Carvalho Chehab 		break;
4089a0bf528SMauro Carvalho Chehab 	case SEC_VOLTAGE_13:
4099a0bf528SMauro Carvalho Chehab 		data &= ~0x03;
4109a0bf528SMauro Carvalho Chehab 		data |= 0x01;
4119a0bf528SMauro Carvalho Chehab 		break;
4129a0bf528SMauro Carvalho Chehab 	case SEC_VOLTAGE_OFF:
4139a0bf528SMauro Carvalho Chehab 		break;
4149a0bf528SMauro Carvalho Chehab 	}
4159a0bf528SMauro Carvalho Chehab 
4169a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0xa2, data);
4179a0bf528SMauro Carvalho Chehab 
4189a0bf528SMauro Carvalho Chehab 	return 0;
4199a0bf528SMauro Carvalho Chehab }
4209a0bf528SMauro Carvalho Chehab 
ds3000_read_status(struct dvb_frontend * fe,enum fe_status * status)4210df289a2SMauro Carvalho Chehab static int ds3000_read_status(struct dvb_frontend *fe, enum fe_status *status)
4229a0bf528SMauro Carvalho Chehab {
4239a0bf528SMauro Carvalho Chehab 	struct ds3000_state *state = fe->demodulator_priv;
4249a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
4259a0bf528SMauro Carvalho Chehab 	int lock;
4269a0bf528SMauro Carvalho Chehab 
4279a0bf528SMauro Carvalho Chehab 	*status = 0;
4289a0bf528SMauro Carvalho Chehab 
4299a0bf528SMauro Carvalho Chehab 	switch (c->delivery_system) {
4309a0bf528SMauro Carvalho Chehab 	case SYS_DVBS:
4319a0bf528SMauro Carvalho Chehab 		lock = ds3000_readreg(state, 0xd1);
4329a0bf528SMauro Carvalho Chehab 		if ((lock & 0x07) == 0x07)
4339a0bf528SMauro Carvalho Chehab 			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
4349a0bf528SMauro Carvalho Chehab 				FE_HAS_VITERBI | FE_HAS_SYNC |
4359a0bf528SMauro Carvalho Chehab 				FE_HAS_LOCK;
4369a0bf528SMauro Carvalho Chehab 
4379a0bf528SMauro Carvalho Chehab 		break;
4389a0bf528SMauro Carvalho Chehab 	case SYS_DVBS2:
4399a0bf528SMauro Carvalho Chehab 		lock = ds3000_readreg(state, 0x0d);
4409a0bf528SMauro Carvalho Chehab 		if ((lock & 0x8f) == 0x8f)
4419a0bf528SMauro Carvalho Chehab 			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
4429a0bf528SMauro Carvalho Chehab 				FE_HAS_VITERBI | FE_HAS_SYNC |
4439a0bf528SMauro Carvalho Chehab 				FE_HAS_LOCK;
4449a0bf528SMauro Carvalho Chehab 
4459a0bf528SMauro Carvalho Chehab 		break;
4469a0bf528SMauro Carvalho Chehab 	default:
44727924dccSOlli Salonen 		return -EINVAL;
4489a0bf528SMauro Carvalho Chehab 	}
4499a0bf528SMauro Carvalho Chehab 
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 
4539a0bf528SMauro Carvalho Chehab 	dprintk("%s: status = 0x%02x\n", __func__, lock);
4549a0bf528SMauro Carvalho Chehab 
4559a0bf528SMauro Carvalho Chehab 	return 0;
4569a0bf528SMauro Carvalho Chehab }
4579a0bf528SMauro Carvalho Chehab 
4589a0bf528SMauro Carvalho Chehab /* read DS3000 BER value */
ds3000_read_ber(struct dvb_frontend * fe,u32 * ber)4599a0bf528SMauro Carvalho Chehab static int ds3000_read_ber(struct dvb_frontend *fe, u32* ber)
4609a0bf528SMauro Carvalho Chehab {
4619a0bf528SMauro Carvalho Chehab 	struct ds3000_state *state = fe->demodulator_priv;
4629a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
4639a0bf528SMauro Carvalho Chehab 	u8 data;
4649a0bf528SMauro Carvalho Chehab 	u32 ber_reading, lpdc_frames;
4659a0bf528SMauro Carvalho Chehab 
4669a0bf528SMauro Carvalho Chehab 	dprintk("%s()\n", __func__);
4679a0bf528SMauro Carvalho Chehab 
4689a0bf528SMauro Carvalho Chehab 	switch (c->delivery_system) {
4699a0bf528SMauro Carvalho Chehab 	case SYS_DVBS:
4709a0bf528SMauro Carvalho Chehab 		/* set the number of bytes checked during
4719a0bf528SMauro Carvalho Chehab 		BER estimation */
4729a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xf9, 0x04);
4739a0bf528SMauro Carvalho Chehab 		/* read BER estimation status */
4749a0bf528SMauro Carvalho Chehab 		data = ds3000_readreg(state, 0xf8);
4759a0bf528SMauro Carvalho Chehab 		/* check if BER estimation is ready */
4769a0bf528SMauro Carvalho Chehab 		if ((data & 0x10) == 0) {
4779a0bf528SMauro Carvalho Chehab 			/* this is the number of error bits,
4789a0bf528SMauro Carvalho Chehab 			to calculate the bit error rate
4799a0bf528SMauro Carvalho Chehab 			divide to 8388608 */
4809a0bf528SMauro Carvalho Chehab 			*ber = (ds3000_readreg(state, 0xf7) << 8) |
4819a0bf528SMauro Carvalho Chehab 				ds3000_readreg(state, 0xf6);
4829a0bf528SMauro Carvalho Chehab 			/* start counting error bits */
4839a0bf528SMauro Carvalho Chehab 			/* need to be set twice
4849a0bf528SMauro Carvalho Chehab 			otherwise it fails sometimes */
4859a0bf528SMauro Carvalho Chehab 			data |= 0x10;
4869a0bf528SMauro Carvalho Chehab 			ds3000_writereg(state, 0xf8, data);
4879a0bf528SMauro Carvalho Chehab 			ds3000_writereg(state, 0xf8, data);
4889a0bf528SMauro Carvalho Chehab 		} else
4899a0bf528SMauro Carvalho Chehab 			/* used to indicate that BER estimation
4909a0bf528SMauro Carvalho Chehab 			is not ready, i.e. BER is unknown */
4919a0bf528SMauro Carvalho Chehab 			*ber = 0xffffffff;
4929a0bf528SMauro Carvalho Chehab 		break;
4939a0bf528SMauro Carvalho Chehab 	case SYS_DVBS2:
4949a0bf528SMauro Carvalho Chehab 		/* read the number of LPDC decoded frames */
4959a0bf528SMauro Carvalho Chehab 		lpdc_frames = (ds3000_readreg(state, 0xd7) << 16) |
4969a0bf528SMauro Carvalho Chehab 				(ds3000_readreg(state, 0xd6) << 8) |
4979a0bf528SMauro Carvalho Chehab 				ds3000_readreg(state, 0xd5);
4989a0bf528SMauro Carvalho Chehab 		/* read the number of packets with bad CRC */
4999a0bf528SMauro Carvalho Chehab 		ber_reading = (ds3000_readreg(state, 0xf8) << 8) |
5009a0bf528SMauro Carvalho Chehab 				ds3000_readreg(state, 0xf7);
5019a0bf528SMauro Carvalho Chehab 		if (lpdc_frames > 750) {
5029a0bf528SMauro Carvalho Chehab 			/* clear LPDC frame counters */
5039a0bf528SMauro Carvalho Chehab 			ds3000_writereg(state, 0xd1, 0x01);
5049a0bf528SMauro Carvalho Chehab 			/* clear bad packets counter */
5059a0bf528SMauro Carvalho Chehab 			ds3000_writereg(state, 0xf9, 0x01);
5069a0bf528SMauro Carvalho Chehab 			/* enable bad packets counter */
5079a0bf528SMauro Carvalho Chehab 			ds3000_writereg(state, 0xf9, 0x00);
5089a0bf528SMauro Carvalho Chehab 			/* enable LPDC frame counters */
5099a0bf528SMauro Carvalho Chehab 			ds3000_writereg(state, 0xd1, 0x00);
5109a0bf528SMauro Carvalho Chehab 			*ber = ber_reading;
5119a0bf528SMauro Carvalho Chehab 		} else
5129a0bf528SMauro Carvalho Chehab 			/* used to indicate that BER estimation is not ready,
5139a0bf528SMauro Carvalho Chehab 			i.e. BER is unknown */
5149a0bf528SMauro Carvalho Chehab 			*ber = 0xffffffff;
5159a0bf528SMauro Carvalho Chehab 		break;
5169a0bf528SMauro Carvalho Chehab 	default:
51727924dccSOlli Salonen 		return -EINVAL;
5189a0bf528SMauro Carvalho Chehab 	}
5199a0bf528SMauro Carvalho Chehab 
5209a0bf528SMauro Carvalho Chehab 	return 0;
5219a0bf528SMauro Carvalho Chehab }
5229a0bf528SMauro Carvalho Chehab 
ds3000_read_signal_strength(struct dvb_frontend * fe,u16 * signal_strength)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 
5329a0bf528SMauro Carvalho Chehab /* calculate DS3000 snr value in dB */
ds3000_read_snr(struct dvb_frontend * fe,u16 * snr)5339a0bf528SMauro Carvalho Chehab static int ds3000_read_snr(struct dvb_frontend *fe, u16 *snr)
5349a0bf528SMauro Carvalho Chehab {
5359a0bf528SMauro Carvalho Chehab 	struct ds3000_state *state = fe->demodulator_priv;
5369a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
5379a0bf528SMauro Carvalho Chehab 	u8 snr_reading, snr_value;
5389a0bf528SMauro Carvalho Chehab 	u32 dvbs2_signal_reading, dvbs2_noise_reading, tmp;
5399a0bf528SMauro Carvalho Chehab 	static const u16 dvbs_snr_tab[] = { /* 20 x Table (rounded up) */
5409a0bf528SMauro Carvalho Chehab 		0x0000, 0x1b13, 0x2aea, 0x3627, 0x3ede, 0x45fe, 0x4c03,
5419a0bf528SMauro Carvalho Chehab 		0x513a, 0x55d4, 0x59f2, 0x5dab, 0x6111, 0x6431, 0x6717,
5429a0bf528SMauro Carvalho Chehab 		0x69c9, 0x6c4e, 0x6eac, 0x70e8, 0x7304, 0x7505
5439a0bf528SMauro Carvalho Chehab 	};
5449a0bf528SMauro Carvalho Chehab 	static const u16 dvbs2_snr_tab[] = { /* 80 x Table (rounded up) */
5459a0bf528SMauro Carvalho Chehab 		0x0000, 0x0bc2, 0x12a3, 0x1785, 0x1b4e, 0x1e65, 0x2103,
5469a0bf528SMauro Carvalho Chehab 		0x2347, 0x2546, 0x2710, 0x28ae, 0x2a28, 0x2b83, 0x2cc5,
5479a0bf528SMauro Carvalho Chehab 		0x2df1, 0x2f09, 0x3010, 0x3109, 0x31f4, 0x32d2, 0x33a6,
5489a0bf528SMauro Carvalho Chehab 		0x3470, 0x3531, 0x35ea, 0x369b, 0x3746, 0x37ea, 0x3888,
5499a0bf528SMauro Carvalho Chehab 		0x3920, 0x39b3, 0x3a42, 0x3acc, 0x3b51, 0x3bd3, 0x3c51,
5509a0bf528SMauro Carvalho Chehab 		0x3ccb, 0x3d42, 0x3db6, 0x3e27, 0x3e95, 0x3f00, 0x3f68,
5519a0bf528SMauro Carvalho Chehab 		0x3fcf, 0x4033, 0x4094, 0x40f4, 0x4151, 0x41ac, 0x4206,
5529a0bf528SMauro Carvalho Chehab 		0x425e, 0x42b4, 0x4308, 0x435b, 0x43ac, 0x43fc, 0x444a,
5539a0bf528SMauro Carvalho Chehab 		0x4497, 0x44e2, 0x452d, 0x4576, 0x45bd, 0x4604, 0x4649,
5549a0bf528SMauro Carvalho Chehab 		0x468e, 0x46d1, 0x4713, 0x4755, 0x4795, 0x47d4, 0x4813,
5559a0bf528SMauro Carvalho Chehab 		0x4851, 0x488d, 0x48c9, 0x4904, 0x493f, 0x4978, 0x49b1,
5569a0bf528SMauro Carvalho Chehab 		0x49e9, 0x4a20, 0x4a57
5579a0bf528SMauro Carvalho Chehab 	};
5589a0bf528SMauro Carvalho Chehab 
5599a0bf528SMauro Carvalho Chehab 	dprintk("%s()\n", __func__);
5609a0bf528SMauro Carvalho Chehab 
5619a0bf528SMauro Carvalho Chehab 	switch (c->delivery_system) {
5629a0bf528SMauro Carvalho Chehab 	case SYS_DVBS:
5639a0bf528SMauro Carvalho Chehab 		snr_reading = ds3000_readreg(state, 0xff);
5649a0bf528SMauro Carvalho Chehab 		snr_reading /= 8;
5659a0bf528SMauro Carvalho Chehab 		if (snr_reading == 0)
5669a0bf528SMauro Carvalho Chehab 			*snr = 0x0000;
5679a0bf528SMauro Carvalho Chehab 		else {
5689a0bf528SMauro Carvalho Chehab 			if (snr_reading > 20)
5699a0bf528SMauro Carvalho Chehab 				snr_reading = 20;
5709a0bf528SMauro Carvalho Chehab 			snr_value = dvbs_snr_tab[snr_reading - 1] * 10 / 23026;
5719a0bf528SMauro Carvalho Chehab 			/* cook the value to be suitable for szap-s2
5729a0bf528SMauro Carvalho Chehab 			human readable output */
5739a0bf528SMauro Carvalho Chehab 			*snr = snr_value * 8 * 655;
5749a0bf528SMauro Carvalho Chehab 		}
5759a0bf528SMauro Carvalho Chehab 		dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
5769a0bf528SMauro Carvalho Chehab 				snr_reading, *snr);
5779a0bf528SMauro Carvalho Chehab 		break;
5789a0bf528SMauro Carvalho Chehab 	case SYS_DVBS2:
5799a0bf528SMauro Carvalho Chehab 		dvbs2_noise_reading = (ds3000_readreg(state, 0x8c) & 0x3f) +
5809a0bf528SMauro Carvalho Chehab 				(ds3000_readreg(state, 0x8d) << 4);
5819a0bf528SMauro Carvalho Chehab 		dvbs2_signal_reading = ds3000_readreg(state, 0x8e);
5829a0bf528SMauro Carvalho Chehab 		tmp = dvbs2_signal_reading * dvbs2_signal_reading >> 1;
5839a0bf528SMauro Carvalho Chehab 		if (tmp == 0) {
5849a0bf528SMauro Carvalho Chehab 			*snr = 0x0000;
5859a0bf528SMauro Carvalho Chehab 			return 0;
5869a0bf528SMauro Carvalho Chehab 		}
5879a0bf528SMauro Carvalho Chehab 		if (dvbs2_noise_reading == 0) {
5889a0bf528SMauro Carvalho Chehab 			snr_value = 0x0013;
5899a0bf528SMauro Carvalho Chehab 			/* cook the value to be suitable for szap-s2
5909a0bf528SMauro Carvalho Chehab 			human readable output */
5919a0bf528SMauro Carvalho Chehab 			*snr = 0xffff;
5929a0bf528SMauro Carvalho Chehab 			return 0;
5939a0bf528SMauro Carvalho Chehab 		}
5949a0bf528SMauro Carvalho Chehab 		if (tmp > dvbs2_noise_reading) {
5959a0bf528SMauro Carvalho Chehab 			snr_reading = tmp / dvbs2_noise_reading;
5969a0bf528SMauro Carvalho Chehab 			if (snr_reading > 80)
5979a0bf528SMauro Carvalho Chehab 				snr_reading = 80;
5989a0bf528SMauro Carvalho Chehab 			snr_value = dvbs2_snr_tab[snr_reading - 1] / 1000;
5999a0bf528SMauro Carvalho Chehab 			/* cook the value to be suitable for szap-s2
6009a0bf528SMauro Carvalho Chehab 			human readable output */
6019a0bf528SMauro Carvalho Chehab 			*snr = snr_value * 5 * 655;
6029a0bf528SMauro Carvalho Chehab 		} else {
6039a0bf528SMauro Carvalho Chehab 			snr_reading = dvbs2_noise_reading / tmp;
6049a0bf528SMauro Carvalho Chehab 			if (snr_reading > 80)
6059a0bf528SMauro Carvalho Chehab 				snr_reading = 80;
606b59de95bSHeinrich Schuchardt 			*snr = -(dvbs2_snr_tab[snr_reading - 1] / 1000);
6079a0bf528SMauro Carvalho Chehab 		}
6089a0bf528SMauro Carvalho Chehab 		dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
6099a0bf528SMauro Carvalho Chehab 				snr_reading, *snr);
6109a0bf528SMauro Carvalho Chehab 		break;
6119a0bf528SMauro Carvalho Chehab 	default:
61227924dccSOlli Salonen 		return -EINVAL;
6139a0bf528SMauro Carvalho Chehab 	}
6149a0bf528SMauro Carvalho Chehab 
6159a0bf528SMauro Carvalho Chehab 	return 0;
6169a0bf528SMauro Carvalho Chehab }
6179a0bf528SMauro Carvalho Chehab 
6189a0bf528SMauro Carvalho Chehab /* read DS3000 uncorrected blocks */
ds3000_read_ucblocks(struct dvb_frontend * fe,u32 * ucblocks)6199a0bf528SMauro Carvalho Chehab static int ds3000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
6209a0bf528SMauro Carvalho Chehab {
6219a0bf528SMauro Carvalho Chehab 	struct ds3000_state *state = fe->demodulator_priv;
6229a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
6239a0bf528SMauro Carvalho Chehab 	u8 data;
6249a0bf528SMauro Carvalho Chehab 	u16 _ucblocks;
6259a0bf528SMauro Carvalho Chehab 
6269a0bf528SMauro Carvalho Chehab 	dprintk("%s()\n", __func__);
6279a0bf528SMauro Carvalho Chehab 
6289a0bf528SMauro Carvalho Chehab 	switch (c->delivery_system) {
6299a0bf528SMauro Carvalho Chehab 	case SYS_DVBS:
6309a0bf528SMauro Carvalho Chehab 		*ucblocks = (ds3000_readreg(state, 0xf5) << 8) |
6319a0bf528SMauro Carvalho Chehab 				ds3000_readreg(state, 0xf4);
6329a0bf528SMauro Carvalho Chehab 		data = ds3000_readreg(state, 0xf8);
6339a0bf528SMauro Carvalho Chehab 		/* clear packet counters */
6349a0bf528SMauro Carvalho Chehab 		data &= ~0x20;
6359a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xf8, data);
6369a0bf528SMauro Carvalho Chehab 		/* enable packet counters */
6379a0bf528SMauro Carvalho Chehab 		data |= 0x20;
6389a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xf8, data);
6399a0bf528SMauro Carvalho Chehab 		break;
6409a0bf528SMauro Carvalho Chehab 	case SYS_DVBS2:
6419a0bf528SMauro Carvalho Chehab 		_ucblocks = (ds3000_readreg(state, 0xe2) << 8) |
6429a0bf528SMauro Carvalho Chehab 				ds3000_readreg(state, 0xe1);
6439a0bf528SMauro Carvalho Chehab 		if (_ucblocks > state->prevUCBS2)
6449a0bf528SMauro Carvalho Chehab 			*ucblocks = _ucblocks - state->prevUCBS2;
6459a0bf528SMauro Carvalho Chehab 		else
6469a0bf528SMauro Carvalho Chehab 			*ucblocks = state->prevUCBS2 - _ucblocks;
6479a0bf528SMauro Carvalho Chehab 		state->prevUCBS2 = _ucblocks;
6489a0bf528SMauro Carvalho Chehab 		break;
6499a0bf528SMauro Carvalho Chehab 	default:
65027924dccSOlli Salonen 		return -EINVAL;
6519a0bf528SMauro Carvalho Chehab 	}
6529a0bf528SMauro Carvalho Chehab 
6539a0bf528SMauro Carvalho Chehab 	return 0;
6549a0bf528SMauro Carvalho Chehab }
6559a0bf528SMauro Carvalho Chehab 
ds3000_set_tone(struct dvb_frontend * fe,enum fe_sec_tone_mode tone)6560df289a2SMauro Carvalho Chehab static int ds3000_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone)
6579a0bf528SMauro Carvalho Chehab {
6589a0bf528SMauro Carvalho Chehab 	struct ds3000_state *state = fe->demodulator_priv;
6599a0bf528SMauro Carvalho Chehab 	u8 data;
6609a0bf528SMauro Carvalho Chehab 
6619a0bf528SMauro Carvalho Chehab 	dprintk("%s(%d)\n", __func__, tone);
6629a0bf528SMauro Carvalho Chehab 	if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
6639a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
6649a0bf528SMauro Carvalho Chehab 		return -EINVAL;
6659a0bf528SMauro Carvalho Chehab 	}
6669a0bf528SMauro Carvalho Chehab 
6679a0bf528SMauro Carvalho Chehab 	data = ds3000_readreg(state, 0xa2);
6689a0bf528SMauro Carvalho Chehab 	data &= ~0xc0;
6699a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0xa2, data);
6709a0bf528SMauro Carvalho Chehab 
6719a0bf528SMauro Carvalho Chehab 	switch (tone) {
6729a0bf528SMauro Carvalho Chehab 	case SEC_TONE_ON:
6739a0bf528SMauro Carvalho Chehab 		dprintk("%s: setting tone on\n", __func__);
6749a0bf528SMauro Carvalho Chehab 		data = ds3000_readreg(state, 0xa1);
6759a0bf528SMauro Carvalho Chehab 		data &= ~0x43;
6769a0bf528SMauro Carvalho Chehab 		data |= 0x04;
6779a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xa1, data);
6789a0bf528SMauro Carvalho Chehab 		break;
6799a0bf528SMauro Carvalho Chehab 	case SEC_TONE_OFF:
6809a0bf528SMauro Carvalho Chehab 		dprintk("%s: setting tone off\n", __func__);
6819a0bf528SMauro Carvalho Chehab 		data = ds3000_readreg(state, 0xa2);
6829a0bf528SMauro Carvalho Chehab 		data |= 0x80;
6839a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xa2, data);
6849a0bf528SMauro Carvalho Chehab 		break;
6859a0bf528SMauro Carvalho Chehab 	}
6869a0bf528SMauro Carvalho Chehab 
6879a0bf528SMauro Carvalho Chehab 	return 0;
6889a0bf528SMauro Carvalho Chehab }
6899a0bf528SMauro Carvalho Chehab 
ds3000_send_diseqc_msg(struct dvb_frontend * fe,struct dvb_diseqc_master_cmd * d)6909a0bf528SMauro Carvalho Chehab static int ds3000_send_diseqc_msg(struct dvb_frontend *fe,
6919a0bf528SMauro Carvalho Chehab 				struct dvb_diseqc_master_cmd *d)
6929a0bf528SMauro Carvalho Chehab {
6939a0bf528SMauro Carvalho Chehab 	struct ds3000_state *state = fe->demodulator_priv;
6949a0bf528SMauro Carvalho Chehab 	int i;
6959a0bf528SMauro Carvalho Chehab 	u8 data;
6969a0bf528SMauro Carvalho Chehab 
6979a0bf528SMauro Carvalho Chehab 	/* Dump DiSEqC message */
6989a0bf528SMauro Carvalho Chehab 	dprintk("%s(", __func__);
6999a0bf528SMauro Carvalho Chehab 	for (i = 0 ; i < d->msg_len;) {
7009a0bf528SMauro Carvalho Chehab 		dprintk("0x%02x", d->msg[i]);
7019a0bf528SMauro Carvalho Chehab 		if (++i < d->msg_len)
7029a0bf528SMauro Carvalho Chehab 			dprintk(", ");
7039a0bf528SMauro Carvalho Chehab 	}
7049a0bf528SMauro Carvalho Chehab 
7059a0bf528SMauro Carvalho Chehab 	/* enable DiSEqC message send pin */
7069a0bf528SMauro Carvalho Chehab 	data = ds3000_readreg(state, 0xa2);
7079a0bf528SMauro Carvalho Chehab 	data &= ~0xc0;
7089a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0xa2, data);
7099a0bf528SMauro Carvalho Chehab 
7109a0bf528SMauro Carvalho Chehab 	/* DiSEqC message */
7119a0bf528SMauro Carvalho Chehab 	for (i = 0; i < d->msg_len; i++)
7129a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xa3 + i, d->msg[i]);
7139a0bf528SMauro Carvalho Chehab 
7149a0bf528SMauro Carvalho Chehab 	data = ds3000_readreg(state, 0xa1);
7159a0bf528SMauro Carvalho Chehab 	/* clear DiSEqC message length and status,
7169a0bf528SMauro Carvalho Chehab 	enable DiSEqC message send */
7179a0bf528SMauro Carvalho Chehab 	data &= ~0xf8;
7189a0bf528SMauro Carvalho Chehab 	/* set DiSEqC mode, modulation active during 33 pulses,
7199a0bf528SMauro Carvalho Chehab 	set DiSEqC message length */
7209a0bf528SMauro Carvalho Chehab 	data |= ((d->msg_len - 1) << 3) | 0x07;
7219a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0xa1, data);
7229a0bf528SMauro Carvalho Chehab 
7239a0bf528SMauro Carvalho Chehab 	/* wait up to 150ms for DiSEqC transmission to complete */
7249a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 15; i++) {
7259a0bf528SMauro Carvalho Chehab 		data = ds3000_readreg(state, 0xa1);
7269a0bf528SMauro Carvalho Chehab 		if ((data & 0x40) == 0)
7279a0bf528SMauro Carvalho Chehab 			break;
7289a0bf528SMauro Carvalho Chehab 		msleep(10);
7299a0bf528SMauro Carvalho Chehab 	}
7309a0bf528SMauro Carvalho Chehab 
7319a0bf528SMauro Carvalho Chehab 	/* DiSEqC timeout after 150ms */
7329a0bf528SMauro Carvalho Chehab 	if (i == 15) {
7339a0bf528SMauro Carvalho Chehab 		data = ds3000_readreg(state, 0xa1);
7349a0bf528SMauro Carvalho Chehab 		data &= ~0x80;
7359a0bf528SMauro Carvalho Chehab 		data |= 0x40;
7369a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xa1, data);
7379a0bf528SMauro Carvalho Chehab 
7389a0bf528SMauro Carvalho Chehab 		data = ds3000_readreg(state, 0xa2);
7399a0bf528SMauro Carvalho Chehab 		data &= ~0xc0;
7409a0bf528SMauro Carvalho Chehab 		data |= 0x80;
7419a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xa2, data);
7429a0bf528SMauro Carvalho Chehab 
74327924dccSOlli Salonen 		return -ETIMEDOUT;
7449a0bf528SMauro Carvalho Chehab 	}
7459a0bf528SMauro Carvalho Chehab 
7469a0bf528SMauro Carvalho Chehab 	data = ds3000_readreg(state, 0xa2);
7479a0bf528SMauro Carvalho Chehab 	data &= ~0xc0;
7489a0bf528SMauro Carvalho Chehab 	data |= 0x80;
7499a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0xa2, data);
7509a0bf528SMauro Carvalho Chehab 
7519a0bf528SMauro Carvalho Chehab 	return 0;
7529a0bf528SMauro Carvalho Chehab }
7539a0bf528SMauro Carvalho Chehab 
7549a0bf528SMauro Carvalho Chehab /* Send DiSEqC burst */
ds3000_diseqc_send_burst(struct dvb_frontend * fe,enum fe_sec_mini_cmd burst)7559a0bf528SMauro Carvalho Chehab static int ds3000_diseqc_send_burst(struct dvb_frontend *fe,
7560df289a2SMauro Carvalho Chehab 				    enum fe_sec_mini_cmd burst)
7579a0bf528SMauro Carvalho Chehab {
7589a0bf528SMauro Carvalho Chehab 	struct ds3000_state *state = fe->demodulator_priv;
7599a0bf528SMauro Carvalho Chehab 	int i;
7609a0bf528SMauro Carvalho Chehab 	u8 data;
7619a0bf528SMauro Carvalho Chehab 
7629a0bf528SMauro Carvalho Chehab 	dprintk("%s()\n", __func__);
7639a0bf528SMauro Carvalho Chehab 
7649a0bf528SMauro Carvalho Chehab 	data = ds3000_readreg(state, 0xa2);
7659a0bf528SMauro Carvalho Chehab 	data &= ~0xc0;
7669a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0xa2, data);
7679a0bf528SMauro Carvalho Chehab 
7689a0bf528SMauro Carvalho Chehab 	/* DiSEqC burst */
7699a0bf528SMauro Carvalho Chehab 	if (burst == SEC_MINI_A)
7709a0bf528SMauro Carvalho Chehab 		/* Unmodulated tone burst */
7719a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xa1, 0x02);
7729a0bf528SMauro Carvalho Chehab 	else if (burst == SEC_MINI_B)
7739a0bf528SMauro Carvalho Chehab 		/* Modulated tone burst */
7749a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xa1, 0x01);
7759a0bf528SMauro Carvalho Chehab 	else
7769a0bf528SMauro Carvalho Chehab 		return -EINVAL;
7779a0bf528SMauro Carvalho Chehab 
7789a0bf528SMauro Carvalho Chehab 	msleep(13);
7799a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 5; i++) {
7809a0bf528SMauro Carvalho Chehab 		data = ds3000_readreg(state, 0xa1);
7819a0bf528SMauro Carvalho Chehab 		if ((data & 0x40) == 0)
7829a0bf528SMauro Carvalho Chehab 			break;
7839a0bf528SMauro Carvalho Chehab 		msleep(1);
7849a0bf528SMauro Carvalho Chehab 	}
7859a0bf528SMauro Carvalho Chehab 
7869a0bf528SMauro Carvalho Chehab 	if (i == 5) {
7879a0bf528SMauro Carvalho Chehab 		data = ds3000_readreg(state, 0xa1);
7889a0bf528SMauro Carvalho Chehab 		data &= ~0x80;
7899a0bf528SMauro Carvalho Chehab 		data |= 0x40;
7909a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xa1, data);
7919a0bf528SMauro Carvalho Chehab 
7929a0bf528SMauro Carvalho Chehab 		data = ds3000_readreg(state, 0xa2);
7939a0bf528SMauro Carvalho Chehab 		data &= ~0xc0;
7949a0bf528SMauro Carvalho Chehab 		data |= 0x80;
7959a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xa2, data);
7969a0bf528SMauro Carvalho Chehab 
79727924dccSOlli Salonen 		return -ETIMEDOUT;
7989a0bf528SMauro Carvalho Chehab 	}
7999a0bf528SMauro Carvalho Chehab 
8009a0bf528SMauro Carvalho Chehab 	data = ds3000_readreg(state, 0xa2);
8019a0bf528SMauro Carvalho Chehab 	data &= ~0xc0;
8029a0bf528SMauro Carvalho Chehab 	data |= 0x80;
8039a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0xa2, data);
8049a0bf528SMauro Carvalho Chehab 
8059a0bf528SMauro Carvalho Chehab 	return 0;
8069a0bf528SMauro Carvalho Chehab }
8079a0bf528SMauro Carvalho Chehab 
ds3000_release(struct dvb_frontend * fe)8089a0bf528SMauro Carvalho Chehab static void ds3000_release(struct dvb_frontend *fe)
8099a0bf528SMauro Carvalho Chehab {
8109a0bf528SMauro Carvalho Chehab 	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 
8159a0bf528SMauro Carvalho Chehab 	dprintk("%s\n", __func__);
8169a0bf528SMauro Carvalho Chehab 	kfree(state);
8179a0bf528SMauro Carvalho Chehab }
8189a0bf528SMauro Carvalho Chehab 
819bd336e63SMax Kellermann static const struct dvb_frontend_ops ds3000_ops;
8209a0bf528SMauro Carvalho Chehab 
ds3000_attach(const struct ds3000_config * config,struct i2c_adapter * i2c)8219a0bf528SMauro Carvalho Chehab struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
8229a0bf528SMauro Carvalho Chehab 				    struct i2c_adapter *i2c)
8239a0bf528SMauro Carvalho Chehab {
824d303b7c5SMarkus Elfring 	struct ds3000_state *state;
8259a0bf528SMauro Carvalho Chehab 	int ret;
8269a0bf528SMauro Carvalho Chehab 
8279a0bf528SMauro Carvalho Chehab 	dprintk("%s\n", __func__);
8289a0bf528SMauro Carvalho Chehab 
8299a0bf528SMauro Carvalho Chehab 	/* allocate memory for the internal state */
8302d3da59fSMarkus Elfring 	state = kzalloc(sizeof(*state), GFP_KERNEL);
831c38e8657SMarkus Elfring 	if (!state)
8329722e569SMarkus Elfring 		return NULL;
8339a0bf528SMauro Carvalho Chehab 
8349a0bf528SMauro Carvalho Chehab 	state->config = config;
8359a0bf528SMauro Carvalho Chehab 	state->i2c = i2c;
8369a0bf528SMauro Carvalho Chehab 	state->prevUCBS2 = 0;
8379a0bf528SMauro Carvalho Chehab 
8389a0bf528SMauro Carvalho Chehab 	/* check if the demod is present */
8399a0bf528SMauro Carvalho Chehab 	ret = ds3000_readreg(state, 0x00) & 0xfe;
8409a0bf528SMauro Carvalho Chehab 	if (ret != 0xe0) {
8419722e569SMarkus Elfring 		kfree(state);
8429a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "Invalid probe, probably not a DS3000\n");
8439722e569SMarkus Elfring 		return NULL;
8449a0bf528SMauro Carvalho Chehab 	}
8459a0bf528SMauro Carvalho Chehab 
8469a0bf528SMauro Carvalho Chehab 	printk(KERN_INFO "DS3000 chip version: %d.%d attached.\n",
8479a0bf528SMauro Carvalho Chehab 			ds3000_readreg(state, 0x02),
8489a0bf528SMauro Carvalho Chehab 			ds3000_readreg(state, 0x01));
8499a0bf528SMauro Carvalho Chehab 
8509a0bf528SMauro Carvalho Chehab 	memcpy(&state->frontend.ops, &ds3000_ops,
8519a0bf528SMauro Carvalho Chehab 			sizeof(struct dvb_frontend_ops));
8529a0bf528SMauro Carvalho Chehab 	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);
8609a0bf528SMauro Carvalho Chehab 	return &state->frontend;
8619a0bf528SMauro Carvalho Chehab }
862*86495af1SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(ds3000_attach);
8639a0bf528SMauro Carvalho Chehab 
ds3000_set_carrier_offset(struct dvb_frontend * fe,s32 carrier_offset_khz)8649a0bf528SMauro Carvalho Chehab static int ds3000_set_carrier_offset(struct dvb_frontend *fe,
8659a0bf528SMauro Carvalho Chehab 					s32 carrier_offset_khz)
8669a0bf528SMauro Carvalho Chehab {
8679a0bf528SMauro Carvalho Chehab 	struct ds3000_state *state = fe->demodulator_priv;
8689a0bf528SMauro Carvalho Chehab 	s32 tmp;
8699a0bf528SMauro Carvalho Chehab 
8709a0bf528SMauro Carvalho Chehab 	tmp = carrier_offset_khz;
8719a0bf528SMauro Carvalho Chehab 	tmp *= 65536;
8729a0bf528SMauro Carvalho Chehab 	tmp = (2 * tmp + DS3000_SAMPLE_RATE) / (2 * DS3000_SAMPLE_RATE);
8739a0bf528SMauro Carvalho Chehab 
8749a0bf528SMauro Carvalho Chehab 	if (tmp < 0)
8759a0bf528SMauro Carvalho Chehab 		tmp += 65536;
8769a0bf528SMauro Carvalho Chehab 
8779a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0x5f, tmp >> 8);
8789a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0x5e, tmp & 0xff);
8799a0bf528SMauro Carvalho Chehab 
8809a0bf528SMauro Carvalho Chehab 	return 0;
8819a0bf528SMauro Carvalho Chehab }
8829a0bf528SMauro Carvalho Chehab 
ds3000_set_frontend(struct dvb_frontend * fe)8839a0bf528SMauro Carvalho Chehab static int ds3000_set_frontend(struct dvb_frontend *fe)
8849a0bf528SMauro Carvalho Chehab {
8859a0bf528SMauro Carvalho Chehab 	struct ds3000_state *state = fe->demodulator_priv;
8869a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
8879a0bf528SMauro Carvalho Chehab 
8889a0bf528SMauro Carvalho Chehab 	int i;
8890df289a2SMauro Carvalho Chehab 	enum fe_status status;
8909a0bf528SMauro Carvalho Chehab 	s32 offset_khz;
891c1965eaeSKonstantin Dimitrov 	u32 frequency;
892c1965eaeSKonstantin Dimitrov 	u16 value;
8939a0bf528SMauro Carvalho Chehab 
8949a0bf528SMauro Carvalho Chehab 	dprintk("%s() ", __func__);
8959a0bf528SMauro Carvalho Chehab 
8969a0bf528SMauro Carvalho Chehab 	if (state->config->set_ts_params)
8979a0bf528SMauro Carvalho Chehab 		state->config->set_ts_params(fe, 0);
8989a0bf528SMauro Carvalho Chehab 	/* Tune */
899c1965eaeSKonstantin Dimitrov 	if (fe->ops.tuner_ops.set_params)
900c1965eaeSKonstantin Dimitrov 		fe->ops.tuner_ops.set_params(fe);
9019a0bf528SMauro Carvalho Chehab 
9029a0bf528SMauro Carvalho Chehab 	/* ds3000 global reset */
9039a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0x07, 0x80);
9049a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0x07, 0x00);
905868c9a17SMauro Carvalho Chehab 	/* ds3000 built-in uC reset */
9069a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0xb2, 0x01);
9079a0bf528SMauro Carvalho Chehab 	/* ds3000 software reset */
9089a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0x00, 0x01);
9099a0bf528SMauro Carvalho Chehab 
9109a0bf528SMauro Carvalho Chehab 	switch (c->delivery_system) {
9119a0bf528SMauro Carvalho Chehab 	case SYS_DVBS:
9129a0bf528SMauro Carvalho Chehab 		/* initialise the demod in DVB-S mode */
9139a0bf528SMauro Carvalho Chehab 		for (i = 0; i < sizeof(ds3000_dvbs_init_tab); i += 2)
9149a0bf528SMauro Carvalho Chehab 			ds3000_writereg(state,
9159a0bf528SMauro Carvalho Chehab 				ds3000_dvbs_init_tab[i],
9169a0bf528SMauro Carvalho Chehab 				ds3000_dvbs_init_tab[i + 1]);
9179a0bf528SMauro Carvalho Chehab 		value = ds3000_readreg(state, 0xfe);
9189a0bf528SMauro Carvalho Chehab 		value &= 0xc0;
9199a0bf528SMauro Carvalho Chehab 		value |= 0x1b;
9209a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xfe, value);
9219a0bf528SMauro Carvalho Chehab 		break;
9229a0bf528SMauro Carvalho Chehab 	case SYS_DVBS2:
9239a0bf528SMauro Carvalho Chehab 		/* initialise the demod in DVB-S2 mode */
9249a0bf528SMauro Carvalho Chehab 		for (i = 0; i < sizeof(ds3000_dvbs2_init_tab); i += 2)
9259a0bf528SMauro Carvalho Chehab 			ds3000_writereg(state,
9269a0bf528SMauro Carvalho Chehab 				ds3000_dvbs2_init_tab[i],
9279a0bf528SMauro Carvalho Chehab 				ds3000_dvbs2_init_tab[i + 1]);
9289a0bf528SMauro Carvalho Chehab 		if (c->symbol_rate >= 30000000)
9299a0bf528SMauro Carvalho Chehab 			ds3000_writereg(state, 0xfe, 0x54);
9309a0bf528SMauro Carvalho Chehab 		else
9319a0bf528SMauro Carvalho Chehab 			ds3000_writereg(state, 0xfe, 0x98);
9329a0bf528SMauro Carvalho Chehab 		break;
9339a0bf528SMauro Carvalho Chehab 	default:
93427924dccSOlli Salonen 		return -EINVAL;
9359a0bf528SMauro Carvalho Chehab 	}
9369a0bf528SMauro Carvalho Chehab 
9379a0bf528SMauro Carvalho Chehab 	/* enable 27MHz clock output */
9389a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0x29, 0x80);
9399a0bf528SMauro Carvalho Chehab 	/* enable ac coupling */
9409a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0x25, 0x8a);
9419a0bf528SMauro Carvalho Chehab 
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 
9519a0bf528SMauro Carvalho Chehab 	/* enhance symbol rate performance */
9529a0bf528SMauro Carvalho Chehab 	if ((c->symbol_rate / 1000) <= 5000) {
9539a0bf528SMauro Carvalho Chehab 		value = 29777 / (c->symbol_rate / 1000) + 1;
9549a0bf528SMauro Carvalho Chehab 		if (value % 2 != 0)
9559a0bf528SMauro Carvalho Chehab 			value++;
9569a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xc3, 0x0d);
9579a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xc8, value);
9589a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xc4, 0x10);
9599a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xc7, 0x0e);
9609a0bf528SMauro Carvalho Chehab 	} else if ((c->symbol_rate / 1000) <= 10000) {
9619a0bf528SMauro Carvalho Chehab 		value = 92166 / (c->symbol_rate / 1000) + 1;
9629a0bf528SMauro Carvalho Chehab 		if (value % 2 != 0)
9639a0bf528SMauro Carvalho Chehab 			value++;
9649a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xc3, 0x07);
9659a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xc8, value);
9669a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xc4, 0x09);
9679a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xc7, 0x12);
9689a0bf528SMauro Carvalho Chehab 	} else if ((c->symbol_rate / 1000) <= 20000) {
9699a0bf528SMauro Carvalho Chehab 		value = 64516 / (c->symbol_rate / 1000) + 1;
9709a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xc3, value);
9719a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xc8, 0x0e);
9729a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xc4, 0x07);
9739a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xc7, 0x18);
9749a0bf528SMauro Carvalho Chehab 	} else {
9759a0bf528SMauro Carvalho Chehab 		value = 129032 / (c->symbol_rate / 1000) + 1;
9769a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xc3, value);
9779a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xc8, 0x0a);
9789a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xc4, 0x05);
9799a0bf528SMauro Carvalho Chehab 		ds3000_writereg(state, 0xc7, 0x24);
9809a0bf528SMauro Carvalho Chehab 	}
9819a0bf528SMauro Carvalho Chehab 
9829a0bf528SMauro Carvalho Chehab 	/* normalized symbol rate rounded to the closest integer */
9839a0bf528SMauro Carvalho Chehab 	value = (((c->symbol_rate / 1000) << 16) +
9849a0bf528SMauro Carvalho Chehab 			(DS3000_SAMPLE_RATE / 2)) / DS3000_SAMPLE_RATE;
9859a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0x61, value & 0x00ff);
9869a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0x62, (value & 0xff00) >> 8);
9879a0bf528SMauro Carvalho Chehab 
9889a0bf528SMauro Carvalho Chehab 	/* co-channel interference cancellation disabled */
9899a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0x56, 0x00);
9909a0bf528SMauro Carvalho Chehab 
9919a0bf528SMauro Carvalho Chehab 	/* equalizer disabled */
9929a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0x76, 0x00);
9939a0bf528SMauro Carvalho Chehab 
9949a0bf528SMauro Carvalho Chehab 	/*ds3000_writereg(state, 0x08, 0x03);
9959a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0xfd, 0x22);
9969a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0x08, 0x07);
9979a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0xfd, 0x42);
9989a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0x08, 0x07);*/
9999a0bf528SMauro Carvalho Chehab 
10009a0bf528SMauro Carvalho Chehab 	if (state->config->ci_mode) {
10019a0bf528SMauro Carvalho Chehab 		switch (c->delivery_system) {
10029a0bf528SMauro Carvalho Chehab 		case SYS_DVBS:
10039a0bf528SMauro Carvalho Chehab 		default:
10049a0bf528SMauro Carvalho Chehab 			ds3000_writereg(state, 0xfd, 0x80);
10059a0bf528SMauro Carvalho Chehab 		break;
10069a0bf528SMauro Carvalho Chehab 		case SYS_DVBS2:
10079a0bf528SMauro Carvalho Chehab 			ds3000_writereg(state, 0xfd, 0x01);
10089a0bf528SMauro Carvalho Chehab 			break;
10099a0bf528SMauro Carvalho Chehab 		}
10109a0bf528SMauro Carvalho Chehab 	}
10119a0bf528SMauro Carvalho Chehab 
10129a0bf528SMauro Carvalho Chehab 	/* ds3000 out of software reset */
10139a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0x00, 0x00);
1014868c9a17SMauro Carvalho Chehab 	/* start ds3000 built-in uC */
10159a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0xb2, 0x00);
10169a0bf528SMauro Carvalho Chehab 
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;
10209a0bf528SMauro Carvalho Chehab 		ds3000_set_carrier_offset(fe, offset_khz);
1021c1965eaeSKonstantin Dimitrov 	}
10229a0bf528SMauro Carvalho Chehab 
10239a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 30 ; i++) {
10249a0bf528SMauro Carvalho Chehab 		ds3000_read_status(fe, &status);
10259a0bf528SMauro Carvalho Chehab 		if (status & FE_HAS_LOCK)
10269a0bf528SMauro Carvalho Chehab 			break;
10279a0bf528SMauro Carvalho Chehab 
10289a0bf528SMauro Carvalho Chehab 		msleep(10);
10299a0bf528SMauro Carvalho Chehab 	}
10309a0bf528SMauro Carvalho Chehab 
10319a0bf528SMauro Carvalho Chehab 	return 0;
10329a0bf528SMauro Carvalho Chehab }
10339a0bf528SMauro Carvalho Chehab 
ds3000_tune(struct dvb_frontend * fe,bool re_tune,unsigned int mode_flags,unsigned int * delay,enum fe_status * status)10349a0bf528SMauro Carvalho Chehab static int ds3000_tune(struct dvb_frontend *fe,
10359a0bf528SMauro Carvalho Chehab 			bool re_tune,
10369a0bf528SMauro Carvalho Chehab 			unsigned int mode_flags,
10379a0bf528SMauro Carvalho Chehab 			unsigned int *delay,
10380df289a2SMauro Carvalho Chehab 			enum fe_status *status)
10399a0bf528SMauro Carvalho Chehab {
10409a0bf528SMauro Carvalho Chehab 	if (re_tune) {
10419a0bf528SMauro Carvalho Chehab 		int ret = ds3000_set_frontend(fe);
10429a0bf528SMauro Carvalho Chehab 		if (ret)
10439a0bf528SMauro Carvalho Chehab 			return ret;
10449a0bf528SMauro Carvalho Chehab 	}
10459a0bf528SMauro Carvalho Chehab 
10469a0bf528SMauro Carvalho Chehab 	*delay = HZ / 5;
10479a0bf528SMauro Carvalho Chehab 
10489a0bf528SMauro Carvalho Chehab 	return ds3000_read_status(fe, status);
10499a0bf528SMauro Carvalho Chehab }
10509a0bf528SMauro Carvalho Chehab 
ds3000_get_algo(struct dvb_frontend * fe)10519a0bf528SMauro Carvalho Chehab static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe)
10529a0bf528SMauro Carvalho Chehab {
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 
10589a0bf528SMauro Carvalho Chehab 	dprintk("%s()\n", __func__);
10599a0bf528SMauro Carvalho Chehab 	return DVBFE_ALGO_HW;
10609a0bf528SMauro Carvalho Chehab }
10619a0bf528SMauro Carvalho Chehab 
10629a0bf528SMauro Carvalho Chehab /*
10639a0bf528SMauro Carvalho Chehab  * Initialise or wake up device
10649a0bf528SMauro Carvalho Chehab  *
10659a0bf528SMauro Carvalho Chehab  * Power config will reset and load initial firmware if required
10669a0bf528SMauro Carvalho Chehab  */
ds3000_initfe(struct dvb_frontend * fe)10679a0bf528SMauro Carvalho Chehab static int ds3000_initfe(struct dvb_frontend *fe)
10689a0bf528SMauro Carvalho Chehab {
10699a0bf528SMauro Carvalho Chehab 	struct ds3000_state *state = fe->demodulator_priv;
10709a0bf528SMauro Carvalho Chehab 	int ret;
10719a0bf528SMauro Carvalho Chehab 
10729a0bf528SMauro Carvalho Chehab 	dprintk("%s()\n", __func__);
10739a0bf528SMauro Carvalho Chehab 	/* hard reset */
10749a0bf528SMauro Carvalho Chehab 	ds3000_writereg(state, 0x08, 0x01 | ds3000_readreg(state, 0x08));
10759a0bf528SMauro Carvalho Chehab 	msleep(1);
10769a0bf528SMauro Carvalho Chehab 
10779a0bf528SMauro Carvalho Chehab 	/* Load the firmware if required */
10789a0bf528SMauro Carvalho Chehab 	ret = ds3000_firmware_ondemand(fe);
10799a0bf528SMauro Carvalho Chehab 	if (ret != 0) {
10809a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "%s: Unable initialize firmware\n", __func__);
10819a0bf528SMauro Carvalho Chehab 		return ret;
10829a0bf528SMauro Carvalho Chehab 	}
10839a0bf528SMauro Carvalho Chehab 
10849a0bf528SMauro Carvalho Chehab 	return 0;
10859a0bf528SMauro Carvalho Chehab }
10869a0bf528SMauro Carvalho Chehab 
1087bd336e63SMax Kellermann static const struct dvb_frontend_ops ds3000_ops = {
10889a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_DVBS, SYS_DVBS2 },
10899a0bf528SMauro Carvalho Chehab 	.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,
10959a0bf528SMauro Carvalho Chehab 		.symbol_rate_min = 1000000,
10969a0bf528SMauro Carvalho Chehab 		.symbol_rate_max = 45000000,
10979a0bf528SMauro Carvalho Chehab 		.caps = FE_CAN_INVERSION_AUTO |
10989a0bf528SMauro Carvalho Chehab 			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
10999a0bf528SMauro Carvalho Chehab 			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
11009a0bf528SMauro Carvalho Chehab 			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
11019a0bf528SMauro Carvalho Chehab 			FE_CAN_2G_MODULATION |
11029a0bf528SMauro Carvalho Chehab 			FE_CAN_QPSK | FE_CAN_RECOVER
11039a0bf528SMauro Carvalho Chehab 	},
11049a0bf528SMauro Carvalho Chehab 
11059a0bf528SMauro Carvalho Chehab 	.release = ds3000_release,
11069a0bf528SMauro Carvalho Chehab 
11079a0bf528SMauro Carvalho Chehab 	.init = ds3000_initfe,
1108c1965eaeSKonstantin Dimitrov 	.i2c_gate_ctrl = ds3000_i2c_gate_ctrl,
11099a0bf528SMauro Carvalho Chehab 	.read_status = ds3000_read_status,
11109a0bf528SMauro Carvalho Chehab 	.read_ber = ds3000_read_ber,
1111a0a030bdSMalcolm Priestley 	.read_signal_strength = ds3000_read_signal_strength,
11129a0bf528SMauro Carvalho Chehab 	.read_snr = ds3000_read_snr,
11139a0bf528SMauro Carvalho Chehab 	.read_ucblocks = ds3000_read_ucblocks,
11149a0bf528SMauro Carvalho Chehab 	.set_voltage = ds3000_set_voltage,
11159a0bf528SMauro Carvalho Chehab 	.set_tone = ds3000_set_tone,
11169a0bf528SMauro Carvalho Chehab 	.diseqc_send_master_cmd = ds3000_send_diseqc_msg,
11179a0bf528SMauro Carvalho Chehab 	.diseqc_send_burst = ds3000_diseqc_send_burst,
11189a0bf528SMauro Carvalho Chehab 	.get_frontend_algo = ds3000_get_algo,
11199a0bf528SMauro Carvalho Chehab 
11209a0bf528SMauro Carvalho Chehab 	.set_frontend = ds3000_set_frontend,
11219a0bf528SMauro Carvalho Chehab 	.tune = ds3000_tune,
11229a0bf528SMauro Carvalho Chehab };
11239a0bf528SMauro Carvalho Chehab 
11249a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
11259a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
11269a0bf528SMauro Carvalho Chehab 
11274bd69e7bSMauro Carvalho Chehab MODULE_DESCRIPTION("DVB Frontend module for Montage Technology DS3000 hardware");
1128c1965eaeSKonstantin Dimitrov MODULE_AUTHOR("Konstantin Dimitrov <kosio.dimitrov@gmail.com>");
11299a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
1130feadd7d3SRémi Cardona MODULE_FIRMWARE(DS3000_DEFAULT_FIRMWARE);
1131