Merge git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb

* git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb:
  V4L/DVB (7751): ir-kbd-i2c: Save a temporary memory allocation in ir_probe
  V4L/DVB (7750): au0828/ cleanups and fixes
  V4L/DVB (7748): tuner-core: some adjustments at tuner logs, if debug enabled
  V4L/DVB (7746): pvrusb2: make signed one-bit bitfields unsigned
  V4L/DVB (7744): pvrusb2-dvb: add atsc/qam support for Hauppauge pvrusb2 model 751xx
  V4L/DVB (7742): cx88: Add support for the DViCO FusionHDTV_7_GOLD digital modes
  V4L/DVB (7741): s5h1411: Adding support for this ATSC/QAM demodulator
  V4L/DVB (7740): tuner-xc2028.c dubious !x & y
  V4L/DVB (7739): mt312.h: dubious one-bit signed bitfield
  V4L/DVB (7735): Fix compilation for au0828
  V4L/DVB (7734): em28xx: copy and paste error in em28xx_init_isoc
  V4L/DVB (7733): blackbird_find_mailbox negative return ignored in blackbird_initialize_codec()
  V4L/DVB (7732): vivi: fix a warning
This commit is contained in:
Linus Torvalds 2008-04-26 09:49:51 -07:00
commit c837c93a03
23 changed files with 1135 additions and 109 deletions

View file

@ -307,6 +307,14 @@ config DVB_AU8522
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
config DVB_S5H1411
tristate "Samsung S5H1411 based"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
comment "Tuners/PLL support"
depends on DVB_CORE

View file

@ -55,3 +55,4 @@ obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o
obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
obj-$(CONFIG_DVB_AU8522) += au8522.o
obj-$(CONFIG_DVB_TDA10048) += tda10048.o
obj-$(CONFIG_DVB_S5H1411) += s5h1411.o

View file

@ -33,7 +33,7 @@ struct mt312_config {
u8 demod_address;
/* inverted voltage setting */
int voltage_inverted:1;
unsigned int voltage_inverted:1;
};
#if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE))

View file

