/*
* 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 <linux/regmap.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_client *client;
struct regmap *regmap;
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;
if (debug & DEBUG_I2C_WRITE)
deb_i2c_write("reg: 0x%04x, data: %*ph\n", reg, count, src);
ret = regmap_bulk_write(state->regmap, reg, src, count);
if (ret)
dev_err(&state->client->dev, "%s: ret == %d\n", __func__, ret);
return ret;
}
static int si2165_read(struct si2165_state *state,
const u16 reg, u8 *val, const int count)
{
int ret = regmap_bulk_read(state->regmap, reg, val, count);
if (ret) {
dev_err(&state->client->dev, "%s: error (addr %02x reg %04x error (ret == %i)\n",
__func__, state->config.i2c_addr, reg, ret);
return ret;
}
if (debug & DEBUG_I2C_READ)
deb_i2c_read("reg: 0x%04x, data: %*ph\n", reg, count, val);
return 0;
}
static int si2165_readreg8(struct si2165_state *state,
const u16 reg, u8 *val)
{
unsigned int val_tmp;
int ret = regmap_read(state->regmap, reg, &val_tmp);
*val = (u8)val_tmp;
deb_readreg("R(0x%04x)=0x%02x\n", reg, *val);
return