/*
* Driver for Silicon Labs Si2161 DVB-T and Si2165 DVB-C/-T Demodulator
*
* Copyright (C) 2013-2014 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.
*
* References:
* http://www.silabs.com/Support%20Documents/TechnicalDocs/Si2165-short.pdf
*/
#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 <linux/firmware.h>
#include "dvb_frontend.h"
#include "dvb_math.h"
#include "si2165_priv.h"
#include "si2165.h"
/*
* Hauppauge WinTV-HVR-930C-HD B130 / PCTV QuatroStick 521e 1113xx
* uses 16 MHz xtal
*
* Hauppauge WinTV-HVR-930C-HD B131 / PCTV QuatroStick 522e 1114xx
* uses 24 MHz clock provided by tuner
*/
struct si2165_state {
struct i2c_adapter *i2c;
struct dvb_frontend fe;
struct si2165_config config;
u8 chip_revcode;
u8 chip_type;
/* calculated by xtal and div settings */
u32 fvco_hz;
u32 sys_clk;
u32 adc_clk;
bool has_dvbc;
bool has_dvbt;
bool firmware_loaded;
};
#define DEBUG_OTHER 0x01
#define DEBUG_I2C_WRITE 0x02
#define DEBUG_I2C_READ 0x04
#define DEBUG_REG_READ 0x08
#define DEBUG_REG_WRITE 0x10
#define DEBUG_FW_LOAD 0x20
static int debug = 0x00;
#define dprintk(args...) \
do { \
if (debug & DEBUG_OTHER) \
printk(KERN_DEBUG "si2165: " args); \
} while (0)
#define deb_i2c_write(args...) \
do { \
if (debug & DEBUG_I2C_WRITE) \
printk(KERN_DEBUG "si2165: i2c write: " args); \
} while (0)
#define deb_i2c_read(args...) \
do { \
if (debug & DEBUG_I2C_READ) \
printk(KERN_DEBUG "si2165: i2c read: " args); \
} while (0)
#define deb_readreg(args...) \
do { \
if (debug & DEBUG_REG_READ) \
printk(KERN_DEBUG "si2165: reg read: " args); \
} while (0)
#define deb_writereg(args...) \
do { \
if (debug & DEBUG_REG_WRITE) \
printk(KERN_DEBUG "si2165: reg write: " args); \
} while (0)
#define deb_fw_load(args...) \
do { \
if (debug & DEBUG_FW_LOAD) \
printk(KERN_DEBUG "si2165: fw load: " args); \
} while (0)
static int si2165_write(struct si2165_state *state, const u16 reg,
const u8 *src, const int count)
{
int ret;
struct i2c_msg msg;
u8 buf[2 + 4]; /* write a maximum of 4 bytes of data */
if (count + 2 > sizeof(buf)) {
dev_warn(&state->i2c->dev,
"%s: i2c wr reg=%04x: count=%d is too big!\n",
KBUILD_MODNAME, reg, count);
return -EINVAL;
}
buf[0] = reg >> 8;
buf[1] = reg & 0xff;
memcpy(buf + 2, src, count);
msg.addr = state->config.i2c_addr;
msg.flags = 0;
msg.buf = buf;
msg.len = count + 2;
if (debug & DEBUG_I2C_WRITE)
deb_i2c_write("reg: 0x%04x, data: %*ph\n", reg, count, src);
ret = i2c_transfer(state->i2c, &msg, 1);
if (ret != 1) {
dev_err(&state->i2c->dev, "%s: ret == %d\n", __func__, ret);
if (ret < 0)
return ret;
else
return -EREMOTEIO;
}
return 0;
}
static int si2165_read(struct si2165_state *state,
const u16 reg, u8 *val, const int count)
{
int ret;
u8 reg_buf[] = { reg >> 8, reg & 0xff };
struct i2c_msg msg[]