@ -0,0 +1,888 @@
/*
Samsung S5H1411 VSB/QAM demodulator driver
Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
#include "dvb-pll.h"
#include "s5h1411.h"
struct s5h1411_state {
struct i2c_adapter *i2c;
/* configuration settings */
const struct s5h1411_config *config;
struct dvb_frontend frontend;
fe_modulation_t current_modulation;
u32 current_frequency;
int if_freq;
u8 inversion;
};
static int debug;
#define dprintk(arg...) do { \
if (debug) \
printk(arg); \
} while (0)
/* Register values to initialise the demod, defaults to VSB */
static struct init_tab {
u8 addr;
u8 reg;
u16 data;
} init_tab[] = {
{ S5H1411_I2C_TOP_ADDR, 0x00, 0x0071, },
{ S5H1411_I2C_TOP_ADDR, 0x08, 0x0047, },
{ S5H1411_I2C_TOP_ADDR, 0x1c, 0x0400, },
{ S5H1411_I2C_TOP_ADDR, 0x1e, 0x0370, },
{ S5H1411_I2C_TOP_ADDR, 0x1f, 0x342a, },
{ S5H1411_I2C_TOP_ADDR, 0x24, 0x0231, },
{ S5H1411_I2C_TOP_ADDR, 0x25, 0x1011, },
{ S5H1411_I2C_TOP_ADDR, 0x26, 0x0f07, },
{ S5H1411_I2C_TOP_ADDR, 0x27, 0x0f04, },
{ S5H1411_I2C_TOP_ADDR, 0x28, 0x070f, },
{ S5H1411_I2C_TOP_ADDR, 0x29, 0x2820, },
{ S5H1411_I2C_TOP_ADDR, 0x2a, 0x102e, },
{ S5H1411_I2C_TOP_ADDR, 0x2b, 0x0220, },
{ S5H1411_I2C_TOP_ADDR, 0x2e, 0x0d0e, },
{ S5H1411_I2C_TOP_ADDR, 0x2f, 0x1013, },
{ S5H1411_I2C_TOP_ADDR, 0x31, 0x171b, },
{ S5H1411_I2C_TOP_ADDR, 0x32, 0x0e0f, },
{ S5H1411_I2C_TOP_ADDR, 0x33, 0x0f10, },
{ S5H1411_I2C_TOP_ADDR, 0x34, 0x170e, },
{ S5H1411_I2C_TOP_ADDR, 0x35, 0x4b10, },
{ S5H1411_I2C_TOP_ADDR, 0x36, 0x0f17, },
{ S5H1411_I2C_TOP_ADDR, 0x3c, 0x1577, },
{ S5H1411_I2C_TOP_ADDR, 0x3d, 0x081a, },
{ S5H1411_I2C_TOP_ADDR, 0x3e, 0x77ee, },
{ S5H1411_I2C_TOP_ADDR, 0x40, 0x1e09, },
{ S5H1411_I2C_TOP_ADDR, 0x41, 0x0f0c, },
{ S5H1411_I2C_TOP_ADDR, 0x42, 0x1f10, },
{ S5H1411_I2C_TOP_ADDR, 0x4d, 0x0509, },
{ S5H1411_I2C_TOP_ADDR, 0x4e, 0x0a00, },
{ S5H1411_I2C_TOP_ADDR, 0x50, 0x0000, },
{ S5H1411_I2C_TOP_ADDR, 0x5b, 0x0000, },
{ S5H1411_I2C_TOP_ADDR, 0x5c, 0x0008, },
{ S5H1411_I2C_TOP_ADDR, 0x57, 0x1101, },
{ S5H1411_I2C_TOP_ADDR, 0x65, 0x007c, },
{ S5H1411_I2C_TOP_ADDR, 0x68, 0x0512, },
{ S5H1411_I2C_TOP_ADDR, 0x69, 0x0258, },
{ S5H1411_I2C_TOP_ADDR, 0x70, 0x0004, },
{ S5H1411_I2C_TOP_ADDR, 0x71, 0x0007, },
{ S5H1411_I2C_TOP_ADDR, 0x76, 0x00a9, },
{ S5H1411_I2C_TOP_ADDR, 0x78, 0x3141, },
{ S5H1411_I2C_TOP_ADDR, 0x7a, 0x3141, },
{ S5H1411_I2C_TOP_ADDR, 0xb3, 0x8003, },
{ S5H1411_I2C_TOP_ADDR, 0xb5, 0xafbb, },
{ S5H1411_I2C_TOP_ADDR, 0xb5, 0xa6bb, },
{ S5H1411_I2C_TOP_ADDR, 0xb6, 0x0609, },
{ S5H1411_I2C_TOP_ADDR, 0xb7, 0x2f06, },
{ S5H1411_I2C_TOP_ADDR, 0xb8, 0x003f, },
{ S5H1411_I2C_TOP_ADDR, 0xb9, 0x2700, },
{ S5H1411_I2C_TOP_ADDR, 0xba, 0xfac8, },
{ S5H1411_I2C_TOP_ADDR, 0xbe, 0x1003, },
{ S5H1411_I2C_TOP_ADDR, 0xbf, 0x103f, },
{ S5H1411_I2C_TOP_ADDR, 0xce, 0x2000, },
{ S5H1411_I2C_TOP_ADDR, 0xcf, 0x0800, },
{ S5H1411_I2C_TOP_ADDR, 0xd0, 0x0800, },
{ S5H1411_I2C_TOP_ADDR, 0xd1, 0x0400, },
{ S5H1411_I2C_TOP_ADDR, 0xd2, 0x0800, },
{ S5H1411_I2C_TOP_ADDR, 0xd3, 0x2000, },
{ S5H1411_I2C_TOP_ADDR, 0xd4, 0x3000, },
{ S5H1411_I2C_TOP_ADDR, 0xdb, 0x4a9b, },
{ S5H1411_I2C_TOP_ADDR, 0xdc, 0x1000, },
{ S5H1411_I2C_TOP_ADDR, 0xde, 0x0001, },
{ S5H1411_I2C_TOP_ADDR, 0xdf, 0x0000, },
{ S5H1411_I2C_TOP_ADDR, 0xe3, 0x0301, },
{ S5H1411_I2C_QAM_ADDR, 0xf3, 0x0000, },
{ S5H1411_I2C_QAM_ADDR, 0xf3, 0x0001, },
{ S5H1411_I2C_QAM_ADDR, 0x08, 0x0600, },
{ S5H1411_I2C_QAM_ADDR, 0x18, 0x4201, },
{ S5H1411_I2C_QAM_ADDR, 0x1e, 0x6476, },
{ S5H1411_I2C_QAM_ADDR, 0x21, 0x0830, },
{ S5H1411_I2C_QAM_ADDR, 0x0c, 0x5679, },
{ S5H1411_I2C_QAM_ADDR, 0x0d, 0x579b, },
{ S5H1411_I2C_QAM_ADDR, 0x24, 0x0102, },
{ S5H1411_I2C_QAM_ADDR, 0x31, 0x7488, },
{ S5H1411_I2C_QAM_ADDR, 0x32, 0x0a08, },
{ S5H1411_I2C_QAM_ADDR, 0x3d, 0x8689, },
{ S5H1411_I2C_QAM_ADDR, 0x49, 0x0048, },
{ S5H1411_I2C_QAM_ADDR, 0x57, 0x2012, },
{ S5H1411_I2C_QAM_ADDR, 0x5d, 0x7676, },
{ S5H1411_I2C_QAM_ADDR, 0x04, 0x0400, },
{ S5H1411_I2C_QAM_ADDR, 0x58, 0x00c0, },
{ S5H1411_I2C_QAM_ADDR, 0x5b, 0x0100, },
};
/* VSB SNR lookup table */
static struct vsb_snr_tab {
u16 val;
u16 data;
} vsb_snr_tab[] = {
{ 0x39f, 300, },
{ 0x39b, 295, },
{ 0x397, 290, },
{ 0x394, 285, },
{ 0x38f, 280, },
{ 0x38b, 275, },
{ 0x387, 270, },
{ 0x382, 265, },
{ 0x37d, 260, },
{ 0x377, 255, },
{ 0x370, 250, },
{ 0x36a, 245, },
{ 0x364, 240, },
{ 0x35b, 235, },
{ 0x353, 230, },
{ 0x349, 225, },
{ 0x340, 320, },
{ 0x337, 215, },
{ 0x327, 210, },
{ 0x31b, 205, },
{ 0x310, 200, },
{ 0x302, 195, },
{ 0x2f3, 190, },
{ 0x2e4, 185, },
{ 0x2d7, 180, },
{ 0x2cd, 175, },
{ 0x2bb, 170, },
{ 0x2a9, 165, },
{ 0x29e, 160, },
{ 0x284, 155, },
{ 0x27a, 150, },
{ 0x260, 145, },
{ 0x23a, 140, },
{ 0x224, 135, },
{ 0x213, 130, },
{ 0x204, 125, },
{ 0x1fe, 120, },
{ 0, 0, },
};
/* QAM64 SNR lookup table */
static struct qam64_snr_tab {
u16 val;
u16 data;
} qam64_snr_tab[] = {
{ 0x0001, 0, },
{ 0x0af0, 300, },
{ 0x0d80, 290, },
{ 0x10a0, 280, },
{ 0x14b5, 270, },
{ 0x1590, 268, },
{ 0x1680, 266, },
{ 0x17b0, 264, },
{ 0x18c0, 262, },
{ 0x19b0, 260, },
{ 0x1ad0, 258, },
{ 0x1d00, 256, },
{ 0x1da0, 254, },
{ 0x1ef0, 252, },
{ 0x2050, 250, },
{ 0x20f0, 249, },
{ 0x21d0, 248, },
{ 0x22b0, 247, },
{ 0x23a0, 246, },
{ 0x2470, 245, },
{ 0x24f0, 244, },
{ 0x25a0, 243, },
{ 0x26c0, 242, },
{ 0x27b0, 241, },
{ 0x28d0, 240, },
{ 0x29b0, 239, },
{ 0x2ad0, 238, },
{ 0x2ba0, 237, },
{ 0x2c80, 236, },
{ 0x2d20, 235, },
{ 0x2e00, 234, },
{ 0x2f10, 233, },
{ 0x3050, 232, },
{ 0x3190, 231, },
{ 0x3300, 230, },
{ 0x3340, 229, },
{ 0x3200, 228, },
{ 0x3550, 227, },
{ 0x3610, 226, },
{ 0x3600, 225, },
{ 0x3700, 224, },
{ 0x3800, 223, },
{ 0x3920, 222, },
{ 0x3a20, 221, },
{ 0x3b30, 220, },
{ 0x3d00, 219, },
{ 0x3e00, 218, },
{ 0x4000, 217, },
{ 0x4100, 216, },
{ 0x4300, 215, },
{ 0x4400, 214, },
{ 0x4600, 213, },
{ 0x4700, 212, },
{ 0x4800, 211, },
{ 0x4a00, 210, },
{ 0x4b00, 209, },
{ 0x4d00, 208, },
{ 0x4f00, 207, },
{ 0x5050, 206, },
{ 0x5200, 205, },
{ 0x53c0, 204, },
{ 0x5450, 203, },
{ 0x5650, 202, },
{ 0x5820, 201, },
{ 0x6000, 200, },
{ 0xffff, 0, },
};
/* QAM256 SNR lookup table */
static struct qam256_snr_tab {
u16 val;
u16 data;
} qam256_snr_tab[] = {
{ 0x0001, 0, },
{ 0x0970, 400, },
{ 0x0a90, 390, },
{ 0x0b90, 380, },
{ 0x0d90, 370, },
{ 0x0ff0, 360, },
{ 0x1240, 350, },
{ 0x1345, 348, },
{ 0x13c0, 346, },
{ 0x14c0, 344, },
{ 0x1500, 342, },
{ 0x1610, 340, },
{ 0x1700, 338, },
{ 0x1800, 336, },
{ 0x18b0, 334, },
{ 0x1900, 332, },
{ 0x1ab0, 330, },
{ 0x1bc0, 328, },
{ 0x1cb0, 326, },
{ 0x1db0, 324, },
{ 0x1eb0, 322, },
{ 0x2030, 320, },
{ 0x2200, 318, },
{ 0x2280, 316, },
{ 0x2410, 314, },
{ 0x25b0, 312, },
{ 0x27a0, 310, },
{ 0x2840, 308, },
{ 0x29d0, 306, },
{ 0x2b10, 304, },
{ 0x2d30, 302, },
{ 0x2f20, 300, },
{ 0x30c0, 298, },
{ 0x3260, 297, },
{ 0x32c0, 296, },
{ 0x3300, 295, },
{ 0x33b0, 294, },
{ 0x34b0, 293, },
{ 0x35a0, 292, },
{ 0x3650, 291, },
{ 0x3800, 290, },
{ 0x3900, 289, },
{ 0x3a50, 288, },
{ 0x3b30, 287, },
{ 0x3cb0, 286, },
{ 0x3e20, 285, },
{ 0x3fa0, 284, },
{ 0x40a0, 283, },
{ 0x41c0, 282, },
{ 0x42f0, 281, },
{ 0x44a0, 280, },
{ 0x4600, 279, },
{ 0x47b0, 278, },
{ 0x4900, 277, },
{ 0x4a00, 276, },
{ 0x4ba0, 275, },
{ 0x4d00, 274, },
{ 0x4f00, 273, },
{ 0x5000, 272, },
{ 0x51f0, 272, },
{ 0x53a0, 270, },
{ 0x5520, 269, },
{ 0x5700, 268, },
{ 0x5800, 267, },
{ 0x5a00, 266, },
{ 0x5c00, 265, },
{ 0x5d00, 264, },
{ 0x5f00, 263, },
{ 0x6000, 262, },
{ 0x6200, 261, },
{ 0x6400, 260, },
{ 0xffff, 0, },
};
/* 8 bit registers, 16 bit values */
static int s5h1411_writereg(struct s5h1411_state *state,
u8 addr, u8 reg, u16 data)
{
int ret;
u8 buf [] = { reg, data >> 8, data & 0xff };
struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
ret = i2c_transfer(state->i2c, &msg, 1);
if (ret != 1)
printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, "
"ret == %i)\n", __func__, addr, reg, data, ret);
return (ret != 1) ? -1 : 0;
}
static u16 s5h1411_readreg(struct s5h1411_state *state, u8 addr, u8 reg)
{
int ret;
u8 b0 [] = { reg };
u8 b1 [] = { 0, 0 };
struct i2c_msg msg [] = {
{ .addr = addr, .flags = 0, .buf = b0, .len = 1 },
{ .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2)
printk(KERN_ERR "%s: readreg error (ret == %i)\n",
__func__, ret);
return (b1[0] << 8) | b1[1];
}
static int s5h1411_softreset(struct dvb_frontend *fe)
{
struct s5h1411_state *state = fe->demodulator_priv;
dprintk("%s()\n", __func__);
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 0);
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 1);
return 0;
}
static int s5h1411_set_if_freq(struct dvb_frontend *fe, int KHz)
{
struct s5h1411_state *state = fe->demodulator_priv;
dprintk("%s(%d KHz)\n", __func__, KHz);
switch (KHz) {
case 3250:
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x10d9);
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x5342);
s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x10d9);
break;
case 3500:
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1225);
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x1e96);
s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1225);
break;
case 4000:
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x14bc);
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0xb53e);
s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x14bd);
break;
default:
dprintk("%s(%d KHz) Invalid, defaulting to 5380\n",
__func__, KHz);
/* no break, need to continue */
case 5380:
case 44000:
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1be4);
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x3655);
s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1be4);
break;
}
state->if_freq = KHz;
return 0;
}
static int s5h1411_set_mpeg_timing(struct dvb_frontend *fe, int mode)
{
struct s5h1411_state *state = fe->demodulator_priv;
u16 val;
dprintk("%s(%d)\n", __func__, mode);
val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbe) & 0xcfff;
switch (mode) {
case S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK:
val |= 0x0000;
break;
case S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK:
dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode);
val |= 0x1000;
break;
case S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK:
val |= 0x2000;
break;
case S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK:
val |= 0x3000;
break;
default:
return -EINVAL;
}
/* Configure MPEG Signal Timing charactistics */
return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbe, val);
}
static int s5h1411_set_spectralinversion(struct dvb_frontend *fe, int inversion)
{
struct s5h1411_state *state = fe->demodulator_priv;
u16 val;
dprintk("%s(%d)\n", __func__, inversion);
val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x24) & ~0x1000;
if (inversion == 1)
val |= 0x1000; /* Inverted */
else
val |= 0x0000;
state->inversion = inversion;
return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x24, val);
}
static int s5h1411_enable_modulation(struct dvb_frontend *fe,
fe_modulation_t m)
{
struct s5h1411_state *state = fe->demodulator_priv;
dprintk("%s(0x%08x)\n", __func__, m);
switch (m) {
case VSB_8:
dprintk("%s() VSB_8\n", __func__);
s5h1411_set_if_freq(fe, state->config->vsb_if);
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x71);
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x00);
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0xf1);
break;
case QAM_64:
case QAM_256:
dprintk("%s() QAM_AUTO (64/256)\n", __func__);
s5h1411_set_if_freq(fe, state->config->qam_if);
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x0171);
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x0001);
s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x16, 0x1101);
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0x00f0);
break;
default:
dprintk("%s() Invalid modulation\n", __func__);
return -EINVAL;
}
state->current_modulation = m;
s5h1411_softreset(fe);
return 0;
}
static int s5h1411_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct s5h1411_state *state = fe->demodulator_priv;
dprintk("%s(%d)\n", __func__, enable);
if (enable)
return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1);
else
return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 0);
}
static int s5h1411_set_gpio(struct dvb_frontend *fe, int enable)
{
struct s5h1411_state *state = fe->demodulator_priv;
u16 val;
dprintk("%s(%d)\n", __func__, enable);
val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xe0) & ~0x02;
if (enable)
return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0,
val | 0x02);
else
return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0, val);
}
static int s5h1411_sleep(struct dvb_frontend *fe, int enable)
{
struct s5h1411_state *state = fe->demodulator_priv;
dprintk("%s(%d)\n", __func__, enable);
if (enable)
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 1);
else {
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 0);
s5h1411_softreset(fe);
}
return 0;
}
static int s5h1411_register_reset(struct dvb_frontend *fe)
{
struct s5h1411_state *state = fe->demodulator_priv;
dprintk("%s()\n", __func__);
return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf3, 0);
}
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
static int s5h1411_set_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct s5h1411_state *state = fe->demodulator_priv;
dprintk("%s(frequency=%d)\n", __func__, p->frequency);
s5h1411_softreset(fe);
state->current_frequency = p->frequency;
s5h1411_enable_modulation(fe, p->u.vsb.modulation);
/* Allow the demod to settle */
msleep(100);
if (fe->ops.tuner_ops.set_params) {
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
fe->ops.tuner_ops.set_params(fe, p);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
return 0;
}
/* Reset the demod hardware and reset all of the configuration registers
to a default state. */
static int s5h1411_init(struct dvb_frontend *fe)
{
struct s5h1411_state *state = fe->demodulator_priv;
int i;
dprintk("%s()\n", __func__);
s5h1411_sleep(fe, 0);
s5h1411_register_reset(fe);
for (i = 0; i < ARRAY_SIZE(init_tab); i++)
s5h1411_writereg(state, init_tab[i].addr,
init_tab[i].reg,
init_tab[i].data);
/* The datasheet says that after initialisation, VSB is default */
state->current_modulation = VSB_8;
if (state->config->output_mode == S5H1411_SERIAL_OUTPUT)
/* Serial */
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, 0x1101);
else
/* Parallel */
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, 0x1001);
s5h1411_set_spectralinversion(fe, state->config->inversion);
s5h1411_set_if_freq(fe, state->config->vsb_if);
s5h1411_set_gpio(fe, state->config->gpio);
s5h1411_set_mpeg_timing(fe, state->config->mpeg_timing);
s5h1411_softreset(fe);
/* Note: Leaving the I2C gate closed. */
s5h1411_i2c_gate_ctrl(fe, 0);
return 0;
}
static int s5h1411_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct s5h1411_state *state = fe->demodulator_priv;
u16 reg;
u32 tuner_status = 0;
*status = 0;
/* Get the demodulator status */
reg = (s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2) >> 15)
& 0x0001;
if (reg)
*status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_SIGNAL;
switch (state->current_modulation) {
case QAM_64:
case QAM_256:
reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf0);
if (reg & 0x100)
*status |= FE_HAS_VITERBI;
if (reg & 0x10)
*status |= FE_HAS_SYNC;
break;
case VSB_8:
reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x5e);
if (reg & 0x0001)
*status |= FE_HAS_SYNC;
reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2);
if (reg & 0x1000)
*status |= FE_HAS_VITERBI;
break;
default:
return -EINVAL;
}
switch (state->config->status_mode) {
case S5H1411_DEMODLOCKING:
if (*status & FE_HAS_VITERBI)
*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
break;
case S5H1411_TUNERLOCKING:
/* Get the tuner status */
if (fe->ops.tuner_ops.get_status) {
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
fe->ops.tuner_ops.get_status(fe, &tuner_status);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
if (tuner_status)
*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
break;
}
dprintk("%s() status 0x%08x\n", __func__, *status);
return 0;
}
static int s5h1411_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
{
int i, ret = -EINVAL;
dprintk("%s()\n", __func__);
for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
if (v < qam256_snr_tab[i].val) {
*snr = qam256_snr_tab[i].data;
ret = 0;
break;
}
}
return ret;
}
static int s5h1411_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
{
int i, ret = -EINVAL;
dprintk("%s()\n", __func__);
for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
if (v < qam64_snr_tab[i].val) {
*snr = qam64_snr_tab[i].data;
ret = 0;
break;
}
}
return ret;
}
static int s5h1411_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
{
int i, ret = -EINVAL;
dprintk("%s()\n", __func__);
for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
if (v > vsb_snr_tab[i].val) {
*snr = vsb_snr_tab[i].data;
ret = 0;
break;
}
}
dprintk("%s() snr=%d\n", __func__, *snr);
return ret;
}
static int s5h1411_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct s5h1411_state *state = fe->demodulator_priv;
u16 reg;
dprintk("%s()\n", __func__);
switch (state->current_modulation) {
case QAM_64:
reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1);
return s5h1411_qam64_lookup_snr(fe, snr, reg);
case QAM_256:
reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1);
return s5h1411_qam256_lookup_snr(fe, snr, reg);
case VSB_8:
reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR,
0xf2) & 0x3ff;
return s5h1411_vsb_lookup_snr(fe, snr, reg);
default:
break;
}
return -EINVAL;
}
static int s5h1411_read_signal_strength(struct dvb_frontend *fe,
u16 *signal_strength)
{
return s5h1411_read_snr(fe, signal_strength);
}
static int s5h1411_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
struct s5h1411_state *state = fe->demodulator_priv;
*ucblocks = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xc9);
return 0;
}
static int s5h1411_read_ber(struct dvb_frontend *fe, u32 *ber)
{
return s5h1411_read_ucblocks(fe, ber);
}
static int s5h1411_get_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct s5h1411_state *state = fe->demodulator_priv;
p->frequency = state->current_frequency;
p->u.vsb.modulation = state->current_modulation;
return 0;
}
static int s5h1411_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *tune)
{
tune->min_delay_ms = 1000;
return 0;
}
static void s5h1411_release(struct dvb_frontend *fe)
{
struct s5h1411_state *state = fe->demodulator_priv;
kfree(state);
}
static struct dvb_frontend_ops s5h1411_ops;
struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config,
struct i2c_adapter *i2c)
{
struct s5h1411_state *state = NULL;
u16 reg;
/* allocate memory for the internal state */
state = kmalloc(sizeof(struct s5h1411_state), GFP_KERNEL);
if (state == NULL)
goto error;
/* setup the state */
state->config = config;
state->i2c = i2c;
state->current_modulation = VSB_8;
state->inversion = state->config->inversion;
/* check if the demod exists */
reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x05);
if (reg != 0x0066)
goto error;
/* create dvb_frontend */
memcpy(&state->frontend.ops, &s5h1411_ops,
sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
if (s5h1411_init(&state->frontend) != 0) {
printk(KERN_ERR "%s: Failed to initialize correctly\n",
__func__);
goto error;
}
/* Note: Leaving the I2C gate open here. */
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1);
return &state->frontend;
error:
kfree(state);
return NULL;
}
EXPORT_SYMBOL(s5h1411_attach);
static struct dvb_frontend_ops s5h1411_ops = {
.info = {
.name = "Samsung S5H1411 QAM/8VSB Frontend",
.type = FE_ATSC,
.frequency_min = 54000000,
.frequency_max = 858000000,
.frequency_stepsize = 62500,
.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
},
.init = s5h1411_init,
.i2c_gate_ctrl = s5h1411_i2c_gate_ctrl,
.set_frontend = s5h1411_set_frontend,
.get_frontend = s5h1411_get_frontend,
.get_tune_settings = s5h1411_get_tune_settings,
.read_status = s5h1411_read_status,
.read_ber = s5h1411_read_ber,
.read_signal_strength = s5h1411_read_signal_strength,
.read_snr = s5h1411_read_snr,
.read_ucblocks = s5h1411_read_ucblocks,
.release = s5h1411_release,
};
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Enable verbose debug messages");
MODULE_DESCRIPTION("Samsung S5H1411 QAM-B/ATSC Demodulator driver");
MODULE_AUTHOR("Steven Toth");
MODULE_LICENSE("GPL");
/*
* Local variables:
* c-basic-offset: 8
*/

