/*
Auvitek AU8522 QAM/8VSB demodulator driver
Copyright (C) 2008 Steven Toth <stoth@linuxtv.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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
#include "au8522.h"
struct au8522_state {
struct i2c_adapter *i2c;
/* configuration settings */
const struct au8522_config *config;
struct dvb_frontend frontend;
u32 current_frequency;
fe_modulation_t current_modulation;
u32 fe_status;
unsigned int led_state;
};
static int debug;
#define dprintk(arg...) do { \
if (debug) \
printk(arg); \
} while (0)
/* 16 bit registers, 8 bit values */
static int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
{
int ret;
u8 buf [] = { reg >> 8, reg & 0xff, data };
struct i2c_msg msg = { .addr = state->config->demod_address,
.flags = 0, .buf = buf, .len = 3 };
ret = i2c_transfer(state->i2c, &msg, 1);
if (ret != 1)
printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
"ret == %i)\n", __func__, reg, data, ret);
return (ret != 1) ? -1 : 0;
}
static u8 au8522_readreg(struct au8522_state *state, u16 reg)
{
int ret;
u8 b0 [] = { reg >> 8, reg & 0xff };
u8 b1 [] = { 0 };
struct i2c_msg msg [] = {
{ .addr = state->config->demod_address, .flags = 0,
.buf = b0, .len = 2 },
{ .addr = state->config->demod_address, .flags = I2C_M_RD,
.buf = b1, .len = 1 } };
ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2)
printk(KERN_ERR "%s: readreg error (ret == %i)\n",
__func__, ret);
return b1[0];
}
static int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct au8522_state *state = fe->demodulator_priv;
dprintk("%s(%d)\n", __func__, enable);
if (enable)
return au8522_writereg(state, 0x106, 1);
else
return au8522_writereg(state, 0x106, 0);
}
struct mse2snr_tab {
u16 val;
u16 data;
};
/* VSB SNR lookup table */
static struct mse2snr_tab vsb_mse2snr_tab[] = {
{ 0, 270 },
{ 2, 250 },
{ 3, 240 },
{ 5, 230 },
{ 7, 220 },
{ 9, 210 },
{ 12, 200 },
{ 13, 195 },
{ 15, 190 },
{ 17, 185 },
{ 19, 180 },
{ 21, 175 },
{ 24, 170 },
{ 27, 165 },
{ 31, 160 },
{ 32, 158 },
{ 33, 156 },
{ 36, 152 },
{ 37, 150 },
{ 39, 148 },
{ 40, 146 },
{ 41, 144 },
{ 43, 142 },
{ 44, 140 },
{ 48, 135 },
{ 50, 130 },
{ 43, 142 },
{ 53, 125 },
{ 56, 120 },
{ 256, 115 },
};
/* QAM64 SNR lookup table */
static struct mse2snr_tab qam64_mse2snr_tab[] = {
{ 15, 0 },
{ 16, 290 },
{ 17, 288 },
{ 18, 286 },
{ 19, 284 },
{ 20, 282 },
{ 21, 281 },
{ 22, 279 },
{ 23, 277 },
{ 24, 275 },
{ 25, 273 },
{ 26, 271 },
{ 27, 269 },
{ 28, 268 },
{ 29,