/*
Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver
Copyright (C) 2006-2008 Steven Toth <stoth@hauppauge.com>
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.
*/
/*
* Updates by Darron Broad 2007.
*
* March
* Fixed some bugs.
* Added diseqc support.
* Added corrected signal strength support.
*
* August
* Sync with legacy version.
* Some clean ups.
*/
/* Updates by Igor Liplianin
*
* September, 9th 2008
* Fixed locking on high symbol rates (>30000).
*/
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/firmware.h>
#include "dvb_frontend.h"
#include "cx24116.h"
/*
* Fetch firmware in the following manner.
*
* #!/bin/sh
* wget ftp://167.206.143.11/outgoing/Oxford/88x_2_117_24275_1_INF.zip
* unzip 88x_2_117_24275_1_INF.zip
* dd if=Driver88/hcw88bda.sys of=dvb-fe-cx24116.fw skip=81768 bs=1 count=32522
*/
#define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw"
#define CX24116_SEARCH_RANGE_KHZ 5000
/* registers (TO BE COMPLETED) */
#define CX24116_REG_SIGNAL (0xd5)
/* arg buffer size */
#define CX24116_ARGLEN (0x1e)
/* arg offset for DiSEqC */
#define CX24116_DISEQC_BURST (1)
#define CX24116_DISEQC_ARG2_2 (2) /* unknown value=2 */
#define CX24116_DISEQC_ARG3_0 (3) /* unknown value=0 */
#define CX24116_DISEQC_ARG4_0 (4) /* unknown value=0 */
#define CX24116_DISEQC_MSGLEN (5)
#define CX24116_DISEQC_MSGOFS (6)
/* DiSEqC burst */
#define CX24116_DISEQC_MINI_A (0)
#define CX24116_DISEQC_MINI_B (1)
static int debug = 0;
#define dprintk(args...) \
do { \
if (debug) printk ("cx24116: " args); \
} while (0)
enum cmds
{
CMD_INIT_CMD10 = 0x10,
CMD_TUNEREQUEST = 0x11,
CMD_INIT_CMD13 = 0x13,
CMD_INIT_CMD14 = 0x14,
CMD_SEND_DISEQC = 0x21,
CMD_SET_TONEPRE = 0x22,
CMD_SET_TONE = 0x23,
};
/* The Demod/Tuner can't easily provide these, we cache them */
struct cx24116_tuning
{
u32 frequency;
u32 symbol_rate;
fe_spectral_inversion_t inversion;
fe_code_rate_t fec;
fe_modulation_t modulation;
/* Demod values */
u8 fec_val;
u8 fec_mask;
u8 inversion_val;
};
/* Basic commands that are sent to the firmware */
struct cx24116_cmd
{
u8 len;
u8 args[CX24116_ARGLEN];
};
struct cx24116_state
{
struct i2c_adapter* i2c;
const struct cx24116_config* config;
struct dvb_frontend frontend;
struct cx24116_tuning dcur;
struct cx24116_tuning dnxt;
u8 skip_fw_load;
u8 burst;
};
static int cx24116_writereg(struct cx24116_state* state, int reg, int data)
{
u8 buf[] = { reg, data };
struct i2c_msg msg = { .addr = state->config->demod_address,
.flags = 0, .buf = buf, .len = 2 };
int err;
if (debug>1)
printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n",
__func__,reg, data);
if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
printk("%s: writereg error(err == %i, reg == 0x%02x,"
" value == 0x%02x)\n", __func__, err, reg, data);
return -EREMOTEIO;
}
return 0;
}
/* Bulk byte writes to a single I2C address, for 32k firmware load */
static int cx24116_writeregN(struct cx24116_state* state, int reg, u8 *data, u16 len)
{
int ret = -EREMOTEIO;
struct i2c_msg msg;
u8 *buf;
buf = kmalloc(len + 1, GFP_KERNEL);
if (buf == NULL) {
printk("Unable to kmalloc\n");
ret = -ENOMEM;
goto error;
}
*(buf) = reg;
memcpy(buf + 1, data, len);
msg.addr = state->config->demod_address;
msg.flags = 0;
msg.buf = buf;
msg.len = len + 1;
if (debug>1)
printk("cx24116: %s: write regN 0x%02x, len = %d\n",
__func__,reg, len);
if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) {
printk("%s: writereg error(err == %i, reg == 0x%02x\n",
__func__, ret, reg);
ret = -EREMOTEIO;
}
error:
kfree(buf);
return ret;
}
static int cx24116_readreg(struct cx24116_state* state, u8 reg)
{
int ret;
u8 b0[] = { reg };
u8 b1[] = { 0 };
struct i2c_msg msg[] = {
{ .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1