/*
Driver for Zarlink VP310/MT312/ZL10313 Satellite Channel Decoder
Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
Copyright (C) 2008 Matthias Schwarzott <zzam@gentoo.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
References:
http://products.zarlink.com/product_profiles/MT312.htm
http://products.zarlink.com/product_profiles/SL1935.htm
*/
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/slab.h>
#include "dvb_frontend.h"
#include "mt312_priv.h"
#include "mt312.h"
struct mt312_state {
struct i2c_adapter *i2c;
/* configuration settings */
const struct mt312_config *config;
struct dvb_frontend frontend;
u8 id;
unsigned long xtal;
u8 freq_mult;
};
static int debug;
#define dprintk(args...) \
do { \
if (debug) \
printk(KERN_DEBUG "mt312: " args); \
} while (0)
#define MT312_PLL_CLK 10000000UL /* 10 MHz */
#define MT312_PLL_CLK_10_111 10111000UL /* 10.111 MHz */
static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
u8 *buf, const size_t count)
{
int ret;
struct i2c_msg msg[2];
u8 regbuf[1] = { reg };
msg[0].addr = state->config->demod_address;
msg[0].flags = 0;
msg[0].buf = regbuf;
msg[0].len = 1;
msg[1].addr = state->config->demod_address;
msg[1].flags = I2C_M_RD;
msg[1].buf = buf;
msg[1].len = count;
ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2) {
printk(KERN_DEBUG "%s: ret == %d\n", __func__, ret);
return -EREMOTEIO;
}
if (debug) {
int i;
dprintk("R(%d):", reg & 0x7f);
for (i = 0; i < count; i++)
printk(KERN_CONT " %02x", buf[i]);
printk("\n");
}
return 0;
}
static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
const u8 *src, const size_t count)
{
int ret;
u8 buf[count + 1];
struct i2c_msg msg;
if (debug) {
int i;
dprintk("W(%d):", reg & 0x7f);
for (i = 0; i < count; i++)
printk(KERN_CONT " %02x", src[i]);
printk("\n");
}
buf[0] = reg;
memcpy(&buf[1], src, count);
msg.addr = state->config->demod_address;
msg.flags = 0;
msg.buf = buf;
msg.len = count + 1;
ret = i2c_transfer(state->i2c, &msg, 1);
if (ret != 1) {
dprintk("%s: ret == %d\n", __func__, ret);
return -EREMOTEIO;
}
return 0;
}
static inline int mt312_readreg(struct mt312_state *state,
const enum mt312_reg_addr reg, u8 *val)
{
return mt312_read(state, reg, val, 1);
}
static inline int mt312_writereg(struct mt312_state *state,
const enum mt312_reg_addr reg, const u8 val)
{
return mt312_write(state, reg, &val, 1);
}
static inline u32 mt312_div(u32 a, u32 b)
{
return (a + (b / 2)) / b;
}
static int mt312_reset(struct mt312_state *state, const u8 full)
{
return mt312_writereg(state, RESET, full ? 0x80 : 0x40);
}
static int mt312_get_inversion(struct mt312_state *state,
fe_spectral_inversion_t *i)
{
int ret;
u8 vit_mode;
ret = mt312_readreg(state, VIT_MODE, &vit_mode);
if (ret < 0)
return ret;
if (vit_mode & 0x80) /* auto inversion was used */
*i = (vit_mode & 0x40) ? INVERSION_ON : INVERSION_OFF;
return 0;
}
static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr)
{
int ret;
u8 sym_rate_h;
u8 dec_ratio;
u16 sym_rat_op;
u16 monitor;
u8 buf[2];
ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h);
if (ret < 0)
return ret;
if (sym_rate_h & 0x80) {
/* symbol rate search was used */
ret