/*
* Driver for Silicon Labs Si2161 DVB-T and Si2165 DVB-C/-T Demodulator
*
* Copyright (C) 2013-2017 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 <media/dvb_frontend.h>
#include <media/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;
/* DVBv3 stats */
u64 ber_prev;
bool has_dvbc;
bool has_dvbt;
bool firmware_loaded;
};
static int si2165_write(struct si2165_state *state, const u16 reg,
const u8 *src, const int count)
{
int ret;
dev_dbg(&state->client->dev, "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;
}
dev_dbg(