/*
* Driver for DiBcom DiB3000MC/P-demodulator.
*
* Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/)
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
*
* This code is partially based on the previous dib3000mc.c .
*
* 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, version 2.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <media/dvb_frontend.h>
#include "dib3000mc.h"
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
static int buggy_sfn_workaround;
module_param(buggy_sfn_workaround, int, 0644);
MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
#define dprintk(fmt, arg...) do { \
if (debug) \
printk(KERN_DEBUG pr_fmt("%s: " fmt), \
__func__, ##arg); \
} while (0)
struct dib3000mc_state {
struct dvb_frontend demod;
struct dib3000mc_config *cfg;
u8 i2c_addr;
struct i2c_adapter *i2c_adap;
struct dibx000_i2c_master i2c_master;
u32 timf;
u32 current_bandwidth;
u16 dev_id;
u8 sfn_workaround_active :1;
};
static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg)
{
struct i2c_msg msg[2] = {
{ .addr = state->i2c_addr >> 1, .flags = 0, .len = 2 },
{ .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .len = 2 },
};
u16 word;
u8 *b;
b = kmalloc(4, GFP_KERNEL);
if (!b)
return 0;
b[0] = (reg >> 8) | 0x80;
b[1] = reg;
b[2] = 0;
b[3] = 0;
msg[0].buf = b;
msg[1].buf = b + 2;
if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
dprintk("i2c read error on %d\n",reg);
word = (b[2] << 8) | b[3];
kfree(b);
return word;
}
static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val)
{
struct i2c_msg msg = {
.addr = state->i2c_addr >> 1, .flags = 0, .len = 4
};
int rc;
u8 *b;
b = kmalloc(4, GFP_KERNEL);
if (!b)
return -ENOMEM;
b[0] = reg >> 8;
b[1] = reg;
b[2] = val >> 8;
b[3] = val;
msg.buf = b;
rc = i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
kfree(b);
return rc;
}
static int dib3000mc_identify(struct dib3000mc_state *state)
{
u16 value;
if ((value = dib3000mc_read_word(state, 1025)) != 0x01b3) {
dprintk("-E- DiB3000MC/P: wrong Vendor ID (read=0x%x)\n",value);
return -EREMOTEIO;
}
value = dib3000mc_read_word(state, 1026);
if (value != 0x3001 && value != 0x3002) {
dprintk("-E- DiB3000MC/P: wrong Device ID (%x)\n",value);
return -EREMOTEIO;
}
state->dev_id = value;
dprintk("-I- found DiB3000MC/P: %x\n",state->dev_id);
return 0;
}
static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset)
{
u32 timf;
if (state->timf == 0) {
timf = 1384402; // default value for 8MHz
if (update_offset)
msleep(200); // first time we do an update
} else
timf = state->timf;
timf *= (bw / 1000);
if (update_offset) {
s16 tim_offs = dib3000mc_read_word(state, 416);
if (