View file

@ -0,0 +1,90 @@
/*
Samsung S5H1411 VSB/QAM demodulator driver
Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __S5H1411_H__
#define __S5H1411_H__
#include <linux/dvb/frontend.h>
#define S5H1411_I2C_TOP_ADDR (0x32 >> 1)
#define S5H1411_I2C_QAM_ADDR (0x34 >> 1)
struct s5h1411_config {
/* serial/parallel output */
#define S5H1411_PARALLEL_OUTPUT 0
#define S5H1411_SERIAL_OUTPUT 1
u8 output_mode;
/* GPIO Setting */
#define S5H1411_GPIO_OFF 0
#define S5H1411_GPIO_ON 1
u8 gpio;
/* MPEG signal timing */
#define S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0
#define S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1
#define S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2
#define S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
u16 mpeg_timing;
/* IF Freq for QAM and VSB in KHz */
#define S5H1411_IF_2500 2500
#define S5H1411_IF_3500 3500
#define S5H1411_IF_4000 4000
#define S5H1411_IF_5380 5380
#define S5H1411_IF_44000 44000
#define S5H1411_VSB_IF_DEFAULT S5H1411_IF_44000
#define S5H1411_QAM_IF_DEFAULT S5H1411_IF_44000
u16 qam_if;
u16 vsb_if;
/* Spectral Inversion */
#define S5H1411_INVERSION_OFF 0
#define S5H1411_INVERSION_ON 1
u8 inversion;
/* Return lock status based on tuner lock, or demod lock */
#define S5H1411_TUNERLOCKING 0
#define S5H1411_DEMODLOCKING 1
u8 status_mode;
};
#if defined(CONFIG_DVB_S5H1411) || \
(defined(CONFIG_DVB_S5H1411_MODULE) && defined(MODULE))
extern struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config,
struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend *s5h1411_attach(
const struct s5h1411_config *config,
struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif /* CONFIG_DVB_S5H1411 */
#endif /* __S5H1411_H__ */
/*
* Local variables:
* c-basic-offset: 8
*/

View file

@ -1,7 +1,7 @@
config VIDEO_AU0828
tristate "Auvitek AU0828 support"
depends on VIDEO_DEV && I2C && INPUT
depends on VIDEO_DEV && I2C && INPUT && DVB_CORE
select I2C_ALGOBIT
select DVB_AU8522 if !DVB_FE_CUSTOMIZE
select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE

View file

@ -36,7 +36,6 @@ struct au0828_board au0828_boards[] = {
.name = "DViCO FusionHDTV USB",
},
};
const unsigned int au0828_bcount = ARRAY_SIZE(au0828_boards);
/* Tuner callback function for au0828 boards. Currently only needed
* for HVR1500Q, which has an xc5000 tuner.

View file

@ -32,18 +32,10 @@
* 4 = I2C related
* 8 = Bridge related
*/
unsigned int debug;
module_param(debug, int, 0644);
int au0828_debug;
module_param_named(debug, au0828_debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages");
unsigned int usb_debug;
module_param(usb_debug, int, 0644);
MODULE_PARM_DESC(usb_debug, "enable usb debug messages");
unsigned int bridge_debug;
module_param(bridge_debug, int, 0644);
MODULE_PARM_DESC(bridge_debug, "enable bridge debug messages");
#define _AU0828_BULKPIPE 0x03
#define _BULKPIPESIZE 0xffff
@ -229,24 +221,18 @@ static int __init au0828_init(void)
{
int ret;
if (debug)
if (au0828_debug & 1)
printk(KERN_INFO "%s() Debugging is enabled\n", __func__);
if (usb_debug) {
if (au0828_debug & 2)
printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__);
debug |= 2;
}
if (i2c_debug) {
if (au0828_debug & 4)
printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__);
debug |= 4;
}
if (bridge_debug) {
if (au0828_debug & 8)
printk(KERN_INFO "%s() Bridge Debugging is enabled\n",
__func__);
debug |= 8;
}
printk(KERN_INFO "au0828 driver loaded\n");

