11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
26a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott    Driver for Zarlink VP310/MT312/ZL10313 Satellite Channel Decoder
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
56a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott    Copyright (C) 2008 Matthias Schwarzott <zzam@gentoo.org>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is free software; you can redistribute it and/or modify
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    it under the terms of the GNU General Public License as published by
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    the Free Software Foundation; either version 2 of the License, or
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    (at your option) any later version.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is distributed in the hope that it will be useful,
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    but WITHOUT ANY WARRANTY; without even the implied warranty of
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    GNU General Public License for more details.
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    You should have received a copy of the GNU General Public License
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    along with this program; if not, write to the Free Software
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    References:
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    http://products.zarlink.com/product_profiles/MT312.htm
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    http://products.zarlink.com/product_profiles/SL1935.htm
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
324e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/string.h>
334e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/slab.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "dvb_frontend.h"
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "mt312_priv.h"
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "mt312.h"
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
398393796dfa4cf5dffcceec464c7789bec3a2f471Mauro Carvalho Chehab/* Max transfer size done by I2C transfer functions */
408393796dfa4cf5dffcceec464c7789bec3a2f471Mauro Carvalho Chehab#define MAX_XFER_SIZE  64
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct mt312_state {
4389f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott	struct i2c_adapter *i2c;
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* configuration settings */
4589f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott	const struct mt312_config *config;
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dvb_frontend frontend;
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 id;
49111221fb676176dc90638d6004f1c26164ddd5aeMatthias Schwarzott	unsigned long xtal;
50111221fb676176dc90638d6004f1c26164ddd5aeMatthias Schwarzott	u8 freq_mult;
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int debug;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define dprintk(args...) \
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do { \
5689f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott		if (debug) \
5789f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott			printk(KERN_DEBUG "mt312: " args); \
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (0)
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MT312_PLL_CLK		10000000UL	/* 10 MHz */
616a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott#define MT312_PLL_CLK_10_111	10111000UL	/* 10.111 MHz */
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6389f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
641881ee89e0fe03ac5bba9045acb3bea1818f9466Matthias Schwarzott		      u8 *buf, const size_t count)
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_msg msg[2];
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 regbuf[1] = { reg };
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg[0].addr = state->config->demod_address;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg[0].flags = 0;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg[0].buf = regbuf;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg[0].len = 1;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg[1].addr = state->config->demod_address;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg[1].flags = I2C_M_RD;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg[1].buf = buf;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg[1].len = count;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = i2c_transfer(state->i2c, msg, 2);
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret != 2) {
82302e8acc4137821cd30514da3d91ac109b461c7dMatthias Schwarzott		printk(KERN_DEBUG "%s: ret == %d\n", __func__, ret);
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EREMOTEIO;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8689f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott	if (debug) {
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int i;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk("R(%d):", reg & 0x7f);
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < count; i++)
900389b34e7c5c2dcdef61ed1741db674b47e4dc00Matthias Schwarzott			printk(KERN_CONT " %02x", buf[i]);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("\n");
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9789f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
981881ee89e0fe03ac5bba9045acb3bea1818f9466Matthias Schwarzott		       const u8 *src, const size_t count)
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
1018393796dfa4cf5dffcceec464c7789bec3a2f471Mauro Carvalho Chehab	u8 buf[MAX_XFER_SIZE];
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_msg msg;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1048393796dfa4cf5dffcceec464c7789bec3a2f471Mauro Carvalho Chehab	if (1 + count > sizeof(buf)) {
1058393796dfa4cf5dffcceec464c7789bec3a2f471Mauro Carvalho Chehab		printk(KERN_WARNING
10635f30f36a7e66caa0973a4db620b4245df2cf428Mauro Carvalho Chehab		       "mt312: write: len=%zu is too big!\n", count);
1078393796dfa4cf5dffcceec464c7789bec3a2f471Mauro Carvalho Chehab		return -EINVAL;
1088393796dfa4cf5dffcceec464c7789bec3a2f471Mauro Carvalho Chehab	}
1098393796dfa4cf5dffcceec464c7789bec3a2f471Mauro Carvalho Chehab
11089f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott	if (debug) {
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int i;
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk("W(%d):", reg & 0x7f);
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < count; i++)
1140389b34e7c5c2dcdef61ed1741db674b47e4dc00Matthias Schwarzott			printk(KERN_CONT " %02x", src[i]);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("\n");
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[0] = reg;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(&buf[1], src, count);
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg.addr = state->config->demod_address;
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg.flags = 0;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg.buf = buf;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg.len = count + 1;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = i2c_transfer(state->i2c, &msg, 1);
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret != 1) {
129271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison		dprintk("%s: ret == %d\n", __func__, ret);
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EREMOTEIO;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13689f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic inline int mt312_readreg(struct mt312_state *state,
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				const enum mt312_reg_addr reg, u8 *val)
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return mt312_read(state, reg, val, 1);
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14289f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic inline int mt312_writereg(struct mt312_state *state,
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 const enum mt312_reg_addr reg, const u8 val)
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return mt312_write(state, reg, &val, 1);
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u32 mt312_div(u32 a, u32 b)
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (a + (b / 2)) / b;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15389f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_reset(struct mt312_state *state, const u8 full)
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return mt312_writereg(state, RESET, full ? 0x80 : 0x40);
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15889f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_get_inversion(struct mt312_state *state,
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       fe_spectral_inversion_t *i)
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 vit_mode;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
164994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_readreg(state, VIT_MODE, &vit_mode);
165994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (vit_mode & 0x80)	/* auto inversion was used */
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*i = (vit_mode & 0x40) ? INVERSION_ON : INVERSION_OFF;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17489f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr)
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 sym_rate_h;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 dec_ratio;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 sym_rat_op;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 monitor;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 buf[2];
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
183994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h);
184994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18789f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott	if (sym_rate_h & 0x80) {
18889f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott		/* symbol rate search was used */
189994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott		ret = mt312_writereg(state, MON_CTRL, 0x03);
190994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott		if (ret < 0)
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ret;
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
193994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott		ret = mt312_read(state, MONITOR_H, buf, sizeof(buf));
194994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott		if (ret < 0)
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ret;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		monitor = (buf[0] << 8) | buf[1];
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1990b6a3342a645208feaab76332f1eee33e1688bd5Matthias Schwarzott		dprintk("sr(auto) = %u\n",
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       mt312_div(monitor * 15625, 4));
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
202994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott		ret = mt312_writereg(state, MON_CTRL, 0x05);
203994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott		if (ret < 0)
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ret;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
206994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott		ret = mt312_read(state, MONITOR_H, buf, sizeof(buf));
207994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott		if (ret < 0)
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ret;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dec_ratio = ((buf[0] >> 5) & 0x07) * 32;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
212994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott		ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf));
213994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott		if (ret < 0)
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ret;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sym_rat_op = (buf[0] << 8) | buf[1];
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2180b6a3342a645208feaab76332f1eee33e1688bd5Matthias Schwarzott		dprintk("sym_rat_op=%d dec_ratio=%d\n",
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       sym_rat_op, dec_ratio);
2200b6a3342a645208feaab76332f1eee33e1688bd5Matthias Schwarzott		dprintk("*sr(manual) = %lu\n",
221111221fb676176dc90638d6004f1c26164ddd5aeMatthias Schwarzott		       (((state->xtal * 8192) / (sym_rat_op + 8192)) *
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			2) - dec_ratio);
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22889f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_get_code_rate(struct mt312_state *state, fe_code_rate_t *cr)
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const fe_code_rate_t fec_tab[8] =
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8,
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FEC_AUTO, FEC_AUTO };
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fec_status;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
237994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_readreg(state, FEC_STATUS, &fec_status);
238994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*cr = fec_tab[(fec_status >> 4) & 0x07];
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24689f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_initfe(struct dvb_frontend *fe)
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
248b8742700f13163ffa00cddce2a3c940b9ab2ab5aJohannes Stezenbach	struct mt312_state *state = fe->demodulator_priv;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 buf[2];
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* wake up */
253994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_writereg(state, CONFIG,
254111221fb676176dc90638d6004f1c26164ddd5aeMatthias Schwarzott			(state->freq_mult == 6 ? 0x88 : 0x8c));
255994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* wait at least 150 usec */
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(150);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* full reset */
262994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_reset(state, 1);
263994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26689f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott/* Per datasheet, write correct values. 09/28/03 ACCJr.
26789f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott * If we don't do this, we won't get FE_HAS_VITERBI in the VP310. */
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
26989f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott		u8 buf_def[8] = { 0x14, 0x12, 0x03, 0x02,
27089f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott				  0x01, 0x00, 0x00, 0x00 };
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
272994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott		ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def));
273994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott		if (ret < 0)
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ret;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2776a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	switch (state->id) {
2786a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	case ID_ZL10313:
2796a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		/* enable ADC */
2806a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		ret = mt312_writereg(state, GPP_CTRL, 0x80);
2816a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		if (ret < 0)
2826a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott			return ret;
2836a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott
2846a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		/* configure ZL10313 for optimal ADC performance */
2856a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		buf[0] = 0x80;
2866a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		buf[1] = 0xB0;
2876a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		ret = mt312_write(state, HW_CTRL, buf, 2);
2886a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		if (ret < 0)
2896a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott			return ret;
2906a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott
2916a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		/* enable MPEG output and ADCs */
2926a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		ret = mt312_writereg(state, HW_CTRL, 0x00);
2936a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		if (ret < 0)
2946a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott			return ret;
2956a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott
2966a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		ret = mt312_writereg(state, MPEG_CTRL, 0x00);
2976a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		if (ret < 0)
2986a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott			return ret;
2996a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott
3006a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		break;
3016a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	}
3026a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* SYS_CLK */
304111221fb676176dc90638d6004f1c26164ddd5aeMatthias Schwarzott	buf[0] = mt312_div(state->xtal * state->freq_mult * 2, 1000000);
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* DISEQC_RATIO */
307111221fb676176dc90638d6004f1c26164ddd5aeMatthias Schwarzott	buf[1] = mt312_div(state->xtal, 22000 * 4);
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
309994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_write(state, SYS_CLK, buf, sizeof(buf));
310994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
313994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_writereg(state, SNR_THS_HIGH, 0x32);
314994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3176a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	/* different MOCLK polarity */
3186a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	switch (state->id) {
3196a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	case ID_ZL10313:
3206a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		buf[0] = 0x33;
3216a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		break;
3226a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	default:
3236a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		buf[0] = 0x53;
3246a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		break;
3256a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	}
3266a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott
3276a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	ret = mt312_writereg(state, OP_CTRL, buf[0]);
328994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* TS_SW_LIM */
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[0] = 0x8c;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[1] = 0x98;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
335994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf));
336994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
339994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_writereg(state, CS_SW_LIM, 0x69);
340994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34689f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_send_master_cmd(struct dvb_frontend *fe,
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 struct dvb_diseqc_master_cmd *c)
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
349b8742700f13163ffa00cddce2a3c940b9ab2ab5aJohannes Stezenbach	struct mt312_state *state = fe->demodulator_priv;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 diseqc_mode;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg)))
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
356994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
357994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
360994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len);
361994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
364994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_writereg(state, DISEQC_MODE,
365994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott			     (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3)
366994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott			     | 0x04);
367994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37082cd2dff4a5562a081c8bbf449a1ae7b9ecb5b1bMatthias Schwarzott	/* is there a better way to wait for message to be transmitted */
37182cd2dff4a5562a081c8bbf449a1ae7b9ecb5b1bMatthias Schwarzott	msleep(100);
37282cd2dff4a5562a081c8bbf449a1ae7b9ecb5b1bMatthias Schwarzott
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set DISEQC_MODE[2:0] to zero if a return message is expected */
374994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (c->msg[0] & 0x02) {
375994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott		ret = mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40));
376994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott		if (ret < 0)
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ret;
378994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	}
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38389f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_send_burst(struct dvb_frontend *fe, const fe_sec_mini_cmd_t c)
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
385b8742700f13163ffa00cddce2a3c940b9ab2ab5aJohannes Stezenbach	struct mt312_state *state = fe->demodulator_priv;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const u8 mini_tab[2] = { 0x02, 0x03 };
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 diseqc_mode;
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (c > SEC_MINI_B)
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
394994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
395994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
398994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_writereg(state, DISEQC_MODE,
399994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott			     (diseqc_mode & 0x40) | mini_tab[c]);
400994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40689f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_set_tone(struct dvb_frontend *fe, const fe_sec_tone_mode_t t)
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
408b8742700f13163ffa00cddce2a3c940b9ab2ab5aJohannes Stezenbach	struct mt312_state *state = fe->demodulator_priv;
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const u8 tone_tab[2] = { 0x01, 0x00 };
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 diseqc_mode;
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (t > SEC_TONE_OFF)
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
417994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
418994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_writereg(state, DISEQC_MODE,
422994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott			     (diseqc_mode & 0x40) | tone_tab[t]);
423994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42989f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_set_voltage(struct dvb_frontend *fe, const fe_sec_voltage_t v)
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
431b8742700f13163ffa00cddce2a3c940b9ab2ab5aJohannes Stezenbach	struct mt312_state *state = fe->demodulator_priv;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const u8 volt_tab[3] = { 0x00, 0x40, 0x00 };
43311d3f323930ef625c1018ed13adeb04127c356e0Matthias Schwarzott	u8 val;
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (v > SEC_VOLTAGE_OFF)
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43811d3f323930ef625c1018ed13adeb04127c356e0Matthias Schwarzott	val = volt_tab[v];
43911d3f323930ef625c1018ed13adeb04127c356e0Matthias Schwarzott	if (state->config->voltage_inverted)
44011d3f323930ef625c1018ed13adeb04127c356e0Matthias Schwarzott		val ^= 0x40;
44111d3f323930ef625c1018ed13adeb04127c356e0Matthias Schwarzott
44211d3f323930ef625c1018ed13adeb04127c356e0Matthias Schwarzott	return mt312_writereg(state, DISEQC_MODE, val);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44589f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s)
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
447b8742700f13163ffa00cddce2a3c940b9ab2ab5aJohannes Stezenbach	struct mt312_state *state = fe->demodulator_priv;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 status[3];
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*s = 0;
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
453994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status));
454994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4570b6a3342a645208feaab76332f1eee33e1688bd5Matthias Schwarzott	dprintk("QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x,"
45889f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott		" FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]);
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status[0] & 0xc0)
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*s |= FE_HAS_SIGNAL;	/* signal noise ratio */
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status[0] & 0x04)
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*s |= FE_HAS_CARRIER;	/* qpsk carrier lock */
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status[2] & 0x02)
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*s |= FE_HAS_VITERBI;	/* viterbi lock */
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status[2] & 0x04)
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*s |= FE_HAS_SYNC;	/* byte align lock */
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status[0] & 0x01)
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*s |= FE_HAS_LOCK;	/* qpsk lock */
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47489f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_read_ber(struct dvb_frontend *fe, u32 *ber)
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
476b8742700f13163ffa00cddce2a3c940b9ab2ab5aJohannes Stezenbach	struct mt312_state *state = fe->demodulator_priv;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 buf[3];
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
480994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_read(state, RS_BERCNT_H, buf, 3);
481994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48989f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_read_signal_strength(struct dvb_frontend *fe,
49089f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott				      u16 *signal_strength)
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
492b8742700f13163ffa00cddce2a3c940b9ab2ab5aJohannes Stezenbach	struct mt312_state *state = fe->demodulator_priv;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 buf[3];
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 agc;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s16 err_db;
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
498994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_read(state, AGC_H, buf, sizeof(buf));
499994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	agc = (buf[0] << 6) | (buf[1] >> 2);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err_db = (s16) (((buf[1] & 0x03) << 14) | buf[2] << 6) >> 6;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*signal_strength = agc;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5070b6a3342a645208feaab76332f1eee33e1688bd5Matthias Schwarzott	dprintk("agc=%08x err_db=%hd\n", agc, err_db);
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51289f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_read_snr(struct dvb_frontend *fe, u16 *snr)
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
514b8742700f13163ffa00cddce2a3c940b9ab2ab5aJohannes Stezenbach	struct mt312_state *state = fe->demodulator_priv;
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 buf[2];
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5181881ee89e0fe03ac5bba9045acb3bea1818f9466Matthias Schwarzott	ret = mt312_read(state, M_SNR_H, buf, sizeof(buf));
519994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1);
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
52789f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc)
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
529b8742700f13163ffa00cddce2a3c940b9ab2ab5aJohannes Stezenbach	struct mt312_state *state = fe->demodulator_priv;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 buf[2];
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5331881ee89e0fe03ac5bba9045acb3bea1818f9466Matthias Schwarzott	ret = mt312_read(state, RS_UBC_H, buf, sizeof(buf));
534994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*ubc = (buf[0] << 8) | buf[1];
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
542827b5f3e30296f5ddeedc0c0359b1db77fd499a6Mauro Carvalho Chehabstatic int mt312_set_frontend(struct dvb_frontend *fe)
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
544827b5f3e30296f5ddeedc0c0359b1db77fd499a6Mauro Carvalho Chehab	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
545b8742700f13163ffa00cddce2a3c940b9ab2ab5aJohannes Stezenbach	struct mt312_state *state = fe->demodulator_priv;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 buf[5], config_val;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 sr;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const u8 fec_tab[10] =
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    { 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10, 0x20, 0x3f, 0x3f };
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const u8 inv_tab[3] = { 0x00, 0x40, 0x80 };
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
554271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s: Freq %d\n", __func__, p->frequency);
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
556dea74869f3c62b0b7addd67017b22b394e942aacPatrick Boettcher	if ((p->frequency < fe->ops.info.frequency_min)
557dea74869f3c62b0b7addd67017b22b394e942aacPatrick Boettcher	    || (p->frequency > fe->ops.info.frequency_max))
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
560830e4b55b02b8a2638958e4249eba71797940ee5Mauro Carvalho Chehab	if (((int)p->inversion < INVERSION_OFF)
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    || (p->inversion > INVERSION_ON))
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
564827b5f3e30296f5ddeedc0c0359b1db77fd499a6Mauro Carvalho Chehab	if ((p->symbol_rate < fe->ops.info.symbol_rate_min)
565827b5f3e30296f5ddeedc0c0359b1db77fd499a6Mauro Carvalho Chehab	    || (p->symbol_rate > fe->ops.info.symbol_rate_max))
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
568830e4b55b02b8a2638958e4249eba71797940ee5Mauro Carvalho Chehab	if (((int)p->fec_inner < FEC_NONE)
569827b5f3e30296f5ddeedc0c0359b1db77fd499a6Mauro Carvalho Chehab	    || (p->fec_inner > FEC_AUTO))
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
572827b5f3e30296f5ddeedc0c0359b1db77fd499a6Mauro Carvalho Chehab	if ((p->fec_inner == FEC_4_5)
573827b5f3e30296f5ddeedc0c0359b1db77fd499a6Mauro Carvalho Chehab	    || (p->fec_inner == FEC_8_9))
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (state->id) {
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ID_VP310:
57889f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott	/* For now we will do this only for the VP310.
57989f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott	 * It should be better for the mt312 as well,
58089f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott	 * but tuning will be slower. ACCJr 09/29/03
58189f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott	 */
582682e852e2638ed0aff84aa51181c9e5d2f939562Alexey Dobriyan		ret = mt312_readreg(state, CONFIG, &config_val);
583682e852e2638ed0aff84aa51181c9e5d2f939562Alexey Dobriyan		if (ret < 0)
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ret;
585827b5f3e30296f5ddeedc0c0359b1db77fd499a6Mauro Carvalho Chehab		if (p->symbol_rate >= 30000000) {
58689f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott			/* Note that 30MS/s should use 90MHz */
587111221fb676176dc90638d6004f1c26164ddd5aeMatthias Schwarzott			if (state->freq_mult == 6) {
58889f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott				/* We are running 60MHz */
589111221fb676176dc90638d6004f1c26164ddd5aeMatthias Schwarzott				state->freq_mult = 9;
590994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott				ret = mt312_initfe(fe);
591994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott				if (ret < 0)
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return ret;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
59489f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott		} else {
595111221fb676176dc90638d6004f1c26164ddd5aeMatthias Schwarzott			if (state->freq_mult == 9) {
59689f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott				/* We are running 90MHz */
597111221fb676176dc90638d6004f1c26164ddd5aeMatthias Schwarzott				state->freq_mult = 6;
598994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott				ret = mt312_initfe(fe);
599994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott				if (ret < 0)
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return ret;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ID_MT312:
6066a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	case ID_ZL10313:
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
613dea74869f3c62b0b7addd67017b22b394e942aacPatrick Boettcher	if (fe->ops.tuner_ops.set_params) {
61414d24d148c7521b2b88b396652e36f55d061e195Mauro Carvalho Chehab		fe->ops.tuner_ops.set_params(fe);
61589f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott		if (fe->ops.i2c_gate_ctrl)
61689f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott			fe->ops.i2c_gate_ctrl(fe, 0);
617a81870e00bf502db2c579dcb9721adab3775ba58Andrew de Quincey	}
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* sr = (u16)(sr * 256.0 / 1000000.0) */
620827b5f3e30296f5ddeedc0c0359b1db77fd499a6Mauro Carvalho Chehab	sr = mt312_div(p->symbol_rate * 4, 15625);
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* SYM_RATE */
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[0] = (sr >> 8) & 0x3f;
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[1] = (sr >> 0) & 0xff;
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* VIT_MODE */
627827b5f3e30296f5ddeedc0c0359b1db77fd499a6Mauro Carvalho Chehab	buf[2] = inv_tab[p->inversion] | fec_tab[p->fec_inner];
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* QPSK_CTRL */
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[3] = 0x40;		/* swap I and Q before QPSK demodulation */
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
632827b5f3e30296f5ddeedc0c0359b1db77fd499a6Mauro Carvalho Chehab	if (p->symbol_rate < 10000000)
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[3] |= 0x04;	/* use afc mode */
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* GO */
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[4] = 0x01;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
638994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf));
639994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6429101e6222cb115240e24160bb90cce425bb74de5Mauro Carvalho Chehab	mt312_reset(state, 0);
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6477c61d80a9bcfc3fdec8ffd75756cad6a64678229Mauro Carvalho Chehabstatic int mt312_get_frontend(struct dvb_frontend *fe)
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6497c61d80a9bcfc3fdec8ffd75756cad6a64678229Mauro Carvalho Chehab	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
650b8742700f13163ffa00cddce2a3c940b9ab2ab5aJohannes Stezenbach	struct mt312_state *state = fe->demodulator_priv;
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
653994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_get_inversion(state, &p->inversion);
654994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
657827b5f3e30296f5ddeedc0c0359b1db77fd499a6Mauro Carvalho Chehab	ret = mt312_get_symbol_rate(state, &p->symbol_rate);
658994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661827b5f3e30296f5ddeedc0c0359b1db77fd499a6Mauro Carvalho Chehab	ret = mt312_get_code_rate(state, &p->fec_inner);
662994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
66889f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
669a81870e00bf502db2c579dcb9721adab3775ba58Andrew de Quincey{
67089f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott	struct mt312_state *state = fe->demodulator_priv;
671a81870e00bf502db2c579dcb9721adab3775ba58Andrew de Quincey
6726a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	u8 val = 0x00;
6736a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	int ret;
6746a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott
6756a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	switch (state->id) {
6766a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	case ID_ZL10313:
6776a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		ret = mt312_readreg(state, GPP_CTRL, &val);
6786a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		if (ret < 0)
6796a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott			goto error;
6806a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott
68125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		/* preserve this bit to not accidentally shutdown ADC */
6826a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		val &= 0x80;
6836a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		break;
684a81870e00bf502db2c579dcb9721adab3775ba58Andrew de Quincey	}
6856a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott
6866a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	if (enable)
6876a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		val |= 0x40;
6886a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	else
6896a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		val &= ~0x40;
6906a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott
6916a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	ret = mt312_writereg(state, GPP_CTRL, val);
6926a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott
6936a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzotterror:
6946a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	return ret;
695a81870e00bf502db2c579dcb9721adab3775ba58Andrew de Quincey}
696a81870e00bf502db2c579dcb9721adab3775ba58Andrew de Quincey
69789f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_sleep(struct dvb_frontend *fe)
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
699b8742700f13163ffa00cddce2a3c940b9ab2ab5aJohannes Stezenbach	struct mt312_state *state = fe->demodulator_priv;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 config;
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* reset all registers to defaults */
704994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_reset(state, 1);
705994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7086a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	if (state->id == ID_ZL10313) {
7096a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		/* reset ADC */
7106a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		ret = mt312_writereg(state, GPP_CTRL, 0x00);
7116a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		if (ret < 0)
7126a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott			return ret;
7136a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott
7146a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		/* full shutdown of ADCs, mpeg bus tristated */
7156a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		ret = mt312_writereg(state, HW_CTRL, 0x0d);
7166a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		if (ret < 0)
7176a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott			return ret;
7186a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	}
7196a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott
720994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_readreg(state, CONFIG, &config);
721994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* enter standby */
725994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	ret = mt312_writereg(state, CONFIG, config & 0x7f);
726994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4eMatthias Schwarzott	if (ret < 0)
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
73289f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic int mt312_get_tune_settings(struct dvb_frontend *fe,
73389f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott		struct dvb_frontend_tune_settings *fesettings)
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fesettings->min_delay_ms = 50;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fesettings->step_size = 0;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fesettings->max_drift = 0;
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
74189f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzottstatic void mt312_release(struct dvb_frontend *fe)
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
74389f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott	struct mt312_state *state = fe->demodulator_priv;
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(state);
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
747111221fb676176dc90638d6004f1c26164ddd5aeMatthias Schwarzott#define MT312_SYS_CLK		90000000UL	/* 90 MHz */
748e4671b6bc0b5b488adc5acbcfcbfa6661abec94eMatthias Schwarzottstatic struct dvb_frontend_ops mt312_ops = {
749827b5f3e30296f5ddeedc0c0359b1db77fd499a6Mauro Carvalho Chehab	.delsys = { SYS_DVBS },
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.info = {
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.name = "Zarlink ???? DVB-S",
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.frequency_min = 950000,
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.frequency_max = 2150000,
7540389b34e7c5c2dcdef61ed1741db674b47e4dc00Matthias Schwarzott		/* FIXME: adjust freq to real used xtal */
7550389b34e7c5c2dcdef61ed1741db674b47e4dc00Matthias Schwarzott		.frequency_stepsize = (MT312_PLL_CLK / 1000) / 128,
756111221fb676176dc90638d6004f1c26164ddd5aeMatthias Schwarzott		.symbol_rate_min = MT312_SYS_CLK / 128, /* FIXME as above */
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.symbol_rate_max = MT312_SYS_CLK / 2,
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.caps =
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_MUTE_TS |
7629101e6222cb115240e24160bb90cce425bb74de5Mauro Carvalho Chehab		    FE_CAN_RECOVER
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release = mt312_release,
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.init = mt312_initfe,
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sleep = mt312_sleep,
769a81870e00bf502db2c579dcb9721adab3775ba58Andrew de Quincey	.i2c_gate_ctrl = mt312_i2c_gate_ctrl,
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771827b5f3e30296f5ddeedc0c0359b1db77fd499a6Mauro Carvalho Chehab	.set_frontend = mt312_set_frontend,
772827b5f3e30296f5ddeedc0c0359b1db77fd499a6Mauro Carvalho Chehab	.get_frontend = mt312_get_frontend,
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_tune_settings = mt312_get_tune_settings,
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_status = mt312_read_status,
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_ber = mt312_read_ber,
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_signal_strength = mt312_read_signal_strength,
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_snr = mt312_read_snr,
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_ucblocks = mt312_read_ucblocks,
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.diseqc_send_master_cmd = mt312_send_master_cmd,
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.diseqc_send_burst = mt312_send_burst,
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_tone = mt312_set_tone,
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_voltage = mt312_set_voltage,
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
787e4671b6bc0b5b488adc5acbcfcbfa6661abec94eMatthias Schwarzottstruct dvb_frontend *mt312_attach(const struct mt312_config *config,
78889f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott					struct i2c_adapter *i2c)
789805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk{
79089f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott	struct mt312_state *state = NULL;
791805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk
792805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk	/* allocate memory for the internal state */
793084e24acc906c162c92de7df807190856ae60928Matthias Schwarzott	state = kzalloc(sizeof(struct mt312_state), GFP_KERNEL);
794805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk	if (state == NULL)
795805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk		goto error;
796805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk
797805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk	/* setup the state */
798805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk	state->config = config;
799805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk	state->i2c = i2c;
800805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk
801805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk	/* check if the demod is there */
802805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk	if (mt312_readreg(state, ID, &state->id) < 0)
803805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk		goto error;
804805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk
805dea74869f3c62b0b7addd67017b22b394e942aacPatrick Boettcher	/* create dvb_frontend */
806e4671b6bc0b5b488adc5acbcfcbfa6661abec94eMatthias Schwarzott	memcpy(&state->frontend.ops, &mt312_ops,
80789f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott		sizeof(struct dvb_frontend_ops));
808dea74869f3c62b0b7addd67017b22b394e942aacPatrick Boettcher	state->frontend.demodulator_priv = state;
809dea74869f3c62b0b7addd67017b22b394e942aacPatrick Boettcher
810805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk	switch (state->id) {
811805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk	case ID_VP310:
812dea74869f3c62b0b7addd67017b22b394e942aacPatrick Boettcher		strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S");
813111221fb676176dc90638d6004f1c26164ddd5aeMatthias Schwarzott		state->xtal = MT312_PLL_CLK;
814111221fb676176dc90638d6004f1c26164ddd5aeMatthias Schwarzott		state->freq_mult = 9;
815805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk		break;
816805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk	case ID_MT312:
817dea74869f3c62b0b7addd67017b22b394e942aacPatrick Boettcher		strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S");
818111221fb676176dc90638d6004f1c26164ddd5aeMatthias Schwarzott		state->xtal = MT312_PLL_CLK;
819111221fb676176dc90638d6004f1c26164ddd5aeMatthias Schwarzott		state->freq_mult = 6;
820805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk		break;
8216a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott	case ID_ZL10313:
8226a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		strcpy(state->frontend.ops.info.name, "Zarlink ZL10313 DVB-S");
8236a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		state->xtal = MT312_PLL_CLK_10_111;
8246a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		state->freq_mult = 9;
8256a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		break;
826805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk	default:
8276a5cbd591c703491b62892682adc124ece67f3a9Matthias Schwarzott		printk(KERN_WARNING "Only Zarlink VP310/MT312/ZL10313"
82889f6475857b89e956a8bcfef64944409ce4173b4Matthias Schwarzott			" are supported chips.\n");
829805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk		goto error;
830805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk	}
831805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk
832805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk	return &state->frontend;
833805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk
834805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunkerror:
835805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk	kfree(state);
836805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk	return NULL;
837805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk}
838e4671b6bc0b5b488adc5acbcfcbfa6661abec94eMatthias SchwarzottEXPORT_SYMBOL(mt312_attach);
839805e660ca32ef63b81203a556f29fef262b95cc0Adrian Bunk
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, int, 0644);
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8436a5cbd591c703491b62892682adc124ece67f3a9Matthias SchwarzottMODULE_DESCRIPTION("Zarlink VP310/MT312/ZL10313 DVB-S Demodulator driver");
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
845e4671b6bc0b5b488adc5acbcfcbfa6661abec94eMatthias SchwarzottMODULE_AUTHOR("Matthias Schwarzott <zzam@gentoo.org>");
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
848