#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <asm/div64.h>
#include "dvb_frontend.h"
-#include "dvb_functions.h"
-#if 0
-#define dprintk(x...) printk(x)
-#else
-#define dprintk(x...)
-#endif
+#define FRONTEND_NAME "dvbfe_stv0299"
+
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
+ } while (0)
+
+static int debug;
+static int stv0299_status;
-static int stv0299_status = 0;
-static int disable_typhoon = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+module_param(stv0299_status, int, 0444);
+MODULE_PARM_DESC(stv0299_status, "Which status value to support "
+ "(0 == BER (default), 1 == UCBLOCKS)");
#define STATUS_BER 0
#define STATUS_UCBLOCKS 1
#define SAMSUNG_TBMU24112IMB 4
#define PHILIPS_SU1278_TSA_TT 5 // SU1278 with TSA5059 synth and TechnoTrend settings
#define PHILIPS_SU1278_TSA_TY 6 // SU1278 with TUA5059 synth and Typhoon wiring
+#define PHILIPS_SU1278_TSA_CI 7 // SU1278 with TUA5059 synth and TerraTec Cinergy wiring
/* Master Clock = 88 MHz */
#define M_CLK (88000000UL)
u32 tuner_frequency;
u32 symbol_rate;
fe_code_rate_t fec_inner;
+ struct i2c_adapter *i2c;
+ struct dvb_adapter *dvb;
};
0x34, 0x13
};
-static int stv0299_set_FEC (struct dvb_i2c_bus *i2c, fe_code_rate_t fec);
-static int stv0299_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate, int tuner_type);
+static int stv0299_set_FEC (struct i2c_adapter *i2c, fe_code_rate_t fec);
+static int stv0299_set_symbolrate (struct i2c_adapter *i2c, u32 srate, int tuner_type);
-static int stv0299_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data)
+static int stv0299_writereg (struct i2c_adapter *i2c, u8 reg, u8 data)
{
int ret;
u8 buf [] = { reg, data };
struct i2c_msg msg = { .addr = 0x68, .flags = 0, .buf = buf, .len = 2 };
- ret = i2c->xfer (i2c, &msg, 1);
+ ret = i2c_transfer (i2c, &msg, 1);
if (ret != 1)
dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
"ret == %i)\n", __FUNCTION__, reg, data, ret);
- return (ret != 1) ? -1 : 0;
+ return (ret != 1) ? -EREMOTEIO : 0;
}
-static u8 stv0299_readreg (struct dvb_i2c_bus *i2c, u8 reg)
+static u8 stv0299_readreg (struct i2c_adapter *i2c, u8 reg)
{
int ret;
u8 b0 [] = { reg };
struct i2c_msg msg [] = { { .addr = 0x68, .flags = 0, .buf = b0, .len = 1 },
{ .addr = 0x68, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
- ret = i2c->xfer (i2c, msg, 2);
+ ret = i2c_transfer (i2c, msg, 2);
if (ret != 2)
dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
}
-static int stv0299_readregs (struct dvb_i2c_bus *i2c, u8 reg1, u8 *b, u8 len)
+static int stv0299_readregs (struct i2c_adapter *i2c, u8 reg1, u8 *b, u8 len)
{
int ret;
struct i2c_msg msg [] = { { .addr = 0x68, .flags = 0, .buf = ®1, .len = 1 },
{ .addr = 0x68, .flags = I2C_M_RD, .buf = b, .len = len } };
- ret = i2c->xfer (i2c, msg, 2);
+ ret = i2c_transfer (i2c, msg, 2);
if (ret != 2)
dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
}
-static int pll_write (struct dvb_i2c_bus *i2c, u8 addr, u8 *data, int len)
+static int pll_write (struct i2c_adapter *i2c, u8 addr, u8 *data, int len)
{
int ret;
struct i2c_msg msg = { .addr = addr, .buf = data, .len = len };
stv0299_writereg(i2c, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
- ret = i2c->xfer (i2c, &msg, 1);
+ ret = i2c_transfer (i2c, &msg, 1);
stv0299_writereg(i2c, 0x05, 0x35); /* disable i2c repeater on stv0299 */
}
-static int sl1935_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype)
+static int sl1935_set_tv_freq (struct i2c_adapter *i2c, u32 freq, int ftype)
{
u8 buf[4];
u32 div;
* set up the downconverter frequency divisor for a
* reference clock comparision frequency of 125 kHz.
*/
-static int tsa5059_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype, int srate)
+static int tsa5059_set_tv_freq (struct i2c_adapter *i2c, u32 freq, int ftype, int srate)
{
u8 addr;
u32 div;
case PHILIPS_SU1278_TSA:
case PHILIPS_SU1278_TSA_TT:
case PHILIPS_SU1278_TSA_TY:
- if (ftype == PHILIPS_SU1278_TSA_TY)
+ case PHILIPS_SU1278_TSA_CI:
+ if (ftype == PHILIPS_SU1278_TSA_TY || ftype == PHILIPS_SU1278_TSA_CI)
addr = 0x61;
else
addr = 0x60;
#define MIN2(a,b) ((a) < (b) ? (a) : (b))
#define MIN3(a,b,c) MIN2(MIN2(a,b),c)
-static int tua6100_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq,
+static int tua6100_set_tv_freq (struct i2c_adapter *i2c, u32 freq,
int ftype, int srate)
{
u8 reg0 [2] = { 0x00, 0x00 };
}
-static int pll_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype, int srate)
+static int pll_set_tv_freq (struct i2c_adapter *i2c, u32 freq, int ftype, int srate)
{
switch(ftype) {
case SAMSUNG_TBMU24112IMB:
}
#if 0
-static int tsa5059_read_status (struct dvb_i2c_bus *i2c)
+static int tsa5059_read_status (struct i2c_adapter *i2c)
{
int ret;
u8 rpt1 [] = { 0x05, 0xb5 };
dprintk ("%s\n", __FUNCTION__);
- ret = i2c->xfer (i2c, msg, 2);
+ ret = i2c_transfer (i2c, msg, 2);
if (ret != 2)
dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
#endif
-static int stv0299_init (struct dvb_i2c_bus *i2c, int ftype)
+static int stv0299_init (struct i2c_adapter *i2c, int ftype)
{
int i;
stv0299_writereg (i2c, init_tab[i], init_tab[i+1]);
/* AGC1 reference register setup */
- if (ftype == PHILIPS_SU1278_TSA || ftype == PHILIPS_SU1278_TSA_TY)
+ if (ftype == PHILIPS_SU1278_TSA || ftype == PHILIPS_SU1278_TSA_TY || ftype == PHILIPS_SU1278_TSA_CI)
stv0299_writereg (i2c, 0x0f, 0x92); /* Iagc = Inverse, m1 = 18 */
else if (ftype == PHILIPS_SU1278_TUA)
stv0299_writereg (i2c, 0x0f, 0x94); /* Iagc = Inverse, m1 = 20 */
}
-static int stv0299_set_FEC (struct dvb_i2c_bus *i2c, fe_code_rate_t fec)
+static int stv0299_set_FEC (struct i2c_adapter *i2c, fe_code_rate_t fec)
{
dprintk ("%s\n", __FUNCTION__);
}
-static fe_code_rate_t stv0299_get_fec (struct dvb_i2c_bus *i2c)
+static fe_code_rate_t stv0299_get_fec (struct i2c_adapter *i2c)
{
static fe_code_rate_t fec_tab [] = { FEC_2_3, FEC_3_4, FEC_5_6,
FEC_7_8, FEC_1_2 };
}
-static int stv0299_wait_diseqc_fifo (struct dvb_i2c_bus *i2c, int timeout)
+static int stv0299_wait_diseqc_fifo (struct i2c_adapter *i2c, int timeout)
{
unsigned long start = jiffies;
dprintk ("%s: timeout!!\n", __FUNCTION__);
return -ETIMEDOUT;
}
- dvb_delay(10);
+ msleep(10);
};
return 0;
}
-static int stv0299_wait_diseqc_idle (struct dvb_i2c_bus *i2c, int timeout)
+static int stv0299_wait_diseqc_idle (struct i2c_adapter *i2c, int timeout)
{
unsigned long start = jiffies;
dprintk ("%s: timeout!!\n", __FUNCTION__);
return -ETIMEDOUT;
}
- dvb_delay(10);
+ msleep(10);
};
return 0;
}
-static int stv0299_send_diseqc_msg (struct dvb_i2c_bus *i2c,
+static int stv0299_send_diseqc_msg (struct i2c_adapter *i2c,
struct dvb_diseqc_master_cmd *m)
{
u8 val;
}
-static int stv0299_send_diseqc_burst (struct dvb_i2c_bus *i2c, fe_sec_mini_cmd_t burst)
+static int stv0299_send_diseqc_burst (struct i2c_adapter *i2c, fe_sec_mini_cmd_t burst)
{
u8 val;
}
-static int stv0299_set_tone (struct dvb_i2c_bus *i2c, fe_sec_tone_mode_t tone)
+static int stv0299_set_tone (struct i2c_adapter *i2c, fe_sec_tone_mode_t tone)
{
u8 val;
}
-static int stv0299_set_voltage (struct dvb_i2c_bus *i2c, fe_sec_voltage_t voltage,
+static int stv0299_set_voltage (struct i2c_adapter *i2c, fe_sec_voltage_t voltage,
int tuner_type)
{
u8 reg0x08;
return stv0299_writereg (i2c, 0x08, 0x00); /* LNB power off! */
}
+ if (tuner_type == PHILIPS_SU1278_TSA_CI)
+ {
+ stv0299_writereg (i2c, 0x08, reg0x08 & 0xBF); // switch LNB power on OP2/LOCK pin off
+ }
+ else
+ {
stv0299_writereg (i2c, 0x08, reg0x08 | 0x40);
+ }
switch (voltage) {
case SEC_VOLTAGE_13:
- if (tuner_type == PHILIPS_SU1278_TSA_TY)
+ if (tuner_type == PHILIPS_SU1278_TSA_TY || tuner_type == PHILIPS_SU1278_TSA_CI)
return stv0299_writereg (i2c, 0x0c, reg0x0c | 0x10);
else
return stv0299_writereg (i2c, 0x0c, reg0x0c | 0x40);
}
-static int stv0299_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate, int tuner_type)
+static int stv0299_set_symbolrate (struct i2c_adapter *i2c, u32 srate, int tuner_type)
{
u64 big = srate;
u32 ratio;
break;
case PHILIPS_SU1278_TSA_TY:
+ case PHILIPS_SU1278_TSA_CI:
case PHILIPS_SU1278_TSA:
aclk = 0xb5;
if (srate < 2000000) bclk = 0x86;
}
-static int stv0299_get_symbolrate (struct dvb_i2c_bus *i2c, int tuner_type)
+static int stv0299_get_symbolrate (struct i2c_adapter *i2c, int tuner_type)
{
u32 Mclk = M_CLK / 4096L;
u32 srate;
static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
{
- struct dvb_i2c_bus *i2c = fe->i2c;
struct stv0299_state *state = (struct stv0299_state *) fe->data;
+ struct i2c_adapter *i2c = state->i2c;
dprintk ("%s\n", __FUNCTION__);
return 0;
}
-static long probe_tuner (struct dvb_i2c_bus *i2c)
+static long probe_tuner (struct i2c_adapter *adapter)
{
- struct dvb_adapter * adapter = (struct dvb_adapter *) i2c->adapter;
+ struct i2c_adapter *i2c = adapter; /* superfluous */
/* read the status register of TSA5059 */
u8 rpt[] = { 0x05, 0xb5 };
stv0299_writereg (i2c, 0x03, 0x00);
- printk ("%s: try to attach to %s\n", __FUNCTION__, adapter->name);
-
- if ( strcmp(adapter->name, "SkyStar2") == 0 )
- {
- printk ("%s: setup for tuner Samsung TBMU24112IMB\n", __FILE__);
+ printk("stv0299: try to attach to %s\n", adapter->name);
+ if (!strcmp(adapter->name, "SkyStar2")) {
+ printk ("stv0299: setup for tuner Samsung TBMU24112IMB\n");
return SAMSUNG_TBMU24112IMB;
}
- if ((ret = i2c->xfer(i2c, msg1, 2)) == 2) {
+ if ((ret = i2c_transfer(i2c, msg1, 2)) == 2) {
if ( strcmp(adapter->name, "TT-Budget/WinTV-NOVA-CI PCI") == 0 ) {
// technotrend cards require non-datasheet settings
- printk ("%s: setup for tuner SU1278 (TSA5059 synth) on"
- " TechnoTrend hardware\n", __FILE__);
+ printk ("stv0299: setup for tuner SU1278 (TSA5059 synth) on TechnoTrend hardware\n");
return PHILIPS_SU1278_TSA_TT;
} else {
// fall back to datasheet-recommended settings
- printk ("%s: setup for tuner SU1278 (TSA5059 synth)\n",
- __FILE__);
+ printk ("stv0299: setup for tuner SU1278 (TSA5059 synth)\n");
return PHILIPS_SU1278_TSA;
}
}
- if ((ret = i2c->xfer(i2c, msg2, 2)) == 2) {
- if ( strcmp(adapter->name, "KNC1 DVB-S") == 0 &&
- !disable_typhoon )
+ if ((ret = i2c_transfer(i2c, msg2, 2)) == 2) {
+ if ( strcmp(adapter->name, "KNC1 DVB-S") == 0 )
{
// Typhoon cards have unusual wiring.
- printk ("%s: setup for tuner SU1278 (TSA5059 synth) on"
- " Typhoon hardware\n", __FILE__);
+ printk ("stv0299: setup for tuner SU1278 (TSA5059 synth) on Typhoon hardware\n");
return PHILIPS_SU1278_TSA_TY;
}
+ else if ( strcmp(adapter->name, "TerraTec Cinergy 1200 DVB-S") == 0 )
+ {
+ // Cinergy cards have unusual wiring.
+ printk ("%s: setup for tuner SU1278 (TSA5059 synth) on"
+ " TerraTec hardware\n", __FILE__);
+ return PHILIPS_SU1278_TSA_CI;
+ }
//else if ((stat[0] & 0x3f) == 0) {
else if (0) {
- printk ("%s: setup for tuner TDQF-S001F\n", __FILE__);
+ printk ("stv0299: setup for tuner TDQF-S001F\n");
return LG_TDQF_S001F;
} else {
- printk ("%s: setup for tuner BSRU6, TDQB-S00x\n",
- __FILE__);
+ printk ("stv0299: setup for tuner BSRU6, TDQB-S00x\n");
return ALPS_BSRU6;
}
}
*/
stv0299_writereg (i2c, 0x02, 0x00);
- if ((ret = i2c->xfer(i2c, msg3, 2)) == 2) {
- printk ("%s: setup for tuner Philips SU1278 (TUA6100 synth)\n",
- __FILE__);
+ if ((ret = i2c_transfer(i2c, msg3, 2)) == 2) {
+ printk ("stv0299: setup for tuner Philips SU1278 (TUA6100 synth)\n");
return PHILIPS_SU1278_TUA;
}
- printk ("%s: unknown PLL synthesizer (ret == %i), "
- "please report to <linuxdvb@linuxtv.org>!!\n",
- __FILE__, ret);
+ printk ("stv0299: unknown PLL synthesizer (ret == %i), please report to <linuxdvb@linuxtv.org>!!\n", ret);
return UNKNOWN_FRONTEND;
}
+static struct i2c_client client_template;
-static int uni0299_attach (struct dvb_i2c_bus *i2c, void **data)
+static int attach_adapter(struct i2c_adapter *adapter)
{
+ struct i2c_client *client;
struct stv0299_state* state;
int tuner_type;
+ int ret;
u8 id;
- stv0299_writereg (i2c, 0x02, 0x34); /* standby off */
- dvb_delay(200);
- id = stv0299_readreg (i2c, 0x00);
+ stv0299_writereg(adapter, 0x02, 0x34); /* standby off */
+ msleep(200);
+ id = stv0299_readreg(adapter, 0x00);
dprintk ("%s: id == 0x%02x\n", __FUNCTION__, id);
if (id != 0xa1 && id != 0x80)
return -ENODEV;
- if ((tuner_type = probe_tuner(i2c)) < 0)
+ if ((tuner_type = probe_tuner(adapter)) < 0)
return -ENODEV;
if ((state = kmalloc(sizeof(struct stv0299_state), GFP_KERNEL)) == NULL) {
return -ENOMEM;
}
- *data = state;
+ if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+ kfree(state);
+ return -ENOMEM;
+ }
+
state->tuner_type = tuner_type;
state->tuner_frequency = 0;
state->initialised = 0;
- return dvb_register_frontend (uni0299_ioctl, i2c, (void *) state,
- &uni0299_info);
+ state->i2c = adapter;
+
+ memcpy(client, &client_template, sizeof(struct i2c_client));
+ client->adapter = adapter;
+ client->addr = (0x68>>1);
+ i2c_set_clientdata(client, (void*)state);
+
+ ret = i2c_attach_client(client);
+ if (ret) {
+ kfree(client);
+ kfree(state);
+ return -EFAULT;
+ }
+
+ BUG_ON(!state->dvb);
+
+ ret = dvb_register_frontend(uni0299_ioctl, state->dvb, state,
+ &uni0299_info, THIS_MODULE);
+ if (ret) {
+ i2c_detach_client(client);
+ kfree(client);
+ kfree(state);
+ return -EFAULT;
}
+ return 0;
+}
+
+static int detach_client(struct i2c_client *client)
+{
+ struct stv0299_state *state = (struct stv0299_state*)i2c_get_clientdata(client);
+
+ dvb_unregister_frontend_new (uni0299_ioctl, state->dvb);
+ i2c_detach_client(client);
+ kfree(client);
+ kfree(state);
+ return 0;
+}
-static void uni0299_detach (struct dvb_i2c_bus *i2c, void *data)
+static int command (struct i2c_client *client, unsigned int cmd, void *arg)
{
+ struct stv0299_state *data = (struct stv0299_state*)i2c_get_clientdata(client);
dprintk ("%s\n", __FUNCTION__);
- kfree(data);
- dvb_unregister_frontend (uni0299_ioctl, i2c);
+
+ switch (cmd) {
+ case FE_REGISTER: {
+ data->dvb = (struct dvb_adapter*)arg;
+ break;
+ }
+ case FE_UNREGISTER: {
+ data->dvb = NULL;
+ break;
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
}
+static struct i2c_driver driver = {
+ .owner = THIS_MODULE,
+ .name = FRONTEND_NAME,
+ .id = I2C_DRIVERID_DVBFE_STV0299,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = attach_adapter,
+ .detach_client = detach_client,
+ .command = command,
+};
+
+static struct i2c_client client_template = {
+ .name = FRONTEND_NAME,
+ .flags = I2C_CLIENT_ALLOW_USE,
+ .driver = &driver,
+};
static int __init init_uni0299 (void)
{
- dprintk ("%s\n", __FUNCTION__);
- return dvb_register_i2c_device (NULL, uni0299_attach, uni0299_detach);
+ return i2c_add_driver(&driver);
}
-
static void __exit exit_uni0299 (void)
{
- dprintk ("%s\n", __FUNCTION__);
-
- dvb_unregister_i2c_device (uni0299_attach);
+ if (i2c_del_driver(&driver))
+ printk("stv0299: driver deregistration failed\n");
}
module_init (init_uni0299);
module_exit (exit_uni0299);
MODULE_DESCRIPTION("Universal STV0299/TSA5059/SL1935 DVB Frontend driver");
-MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, Andreas Oberritter, Andrew de Quincey");
+MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
+ "Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy");
MODULE_LICENSE("GPL");
-MODULE_PARM(stv0299_status, "i");
-MODULE_PARM_DESC(stv0299_status, "Which status value to support (0: BER, 1: UCBLOCKS)");
-
-MODULE_PARM(disable_typhoon, "i");
-MODULE_PARM_DESC(disable_typhoon, "Disable support for Philips SU1278 on Typhoon hardware.");
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
/*
- This driver needs a copy of the DLL "ttlcdacc.dll" from the Haupauge or Technotrend
- windows driver saved as '/usr/lib/hotplug/firmware/tda1004x.bin'.
- You can also pass the complete file name with the module parameter 'tda1004x_firmware'.
-
- Currently the DLL from v2.15a of the technotrend driver is supported. Other versions can
- be added reasonably painlessly.
-
- Windows driver URL: http://www.technotrend.de/
+ * This driver needs external firmware. Please use the commands
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
+ * download/extract them, and then copy them to /usr/lib/hotplug/firmware.
*/
+#define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw"
+#define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw"
-
-#include <linux/kernel.h>
-#include <linux/vmalloc.h>
-#include <linux/module.h>
#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/fcntl.h>
-#include <linux/errno.h>
-#include <linux/syscalls.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
#include "dvb_frontend.h"
-#include "dvb_functions.h"
-
-#ifndef DVB_TDA1004X_FIRMWARE_FILE
-#define DVB_TDA1004X_FIRMWARE_FILE "/usr/lib/hotplug/firmware/tda1004x.bin"
-#endif
-
-static int tda1004x_debug = 0;
-static char *tda1004x_firmware = DVB_TDA1004X_FIRMWARE_FILE;
-
-#define MC44BC374_ADDRESS 0x65
-
-#define TDA1004X_CHIPID 0x00
-#define TDA1004X_AUTO 0x01
-#define TDA1004X_IN_CONF1 0x02
-#define TDA1004X_IN_CONF2 0x03
-#define TDA1004X_OUT_CONF1 0x04
-#define TDA1004X_OUT_CONF2 0x05
-#define TDA1004X_STATUS_CD 0x06
-#define TDA1004X_CONFC4 0x07
-#define TDA1004X_DSSPARE2 0x0C
-#define TDA10045H_CODE_IN 0x0D
-#define TDA10045H_FWPAGE 0x0E
-#define TDA1004X_SCAN_CPT 0x10
-#define TDA1004X_DSP_CMD 0x11
-#define TDA1004X_DSP_ARG 0x12
-#define TDA1004X_DSP_DATA1 0x13
-#define TDA1004X_DSP_DATA2 0x14
-#define TDA1004X_CONFADC1 0x15
-#define TDA1004X_CONFC1 0x16
-#define TDA10045H_S_AGC 0x1a
-#define TDA10046H_AGC_TUN_LEVEL 0x1a
-#define TDA1004X_SNR 0x1c
-#define TDA1004X_CONF_TS1 0x1e
-#define TDA1004X_CONF_TS2 0x1f
-#define TDA1004X_CBER_RESET 0x20
-#define TDA1004X_CBER_MSB 0x21
-#define TDA1004X_CBER_LSB 0x22
-#define TDA1004X_CVBER_LUT 0x23
-#define TDA1004X_VBER_MSB 0x24
-#define TDA1004X_VBER_MID 0x25
-#define TDA1004X_VBER_LSB 0x26
-#define TDA1004X_UNCOR 0x27
-
-#define TDA10045H_CONFPLL_P 0x2D
-#define TDA10045H_CONFPLL_M_MSB 0x2E
-#define TDA10045H_CONFPLL_M_LSB 0x2F
-#define TDA10045H_CONFPLL_N 0x30
-
-#define TDA10046H_CONFPLL1 0x2D
-#define TDA10046H_CONFPLL2 0x2F
-#define TDA10046H_CONFPLL3 0x30
-#define TDA10046H_TIME_WREF1 0x31
-#define TDA10046H_TIME_WREF2 0x32
-#define TDA10046H_TIME_WREF3 0x33
-#define TDA10046H_TIME_WREF4 0x34
-#define TDA10046H_TIME_WREF5 0x35
-
-#define TDA10045H_UNSURW_MSB 0x31
-#define TDA10045H_UNSURW_LSB 0x32
-#define TDA10045H_WREF_MSB 0x33
-#define TDA10045H_WREF_MID 0x34
-#define TDA10045H_WREF_LSB 0x35
-#define TDA10045H_MUXOUT 0x36
-#define TDA1004X_CONFADC2 0x37
-
-#define TDA10045H_IOFFSET 0x38
+
+#define FRONTEND_NAME "dvbfe_tda1004x"
+
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
+ } while (0)
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+#define MC44BC374_ADDRESS 0x65
+
+#define TDA1004X_CHIPID 0x00
+#define TDA1004X_AUTO 0x01
+#define TDA1004X_IN_CONF1 0x02
+#define TDA1004X_IN_CONF2 0x03
+#define TDA1004X_OUT_CONF1 0x04
+#define TDA1004X_OUT_CONF2 0x05
+#define TDA1004X_STATUS_CD 0x06
+#define TDA1004X_CONFC4 0x07
+#define TDA1004X_DSSPARE2 0x0C
+#define TDA10045H_CODE_IN 0x0D
+#define TDA10045H_FWPAGE 0x0E
+#define TDA1004X_SCAN_CPT 0x10
+#define TDA1004X_DSP_CMD 0x11
+#define TDA1004X_DSP_ARG 0x12
+#define TDA1004X_DSP_DATA1 0x13
+#define TDA1004X_DSP_DATA2 0x14
+#define TDA1004X_CONFADC1 0x15
+#define TDA1004X_CONFC1 0x16
+#define TDA10045H_S_AGC 0x1a
+#define TDA10046H_AGC_TUN_LEVEL 0x1a
+#define TDA1004X_SNR 0x1c
+#define TDA1004X_CONF_TS1 0x1e
+#define TDA1004X_CONF_TS2 0x1f
+#define TDA1004X_CBER_RESET 0x20
+#define TDA1004X_CBER_MSB 0x21
+#define TDA1004X_CBER_LSB 0x22
+#define TDA1004X_CVBER_LUT 0x23
+#define TDA1004X_VBER_MSB 0x24
+#define TDA1004X_VBER_MID 0x25
+#define TDA1004X_VBER_LSB 0x26
+#define TDA1004X_UNCOR 0x27
+
+#define TDA10045H_CONFPLL_P 0x2D
+#define TDA10045H_CONFPLL_M_MSB 0x2E
+#define TDA10045H_CONFPLL_M_LSB 0x2F
+#define TDA10045H_CONFPLL_N 0x30
+
+#define TDA10046H_CONFPLL1 0x2D
+#define TDA10046H_CONFPLL2 0x2F
+#define TDA10046H_CONFPLL3 0x30
+#define TDA10046H_TIME_WREF1 0x31
+#define TDA10046H_TIME_WREF2 0x32
+#define TDA10046H_TIME_WREF3 0x33
+#define TDA10046H_TIME_WREF4 0x34
+#define TDA10046H_TIME_WREF5 0x35
+
+#define TDA10045H_UNSURW_MSB 0x31
+#define TDA10045H_UNSURW_LSB 0x32
+#define TDA10045H_WREF_MSB 0x33
+#define TDA10045H_WREF_MID 0x34
+#define TDA10045H_WREF_LSB 0x35
+#define TDA10045H_MUXOUT 0x36
+#define TDA1004X_CONFADC2 0x37
+
+#define TDA10045H_IOFFSET 0x38
#define TDA10046H_CONF_TRISTATE1 0x3B
#define TDA10046H_CONF_TRISTATE2 0x3C
-#define TDA10046H_CONF_POLARITY 0x3D
-#define TDA10046H_FREQ_OFFSET 0x3E
-#define TDA10046H_GPIO_OUT_SEL 0x41
-#define TDA10046H_GPIO_SELECT 0x42
-#define TDA10046H_AGC_CONF 0x43
-#define TDA10046H_AGC_GAINS 0x46
-#define TDA10046H_AGC_TUN_MIN 0x47
-#define TDA10046H_AGC_TUN_MAX 0x48
-#define TDA10046H_AGC_IF_MIN 0x49
-#define TDA10046H_AGC_IF_MAX 0x4A
-
-#define TDA10046H_FREQ_PHY2_MSB 0x4D
-#define TDA10046H_FREQ_PHY2_LSB 0x4E
-
-#define TDA10046H_CVBER_CTRL 0x4F
-#define TDA10046H_AGC_IF_LEVEL 0x52
-#define TDA10046H_CODE_CPT 0x57
-#define TDA10046H_CODE_IN 0x58
+#define TDA10046H_CONF_POLARITY 0x3D
+#define TDA10046H_FREQ_OFFSET 0x3E
+#define TDA10046H_GPIO_OUT_SEL 0x41
+#define TDA10046H_GPIO_SELECT 0x42
+#define TDA10046H_AGC_CONF 0x43
+#define TDA10046H_AGC_GAINS 0x46
+#define TDA10046H_AGC_TUN_MIN 0x47
+#define TDA10046H_AGC_TUN_MAX 0x48
+#define TDA10046H_AGC_IF_MIN 0x49
+#define TDA10046H_AGC_IF_MAX 0x4A
+
+#define TDA10046H_FREQ_PHY2_MSB 0x4D
+#define TDA10046H_FREQ_PHY2_LSB 0x4E
+
+#define TDA10046H_CVBER_CTRL 0x4F
+#define TDA10046H_AGC_IF_LEVEL 0x52
+#define TDA10046H_CODE_CPT 0x57
+#define TDA10046H_CODE_IN 0x58
#define FE_TYPE_TDA10045H 0
#define TUNER_TYPE_TD1344 0
#define TUNER_TYPE_TD1316 1
-#define dprintk if (tda1004x_debug) printk
-
static struct dvb_frontend_info tda10045h_info = {
.name = "Philips TDA10045H",
.type = FE_OFDM,
};
static struct dvb_frontend_info tda10046h_info = {
- .name = "Philips TDA10046H",
- .type = FE_OFDM,
- .frequency_min = 51000000,
- .frequency_max = 858000000,
- .frequency_stepsize = 166667,
- .caps =
- FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
+ .name = "Philips TDA10046H",
+ .type = FE_OFDM,
+ .frequency_min = 51000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 166667,
+ .caps =
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
};
-
struct tda1004x_state {
u8 tda1004x_address;
u8 tuner_address;
- u8 initialised:1;
- u8 tuner_type:2;
- u8 fe_type:2;
-};
-
-
-struct fwinfo {
- int file_size;
- int fw_offset;
- int fw_size;
+ u8 initialised;
+ u8 tuner_type;
+ u8 fe_type;
+ struct i2c_adapter *i2c;
+ struct dvb_adapter *dvb;
+
+ int dspCodeCounterReg;
+ int dspCodeInReg;
+ int dspVersion;
};
-static struct fwinfo tda10045h_fwinfo[] = { {.file_size = 286720,.fw_offset = 0x34cc5,.fw_size = 30555} };
-static int tda10045h_fwinfo_count = sizeof(tda10045h_fwinfo) / sizeof(struct fwinfo);
-
-static struct fwinfo tda10046h_fwinfo[] = { {.file_size = 286720,.fw_offset = 0x3c4f9,.fw_size = 24479} };
-static int tda10046h_fwinfo_count = sizeof(tda10046h_fwinfo) / sizeof(struct fwinfo);
-
-static int tda1004x_write_byte(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg, int data)
+static int tda1004x_write_byte(struct i2c_adapter *i2c, struct tda1004x_state *tda_state, int reg, int data)
{
int ret;
u8 buf[] = { reg, data };
dprintk("%s: reg=0x%x, data=0x%x\n", __FUNCTION__, reg, data);
- msg.addr = tda_state->tda1004x_address;
- ret = i2c->xfer(i2c, &msg, 1);
+ msg.addr = tda_state->tda1004x_address;
+ ret = i2c_transfer(i2c, &msg, 1);
if (ret != 1)
dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
- __FUNCTION__, reg, data, ret);
+ __FUNCTION__, reg, data, ret);
dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __FUNCTION__,
reg, data, ret);
return (ret != 1) ? -1 : 0;
}
-static int tda1004x_read_byte(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg)
+static int tda1004x_read_byte(struct i2c_adapter *i2c, struct tda1004x_state *tda_state, int reg)
{
int ret;
u8 b0[] = { reg };
u8 b1[] = { 0 };
struct i2c_msg msg[] = {{ .addr=0, .flags=0, .buf=b0, .len=1},
- { .addr=0, .flags=I2C_M_RD, .buf=b1, .len = 1}};
+ { .addr=0, .flags=I2C_M_RD, .buf=b1, .len = 1}};
dprintk("%s: reg=0x%x\n", __FUNCTION__, reg);
- msg[0].addr = tda_state->tda1004x_address;
- msg[1].addr = tda_state->tda1004x_address;
- ret = i2c->xfer(i2c, msg, 2);
+ msg[0].addr = tda_state->tda1004x_address;
+ msg[1].addr = tda_state->tda1004x_address;
+ ret = i2c_transfer(i2c, msg, 2);
if (ret != 2) {
dprintk("%s: error reg=0x%x, ret=%i\n", __FUNCTION__, reg,
- ret);
+ ret);
return -1;
}
return b1[0];
}
-static int tda1004x_write_mask(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg, int mask, int data)
+static int tda1004x_write_mask(struct i2c_adapter *i2c, struct tda1004x_state *tda_state, int reg, int mask, int data)
{
- int val;
+ int val;
dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __FUNCTION__, reg,
mask, data);
return tda1004x_write_byte(i2c, tda_state, reg, val);
}
-static int tda1004x_write_buf(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg, unsigned char *buf, int len)
+static int tda1004x_write_buf(struct i2c_adapter *i2c, struct tda1004x_state *tda_state, int reg, unsigned char *buf, int len)
{
int i;
int result;
return result;
}
-static int tda1004x_enable_tuner_i2c(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state)
+static int tda1004x_enable_tuner_i2c(struct i2c_adapter *i2c, struct tda1004x_state *tda_state)
{
- int result;
+ int result;
dprintk("%s\n", __FUNCTION__);
result = tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 2, 2);
- dvb_delay(1);
+ msleep(1);
return result;
}
-static int tda1004x_disable_tuner_i2c(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state)
+static int tda1004x_disable_tuner_i2c(struct i2c_adapter *i2c, struct tda1004x_state *tda_state)
{
-
dprintk("%s\n", __FUNCTION__);
return tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 2, 0);
}
-
-static int tda10045h_set_bandwidth(struct dvb_i2c_bus *i2c,
- struct tda1004x_state *tda_state,
- fe_bandwidth_t bandwidth)
+static int tda10045h_set_bandwidth(struct i2c_adapter *i2c,
+ struct tda1004x_state *tda_state,
+ fe_bandwidth_t bandwidth)
{
- static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f };
- static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb };
- static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 };
+ static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f };
+ static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb };
+ static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 };
- switch (bandwidth) {
+ switch (bandwidth) {
case BANDWIDTH_6_MHZ:
tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x14);
- tda1004x_write_buf(i2c, tda_state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz));
+ tda1004x_write_buf(i2c, tda_state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz));
break;
case BANDWIDTH_7_MHZ:
tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x80);
- tda1004x_write_buf(i2c, tda_state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz));
+ tda1004x_write_buf(i2c, tda_state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz));
break;
case BANDWIDTH_8_MHZ:
tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x14);
- tda1004x_write_buf(i2c, tda_state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz));
+ tda1004x_write_buf(i2c, tda_state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz));
break;
default:
return -EINVAL;
}
- tda1004x_write_byte(i2c, tda_state, TDA10045H_IOFFSET, 0);
+ tda1004x_write_byte(i2c, tda_state, TDA10045H_IOFFSET, 0);
- // done
- return 0;
+ return 0;
}
-
-static int tda10046h_set_bandwidth(struct dvb_i2c_bus *i2c,
- struct tda1004x_state *tda_state,
- fe_bandwidth_t bandwidth)
+static int tda10046h_set_bandwidth(struct i2c_adapter *i2c,
+ struct tda1004x_state *tda_state,
+ fe_bandwidth_t bandwidth)
{
- static u8 bandwidth_6mhz[] = { 0x80, 0x15, 0xfe, 0xab, 0x8e };
- static u8 bandwidth_7mhz[] = { 0x6e, 0x02, 0x53, 0xc8, 0x25 };
- static u8 bandwidth_8mhz[] = { 0x60, 0x12, 0xa8, 0xe4, 0xbd };
-
- switch (bandwidth) {
- case BANDWIDTH_6_MHZ:
- tda1004x_write_buf(i2c, tda_state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz));
- tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0);
- break;
-
- case BANDWIDTH_7_MHZ:
- tda1004x_write_buf(i2c, tda_state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz));
- tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0);
- break;
-
- case BANDWIDTH_8_MHZ:
- tda1004x_write_buf(i2c, tda_state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz));
- tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0xFF);
- break;
-
- default:
- return -EINVAL;
- }
-
- // done
- return 0;
-}
+ static u8 bandwidth_6mhz[] = { 0x80, 0x15, 0xfe, 0xab, 0x8e };
+ static u8 bandwidth_7mhz[] = { 0x6e, 0x02, 0x53, 0xc8, 0x25 };
+ static u8 bandwidth_8mhz[] = { 0x60, 0x12, 0xa8, 0xe4, 0xbd };
+
+ switch (bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ tda1004x_write_buf(i2c, tda_state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz));
+ tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0);
+ break;
+
+ case BANDWIDTH_7_MHZ:
+ tda1004x_write_buf(i2c, tda_state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz));
+ tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0);
+ break;
+ case BANDWIDTH_8_MHZ:
+ tda1004x_write_buf(i2c, tda_state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz));
+ tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0xFF);
+ break;
-static int tda1004x_fwupload(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state)
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int tda1004x_do_upload(struct i2c_adapter *i2c, struct tda1004x_state *state, unsigned char *mem, unsigned int len)
{
- u8 fw_buf[65];
- struct i2c_msg fw_msg = {.addr = 0,.flags = 0,.buf = fw_buf,.len = 0 };
- unsigned char *firmware = NULL;
- int filesize;
- int fd;
- int fwinfo_idx;
- int fw_size = 0;
- int fw_pos, fw_offset;
+ u8 buf[65];
+ struct i2c_msg fw_msg = {.addr = 0,.flags = 0,.buf = buf,.len = 0 };
int tx_size;
- mm_segment_t fs = get_fs();
- int dspCodeCounterReg=0, dspCodeInReg=0, dspVersion=0;
- int fwInfoCount=0;
- struct fwinfo* fwInfo = NULL;
- unsigned long timeout;
-
- // DSP parameters
- switch(tda_state->fe_type) {
- case FE_TYPE_TDA10045H:
- dspCodeCounterReg = TDA10045H_FWPAGE;
- dspCodeInReg = TDA10045H_CODE_IN;
- dspVersion = 0x2c;
- fwInfoCount = tda10045h_fwinfo_count;
- fwInfo = tda10045h_fwinfo;
- break;
-
- case FE_TYPE_TDA10046H:
- dspCodeCounterReg = TDA10046H_CODE_CPT;
- dspCodeInReg = TDA10046H_CODE_IN;
- dspVersion = 0x20;
- fwInfoCount = tda10046h_fwinfo_count;
- fwInfo = tda10046h_fwinfo;
- break;
- }
-
- // Load the firmware
- set_fs(get_ds());
- fd = sys_open(tda1004x_firmware, 0, 0);
- if (fd < 0) {
- printk("%s: Unable to open firmware %s\n", __FUNCTION__,
- tda1004x_firmware);
- return -EIO;
- }
- filesize = sys_lseek(fd, 0L, 2);
- if (filesize <= 0) {
- printk("%s: Firmware %s is empty\n", __FUNCTION__,
- tda1004x_firmware);
- sys_close(fd);
- return -EIO;
- }
+ int pos = 0;
- // find extraction parameters for firmware
- for (fwinfo_idx = 0; fwinfo_idx < fwInfoCount; fwinfo_idx++) {
- if (fwInfo[fwinfo_idx].file_size == filesize)
- break;
- }
- if (fwinfo_idx >= fwInfoCount) {
- printk("%s: Unsupported firmware %s\n", __FUNCTION__, tda1004x_firmware);
- sys_close(fd);
- return -EIO;
- }
- fw_size = fwInfo[fwinfo_idx].fw_size;
- fw_offset = fwInfo[fwinfo_idx].fw_offset;
-
- // allocate buffer for it
- firmware = vmalloc(fw_size);
- if (firmware == NULL) {
- printk("%s: Out of memory loading firmware\n",
- __FUNCTION__);
- sys_close(fd);
- return -EIO;
- }
+ /* clear code counter */
+ tda1004x_write_byte(i2c, state, state->dspCodeCounterReg, 0);
+ fw_msg.addr = state->tda1004x_address;
- // read it!
- sys_lseek(fd, fw_offset, 0);
- if (sys_read(fd, firmware, fw_size) != fw_size) {
- printk("%s: Failed to read firmware\n", __FUNCTION__);
- vfree(firmware);
- sys_close(fd);
- return -EIO;
- }
- sys_close(fd);
- set_fs(fs);
-
- // set some valid bandwith parameters before uploading
- switch(tda_state->fe_type) {
- case FE_TYPE_TDA10045H:
- // reset chip
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 0x10, 0);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 8);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 0);
- dvb_delay(10);
-
- // set parameters
- tda10045h_set_bandwidth(i2c, tda_state, BANDWIDTH_8_MHZ);
- break;
-
- case FE_TYPE_TDA10046H:
- // reset chip
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 1, 0);
- tda1004x_write_mask(i2c, tda_state, TDA10046H_CONF_TRISTATE1, 1, 0);
- dvb_delay(10);
-
- // set parameters
- tda1004x_write_byte(i2c, tda_state, TDA10046H_CONFPLL2, 10);
- tda1004x_write_byte(i2c, tda_state, TDA10046H_CONFPLL3, 0);
- tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_OFFSET, 99);
- tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
- tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
- break;
- }
-
- // do the firmware upload
- tda1004x_write_byte(i2c, tda_state, dspCodeCounterReg, 0); // clear code counter
- fw_msg.addr = tda_state->tda1004x_address;
- fw_pos = 0;
- while (fw_pos != fw_size) {
+ buf[0] = state->dspCodeInReg;
+ while (pos != len) {
// work out how much to send this time
- tx_size = fw_size - fw_pos;
- if (tx_size > 0x10) {
- tx_size = 0x10;
+ tx_size = len - pos;
+ if (tx_size > 0x10) {
+ tx_size = 0x10;
}
// send the chunk
- fw_buf[0] = dspCodeInReg;
- memcpy(fw_buf + 1, firmware + fw_pos, tx_size);
+ memcpy(buf + 1, mem + pos, tx_size);
fw_msg.len = tx_size + 1;
- if (i2c->xfer(i2c, &fw_msg, 1) != 1) {
- printk("tda1004x: Error during firmware upload\n");
- vfree(firmware);
+ if (i2c_transfer(i2c, &fw_msg, 1) != 1) {
+ printk("tda1004x: Error during firmware upload\n");
return -EIO;
}
- fw_pos += tx_size;
+ pos += tx_size;
- dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, fw_pos);
+ dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, pos);
}
- vfree(firmware);
-
- // wait for DSP to initialise
- switch(tda_state->fe_type) {
- case FE_TYPE_TDA10045H:
- // DSPREADY doesn't seem to work on the TDA10045H
- dvb_delay(100);
- break;
-
- case FE_TYPE_TDA10046H:
- timeout = jiffies + HZ;
- while(!(tda1004x_read_byte(i2c, tda_state, TDA1004X_STATUS_CD) & 0x20)) {
- if (time_after(jiffies, timeout)) {
- printk("tda1004x: DSP failed to initialised.\n");
- return -EIO;
- }
-
- dvb_delay(1);
- }
- break;
- }
-
- // check upload was OK
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP
- tda1004x_write_byte(i2c, tda_state, TDA1004X_DSP_CMD, 0x67);
- if ((tda1004x_read_byte(i2c, tda_state, TDA1004X_DSP_DATA1) != 0x67) ||
- (tda1004x_read_byte(i2c, tda_state, TDA1004X_DSP_DATA2) != dspVersion)) {
- printk("%s: firmware upload failed!\n", __FUNCTION__);
+ return 0;
+}
+
+static int tda1004x_check_upload_ok(struct i2c_adapter *i2c, struct tda1004x_state *state)
+{
+ u8 data1, data2;
+
+ // check upload was OK
+ tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP
+ tda1004x_write_byte(i2c, state, TDA1004X_DSP_CMD, 0x67);
+
+ data1 = tda1004x_read_byte(i2c, state, TDA1004X_DSP_DATA1);
+ data2 = tda1004x_read_byte(i2c, state, TDA1004X_DSP_DATA2);
+ if (data1 != 0x67 || data2 != state->dspVersion) {
+ printk("tda1004x: firmware upload failed!\n");
return -EIO;
}
- // success
- return 0;
+ return 0;
}
-static int tda10045h_init(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state)
+static int tda10045_fwupload(struct i2c_adapter *i2c, struct tda1004x_state *state, struct i2c_client *client)
{
- struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = NULL,.len = 0 };
- static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
+ int ret;
+ const struct firmware *fw;
+
+ /* request the firmware, this will block until someone uploads it */
+ printk("tda1004x: waiting for firmware upload...\n");
+ ret = request_firmware(&fw, TDA10045_DEFAULT_FIRMWARE, &client->dev);
+ if (ret) {
+ printk("tda1004x: no firmware upload (timeout or file not found?)\n");
+ return ret;
+ }
- dprintk("%s\n", __FUNCTION__);
+ /* set some valid bandwith parameters before uploading */
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
+ /* reset chip */
+ tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 0x10, 0);
+ tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 8, 8);
+ tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 8, 0);
+ msleep(10);
- // Disable the MC44BC374C
- tda1004x_enable_tuner_i2c(i2c, tda_state);
- tuner_msg.addr = MC44BC374_ADDRESS;
- tuner_msg.buf = disable_mc44BC374c;
- tuner_msg.len = sizeof(disable_mc44BC374c);
- if (i2c->xfer(i2c, &tuner_msg, 1) != 1) {
- i2c->xfer(i2c, &tuner_msg, 1);
- }
- tda1004x_disable_tuner_i2c(i2c, tda_state);
+ /* set parameters */
+ tda10045h_set_bandwidth(i2c, state, BANDWIDTH_8_MHZ);
+
+ ret = tda1004x_do_upload(i2c, state, fw->data, fw->size);
+ if (ret)
+ return ret;
+
+ /* wait for DSP to initialise */
+ /* DSPREADY doesn't seem to work on the TDA10045H */
+ msleep(100);
+
+ ret = tda1004x_check_upload_ok(i2c, state);
+ if (ret)
+ return ret;
- // tda setup
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 8, 0); // select HP stream
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x40, 0); // no frequency inversion
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x80, 0x80); // enable pulse killer
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x10, 0x10); // enable auto offset
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0xC0, 0x0); // no frequency offset
- tda1004x_write_byte(i2c, tda_state, TDA1004X_CONF_TS1, 0); // setup MPEG2 TS interface
- tda1004x_write_byte(i2c, tda_state, TDA1004X_CONF_TS2, 0); // setup MPEG2 TS interface
- tda1004x_write_mask(i2c, tda_state, TDA1004X_VBER_MSB, 0xe0, 0xa0); // 10^6 VBER measurement bits
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x10, 0); // VAGC polarity
- tda1004x_write_byte(i2c, tda_state, TDA1004X_CONFADC1, 0x2e);
-
- // done
return 0;
}
+static int tda10046_fwupload(struct i2c_adapter *i2c, struct tda1004x_state *state, struct i2c_client *client)
+{
+ unsigned long timeout;
+ int ret;
+ const struct firmware *fw;
+
+ /* request the firmware, this will block until someone uploads it */
+ printk("tda1004x: waiting for firmware upload...\n");
+ ret = request_firmware(&fw, TDA10046_DEFAULT_FIRMWARE, &client->dev);
+ if (ret) {
+ printk("tda1004x: no firmware upload (timeout or file not found?)\n");
+ return ret;
+ }
+
+ /* set some valid bandwith parameters before uploading */
+
+ /* reset chip */
+ tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 1, 0);
+ tda1004x_write_mask(i2c, state, TDA10046H_CONF_TRISTATE1, 1, 0);
+ msleep(10);
+
+ /* set parameters */
+ tda1004x_write_byte(i2c, state, TDA10046H_CONFPLL2, 10);
+ tda1004x_write_byte(i2c, state, TDA10046H_CONFPLL3, 0);
+ tda1004x_write_byte(i2c, state, TDA10046H_FREQ_OFFSET, 99);
+ tda1004x_write_byte(i2c, state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
+ tda1004x_write_byte(i2c, state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
+ tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
+
+ ret = tda1004x_do_upload(i2c, state, fw->data, fw->size);
+ if (ret)
+ return ret;
+
+ /* wait for DSP to initialise */
+ timeout = jiffies + HZ;
+ while(!(tda1004x_read_byte(i2c, state, TDA1004X_STATUS_CD) & 0x20)) {
+ if (time_after(jiffies, timeout)) {
+ printk("tda1004x: DSP failed to initialised.\n");
+ return -EIO;
+ }
+ msleep(1);
+ }
+
+ ret = tda1004x_check_upload_ok(i2c, state);
+ if (ret)
+ return ret;
+ return 0;
+}
-static int tda10046h_init(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state)
+static int tda10045h_init(struct i2c_adapter *i2c, struct tda1004x_state *tda_state)
{
- struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = NULL,.len = 0 };
- static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
+ struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = NULL,.len = 0 };
+ static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
- dprintk("%s\n", __FUNCTION__);
+ dprintk("%s\n", __FUNCTION__);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 1, 0); // wake up the chip
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
- // Disable the MC44BC374C
- tda1004x_enable_tuner_i2c(i2c, tda_state);
- tuner_msg.addr = MC44BC374_ADDRESS;
- tuner_msg.buf = disable_mc44BC374c;
- tuner_msg.len = sizeof(disable_mc44BC374c);
- if (i2c->xfer(i2c, &tuner_msg, 1) != 1) {
- i2c->xfer(i2c, &tuner_msg, 1);
- }
- tda1004x_disable_tuner_i2c(i2c, tda_state);
-
- // tda setup
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x40, 0x40); // TT TDA10046H needs inversion ON
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 8, 0); // select HP stream
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x80, 0); // disable pulse killer
- tda1004x_write_byte(i2c, tda_state, TDA10046H_CONFPLL2, 10); // PLL M = 10
- tda1004x_write_byte(i2c, tda_state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
- tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_OFFSET, 99); // FREQOFFS = 99
- tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_PHY2_MSB, 0xd4); // } PHY2 = -11221
- tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_PHY2_LSB, 0x2c); // }
- tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_CONF, 0); // AGC setup
- tda1004x_write_mask(i2c, tda_state, TDA10046H_CONF_POLARITY, 0x60, 0x60); // set AGC polarities
- tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_TUN_MIN, 0); // }
- tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
- tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_IF_MIN, 0); // }
- tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_IF_MAX, 0xff); // }
- tda1004x_write_mask(i2c, tda_state, TDA10046H_CVBER_CTRL, 0x30, 0x10); // 10^6 VBER measurement bits
- tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x80, 0); // crystal is 50ppm
- tda1004x_write_byte(i2c, tda_state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONF_TS2, 0x31, 0); // MPEG2 interface config
- tda1004x_write_mask(i2c, tda_state, TDA10046H_CONF_TRISTATE1, 0x9e, 0); // disable AGC_TUN
- tda1004x_write_byte(i2c, tda_state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup
- tda1004x_write_byte(i2c, tda_state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config
- tda1004x_write_mask(i2c, tda_state, TDA10046H_GPIO_SELECT, 8, 8); // GPIO select
- tda10046h_set_bandwidth(i2c, tda_state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
-
- // done
- return 0;
+ // Disable the MC44BC374C
+ tda1004x_enable_tuner_i2c(i2c, tda_state);
+ tuner_msg.addr = MC44BC374_ADDRESS;
+ tuner_msg.buf = disable_mc44BC374c;
+ tuner_msg.len = sizeof(disable_mc44BC374c);
+ if (i2c_transfer(i2c, &tuner_msg, 1) != 1) {
+ i2c_transfer(i2c, &tuner_msg, 1);
+ }
+ tda1004x_disable_tuner_i2c(i2c, tda_state);
+
+ // tda setup
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 8, 0); // select HP stream
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x40, 0); // no frequency inversion
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x80, 0x80); // enable pulse killer
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x10, 0x10); // enable auto offset
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0xC0, 0x0); // no frequency offset
+ tda1004x_write_byte(i2c, tda_state, TDA1004X_CONF_TS1, 0); // setup MPEG2 TS interface
+ tda1004x_write_byte(i2c, tda_state, TDA1004X_CONF_TS2, 0); // setup MPEG2 TS interface
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_VBER_MSB, 0xe0, 0xa0); // 10^6 VBER measurement bits
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x10, 0); // VAGC polarity
+ tda1004x_write_byte(i2c, tda_state, TDA1004X_CONFADC1, 0x2e);
+
+ return 0;
}
+static int tda10046h_init(struct i2c_adapter *i2c, struct tda1004x_state *tda_state)
+{
+ struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = NULL,.len = 0 };
+ static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
+ dprintk("%s\n", __FUNCTION__);
+
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 1, 0); // wake up the chip
+
+ // Disable the MC44BC374C
+ tda1004x_enable_tuner_i2c(i2c, tda_state);
+ tuner_msg.addr = MC44BC374_ADDRESS;
+ tuner_msg.buf = disable_mc44BC374c;
+ tuner_msg.len = sizeof(disable_mc44BC374c);
+ if (i2c_transfer(i2c, &tuner_msg, 1) != 1) {
+ i2c_transfer(i2c, &tuner_msg, 1);
+ }
+ tda1004x_disable_tuner_i2c(i2c, tda_state);
+
+ // tda setup
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x40, 0x40); // TT TDA10046H needs inversion ON
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 8, 0); // select HP stream
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x80, 0); // disable pulse killer
+ tda1004x_write_byte(i2c, tda_state, TDA10046H_CONFPLL2, 10); // PLL M = 10
+ tda1004x_write_byte(i2c, tda_state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
+ tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_OFFSET, 99); // FREQOFFS = 99
+ tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_PHY2_MSB, 0xd4); // } PHY2 = -11221
+ tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_PHY2_LSB, 0x2c); // }
+ tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_CONF, 0); // AGC setup
+ tda1004x_write_mask(i2c, tda_state, TDA10046H_CONF_POLARITY, 0x60, 0x60); // set AGC polarities
+ tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_TUN_MIN, 0); // }
+ tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
+ tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_IF_MIN, 0); // }
+ tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_IF_MAX, 0xff); // }
+ tda1004x_write_mask(i2c, tda_state, TDA10046H_CVBER_CTRL, 0x30, 0x10); // 10^6 VBER measurement bits
+ tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x80, 0); // crystal is 50ppm
+ tda1004x_write_byte(i2c, tda_state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONF_TS2, 0x31, 0); // MPEG2 interface config
+ tda1004x_write_mask(i2c, tda_state, TDA10046H_CONF_TRISTATE1, 0x9e, 0); // disable AGC_TUN
+ tda1004x_write_byte(i2c, tda_state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup
+ tda1004x_write_byte(i2c, tda_state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config
+ tda1004x_write_mask(i2c, tda_state, TDA10046H_GPIO_SELECT, 8, 8); // GPIO select
+ tda10046h_set_bandwidth(i2c, tda_state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
+
+ return 0;
+}
static int tda1004x_encode_fec(int fec)
{
return -1;
}
-static int tda1004x_set_frequency(struct dvb_i2c_bus *i2c,
- struct tda1004x_state *tda_state,
- struct dvb_frontend_parameters *fe_params)
+static int tda1004x_set_frequency(struct i2c_adapter *i2c,
+ struct tda1004x_state *tda_state,
+ struct dvb_frontend_parameters *fe_params)
{
u8 tuner_buf[4];
struct i2c_msg tuner_msg = {.addr=0, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) };
- int tuner_frequency = 0;
- u8 band, cp, filter;
+ int tuner_frequency = 0;
+ u8 band, cp, filter;
int counter, counter2;
dprintk("%s\n", __FUNCTION__);
// setup the frequency buffer
- switch (tda_state->tuner_type) {
- case TUNER_TYPE_TD1344:
+ switch (tda_state->tuner_type) {
+ case TUNER_TYPE_TD1344:
// setup tuner buffer
- // ((Fif+((1000000/6)/2)) + Finput)/(1000000/6)
+ // ((Fif+((1000000/6)/2)) + Finput)/(1000000/6)
tuner_frequency =
- (((fe_params->frequency / 1000) * 6) + 217502) / 1000;
+ (((fe_params->frequency / 1000) * 6) + 217502) / 1000;
tuner_buf[0] = tuner_frequency >> 8;
tuner_buf[1] = tuner_frequency & 0xff;
tuner_buf[2] = 0x88;
tda1004x_enable_tuner_i2c(i2c, tda_state);
tuner_msg.addr = tda_state->tuner_address;
tuner_msg.len = 4;
- i2c->xfer(i2c, &tuner_msg, 1);
+ i2c_transfer(i2c, &tuner_msg, 1);
// wait for it to finish
tuner_msg.len = 1;
counter = 0;
counter2 = 0;
while (counter++ < 100) {
- if (i2c->xfer(i2c, &tuner_msg, 1) == 1) {
+ if (i2c_transfer(i2c, &tuner_msg, 1) == 1) {
if (tuner_buf[0] & 0x40) {
counter2++;
} else {
tda1004x_disable_tuner_i2c(i2c, tda_state);
break;
- case TUNER_TYPE_TD1316:
+ case TUNER_TYPE_TD1316:
// determine charge pump
tuner_frequency = fe_params->frequency + 36130000;
if (tuner_frequency < 87000000) {
return -EINVAL;
} else if (tuner_frequency < 130000000) {
- cp = 3;
+ cp = 3;
} else if (tuner_frequency < 160000000) {
cp = 5;
} else if (tuner_frequency < 200000000) {
// determine band
if (fe_params->frequency < 49000000) {
- return -EINVAL;
+ return -EINVAL;
} else if (fe_params->frequency < 159000000) {
- band = 1;
+ band = 1;
} else if (fe_params->frequency < 444000000) {
band = 2;
} else if (fe_params->frequency < 861000000) {
// work out filter
switch (fe_params->u.ofdm.bandwidth) {
case BANDWIDTH_6_MHZ:
- filter = 0;
- break;
+ filter = 0;
+ break;
- case BANDWIDTH_7_MHZ:
+ case BANDWIDTH_7_MHZ:
filter = 0;
break;
return -EINVAL;
}
- // calculate divisor
- // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
+ // calculate divisor
+ // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
tuner_frequency =
- (((fe_params->frequency / 1000) * 6) + 217280) / 1000;
+ (((fe_params->frequency / 1000) * 6) + 217280) / 1000;
- // setup tuner buffer
+ // setup tuner buffer
tuner_buf[0] = tuner_frequency >> 8;
tuner_buf[1] = tuner_frequency & 0xff;
tuner_buf[2] = 0xca;
tuner_buf[3] = (cp << 5) | (filter << 3) | band;
// tune it
- if (tda_state->fe_type == FE_TYPE_TDA10046H) {
- // setup auto offset
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x10, 0x10);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x80, 0);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0xC0, 0);
-
- // disable agc_conf[2]
- tda1004x_write_mask(i2c, tda_state, TDA10046H_AGC_CONF, 4, 0);
- }
+ if (tda_state->fe_type == FE_TYPE_TDA10046H) {
+ // setup auto offset
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x10, 0x10);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x80, 0);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0xC0, 0);
+
+ // disable agc_conf[2]
+ tda1004x_write_mask(i2c, tda_state, TDA10046H_AGC_CONF, 4, 0);
+ }
tda1004x_enable_tuner_i2c(i2c, tda_state);
tuner_msg.addr = tda_state->tuner_address;
tuner_msg.len = 4;
- if (i2c->xfer(i2c, &tuner_msg, 1) != 1) {
+ if (i2c_transfer(i2c, &tuner_msg, 1) != 1) {
return -EIO;
}
- dvb_delay(1);
+ msleep(1);
tda1004x_disable_tuner_i2c(i2c, tda_state);
- if (tda_state->fe_type == FE_TYPE_TDA10046H)
- tda1004x_write_mask(i2c, tda_state, TDA10046H_AGC_CONF, 4, 4);
+ if (tda_state->fe_type == FE_TYPE_TDA10046H)
+ tda1004x_write_mask(i2c, tda_state, TDA10046H_AGC_CONF, 4, 4);
break;
default:
dprintk("%s: success\n", __FUNCTION__);
- // done
return 0;
}
-static int tda1004x_set_fe(struct dvb_i2c_bus *i2c,
- struct tda1004x_state *tda_state,
- struct dvb_frontend_parameters *fe_params)
+static int tda1004x_set_fe(struct i2c_adapter *i2c,
+ struct tda1004x_state *tda_state,
+ struct dvb_frontend_parameters *fe_params)
{
int tmp;
- int inversion;
+ int inversion;
dprintk("%s\n", __FUNCTION__);
// set frequency
- if ((tmp = tda1004x_set_frequency(i2c, tda_state, fe_params)) < 0)
+ if ((tmp = tda1004x_set_frequency(i2c, tda_state, fe_params)) < 0)
return tmp;
- // hardcoded to use auto as much as possible
- fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
- fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
- fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
+ // Hardcoded to use auto as much as possible
+ // The TDA10045 is very unreliable if AUTO mode is _not_ used. I have not
+ // yet tested the TDA10046 to see if this issue has been fixed
+ fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
+ fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
+ fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
// Set standard params.. or put them to auto
if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) ||
tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 7, tmp);
// set LP FEC
- if (fe_params->u.ofdm.code_rate_LP != FEC_NONE) {
- tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP);
- if (tmp < 0) return tmp;
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0x38, tmp << 3);
- }
+ tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP);
+ if (tmp < 0) return tmp;
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0x38, tmp << 3);
// set constellation
switch (fe_params->u.ofdm.constellation) {
}
}
- // set bandwidth
- switch(tda_state->fe_type) {
- case FE_TYPE_TDA10045H:
- tda10045h_set_bandwidth(i2c, tda_state, fe_params->u.ofdm.bandwidth);
- break;
+ // set bandwidth
+ switch(tda_state->fe_type) {
+ case FE_TYPE_TDA10045H:
+ tda10045h_set_bandwidth(i2c, tda_state, fe_params->u.ofdm.bandwidth);
+ break;
- case FE_TYPE_TDA10046H:
- tda10046h_set_bandwidth(i2c, tda_state, fe_params->u.ofdm.bandwidth);
- break;
- }
+ case FE_TYPE_TDA10046H:
+ tda10046h_set_bandwidth(i2c, tda_state, fe_params->u.ofdm.bandwidth);
+ break;
+ }
- // need to invert the inversion for TT TDA10046H
- inversion = fe_params->inversion;
- if (tda_state->fe_type == FE_TYPE_TDA10046H) {
- inversion = inversion ? INVERSION_OFF : INVERSION_ON;
- }
+ // need to invert the inversion for TT TDA10046H
+ inversion = fe_params->inversion;
+ if (tda_state->fe_type == FE_TYPE_TDA10046H) {
+ inversion = inversion ? INVERSION_OFF : INVERSION_ON;
+ }
// set inversion
- switch (inversion) {
+ switch (inversion) {
case INVERSION_OFF:
tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x20, 0);
break;
return -EINVAL;
}
- // start the lock
- switch(tda_state->fe_type) {
- case FE_TYPE_TDA10045H:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 8);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 0);
- dvb_delay(10);
- break;
-
- case FE_TYPE_TDA10046H:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x40, 0x40);
- dvb_delay(10);
- break;
- }
-
- // done
+ // start the lock
+ switch(tda_state->fe_type) {
+ case FE_TYPE_TDA10045H:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 8);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 0);
+ msleep(10);
+ break;
+
+ case FE_TYPE_TDA10046H:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x40, 0x40);
+ msleep(10);
+ break;
+ }
+
return 0;
}
-
-static int tda1004x_get_fe(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, struct dvb_frontend_parameters *fe_params)
+static int tda1004x_get_fe(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, struct dvb_frontend_parameters *fe_params)
{
-
dprintk("%s\n", __FUNCTION__);
// inversion status
fe_params->inversion = INVERSION_ON;
}
- // need to invert the inversion for TT TDA10046H
- if (tda_state->fe_type == FE_TYPE_TDA10046H) {
- fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON;
- }
+ // need to invert the inversion for TT TDA10046H
+ if (tda_state->fe_type == FE_TYPE_TDA10046H) {
+ fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON;
+ }
// bandwidth
- switch(tda_state->fe_type) {
- case FE_TYPE_TDA10045H:
- switch (tda1004x_read_byte(i2c, tda_state, TDA10045H_WREF_LSB)) {
- case 0x14:
- fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
- break;
- case 0xdb:
- fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+ switch(tda_state->fe_type) {
+ case FE_TYPE_TDA10045H:
+ switch (tda1004x_read_byte(i2c, tda_state, TDA10045H_WREF_LSB)) {
+ case 0x14:
+ fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+ break;
+ case 0xdb:
+ fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+ break;
+ case 0x4f:
+ fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+ break;
+ }
break;
- case 0x4f:
- fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+
+ case FE_TYPE_TDA10046H:
+ switch (tda1004x_read_byte(i2c, tda_state, TDA10046H_TIME_WREF1)) {
+ case 0x60:
+ fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+ break;
+ case 0x6e:
+ fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+ break;
+ case 0x80:
+ fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+ break;
+ }
break;
}
- break;
-
- case FE_TYPE_TDA10046H:
- switch (tda1004x_read_byte(i2c, tda_state, TDA10046H_TIME_WREF1)) {
- case 0x60:
- fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
- break;
- case 0x6e:
- fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
- break;
- case 0x80:
- fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
- break;
- }
- break;
- }
// FEC
fe_params->u.ofdm.code_rate_HP =
break;
}
- // done
return 0;
}
-
-static int tda1004x_read_status(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, fe_status_t * fe_status)
+static int tda1004x_read_status(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, fe_status_t * fe_status)
{
int status;
- int cber;
- int vber;
+ int cber;
+ int vber;
dprintk("%s\n", __FUNCTION__);
return -EIO;
}
- // decode
+ // decode
*fe_status = 0;
- if (status & 4) *fe_status |= FE_HAS_SIGNAL;
- if (status & 2) *fe_status |= FE_HAS_CARRIER;
- if (status & 8) *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
-
- // if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi
- // is getting anything valid
- if (!(*fe_status & FE_HAS_VITERBI)) {
- // read the CBER
- cber = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_LSB);
- if (cber == -1) return -EIO;
- status = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_MSB);
- if (status == -1) return -EIO;
- cber |= (status << 8);
- tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_RESET);
-
- if (cber != 65535) {
- *fe_status |= FE_HAS_VITERBI;
- }
- }
-
- // if we DO have some valid VITERBI output, but don't already have SYNC
- // bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid.
- if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) {
- // read the VBER
- vber = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_LSB);
- if (vber == -1) return -EIO;
- status = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_MID);
- if (status == -1) return -EIO;
- vber |= (status << 8);
- status = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_MSB);
- if (status == -1) return -EIO;
- vber |= ((status << 16) & 0x0f);
- tda1004x_read_byte(i2c, tda_state, TDA1004X_CVBER_LUT);
-
- // if RS has passed some valid TS packets, then we must be
- // getting some SYNC bytes
- if (vber < 16632) {
- *fe_status |= FE_HAS_SYNC;
- }
- }
+ if (status & 4) *fe_status |= FE_HAS_SIGNAL;
+ if (status & 2) *fe_status |= FE_HAS_CARRIER;
+ if (status & 8) *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+
+ // if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi
+ // is getting anything valid
+ if (!(*fe_status & FE_HAS_VITERBI)) {
+ // read the CBER
+ cber = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_LSB);
+ if (cber == -1) return -EIO;
+ status = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_MSB);
+ if (status == -1) return -EIO;
+ cber |= (status << 8);
+ tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_RESET);
+
+ if (cber != 65535) {
+ *fe_status |= FE_HAS_VITERBI;
+ }
+ }
+
+ // if we DO have some valid VITERBI output, but don't already have SYNC
+ // bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid.
+ if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) {
+ // read the VBER
+ vber = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_LSB);
+ if (vber == -1) return -EIO;
+ status = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_MID);
+ if (status == -1) return -EIO;
+ vber |= (status << 8);
+ status = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_MSB);
+ if (status == -1) return -EIO;
+ vber |= ((status << 16) & 0x0f);
+ tda1004x_read_byte(i2c, tda_state, TDA1004X_CVBER_LUT);
+
+ // if RS has passed some valid TS packets, then we must be
+ // getting some SYNC bytes
+ if (vber < 16632) {
+ *fe_status |= FE_HAS_SYNC;
+ }
+ }
// success
dprintk("%s: fe_status=0x%x\n", __FUNCTION__, *fe_status);
return 0;
}
-static int tda1004x_read_signal_strength(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u16 * signal)
+static int tda1004x_read_signal_strength(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, u16 * signal)
{
int tmp;
- int reg = 0;
+ int reg = 0;
dprintk("%s\n", __FUNCTION__);
- // determine the register to use
- switch(tda_state->fe_type) {
- case FE_TYPE_TDA10045H:
- reg = TDA10045H_S_AGC;
- break;
+ // determine the register to use
+ switch(tda_state->fe_type) {
+ case FE_TYPE_TDA10045H:
+ reg = TDA10045H_S_AGC;
+ break;
- case FE_TYPE_TDA10046H:
- reg = TDA10046H_AGC_IF_LEVEL;
- break;
- }
+ case FE_TYPE_TDA10046H:
+ reg = TDA10046H_AGC_IF_LEVEL;
+ break;
+ }
// read it
- tmp = tda1004x_read_byte(i2c, tda_state, reg);
+ tmp = tda1004x_read_byte(i2c, tda_state, reg);
if (tmp < 0)
return -EIO;
- // done
*signal = (tmp << 8) | tmp;
dprintk("%s: signal=0x%x\n", __FUNCTION__, *signal);
return 0;
}
-
-static int tda1004x_read_snr(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u16 * snr)
+static int tda1004x_read_snr(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, u16 * snr)
{
int tmp;
tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_SNR);
if (tmp < 0)
return -EIO;
- if (tmp) {
- tmp = 255 - tmp;
- }
+ if (tmp) {
+ tmp = 255 - tmp;
+ }
- // done
*snr = ((tmp << 8) | tmp);
dprintk("%s: snr=0x%x\n", __FUNCTION__, *snr);
return 0;
}
-static int tda1004x_read_ucblocks(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u32* ucblocks)
+static int tda1004x_read_ucblocks(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, u32* ucblocks)
{
int tmp;
int tmp2;
tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_UNCOR);
if (tmp < 0)
return -EIO;
- tmp &= 0x7f;
+ tmp &= 0x7f;
while (counter++ < 5) {
tda1004x_write_mask(i2c, tda_state, TDA1004X_UNCOR, 0x80, 0);
tda1004x_write_mask(i2c, tda_state, TDA1004X_UNCOR, 0x80, 0);
break;
}
- // done
if (tmp != 0x7f) {
*ucblocks = tmp;
} else {
return 0;
}
-static int tda1004x_read_ber(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u32* ber)
+static int tda1004x_read_ber(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, u32* ber)
{
- int tmp;
+ int tmp;
dprintk("%s\n", __FUNCTION__);
// read it in
- tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_LSB);
- if (tmp < 0) return -EIO;
- *ber = tmp << 1;
- tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_MSB);
- if (tmp < 0) return -EIO;
- *ber |= (tmp << 9);
- tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_RESET);
-
- // done
+ tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_LSB);
+ if (tmp < 0) return -EIO;
+ *ber = tmp << 1;
+ tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_MSB);
+ if (tmp < 0) return -EIO;
+ *ber |= (tmp << 9);
+ tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_RESET);
+
dprintk("%s: ber=0x%x\n", __FUNCTION__, *ber);
return 0;
}
-static int tda1004x_sleep(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state)
+static int tda1004x_sleep(struct i2c_adapter *i2c, struct tda1004x_state* tda_state)
{
switch(tda_state->fe_type) {
case FE_TYPE_TDA10045H:
return 0;
}
-
static int tda1004x_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
{
- int status = 0;
- struct dvb_i2c_bus *i2c = fe->i2c;
struct tda1004x_state *tda_state = (struct tda1004x_state *) fe->data;
+ struct i2c_adapter *i2c = tda_state->i2c;
+ int status = 0;
dprintk("%s: cmd=0x%x\n", __FUNCTION__, cmd);
switch (cmd) {
case FE_GET_INFO:
- switch(tda_state->fe_type) {
- case FE_TYPE_TDA10045H:
- memcpy(arg, &tda10045h_info, sizeof(struct dvb_frontend_info));
- break;
-
- case FE_TYPE_TDA10046H:
- memcpy(arg, &tda10046h_info, sizeof(struct dvb_frontend_info));
- break;
- }
+ switch(tda_state->fe_type) {
+ case FE_TYPE_TDA10045H:
+ memcpy(arg, &tda10045h_info, sizeof(struct dvb_frontend_info));
+ break;
+
+ case FE_TYPE_TDA10046H:
+ memcpy(arg, &tda10046h_info, sizeof(struct dvb_frontend_info));
+ break;
+ }
break;
case FE_READ_STATUS:
return 0;
// OK, perform initialisation
- switch(tda_state->fe_type) {
- case FE_TYPE_TDA10045H:
- status = tda10045h_init(i2c, tda_state);
- break;
-
- case FE_TYPE_TDA10046H:
- status = tda10046h_init(i2c, tda_state);
- break;
- }
+ switch(tda_state->fe_type) {
+ case FE_TYPE_TDA10045H:
+ status = tda10045h_init(i2c, tda_state);
+ break;
+
+ case FE_TYPE_TDA10046H:
+ status = tda10046h_init(i2c, tda_state);
+ break;
+ }
if (status == 0)
tda_state->initialised = 1;
return status;
fesettings->max_drift = 166667*2;
return 0;
}
-
+
default:
return -EOPNOTSUPP;
}
return 0;
}
-
-static int tda1004x_attach(struct dvb_i2c_bus *i2c, void **data)
+static int tda1004x_attach(struct i2c_adapter *i2c, struct tda1004x_state* state)
{
- int tda1004x_address = -1;
+ int tda1004x_address = -1;
int tuner_address = -1;
- int fe_type = -1;
- int tuner_type = -1;
- struct tda1004x_state tda_state;
- struct tda1004x_state* ptda_state;
+ int fe_type = -1;
+ int tuner_type = -1;
struct i2c_msg tuner_msg = {.addr=0, .flags=0, .buf=NULL, .len=0 };
- static u8 td1344_init[] = { 0x0b, 0xf5, 0x88, 0xab };
- static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
- static u8 td1316_init_tda10046h[] = { 0x0b, 0xf5, 0x80, 0xab };
- int status;
+ static u8 td1344_init[] = { 0x0b, 0xf5, 0x88, 0xab };
+ static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+ static u8 td1316_init_tda10046h[] = { 0x0b, 0xf5, 0x80, 0xab };
dprintk("%s\n", __FUNCTION__);
- // probe for tda10045h
- if (tda1004x_address == -1) {
- tda_state.tda1004x_address = 0x08;
- if (tda1004x_read_byte(i2c, &tda_state, TDA1004X_CHIPID) == 0x25) {
- tda1004x_address = 0x08;
- fe_type = FE_TYPE_TDA10045H;
- printk("tda1004x: Detected Philips TDA10045H.\n");
- }
- }
-
- // probe for tda10046h
- if (tda1004x_address == -1) {
- tda_state.tda1004x_address = 0x08;
- if (tda1004x_read_byte(i2c, &tda_state, TDA1004X_CHIPID) == 0x46) {
- tda1004x_address = 0x08;
- fe_type = FE_TYPE_TDA10046H;
- printk("tda1004x: Detected Philips TDA10046H.\n");
- }
- }
-
- // did we find a frontend?
- if (tda1004x_address == -1) {
+ // probe for tda10045h
+ if (tda1004x_address == -1) {
+ state->tda1004x_address = 0x08;
+ if (tda1004x_read_byte(i2c, state, TDA1004X_CHIPID) == 0x25) {
+ tda1004x_address = 0x08;
+ fe_type = FE_TYPE_TDA10045H;
+ printk("tda1004x: Detected Philips TDA10045H.\n");
+ }
+ }
+
+ // probe for tda10046h
+ if (tda1004x_address == -1) {
+ state->tda1004x_address = 0x08;
+ if (tda1004x_read_byte(i2c, state, TDA1004X_CHIPID) == 0x46) {
+ tda1004x_address = 0x08;
+ fe_type = FE_TYPE_TDA10046H;
+ printk("tda1004x: Detected Philips TDA10046H.\n");
+ }
+ }
+
+ // did we find a frontend?
+ if (tda1004x_address == -1) {
return -ENODEV;
- }
-
- // enable access to the tuner
- tda1004x_enable_tuner_i2c(i2c, &tda_state);
-
- // check for a TD1344 first
- if (tuner_address == -1) {
- tuner_msg.addr = 0x61;
- tuner_msg.buf = td1344_init;
- tuner_msg.len = sizeof(td1344_init);
- if (i2c->xfer(i2c, &tuner_msg, 1) == 1) {
- dvb_delay(1);
- tuner_address = 0x61;
- tuner_type = TUNER_TYPE_TD1344;
- printk("tda1004x: Detected Philips TD1344 tuner.\n");
- }
- }
-
- // OK, try a TD1316 on address 0x63
- if (tuner_address == -1) {
- tuner_msg.addr = 0x63;
- tuner_msg.buf = td1316_init;
- tuner_msg.len = sizeof(td1316_init);
- if (i2c->xfer(i2c, &tuner_msg, 1) == 1) {
- dvb_delay(1);
- tuner_address = 0x63;
- tuner_type = TUNER_TYPE_TD1316;
- printk("tda1004x: Detected Philips TD1316 tuner.\n");
- }
- }
-
- // OK, TD1316 again, on address 0x60 (TDA10046H)
- if (tuner_address == -1) {
- tuner_msg.addr = 0x60;
- tuner_msg.buf = td1316_init_tda10046h;
- tuner_msg.len = sizeof(td1316_init_tda10046h);
- if (i2c->xfer(i2c, &tuner_msg, 1) == 1) {
- dvb_delay(1);
- tuner_address = 0x60;
- tuner_type = TUNER_TYPE_TD1316;
- printk("tda1004x: Detected Philips TD1316 tuner.\n");
+ }
+
+ // enable access to the tuner
+ tda1004x_enable_tuner_i2c(i2c, state);
+
+ // check for a TD1344 first
+ if (tuner_address == -1) {
+ tuner_msg.addr = 0x61;
+ tuner_msg.buf = td1344_init;
+ tuner_msg.len = sizeof(td1344_init);
+ if (i2c_transfer(i2c, &tuner_msg, 1) == 1) {
+ msleep(1);
+ tuner_address = 0x61;
+ tuner_type = TUNER_TYPE_TD1344;
+ printk("tda1004x: Detected Philips TD1344 tuner.\n");
+ }
+ }
+
+ // OK, try a TD1316 on address 0x63
+ if (tuner_address == -1) {
+ tuner_msg.addr = 0x63;
+ tuner_msg.buf = td1316_init;
+ tuner_msg.len = sizeof(td1316_init);
+ if (i2c_transfer(i2c, &tuner_msg, 1) == 1) {
+ msleep(1);
+ tuner_address = 0x63;
+ tuner_type = TUNER_TYPE_TD1316;
+ printk("tda1004x: Detected Philips TD1316 tuner.\n");
}
}
- tda1004x_disable_tuner_i2c(i2c, &tda_state);
+
+ // OK, TD1316 again, on address 0x60 (TDA10046H)
+ if (tuner_address == -1) {
+ tuner_msg.addr = 0x60;
+ tuner_msg.buf = td1316_init_tda10046h;
+ tuner_msg.len = sizeof(td1316_init_tda10046h);
+ if (i2c_transfer(i2c, &tuner_msg, 1) == 1) {
+ msleep(1);
+ tuner_address = 0x60;
+ tuner_type = TUNER_TYPE_TD1316;
+ printk("tda1004x: Detected Philips TD1316 tuner.\n");
+ }
+ }
+ tda1004x_disable_tuner_i2c(i2c, state);
// did we find a tuner?
if (tuner_address == -1) {
return -ENODEV;
}
- // create state
- tda_state.tda1004x_address = tda1004x_address;
- tda_state.fe_type = fe_type;
- tda_state.tuner_address = tuner_address;
- tda_state.tuner_type = tuner_type;
- tda_state.initialised = 0;
+ // create state
+ state->tda1004x_address = tda1004x_address;
+ state->fe_type = fe_type;
+ state->tuner_address = tuner_address;
+ state->tuner_type = tuner_type;
+ state->initialised = 0;
+
+ return 0;
+}
+
+static struct i2c_client client_template;
- // upload firmware
- if ((status = tda1004x_fwupload(i2c, &tda_state)) != 0) return status;
+static int attach_adapter(struct i2c_adapter *adapter)
+{
+ struct i2c_client *client;
+ struct tda1004x_state *state;
+ int ret;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+ return -ENOMEM;
+ }
- // create the real state we'll be passing about
- if ((ptda_state = (struct tda1004x_state*) kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL)) == NULL) {
+ if (NULL == (state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL))) {
+ kfree(client);
return -ENOMEM;
}
- memcpy(ptda_state, &tda_state, sizeof(struct tda1004x_state));
- *data = ptda_state;
+ state->i2c = adapter;
- // register
- switch(tda_state.fe_type) {
- case FE_TYPE_TDA10045H:
- return dvb_register_frontend(tda1004x_ioctl, i2c, ptda_state, &tda10045h_info);
+ ret = tda1004x_attach(adapter, state);
+ if (ret) {
+ kfree(state);
+ kfree(client);
+ return -ENODEV;
+ }
- case FE_TYPE_TDA10046H:
- return dvb_register_frontend(tda1004x_ioctl, i2c, ptda_state, &tda10046h_info);
- }
+ memcpy(client, &client_template, sizeof(struct i2c_client));
+ client->adapter = adapter;
+ client->addr = state->tda1004x_address;
+ i2c_set_clientdata(client, (void*)state);
- // should not get here
- return -EINVAL;
+ ret = i2c_attach_client(client);
+ if (ret) {
+ kfree(client);
+ kfree(state);
+ return ret;
+ }
+
+ // upload firmware
+ BUG_ON(!state->dvb);
+
+ switch(state->fe_type) {
+ case FE_TYPE_TDA10045H:
+ state->dspCodeCounterReg = TDA10045H_FWPAGE;
+ state->dspCodeInReg = TDA10045H_CODE_IN;
+ state->dspVersion = 0x2c;
+
+ ret = tda10045_fwupload(adapter, state, client);
+ if (ret) {
+ printk("tda1004x: firmware upload failed\n");
+ goto out;
+ }
+
+ ret = dvb_register_frontend(tda1004x_ioctl, state->dvb,
+ state, &tda10045h_info,
+ THIS_MODULE);
+ break;
+ case FE_TYPE_TDA10046H:
+ state->dspCodeCounterReg = TDA10046H_CODE_CPT;
+ state->dspCodeInReg = TDA10046H_CODE_IN;
+ state->dspVersion = 0x20;
+
+ ret = tda10046_fwupload(adapter, state, client);
+ if (ret) {
+ printk("tda1004x: firmware upload failed\n");
+ goto out;
+ }
+
+ ret = dvb_register_frontend(tda1004x_ioctl, state->dvb,
+ state, &tda10046h_info,
+ THIS_MODULE);
+ break;
+ default:
+ BUG_ON(1);
+ }
+
+ if (ret) {
+ printk("tda1004x: registering frontend failed\n");
+ goto out;
+ }
+
+ return 0;
+out:
+ i2c_detach_client(client);
+ kfree(client);
+ kfree(state);
+ return ret;
}
+static int detach_client(struct i2c_client *client)
+{
+ struct tda1004x_state *state = (struct tda1004x_state*)i2c_get_clientdata(client);
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ dvb_unregister_frontend (tda1004x_ioctl, state->dvb);
+ i2c_detach_client(client);
+ BUG_ON(state->dvb);
+ kfree(client);
+ kfree(state);
+ return 0;
+}
-static
-void tda1004x_detach(struct dvb_i2c_bus *i2c, void *data)
+static int command (struct i2c_client *client, unsigned int cmd, void *arg)
{
- dprintk("%s\n", __FUNCTION__);
+ struct tda1004x_state *state = (struct tda1004x_state*)i2c_get_clientdata(client);
+
+ dprintk ("%s\n", __FUNCTION__);
- kfree(data);
- dvb_unregister_frontend(tda1004x_ioctl, i2c);
+ switch (cmd) {
+ case FE_REGISTER:
+ state->dvb = (struct dvb_adapter*)arg;
+ break;
+ case FE_UNREGISTER:
+ state->dvb = NULL;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
}
+static struct i2c_driver driver = {
+ .owner = THIS_MODULE,
+ .name = FRONTEND_NAME,
+ .id = I2C_DRIVERID_DVBFE_TDA1004X,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = attach_adapter,
+ .detach_client = detach_client,
+ .command = command,
+};
-static
-int __init init_tda1004x(void)
+static struct i2c_client client_template = {
+ .name = FRONTEND_NAME,
+ .flags = I2C_CLIENT_ALLOW_USE,
+ .driver = &driver,
+};
+
+static int __init init_tda1004x(void)
{
- return dvb_register_i2c_device(THIS_MODULE, tda1004x_attach, tda1004x_detach);
+ return i2c_add_driver(&driver);
}
-
-static
-void __exit exit_tda1004x(void)
+static void __exit exit_tda1004x(void)
{
- dvb_unregister_i2c_device(tda1004x_attach);
+ if (i2c_del_driver(&driver))
+ printk("tda1004x: driver deregistration failed\n");
}
module_init(init_tda1004x);
MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach");
MODULE_LICENSE("GPL");
-MODULE_PARM(tda1004x_debug, "i");
-MODULE_PARM_DESC(tda1004x_debug, "enable verbose debug messages");
-
-MODULE_PARM(tda1004x_firmware, "s");
-MODULE_PARM_DESC(tda1004x_firmware, "Where to find the firmware file");
#include <linux/slab.h>
#include "dvb_frontend.h"
-#include "dvb_functions.h"
+/* I2C_DRIVERID_VES1820 is already defined in i2c-id.h */
#if 0
-#define dprintk(x...) printk(x)
-#else
-#define dprintk(x...)
+static int debug = 0;
+#define dprintk if (debug) printk
#endif
-#define MAX_UNITS 4
-static int pwm[MAX_UNITS] = { -1, -1, -1, -1 };
static int verbose;
-/**
- * since we need only a few bits to store internal state we don't allocate
- * extra memory but use frontend->data as bitfield
- */
+struct ves1820_state {
+ int pwm;
+ u8 reg0;
+ int tuner;
+ u8 demod_addr;
+ struct i2c_adapter *i2c;
+ struct dvb_adapter *dvb;
+};
-#define SET_PWM(data,pwm) do { \
- long d = (long)data; \
- d &= ~0xff; \
- d |= pwm; \
- data = (void *)d; \
-} while (0)
-
-#define SET_REG0(data,reg0) do { \
- long d = (long)data; \
- d &= ~(0xff << 8); \
- d |= reg0 << 8; \
- data = (void *)d; \
-} while (0)
-
-#define SET_TUNER(data,type) do { \
- long d = (long)data; \
- d &= ~(0xff << 16); \
- d |= type << 16; \
- data = (void *)d; \
-} while (0)
-
-#define SET_DEMOD_ADDR(data,type) do { \
- long d = (long)data; \
- d &= ~(0xff << 24); \
- d |= type << 24; \
- data = (void *)d; \
-} while (0)
-
-#define GET_PWM(data) ((u8) ((long) data & 0xff))
-#define GET_REG0(data) ((u8) (((long) data >> 8) & 0xff))
-#define GET_TUNER(data) ((u8) (((long) data >> 16) & 0xff))
-#define GET_DEMOD_ADDR(data) ((u8) (((long) data >> 24) & 0xff))
+/* possible ves1820 adresses */
+static u8 addr[] = { 0x61, 0x62 };
#if defined(CONFIG_DBOX2)
#define XIN 69600000UL
.symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */
.notifier_delay = ?,
#endif
- .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
- FE_CAN_QAM_128 | FE_CAN_QAM_256 |
- FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO,
+ .caps = FE_CAN_QAM_16 |
+ FE_CAN_QAM_32 |
+ FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 |
+ FE_CAN_QAM_256 |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_INVERSION_AUTO,
};
-
-
-static u8 ves1820_inittab [] =
-{
+static u8 ves1820_inittab[] = {
0x69, 0x6A, 0x9B, 0x12, 0x12, 0x46, 0x26, 0x1A,
0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x20,
0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40
};
-
-static int ves1820_writereg (struct dvb_frontend *fe, u8 reg, u8 data)
+static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data)
{
- u8 addr = GET_DEMOD_ADDR(fe->data);
u8 buf[] = { 0x00, reg, data };
- struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
- struct dvb_i2c_bus *i2c = fe->i2c;
+ struct i2c_msg msg = {.addr = state->demod_addr,.flags = 0,.buf = buf,.len = 3 };
int ret;
- ret = i2c->xfer (i2c, &msg, 1);
+ ret = i2c_transfer(state->i2c, &msg, 1);
if (ret != 1)
- printk("DVB: VES1820(%d): %s, writereg error "
- "(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
- fe->i2c->adapter->num, __FUNCTION__, reg, data, ret);
+ printk("ves1820: %s(): writereg error (reg == 0x%02x,"
+ "val == 0x%02x, ret == %i)\n", __FUNCTION__, reg, data, ret);
- dvb_delay(10);
+ msleep(10);
return (ret != 1) ? -EREMOTEIO : 0;
}
-
-static u8 ves1820_readreg (struct dvb_frontend *fe, u8 reg)
+static u8 ves1820_readreg(struct ves1820_state *state, u8 reg)
{
u8 b0 [] = { 0x00, reg };
u8 b1 [] = { 0 };
- u8 addr = GET_DEMOD_ADDR(fe->data);
- struct i2c_msg msg [] = { { .addr = addr, .flags = 0, .buf = b0, .len = 2 },
- { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
- struct dvb_i2c_bus *i2c = fe->i2c;
+ struct i2c_msg msg[] = {
+ {.addr = state->demod_addr,.flags = 0,.buf = b0,.len = 2},
+ {.addr = state->demod_addr,.flags = I2C_M_RD,.buf = b1,.len = 1}
+ };
int ret;
- ret = i2c->xfer (i2c, msg, 2);
+ ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2)
- printk("DVB: VES1820(%d): %s: readreg error (ret == %i)\n",
- fe->i2c->adapter->num, __FUNCTION__, ret);
+ printk("ves1820: %s(): readreg error (reg == 0x%02x,"
+ "ret == %i)\n", __FUNCTION__, reg, ret);
return b1[0];
}
-
-static int tuner_write (struct dvb_i2c_bus *i2c, u8 addr, u8 data [4])
+static int tuner_write(struct ves1820_state *state, u8 addr, u8 data[4])
{
int ret;
struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
- ret = i2c->xfer (i2c, &msg, 1);
+ ret = i2c_transfer(state->i2c, &msg, 1);
if (ret != 1)
- printk("DVB: VES1820(%d): %s: i/o error (ret == %i)\n",
- i2c->adapter->num, __FUNCTION__, ret);
+ printk("ves1820: %s(): i/o error (ret == %i)\n", __FUNCTION__, ret);
return (ret != 1) ? -EREMOTEIO : 0;
}
* set up the downconverter frequency divisor for a
* reference clock comparision frequency of 62.5 kHz.
*/
-static int tuner_set_tv_freq (struct dvb_frontend *fe, u32 freq)
+static int tuner_set_tv_freq(struct ves1820_state *state, u32 freq)
{
u32 div, ifreq;
- static u8 addr [] = { 0x61, 0x62 };
static u8 byte3 [] = { 0x8e, 0x85 };
- int tuner_type = GET_TUNER(fe->data);
+ int tuner_type = state->tuner;
u8 buf [4];
if (tuner_type == 0xff) /* PLL not reachable over i2c ... */
return 0;
- if (strstr (fe->i2c->adapter->name, "Technotrend") ||
- strstr (fe->i2c->adapter->name, "TT-Budget"))
+ if (strstr(state->i2c->name, "Technotrend")
+ || strstr(state->i2c->name, "TT-Budget"))
ifreq = 35937500;
else
ifreq = 36125000;
if (tuner_type == 1) {
buf[2] |= (div >> 10) & 0x60;
- buf[3] = (freq < 174000000 ? 0x88 :
- freq < 470000000 ? 0x84 : 0x81);
+ buf[3] = (freq < 174000000 ? 0x88 : freq < 470000000 ? 0x84 : 0x81);
} else {
- buf[3] = (freq < 174000000 ? 0xa1 :
- freq < 454000000 ? 0x92 : 0x34);
+ buf[3] = (freq < 174000000 ? 0xa1 : freq < 454000000 ? 0x92 : 0x34);
}
- return tuner_write (fe->i2c, addr[tuner_type], buf);
+ return tuner_write(state, addr[tuner_type], buf);
}
-
-static int ves1820_setup_reg0 (struct dvb_frontend *fe, u8 reg0,
- fe_spectral_inversion_t inversion)
+static int ves1820_setup_reg0(struct ves1820_state *state, u8 reg0, fe_spectral_inversion_t inversion)
{
- reg0 |= GET_REG0(fe->data) & 0x62;
+ reg0 |= state->reg0 & 0x62;
if (INVERSION_ON == inversion)
ENABLE_INVERSION(reg0);
else if (INVERSION_OFF == inversion)
DISABLE_INVERSION(reg0);
- ves1820_writereg (fe, 0x00, reg0 & 0xfe);
- ves1820_writereg (fe, 0x00, reg0 | 0x01);
+ ves1820_writereg(state, 0x00, reg0 & 0xfe);
+ ves1820_writereg(state, 0x00, reg0 | 0x01);
/**
* check lock and toggle inversion bit if required...
*/
- if (INVERSION_AUTO == inversion && !(ves1820_readreg (fe, 0x11) & 0x08)) {
+ if (INVERSION_AUTO == inversion && !(ves1820_readreg(state, 0x11) & 0x08)) {
mdelay(50);
- if (!(ves1820_readreg (fe, 0x11) & 0x08)) {
+ if (!(ves1820_readreg(state, 0x11) & 0x08)) {
reg0 ^= 0x20;
- ves1820_writereg (fe, 0x00, reg0 & 0xfe);
- ves1820_writereg (fe, 0x00, reg0 | 0x01);
+ ves1820_writereg(state, 0x00, reg0 & 0xfe);
+ ves1820_writereg(state, 0x00, reg0 | 0x01);
}
}
- SET_REG0(fe->data, reg0);
+ state->reg0 = reg0;
return 0;
}
-
-static int ves1820_init (struct dvb_frontend *fe)
+static int ves1820_init(struct ves1820_state *state)
{
int i;
- dprintk("DVB: VES1820(%d): init chip\n", fe->i2c->adapter->num);
-
- ves1820_writereg (fe, 0, 0);
+ ves1820_writereg(state, 0, 0);
#if defined(CONFIG_DBOX2)
ves1820_inittab[2] &= ~0x08;
#endif
for (i=0; i<53; i++)
- ves1820_writereg (fe, i, ves1820_inittab[i]);
+ ves1820_writereg(state, i, ves1820_inittab[i]);
- ves1820_writereg (fe, 0x34, GET_PWM(fe->data));
+ ves1820_writereg(state, 0x34, state->pwm);
return 0;
}
-
-static int ves1820_set_symbolrate (struct dvb_frontend *fe, u32 symbolrate)
+static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate)
{
s32 BDR;
s32 BDRI;
if (symbolrate < 500000)
symbolrate = 500000;
- if (symbolrate < XIN/16) NDEC = 1;
- if (symbolrate < XIN/32) NDEC = 2;
- if (symbolrate < XIN/64) NDEC = 3;
-
- if (symbolrate < (u32)(XIN/12.3)) SFIL = 1;
- if (symbolrate < (u32)(XIN/16)) SFIL = 0;
- if (symbolrate < (u32)(XIN/24.6)) SFIL = 1;
- if (symbolrate < (u32)(XIN/32)) SFIL = 0;
- if (symbolrate < (u32)(XIN/49.2)) SFIL = 1;
- if (symbolrate < (u32)(XIN/64)) SFIL = 0;
- if (symbolrate < (u32)(XIN/98.4)) SFIL = 1;
+ if (symbolrate < XIN / 16)
+ NDEC = 1;
+ if (symbolrate < XIN / 32)
+ NDEC = 2;
+ if (symbolrate < XIN / 64)
+ NDEC = 3;
+
+ if (symbolrate < (u32) (XIN / 12.3))
+ SFIL = 1;
+ if (symbolrate < (u32) (XIN / 16))
+ SFIL = 0;
+ if (symbolrate < (u32) (XIN / 24.6))
+ SFIL = 1;
+ if (symbolrate < (u32) (XIN / 32))
+ SFIL = 0;
+ if (symbolrate < (u32) (XIN / 49.2))
+ SFIL = 1;
+ if (symbolrate < (u32) (XIN / 64))
+ SFIL = 0;
+ if (symbolrate < (u32) (XIN / 98.4))
+ SFIL = 1;
symbolrate <<= NDEC;
ratio = (symbolrate << 4) / FIN;
NDEC = (NDEC << 6) | ves1820_inittab[0x03];
- ves1820_writereg (fe, 0x03, NDEC);
- ves1820_writereg (fe, 0x0a, BDR&0xff);
- ves1820_writereg (fe, 0x0b, (BDR>> 8)&0xff);
- ves1820_writereg (fe, 0x0c, (BDR>>16)&0x3f);
+ ves1820_writereg(state, 0x03, NDEC);
+ ves1820_writereg(state, 0x0a, BDR & 0xff);
+ ves1820_writereg(state, 0x0b, (BDR >> 8) & 0xff);
+ ves1820_writereg(state, 0x0c, (BDR >> 16) & 0x3f);
- ves1820_writereg (fe, 0x0d, BDRI);
- ves1820_writereg (fe, 0x0e, SFIL);
+ ves1820_writereg(state, 0x0d, BDRI);
+ ves1820_writereg(state, 0x0e, SFIL);
return 0;
}
-
-static int ves1820_set_parameters (struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int ves1820_set_parameters(struct ves1820_state *state, struct dvb_frontend_parameters *p)
{
static const u8 reg0x00 [] = { 0x00, 0x04, 0x08, 0x0c, 0x10 };
static const u8 reg0x01 [] = { 140, 140, 106, 100, 92 };
if (real_qam < 0 || real_qam > 4)
return -EINVAL;
- tuner_set_tv_freq (fe, p->frequency);
- ves1820_set_symbolrate (fe, p->u.qam.symbol_rate);
- ves1820_writereg (fe, 0x34, GET_PWM(fe->data));
+ tuner_set_tv_freq(state, p->frequency);
+ ves1820_set_symbolrate(state, p->u.qam.symbol_rate);
+ ves1820_writereg(state, 0x34, state->pwm);
- ves1820_writereg (fe, 0x01, reg0x01[real_qam]);
- ves1820_writereg (fe, 0x05, reg0x05[real_qam]);
- ves1820_writereg (fe, 0x08, reg0x08[real_qam]);
- ves1820_writereg (fe, 0x09, reg0x09[real_qam]);
+ ves1820_writereg(state, 0x01, reg0x01[real_qam]);
+ ves1820_writereg(state, 0x05, reg0x05[real_qam]);
+ ves1820_writereg(state, 0x08, reg0x08[real_qam]);
+ ves1820_writereg(state, 0x09, reg0x09[real_qam]);
- ves1820_setup_reg0 (fe, reg0x00[real_qam], p->inversion);
+ ves1820_setup_reg0(state, reg0x00[real_qam], p->inversion);
/* yes, this speeds things up: userspace reports lock in about 8 ms
instead of 500 to 1200 ms after calling FE_SET_FRONTEND. */
return 0;
}
-
-
static int ves1820_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
{
+ struct ves1820_state *state = (struct ves1820_state *) fe->data;
+
switch (cmd) {
case FE_GET_INFO:
memcpy (arg, &ves1820_info, sizeof(struct dvb_frontend_info));
*status = 0;
- sync = ves1820_readreg (fe, 0x11);
+ sync = ves1820_readreg(state, 0x11);
if (sync & 1)
*status |= FE_HAS_SIGNAL;
case FE_READ_BER:
{
- u32 ber = ves1820_readreg(fe, 0x14) |
- (ves1820_readreg(fe, 0x15) << 8) |
- ((ves1820_readreg(fe, 0x16) & 0x0f) << 16);
+ u32 ber = ves1820_readreg(state, 0x14) |
+ (ves1820_readreg(state, 0x15) << 8) |
+ ((ves1820_readreg(state, 0x16) & 0x0f) << 16);
*((u32*) arg) = 10 * ber;
break;
}
case FE_READ_SIGNAL_STRENGTH:
{
- u8 gain = ves1820_readreg(fe, 0x17);
+ u8 gain = ves1820_readreg(state, 0x17);
*((u16*) arg) = (gain << 8) | gain;
break;
}
case FE_READ_SNR:
{
- u8 quality = ~ves1820_readreg(fe, 0x18);
+ u8 quality = ~ves1820_readreg(state, 0x18);
*((u16*) arg) = (quality << 8) | quality;
break;
}
case FE_READ_UNCORRECTED_BLOCKS:
- *((u32*) arg) = ves1820_readreg (fe, 0x13) & 0x7f;
+ *((u32 *) arg) = ves1820_readreg(state, 0x13) & 0x7f;
if (*((u32*) arg) == 0x7f)
*((u32*) arg) = 0xffffffff;
/* reset uncorrected block counter */
- ves1820_writereg (fe, 0x10, ves1820_inittab[0x10] & 0xdf);
- ves1820_writereg (fe, 0x10, ves1820_inittab[0x10]);
+ ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf);
+ ves1820_writereg(state, 0x10, ves1820_inittab[0x10]);
break;
case FE_SET_FRONTEND:
- return ves1820_set_parameters (fe, arg);
+ return ves1820_set_parameters(state, arg);
case FE_GET_FRONTEND:
{
struct dvb_frontend_parameters *p = (struct dvb_frontend_parameters *)arg;
- u8 reg0 = GET_REG0(fe->data);
int sync;
s8 afc = 0;
- sync = ves1820_readreg (fe, 0x11);
- afc = ves1820_readreg(fe, 0x19);
+ sync = ves1820_readreg(state, 0x11);
+ afc = ves1820_readreg(state, 0x19);
if (verbose) {
/* AFC only valid when carrier has been recovered */
- printk(sync & 2 ? "DVB: VES1820(%d): AFC (%d) %dHz\n" :
- "DVB: VES1820(%d): [AFC (%d) %dHz]\n",
- fe->i2c->adapter->num, afc,
- -((s32)p->u.qam.symbol_rate * afc) >> 10);
+ printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" :
+ "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->u.qam.symbol_rate * afc) >> 10);
}
- p->inversion = HAS_INVERSION(reg0) ? INVERSION_ON : INVERSION_OFF;
- p->u.qam.modulation = ((reg0 >> 2) & 7) + QAM_16;
+ p->inversion = HAS_INVERSION(state->reg0) ? INVERSION_ON : INVERSION_OFF;
+ p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
p->u.qam.fec_inner = FEC_NONE;
break;
}
case FE_SLEEP:
- ves1820_writereg (fe, 0x1b, 0x02); /* pdown ADC */
- ves1820_writereg (fe, 0x00, 0x80); /* standby */
+ ves1820_writereg(state, 0x1b, 0x02); /* pdown ADC */
+ ves1820_writereg(state, 0x00, 0x80); /* standby */
break;
case FE_INIT:
- return ves1820_init (fe);
+ return ves1820_init(state);
default:
return -EINVAL;
return 0;
}
-
-static long probe_tuner (struct dvb_i2c_bus *i2c)
+static long probe_tuner(struct i2c_adapter *i2c)
{
- static const struct i2c_msg msg1 =
- { .addr = 0x61, .flags = 0, .buf = NULL, .len = 0 };
- static const struct i2c_msg msg2 =
- { .addr = 0x62, .flags = 0, .buf = NULL, .len = 0 };
+ struct i2c_msg msg1 = {.addr = 0x61,.flags = 0,.buf = NULL,.len = 0 };
+ struct i2c_msg msg2 = {.addr = 0x62,.flags = 0,.buf = NULL,.len = 0 };
int type;
- if (i2c->xfer(i2c, &msg1, 1) == 1) {
+ if (i2c_transfer(i2c, &msg1, 1) == 1) {
type = 0;
- printk ("DVB: VES1820(%d): setup for tuner spXXXX\n", i2c->adapter->num);
- } else if (i2c->xfer(i2c, &msg2, 1) == 1) {
+ printk("ves1820: setup for tuner spXXXX\n");
+ } else if (i2c_transfer(i2c, &msg2, 1) == 1) {
type = 1;
- printk ("DVB: VES1820(%d): setup for tuner sp5659c\n", i2c->adapter->num);
+ printk("ves1820: setup for tuner sp5659c\n");
} else {
type = -1;
}
return type;
}
-
-static u8 read_pwm (struct dvb_i2c_bus *i2c)
+static u8 read_pwm(struct i2c_adapter *i2c)
{
u8 b = 0xff;
u8 pwm;
struct i2c_msg msg [] = { { .addr = 0x50, .flags = 0, .buf = &b, .len = 1 },
- { .addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1 } };
+ {.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1}
+ };
- if ((i2c->xfer(i2c, msg, 2) != 2) || (pwm == 0xff))
+ if ((i2c_transfer(i2c, msg, 2) != 2) || (pwm == 0xff))
pwm = 0x48;
- printk("DVB: VES1820(%d): pwm=0x%02x\n", i2c->adapter->num, pwm);
+ printk("ves1820: pwm=0x%02x\n", pwm);
return pwm;
}
-
-static long probe_demod_addr (struct dvb_i2c_bus *i2c)
+static long probe_demod_addr(struct i2c_adapter *i2c)
{
u8 b [] = { 0x00, 0x1a };
u8 id;
struct i2c_msg msg [] = { { .addr = 0x08, .flags = 0, .buf = b, .len = 2 },
- { .addr = 0x08, .flags = I2C_M_RD, .buf = &id, .len = 1 } };
+ {.addr = 0x08,.flags = I2C_M_RD,.buf = &id,.len = 1}
+ };
- if (i2c->xfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70)
+ if (i2c_transfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70)
return msg[0].addr;
msg[0].addr = msg[1].addr = 0x09;
- if (i2c->xfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70)
+ if (i2c_transfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70)
return msg[0].addr;
return -1;
}
+static ssize_t attr_read_pwm(struct device *dev, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ves1820_state *state = (struct ves1820_state *) i2c_get_clientdata(client);
+ return sprintf(buf, "0x%02x\n", state->pwm);
+}
+
+static ssize_t attr_write_pwm(struct device *dev, const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ves1820_state *state = (struct ves1820_state *) i2c_get_clientdata(client);
+ unsigned long pwm;
+ pwm = simple_strtoul(buf, NULL, 0);
+ state->pwm = pwm & 0xff;
+ return strlen(buf)+1;
+}
-static int ves1820_attach (struct dvb_i2c_bus *i2c, void **data)
+static struct device_attribute dev_attr_client_name = {
+ .attr = { .name = "pwm", .mode = S_IRUGO|S_IWUGO, .owner = THIS_MODULE },
+ .show = &attr_read_pwm,
+ .store = &attr_write_pwm,
+};
+
+static struct i2c_client client_template;
+
+static int attach_adapter(struct i2c_adapter *adapter)
{
- void *priv = NULL;
+ struct i2c_client *client;
+ struct ves1820_state *state;
long demod_addr;
- long tuner_type;
+ int tuner_type;
+ int ret;
- if ((demod_addr = probe_demod_addr(i2c)) < 0)
+ demod_addr = probe_demod_addr(adapter);
+ if (demod_addr < 0)
return -ENODEV;
- tuner_type = probe_tuner(i2c);
+ tuner_type = probe_tuner(adapter);
+ if (tuner_type < 0) {
+ printk("ves1820: demod found, but unknown tuner type.\n");
+ return -ENODEV;
+ }
- if ((i2c->adapter->num < MAX_UNITS) && pwm[i2c->adapter->num] != -1) {
- printk("DVB: VES1820(%d): pwm=0x%02x (user specified)\n",
- i2c->adapter->num, pwm[i2c->adapter->num]);
- SET_PWM(priv, pwm[i2c->adapter->num]);
+ if ((state = kmalloc(sizeof(struct ves1820_state), GFP_KERNEL)) == NULL) {
+ return -ENOMEM;
}
- else
- SET_PWM(priv, read_pwm(i2c));
- SET_REG0(priv, ves1820_inittab[0]);
- SET_TUNER(priv, tuner_type);
- SET_DEMOD_ADDR(priv, demod_addr);
- return dvb_register_frontend (ves1820_ioctl, i2c, priv, &ves1820_info);
+ if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+ kfree(state);
+ return -ENOMEM;
+ }
+
+ memset(state, 0, sizeof(*state));
+ state->i2c = adapter;
+ state->tuner = tuner_type;
+ state->pwm = read_pwm(adapter);
+ state->reg0 = ves1820_inittab[0];
+ state->demod_addr = demod_addr;
+
+ memcpy(client, &client_template, sizeof(struct i2c_client));
+ client->adapter = adapter;
+ client->addr = addr[tuner_type];
+
+ i2c_set_clientdata(client, (void *) state);
+
+ ret = i2c_attach_client(client);
+ if (ret) {
+ kfree(client);
+ kfree(state);
+ return ret;
}
+ BUG_ON(!state->dvb);
-static void ves1820_detach (struct dvb_i2c_bus *i2c, void *data)
+ device_create_file(&client->dev, &dev_attr_client_name);
+
+ ret = dvb_register_frontend(ves1820_ioctl, state->dvb, state, &ves1820_info, THIS_MODULE);
+ if (ret) {
+ i2c_detach_client(client);
+ kfree(client);
+ kfree(state);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int detach_client(struct i2c_client *client)
{
- dvb_unregister_frontend (ves1820_ioctl, i2c);
+ struct ves1820_state *state = (struct ves1820_state *) i2c_get_clientdata(client);
+ dvb_unregister_frontend_new(ves1820_ioctl, state->dvb);
+ device_remove_file(&client->dev, &dev_attr_client_name);
+ i2c_detach_client(client);
+ BUG_ON(state->dvb);
+ kfree(client);
+ kfree(state);
+ return 0;
}
+static int command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+ struct ves1820_state *state = (struct ves1820_state *) i2c_get_clientdata(client);
+
+ switch (cmd) {
+ case FE_REGISTER:{
+ state->dvb = (struct dvb_adapter *) arg;
+ break;
+ }
+ case FE_UNREGISTER:{
+ state->dvb = NULL;
+ break;
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static struct i2c_driver driver = {
+ .owner = THIS_MODULE,
+ .name = "ves1820",
+ .id = I2C_DRIVERID_VES1820,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = attach_adapter,
+ .detach_client = detach_client,
+ .command = command,
+};
+
+static struct i2c_client client_template = {
+ I2C_DEVNAME("ves1820"),
+ .flags = I2C_CLIENT_ALLOW_USE,
+ .driver = &driver,
+};
static int __init init_ves1820 (void)
{
- int i;
- for (i = 0; i < MAX_UNITS; i++)
- if (pwm[i] < -1 || pwm[i] > 255)
- return -EINVAL;
- return dvb_register_i2c_device (THIS_MODULE,
- ves1820_attach, ves1820_detach);
+ return i2c_add_driver(&driver);
}
-
static void __exit exit_ves1820 (void)
{
- dvb_unregister_i2c_device (ves1820_attach);
+ if (i2c_del_driver(&driver))
+ printk("ves1820: driver deregistration failed\n");
}
-
module_init(init_ves1820);
module_exit(exit_ves1820);
-MODULE_PARM(pwm, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM_DESC(pwm, "override PWM value stored in EEPROM (tuner calibration)");
MODULE_PARM(verbose, "i");
MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");