/*
Driver for M88RS2000 demodulator and tuner
Copyright (C) 2012 Malcolm Priestley (tvboxspy@gmail.com)
Beta Driver
Include various calculation code from DS3000 driver.
Copyright (C) 2009 Konstantin Dimitrov.
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/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/jiffies.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/types.h>
#include "dvb_frontend.h"
#include "m88rs2000.h"
struct m88rs2000_state {
struct i2c_adapter *i2c;
const struct m88rs2000_config *config;
struct dvb_frontend frontend;
u8 no_lock_count;
u32 tuner_frequency;
u32 symbol_rate;
fe_code_rate_t fec_inner;
u8 tuner_level;
int errmode;
};
static int m88rs2000_debug;
module_param_named(debug, m88rs2000_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
#define dprintk(level, args...) do { \
if (level & m88rs2000_debug) \
printk(KERN_DEBUG "m88rs2000-fe: " args); \
} while (0)
#define deb_info(args...) dprintk(0x01, args)
#define info(format, arg...) \
printk(KERN_INFO "m88rs2000-fe: " format "\n" , ## arg)
static int m88rs2000_writereg(struct m88rs2000_state *state, u8 tuner,
u8 reg, u8 data)
{
int ret;
u8 addr = (tuner == 0) ? state->config->tuner_addr :
state->config->demod_addr;
u8 buf[] = { reg, data };
struct i2c_msg msg = {
.addr = addr,
.flags = 0,
.buf = buf,
.len = 2
};
ret = i2c_transfer(state->i2c, &msg, 1);
if (ret != 1)
deb_info("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
"ret == %i)\n", __func__, reg, data, ret);
return (ret != 1) ? -EREMOTEIO : 0;
}
static int m88rs2000_demod_write(struct m88rs2000_state *state, u8 reg, u8 data)
{
return m88rs2000_writereg(state, 1, reg, data);
}
static int m88rs2000_tuner_write(struct m88rs2000_state *state, u8 reg, u8 data)
{
m88rs2000_demod_write(state, 0x81, 0x84);
udelay(10);
return m88rs2000_writereg(state, 0, reg, data);
}
static int m88rs2000_write(struct dvb_frontend *fe, const u8 buf[], int len)
{
struct m88rs2000_state *state = fe->demodulator_priv;
if (len != 2)
return -EINVAL;
return m88rs2000_writereg(state, 1, buf[0], buf[1]);
}
static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 tuner, u8 reg)
{
int ret;
u8 b0[] = { reg };
u8 b1[] = { 0 };
u8 addr = (tuner == 0) ? state->config->tuner_addr :
state->config->demod_addr;
struct i2c_msg msg[] = {
{
.addr = addr,
.flags = 0,
.buf = b0,
.len = 1
}, {
.addr = addr,
.flags = I2C_M_RD,
.buf = b1,
.len = 1
}
};
ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2)
deb_info("%s: readreg error (reg == 0x%02x, ret == %i)\n",
__func__, reg, ret);
return b1[0];
}
static u8 m88rs2000_demod_read(struct m88rs2000_state *state, u8 reg)
{
return m88rs2000_readreg(state, 1, reg);
}
static u8 m88rs2000_tuner_read(struct m88rs2000_state *state, u8 reg)
{
m88rs2000_demod_write(state, 0x81, 0x85);
udelay(10);
return m88rs2000_readreg(state, 0, reg);
}
static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate)
{
struct m88rs2000_state *state = fe->demodulator_priv;
int ret;
u32 temp;
u8 b[3];
if ((srate < 1000000) || (srate > 45000000))
return -EINVAL;
temp = srate / 1000;
temp *= 11831;
temp /= 68;
temp -= 3;
b[0] = (u8) (