View file

@ -204,7 +204,7 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
return ret;
}
int dvb_register(struct au0828_dev *dev)
static int dvb_register(struct au0828_dev *dev)
{
struct au0828_dvb *dvb = &dev->dvb;
int result;

View file

@ -29,11 +29,7 @@
#include <media/v4l2-common.h>
unsigned int i2c_debug;
module_param(i2c_debug, int, 0444);
MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
unsigned int i2c_scan;
static int i2c_scan;
module_param(i2c_scan, int, 0444);
MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");

View file

@ -96,15 +96,12 @@ struct au0828_buff {
/* au0828-core.c */
extern u32 au0828_read(struct au0828_dev *dev, u16 reg);
extern u32 au0828_write(struct au0828_dev *dev, u16 reg, u32 val);
extern unsigned int debug;
extern unsigned int usb_debug;
extern unsigned int bridge_debug;
extern int au0828_debug;
/* ----------------------------------------------------------- */
/* au0828-cards.c */
extern struct au0828_board au0828_boards[];
extern struct usb_device_id au0828_usb_id_table[];
extern const unsigned int au0828_bcount;
extern void au0828_gpio_setup(struct au0828_dev *dev);
extern int au0828_tuner_callback(void *priv, int command, int arg);
extern void au0828_card_setup(struct au0828_dev *dev);
@ -115,7 +112,6 @@ extern int au0828_i2c_register(struct au0828_dev *dev);
extern int au0828_i2c_unregister(struct au0828_dev *dev);
extern void au0828_call_i2c_clients(struct au0828_dev *dev,
unsigned int cmd, void *arg);
extern unsigned int i2c_debug;
/* ----------------------------------------------------------- */
/* au0828-dvb.c */
@ -123,6 +119,6 @@ extern int au0828_dvb_register(struct au0828_dev *dev);
extern void au0828_dvb_unregister(struct au0828_dev *dev);
#define dprintk(level, fmt, arg...)\
do { if (debug & level)\
do { if (au0828_debug & level)\
printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
} while (0)

View file

@ -58,6 +58,7 @@ config VIDEO_CX88_DVB
select DVB_CX24123 if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB/ATSC cards based on the
Conexant 2388x chip.

View file

@ -546,10 +546,12 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
if (retval < 0)
return retval;
dev->mailbox = blackbird_find_mailbox(dev);
if (dev->mailbox < 0)
retval = blackbird_find_mailbox(dev);
if (retval < 0)
return -1;
dev->mailbox = retval;
retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
if (retval < 0) {
dprintk(0, "ERROR: Firmware ping failed!\n");

View file

@ -1591,6 +1591,7 @@ static const struct cx88_board cx88_boards[] = {
.vmux = 2,
.gpio0 = 0x16d9,
}},
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_PROLINK_PV_8000GT] = {
.name = "Prolink Pixelview MPEG 8000GT",

View file

@ -47,6 +47,7 @@
#include "isl6421.h"
#include "tuner-simple.h"
#include "tda9887.h"
#include "s5h1411.h"
MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@ -463,6 +464,22 @@ static struct zl10353_config cx88_geniatech_x8000_mt = {
.no_tuner = 1,
};
static struct s5h1411_config dvico_fusionhdtv7_config = {
.output_mode = S5H1411_SERIAL_OUTPUT,
.gpio = S5H1411_GPIO_ON,
.mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
.qam_if = S5H1411_IF_44000,
.vsb_if = S5H1411_IF_44000,
.inversion = S5H1411_INVERSION_OFF,
.status_mode = S5H1411_DEMODLOCKING
};
static struct xc5000_config dvico_fusionhdtv7_tuner_config = {
.i2c_address = 0xc2 >> 1,
.if_khz = 5380,
.tuner_callback = cx88_tuner_callback,
};
static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
{
struct dvb_frontend *fe;
@ -844,6 +861,21 @@ static int dvb_register(struct cx8802_dev *dev)
if (attach_xc3028(0x61, dev) < 0)
return -EINVAL;
break;
case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
dev->dvb.frontend = dvb_attach(s5h1411_attach,
&dvico_fusionhdtv7_config,
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
/* tuner_config.video_dev must point to
* i2c_adap.algo_data
*/
dvico_fusionhdtv7_tuner_config.priv =
dev->core->i2c_adap.algo_data;
dvb_attach(xc5000_attach, dev->dvb.frontend,
&dev->core->i2c_adap,
&dvico_fusionhdtv7_tuner_config);
}
break;
default:
printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
dev->core->name);

View file

@ -650,7 +650,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
GFP_KERNEL);
if (!dev->isoc_ctl.urb) {
if (!dev->isoc_ctl.transfer_buffer) {
em28xx_errdev("cannot allocate memory for usbtransfer\n");
kfree(dev->isoc_ctl.urb);
return -ENOMEM;

View file

@ -509,8 +509,11 @@ static int ir_probe(struct i2c_adapter *adap)
static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 };
static const int probe_cx23885[] = { 0x6b, -1 };
const int *probe;
struct i2c_client *c;
unsigned char buf;
struct i2c_msg msg = {
.flags = I2C_M_RD,
.len = 0,
.buf = NULL,
};
int i, rc;
switch (adap->id) {
@ -536,23 +539,17 @@ static int ir_probe(struct i2c_adapter *adap)
return 0;
}
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
return -ENOMEM;
c->adapter = adap;
for (i = 0; -1 != probe[i]; i++) {
c->addr = probe[i];
rc = i2c_master_recv(c, &buf, 0);
msg.addr = probe[i];
rc = i2c_transfer(adap, &msg, 1);
dprintk(1,"probe 0x%02x @ %s: %s\n",
probe[i], adap->name,
(0 == rc) ? "yes" : "no");
if (0 == rc) {
(1 == rc) ? "yes" : "no");
if (1 == rc) {
ir_attach(adap, probe[i], 0, 0);
break;
}
}
kfree(c);
return 0;
}

View file

@ -64,6 +64,7 @@ config VIDEO_PVRUSB2_DVB
depends on VIDEO_PVRUSB2 && DVB_CORE && EXPERIMENTAL
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_S5H1409 if !DVB_FE_CUSTOMISE
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
select DVB_TDA18271 if !DVB_FE_CUSTOMIZE
select TUNER_SIMPLE if !DVB_FE_CUSTOMISE

View file

@ -36,6 +36,7 @@ pvr2_device_desc structures.
#include "pvrusb2-hdw-internal.h"
#include "lgdt330x.h"
#include "s5h1409.h"
#include "s5h1411.h"
#include "tda10048.h"
#include "tda18271.h"
#include "tda8290.h"
@ -368,6 +369,15 @@ static struct s5h1409_config pvr2_s5h1409_config = {
.status_mode = S5H1409_DEMODLOCKING,
};
static struct s5h1411_config pvr2_s5h1411_config = {
.output_mode = S5H1411_PARALLEL_OUTPUT,
.gpio = S5H1411_GPIO_OFF,
.vsb_if = S5H1411_IF_44000,
.qam_if = S5H1411_IF_4000,
.inversion = S5H1411_INVERSION_ON,
.status_mode = S5H1411_DEMODLOCKING,
};
static struct tda18271_std_map hauppauge_tda18271_std_map = {
.atsc_6 = { .if_freq = 5380, .agc_mode = 3, .std = 3,
.if_lvl = 6, .rfagc_top = 0x37, },
@ -390,6 +400,16 @@ static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap)
return -EIO;
}
static int pvr2_s5h1411_attach(struct pvr2_dvb_adapter *adap)
{
adap->fe = dvb_attach(s5h1411_attach, &pvr2_s5h1411_config,
&adap->channel.hdw->i2c_adap);
if (adap->fe)
return 0;
return -EIO;
}
static int pvr2_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
{
dvb_attach(tda829x_attach, adap->fe,
@ -406,6 +426,11 @@ struct pvr2_dvb_props pvr2_750xx_dvb_props = {
.frontend_attach = pvr2_s5h1409_attach,
.tuner_attach = pvr2_tda18271_8295_attach,
};
struct pvr2_dvb_props pvr2_751xx_dvb_props = {
.frontend_attach = pvr2_s5h1411_attach,
.tuner_attach = pvr2_tda18271_8295_attach,
};
#endif
static const char *pvr2_client_75xxx[] = {
@ -454,6 +479,9 @@ static const struct pvr2_device_desc pvr2_device_751xx = {
.digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
.default_std_mask = V4L2_STD_NTSC_M,
.led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
#ifdef CONFIG_VIDEO_PVRUSB2_DVB
.dvb_props = &pvr2_751xx_dvb_props,
#endif
};

View file

@ -104,28 +104,28 @@ struct pvr2_device_desc {
unsigned char digital_control_scheme;
/* If set, we don't bother trying to load cx23416 firmware. */
int flag_skip_cx23416_firmware:1;
unsigned int flag_skip_cx23416_firmware:1;
/* If set, the encoder must be healthy in order for digital mode to
work (otherwise we assume that digital streaming will work even
if we fail to locate firmware for the encoder). If the device
doesn't support digital streaming then this flag has no
effect. */
int flag_digital_requires_cx23416:1;
unsigned int flag_digital_requires_cx23416:1;
/* Device has a hauppauge eeprom which we can interrogate. */
int flag_has_hauppauge_rom:1;
unsigned int flag_has_hauppauge_rom:1;
/* Device does not require a powerup command to be issued. */
int flag_no_powerup:1;
unsigned int flag_no_powerup:1;
/* Device has a cx25840 - this enables special additional logic to
handle it. */
int flag_has_cx25840:1;
unsigned int flag_has_cx25840:1;
/* Device has a wm8775 - this enables special additional logic to
ensure that it is found. */
int flag_has_wm8775:1;
unsigned int flag_has_wm8775:1;
/* Device has IR hardware that can be faked into looking like a
normal Hauppauge i2c IR receiver. This is currently very
@ -135,15 +135,15 @@ struct pvr2_device_desc {
to virtualize the presence of the non-existant IR receiver chip and
implement the virtual receiver in terms of appropriate FX2
commands. */
int flag_has_hauppauge_custom_ir:1;
unsigned int flag_has_hauppauge_custom_ir:1;
/* These bits define which kinds of sources the device can handle.
Note: Digital tuner presence is inferred by the
digital_control_scheme enumeration. */
int flag_has_fmradio:1; /* Has FM radio receiver */
int flag_has_analogtuner:1; /* Has analog tuner */
int flag_has_composite:1; /* Has composite input */
int flag_has_svideo:1; /* Has s-video input */
unsigned int flag_has_fmradio:1; /* Has FM radio receiver */
unsigned int flag_has_analogtuner:1; /* Has analog tuner */
unsigned int flag_has_composite:1; /* Has composite input */
unsigned int flag_has_svideo:1; /* Has s-video input */
};
extern struct usb_device_id pvr2_device_table[];

View file

@ -369,19 +369,13 @@ static void set_type(struct i2c_client *c, unsigned int type,
break;
}
case TUNER_TEA5767:
if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
t->type = TUNER_ABSENT;
t->mode_mask = T_UNINITIALIZED;
return;
}
if (!tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr))
goto attach_failed;
t->mode_mask = T_RADIO;
break;
case TUNER_TEA5761:
if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
t->type = TUNER_ABSENT;
t->mode_mask = T_UNINITIALIZED;
return;
}
if (!tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr))
goto attach_failed;
t->mode_mask = T_RADIO;
break;
case TUNER_PHILIPS_FMD1216ME_MK3:
@ -394,12 +388,9 @@ static void set_type(struct i2c_client *c, unsigned int type,
buffer[2] = 0x86;
buffer[3] = 0x54;
i2c_master_send(c, buffer, 4);
if (simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr,
t->type) == NULL) {
t->type = TUNER_ABSENT;
t->mode_mask = T_UNINITIALIZED;
return;
}
if (!simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr,
t->type))
goto attach_failed;
break;
case TUNER_PHILIPS_TD1316:
buffer[0] = 0x0b;
@ -407,12 +398,9 @@ static void set_type(struct i2c_client *c, unsigned int type,
buffer[2] = 0x86;
buffer[3] = 0xa4;
i2c_master_send(c,buffer,4);
if (simple_tuner_attach(&t->fe, t->i2c->adapter,
t->i2c->addr, t->type) == NULL) {
t->type = TUNER_ABSENT;
t->mode_mask = T_UNINITIALIZED;
return;
}
if (!simple_tuner_attach(&t->fe, t->i2c->adapter,
t->i2c->addr, t->type))
goto attach_failed;
break;
case TUNER_XC2028:
{
@ -421,40 +409,34 @@ static void set_type(struct i2c_client *c, unsigned int type,
.i2c_addr = t->i2c->addr,
.callback = t->tuner_callback,
};
if (!xc2028_attach(&t->fe, &cfg)) {
t->type = TUNER_ABSENT;
t->mode_mask = T_UNINITIALIZED;
return;
}
if (!xc2028_attach(&t->fe, &cfg))
goto attach_failed;
break;
}
case TUNER_TDA9887:
tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
break;
case TUNER_XC5000:
{
struct dvb_tuner_ops *xc_tuner_ops;
xc5000_cfg.i2c_address = t->i2c->addr;
xc5000_cfg.if_khz = 5380;
xc5000_cfg.priv = c->adapter->algo_data;
xc5000_cfg.tuner_callback = t->tuner_callback;
if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) {
t->type = TUNER_ABSENT;
t->mode_mask = T_UNINITIALIZED;
return;
}
{
struct dvb_tuner_ops *xc_tuner_ops;
if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg))
goto attach_failed;
xc_tuner_ops = &t->fe.ops.tuner_ops;
if(xc_tuner_ops->init != NULL)
if (xc_tuner_ops->init)
xc_tuner_ops->init(&t->fe);
}
break;
}
default:
if (simple_tuner_attach(&t->fe, t->i2c->adapter,
t->i2c->addr, t->type) == NULL) {
t->type = TUNER_ABSENT;
t->mode_mask = T_UNINITIALIZED;
return;
}
if (!simple_tuner_attach(&t->fe, t->i2c->adapter,
t->i2c->addr, t->type))
goto attach_failed;
break;
}
@ -476,11 +458,27 @@ static void set_type(struct i2c_client *c, unsigned int type,
if (t->mode_mask == T_UNINITIALIZED)
t->mode_mask = new_mode_mask;
set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq);
/* xc2028/3028 and xc5000 requires a firmware to be set-up later
trying to set a frequency here will just fail
FIXME: better to move set_freq to the tuner code. This is needed
on analog tuners for PLL to properly work
*/
if (t->type != TUNER_XC2028 && t->type != TUNER_XC5000)
set_freq(c, (V4L2_TUNER_RADIO == t->mode) ?
t->radio_freq : t->tv_freq);
tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
c->adapter->name, c->driver->driver.name, c->addr << 1, type,
t->mode_mask);
tuner_i2c_address_check(t);
return;
attach_failed:
tuner_dbg("Tuner attach for type = %d failed.\n", t->type);
t->type = TUNER_ABSENT;
t->mode_mask = T_UNINITIALIZED;
return;
}
/*
@ -495,14 +493,16 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
{
struct tuner *t = i2c_get_clientdata(c);
tuner_dbg("set addr for type %i\n", t->type);
if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
(t->mode_mask & tun_setup->mode_mask))) ||
(tun_setup->addr == c->addr)) {
set_type(c, tun_setup->type, tun_setup->mode_mask,
tun_setup->config, tun_setup->tuner_callback);
}
} else
tuner_dbg("set addr discarded for type %i, mask %x. "
"Asked to change tuner at addr 0x%02x, with mask %x\n",
t->type, t->mode_mask,
tun_setup->addr, tun_setup->mode_mask);
}
static inline int check_mode(struct tuner *t, char *cmd)

View file

@ -432,7 +432,7 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
type &= type_mask;
if (!type & SCODE)
if (!(type & SCODE))
type_mask = ~0;
/* Seek for exact match */

View file

@ -888,7 +888,7 @@ static int vivi_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
struct vivi_dev *dev;
struct vivi_fh *fh;
struct vivi_fh *fh = NULL;
int i;
int retval = 0;