mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (583 commits) V4L/DVB (10130): use USB API functions rather than constants V4L/DVB (10129): dvb: remove deprecated use of RW_LOCK_UNLOCKED in frontends V4L/DVB (10128): modify V4L documentation to be a valid XHTML V4L/DVB (10127): stv06xx: Avoid having y unitialized V4L/DVB (10125): em28xx: Don't do AC97 vendor detection for i2s audio devices V4L/DVB (10124): em28xx: expand output formats available V4L/DVB (10123): em28xx: fix reversed definitions of I2S audio modes V4L/DVB (10122): em28xx: don't load em28xx-alsa for em2870 based devices V4L/DVB (10121): em28xx: remove worthless Pinnacle PCTV HD Mini 80e device profile V4L/DVB (10120): em28xx: remove redundant Pinnacle Dazzle DVC 100 profile V4L/DVB (10119): em28xx: fix corrupted XCLK value V4L/DVB (10118): zoran: fix warning for a variable not used V4L/DVB (10116): af9013: Fix gcc false warnings V4L/DVB (10111a): usbvideo.h: remove an useless blank line V4L/DVB (10111): quickcam_messenger.c: fix a warning V4L/DVB (10110): v4l2-ioctl: Fix warnings when using .unlocked_ioctl = __video_ioctl2 V4L/DVB (10109): anysee: Fix usage of an unitialized function V4L/DVB (10104): uvcvideo: Add support for video output devices V4L/DVB (10102): uvcvideo: Ignore interrupt endpoint for built-in iSight webcams. V4L/DVB (10101): uvcvideo: Fix bulk URB processing when the header is erroneous ...
This commit is contained in:
commit
f54a6ec0fd
326 changed files with 38108 additions and 11079 deletions
|
|
@ -2391,6 +2391,67 @@ IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE] = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_powercolor_real_angel);
|
||||
|
||||
/* Kworld Plus TV Analog Lite PCI IR
|
||||
Mauro Carvalho Chehab <mchehab@infradead.org>
|
||||
*/
|
||||
IR_KEYTAB_TYPE ir_codes_kworld_plus_tv_analog[IR_KEYTAB_SIZE] = {
|
||||
[0x0c] = KEY_PROG1, /* Kworld key */
|
||||
[0x16] = KEY_CLOSECD, /* -> ) */
|
||||
[0x1d] = KEY_POWER2,
|
||||
|
||||
[0x00] = KEY_1,
|
||||
[0x01] = KEY_2,
|
||||
[0x02] = KEY_3, /* Two keys have the same code: 3 and left */
|
||||
[0x03] = KEY_4, /* Two keys have the same code: 3 and right */
|
||||
[0x04] = KEY_5,
|
||||
[0x05] = KEY_6,
|
||||
[0x06] = KEY_7,
|
||||
[0x07] = KEY_8,
|
||||
[0x08] = KEY_9,
|
||||
[0x0a] = KEY_0,
|
||||
|
||||
[0x09] = KEY_AGAIN,
|
||||
[0x14] = KEY_MUTE,
|
||||
|
||||
[0x20] = KEY_UP,
|
||||
[0x21] = KEY_DOWN,
|
||||
[0x0b] = KEY_ENTER,
|
||||
|
||||
[0x10] = KEY_CHANNELUP,
|
||||
[0x11] = KEY_CHANNELDOWN,
|
||||
|
||||
/* Couldn't map key left/key right since those
|
||||
conflict with '3' and '4' scancodes
|
||||
I dunno what the original driver does
|
||||
*/
|
||||
|
||||
[0x13] = KEY_VOLUMEUP,
|
||||
[0x12] = KEY_VOLUMEDOWN,
|
||||
|
||||
/* The lower part of the IR
|
||||
There are several duplicated keycodes there.
|
||||
Most of them conflict with digits.
|
||||
Add mappings just to the unused scancodes.
|
||||
Somehow, the original driver has a way to know,
|
||||
but this doesn't seem to be on some GPIO.
|
||||
Also, it is not related to the time between keyup
|
||||
and keydown.
|
||||
*/
|
||||
[0x19] = KEY_PAUSE, /* Timeshift */
|
||||
[0x1a] = KEY_STOP,
|
||||
[0x1b] = KEY_RECORD,
|
||||
|
||||
[0x22] = KEY_TEXT,
|
||||
|
||||
[0x15] = KEY_AUDIO, /* ((*)) */
|
||||
[0x0f] = KEY_ZOOM,
|
||||
[0x1c] = KEY_SHUFFLE, /* snapshot */
|
||||
|
||||
[0x18] = KEY_RED, /* B */
|
||||
[0x23] = KEY_GREEN, /* C */
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_kworld_plus_tv_analog);
|
||||
|
||||
IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE] = {
|
||||
[0x20] = KEY_LIST,
|
||||
[0x00] = KEY_POWER,
|
||||
|
|
@ -2511,3 +2572,35 @@ IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE] = {
|
|||
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_real_audio_220_32_keys);
|
||||
|
||||
/* ATI TV Wonder HD 600 USB
|
||||
Devin Heitmueller <devin.heitmueller@gmail.com>
|
||||
*/
|
||||
IR_KEYTAB_TYPE ir_codes_ati_tv_wonder_hd_600[IR_KEYTAB_SIZE] = {
|
||||
[0x00] = KEY_RECORD, /* Row 1 */
|
||||
[0x01] = KEY_PLAYPAUSE,
|
||||
[0x02] = KEY_STOP,
|
||||
[0x03] = KEY_POWER,
|
||||
[0x04] = KEY_PREVIOUS, /* Row 2 */
|
||||
[0x05] = KEY_REWIND,
|
||||
[0x06] = KEY_FORWARD,
|
||||
[0x07] = KEY_NEXT,
|
||||
[0x08] = KEY_EPG, /* Row 3 */
|
||||
[0x09] = KEY_HOME,
|
||||
[0x0a] = KEY_MENU,
|
||||
[0x0b] = KEY_CHANNELUP,
|
||||
[0x0c] = KEY_BACK, /* Row 4 */
|
||||
[0x0d] = KEY_UP,
|
||||
[0x0e] = KEY_INFO,
|
||||
[0x0f] = KEY_CHANNELDOWN,
|
||||
[0x10] = KEY_LEFT, /* Row 5 */
|
||||
[0x11] = KEY_SELECT,
|
||||
[0x12] = KEY_RIGHT,
|
||||
[0x13] = KEY_VOLUMEUP,
|
||||
[0x14] = KEY_LAST, /* Row 6 */
|
||||
[0x15] = KEY_DOWN,
|
||||
[0x16] = KEY_MUTE,
|
||||
[0x17] = KEY_VOLUMEDOWN,
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL_GPL(ir_codes_ati_tv_wonder_hd_600);
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ static int fops_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
|
|||
/*
|
||||
DEB_EE(("inode:%p, file:%p, cmd:%d, arg:%li\n",inode, file, cmd, arg));
|
||||
*/
|
||||
return video_usercopy(inode, file, cmd, arg, saa7146_video_do_ioctl);
|
||||
return video_usercopy(file, cmd, arg, saa7146_video_do_ioctl);
|
||||
}
|
||||
|
||||
static int fops_mmap(struct file *file, struct vm_area_struct * vma)
|
||||
|
|
|
|||
|
|
@ -834,7 +834,7 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
|
|||
* copying is done already, arg is a kernel pointer.
|
||||
*/
|
||||
|
||||
static int __saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
||||
int saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
||||
{
|
||||
struct saa7146_fh *fh = file->private_data;
|
||||
struct saa7146_dev *dev = fh->dev;
|
||||
|
|
@ -1216,17 +1216,11 @@ static int __saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *a
|
|||
#endif
|
||||
default:
|
||||
return v4l_compat_translate_ioctl(file, cmd, arg,
|
||||
__saa7146_video_do_ioctl);
|
||||
saa7146_video_do_ioctl);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int saa7146_video_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
{
|
||||
return __saa7146_video_do_ioctl(file, cmd, arg);
|
||||
}
|
||||
|
||||
/*********************************************************************************/
|
||||
/* buffer handling functions */
|
||||
|
||||
|
|
|
|||
|
|
@ -3598,7 +3598,7 @@ static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum,
|
|||
76, 77, 91, 134, 135, 137, 147,
|
||||
156, 166, 167, 168, 25 };
|
||||
|
||||
*count = sizeof(RegAddr) / sizeof(u8);
|
||||
*count = ARRAY_SIZE(RegAddr);
|
||||
|
||||
status += MXL_BlockInit(fe);
|
||||
|
||||
|
|
@ -3630,7 +3630,7 @@ static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal,
|
|||
*/
|
||||
#endif
|
||||
|
||||
*count = sizeof(RegAddr) / sizeof(u8);
|
||||
*count = ARRAY_SIZE(RegAddr);
|
||||
|
||||
for (i = 0 ; i < *count; i++) {
|
||||
RegNum[i] = RegAddr[i];
|
||||
|
|
@ -3648,7 +3648,7 @@ static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum,
|
|||
|
||||
u8 RegAddr[] = {43, 136};
|
||||
|
||||
*count = sizeof(RegAddr) / sizeof(u8);
|
||||
*count = ARRAY_SIZE(RegAddr);
|
||||
|
||||
for (i = 0; i < *count; i++) {
|
||||
RegNum[i] = RegAddr[i];
|
||||
|
|
|
|||
|
|
@ -80,10 +80,11 @@ static void tda827x_set_std(struct dvb_frontend *fe,
|
|||
mode = "xx";
|
||||
}
|
||||
|
||||
if (params->mode == V4L2_TUNER_RADIO)
|
||||
if (params->mode == V4L2_TUNER_RADIO) {
|
||||
priv->sgIF = 88; /* if frequency is 5.5 MHz */
|
||||
|
||||
dprintk("setting tda827x to system %s\n", mode);
|
||||
dprintk("setting tda827x to radio FM\n");
|
||||
} else
|
||||
dprintk("setting tda827x to system %s\n", mode);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -199,7 +200,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
|
|||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(priv->i2c_adap, &msg, 1);
|
||||
|
||||
priv->frequency = tuner_freq - if_freq; // FIXME
|
||||
priv->frequency = params->frequency;
|
||||
priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
|
||||
|
||||
return 0;
|
||||
|
|
@ -304,7 +305,7 @@ static int tda827xo_set_analog_params(struct dvb_frontend *fe,
|
|||
reg2[1] = 0x08; /* Vsync en */
|
||||
i2c_transfer(priv->i2c_adap, &msg, 1);
|
||||
|
||||
priv->frequency = freq * 62500;
|
||||
priv->frequency = params->frequency;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -591,7 +592,7 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
|
|||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(priv->i2c_adap, &msg, 1);
|
||||
|
||||
priv->frequency = tuner_freq - if_freq; // FIXME
|
||||
priv->frequency = params->frequency;
|
||||
priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
|
||||
|
||||
return 0;
|
||||
|
|
@ -691,7 +692,7 @@ static int tda827xa_set_analog_params(struct dvb_frontend *fe,
|
|||
tuner_reg[1] = 0x19 + (priv->lpsel << 1);
|
||||
i2c_transfer(priv->i2c_adap, &msg, 1);
|
||||
|
||||
priv->frequency = freq * 62500;
|
||||
priv->frequency = params->frequency;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ static int debug;
|
|||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "enable verbose debug messages");
|
||||
|
||||
static int deemphasis_50;
|
||||
MODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis");
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
struct tda8290_priv {
|
||||
|
|
@ -139,9 +142,34 @@ static void set_audio(struct dvb_frontend *fe,
|
|||
mode = "xx";
|
||||
}
|
||||
|
||||
tuner_dbg("setting tda829x to system %s\n", mode);
|
||||
if (params->mode == V4L2_TUNER_RADIO) {
|
||||
priv->tda8290_easy_mode = 0x01; /* Start with MN values */
|
||||
tuner_dbg("setting to radio FM\n");
|
||||
} else {
|
||||
tuner_dbg("setting tda829x to system %s\n", mode);
|
||||
}
|
||||
}
|
||||
|
||||
struct {
|
||||
unsigned char seq[2];
|
||||
} fm_mode[] = {
|
||||
{ { 0x01, 0x81} }, /* Put device into expert mode */
|
||||
{ { 0x03, 0x48} }, /* Disable NOTCH and VIDEO filters */
|
||||
{ { 0x04, 0x04} }, /* Disable color carrier filter (SSIF) */
|
||||
{ { 0x05, 0x04} }, /* ADC headroom */
|
||||
{ { 0x06, 0x10} }, /* group delay flat */
|
||||
|
||||
{ { 0x07, 0x00} }, /* use the same radio DTO values as a tda8295 */
|
||||
{ { 0x08, 0x00} },
|
||||
{ { 0x09, 0x80} },
|
||||
{ { 0x0a, 0xda} },
|
||||
{ { 0x0b, 0x4b} },
|
||||
{ { 0x0c, 0x68} },
|
||||
|
||||
{ { 0x0d, 0x00} }, /* PLL off, no video carrier detect */
|
||||
{ { 0x14, 0x00} }, /* disable auto mute if no video */
|
||||
};
|
||||
|
||||
static void tda8290_set_params(struct dvb_frontend *fe,
|
||||
struct analog_parameters *params)
|
||||
{
|
||||
|
|
@ -178,15 +206,30 @@ static void tda8290_set_params(struct dvb_frontend *fe,
|
|||
tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
|
||||
msleep(1);
|
||||
|
||||
expert_mode[1] = priv->tda8290_easy_mode + 0x80;
|
||||
tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
|
||||
tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
|
||||
tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
|
||||
if (priv->tda8290_easy_mode & 0x60)
|
||||
tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
|
||||
else
|
||||
tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
|
||||
tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
|
||||
if (params->mode == V4L2_TUNER_RADIO) {
|
||||
int i;
|
||||
unsigned char deemphasis[] = { 0x13, 1 };
|
||||
|
||||
/* FIXME: allow using a different deemphasis */
|
||||
|
||||
if (deemphasis_50)
|
||||
deemphasis[1] = 2;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fm_mode); i++)
|
||||
tuner_i2c_xfer_send(&priv->i2c_props, fm_mode[i].seq, 2);
|
||||
|
||||
tuner_i2c_xfer_send(&priv->i2c_props, deemphasis, 2);
|
||||
} else {
|
||||
expert_mode[1] = priv->tda8290_easy_mode + 0x80;
|
||||
tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
|
||||
tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
|
||||
tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
|
||||
if (priv->tda8290_easy_mode & 0x60)
|
||||
tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
|
||||
else
|
||||
tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
|
||||
tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
|
||||
}
|
||||
|
||||
tda8290_i2c_bridge(fe, 1);
|
||||
|
||||
|
|
|
|||
|
|
@ -180,11 +180,10 @@ static struct tvnorm tvnorms[] = {
|
|||
},{
|
||||
.std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
|
||||
.name = "SECAM-BGH",
|
||||
.b = ( cPositiveAmTV |
|
||||
.b = ( cNegativeFmTV |
|
||||
cQSS ),
|
||||
.c = ( cTopDefault),
|
||||
.e = ( cGating_36 |
|
||||
cAudioIF_5_5 |
|
||||
.e = ( cAudioIF_5_5 |
|
||||
cVideoIF_38_90 ),
|
||||
},{
|
||||
.std = V4L2_STD_SECAM_L,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,12 @@ static int debug;
|
|||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "enable verbose debug messages");
|
||||
|
||||
static int no_poweroff;
|
||||
module_param(no_poweroff, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "0 (default) powers device off when not used.\n"
|
||||
"1 keep device energized and with tuner ready all the times.\n"
|
||||
" Faster, but consumes more power and keeps the device hotter\n");
|
||||
|
||||
static char audio_std[8];
|
||||
module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
|
||||
MODULE_PARM_DESC(audio_std,
|
||||
|
|
@ -1091,6 +1097,34 @@ static int xc2028_set_params(struct dvb_frontend *fe,
|
|||
T_DIGITAL_TV, type, 0, demod);
|
||||
}
|
||||
|
||||
static int xc2028_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct xc2028_data *priv = fe->tuner_priv;
|
||||
int rc = 0;
|
||||
|
||||
/* Avoid firmware reload on slow devices */
|
||||
if (no_poweroff)
|
||||
return 0;
|
||||
|
||||
tuner_dbg("Putting xc2028/3028 into poweroff mode.\n");
|
||||
if (debug > 1) {
|
||||
tuner_dbg("Printing sleep stack trace:\n");
|
||||
dump_stack();
|
||||
}
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
if (priv->firm_version < 0x0202)
|
||||
rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00});
|
||||
else
|
||||
rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00});
|
||||
|
||||
priv->cur_fw.type = 0; /* need firmware reload */
|
||||
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int xc2028_dvb_release(struct dvb_frontend *fe)
|
||||
{
|
||||
|
|
@ -1171,6 +1205,7 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
|
|||
.get_frequency = xc2028_get_frequency,
|
||||
.get_rf_strength = xc2028_signal,
|
||||
.set_params = xc2028_set_params,
|
||||
.sleep = xc2028_sleep,
|
||||
};
|
||||
|
||||
struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
|
||||
|
|
|
|||
|
|
@ -36,10 +36,6 @@ static int debug;
|
|||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
|
||||
|
||||
static int xc5000_load_fw_on_attach;
|
||||
module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644);
|
||||
MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
|
||||
|
||||
static DEFINE_MUTEX(xc5000_list_mutex);
|
||||
static LIST_HEAD(hybrid_tuner_instance_list);
|
||||
|
||||
|
|
@ -1017,9 +1013,6 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
|
|||
memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
|
||||
sizeof(struct dvb_tuner_ops));
|
||||
|
||||
if (xc5000_load_fw_on_attach)
|
||||
xc5000_init(fe);
|
||||
|
||||
return fe;
|
||||
fail:
|
||||
mutex_unlock(&xc5000_list_mutex);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,19 @@
|
|||
# DVB device configuration
|
||||
#
|
||||
|
||||
config DVB_DYNAMIC_MINORS
|
||||
bool "Dynamic DVB minor allocation"
|
||||
depends on DVB_CORE
|
||||
default n
|
||||
help
|
||||
If you say Y here, the DVB subsystem will use dynamic minor
|
||||
allocation for any device that uses the DVB major number.
|
||||
This means that you can have more than 4 of a single type
|
||||
of device (like demuxes and frontends) per adapter, but udev
|
||||
will be required to manage the device nodes.
|
||||
|
||||
If you are unsure about this, say N here.
|
||||
|
||||
menuconfig DVB_CAPTURE_DRIVERS
|
||||
bool "DVB/ATSC adapters"
|
||||
depends on DVB_CORE
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ config DVB_B2C2_FLEXCOP
|
|||
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
|
||||
select DVB_CX24123 if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
|
||||
select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Support for the digital TV receiver chip made by B2C2 Inc. included in
|
||||
Technisats PCI cards and USB boxes.
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -368,7 +367,7 @@ static int __devinit dm1105dvb_dma_map(struct dm1105dvb *dm1105dvb)
|
|||
{
|
||||
dm1105dvb->ts_buf = pci_alloc_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, &dm1105dvb->dma_addr);
|
||||
|
||||
return pci_dma_mapping_error(dm1105dvb->pdev, dm1105dvb->dma_addr);
|
||||
return !dm1105dvb->ts_buf;
|
||||
}
|
||||
|
||||
static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb)
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ struct dvb_frontend_private {
|
|||
unsigned int step_size;
|
||||
int quality;
|
||||
unsigned int check_wrapped;
|
||||
enum dvbfe_search algo_status;
|
||||
};
|
||||
|
||||
static void dvb_frontend_wakeup(struct dvb_frontend *fe);
|
||||
|
|
@ -516,6 +517,8 @@ static int dvb_frontend_thread(void *data)
|
|||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
unsigned long timeout;
|
||||
fe_status_t s;
|
||||
enum dvbfe_algo algo;
|
||||
|
||||
struct dvb_frontend_parameters *params;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
|
@ -562,23 +565,80 @@ restart:
|
|||
|
||||
/* do an iteration of the tuning loop */
|
||||
if (fe->ops.get_frontend_algo) {
|
||||
if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) {
|
||||
/* have we been asked to retune? */
|
||||
params = NULL;
|
||||
algo = fe->ops.get_frontend_algo(fe);
|
||||
switch (algo) {
|
||||
case DVBFE_ALGO_HW:
|
||||
dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__);
|
||||
params = NULL; /* have we been asked to RETUNE ? */
|
||||
|
||||
if (fepriv->state & FESTATE_RETUNE) {
|
||||
dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
|
||||
params = &fepriv->parameters;
|
||||
fepriv->state = FESTATE_TUNED;
|
||||
}
|
||||
|
||||
fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
|
||||
if (s != fepriv->status) {
|
||||
if (fe->ops.tune)
|
||||
fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
|
||||
|
||||
if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
|
||||
dprintk("%s: state changed, adding current state\n", __func__);
|
||||
dvb_frontend_add_event(fe, s);
|
||||
fepriv->status = s;
|
||||
}
|
||||
} else
|
||||
break;
|
||||
case DVBFE_ALGO_SW:
|
||||
dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__);
|
||||
dvb_frontend_swzigzag(fe);
|
||||
} else
|
||||
break;
|
||||
case DVBFE_ALGO_CUSTOM:
|
||||
params = NULL; /* have we been asked to RETUNE ? */
|
||||
dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);
|
||||
if (fepriv->state & FESTATE_RETUNE) {
|
||||
dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);
|
||||
params = &fepriv->parameters;
|
||||
fepriv->state = FESTATE_TUNED;
|
||||
}
|
||||
/* Case where we are going to search for a carrier
|
||||
* User asked us to retune again for some reason, possibly
|
||||
* requesting a search with a new set of parameters
|
||||
*/
|
||||
if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
|
||||
if (fe->ops.search) {
|
||||
fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters);
|
||||
/* We did do a search as was requested, the flags are
|
||||
* now unset as well and has the flags wrt to search.
|
||||
*/
|
||||
} else {
|
||||
fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN;
|
||||
}
|
||||
}
|
||||
/* Track the carrier if the search was successful */
|
||||
if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) {
|
||||
if (fe->ops.track)
|
||||
fe->ops.track(fe, &fepriv->parameters);
|
||||
} else {
|
||||
fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
|
||||
fepriv->delay = HZ / 2;
|
||||
}
|
||||
fe->ops.read_status(fe, &s);
|
||||
if (s != fepriv->status) {
|
||||
dvb_frontend_add_event(fe, s); /* update event list */
|
||||
fepriv->status = s;
|
||||
if (!(s & FE_HAS_LOCK)) {
|
||||
fepriv->delay = HZ / 10;
|
||||
fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
|
||||
} else {
|
||||
fepriv->delay = 60 * HZ;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dprintk("%s: UNDEFINED ALGO !\n", __func__);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
dvb_frontend_swzigzag(fe);
|
||||
}
|
||||
}
|
||||
|
||||
if (dvb_powerdown_on_sleep) {
|
||||
|
|
@ -1226,6 +1286,9 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
|
|||
dprintk("%s() Finalised property cache\n", __func__);
|
||||
dtv_property_cache_submit(fe);
|
||||
|
||||
/* Request the search algorithm to search */
|
||||
fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
|
||||
|
||||
r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND,
|
||||
&fepriv->parameters);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -69,6 +69,125 @@ struct analog_parameters {
|
|||
u64 std;
|
||||
};
|
||||
|
||||
enum dvbfe_modcod {
|
||||
DVBFE_MODCOD_DUMMY_PLFRAME = 0,
|
||||
DVBFE_MODCOD_QPSK_1_4,
|
||||
DVBFE_MODCOD_QPSK_1_3,
|
||||
DVBFE_MODCOD_QPSK_2_5,
|
||||
DVBFE_MODCOD_QPSK_1_2,
|
||||
DVBFE_MODCOD_QPSK_3_5,
|
||||
DVBFE_MODCOD_QPSK_2_3,
|
||||
DVBFE_MODCOD_QPSK_3_4,
|
||||
DVBFE_MODCOD_QPSK_4_5,
|
||||
DVBFE_MODCOD_QPSK_5_6,
|
||||
DVBFE_MODCOD_QPSK_8_9,
|
||||
DVBFE_MODCOD_QPSK_9_10,
|
||||
DVBFE_MODCOD_8PSK_3_5,
|
||||
DVBFE_MODCOD_8PSK_2_3,
|
||||
DVBFE_MODCOD_8PSK_3_4,
|
||||
DVBFE_MODCOD_8PSK_5_6,
|
||||
DVBFE_MODCOD_8PSK_8_9,
|
||||
DVBFE_MODCOD_8PSK_9_10,
|
||||
DVBFE_MODCOD_16APSK_2_3,
|
||||
DVBFE_MODCOD_16APSK_3_4,
|
||||
DVBFE_MODCOD_16APSK_4_5,
|
||||
DVBFE_MODCOD_16APSK_5_6,
|
||||
DVBFE_MODCOD_16APSK_8_9,
|
||||
DVBFE_MODCOD_16APSK_9_10,
|
||||
DVBFE_MODCOD_32APSK_3_4,
|
||||
DVBFE_MODCOD_32APSK_4_5,
|
||||
DVBFE_MODCOD_32APSK_5_6,
|
||||
DVBFE_MODCOD_32APSK_8_9,
|
||||
DVBFE_MODCOD_32APSK_9_10,
|
||||
DVBFE_MODCOD_RESERVED_1,
|
||||
DVBFE_MODCOD_BPSK_1_3,
|
||||
DVBFE_MODCOD_BPSK_1_4,
|
||||
DVBFE_MODCOD_RESERVED_2
|
||||
};
|
||||
|
||||
enum tuner_param {
|
||||
DVBFE_TUNER_FREQUENCY = (1 << 0),
|
||||
DVBFE_TUNER_TUNERSTEP = (1 << 1),
|
||||
DVBFE_TUNER_IFFREQ = (1 << 2),
|
||||
DVBFE_TUNER_BANDWIDTH = (1 << 3),
|
||||
DVBFE_TUNER_REFCLOCK = (1 << 4),
|
||||
DVBFE_TUNER_IQSENSE = (1 << 5),
|
||||
DVBFE_TUNER_DUMMY = (1 << 31)
|
||||
};
|
||||
|
||||
/*
|
||||
* ALGO_HW: (Hardware Algorithm)
|
||||
* ----------------------------------------------------------------
|
||||
* Devices that support this algorithm do everything in hardware
|
||||
* and no software support is needed to handle them.
|
||||
* Requesting these devices to LOCK is the only thing required,
|
||||
* device is supposed to do everything in the hardware.
|
||||
*
|
||||
* ALGO_SW: (Software Algorithm)
|
||||
* ----------------------------------------------------------------
|
||||
* These are dumb devices, that require software to do everything
|
||||
*
|
||||
* ALGO_CUSTOM: (Customizable Agorithm)
|
||||
* ----------------------------------------------------------------
|
||||
* Devices having this algorithm can be customized to have specific
|
||||
* algorithms in the frontend driver, rather than simply doing a
|
||||
* software zig-zag. In this case the zigzag maybe hardware assisted
|
||||
* or it maybe completely done in hardware. In all cases, usage of
|
||||
* this algorithm, in conjunction with the search and track
|
||||
* callbacks, utilizes the driver specific algorithm.
|
||||
*
|
||||
* ALGO_RECOVERY: (Recovery Algorithm)
|
||||
* ----------------------------------------------------------------
|
||||
* These devices have AUTO recovery capabilities from LOCK failure
|
||||
*/
|
||||
enum dvbfe_algo {
|
||||
DVBFE_ALGO_HW = (1 << 0),
|
||||
DVBFE_ALGO_SW = (1 << 1),
|
||||
DVBFE_ALGO_CUSTOM = (1 << 2),
|
||||
DVBFE_ALGO_RECOVERY = (1 << 31)
|
||||
};
|
||||
|
||||
struct tuner_state {
|
||||
u32 frequency;
|
||||
u32 tunerstep;
|
||||
u32 ifreq;
|
||||
u32 bandwidth;
|
||||
u32 iqsense;
|
||||
u32 refclock;
|
||||
};
|
||||
|
||||
/*
|
||||
* search callback possible return status
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_SUCCESS
|
||||
* The frontend search algorithm completed and returned succesfully
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_ASLEEP
|
||||
* The frontend search algorithm is sleeping
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_FAILED
|
||||
* The frontend search for a signal failed
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_INVALID
|
||||
* The frontend search algorith was probably supplied with invalid
|
||||
* parameters and the search is an invalid one
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_ERROR
|
||||
* The frontend search algorithm failed due to some error
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_AGAIN
|
||||
* The frontend search algorithm was requested to search again
|
||||
*/
|
||||
enum dvbfe_search {
|
||||
DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0),
|
||||
DVBFE_ALGO_SEARCH_ASLEEP = (1 << 1),
|
||||
DVBFE_ALGO_SEARCH_FAILED = (1 << 2),
|
||||
DVBFE_ALGO_SEARCH_INVALID = (1 << 3),
|
||||
DVBFE_ALGO_SEARCH_AGAIN = (1 << 4),
|
||||
DVBFE_ALGO_SEARCH_ERROR = (1 << 31),
|
||||
};
|
||||
|
||||
|
||||
struct dvb_tuner_ops {
|
||||
|
||||
struct dvb_tuner_info info;
|
||||
|
|
@ -99,6 +218,13 @@ struct dvb_tuner_ops {
|
|||
* tuners which require sophisticated tuning loops, controlling each parameter seperately. */
|
||||
int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
|
||||
int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
|
||||
|
||||
/*
|
||||
* These are provided seperately from set_params in order to facilitate silicon
|
||||
* tuners which require sophisticated tuning loops, controlling each parameter seperately.
|
||||
*/
|
||||
int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
|
||||
int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
|
||||
};
|
||||
|
||||
struct analog_demod_info {
|
||||
|
|
@ -142,7 +268,7 @@ struct dvb_frontend_ops {
|
|||
unsigned int *delay,
|
||||
fe_status_t *status);
|
||||
/* get frontend tuning algorithm from the module */
|
||||
int (*get_frontend_algo)(struct dvb_frontend *fe);
|
||||
enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe);
|
||||
|
||||
/* these two are only used for the swzigzag code */
|
||||
int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
|
||||
|
|
@ -167,6 +293,12 @@ struct dvb_frontend_ops {
|
|||
int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
|
||||
int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
|
||||
|
||||
/* These callbacks are for devices that implement their own
|
||||
* tuning algorithms, rather than a simple swzigzag
|
||||
*/
|
||||
enum dvbfe_search (*search)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
|
||||
int (*track)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
|
||||
|
||||
struct dvb_tuner_ops tuner_ops;
|
||||
struct analog_demod_ops analog_ops;
|
||||
|
||||
|
|
|
|||
|
|
@ -50,33 +50,27 @@ static const char * const dnames[] = {
|
|||
"net", "osd"
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DVB_DYNAMIC_MINORS
|
||||
#define MAX_DVB_MINORS 256
|
||||
#define DVB_MAX_IDS MAX_DVB_MINORS
|
||||
#else
|
||||
#define DVB_MAX_IDS 4
|
||||
#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type)
|
||||
#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)
|
||||
#endif
|
||||
|
||||
static struct class *dvb_class;
|
||||
|
||||
static struct dvb_device* dvbdev_find_device (int minor)
|
||||
{
|
||||
struct dvb_adapter *adap;
|
||||
|
||||
list_for_each_entry(adap, &dvb_adapter_list, list_head) {
|
||||
struct dvb_device *dev;
|
||||
list_for_each_entry(dev, &adap->device_list, list_head)
|
||||
if (nums2minor(adap->num, dev->type, dev->id) == minor)
|
||||
return dev;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dvb_device *dvb_minors[MAX_DVB_MINORS];
|
||||
static DECLARE_RWSEM(minor_rwsem);
|
||||
|
||||
static int dvb_device_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dvb_device *dvbdev;
|
||||
|
||||
lock_kernel();
|
||||
dvbdev = dvbdev_find_device (iminor(inode));
|
||||
down_read(&minor_rwsem);
|
||||
dvbdev = dvb_minors[iminor(inode)];
|
||||
|
||||
if (dvbdev && dvbdev->fops) {
|
||||
int err = 0;
|
||||
|
|
@ -92,9 +86,11 @@ static int dvb_device_open(struct inode *inode, struct file *file)
|
|||
file->f_op = fops_get(old_fops);
|
||||
}
|
||||
fops_put(old_fops);
|
||||
up_read(&minor_rwsem);
|
||||
unlock_kernel();
|
||||
return err;
|
||||
}
|
||||
up_read(&minor_rwsem);
|
||||
unlock_kernel();
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
@ -192,6 +188,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
|||
struct dvb_device *dvbdev;
|
||||
struct file_operations *dvbdevfops;
|
||||
struct device *clsdev;
|
||||
int minor;
|
||||
int id;
|
||||
|
||||
mutex_lock(&dvbdev_register_lock);
|
||||
|
|
@ -231,11 +228,31 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
|||
|
||||
list_add_tail (&dvbdev->list_head, &adap->device_list);
|
||||
|
||||
down_write(&minor_rwsem);
|
||||
#ifdef CONFIG_DVB_DYNAMIC_MINORS
|
||||
for (minor = 0; minor < MAX_DVB_MINORS; minor++)
|
||||
if (dvb_minors[minor] == NULL)
|
||||
break;
|
||||
|
||||
if (minor == MAX_DVB_MINORS) {
|
||||
kfree(dvbdevfops);
|
||||
kfree(dvbdev);
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
#else
|
||||
minor = nums2minor(adap->num, type, id);
|
||||
#endif
|
||||
|
||||
dvbdev->minor = minor;
|
||||
dvb_minors[minor] = dvbdev;
|
||||
up_write(&minor_rwsem);
|
||||
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
|
||||
clsdev = device_create(dvb_class, adap->device,
|
||||
MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
|
||||
NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
|
||||
MKDEV(DVB_MAJOR, minor),
|
||||
dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
|
||||
if (IS_ERR(clsdev)) {
|
||||
printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
|
||||
__func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
|
||||
|
|
@ -243,8 +260,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
|||
}
|
||||
|
||||
dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
|
||||
adap->num, dnames[type], id, nums2minor(adap->num, type, id),
|
||||
nums2minor(adap->num, type, id));
|
||||
adap->num, dnames[type], id, minor, minor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -256,8 +272,11 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
|
|||
if (!dvbdev)
|
||||
return;
|
||||
|
||||
device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
|
||||
dvbdev->type, dvbdev->id)));
|
||||
down_write(&minor_rwsem);
|
||||
dvb_minors[dvbdev->minor] = NULL;
|
||||
up_write(&minor_rwsem);
|
||||
|
||||
device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
|
||||
|
||||
list_del (&dvbdev->list_head);
|
||||
kfree (dvbdev->fops);
|
||||
|
|
@ -413,6 +432,15 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
struct dvb_device *dvbdev = dev_get_drvdata(dev);
|
||||
|
||||
add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id);
|
||||
add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init init_dvbdev(void)
|
||||
{
|
||||
int retval;
|
||||
|
|
@ -434,6 +462,7 @@ static int __init init_dvbdev(void)
|
|||
retval = PTR_ERR(dvb_class);
|
||||
goto error;
|
||||
}
|
||||
dvb_class->dev_uevent = dvb_uevent;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ struct dvb_device {
|
|||
struct file_operations *fops;
|
||||
struct dvb_adapter *adapter;
|
||||
int type;
|
||||
int minor;
|
||||
u32 id;
|
||||
|
||||
/* in theory, 'users' can vanish now,
|
||||
|
|
|
|||
|
|
@ -733,9 +733,19 @@ static int af9015_read_config(struct usb_device *udev)
|
|||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_mygictv);
|
||||
break;
|
||||
case AF9015_REMOTE_DIGITTRADE_DVB_T:
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_digittrade;
|
||||
af9015_properties[i].rc_key_map_size =
|
||||
ARRAY_SIZE(af9015_rc_keys_digittrade);
|
||||
af9015_config.ir_table =
|
||||
af9015_ir_table_digittrade;
|
||||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_digittrade);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (udev->descriptor.idVendor) {
|
||||
switch (le16_to_cpu(udev->descriptor.idVendor)) {
|
||||
case USB_VID_LEADTEK:
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_leadtek;
|
||||
|
|
@ -748,7 +758,7 @@ static int af9015_read_config(struct usb_device *udev)
|
|||
break;
|
||||
case USB_VID_VISIONPLUS:
|
||||
if (udev->descriptor.idProduct ==
|
||||
USB_PID_AZUREWAVE_AD_TU700) {
|
||||
cpu_to_le16(USB_PID_AZUREWAVE_AD_TU700)) {
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_twinhan;
|
||||
af9015_properties[i].rc_key_map_size =
|
||||
|
|
@ -800,6 +810,16 @@ static int af9015_read_config(struct usb_device *udev)
|
|||
ARRAY_SIZE(af9015_ir_table_msi);
|
||||
}
|
||||
break;
|
||||
case USB_VID_AVERMEDIA:
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_avermedia;
|
||||
af9015_properties[i].rc_key_map_size =
|
||||
ARRAY_SIZE(af9015_rc_keys_avermedia);
|
||||
af9015_config.ir_table =
|
||||
af9015_ir_table_avermedia;
|
||||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_avermedia);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1191,6 +1211,7 @@ static struct usb_device_id af9015_usb_table[] = {
|
|||
{USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)},
|
||||
{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)},
|
||||
/* 15 */{USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)},
|
||||
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)},
|
||||
{0},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
|
||||
|
|
@ -1343,7 +1364,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
|
|||
|
||||
.i2c_algo = &af9015_i2c_algo,
|
||||
|
||||
.num_device_descs = 6,
|
||||
.num_device_descs = 7,
|
||||
.devices = {
|
||||
{
|
||||
.name = "Xtensions XD-380",
|
||||
|
|
@ -1375,6 +1396,12 @@ static struct dvb_usb_device_properties af9015_properties[] = {
|
|||
.cold_ids = {&af9015_usb_table[15], NULL},
|
||||
.warm_ids = {NULL},
|
||||
},
|
||||
{
|
||||
.name = "KWorld USB DVB-T TV Stick II " \
|
||||
"(VS-DVB-T 395U)",
|
||||
.cold_ids = {&af9015_usb_table[16], NULL},
|
||||
.warm_ids = {NULL},
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ enum af9015_remote {
|
|||
AF9015_REMOTE_A_LINK_DTU_M,
|
||||
AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
|
||||
AF9015_REMOTE_MYGICTV_U718,
|
||||
AF9015_REMOTE_DIGITTRADE_DVB_T,
|
||||
};
|
||||
|
||||
/* Leadtek WinFast DTV Dongle Gold */
|
||||
|
|
@ -520,4 +521,143 @@ static u8 af9015_ir_table_kworld[] = {
|
|||
0x86, 0x6b, 0x23, 0xdc, 0x45, 0x07, 0x00,
|
||||
};
|
||||
|
||||
/* AverMedia Volar X */
|
||||
static struct dvb_usb_rc_key af9015_rc_keys_avermedia[] = {
|
||||
{ 0x05, 0x3d, KEY_PROG1 }, /* SOURCE */
|
||||
{ 0x05, 0x12, KEY_POWER }, /* POWER */
|
||||
{ 0x05, 0x1e, KEY_1 }, /* 1 */
|
||||
{ 0x05, 0x1f, KEY_2 }, /* 2 */
|
||||
{ 0x05, 0x20, KEY_3 }, /* 3 */
|
||||
{ 0x05, 0x21, KEY_4 }, /* 4 */
|
||||
{ 0x05, 0x22, KEY_5 }, /* 5 */
|
||||
{ 0x05, 0x23, KEY_6 }, /* 6 */
|
||||
{ 0x05, 0x24, KEY_7 }, /* 7 */
|
||||
{ 0x05, 0x25, KEY_8 }, /* 8 */
|
||||
{ 0x05, 0x26, KEY_9 }, /* 9 */
|
||||
{ 0x05, 0x3f, KEY_LEFT }, /* L / DISPLAY */
|
||||
{ 0x05, 0x27, KEY_0 }, /* 0 */
|
||||
{ 0x05, 0x0f, KEY_RIGHT }, /* R / CH RTN */
|
||||
{ 0x05, 0x18, KEY_PROG2 }, /* SNAP SHOT */
|
||||
{ 0x05, 0x1c, KEY_PROG3 }, /* 16-CH PREV */
|
||||
{ 0x05, 0x2d, KEY_VOLUMEDOWN }, /* VOL DOWN */
|
||||
{ 0x05, 0x3e, KEY_ZOOM }, /* FULL SCREEN */
|
||||
{ 0x05, 0x2e, KEY_VOLUMEUP }, /* VOL UP */
|
||||
{ 0x05, 0x10, KEY_MUTE }, /* MUTE */
|
||||
{ 0x05, 0x04, KEY_AUDIO }, /* AUDIO */
|
||||
{ 0x05, 0x15, KEY_RECORD }, /* RECORD */
|
||||
{ 0x05, 0x11, KEY_PLAY }, /* PLAY */
|
||||
{ 0x05, 0x16, KEY_STOP }, /* STOP */
|
||||
{ 0x05, 0x0c, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */
|
||||
{ 0x05, 0x05, KEY_BACK }, /* << / RED */
|
||||
{ 0x05, 0x09, KEY_FORWARD }, /* >> / YELLOW */
|
||||
{ 0x05, 0x17, KEY_TEXT }, /* TELETEXT */
|
||||
{ 0x05, 0x0a, KEY_EPG }, /* EPG */
|
||||
{ 0x05, 0x13, KEY_MENU }, /* MENU */
|
||||
|
||||
{ 0x05, 0x0e, KEY_CHANNELUP }, /* CH UP */
|
||||
{ 0x05, 0x0d, KEY_CHANNELDOWN }, /* CH DOWN */
|
||||
{ 0x05, 0x19, KEY_FIRST }, /* |<< / GREEN */
|
||||
{ 0x05, 0x08, KEY_LAST }, /* >>| / BLUE */
|
||||
};
|
||||
|
||||
static u8 af9015_ir_table_avermedia[] = {
|
||||
0x02, 0xfd, 0x00, 0xff, 0x12, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x01, 0xfe, 0x3d, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x03, 0xfc, 0x17, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x04, 0xfb, 0x0a, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x05, 0xfa, 0x1e, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x06, 0xf9, 0x1f, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x07, 0xf8, 0x20, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x09, 0xf6, 0x21, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x0a, 0xf5, 0x22, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x0b, 0xf4, 0x23, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x0d, 0xf2, 0x24, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x0e, 0xf1, 0x25, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x0f, 0xf0, 0x26, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x11, 0xee, 0x27, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x08, 0xf7, 0x04, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x0c, 0xf3, 0x3e, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x10, 0xef, 0x1c, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x12, 0xed, 0x3f, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x13, 0xec, 0x0f, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x14, 0xeb, 0x10, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x15, 0xea, 0x13, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x17, 0xe8, 0x18, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x18, 0xe7, 0x11, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x19, 0xe6, 0x15, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x1a, 0xe5, 0x0c, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x1b, 0xe4, 0x16, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x1c, 0xe3, 0x09, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x1d, 0xe2, 0x05, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x1e, 0xe1, 0x2d, 0x05, 0x00,
|
||||
0x02, 0xfd, 0x1f, 0xe0, 0x2e, 0x05, 0x00,
|
||||
0x03, 0xfc, 0x00, 0xff, 0x08, 0x05, 0x00,
|
||||
0x03, 0xfc, 0x01, 0xfe, 0x19, 0x05, 0x00,
|
||||
0x03, 0xfc, 0x02, 0xfd, 0x0d, 0x05, 0x00,
|
||||
0x03, 0xfc, 0x03, 0xfc, 0x0e, 0x05, 0x00,
|
||||
};
|
||||
|
||||
/* Digittrade DVB-T USB Stick */
|
||||
static struct dvb_usb_rc_key af9015_rc_keys_digittrade[] = {
|
||||
{ 0x01, 0x0f, KEY_LAST }, /* RETURN */
|
||||
{ 0x05, 0x17, KEY_TEXT }, /* TELETEXT */
|
||||
{ 0x01, 0x08, KEY_EPG }, /* EPG */
|
||||
{ 0x05, 0x13, KEY_POWER }, /* POWER */
|
||||
{ 0x01, 0x09, KEY_ZOOM }, /* FULLSCREEN */
|
||||
{ 0x00, 0x40, KEY_AUDIO }, /* DUAL SOUND */
|
||||
{ 0x00, 0x2c, KEY_PRINT }, /* SNAPSHOT */
|
||||
{ 0x05, 0x16, KEY_SUBTITLE }, /* SUBTITLE */
|
||||
{ 0x00, 0x52, KEY_CHANNELUP }, /* CH Up */
|
||||
{ 0x00, 0x51, KEY_CHANNELDOWN },/* Ch Dn */
|
||||
{ 0x00, 0x57, KEY_VOLUMEUP }, /* Vol Up */
|
||||
{ 0x00, 0x56, KEY_VOLUMEDOWN }, /* Vol Dn */
|
||||
{ 0x01, 0x10, KEY_MUTE }, /* MUTE */
|
||||
{ 0x00, 0x27, KEY_0 },
|
||||
{ 0x00, 0x1e, KEY_1 },
|
||||
{ 0x00, 0x1f, KEY_2 },
|
||||
{ 0x00, 0x20, KEY_3 },
|
||||
{ 0x00, 0x21, KEY_4 },
|
||||
{ 0x00, 0x22, KEY_5 },
|
||||
{ 0x00, 0x23, KEY_6 },
|
||||
{ 0x00, 0x24, KEY_7 },
|
||||
{ 0x00, 0x25, KEY_8 },
|
||||
{ 0x00, 0x26, KEY_9 },
|
||||
{ 0x01, 0x17, KEY_PLAYPAUSE }, /* TIMESHIFT */
|
||||
{ 0x01, 0x15, KEY_RECORD }, /* RECORD */
|
||||
{ 0x03, 0x13, KEY_PLAY }, /* PLAY */
|
||||
{ 0x01, 0x16, KEY_STOP }, /* STOP */
|
||||
{ 0x01, 0x13, KEY_PAUSE }, /* PAUSE */
|
||||
};
|
||||
|
||||
static u8 af9015_ir_table_digittrade[] = {
|
||||
0x00, 0xff, 0x06, 0xf9, 0x13, 0x05, 0x00,
|
||||
0x00, 0xff, 0x4d, 0xb2, 0x17, 0x01, 0x00,
|
||||
0x00, 0xff, 0x1f, 0xe0, 0x2c, 0x00, 0x00,
|
||||
0x00, 0xff, 0x0a, 0xf5, 0x15, 0x01, 0x00,
|
||||
0x00, 0xff, 0x0e, 0xf1, 0x16, 0x01, 0x00,
|
||||
0x00, 0xff, 0x09, 0xf6, 0x09, 0x01, 0x00,
|
||||
0x00, 0xff, 0x01, 0xfe, 0x08, 0x01, 0x00,
|
||||
0x00, 0xff, 0x05, 0xfa, 0x10, 0x01, 0x00,
|
||||
0x00, 0xff, 0x02, 0xfd, 0x56, 0x00, 0x00,
|
||||
0x00, 0xff, 0x40, 0xbf, 0x57, 0x00, 0x00,
|
||||
0x00, 0xff, 0x19, 0xe6, 0x52, 0x00, 0x00,
|
||||
0x00, 0xff, 0x17, 0xe8, 0x51, 0x00, 0x00,
|
||||
0x00, 0xff, 0x10, 0xef, 0x0f, 0x01, 0x00,
|
||||
0x00, 0xff, 0x54, 0xab, 0x27, 0x00, 0x00,
|
||||
0x00, 0xff, 0x1b, 0xe4, 0x1e, 0x00, 0x00,
|
||||
0x00, 0xff, 0x11, 0xee, 0x1f, 0x00, 0x00,
|
||||
0x00, 0xff, 0x15, 0xea, 0x20, 0x00, 0x00,
|
||||
0x00, 0xff, 0x12, 0xed, 0x21, 0x00, 0x00,
|
||||
0x00, 0xff, 0x16, 0xe9, 0x22, 0x00, 0x00,
|
||||
0x00, 0xff, 0x4c, 0xb3, 0x23, 0x00, 0x00,
|
||||
0x00, 0xff, 0x48, 0xb7, 0x24, 0x00, 0x00,
|
||||
0x00, 0xff, 0x04, 0xfb, 0x25, 0x00, 0x00,
|
||||
0x00, 0xff, 0x00, 0xff, 0x26, 0x00, 0x00,
|
||||
0x00, 0xff, 0x1e, 0xe1, 0x13, 0x03, 0x00,
|
||||
0x00, 0xff, 0x1a, 0xe5, 0x13, 0x01, 0x00,
|
||||
0x00, 0xff, 0x03, 0xfc, 0x17, 0x05, 0x00,
|
||||
0x00, 0xff, 0x0d, 0xf2, 0x16, 0x05, 0x00,
|
||||
0x00, 0xff, 0x1d, 0xe2, 0x40, 0x00, 0x00,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
|
|||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int ret, inc, i = 0;
|
||||
int ret = 0, inc, i = 0;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@
|
|||
|
||||
/* debug */
|
||||
int dvb_usb_cinergyt2_debug;
|
||||
int disable_remote;
|
||||
|
||||
module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 "
|
||||
|
|
@ -45,7 +44,7 @@ struct cinergyt2_state {
|
|||
};
|
||||
|
||||
/* We are missing a release hook with usb_device data */
|
||||
struct dvb_usb_device *cinergyt2_usb_device;
|
||||
static struct dvb_usb_device *cinergyt2_usb_device;
|
||||
|
||||
static struct dvb_usb_device_properties cinergyt2_properties;
|
||||
|
||||
|
|
|
|||
|
|
@ -70,11 +70,11 @@ struct dvbt_get_status_msg {
|
|||
uint8_t bandwidth;
|
||||
uint16_t tps;
|
||||
uint8_t flags;
|
||||
uint16_t gain;
|
||||
__le16 gain;
|
||||
uint8_t snr;
|
||||
uint32_t viterbi_error_rate;
|
||||
__le32 viterbi_error_rate;
|
||||
uint32_t rs_error_rate;
|
||||
uint32_t uncorrected_block_count;
|
||||
__le32 uncorrected_block_count;
|
||||
uint8_t lock_bits;
|
||||
uint8_t prev_lock_bits;
|
||||
} __attribute__((packed));
|
||||
|
|
@ -82,9 +82,9 @@ struct dvbt_get_status_msg {
|
|||
|
||||
struct dvbt_set_parameters_msg {
|
||||
uint8_t cmd;
|
||||
uint32_t freq;
|
||||
__le32 freq;
|
||||
uint8_t bandwidth;
|
||||
uint16_t tps;
|
||||
__le16 tps;
|
||||
uint8_t flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@
|
|||
#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
|
||||
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
|
||||
#define USB_PID_KWORLD_399U 0xe399
|
||||
#define USB_PID_KWORLD_395U 0xe396
|
||||
#define USB_PID_KWORLD_PC160_2T 0xc160
|
||||
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
|
||||
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include <linux/version.h>
|
||||
#include "dw2102.h"
|
||||
#include "si21xx.h"
|
||||
#include "stv0299.h"
|
||||
|
|
@ -27,6 +26,10 @@
|
|||
#define USB_PID_DW2104 0x2104
|
||||
#endif
|
||||
|
||||
#ifndef USB_PID_CINERGY_S
|
||||
#define USB_PID_CINERGY_S 0x0064
|
||||
#endif
|
||||
|
||||
#define DW210X_READ_MSG 0
|
||||
#define DW210X_WRITE_MSG 1
|
||||
|
||||
|
|
@ -578,6 +581,7 @@ static struct usb_device_id dw2102_table[] = {
|
|||
{USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
|
||||
{USB_DEVICE(USB_VID_CYPRESS, 0x2104)},
|
||||
{USB_DEVICE(0x9022, 0xd650)},
|
||||
{USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
@ -647,6 +651,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
|
|||
dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
|
||||
DW210X_WRITE_MSG);
|
||||
break;
|
||||
case USB_PID_CINERGY_S:
|
||||
case USB_PID_DW2102:
|
||||
dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
|
||||
DW210X_WRITE_MSG);
|
||||
|
|
@ -655,7 +660,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
|
|||
/* check STV0299 frontend */
|
||||
dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2,
|
||||
DW210X_READ_MSG);
|
||||
if (reset16[0] == 0xa1) {
|
||||
if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) {
|
||||
dw2102_properties.i2c_algo = &dw2102_i2c_algo;
|
||||
dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach;
|
||||
break;
|
||||
|
|
@ -726,7 +731,7 @@ static struct dvb_usb_device_properties dw2102_properties = {
|
|||
},
|
||||
}
|
||||
},
|
||||
.num_device_descs = 2,
|
||||
.num_device_descs = 3,
|
||||
.devices = {
|
||||
{"DVBWorld DVB-S 2102 USB2.0",
|
||||
{&dw2102_table[0], NULL},
|
||||
|
|
@ -736,6 +741,10 @@ static struct dvb_usb_device_properties dw2102_properties = {
|
|||
{&dw2102_table[1], NULL},
|
||||
{NULL},
|
||||
},
|
||||
{"TerraTec Cinergy S USB",
|
||||
{&dw2102_table[4], NULL},
|
||||
{NULL},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,20 @@ struct gp8psk_fe_state {
|
|||
unsigned long status_check_interval;
|
||||
};
|
||||
|
||||
static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe)
|
||||
{
|
||||
struct gp8psk_fe_state *st = fe->demodulator_priv;
|
||||
u8 status;
|
||||
gp8psk_usb_in_op(st->d, GET_8PSK_CONFIG, 0, 0, &status, 1);
|
||||
return status & bmDCtuned;
|
||||
}
|
||||
|
||||
static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode)
|
||||
{
|
||||
struct gp8psk_fe_state *state = fe->demodulator_priv;
|
||||
return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0);
|
||||
}
|
||||
|
||||
static int gp8psk_fe_update_status(struct gp8psk_fe_state *st)
|
||||
{
|
||||
u8 buf[6];
|
||||
|
|
@ -99,39 +113,114 @@ static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_set_property(struct dvb_frontend *fe,
|
||||
struct dtv_property *tvp)
|
||||
{
|
||||
deb_fe("%s(..)\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_get_property(struct dvb_frontend *fe,
|
||||
struct dtv_property *tvp)
|
||||
{
|
||||
deb_fe("%s(..)\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct gp8psk_fe_state *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
u8 cmd[10];
|
||||
u32 freq = fep->frequency * 1000;
|
||||
int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct);
|
||||
|
||||
deb_fe("%s()\n", __func__);
|
||||
|
||||
cmd[4] = freq & 0xff;
|
||||
cmd[5] = (freq >> 8) & 0xff;
|
||||
cmd[6] = (freq >> 16) & 0xff;
|
||||
cmd[7] = (freq >> 24) & 0xff;
|
||||
|
||||
switch(fe->ops.info.type) {
|
||||
case FE_QPSK:
|
||||
cmd[0] = fep->u.qpsk.symbol_rate & 0xff;
|
||||
cmd[1] = (fep->u.qpsk.symbol_rate >> 8) & 0xff;
|
||||
cmd[2] = (fep->u.qpsk.symbol_rate >> 16) & 0xff;
|
||||
cmd[3] = (fep->u.qpsk.symbol_rate >> 24) & 0xff;
|
||||
cmd[8] = ADV_MOD_DVB_QPSK;
|
||||
cmd[9] = 0x03; /*ADV_MOD_FEC_XXX*/
|
||||
switch (c->delivery_system) {
|
||||
case SYS_DVBS:
|
||||
/* Only QPSK is supported for DVB-S */
|
||||
if (c->modulation != QPSK) {
|
||||
deb_fe("%s: unsupported modulation selected (%d)\n",
|
||||
__func__, c->modulation);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
c->fec_inner = FEC_AUTO;
|
||||
break;
|
||||
case SYS_DVBS2:
|
||||
deb_fe("%s: DVB-S2 delivery system selected\n", __func__);
|
||||
break;
|
||||
|
||||
default:
|
||||
// other modes are unsuported right now
|
||||
cmd[0] = 0;
|
||||
cmd[1] = 0;
|
||||
cmd[2] = 0;
|
||||
cmd[3] = 0;
|
||||
cmd[8] = 0;
|
||||
cmd[9] = 0;
|
||||
break;
|
||||
deb_fe("%s: unsupported delivery system selected (%d)\n",
|
||||
__func__, c->delivery_system);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
|
||||
cmd[0] = c->symbol_rate & 0xff;
|
||||
cmd[1] = (c->symbol_rate >> 8) & 0xff;
|
||||
cmd[2] = (c->symbol_rate >> 16) & 0xff;
|
||||
cmd[3] = (c->symbol_rate >> 24) & 0xff;
|
||||
switch (c->modulation) {
|
||||
case QPSK:
|
||||
if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
|
||||
if (gp8psk_tuned_to_DCII(fe))
|
||||
gp8psk_bcm4500_reload(state->d);
|
||||
switch (c->fec_inner) {
|
||||
case FEC_1_2:
|
||||
cmd[9] = 0; break;
|
||||
case FEC_2_3:
|
||||
cmd[9] = 1; break;
|
||||
case FEC_3_4:
|
||||
cmd[9] = 2; break;
|
||||
case FEC_5_6:
|
||||
cmd[9] = 3; break;
|
||||
case FEC_7_8:
|
||||
cmd[9] = 4; break;
|
||||
case FEC_AUTO:
|
||||
cmd[9] = 5; break;
|
||||
default:
|
||||
cmd[9] = 5; break;
|
||||
}
|
||||
cmd[8] = ADV_MOD_DVB_QPSK;
|
||||
break;
|
||||
case PSK_8: /* PSK_8 is for compatibility with DN */
|
||||
cmd[8] = ADV_MOD_TURBO_8PSK;
|
||||
switch (c->fec_inner) {
|
||||
case FEC_2_3:
|
||||
cmd[9] = 0; break;
|
||||
case FEC_3_4:
|
||||
cmd[9] = 1; break;
|
||||
case FEC_3_5:
|
||||
cmd[9] = 2; break;
|
||||
case FEC_5_6:
|
||||
cmd[9] = 3; break;
|
||||
case FEC_8_9:
|
||||
cmd[9] = 4; break;
|
||||
default:
|
||||
cmd[9] = 0; break;
|
||||
}
|
||||
break;
|
||||
case QAM_16: /* QAM_16 is for compatibility with DN */
|
||||
cmd[8] = ADV_MOD_TURBO_16QAM;
|
||||
cmd[9] = 0;
|
||||
break;
|
||||
default: /* Unknown modulation */
|
||||
deb_fe("%s: unsupported modulation selected (%d)\n",
|
||||
__func__, c->modulation);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
|
||||
gp8psk_set_tuner_mode(fe, 0);
|
||||
gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10);
|
||||
|
||||
state->lock = 0;
|
||||
state->next_status_check = jiffies;
|
||||
|
|
@ -140,13 +229,6 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_get_frontend(struct dvb_frontend* fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
|
||||
struct dvb_diseqc_master_cmd *m)
|
||||
{
|
||||
|
|
@ -261,9 +343,13 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
|
|||
.symbol_rate_max = 45000000,
|
||||
.symbol_rate_tolerance = 500, /* ppm */
|
||||
.caps = FE_CAN_INVERSION_AUTO |
|
||||
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_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_QAM_16 is for compatibility
|
||||
* (Myth incorrectly detects Turbo-QPSK as plain QAM-16)
|
||||
*/
|
||||
FE_CAN_QPSK | FE_CAN_QAM_16
|
||||
},
|
||||
|
||||
.release = gp8psk_fe_release,
|
||||
|
|
@ -271,8 +357,10 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
|
|||
.init = NULL,
|
||||
.sleep = NULL,
|
||||
|
||||
.set_property = gp8psk_fe_set_property,
|
||||
.get_property = gp8psk_fe_get_property,
|
||||
.set_frontend = gp8psk_fe_set_frontend,
|
||||
.get_frontend = gp8psk_fe_get_frontend,
|
||||
|
||||
.get_tune_settings = gp8psk_fe_get_tune_settings,
|
||||
|
||||
.read_status = gp8psk_fe_read_status,
|
||||
|
|
|
|||
|
|
@ -174,6 +174,22 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
|
||||
{
|
||||
u8 buf;
|
||||
int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
|
||||
/* Turn off 8psk power */
|
||||
if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
|
||||
return -EINVAL;
|
||||
/* Turn On 8psk power */
|
||||
if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
|
||||
return -EINVAL;
|
||||
/* load BCM4500 firmware */
|
||||
if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
|
||||
if (gp8psk_load_bcm4500fw(d))
|
||||
return EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -92,5 +92,6 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
|
|||
extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
|
||||
extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
|
||||
u16 index, u8 *b, int blen);
|
||||
extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -156,7 +156,8 @@ static int usb_bulk_urb_init(struct usb_data_stream *stream)
|
|||
stream->props.u.bulk.buffersize,
|
||||
usb_urb_complete, stream);
|
||||
|
||||
stream->urb_list[i]->transfer_flags = 0;
|
||||
stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
|
||||
stream->urb_list[i]->transfer_dma = stream->dma_addr[i];
|
||||
stream->urbs_initialized++;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,25 @@ config DVB_FE_CUSTOMISE
|
|||
|
||||
If unsure say N.
|
||||
|
||||
comment "Multistandard (satellite) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_STB0899
|
||||
tristate "STB0899 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
A DVB-S/S2/DSS Multistandard demodulator. Say Y when you want
|
||||
to support this demodulator based frontends
|
||||
|
||||
config DVB_STB6100
|
||||
tristate "STB6100 based tuners"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
A Silicon tuner from ST used in conjunction with the STB0899
|
||||
demodulator. Say Y when you want to support this tuner.
|
||||
|
||||
comment "DVB-S (satellite) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
|
|
@ -78,6 +97,13 @@ config DVB_TDA10086
|
|||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA8261
|
||||
tristate "Philips TDA8261 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_VES1X93
|
||||
tristate "VLSI VES1893 or VES1993 based"
|
||||
depends on DVB_CORE && I2C
|
||||
|
|
@ -92,6 +118,14 @@ config DVB_TUNER_ITD1000
|
|||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TUNER_CX24113
|
||||
tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
|
||||
config DVB_TDA826X
|
||||
tristate "Philips TDA826X silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
|
|
@ -345,6 +379,14 @@ config DVB_LGDT330X
|
|||
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_LGDT3304
|
||||
tristate "LG Electronics LGDT3304"
|
||||
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.
|
||||
|
||||
config DVB_S5H1409
|
||||
tristate "Samsung S5H1409 based"
|
||||
depends on DVB_CORE && I2C
|
||||
|
|
@ -369,6 +411,17 @@ config DVB_S5H1411
|
|||
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
comment "ISDB-T (terrestrial) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_S921
|
||||
tristate "Sharp S921 tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module.
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
comment "Digital terrestrial only tuners/PLL"
|
||||
depends on DVB_CORE
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,13 @@
|
|||
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
|
||||
EXTRA_CFLAGS += -Idrivers/media/common/tuners/
|
||||
|
||||
s921-objs := s921_module.o s921_core.o
|
||||
stb0899-objs = stb0899_drv.o stb0899_algo.o
|
||||
|
||||
obj-$(CONFIG_DVB_PLL) += dvb-pll.o
|
||||
obj-$(CONFIG_DVB_STV0299) += stv0299.o
|
||||
obj-$(CONFIG_DVB_STB0899) += stb0899.o
|
||||
obj-$(CONFIG_DVB_STB6100) += stb6100.o
|
||||
obj-$(CONFIG_DVB_SP8870) += sp8870.o
|
||||
obj-$(CONFIG_DVB_CX22700) += cx22700.o
|
||||
obj-$(CONFIG_DVB_CX24110) += cx24110.o
|
||||
|
|
@ -35,18 +40,21 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o
|
|||
obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
|
||||
obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
|
||||
obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
|
||||
obj-$(CONFIG_DVB_LGDT3304) += lgdt3304.o
|
||||
obj-$(CONFIG_DVB_CX24123) += cx24123.o
|
||||
obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
|
||||
obj-$(CONFIG_DVB_ISL6405) += isl6405.o
|
||||
obj-$(CONFIG_DVB_ISL6421) += isl6421.o
|
||||
obj-$(CONFIG_DVB_TDA10086) += tda10086.o
|
||||
obj-$(CONFIG_DVB_TDA826X) += tda826x.o
|
||||
obj-$(CONFIG_DVB_TDA8261) += tda8261.o
|
||||
obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
|
||||
obj-$(CONFIG_DVB_TUA6100) += tua6100.o
|
||||
obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
|
||||
obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
|
||||
obj-$(CONFIG_DVB_AU8522) += au8522.o
|
||||
obj-$(CONFIG_DVB_TDA10048) += tda10048.o
|
||||
obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
|
||||
obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
|
||||
obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
|
||||
obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
|
||||
|
|
@ -55,3 +63,5 @@ obj-$(CONFIG_DVB_CX24116) += cx24116.o
|
|||
obj-$(CONFIG_DVB_SI21XX) += si21xx.o
|
||||
obj-$(CONFIG_DVB_STV0288) += stv0288.o
|
||||
obj-$(CONFIG_DVB_STB6000) += stb6000.o
|
||||
obj-$(CONFIG_DVB_S921) += s921.o
|
||||
|
||||
|
|
|
|||
|
|
@ -223,12 +223,12 @@ static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw)
|
|||
int ret = 0;
|
||||
u8 i = 0;
|
||||
u8 buf[24];
|
||||
u32 ns_coeff1_2048nu;
|
||||
u32 ns_coeff1_8191nu;
|
||||
u32 ns_coeff1_8192nu;
|
||||
u32 ns_coeff1_8193nu;
|
||||
u32 ns_coeff2_2k;
|
||||
u32 ns_coeff2_8k;
|
||||
u32 uninitialized_var(ns_coeff1_2048nu);
|
||||
u32 uninitialized_var(ns_coeff1_8191nu);
|
||||
u32 uninitialized_var(ns_coeff1_8192nu);
|
||||
u32 uninitialized_var(ns_coeff1_8193nu);
|
||||
u32 uninitialized_var(ns_coeff2_2k);
|
||||
u32 uninitialized_var(ns_coeff2_8k);
|
||||
|
||||
deb_info("%s: adc_clock:%d bw:%d\n", __func__,
|
||||
state->config.adc_clock, bw);
|
||||
|
|
@ -1009,7 +1009,7 @@ static int af9013_update_snr(struct dvb_frontend *fe)
|
|||
int ret;
|
||||
u8 buf[3], i, len;
|
||||
u32 quant = 0;
|
||||
struct snr_table *snr_table;
|
||||
struct snr_table *uninitialized_var(snr_table);
|
||||
|
||||
/* check if quantizer ready (for snr) */
|
||||
ret = af9013_read_reg_bits(state, 0xd2e1, 3, 1, &buf[0]);
|
||||
|
|
|
|||
616
drivers/media/dvb/frontends/cx24113.c
Normal file
616
drivers/media/dvb/frontends/cx24113.c
Normal file
|
|
@ -0,0 +1,616 @@
|
|||
/*
|
||||
* Driver for Conexant CX24113/CX24128 Tuner (Satellite)
|
||||
*
|
||||
* Copyright (C) 2007-8 Patrick Boettcher <pb@linuxtv.org>
|
||||
*
|
||||
* Developed for BBTI / Technisat
|
||||
*
|
||||
* 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/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "cx24113.h"
|
||||
|
||||
static int debug;
|
||||
|
||||
#define info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0)
|
||||
#define err(args...) do { printk(KERN_ERR "CX24113: " args); } while (0)
|
||||
|
||||
#define dprintk(args...) \
|
||||
do { \
|
||||
if (debug) { \
|
||||
printk(KERN_DEBUG "CX24113: %s: ", __func__); \
|
||||
printk(args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
struct cx24113_state {
|
||||
struct i2c_adapter *i2c;
|
||||
const struct cx24113_config *config;
|
||||
|
||||
#define REV_CX24113 0x23
|
||||
u8 rev;
|
||||
u8 ver;
|
||||
|
||||
u8 icp_mode:1;
|
||||
|
||||
#define ICP_LEVEL1 0
|
||||
#define ICP_LEVEL2 1
|
||||
#define ICP_LEVEL3 2
|
||||
#define ICP_LEVEL4 3
|
||||
u8 icp_man:2;
|
||||
u8 icp_auto_low:2;
|
||||
u8 icp_auto_mlow:2;
|
||||
u8 icp_auto_mhi:2;
|
||||
u8 icp_auto_hi:2;
|
||||
u8 icp_dig;
|
||||
|
||||
#define LNA_MIN_GAIN 0
|
||||
#define LNA_MID_GAIN 1
|
||||
#define LNA_MAX_GAIN 2
|
||||
u8 lna_gain:2;
|
||||
|
||||
u8 acp_on:1;
|
||||
|
||||
u8 vco_mode:2;
|
||||
u8 vco_shift:1;
|
||||
#define VCOBANDSEL_6 0x80
|
||||
#define VCOBANDSEL_5 0x01
|
||||
#define VCOBANDSEL_4 0x02
|
||||
#define VCOBANDSEL_3 0x04
|
||||
#define VCOBANDSEL_2 0x08
|
||||
#define VCOBANDSEL_1 0x10
|
||||
u8 vco_band;
|
||||
|
||||
#define VCODIV4 4
|
||||
#define VCODIV2 2
|
||||
u8 vcodiv;
|
||||
|
||||
u8 bs_delay:4;
|
||||
u16 bs_freqcnt:13;
|
||||
u16 bs_rdiv;
|
||||
u8 prescaler_mode:1;
|
||||
|
||||
u8 rfvga_bias_ctrl;
|
||||
|
||||
s16 tuner_gain_thres;
|
||||
u8 gain_level;
|
||||
|
||||
u32 frequency;
|
||||
|
||||
u8 refdiv;
|
||||
|
||||
u8 Fwindow_enabled;
|
||||
};
|
||||
|
||||
static int cx24113_writereg(struct cx24113_state *state, int reg, int data)
|
||||
{
|
||||
u8 buf[] = { reg, data };
|
||||
struct i2c_msg msg = { .addr = state->config->i2c_addr,
|
||||
.flags = 0, .buf = buf, .len = 2 };
|
||||
int err = i2c_transfer(state->i2c, &msg, 1);
|
||||
if (err != 1) {
|
||||
printk(KERN_DEBUG "%s: writereg error(err == %i, reg == 0x%02x,"
|
||||
" data == 0x%02x)\n", __func__, err, reg, data);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx24113_readreg(struct cx24113_state *state, u8 reg)
|
||||
{
|
||||
int ret;
|
||||
u8 b;
|
||||
struct i2c_msg msg[] = {
|
||||
{ .addr = state->config->i2c_addr,
|
||||
.flags = 0, .buf = ®, .len = 1 },
|
||||
{ .addr = state->config->i2c_addr,
|
||||
.flags = I2C_M_RD, .buf = &b, .len = 1 }
|
||||
};
|
||||
|
||||
ret = i2c_transfer(state->i2c, msg, 2);
|
||||
|
||||
if (ret != 2) {
|
||||
printk(KERN_DEBUG "%s: reg=0x%x (error=%d)\n",
|
||||
__func__, reg, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static void cx24113_set_parameters(struct cx24113_state *state)
|
||||
{
|
||||
u8 r;
|
||||
|
||||
r = cx24113_readreg(state, 0x10) & 0x82;
|
||||
r |= state->icp_mode;
|
||||
r |= state->icp_man << 4;
|
||||
r |= state->icp_dig << 2;
|
||||
r |= state->prescaler_mode << 5;
|
||||
cx24113_writereg(state, 0x10, r);
|
||||
|
||||
r = (state->icp_auto_low << 0) | (state->icp_auto_mlow << 2)
|
||||
| (state->icp_auto_mhi << 4) | (state->icp_auto_hi << 6);
|
||||
cx24113_writereg(state, 0x11, r);
|
||||
|
||||
if (state->rev == REV_CX24113) {
|
||||
r = cx24113_readreg(state, 0x20) & 0xec;
|
||||
r |= state->lna_gain;
|
||||
r |= state->rfvga_bias_ctrl << 4;
|
||||
cx24113_writereg(state, 0x20, r);
|
||||
}
|
||||
|
||||
r = cx24113_readreg(state, 0x12) & 0x03;
|
||||
r |= state->acp_on << 2;
|
||||
r |= state->bs_delay << 4;
|
||||
cx24113_writereg(state, 0x12, r);
|
||||
|
||||
r = cx24113_readreg(state, 0x18) & 0x40;
|
||||
r |= state->vco_shift;
|
||||
if (state->vco_band == VCOBANDSEL_6)
|
||||
r |= (1 << 7);
|
||||
else
|
||||
r |= (state->vco_band << 1);
|
||||
cx24113_writereg(state, 0x18, r);
|
||||
|
||||
r = cx24113_readreg(state, 0x14) & 0x20;
|
||||
r |= (state->vco_mode << 6) | ((state->bs_freqcnt >> 8) & 0x1f);
|
||||
cx24113_writereg(state, 0x14, r);
|
||||
cx24113_writereg(state, 0x15, (state->bs_freqcnt & 0xff));
|
||||
|
||||
cx24113_writereg(state, 0x16, (state->bs_rdiv >> 4) & 0xff);
|
||||
r = (cx24113_readreg(state, 0x17) & 0x0f) |
|
||||
((state->bs_rdiv & 0x0f) << 4);
|
||||
cx24113_writereg(state, 0x17, r);
|
||||
}
|
||||
|
||||
#define VGA_0 0x00
|
||||
#define VGA_1 0x04
|
||||
#define VGA_2 0x02
|
||||
#define VGA_3 0x06
|
||||
#define VGA_4 0x01
|
||||
#define VGA_5 0x05
|
||||
#define VGA_6 0x03
|
||||
#define VGA_7 0x07
|
||||
|
||||
#define RFVGA_0 0x00
|
||||
#define RFVGA_1 0x01
|
||||
#define RFVGA_2 0x02
|
||||
#define RFVGA_3 0x03
|
||||
|
||||
static int cx24113_set_gain_settings(struct cx24113_state *state,
|
||||
s16 power_estimation)
|
||||
{
|
||||
u8 ampout = cx24113_readreg(state, 0x1d) & 0xf0,
|
||||
vga = cx24113_readreg(state, 0x1f) & 0x3f,
|
||||
rfvga = cx24113_readreg(state, 0x20) & 0xf3;
|
||||
u8 gain_level = power_estimation >= state->tuner_gain_thres;
|
||||
|
||||
dprintk("power estimation: %d, thres: %d, gain_level: %d/%d\n",
|
||||
power_estimation, state->tuner_gain_thres,
|
||||
state->gain_level, gain_level);
|
||||
|
||||
if (gain_level == state->gain_level)
|
||||
return 0; /* nothing to be done */
|
||||
|
||||
ampout |= 0xf;
|
||||
|
||||
if (gain_level) {
|
||||
rfvga |= RFVGA_0 << 2;
|
||||
vga |= (VGA_7 << 3) | VGA_7;
|
||||
} else {
|
||||
rfvga |= RFVGA_2 << 2;
|
||||
vga |= (VGA_6 << 3) | VGA_2;
|
||||
}
|
||||
state->gain_level = gain_level;
|
||||
|
||||
cx24113_writereg(state, 0x1d, ampout);
|
||||
cx24113_writereg(state, 0x1f, vga);
|
||||
cx24113_writereg(state, 0x20, rfvga);
|
||||
|
||||
return 1; /* did something */
|
||||
}
|
||||
|
||||
static int cx24113_set_Fref(struct cx24113_state *state, u8 high)
|
||||
{
|
||||
u8 xtal = cx24113_readreg(state, 0x02);
|
||||
if (state->rev == 0x43 && state->vcodiv == VCODIV4)
|
||||
high = 1;
|
||||
|
||||
xtal &= ~0x2;
|
||||
if (high)
|
||||
xtal |= high << 1;
|
||||
return cx24113_writereg(state, 0x02, xtal);
|
||||
}
|
||||
|
||||
static int cx24113_enable(struct cx24113_state *state, u8 enable)
|
||||
{
|
||||
u8 r21 = (cx24113_readreg(state, 0x21) & 0xc0) | enable;
|
||||
if (state->rev == REV_CX24113)
|
||||
r21 |= (1 << 1);
|
||||
return cx24113_writereg(state, 0x21, r21);
|
||||
}
|
||||
|
||||
static int cx24113_set_bandwidth(struct cx24113_state *state, u32 bandwidth_khz)
|
||||
{
|
||||
u8 r;
|
||||
|
||||
if (bandwidth_khz <= 19000)
|
||||
r = 0x03 << 6;
|
||||
else if (bandwidth_khz <= 25000)
|
||||
r = 0x02 << 6;
|
||||
else
|
||||
r = 0x01 << 6;
|
||||
|
||||
dprintk("bandwidth to be set: %d\n", bandwidth_khz);
|
||||
bandwidth_khz *= 10;
|
||||
bandwidth_khz -= 10000;
|
||||
bandwidth_khz /= 1000;
|
||||
bandwidth_khz += 5;
|
||||
bandwidth_khz /= 10;
|
||||
|
||||
dprintk("bandwidth: %d %d\n", r >> 6, bandwidth_khz);
|
||||
|
||||
r |= bandwidth_khz & 0x3f;
|
||||
|
||||
return cx24113_writereg(state, 0x1e, r);
|
||||
}
|
||||
|
||||
static int cx24113_set_clk_inversion(struct cx24113_state *state, u8 on)
|
||||
{
|
||||
u8 r = (cx24113_readreg(state, 0x10) & 0x7f) | ((on & 0x1) << 7);
|
||||
return cx24113_writereg(state, 0x10, r);
|
||||
}
|
||||
|
||||
static int cx24113_get_status(struct dvb_frontend *fe, u32 *status)
|
||||
{
|
||||
struct cx24113_state *state = fe->tuner_priv;
|
||||
u8 r = (cx24113_readreg(state, 0x10) & 0x02) >> 1;
|
||||
if (r)
|
||||
*status |= TUNER_STATUS_LOCKED;
|
||||
dprintk("PLL locked: %d\n", r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 cx24113_set_ref_div(struct cx24113_state *state, u8 refdiv)
|
||||
{
|
||||
if (state->rev == 0x43 && state->vcodiv == VCODIV4)
|
||||
refdiv = 2;
|
||||
return state->refdiv = refdiv;
|
||||
}
|
||||
|
||||
static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f)
|
||||
{
|
||||
s32 N;
|
||||
s64 F;
|
||||
u8 R, r;
|
||||
u8 vcodiv;
|
||||
u8 factor;
|
||||
s32 freq_hz = state->frequency * 1000;
|
||||
|
||||
if (state->config->xtal_khz < 20000)
|
||||
factor = 1;
|
||||
else
|
||||
factor = 2;
|
||||
|
||||
if (state->rev == REV_CX24113) {
|
||||
if (state->frequency >= 1100000)
|
||||
vcodiv = VCODIV2;
|
||||
else
|
||||
vcodiv = VCODIV4;
|
||||
} else {
|
||||
if (state->frequency >= 1165000)
|
||||
vcodiv = VCODIV2;
|
||||
else
|
||||
vcodiv = VCODIV4;
|
||||
}
|
||||
state->vcodiv = vcodiv;
|
||||
|
||||
dprintk("calculating N/F for %dHz with vcodiv %d\n", freq_hz, vcodiv);
|
||||
R = 0;
|
||||
do {
|
||||
R = cx24113_set_ref_div(state, R + 1);
|
||||
|
||||
/* calculate tuner PLL settings: */
|
||||
N = (freq_hz / 100 * vcodiv) * R;
|
||||
N /= (state->config->xtal_khz) * factor * 2;
|
||||
N += 5; /* For round up. */
|
||||
N /= 10;
|
||||
N -= 32;
|
||||
} while (N < 6 && R < 3);
|
||||
|
||||
if (N < 6) {
|
||||
err("strange frequency: N < 6\n");
|
||||
return;
|
||||
}
|
||||
F = freq_hz;
|
||||
F *= (u64) (R * vcodiv * 262144);
|
||||
dprintk("1 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
|
||||
do_div(F, state->config->xtal_khz*1000 * factor * 2);
|
||||
dprintk("2 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
|
||||
F -= (N + 32) * 262144;
|
||||
|
||||
dprintk("3 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
|
||||
|
||||
if (state->Fwindow_enabled) {
|
||||
if (F > (262144 / 2 - 1638))
|
||||
F = 262144 / 2 - 1638;
|
||||
if (F < (-262144 / 2 + 1638))
|
||||
F = -262144 / 2 + 1638;
|
||||
if ((F < 3277 && F > 0) || (F > -3277 && F < 0)) {
|
||||
F = 0;
|
||||
r = cx24113_readreg(state, 0x10);
|
||||
cx24113_writereg(state, 0x10, r | (1 << 6));
|
||||
}
|
||||
}
|
||||
dprintk("4 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
|
||||
|
||||
*n = (u16) N;
|
||||
*f = (s32) F;
|
||||
}
|
||||
|
||||
|
||||
static void cx24113_set_nfr(struct cx24113_state *state, u16 n, s32 f, u8 r)
|
||||
{
|
||||
u8 reg;
|
||||
cx24113_writereg(state, 0x19, (n >> 1) & 0xff);
|
||||
|
||||
reg = ((n & 0x1) << 7) | ((f >> 11) & 0x7f);
|
||||
cx24113_writereg(state, 0x1a, reg);
|
||||
|
||||
cx24113_writereg(state, 0x1b, (f >> 3) & 0xff);
|
||||
|
||||
reg = cx24113_readreg(state, 0x1c) & 0x1f;
|
||||
cx24113_writereg(state, 0x1c, reg | ((f & 0x7) << 5));
|
||||
|
||||
cx24113_set_Fref(state, r - 1);
|
||||
}
|
||||
|
||||
static int cx24113_set_frequency(struct cx24113_state *state, u32 frequency)
|
||||
{
|
||||
u8 r = 1; /* or 2 */
|
||||
u16 n = 6;
|
||||
s32 f = 0;
|
||||
|
||||
r = cx24113_readreg(state, 0x14);
|
||||
cx24113_writereg(state, 0x14, r & 0x3f);
|
||||
|
||||
r = cx24113_readreg(state, 0x10);
|
||||
cx24113_writereg(state, 0x10, r & 0xbf);
|
||||
|
||||
state->frequency = frequency;
|
||||
|
||||
dprintk("tuning to frequency: %d\n", frequency);
|
||||
|
||||
cx24113_calc_pll_nf(state, &n, &f);
|
||||
cx24113_set_nfr(state, n, f, state->refdiv);
|
||||
|
||||
r = cx24113_readreg(state, 0x18) & 0xbf;
|
||||
if (state->vcodiv != VCODIV2)
|
||||
r |= 1 << 6;
|
||||
cx24113_writereg(state, 0x18, r);
|
||||
|
||||
/* The need for this sleep is not clear. But helps in some cases */
|
||||
msleep(5);
|
||||
|
||||
r = cx24113_readreg(state, 0x1c) & 0xef;
|
||||
cx24113_writereg(state, 0x1c, r | (1 << 4));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx24113_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct cx24113_state *state = fe->tuner_priv;
|
||||
int ret;
|
||||
|
||||
state->tuner_gain_thres = -50;
|
||||
state->gain_level = 255; /* to force a gain-setting initialization */
|
||||
state->icp_mode = 0;
|
||||
|
||||
if (state->config->xtal_khz < 11000) {
|
||||
state->icp_auto_hi = ICP_LEVEL4;
|
||||
state->icp_auto_mhi = ICP_LEVEL4;
|
||||
state->icp_auto_mlow = ICP_LEVEL3;
|
||||
state->icp_auto_low = ICP_LEVEL3;
|
||||
} else {
|
||||
state->icp_auto_hi = ICP_LEVEL4;
|
||||
state->icp_auto_mhi = ICP_LEVEL4;
|
||||
state->icp_auto_mlow = ICP_LEVEL3;
|
||||
state->icp_auto_low = ICP_LEVEL2;
|
||||
}
|
||||
|
||||
state->icp_dig = ICP_LEVEL3;
|
||||
state->icp_man = ICP_LEVEL1;
|
||||
state->acp_on = 1;
|
||||
state->vco_mode = 0;
|
||||
state->vco_shift = 0;
|
||||
state->vco_band = VCOBANDSEL_1;
|
||||
state->bs_delay = 8;
|
||||
state->bs_freqcnt = 0x0fff;
|
||||
state->bs_rdiv = 0x0fff;
|
||||
state->prescaler_mode = 0;
|
||||
state->lna_gain = LNA_MAX_GAIN;
|
||||
state->rfvga_bias_ctrl = 1;
|
||||
state->Fwindow_enabled = 1;
|
||||
|
||||
cx24113_set_Fref(state, 0);
|
||||
cx24113_enable(state, 0x3d);
|
||||
cx24113_set_parameters(state);
|
||||
|
||||
cx24113_set_gain_settings(state, -30);
|
||||
|
||||
cx24113_set_bandwidth(state, 18025);
|
||||
cx24113_set_clk_inversion(state, 1);
|
||||
|
||||
if (state->config->xtal_khz >= 40000)
|
||||
ret = cx24113_writereg(state, 0x02,
|
||||
(cx24113_readreg(state, 0x02) & 0xfb) | (1 << 2));
|
||||
else
|
||||
ret = cx24113_writereg(state, 0x02,
|
||||
(cx24113_readreg(state, 0x02) & 0xfb) | (0 << 2));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cx24113_set_params(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *p)
|
||||
{
|
||||
struct cx24113_state *state = fe->tuner_priv;
|
||||
/* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */
|
||||
u32 roll_off = 675;
|
||||
u32 bw;
|
||||
|
||||
bw = ((p->u.qpsk.symbol_rate/100) * roll_off) / 1000;
|
||||
bw += (10000000/100) + 5;
|
||||
bw /= 10;
|
||||
bw += 1000;
|
||||
cx24113_set_bandwidth(state, bw);
|
||||
|
||||
cx24113_set_frequency(state, p->frequency);
|
||||
msleep(5);
|
||||
return cx24113_get_status(fe, &bw);
|
||||
}
|
||||
|
||||
static s8 cx24113_agc_table[2][10] = {
|
||||
{-54, -41, -35, -30, -25, -21, -16, -10, -6, -2},
|
||||
{-39, -35, -30, -25, -19, -15, -11, -5, 1, 9},
|
||||
};
|
||||
|
||||
void cx24113_agc_callback(struct dvb_frontend *fe)
|
||||
{
|
||||
struct cx24113_state *state = fe->tuner_priv;
|
||||
s16 s, i;
|
||||
if (!fe->ops.read_signal_strength)
|
||||
return;
|
||||
|
||||
do {
|
||||
/* this only works with the current CX24123 implementation */
|
||||
fe->ops.read_signal_strength(fe, (u16 *) &s);
|
||||
s >>= 8;
|
||||
dprintk("signal strength: %d\n", s);
|
||||
for (i = 0; i < sizeof(cx24113_agc_table[0]); i++)
|
||||
if (cx24113_agc_table[state->gain_level][i] > s)
|
||||
break;
|
||||
s = -25 - i*5;
|
||||
} while (cx24113_set_gain_settings(state, s));
|
||||
}
|
||||
EXPORT_SYMBOL(cx24113_agc_callback);
|
||||
|
||||
static int cx24113_get_frequency(struct dvb_frontend *fe, u32 *frequency)
|
||||
{
|
||||
struct cx24113_state *state = fe->tuner_priv;
|
||||
*frequency = state->frequency;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx24113_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct cx24113_state *state = fe->tuner_priv;
|
||||
dprintk("\n");
|
||||
fe->tuner_priv = NULL;
|
||||
kfree(state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dvb_tuner_ops cx24113_tuner_ops = {
|
||||
.info = {
|
||||
.name = "Conexant CX24113",
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_step = 125,
|
||||
},
|
||||
|
||||
.release = cx24113_release,
|
||||
|
||||
.init = cx24113_init,
|
||||
.sleep = NULL,
|
||||
|
||||
.set_params = cx24113_set_params,
|
||||
.get_frequency = cx24113_get_frequency,
|
||||
.get_bandwidth = NULL,
|
||||
.get_status = cx24113_get_status,
|
||||
};
|
||||
|
||||
struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
|
||||
const struct cx24113_config *config, struct i2c_adapter *i2c)
|
||||
{
|
||||
/* allocate memory for the internal state */
|
||||
struct cx24113_state *state =
|
||||
kzalloc(sizeof(struct cx24113_state), GFP_KERNEL);
|
||||
int rc;
|
||||
if (state == NULL) {
|
||||
err("Unable to kmalloc\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* setup the state */
|
||||
state->config = config;
|
||||
state->i2c = i2c;
|
||||
|
||||
info("trying to detect myself\n");
|
||||
|
||||
/* making a dummy read, because of some expected troubles
|
||||
* after power on */
|
||||
cx24113_readreg(state, 0x00);
|
||||
|
||||
rc = cx24113_readreg(state, 0x00);
|
||||
if (rc < 0) {
|
||||
info("CX24113 not found.\n");
|
||||
goto error;
|
||||
}
|
||||
state->rev = rc;
|
||||
|
||||
switch (rc) {
|
||||
case 0x43:
|
||||
info("detected CX24113 variant\n");
|
||||
break;
|
||||
case REV_CX24113:
|
||||
info("sucessfully detected\n");
|
||||
break;
|
||||
default:
|
||||
err("unsupported device id: %x\n", state->rev);
|
||||
goto error;
|
||||
}
|
||||
state->ver = cx24113_readreg(state, 0x01);
|
||||
info("version: %x\n", state->ver);
|
||||
|
||||
/* create dvb_frontend */
|
||||
memcpy(&fe->ops.tuner_ops, &cx24113_tuner_ops,
|
||||
sizeof(struct dvb_tuner_ops));
|
||||
fe->tuner_priv = state;
|
||||
return fe;
|
||||
|
||||
error:
|
||||
kfree(state);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(cx24113_attach);
|
||||
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <[email protected]>");
|
||||
MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24113/CX24128hardware");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
*
|
||||
* 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.=
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef CX24113_H
|
||||
|
|
@ -30,9 +30,13 @@ struct cx24113_config {
|
|||
u32 xtal_khz;
|
||||
};
|
||||
|
||||
/* TODO: #if defined(CONFIG_DVB_TUNER_CX24113) || \
|
||||
* (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE)) */
|
||||
#if defined(CONFIG_DVB_TUNER_CX24113) || \
|
||||
(defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *,
|
||||
const struct cx24113_config *config, struct i2c_adapter *i2c);
|
||||
|
||||
extern void cx24113_agc_callback(struct dvb_frontend *fe);
|
||||
#else
|
||||
static inline struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
|
||||
const struct cx24113_config *config, struct i2c_adapter *i2c)
|
||||
{
|
||||
|
|
@ -44,5 +48,6 @@ static inline void cx24113_agc_callback(struct dvb_frontend *fe)
|
|||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CX24113_H */
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
|
|||
#define CX24116_HAS_SYNCLOCK (0x08)
|
||||
#define CX24116_HAS_UNKNOWN1 (0x10)
|
||||
#define CX24116_HAS_UNKNOWN2 (0x20)
|
||||
#define CX24116_STATUS_MASK (0x3f)
|
||||
#define CX24116_STATUS_MASK (0x0f)
|
||||
#define CX24116_SIGNAL_MASK (0xc0)
|
||||
|
||||
#define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */
|
||||
|
|
@ -160,6 +160,7 @@ struct cx24116_tuning {
|
|||
fe_spectral_inversion_t inversion;
|
||||
fe_code_rate_t fec;
|
||||
|
||||
fe_delivery_system_t delsys;
|
||||
fe_modulation_t modulation;
|
||||
fe_pilot_t pilot;
|
||||
fe_rolloff_t rolloff;
|
||||
|
|
@ -411,14 +412,15 @@ struct cx24116_modfec {
|
|||
};
|
||||
|
||||
static int cx24116_lookup_fecmod(struct cx24116_state *state,
|
||||
fe_modulation_t m, fe_code_rate_t f)
|
||||
fe_delivery_system_t d, fe_modulation_t m, fe_code_rate_t f)
|
||||
{
|
||||
int i, ret = -EOPNOTSUPP;
|
||||
|
||||
dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) {
|
||||
if ((m == CX24116_MODFEC_MODES[i].modulation) &&
|
||||
if ((d == CX24116_MODFEC_MODES[i].delivery_system) &&
|
||||
(m == CX24116_MODFEC_MODES[i].modulation) &&
|
||||
(f == CX24116_MODFEC_MODES[i].fec)) {
|
||||
ret = i;
|
||||
break;
|
||||
|
|
@ -429,13 +431,13 @@ static int cx24116_lookup_fecmod(struct cx24116_state *state,
|
|||
}
|
||||
|
||||
static int cx24116_set_fec(struct cx24116_state *state,
|
||||
fe_modulation_t mod, fe_code_rate_t fec)
|
||||
fe_delivery_system_t delsys, fe_modulation_t mod, fe_code_rate_t fec)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
|
||||
|
||||
ret = cx24116_lookup_fecmod(state, mod, fec);
|
||||
ret = cx24116_lookup_fecmod(state, delsys, mod, fec);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
@ -679,7 +681,8 @@ static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
|||
{
|
||||
struct cx24116_state *state = fe->demodulator_priv;
|
||||
|
||||
int lock = cx24116_readreg(state, CX24116_REG_SSTATUS);
|
||||
int lock = cx24116_readreg(state, CX24116_REG_SSTATUS) &
|
||||
CX24116_STATUS_MASK;
|
||||
|
||||
dprintk("%s: status = 0x%02x\n", __func__, lock);
|
||||
|
||||
|
|
@ -1205,7 +1208,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
|
|||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
struct cx24116_cmd cmd;
|
||||
fe_status_t tunerstat;
|
||||
int i, status, ret, retune;
|
||||
int i, status, ret, retune = 1;
|
||||
|
||||
dprintk("%s()\n", __func__);
|
||||
|
||||
|
|
@ -1222,7 +1225,6 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
|
|||
|
||||
/* Pilot doesn't exist in DVB-S, turn bit off */
|
||||
state->dnxt.pilot_val = CX24116_PILOT_OFF;
|
||||
retune = 1;
|
||||
|
||||
/* DVB-S only supports 0.35 */
|
||||
if (c->rolloff != ROLLOFF_35) {
|
||||
|
|
@ -1250,7 +1252,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
|
|||
case PILOT_AUTO: /* Not supported but emulated */
|
||||
state->dnxt.pilot_val = (c->modulation == QPSK)
|
||||
? CX24116_PILOT_OFF : CX24116_PILOT_ON;
|
||||
retune = 2;
|
||||
retune++;
|
||||
break;
|
||||
case PILOT_OFF:
|
||||
state->dnxt.pilot_val = CX24116_PILOT_OFF;
|
||||
|
|
@ -1287,6 +1289,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
|
|||
__func__, c->delivery_system);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
state->dnxt.delsys = c->delivery_system;
|
||||
state->dnxt.modulation = c->modulation;
|
||||
state->dnxt.frequency = c->frequency;
|
||||
state->dnxt.pilot = c->pilot;
|
||||
|
|
@ -1297,7 +1300,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
|
|||
return ret;
|
||||
|
||||
/* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */
|
||||
ret = cx24116_set_fec(state, c->modulation, c->fec_inner);
|
||||
ret = cx24116_set_fec(state, c->delivery_system, c->modulation, c->fec_inner);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
|
|
@ -1308,6 +1311,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
|
|||
/* discard the 'current' tuning parameters and prepare to tune */
|
||||
cx24116_clone_params(fe);
|
||||
|
||||
dprintk("%s: delsys = %d\n", __func__, state->dcur.delsys);
|
||||
dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation);
|
||||
dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency);
|
||||
dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__,
|
||||
|
|
@ -1427,6 +1431,23 @@ tuned: /* Set/Reset B/W */
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int cx24116_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *params,
|
||||
unsigned int mode_flags, unsigned int *delay, fe_status_t *status)
|
||||
{
|
||||
*delay = HZ / 5;
|
||||
if (params) {
|
||||
int ret = cx24116_set_frontend(fe, params);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
return cx24116_read_status(fe, status);
|
||||
}
|
||||
|
||||
static int cx24116_get_algo(struct dvb_frontend *fe)
|
||||
{
|
||||
return DVBFE_ALGO_HW;
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops cx24116_ops = {
|
||||
|
||||
.info = {
|
||||
|
|
@ -1458,6 +1479,8 @@ static struct dvb_frontend_ops cx24116_ops = {
|
|||
.set_voltage = cx24116_set_voltage,
|
||||
.diseqc_send_master_cmd = cx24116_send_diseqc_msg,
|
||||
.diseqc_send_burst = cx24116_diseqc_send_burst,
|
||||
.get_frontend_algo = cx24116_get_algo,
|
||||
.tune = cx24116_tune,
|
||||
|
||||
.set_property = cx24116_set_property,
|
||||
.get_property = cx24116_get_property,
|
||||
|
|
|
|||
|
|
@ -66,7 +66,8 @@ struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
|
||||
static inline
|
||||
int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
|
||||
int no_of_demods, u8 default_addr,
|
||||
struct dib7000p_config cfg[])
|
||||
{
|
||||
|
|
@ -74,13 +75,15 @@ extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
extern int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
|
||||
static inline
|
||||
int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
extern int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
|
||||
static inline
|
||||
int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return -ENODEV;
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ static const char mod_name[] = "drx397xD";
|
|||
#define F_SET_0D4h 2
|
||||
|
||||
enum fw_ix {
|
||||
#define _FW_ENTRY(a, b) b
|
||||
#define _FW_ENTRY(a, b, c) b
|
||||
#include "drx397xD_fw.h"
|
||||
};
|
||||
|
||||
|
|
@ -72,11 +72,11 @@ static struct {
|
|||
int refcnt;
|
||||
const u8 *data[ARRAY_SIZE(blob_name)];
|
||||
} fw[] = {
|
||||
#define _FW_ENTRY(a, b) { \
|
||||
.name = a, \
|
||||
.file = 0, \
|
||||
.lock = RW_LOCK_UNLOCKED, \
|
||||
.refcnt = 0, \
|
||||
#define _FW_ENTRY(a, b, c) { \
|
||||
.name = a, \
|
||||
.file = 0, \
|
||||
.lock = __RW_LOCK_UNLOCKED(fw[c].lock), \
|
||||
.refcnt = 0, \
|
||||
.data = { } }
|
||||
#include "drx397xD_fw.h"
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@
|
|||
*/
|
||||
|
||||
#ifdef _FW_ENTRY
|
||||
_FW_ENTRY("drx397xD.A2.fw", DRXD_FW_A2 = 0 ),
|
||||
_FW_ENTRY("drx397xD.B1.fw", DRXD_FW_B1 ),
|
||||
_FW_ENTRY("drx397xD.A2.fw", DRXD_FW_A2 = 0, DRXD_FW_A2 ),
|
||||
_FW_ENTRY("drx397xD.B1.fw", DRXD_FW_B1, DRXD_FW_B1 ),
|
||||
#undef _FW_ENTRY
|
||||
#endif /* _FW_ENTRY */
|
||||
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
|
|||
.count = 4,
|
||||
.entries = {
|
||||
{ 1250000, 500, 0xc4, 0x00},
|
||||
{ 1550000, 500, 0xc4, 0x40},
|
||||
{ 1450000, 500, 0xc4, 0x40},
|
||||
{ 2050000, 500, 0xc4, 0x80},
|
||||
{ 2150000, 500, 0xc4, 0xc0},
|
||||
},
|
||||
|
|
|
|||
378
drivers/media/dvb/frontends/lgdt3304.c
Normal file
378
drivers/media/dvb/frontends/lgdt3304.c
Normal file
|
|
@ -0,0 +1,378 @@
|
|||
/*
|
||||
* Driver for LG ATSC lgdt3304 driver
|
||||
*
|
||||
* Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include "dvb_frontend.h"
|
||||
#include "lgdt3304.h"
|
||||
|
||||
static unsigned int debug = 0;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug,"lgdt3304 debugging (default off)");
|
||||
|
||||
#define dprintk(fmt, args...) if (debug) do {\
|
||||
printk("lgdt3304 debug: " fmt, ##args); } while (0)
|
||||
|
||||
struct lgdt3304_state
|
||||
{
|
||||
struct dvb_frontend frontend;
|
||||
fe_modulation_t current_modulation;
|
||||
__u32 snr;
|
||||
__u32 current_frequency;
|
||||
__u8 addr;
|
||||
struct i2c_adapter *i2c;
|
||||
};
|
||||
|
||||
static int i2c_write_demod_bytes (struct dvb_frontend *fe, __u8 *buf, int len)
|
||||
{
|
||||
struct lgdt3304_state *state = fe->demodulator_priv;
|
||||
struct i2c_msg i2cmsgs = {
|
||||
.addr = state->addr,
|
||||
.flags = 0,
|
||||
.len = 3,
|
||||
.buf = buf
|
||||
};
|
||||
int i;
|
||||
int err;
|
||||
|
||||
for (i=0; i<len-1; i+=3){
|
||||
if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
|
||||
printk("%s i2c_transfer error %d\n", __FUNCTION__, err);
|
||||
if (err < 0)
|
||||
return err;
|
||||
else
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
i2cmsgs.buf += 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lgdt3304_i2c_read_reg(struct dvb_frontend *fe, unsigned int reg)
|
||||
{
|
||||
struct lgdt3304_state *state = fe->demodulator_priv;
|
||||
struct i2c_msg i2cmsgs[2];
|
||||
int ret;
|
||||
__u8 buf;
|
||||
|
||||
__u8 regbuf[2] = { reg>>8, reg&0xff };
|
||||
|
||||
i2cmsgs[0].addr = state->addr;
|
||||
i2cmsgs[0].flags = 0;
|
||||
i2cmsgs[0].len = 2;
|
||||
i2cmsgs[0].buf = regbuf;
|
||||
|
||||
i2cmsgs[1].addr = state->addr;
|
||||
i2cmsgs[1].flags = I2C_M_RD;
|
||||
i2cmsgs[1].len = 1;
|
||||
i2cmsgs[1].buf = &buf;
|
||||
|
||||
if((ret = i2c_transfer(state->i2c, i2cmsgs, 2))<0) {
|
||||
printk("%s i2c_transfer error %d\n", __FUNCTION__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int lgdt3304_i2c_write_reg(struct dvb_frontend *fe, int reg, int val)
|
||||
{
|
||||
struct lgdt3304_state *state = fe->demodulator_priv;
|
||||
char buffer[3] = { reg>>8, reg&0xff, val };
|
||||
int ret;
|
||||
|
||||
struct i2c_msg i2cmsgs = {
|
||||
.addr = state->addr,
|
||||
.flags = 0,
|
||||
.len = 3,
|
||||
.buf=buffer
|
||||
};
|
||||
ret = i2c_transfer(state->i2c, &i2cmsgs, 1);
|
||||
if (ret != 1) {
|
||||
printk("%s i2c_transfer error %d\n", __FUNCTION__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int lgdt3304_soft_Reset(struct dvb_frontend *fe)
|
||||
{
|
||||
lgdt3304_i2c_write_reg(fe, 0x0002, 0x9a);
|
||||
lgdt3304_i2c_write_reg(fe, 0x0002, 0x9b);
|
||||
mdelay(200);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lgdt3304_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) {
|
||||
int err = 0;
|
||||
|
||||
static __u8 lgdt3304_vsb8_data[] = {
|
||||
/* 16bit , 8bit */
|
||||
/* regs , val */
|
||||
0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x13,
|
||||
0x00, 0x0d, 0x02,
|
||||
0x00, 0x0e, 0x02,
|
||||
0x00, 0x12, 0x32,
|
||||
0x00, 0x13, 0xc4,
|
||||
0x01, 0x12, 0x17,
|
||||
0x01, 0x13, 0x15,
|
||||
0x01, 0x14, 0x18,
|
||||
0x01, 0x15, 0xff,
|
||||
0x01, 0x16, 0x2c,
|
||||
0x02, 0x14, 0x67,
|
||||
0x02, 0x24, 0x8d,
|
||||
0x04, 0x27, 0x12,
|
||||
0x04, 0x28, 0x4f,
|
||||
0x03, 0x08, 0x80,
|
||||
0x03, 0x09, 0x00,
|
||||
0x03, 0x0d, 0x00,
|
||||
0x03, 0x0e, 0x1c,
|
||||
0x03, 0x14, 0xe1,
|
||||
0x05, 0x0e, 0x5b,
|
||||
};
|
||||
|
||||
/* not yet tested .. */
|
||||
static __u8 lgdt3304_qam64_data[] = {
|
||||
/* 16bit , 8bit */
|
||||
/* regs , val */
|
||||
0x00, 0x00, 0x18,
|
||||
0x00, 0x0d, 0x02,
|
||||
//0x00, 0x0e, 0x02,
|
||||
0x00, 0x12, 0x2a,
|
||||
0x00, 0x13, 0x00,
|
||||
0x03, 0x14, 0xe3,
|
||||
0x03, 0x0e, 0x1c,
|
||||
0x03, 0x08, 0x66,
|
||||
0x03, 0x09, 0x66,
|
||||
0x03, 0x0a, 0x08,
|
||||
0x03, 0x0b, 0x9b,
|
||||
0x05, 0x0e, 0x5b,
|
||||
};
|
||||
|
||||
|
||||
/* tested with KWorld a340 */
|
||||
static __u8 lgdt3304_qam256_data[] = {
|
||||
/* 16bit , 8bit */
|
||||
/* regs , val */
|
||||
0x00, 0x00, 0x01, //0x19,
|
||||
0x00, 0x12, 0x2a,
|
||||
0x00, 0x13, 0x80,
|
||||
0x00, 0x0d, 0x02,
|
||||
0x03, 0x14, 0xe3,
|
||||
|
||||
0x03, 0x0e, 0x1c,
|
||||
0x03, 0x08, 0x66,
|
||||
0x03, 0x09, 0x66,
|
||||
0x03, 0x0a, 0x08,
|
||||
0x03, 0x0b, 0x9b,
|
||||
|
||||
0x03, 0x0d, 0x14,
|
||||
//0x05, 0x0e, 0x5b,
|
||||
0x01, 0x06, 0x4a,
|
||||
0x01, 0x07, 0x3d,
|
||||
0x01, 0x08, 0x70,
|
||||
0x01, 0x09, 0xa3,
|
||||
|
||||
0x05, 0x04, 0xfd,
|
||||
|
||||
0x00, 0x0d, 0x82,
|
||||
|
||||
0x05, 0x0e, 0x5b,
|
||||
|
||||
0x05, 0x0e, 0x5b,
|
||||
|
||||
0x00, 0x02, 0x9a,
|
||||
|
||||
0x00, 0x02, 0x9b,
|
||||
|
||||
0x00, 0x00, 0x01,
|
||||
0x00, 0x12, 0x2a,
|
||||
0x00, 0x13, 0x80,
|
||||
0x00, 0x0d, 0x02,
|
||||
0x03, 0x14, 0xe3,
|
||||
|
||||
0x03, 0x0e, 0x1c,
|
||||
0x03, 0x08, 0x66,
|
||||
0x03, 0x09, 0x66,
|
||||
0x03, 0x0a, 0x08,
|
||||
0x03, 0x0b, 0x9b,
|
||||
|
||||
0x03, 0x0d, 0x14,
|
||||
0x01, 0x06, 0x4a,
|
||||
0x01, 0x07, 0x3d,
|
||||
0x01, 0x08, 0x70,
|
||||
0x01, 0x09, 0xa3,
|
||||
|
||||
0x05, 0x04, 0xfd,
|
||||
|
||||
0x00, 0x0d, 0x82,
|
||||
|
||||
0x05, 0x0e, 0x5b,
|
||||
};
|
||||
|
||||
struct lgdt3304_state *state = fe->demodulator_priv;
|
||||
if (state->current_modulation != param->u.vsb.modulation) {
|
||||
switch(param->u.vsb.modulation) {
|
||||
case VSB_8:
|
||||
err = i2c_write_demod_bytes(fe, lgdt3304_vsb8_data,
|
||||
sizeof(lgdt3304_vsb8_data));
|
||||
break;
|
||||
case QAM_64:
|
||||
err = i2c_write_demod_bytes(fe, lgdt3304_qam64_data,
|
||||
sizeof(lgdt3304_qam64_data));
|
||||
break;
|
||||
case QAM_256:
|
||||
err = i2c_write_demod_bytes(fe, lgdt3304_qam256_data,
|
||||
sizeof(lgdt3304_qam256_data));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
printk("%s error setting modulation\n", __FUNCTION__);
|
||||
} else {
|
||||
state->current_modulation = param->u.vsb.modulation;
|
||||
}
|
||||
}
|
||||
state->current_frequency = param->frequency;
|
||||
|
||||
lgdt3304_soft_Reset(fe);
|
||||
|
||||
|
||||
if (fe->ops.tuner_ops.set_params)
|
||||
fe->ops.tuner_ops.set_params(fe, param);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lgdt3304_init(struct dvb_frontend *fe) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lgdt3304_sleep(struct dvb_frontend *fe) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int lgdt3304_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
{
|
||||
struct lgdt3304_state *state = fe->demodulator_priv;
|
||||
int r011d;
|
||||
int qam_lck;
|
||||
|
||||
*status = 0;
|
||||
dprintk("lgdt read status\n");
|
||||
|
||||
r011d = lgdt3304_i2c_read_reg(fe, 0x011d);
|
||||
|
||||
dprintk("%02x\n", r011d);
|
||||
|
||||
switch(state->current_modulation) {
|
||||
case VSB_8:
|
||||
if (r011d & 0x80) {
|
||||
dprintk("VSB Locked\n");
|
||||
*status |= FE_HAS_CARRIER;
|
||||
*status |= FE_HAS_LOCK;
|
||||
*status |= FE_HAS_SYNC;
|
||||
*status |= FE_HAS_SIGNAL;
|
||||
}
|
||||
break;
|
||||
case QAM_64:
|
||||
case QAM_256:
|
||||
qam_lck = r011d & 0x7;
|
||||
switch(qam_lck) {
|
||||
case 0x0: dprintk("Unlock\n");
|
||||
break;
|
||||
case 0x4: dprintk("1st Lock in acquisition state\n");
|
||||
break;
|
||||
case 0x6: dprintk("2nd Lock in acquisition state\n");
|
||||
break;
|
||||
case 0x7: dprintk("Final Lock in good reception state\n");
|
||||
*status |= FE_HAS_CARRIER;
|
||||
*status |= FE_HAS_LOCK;
|
||||
*status |= FE_HAS_SYNC;
|
||||
*status |= FE_HAS_SIGNAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printk("%s unhandled modulation\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lgdt3304_read_ber(struct dvb_frontend *fe, __u32 *ber)
|
||||
{
|
||||
dprintk("read ber\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lgdt3304_read_snr(struct dvb_frontend *fe, __u16 *snr)
|
||||
{
|
||||
dprintk("read snr\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lgdt3304_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks)
|
||||
{
|
||||
dprintk("read ucblocks\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lgdt3304_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct lgdt3304_state *state = (struct lgdt3304_state *)fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops demod_lgdt3304={
|
||||
.info = {
|
||||
.name = "LG 3304",
|
||||
.type = FE_ATSC,
|
||||
.frequency_min = 54000000,
|
||||
.frequency_max = 858000000,
|
||||
.frequency_stepsize = 62500,
|
||||
.symbol_rate_min = 5056941,
|
||||
.symbol_rate_max = 10762000,
|
||||
.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
|
||||
},
|
||||
.init = lgdt3304_init,
|
||||
.sleep = lgdt3304_sleep,
|
||||
.set_frontend = lgdt3304_set_parameters,
|
||||
.read_snr = lgdt3304_read_snr,
|
||||
.read_ber = lgdt3304_read_ber,
|
||||
.read_status = lgdt3304_read_status,
|
||||
.read_ucblocks = lgdt3304_read_ucblocks,
|
||||
.release = lgdt3304_release,
|
||||
};
|
||||
|
||||
struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
|
||||
struct lgdt3304_state *state;
|
||||
state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL);
|
||||
memset(state, 0x0, sizeof(struct lgdt3304_state));
|
||||
state->addr = config->i2c_address;
|
||||
state->i2c = i2c;
|
||||
|
||||
memcpy(&state->frontend.ops, &demod_lgdt3304, sizeof(struct dvb_frontend_ops));
|
||||
state->frontend.demodulator_priv = state;
|
||||
return &state->frontend;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(lgdt3304_attach);
|
||||
MODULE_AUTHOR("Markus Rechberger <[email protected]>");
|
||||
MODULE_DESCRIPTION("LGE LGDT3304 DVB-T demodulator driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
45
drivers/media/dvb/frontends/lgdt3304.h
Normal file
45
drivers/media/dvb/frontends/lgdt3304.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Driver for DVB-T lgdt3304 demodulator
|
||||
*
|
||||
* Copyright (C) 2008 Markus Rechberger <mrechberger@gmail.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 LGDT3304_H
|
||||
#define LGDT3304_H
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
struct lgdt3304_config
|
||||
{
|
||||
/* demodulator's I2C address */
|
||||
u8 i2c_address;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_LGDT3304) || (defined(CONFIG_DVB_LGDT3304_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DVB_LGDT */
|
||||
|
||||
#endif /* LGDT3304_H */
|
||||
|
|
@ -874,6 +874,9 @@ struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config,
|
|||
/* Note: Leaving the I2C gate open here. */
|
||||
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1);
|
||||
|
||||
/* Put the device into low-power mode until first use */
|
||||
s5h1411_set_powerstate(&state->frontend, 1);
|
||||
|
||||
return &state->frontend;
|
||||
|
||||
error:
|
||||
|
|
|
|||
216
drivers/media/dvb/frontends/s921_core.c
Normal file
216
drivers/media/dvb/frontends/s921_core.c
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Driver for Sharp s921 driver
|
||||
*
|
||||
* Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include "s921_core.h"
|
||||
|
||||
static int s921_isdb_init(struct s921_isdb_t *dev);
|
||||
static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params);
|
||||
static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params);
|
||||
static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data);
|
||||
|
||||
static u8 init_table[]={ 0x01, 0x40, 0x02, 0x00, 0x03, 0x40, 0x04, 0x01,
|
||||
0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00,
|
||||
0x09, 0x00, 0x0a, 0x00, 0x0b, 0x5a, 0x0c, 0x00,
|
||||
0x0d, 0x00, 0x0f, 0x00, 0x13, 0x1b, 0x14, 0x80,
|
||||
0x15, 0x40, 0x17, 0x70, 0x18, 0x01, 0x19, 0x12,
|
||||
0x1a, 0x01, 0x1b, 0x12, 0x1c, 0xa0, 0x1d, 0x00,
|
||||
0x1e, 0x0a, 0x1f, 0x08, 0x20, 0x40, 0x21, 0xff,
|
||||
0x22, 0x4c, 0x23, 0x4e, 0x24, 0x4c, 0x25, 0x00,
|
||||
0x26, 0x00, 0x27, 0xf4, 0x28, 0x60, 0x29, 0x88,
|
||||
0x2a, 0x40, 0x2b, 0x40, 0x2c, 0xff, 0x2d, 0x00,
|
||||
0x2e, 0xff, 0x2f, 0x00, 0x30, 0x20, 0x31, 0x06,
|
||||
0x32, 0x0c, 0x34, 0x0f, 0x37, 0xfe, 0x38, 0x00,
|
||||
0x39, 0x63, 0x3a, 0x10, 0x3b, 0x10, 0x47, 0x00,
|
||||
0x49, 0xe5, 0x4b, 0x00, 0x50, 0xc0, 0x52, 0x20,
|
||||
0x54, 0x5a, 0x55, 0x5b, 0x56, 0x40, 0x57, 0x70,
|
||||
0x5c, 0x50, 0x5d, 0x00, 0x62, 0x17, 0x63, 0x2f,
|
||||
0x64, 0x6f, 0x68, 0x00, 0x69, 0x89, 0x6a, 0x00,
|
||||
0x6b, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6e, 0x00,
|
||||
0x70, 0x00, 0x71, 0x00, 0x75, 0x00, 0x76, 0x30,
|
||||
0x77, 0x01, 0xaf, 0x00, 0xb0, 0xa0, 0xb2, 0x3d,
|
||||
0xb3, 0x25, 0xb4, 0x8b, 0xb5, 0x4b, 0xb6, 0x3f,
|
||||
0xb7, 0xff, 0xb8, 0xff, 0xb9, 0xfc, 0xba, 0x00,
|
||||
0xbb, 0x00, 0xbc, 0x00, 0xd0, 0x30, 0xe4, 0x84,
|
||||
0xf0, 0x48, 0xf1, 0x19, 0xf2, 0x5a, 0xf3, 0x8e,
|
||||
0xf4, 0x2d, 0xf5, 0x07, 0xf6, 0x5a, 0xf7, 0xba,
|
||||
0xf8, 0xd7 };
|
||||
|
||||
static u8 c_table[]={ 0x58, 0x8a, 0x7b, 0x59, 0x8c, 0x7b, 0x5a, 0x8e, 0x5b,
|
||||
0x5b, 0x90, 0x5b, 0x5c, 0x92, 0x5b, 0x5d, 0x94, 0x5b,
|
||||
0x5e, 0x96, 0x5b, 0x5f, 0x98, 0x3b, 0x60, 0x9a, 0x3b,
|
||||
0x61, 0x9c, 0x3b, 0x62, 0x9e, 0x3b, 0x63, 0xa0, 0x3b,
|
||||
0x64, 0xa2, 0x1b, 0x65, 0xa4, 0x1b, 0x66, 0xa6, 0x1b,
|
||||
0x67, 0xa8, 0x1b, 0x68, 0xaa, 0x1b, 0x69, 0xac, 0x1b,
|
||||
0x6a, 0xae, 0x1b, 0x6b, 0xb0, 0x1b, 0x6c, 0xb2, 0x1b,
|
||||
0x6d, 0xb4, 0xfb, 0x6e, 0xb6, 0xfb, 0x6f, 0xb8, 0xfb,
|
||||
0x70, 0xba, 0xfb, 0x71, 0xbc, 0xdb, 0x72, 0xbe, 0xdb,
|
||||
0x73, 0xc0, 0xdb, 0x74, 0xc2, 0xdb, 0x75, 0xc4, 0xdb,
|
||||
0x76, 0xc6, 0xdb, 0x77, 0xc8, 0xbb, 0x78, 0xca, 0xbb,
|
||||
0x79, 0xcc, 0xbb, 0x7a, 0xce, 0xbb, 0x7b, 0xd0, 0xbb,
|
||||
0x7c, 0xd2, 0xbb, 0x7d, 0xd4, 0xbb, 0x7e, 0xd6, 0xbb,
|
||||
0x7f, 0xd8, 0xbb, 0x80, 0xda, 0x9b, 0x81, 0xdc, 0x9b,
|
||||
0x82, 0xde, 0x9b, 0x83, 0xe0, 0x9b, 0x84, 0xe2, 0x9b,
|
||||
0x85, 0xe4, 0x9b, 0x86, 0xe6, 0x9b, 0x87, 0xe8, 0x9b,
|
||||
0x88, 0xea, 0x9b, 0x89, 0xec, 0x9b };
|
||||
|
||||
int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data) {
|
||||
switch(cmd) {
|
||||
case ISDB_T_CMD_INIT:
|
||||
s921_isdb_init(dev);
|
||||
break;
|
||||
case ISDB_T_CMD_SET_PARAM:
|
||||
s921_isdb_set_parameters(dev, data);
|
||||
break;
|
||||
case ISDB_T_CMD_TUNE:
|
||||
s921_isdb_tune(dev, data);
|
||||
break;
|
||||
case ISDB_T_CMD_GET_STATUS:
|
||||
s921_isdb_get_status(dev, data);
|
||||
break;
|
||||
default:
|
||||
printk("unhandled command\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s921_isdb_init(struct s921_isdb_t *dev) {
|
||||
unsigned int i;
|
||||
unsigned int ret;
|
||||
printk("isdb_init\n");
|
||||
for (i = 0; i < sizeof(init_table); i+=2) {
|
||||
ret = dev->i2c_write(dev->priv_dev, init_table[i], init_table[i+1]);
|
||||
if (ret != 0) {
|
||||
printk("i2c write failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params) {
|
||||
|
||||
int ret;
|
||||
/* auto is sufficient for now, lateron this should be reflected in an extra interface */
|
||||
|
||||
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0xb0, 0xa0); //mod_b2);
|
||||
ret = dev->i2c_write(dev->priv_dev, 0xb2, 0x3d); //mod_b2);
|
||||
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0xb3, 0x25); //mod_b3);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0xb4, 0x8b); //mod_b4);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0xb5, 0x4b); //mod_b5);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0xb6, 0x3f); //mod_b6);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0xb7, 0x3f); //mod_b7);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params) {
|
||||
|
||||
int ret;
|
||||
int index;
|
||||
|
||||
index = (params->frequency - 473143000)/6000000;
|
||||
|
||||
if (index > 48) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev->i2c_write(dev->priv_dev, 0x47, 0x60);
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0x68, 0x00);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0x69, 0x89);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0xf0, 0x48);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0xf1, 0x19);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0xf2, c_table[index*3]);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0xf3, c_table[index*3+1]);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0xf4, c_table[index*3+2]);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0xf5, 0xae);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0xf6, 0xb7);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0xf7, 0xba);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0xf8, 0xd7);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0x68, 0x0a);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dev->i2c_write(dev->priv_dev, 0x69, 0x09);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
dev->i2c_write(dev->priv_dev, 0x01, 0x40);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data) {
|
||||
unsigned int *ret = (unsigned int*)data;
|
||||
u8 ifagc_dt;
|
||||
u8 rfagc_dt;
|
||||
|
||||
mdelay(10);
|
||||
ifagc_dt = dev->i2c_read(dev->priv_dev, 0x81);
|
||||
rfagc_dt = dev->i2c_read(dev->priv_dev, 0x82);
|
||||
if (rfagc_dt == 0x40) {
|
||||
*ret = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
114
drivers/media/dvb/frontends/s921_core.h
Normal file
114
drivers/media/dvb/frontends/s921_core.h
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
#ifndef _S921_CORE_H
|
||||
#define _S921_CORE_H
|
||||
//#define u8 unsigned int
|
||||
//#define u32 unsigned int
|
||||
|
||||
|
||||
|
||||
//#define EINVAL -1
|
||||
#define E_OK 0
|
||||
|
||||
struct s921_isdb_t {
|
||||
void *priv_dev;
|
||||
int (*i2c_write)(void *dev, u8 reg, u8 val);
|
||||
int (*i2c_read)(void *dev, u8 reg);
|
||||
};
|
||||
|
||||
#define ISDB_T_CMD_INIT 0
|
||||
#define ISDB_T_CMD_SET_PARAM 1
|
||||
#define ISDB_T_CMD_TUNE 2
|
||||
#define ISDB_T_CMD_GET_STATUS 3
|
||||
|
||||
struct s921_isdb_t_tune_params {
|
||||
u32 frequency;
|
||||
};
|
||||
|
||||
struct s921_isdb_t_status {
|
||||
};
|
||||
|
||||
struct s921_isdb_t_transmission_mode_params {
|
||||
u8 mode;
|
||||
u8 layer_a_mode;
|
||||
#define ISDB_T_LA_MODE_1 0
|
||||
#define ISDB_T_LA_MODE_2 1
|
||||
#define ISDB_T_LA_MODE_3 2
|
||||
u8 layer_a_carrier_modulation;
|
||||
#define ISDB_T_LA_CM_DQPSK 0
|
||||
#define ISDB_T_LA_CM_QPSK 1
|
||||
#define ISDB_T_LA_CM_16QAM 2
|
||||
#define ISDB_T_LA_CM_64QAM 3
|
||||
#define ISDB_T_LA_CM_NOLAYER 4
|
||||
u8 layer_a_code_rate;
|
||||
#define ISDB_T_LA_CR_1_2 0
|
||||
#define ISDB_T_LA_CR_2_3 1
|
||||
#define ISDB_T_LA_CR_3_4 2
|
||||
#define ISDB_T_LA_CR_5_6 4
|
||||
#define ISDB_T_LA_CR_7_8 8
|
||||
#define ISDB_T_LA_CR_NOLAYER 16
|
||||
u8 layer_a_time_interleave;
|
||||
#define ISDB_T_LA_TI_0 0
|
||||
#define ISDB_T_LA_TI_1 1
|
||||
#define ISDB_T_LA_TI_2 2
|
||||
#define ISDB_T_LA_TI_4 4
|
||||
#define ISDB_T_LA_TI_8 8
|
||||
#define ISDB_T_LA_TI_16 16
|
||||
#define ISDB_T_LA_TI_32 32
|
||||
u8 layer_a_nseg;
|
||||
|
||||
u8 layer_b_mode;
|
||||
#define ISDB_T_LB_MODE_1 0
|
||||
#define ISDB_T_LB_MODE_2 1
|
||||
#define ISDB_T_LB_MODE_3 2
|
||||
u8 layer_b_carrier_modulation;
|
||||
#define ISDB_T_LB_CM_DQPSK 0
|
||||
#define ISDB_T_LB_CM_QPSK 1
|
||||
#define ISDB_T_LB_CM_16QAM 2
|
||||
#define ISDB_T_LB_CM_64QAM 3
|
||||
#define ISDB_T_LB_CM_NOLAYER 4
|
||||
u8 layer_b_code_rate;
|
||||
#define ISDB_T_LB_CR_1_2 0
|
||||
#define ISDB_T_LB_CR_2_3 1
|
||||
#define ISDB_T_LB_CR_3_4 2
|
||||
#define ISDB_T_LB_CR_5_6 4
|
||||
#define ISDB_T_LB_CR_7_8 8
|
||||
#define ISDB_T_LB_CR_NOLAYER 16
|
||||
u8 layer_b_time_interleave;
|
||||
#define ISDB_T_LB_TI_0 0
|
||||
#define ISDB_T_LB_TI_1 1
|
||||
#define ISDB_T_LB_TI_2 2
|
||||
#define ISDB_T_LB_TI_4 4
|
||||
#define ISDB_T_LB_TI_8 8
|
||||
#define ISDB_T_LB_TI_16 16
|
||||
#define ISDB_T_LB_TI_32 32
|
||||
u8 layer_b_nseg;
|
||||
|
||||
u8 layer_c_mode;
|
||||
#define ISDB_T_LC_MODE_1 0
|
||||
#define ISDB_T_LC_MODE_2 1
|
||||
#define ISDB_T_LC_MODE_3 2
|
||||
u8 layer_c_carrier_modulation;
|
||||
#define ISDB_T_LC_CM_DQPSK 0
|
||||
#define ISDB_T_LC_CM_QPSK 1
|
||||
#define ISDB_T_LC_CM_16QAM 2
|
||||
#define ISDB_T_LC_CM_64QAM 3
|
||||
#define ISDB_T_LC_CM_NOLAYER 4
|
||||
u8 layer_c_code_rate;
|
||||
#define ISDB_T_LC_CR_1_2 0
|
||||
#define ISDB_T_LC_CR_2_3 1
|
||||
#define ISDB_T_LC_CR_3_4 2
|
||||
#define ISDB_T_LC_CR_5_6 4
|
||||
#define ISDB_T_LC_CR_7_8 8
|
||||
#define ISDB_T_LC_CR_NOLAYER 16
|
||||
u8 layer_c_time_interleave;
|
||||
#define ISDB_T_LC_TI_0 0
|
||||
#define ISDB_T_LC_TI_1 1
|
||||
#define ISDB_T_LC_TI_2 2
|
||||
#define ISDB_T_LC_TI_4 4
|
||||
#define ISDB_T_LC_TI_8 8
|
||||
#define ISDB_T_LC_TI_16 16
|
||||
#define ISDB_T_LC_TI_32 32
|
||||
u8 layer_c_nseg;
|
||||
};
|
||||
|
||||
int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data);
|
||||
#endif
|
||||
190
drivers/media/dvb/frontends/s921_module.c
Normal file
190
drivers/media/dvb/frontends/s921_module.c
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Driver for Sharp s921 driver
|
||||
*
|
||||
* Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include "dvb_frontend.h"
|
||||
#include "s921_module.h"
|
||||
#include "s921_core.h"
|
||||
|
||||
static unsigned int debug = 0;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug,"s921 debugging (default off)");
|
||||
|
||||
#define dprintk(fmt, args...) if (debug) do {\
|
||||
printk("s921 debug: " fmt, ##args); } while (0)
|
||||
|
||||
struct s921_state
|
||||
{
|
||||
struct dvb_frontend frontend;
|
||||
fe_modulation_t current_modulation;
|
||||
__u32 snr;
|
||||
__u32 current_frequency;
|
||||
__u8 addr;
|
||||
struct s921_isdb_t dev;
|
||||
struct i2c_adapter *i2c;
|
||||
};
|
||||
|
||||
static int s921_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) {
|
||||
struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
|
||||
struct s921_isdb_t_transmission_mode_params params;
|
||||
struct s921_isdb_t_tune_params tune_params;
|
||||
|
||||
tune_params.frequency = param->frequency;
|
||||
s921_isdb_cmd(&state->dev, ISDB_T_CMD_SET_PARAM, ¶ms);
|
||||
s921_isdb_cmd(&state->dev, ISDB_T_CMD_TUNE, &tune_params);
|
||||
mdelay(100);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s921_init(struct dvb_frontend *fe) {
|
||||
printk("s921 init\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s921_sleep(struct dvb_frontend *fe) {
|
||||
printk("s921 sleep\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
{
|
||||
struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
|
||||
unsigned int ret;
|
||||
mdelay(5);
|
||||
s921_isdb_cmd(&state->dev, ISDB_T_CMD_GET_STATUS, &ret);
|
||||
*status = 0;
|
||||
|
||||
printk("status: %02x\n", ret);
|
||||
if (ret == 1) {
|
||||
*status |= FE_HAS_CARRIER;
|
||||
*status |= FE_HAS_VITERBI;
|
||||
*status |= FE_HAS_LOCK;
|
||||
*status |= FE_HAS_SYNC;
|
||||
*status |= FE_HAS_SIGNAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s921_read_ber(struct dvb_frontend *fe, __u32 *ber)
|
||||
{
|
||||
dprintk("read ber\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s921_read_snr(struct dvb_frontend *fe, __u16 *snr)
|
||||
{
|
||||
dprintk("read snr\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s921_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks)
|
||||
{
|
||||
dprintk("read ucblocks\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void s921_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops demod_s921={
|
||||
.info = {
|
||||
.name = "SHARP S921",
|
||||
.type = FE_OFDM,
|
||||
.frequency_min = 473143000,
|
||||
.frequency_max = 767143000,
|
||||
.frequency_stepsize = 6000000,
|
||||
.frequency_tolerance = 0,
|
||||
.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 |
|
||||
FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER |
|
||||
FE_CAN_MUTE_TS
|
||||
},
|
||||
.init = s921_init,
|
||||
.sleep = s921_sleep,
|
||||
.set_frontend = s921_set_parameters,
|
||||
.read_snr = s921_read_snr,
|
||||
.read_ber = s921_read_ber,
|
||||
.read_status = s921_read_status,
|
||||
.read_ucblocks = s921_read_ucblocks,
|
||||
.release = s921_release,
|
||||
};
|
||||
|
||||
static int s921_write(void *dev, u8 reg, u8 val) {
|
||||
struct s921_state *state = dev;
|
||||
char buf[2]={reg,val};
|
||||
int err;
|
||||
struct i2c_msg i2cmsgs = {
|
||||
.addr = state->addr,
|
||||
.flags = 0,
|
||||
.len = 2,
|
||||
.buf = buf
|
||||
};
|
||||
|
||||
if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
|
||||
printk("%s i2c_transfer error %d\n", __FUNCTION__, err);
|
||||
if (err < 0)
|
||||
return err;
|
||||
else
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s921_read(void *dev, u8 reg) {
|
||||
struct s921_state *state = dev;
|
||||
u8 b1;
|
||||
int ret;
|
||||
struct i2c_msg msg[2] = { { .addr = state->addr,
|
||||
.flags = 0,
|
||||
.buf = ®, .len = 1 },
|
||||
{ .addr = state->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = &b1, .len = 1 } };
|
||||
|
||||
ret = i2c_transfer(state->i2c, msg, 2);
|
||||
if (ret != 2)
|
||||
return ret;
|
||||
return b1;
|
||||
}
|
||||
|
||||
struct dvb_frontend* s921_attach(const struct s921_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
|
||||
struct s921_state *state;
|
||||
state = kzalloc(sizeof(struct s921_state), GFP_KERNEL);
|
||||
memset(state, 0x0, sizeof(struct s921_state));
|
||||
|
||||
state->addr = config->i2c_address;
|
||||
state->i2c = i2c;
|
||||
state->dev.i2c_write = &s921_write;
|
||||
state->dev.i2c_read = &s921_read;
|
||||
state->dev.priv_dev = state;
|
||||
|
||||
s921_isdb_cmd(&state->dev, ISDB_T_CMD_INIT, NULL);
|
||||
|
||||
memcpy(&state->frontend.ops, &demod_s921, sizeof(struct dvb_frontend_ops));
|
||||
state->frontend.demodulator_priv = state;
|
||||
return &state->frontend;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(s921_attach);
|
||||
MODULE_AUTHOR("Markus Rechberger <[email protected]>");
|
||||
MODULE_DESCRIPTION("Sharp S921 ISDB-T 1Seg");
|
||||
MODULE_LICENSE("GPL");
|
||||
49
drivers/media/dvb/frontends/s921_module.h
Normal file
49
drivers/media/dvb/frontends/s921_module.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Driver for DVB-T s921 demodulator
|
||||
*
|
||||
* Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
|
||||
*
|
||||
* 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 S921_MODULE_H
|
||||
#define S921_MODULE_H
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include "s921_core.h"
|
||||
|
||||
int s921_isdb_init(struct s921_isdb_t *dev);
|
||||
int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data);
|
||||
|
||||
struct s921_config
|
||||
{
|
||||
/* demodulator's I2C address */
|
||||
u8 i2c_address;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_S921) || (defined(CONFIG_DVB_S921_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend* s921_attach(const struct s921_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend* s921_attach(const struct s921_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DVB_S921 */
|
||||
|
||||
#endif /* S921_H */
|
||||
|
|
@ -8,7 +8,6 @@
|
|||
* (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
#include <linux/version.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
|
|
|||
1519
drivers/media/dvb/frontends/stb0899_algo.c
Normal file
1519
drivers/media/dvb/frontends/stb0899_algo.c
Normal file
File diff suppressed because it is too large
Load diff
287
drivers/media/dvb/frontends/stb0899_cfg.h
Normal file
287
drivers/media/dvb/frontends/stb0899_cfg.h
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
/*
|
||||
STB0899 Multistandard Frontend driver
|
||||
Copyright (C) Manu Abraham (abraham.manu@gmail.com)
|
||||
|
||||
Copyright (C) ST Microelectronics
|
||||
|
||||
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 __STB0899_CFG_H
|
||||
#define __STB0899_CFG_H
|
||||
|
||||
static const struct stb0899_s2_reg stb0899_s2_init_2[] = {
|
||||
|
||||
{ STB0899_OFF0_DMD_STATUS , STB0899_BASE_DMD_STATUS , 0x00000103 }, /* DMDSTATUS */
|
||||
{ STB0899_OFF0_CRL_FREQ , STB0899_BASE_CRL_FREQ , 0x3ed1da56 }, /* CRLFREQ */
|
||||
{ STB0899_OFF0_BTR_FREQ , STB0899_BASE_BTR_FREQ , 0x00004000 }, /* BTRFREQ */
|
||||
{ STB0899_OFF0_IF_AGC_GAIN , STB0899_BASE_IF_AGC_GAIN , 0x00002ade }, /* IFAGCGAIN */
|
||||
{ STB0899_OFF0_BB_AGC_GAIN , STB0899_BASE_BB_AGC_GAIN , 0x000001bc }, /* BBAGCGAIN */
|
||||
{ STB0899_OFF0_DC_OFFSET , STB0899_BASE_DC_OFFSET , 0x00000200 }, /* DCOFFSET */
|
||||
{ STB0899_OFF0_DMD_CNTRL , STB0899_BASE_DMD_CNTRL , 0x0000000f }, /* DMDCNTRL */
|
||||
|
||||
{ STB0899_OFF0_IF_AGC_CNTRL , STB0899_BASE_IF_AGC_CNTRL , 0x03fb4a20 }, /* IFAGCCNTRL */
|
||||
{ STB0899_OFF0_BB_AGC_CNTRL , STB0899_BASE_BB_AGC_CNTRL , 0x00200c97 }, /* BBAGCCNTRL */
|
||||
|
||||
{ STB0899_OFF0_CRL_CNTRL , STB0899_BASE_CRL_CNTRL , 0x00000016 }, /* CRLCNTRL */
|
||||
{ STB0899_OFF0_CRL_PHS_INIT , STB0899_BASE_CRL_PHS_INIT , 0x00000000 }, /* CRLPHSINIT */
|
||||
{ STB0899_OFF0_CRL_FREQ_INIT , STB0899_BASE_CRL_FREQ_INIT , 0x00000000 }, /* CRLFREQINIT */
|
||||
{ STB0899_OFF0_CRL_LOOP_GAIN , STB0899_BASE_CRL_LOOP_GAIN , 0x00000000 }, /* CRLLOOPGAIN */
|
||||
{ STB0899_OFF0_CRL_NOM_FREQ , STB0899_BASE_CRL_NOM_FREQ , 0x3ed097b6 }, /* CRLNOMFREQ */
|
||||
{ STB0899_OFF0_CRL_SWP_RATE , STB0899_BASE_CRL_SWP_RATE , 0x00000000 }, /* CRLSWPRATE */
|
||||
{ STB0899_OFF0_CRL_MAX_SWP , STB0899_BASE_CRL_MAX_SWP , 0x00000000 }, /* CRLMAXSWP */
|
||||
{ STB0899_OFF0_CRL_LK_CNTRL , STB0899_BASE_CRL_LK_CNTRL , 0x0f6cdc01 }, /* CRLLKCNTRL */
|
||||
{ STB0899_OFF0_DECIM_CNTRL , STB0899_BASE_DECIM_CNTRL , 0x00000000 }, /* DECIMCNTRL */
|
||||
{ STB0899_OFF0_BTR_CNTRL , STB0899_BASE_BTR_CNTRL , 0x00003993 }, /* BTRCNTRL */
|
||||
{ STB0899_OFF0_BTR_LOOP_GAIN , STB0899_BASE_BTR_LOOP_GAIN , 0x000d3c6f }, /* BTRLOOPGAIN */
|
||||
{ STB0899_OFF0_BTR_PHS_INIT , STB0899_BASE_BTR_PHS_INIT , 0x00000000 }, /* BTRPHSINIT */
|
||||
{ STB0899_OFF0_BTR_FREQ_INIT , STB0899_BASE_BTR_FREQ_INIT , 0x00000000 }, /* BTRFREQINIT */
|
||||
{ STB0899_OFF0_BTR_NOM_FREQ , STB0899_BASE_BTR_NOM_FREQ , 0x0238e38e }, /* BTRNOMFREQ */
|
||||
{ STB0899_OFF0_BTR_LK_CNTRL , STB0899_BASE_BTR_LK_CNTRL , 0x00000000 }, /* BTRLKCNTRL */
|
||||
{ STB0899_OFF0_DECN_CNTRL , STB0899_BASE_DECN_CNTRL , 0x00000000 }, /* DECNCNTRL */
|
||||
{ STB0899_OFF0_TP_CNTRL , STB0899_BASE_TP_CNTRL , 0x00000000 }, /* TPCNTRL */
|
||||
{ STB0899_OFF0_TP_BUF_STATUS , STB0899_BASE_TP_BUF_STATUS , 0x00000000 }, /* TPBUFSTATUS */
|
||||
{ STB0899_OFF0_DC_ESTIM , STB0899_BASE_DC_ESTIM , 0x00000000 }, /* DCESTIM */
|
||||
{ STB0899_OFF0_FLL_CNTRL , STB0899_BASE_FLL_CNTRL , 0x00000000 }, /* FLLCNTRL */
|
||||
{ STB0899_OFF0_FLL_FREQ_WD , STB0899_BASE_FLL_FREQ_WD , 0x40070000 }, /* FLLFREQWD */
|
||||
{ STB0899_OFF0_ANTI_ALIAS_SEL , STB0899_BASE_ANTI_ALIAS_SEL , 0x00000001 }, /* ANTIALIASSEL */
|
||||
{ STB0899_OFF0_RRC_ALPHA , STB0899_BASE_RRC_ALPHA , 0x00000002 }, /* RRCALPHA */
|
||||
{ STB0899_OFF0_DC_ADAPT_LSHFT , STB0899_BASE_DC_ADAPT_LSHFT , 0x00000000 }, /* DCADAPTISHFT */
|
||||
{ STB0899_OFF0_IMB_OFFSET , STB0899_BASE_IMB_OFFSET , 0x0000fe01 }, /* IMBOFFSET */
|
||||
{ STB0899_OFF0_IMB_ESTIMATE , STB0899_BASE_IMB_ESTIMATE , 0x00000000 }, /* IMBESTIMATE */
|
||||
{ STB0899_OFF0_IMB_CNTRL , STB0899_BASE_IMB_CNTRL , 0x00000001 }, /* IMBCNTRL */
|
||||
{ STB0899_OFF0_IF_AGC_CNTRL2 , STB0899_BASE_IF_AGC_CNTRL2 , 0x00005007 }, /* IFAGCCNTRL2 */
|
||||
{ STB0899_OFF0_DMD_CNTRL2 , STB0899_BASE_DMD_CNTRL2 , 0x00000002 }, /* DMDCNTRL2 */
|
||||
{ STB0899_OFF0_TP_BUFFER , STB0899_BASE_TP_BUFFER , 0x00000000 }, /* TPBUFFER */
|
||||
{ STB0899_OFF0_TP_BUFFER1 , STB0899_BASE_TP_BUFFER1 , 0x00000000 }, /* TPBUFFER1 */
|
||||
{ STB0899_OFF0_TP_BUFFER2 , STB0899_BASE_TP_BUFFER2 , 0x00000000 }, /* TPBUFFER2 */
|
||||
{ STB0899_OFF0_TP_BUFFER3 , STB0899_BASE_TP_BUFFER3 , 0x00000000 }, /* TPBUFFER3 */
|
||||
{ STB0899_OFF0_TP_BUFFER4 , STB0899_BASE_TP_BUFFER4 , 0x00000000 }, /* TPBUFFER4 */
|
||||
{ STB0899_OFF0_TP_BUFFER5 , STB0899_BASE_TP_BUFFER5 , 0x00000000 }, /* TPBUFFER5 */
|
||||
{ STB0899_OFF0_TP_BUFFER6 , STB0899_BASE_TP_BUFFER6 , 0x00000000 }, /* TPBUFFER6 */
|
||||
{ STB0899_OFF0_TP_BUFFER7 , STB0899_BASE_TP_BUFFER7 , 0x00000000 }, /* TPBUFFER7 */
|
||||
{ STB0899_OFF0_TP_BUFFER8 , STB0899_BASE_TP_BUFFER8 , 0x00000000 }, /* TPBUFFER8 */
|
||||
{ STB0899_OFF0_TP_BUFFER9 , STB0899_BASE_TP_BUFFER9 , 0x00000000 }, /* TPBUFFER9 */
|
||||
{ STB0899_OFF0_TP_BUFFER10 , STB0899_BASE_TP_BUFFER10 , 0x00000000 }, /* TPBUFFER10 */
|
||||
{ STB0899_OFF0_TP_BUFFER11 , STB0899_BASE_TP_BUFFER11 , 0x00000000 }, /* TPBUFFER11 */
|
||||
{ STB0899_OFF0_TP_BUFFER12 , STB0899_BASE_TP_BUFFER12 , 0x00000000 }, /* TPBUFFER12 */
|
||||
{ STB0899_OFF0_TP_BUFFER13 , STB0899_BASE_TP_BUFFER13 , 0x00000000 }, /* TPBUFFER13 */
|
||||
{ STB0899_OFF0_TP_BUFFER14 , STB0899_BASE_TP_BUFFER14 , 0x00000000 }, /* TPBUFFER14 */
|
||||
{ STB0899_OFF0_TP_BUFFER15 , STB0899_BASE_TP_BUFFER15 , 0x00000000 }, /* TPBUFFER15 */
|
||||
{ STB0899_OFF0_TP_BUFFER16 , STB0899_BASE_TP_BUFFER16 , 0x0000ff00 }, /* TPBUFFER16 */
|
||||
{ STB0899_OFF0_TP_BUFFER17 , STB0899_BASE_TP_BUFFER17 , 0x00000100 }, /* TPBUFFER17 */
|
||||
{ STB0899_OFF0_TP_BUFFER18 , STB0899_BASE_TP_BUFFER18 , 0x0000fe01 }, /* TPBUFFER18 */
|
||||
{ STB0899_OFF0_TP_BUFFER19 , STB0899_BASE_TP_BUFFER19 , 0x000004fe }, /* TPBUFFER19 */
|
||||
{ STB0899_OFF0_TP_BUFFER20 , STB0899_BASE_TP_BUFFER20 , 0x0000cfe7 }, /* TPBUFFER20 */
|
||||
{ STB0899_OFF0_TP_BUFFER21 , STB0899_BASE_TP_BUFFER21 , 0x0000bec6 }, /* TPBUFFER21 */
|
||||
{ STB0899_OFF0_TP_BUFFER22 , STB0899_BASE_TP_BUFFER22 , 0x0000c2bf }, /* TPBUFFER22 */
|
||||
{ STB0899_OFF0_TP_BUFFER23 , STB0899_BASE_TP_BUFFER23 , 0x0000c1c1 }, /* TPBUFFER23 */
|
||||
{ STB0899_OFF0_TP_BUFFER24 , STB0899_BASE_TP_BUFFER24 , 0x0000c1c1 }, /* TPBUFFER24 */
|
||||
{ STB0899_OFF0_TP_BUFFER25 , STB0899_BASE_TP_BUFFER25 , 0x0000c1c1 }, /* TPBUFFER25 */
|
||||
{ STB0899_OFF0_TP_BUFFER26 , STB0899_BASE_TP_BUFFER26 , 0x0000c1c1 }, /* TPBUFFER26 */
|
||||
{ STB0899_OFF0_TP_BUFFER27 , STB0899_BASE_TP_BUFFER27 , 0x0000c1c0 }, /* TPBUFFER27 */
|
||||
{ STB0899_OFF0_TP_BUFFER28 , STB0899_BASE_TP_BUFFER28 , 0x0000c0c0 }, /* TPBUFFER28 */
|
||||
{ STB0899_OFF0_TP_BUFFER29 , STB0899_BASE_TP_BUFFER29 , 0x0000c1c1 }, /* TPBUFFER29 */
|
||||
{ STB0899_OFF0_TP_BUFFER30 , STB0899_BASE_TP_BUFFER30 , 0x0000c1c1 }, /* TPBUFFER30 */
|
||||
{ STB0899_OFF0_TP_BUFFER31 , STB0899_BASE_TP_BUFFER31 , 0x0000c0c1 }, /* TPBUFFER31 */
|
||||
{ STB0899_OFF0_TP_BUFFER32 , STB0899_BASE_TP_BUFFER32 , 0x0000c0c1 }, /* TPBUFFER32 */
|
||||
{ STB0899_OFF0_TP_BUFFER33 , STB0899_BASE_TP_BUFFER33 , 0x0000c1c1 }, /* TPBUFFER33 */
|
||||
{ STB0899_OFF0_TP_BUFFER34 , STB0899_BASE_TP_BUFFER34 , 0x0000c1c1 }, /* TPBUFFER34 */
|
||||
{ STB0899_OFF0_TP_BUFFER35 , STB0899_BASE_TP_BUFFER35 , 0x0000c0c1 }, /* TPBUFFER35 */
|
||||
{ STB0899_OFF0_TP_BUFFER36 , STB0899_BASE_TP_BUFFER36 , 0x0000c1c1 }, /* TPBUFFER36 */
|
||||
{ STB0899_OFF0_TP_BUFFER37 , STB0899_BASE_TP_BUFFER37 , 0x0000c0c1 }, /* TPBUFFER37 */
|
||||
{ STB0899_OFF0_TP_BUFFER38 , STB0899_BASE_TP_BUFFER38 , 0x0000c1c1 }, /* TPBUFFER38 */
|
||||
{ STB0899_OFF0_TP_BUFFER39 , STB0899_BASE_TP_BUFFER39 , 0x0000c0c0 }, /* TPBUFFER39 */
|
||||
{ STB0899_OFF0_TP_BUFFER40 , STB0899_BASE_TP_BUFFER40 , 0x0000c1c0 }, /* TPBUFFER40 */
|
||||
{ STB0899_OFF0_TP_BUFFER41 , STB0899_BASE_TP_BUFFER41 , 0x0000c1c1 }, /* TPBUFFER41 */
|
||||
{ STB0899_OFF0_TP_BUFFER42 , STB0899_BASE_TP_BUFFER42 , 0x0000c0c0 }, /* TPBUFFER42 */
|
||||
{ STB0899_OFF0_TP_BUFFER43 , STB0899_BASE_TP_BUFFER43 , 0x0000c1c0 }, /* TPBUFFER43 */
|
||||
{ STB0899_OFF0_TP_BUFFER44 , STB0899_BASE_TP_BUFFER44 , 0x0000c0c1 }, /* TPBUFFER44 */
|
||||
{ STB0899_OFF0_TP_BUFFER45 , STB0899_BASE_TP_BUFFER45 , 0x0000c1be }, /* TPBUFFER45 */
|
||||
{ STB0899_OFF0_TP_BUFFER46 , STB0899_BASE_TP_BUFFER46 , 0x0000c1c9 }, /* TPBUFFER46 */
|
||||
{ STB0899_OFF0_TP_BUFFER47 , STB0899_BASE_TP_BUFFER47 , 0x0000c0da }, /* TPBUFFER47 */
|
||||
{ STB0899_OFF0_TP_BUFFER48 , STB0899_BASE_TP_BUFFER48 , 0x0000c0ba }, /* TPBUFFER48 */
|
||||
{ STB0899_OFF0_TP_BUFFER49 , STB0899_BASE_TP_BUFFER49 , 0x0000c1c4 }, /* TPBUFFER49 */
|
||||
{ STB0899_OFF0_TP_BUFFER50 , STB0899_BASE_TP_BUFFER50 , 0x0000c1bf }, /* TPBUFFER50 */
|
||||
{ STB0899_OFF0_TP_BUFFER51 , STB0899_BASE_TP_BUFFER51 , 0x0000c0c1 }, /* TPBUFFER51 */
|
||||
{ STB0899_OFF0_TP_BUFFER52 , STB0899_BASE_TP_BUFFER52 , 0x0000c1c0 }, /* TPBUFFER52 */
|
||||
{ STB0899_OFF0_TP_BUFFER53 , STB0899_BASE_TP_BUFFER53 , 0x0000c0c1 }, /* TPBUFFER53 */
|
||||
{ STB0899_OFF0_TP_BUFFER54 , STB0899_BASE_TP_BUFFER54 , 0x0000c1c1 }, /* TPBUFFER54 */
|
||||
{ STB0899_OFF0_TP_BUFFER55 , STB0899_BASE_TP_BUFFER55 , 0x0000c1c1 }, /* TPBUFFER55 */
|
||||
{ STB0899_OFF0_TP_BUFFER56 , STB0899_BASE_TP_BUFFER56 , 0x0000c1c1 }, /* TPBUFFER56 */
|
||||
{ STB0899_OFF0_TP_BUFFER57 , STB0899_BASE_TP_BUFFER57 , 0x0000c1c1 }, /* TPBUFFER57 */
|
||||
{ STB0899_OFF0_TP_BUFFER58 , STB0899_BASE_TP_BUFFER58 , 0x0000c1c1 }, /* TPBUFFER58 */
|
||||
{ STB0899_OFF0_TP_BUFFER59 , STB0899_BASE_TP_BUFFER59 , 0x0000c1c1 }, /* TPBUFFER59 */
|
||||
{ STB0899_OFF0_TP_BUFFER60 , STB0899_BASE_TP_BUFFER60 , 0x0000c1c1 }, /* TPBUFFER60 */
|
||||
{ STB0899_OFF0_TP_BUFFER61 , STB0899_BASE_TP_BUFFER61 , 0x0000c1c1 }, /* TPBUFFER61 */
|
||||
{ STB0899_OFF0_TP_BUFFER62 , STB0899_BASE_TP_BUFFER62 , 0x0000c1c1 }, /* TPBUFFER62 */
|
||||
{ STB0899_OFF0_TP_BUFFER63 , STB0899_BASE_TP_BUFFER63 , 0x0000c1c0 }, /* TPBUFFER63 */
|
||||
{ STB0899_OFF0_RESET_CNTRL , STB0899_BASE_RESET_CNTRL , 0x00000001 }, /* RESETCNTRL */
|
||||
{ STB0899_OFF0_ACM_ENABLE , STB0899_BASE_ACM_ENABLE , 0x00005654 }, /* ACMENABLE */
|
||||
{ STB0899_OFF0_DESCR_CNTRL , STB0899_BASE_DESCR_CNTRL , 0x00000000 }, /* DESCRCNTRL */
|
||||
{ STB0899_OFF0_CSM_CNTRL1 , STB0899_BASE_CSM_CNTRL1 , 0x00020019 }, /* CSMCNTRL1 */
|
||||
{ STB0899_OFF0_CSM_CNTRL2 , STB0899_BASE_CSM_CNTRL2 , 0x004b3237 }, /* CSMCNTRL2 */
|
||||
{ STB0899_OFF0_CSM_CNTRL3 , STB0899_BASE_CSM_CNTRL3 , 0x0003dd17 }, /* CSMCNTRL3 */
|
||||
{ STB0899_OFF0_CSM_CNTRL4 , STB0899_BASE_CSM_CNTRL4 , 0x00008008 }, /* CSMCNTRL4 */
|
||||
{ STB0899_OFF0_UWP_CNTRL1 , STB0899_BASE_UWP_CNTRL1 , 0x002a3106 }, /* UWPCNTRL1 */
|
||||
{ STB0899_OFF0_UWP_CNTRL2 , STB0899_BASE_UWP_CNTRL2 , 0x0006140a }, /* UWPCNTRL2 */
|
||||
{ STB0899_OFF0_UWP_STAT1 , STB0899_BASE_UWP_STAT1 , 0x00008000 }, /* UWPSTAT1 */
|
||||
{ STB0899_OFF0_UWP_STAT2 , STB0899_BASE_UWP_STAT2 , 0x00000000 }, /* UWPSTAT2 */
|
||||
{ STB0899_OFF0_DMD_STAT2 , STB0899_BASE_DMD_STAT2 , 0x00000000 }, /* DMDSTAT2 */
|
||||
{ STB0899_OFF0_FREQ_ADJ_SCALE , STB0899_BASE_FREQ_ADJ_SCALE , 0x00000471 }, /* FREQADJSCALE */
|
||||
{ STB0899_OFF0_UWP_CNTRL3 , STB0899_BASE_UWP_CNTRL3 , 0x017b0465 }, /* UWPCNTRL3 */
|
||||
{ STB0899_OFF0_SYM_CLK_SEL , STB0899_BASE_SYM_CLK_SEL , 0x00000002 }, /* SYMCLKSEL */
|
||||
{ STB0899_OFF0_SOF_SRCH_TO , STB0899_BASE_SOF_SRCH_TO , 0x00196464 }, /* SOFSRCHTO */
|
||||
{ STB0899_OFF0_ACQ_CNTRL1 , STB0899_BASE_ACQ_CNTRL1 , 0x00000603 }, /* ACQCNTRL1 */
|
||||
{ STB0899_OFF0_ACQ_CNTRL2 , STB0899_BASE_ACQ_CNTRL2 , 0x02046666 }, /* ACQCNTRL2 */
|
||||
{ STB0899_OFF0_ACQ_CNTRL3 , STB0899_BASE_ACQ_CNTRL3 , 0x10046583 }, /* ACQCNTRL3 */
|
||||
{ STB0899_OFF0_FE_SETTLE , STB0899_BASE_FE_SETTLE , 0x00010404 }, /* FESETTLE */
|
||||
{ STB0899_OFF0_AC_DWELL , STB0899_BASE_AC_DWELL , 0x0002aa8a }, /* ACDWELL */
|
||||
{ STB0899_OFF0_ACQUIRE_TRIG , STB0899_BASE_ACQUIRE_TRIG , 0x00000000 }, /* ACQUIRETRIG */
|
||||
{ STB0899_OFF0_LOCK_LOST , STB0899_BASE_LOCK_LOST , 0x00000001 }, /* LOCKLOST */
|
||||
{ STB0899_OFF0_ACQ_STAT1 , STB0899_BASE_ACQ_STAT1 , 0x00000500 }, /* ACQSTAT1 */
|
||||
{ STB0899_OFF0_ACQ_TIMEOUT , STB0899_BASE_ACQ_TIMEOUT , 0x0028a0a0 }, /* ACQTIMEOUT */
|
||||
{ STB0899_OFF0_ACQ_TIME , STB0899_BASE_ACQ_TIME , 0x00000000 }, /* ACQTIME */
|
||||
{ STB0899_OFF0_FINAL_AGC_CNTRL , STB0899_BASE_FINAL_AGC_CNTRL , 0x00800c17 }, /* FINALAGCCNTRL*/
|
||||
{ STB0899_OFF0_FINAL_AGC_GAIN , STB0899_BASE_FINAL_AGC_GAIN , 0x00000000 }, /* FINALAGCCGAIN*/
|
||||
{ STB0899_OFF0_EQUALIZER_INIT , STB0899_BASE_EQUALIZER_INIT , 0x00000000 }, /* EQUILIZERINIT*/
|
||||
{ STB0899_OFF0_EQ_CNTRL , STB0899_BASE_EQ_CNTRL , 0x00054802 }, /* EQCNTL */
|
||||
{ STB0899_OFF0_EQ_I_INIT_COEFF_0, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF0 */
|
||||
{ STB0899_OFF1_EQ_I_INIT_COEFF_1, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF1 */
|
||||
{ STB0899_OFF2_EQ_I_INIT_COEFF_2, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF2 */
|
||||
{ STB0899_OFF3_EQ_I_INIT_COEFF_3, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF3 */
|
||||
{ STB0899_OFF4_EQ_I_INIT_COEFF_4, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF4 */
|
||||
{ STB0899_OFF5_EQ_I_INIT_COEFF_5, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000400 }, /* EQIINITCOEFF5 */
|
||||
{ STB0899_OFF6_EQ_I_INIT_COEFF_6, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF6 */
|
||||
{ STB0899_OFF7_EQ_I_INIT_COEFF_7, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF7 */
|
||||
{ STB0899_OFF8_EQ_I_INIT_COEFF_8, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF8 */
|
||||
{ STB0899_OFF9_EQ_I_INIT_COEFF_9, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF9 */
|
||||
{ STB0899_OFFa_EQ_I_INIT_COEFF_10,STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF10*/
|
||||
{ STB0899_OFF0_EQ_Q_INIT_COEFF_0, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF0 */
|
||||
{ STB0899_OFF1_EQ_Q_INIT_COEFF_1, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF1 */
|
||||
{ STB0899_OFF2_EQ_Q_INIT_COEFF_2, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF2 */
|
||||
{ STB0899_OFF3_EQ_Q_INIT_COEFF_3, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF3 */
|
||||
{ STB0899_OFF4_EQ_Q_INIT_COEFF_4, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF4 */
|
||||
{ STB0899_OFF5_EQ_Q_INIT_COEFF_5, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF5 */
|
||||
{ STB0899_OFF6_EQ_Q_INIT_COEFF_6, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF6 */
|
||||
{ STB0899_OFF7_EQ_Q_INIT_COEFF_7, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF7 */
|
||||
{ STB0899_OFF8_EQ_Q_INIT_COEFF_8, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF8 */
|
||||
{ STB0899_OFF9_EQ_Q_INIT_COEFF_9, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF9 */
|
||||
{ STB0899_OFFa_EQ_Q_INIT_COEFF_10,STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF10*/
|
||||
{ STB0899_OFF0_EQ_I_OUT_COEFF_0 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT0 */
|
||||
{ STB0899_OFF1_EQ_I_OUT_COEFF_1 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT1 */
|
||||
{ STB0899_OFF2_EQ_I_OUT_COEFF_2 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT2 */
|
||||
{ STB0899_OFF3_EQ_I_OUT_COEFF_3 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT3 */
|
||||
{ STB0899_OFF4_EQ_I_OUT_COEFF_4 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT4 */
|
||||
{ STB0899_OFF5_EQ_I_OUT_COEFF_5 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT5 */
|
||||
{ STB0899_OFF6_EQ_I_OUT_COEFF_6 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT6 */
|
||||
{ STB0899_OFF7_EQ_I_OUT_COEFF_7 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT7 */
|
||||
{ STB0899_OFF8_EQ_I_OUT_COEFF_8 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT8 */
|
||||
{ STB0899_OFF9_EQ_I_OUT_COEFF_9 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT9 */
|
||||
{ STB0899_OFFa_EQ_I_OUT_COEFF_10,STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT10*/
|
||||
{ STB0899_OFF0_EQ_Q_OUT_COEFF_0 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT0 */
|
||||
{ STB0899_OFF1_EQ_Q_OUT_COEFF_1 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT1 */
|
||||
{ STB0899_OFF2_EQ_Q_OUT_COEFF_2 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT2 */
|
||||
{ STB0899_OFF3_EQ_Q_OUT_COEFF_3 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT3 */
|
||||
{ STB0899_OFF4_EQ_Q_OUT_COEFF_4 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT4 */
|
||||
{ STB0899_OFF5_EQ_Q_OUT_COEFF_5 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT5 */
|
||||
{ STB0899_OFF6_EQ_Q_OUT_COEFF_6 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT6 */
|
||||
{ STB0899_OFF7_EQ_Q_OUT_COEFF_7 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT7 */
|
||||
{ STB0899_OFF8_EQ_Q_OUT_COEFF_8 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT8 */
|
||||
{ STB0899_OFF9_EQ_Q_OUT_COEFF_9 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT9 */
|
||||
{ STB0899_OFFa_EQ_Q_OUT_COEFF_10, STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT10*/
|
||||
{ 0xffff , 0xffffffff , 0xffffffff },
|
||||
};
|
||||
static const struct stb0899_s2_reg stb0899_s2_init_4[] = {
|
||||
{ STB0899_OFF0_BLOCK_LNGTH , STB0899_BASE_BLOCK_LNGTH , 0x00000008 }, /* BLOCKLNGTH */
|
||||
{ STB0899_OFF0_ROW_STR , STB0899_BASE_ROW_STR , 0x000000b4 }, /* ROWSTR */
|
||||
{ STB0899_OFF0_BN_END_ADDR , STB0899_BASE_BN_END_ADDR , 0x000004b5 }, /* BNANDADDR */
|
||||
{ STB0899_OFF0_CN_END_ADDR , STB0899_BASE_CN_END_ADDR , 0x00000b4b }, /* CNANDADDR */
|
||||
{ STB0899_OFF0_INFO_LENGTH , STB0899_BASE_INFO_LENGTH , 0x00000078 }, /* INFOLENGTH */
|
||||
{ STB0899_OFF0_BOT_ADDR , STB0899_BASE_BOT_ADDR , 0x000001e0 }, /* BOT_ADDR */
|
||||
{ STB0899_OFF0_BCH_BLK_LN , STB0899_BASE_BCH_BLK_LN , 0x0000a8c0 }, /* BCHBLKLN */
|
||||
{ STB0899_OFF0_BCH_T , STB0899_BASE_BCH_T , 0x0000000c }, /* BCHT */
|
||||
{ STB0899_OFF0_CNFG_MODE , STB0899_BASE_CNFG_MODE , 0x00000001 }, /* CNFGMODE */
|
||||
{ STB0899_OFF0_LDPC_STAT , STB0899_BASE_LDPC_STAT , 0x0000000d }, /* LDPCSTAT */
|
||||
{ STB0899_OFF0_ITER_SCALE , STB0899_BASE_ITER_SCALE , 0x00000040 }, /* ITERSCALE */
|
||||
{ STB0899_OFF0_INPUT_MODE , STB0899_BASE_INPUT_MODE , 0x00000000 }, /* INPUTMODE */
|
||||
{ STB0899_OFF0_LDPCDECRST , STB0899_BASE_LDPCDECRST , 0x00000000 }, /* LDPCDECRST */
|
||||
{ STB0899_OFF0_CLK_PER_BYTE_RW , STB0899_BASE_CLK_PER_BYTE_RW , 0x00000008 }, /* CLKPERBYTE */
|
||||
{ STB0899_OFF0_BCH_ERRORS , STB0899_BASE_BCH_ERRORS , 0x00000000 }, /* BCHERRORS */
|
||||
{ STB0899_OFF0_LDPC_ERRORS , STB0899_BASE_LDPC_ERRORS , 0x00000000 }, /* LDPCERRORS */
|
||||
{ STB0899_OFF0_BCH_MODE , STB0899_BASE_BCH_MODE , 0x00000000 }, /* BCHMODE */
|
||||
{ STB0899_OFF0_ERR_ACC_PER , STB0899_BASE_ERR_ACC_PER , 0x00000008 }, /* ERRACCPER */
|
||||
{ STB0899_OFF0_BCH_ERR_ACC , STB0899_BASE_BCH_ERR_ACC , 0x00000000 }, /* BCHERRACC */
|
||||
{ STB0899_OFF0_FEC_TP_SEL , STB0899_BASE_FEC_TP_SEL , 0x00000000 }, /* FECTPSEL */
|
||||
{ 0xffff , 0xffffffff , 0xffffffff },
|
||||
};
|
||||
|
||||
static const struct stb0899_s1_reg stb0899_s1_init_5[] = {
|
||||
{ STB0899_TSTCK , 0x00 },
|
||||
{ STB0899_TSTRES , 0x00 },
|
||||
{ STB0899_TSTOUT , 0x00 },
|
||||
{ STB0899_TSTIN , 0x00 },
|
||||
{ STB0899_TSTSYS , 0x00 },
|
||||
{ STB0899_TSTCHIP , 0x00 },
|
||||
{ STB0899_TSTFREE , 0x00 },
|
||||
{ STB0899_TSTI2C , 0x00 },
|
||||
{ STB0899_BITSPEEDM , 0x00 },
|
||||
{ STB0899_BITSPEEDL , 0x00 },
|
||||
{ STB0899_TBUSBIT , 0x00 },
|
||||
{ STB0899_TSTDIS , 0x00 },
|
||||
{ STB0899_TSTDISRX , 0x00 },
|
||||
{ STB0899_TSTJETON , 0x00 },
|
||||
{ STB0899_TSTDCADJ , 0x00 },
|
||||
{ STB0899_TSTAGC1 , 0x00 },
|
||||
{ STB0899_TSTAGC1N , 0x00 },
|
||||
{ STB0899_TSTPOLYPH , 0x00 },
|
||||
{ STB0899_TSTR , 0x00 },
|
||||
{ STB0899_TSTAGC2 , 0x00 },
|
||||
{ STB0899_TSTCTL1 , 0x00 },
|
||||
{ STB0899_TSTCTL2 , 0x00 },
|
||||
{ STB0899_TSTCTL3 , 0x00 },
|
||||
{ STB0899_TSTDEMAP , 0x00 },
|
||||
{ STB0899_TSTDEMAP2 , 0x00 },
|
||||
{ STB0899_TSTDEMMON , 0x00 },
|
||||
{ STB0899_TSTRATE , 0x00 },
|
||||
{ STB0899_TSTSELOUT , 0x00 },
|
||||
{ STB0899_TSYNC , 0x00 },
|
||||
{ STB0899_TSTERR , 0x00 },
|
||||
{ STB0899_TSTRAM1 , 0x00 },
|
||||
{ STB0899_TSTVSELOUT , 0x00 },
|
||||
{ STB0899_TSTFORCEIN , 0x00 },
|
||||
{ STB0899_TSTRS1 , 0x00 },
|
||||
{ STB0899_TSTRS2 , 0x00 },
|
||||
{ STB0899_TSTRS3 , 0x00 },
|
||||
{ STB0899_GHOSTREG , 0x81 },
|
||||
{ 0xffff , 0xff },
|
||||
};
|
||||
|
||||
#define STB0899_DVBS2_ESNO_AVE 3
|
||||
#define STB0899_DVBS2_ESNO_QUANT 32
|
||||
#define STB0899_DVBS2_AVFRAMES_COARSE 10
|
||||
#define STB0899_DVBS2_AVFRAMES_FINE 20
|
||||
#define STB0899_DVBS2_MISS_THRESHOLD 6
|
||||
#define STB0899_DVBS2_UWP_THRESHOLD_ACQ 1125
|
||||
#define STB0899_DVBS2_UWP_THRESHOLD_TRACK 758
|
||||
#define STB0899_DVBS2_UWP_THRESHOLD_SOF 1350
|
||||
#define STB0899_DVBS2_SOF_SEARCH_TIMEOUT 1664100
|
||||
|
||||
#define STB0899_DVBS2_BTR_NCO_BITS 28
|
||||
#define STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET 15
|
||||
#define STB0899_DVBS2_CRL_NCO_BITS 30
|
||||
#define STB0899_DVBS2_LDPC_MAX_ITER 70
|
||||
|
||||
#endif //__STB0899_CFG_H
|
||||
1684
drivers/media/dvb/frontends/stb0899_drv.c
Normal file
1684
drivers/media/dvb/frontends/stb0899_drv.c
Normal file
File diff suppressed because it is too large
Load diff
162
drivers/media/dvb/frontends/stb0899_drv.h
Normal file
162
drivers/media/dvb/frontends/stb0899_drv.h
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
STB0899 Multistandard Frontend driver
|
||||
Copyright (C) Manu Abraham (abraham.manu@gmail.com)
|
||||
|
||||
Copyright (C) ST Microelectronics
|
||||
|
||||
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 __STB0899_DRV_H
|
||||
#define __STB0899_DRV_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
|
||||
#define STB0899_TSMODE_SERIAL 1
|
||||
#define STB0899_CLKPOL_FALLING 2
|
||||
#define STB0899_CLKNULL_PARITY 3
|
||||
#define STB0899_SYNC_FORCED 4
|
||||
#define STB0899_FECMODE_DSS 5
|
||||
|
||||
struct stb0899_s1_reg {
|
||||
u16 address;
|
||||
u8 data;
|
||||
};
|
||||
|
||||
struct stb0899_s2_reg {
|
||||
u16 offset;
|
||||
u32 base_address;
|
||||
u32 data;
|
||||
};
|
||||
|
||||
enum stb0899_inversion {
|
||||
IQ_SWAP_OFF = 0,
|
||||
IQ_SWAP_ON,
|
||||
IQ_SWAP_AUTO
|
||||
};
|
||||
|
||||
#define STB0899_GPIO00 0xf140
|
||||
#define STB0899_GPIO01 0xf141
|
||||
#define STB0899_GPIO02 0xf142
|
||||
#define STB0899_GPIO03 0xf143
|
||||
#define STB0899_GPIO04 0xf144
|
||||
#define STB0899_GPIO05 0xf145
|
||||
#define STB0899_GPIO06 0xf146
|
||||
#define STB0899_GPIO07 0xf147
|
||||
#define STB0899_GPIO08 0xf148
|
||||
#define STB0899_GPIO09 0xf149
|
||||
#define STB0899_GPIO10 0xf14a
|
||||
#define STB0899_GPIO11 0xf14b
|
||||
#define STB0899_GPIO12 0xf14c
|
||||
#define STB0899_GPIO13 0xf14d
|
||||
#define STB0899_GPIO14 0xf14e
|
||||
#define STB0899_GPIO15 0xf14f
|
||||
#define STB0899_GPIO16 0xf150
|
||||
#define STB0899_GPIO17 0xf151
|
||||
#define STB0899_GPIO18 0xf152
|
||||
#define STB0899_GPIO19 0xf153
|
||||
#define STB0899_GPIO20 0xf154
|
||||
|
||||
#define STB0899_GPIOPULLUP 0x01 /* Output device is connected to Vdd */
|
||||
#define STB0899_GPIOPULLDN 0x00 /* Output device is connected to Vss */
|
||||
|
||||
#define STB0899_POSTPROC_GPIO_POWER 0x00
|
||||
#define STB0899_POSTPROC_GPIO_LOCK 0x01
|
||||
|
||||
/*
|
||||
* Post process output configuration control
|
||||
* 1. POWER ON/OFF (index 0)
|
||||
* 2. FE_HAS_LOCK/LOCK_LOSS (index 1)
|
||||
*
|
||||
* @gpio = one of the above listed GPIO's
|
||||
* @level = output state: pulled up or low
|
||||
*/
|
||||
struct stb0899_postproc {
|
||||
u16 gpio;
|
||||
u8 level;
|
||||
};
|
||||
|
||||
struct stb0899_config {
|
||||
const struct stb0899_s1_reg *init_dev;
|
||||
const struct stb0899_s2_reg *init_s2_demod;
|
||||
const struct stb0899_s1_reg *init_s1_demod;
|
||||
const struct stb0899_s2_reg *init_s2_fec;
|
||||
const struct stb0899_s1_reg *init_tst;
|
||||
|
||||
const struct stb0899_postproc *postproc;
|
||||
|
||||
enum stb0899_inversion inversion;
|
||||
|
||||
u32 xtal_freq;
|
||||
|
||||
u8 demod_address;
|
||||
u8 ts_output_mode;
|
||||
u8 block_sync_mode;
|
||||
u8 ts_pfbit_toggle;
|
||||
|
||||
u8 clock_polarity;
|
||||
u8 data_clk_parity;
|
||||
u8 fec_mode;
|
||||
u8 data_output_ctl;
|
||||
u8 data_fifo_mode;
|
||||
u8 out_rate_comp;
|
||||
u8 i2c_repeater;
|
||||
// int inversion;
|
||||
int lo_clk;
|
||||
int hi_clk;
|
||||
|
||||
u32 esno_ave;
|
||||
u32 esno_quant;
|
||||
u32 avframes_coarse;
|
||||
u32 avframes_fine;
|
||||
u32 miss_threshold;
|
||||
u32 uwp_threshold_acq;
|
||||
u32 uwp_threshold_track;
|
||||
u32 uwp_threshold_sof;
|
||||
u32 sof_search_timeout;
|
||||
|
||||
u32 btr_nco_bits;
|
||||
u32 btr_gain_shift_offset;
|
||||
u32 crl_nco_bits;
|
||||
u32 ldpc_max_iter;
|
||||
|
||||
int (*tuner_set_frequency)(struct dvb_frontend *fe, u32 frequency);
|
||||
int (*tuner_get_frequency)(struct dvb_frontend *fe, u32 *frequency);
|
||||
int (*tuner_set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
|
||||
int (*tuner_get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
|
||||
int (*tuner_set_rfsiggain)(struct dvb_frontend *fe, u32 rf_gain);
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_STB0899) || (defined(CONFIG_DVB_STB0899_MODULE) && defined(MODULE))
|
||||
|
||||
extern struct dvb_frontend *stb0899_attach(struct stb0899_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
|
||||
#else
|
||||
|
||||
static inline struct dvb_frontend *stb0899_attach(struct stb0899_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif //CONFIG_DVB_STB0899
|
||||
|
||||
|
||||
#endif
|
||||
267
drivers/media/dvb/frontends/stb0899_priv.h
Normal file
267
drivers/media/dvb/frontends/stb0899_priv.h
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
/*
|
||||
STB0899 Multistandard Frontend driver
|
||||
Copyright (C) Manu Abraham (abraham.manu@gmail.com)
|
||||
|
||||
Copyright (C) ST Microelectronics
|
||||
|
||||
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 __STB0899_PRIV_H
|
||||
#define __STB0899_PRIV_H
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "stb0899_drv.h"
|
||||
|
||||
#define FE_ERROR 0
|
||||
#define FE_NOTICE 1
|
||||
#define FE_INFO 2
|
||||
#define FE_DEBUG 3
|
||||
#define FE_DEBUGREG 4
|
||||
|
||||
#define dprintk(x, y, z, format, arg...) do { \
|
||||
if (z) { \
|
||||
if ((*x > FE_ERROR) && (*x > y)) \
|
||||
printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \
|
||||
else if ((*x > FE_NOTICE) && (*x > y)) \
|
||||
printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \
|
||||
else if ((*x > FE_INFO) && (*x > y)) \
|
||||
printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \
|
||||
else if ((*x > FE_DEBUG) && (*x > y)) \
|
||||
printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \
|
||||
} else { \
|
||||
if (*x > y) \
|
||||
printk(format, ##arg); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define INRANGE(val, x, y) (((x <= val) && (val <= y)) || \
|
||||
((y <= val) && (val <= x)) ? 1 : 0)
|
||||
|
||||
#define BYTE0 0
|
||||
#define BYTE1 8
|
||||
#define BYTE2 16
|
||||
#define BYTE3 24
|
||||
|
||||
#define GETBYTE(x, y) (((x) >> (y)) & 0xff)
|
||||
#define MAKEWORD32(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
|
||||
#define MAKEWORD16(a, b) (((a) << 8) | (b))
|
||||
|
||||
#define MIN(x, y) ((x) <= (y) ? (x) : (y))
|
||||
#define MAX(x, y) ((x) >= (y) ? (x) : (y))
|
||||
#define ABS(x) ((x) >= 0 ? (x) : -(x))
|
||||
|
||||
#define LSB(x) ((x & 0xff))
|
||||
#define MSB(y) ((y >> 8) & 0xff)
|
||||
|
||||
|
||||
#define STB0899_GETFIELD(bitf, val) ((val >> STB0899_OFFST_##bitf) & ((1 << STB0899_WIDTH_##bitf) - 1))
|
||||
|
||||
|
||||
#define STB0899_SETFIELD(mask, val, width, offset) (mask & (~(((1 << width) - 1) << \
|
||||
offset))) | ((val & \
|
||||
((1 << width) - 1)) << offset)
|
||||
|
||||
#define STB0899_SETFIELD_VAL(bitf, mask, val) (mask = (mask & (~(((1 << STB0899_WIDTH_##bitf) - 1) <<\
|
||||
STB0899_OFFST_##bitf))) | \
|
||||
(val << STB0899_OFFST_##bitf))
|
||||
|
||||
|
||||
enum stb0899_status {
|
||||
NOAGC1 = 0,
|
||||
AGC1OK,
|
||||
NOTIMING,
|
||||
ANALOGCARRIER,
|
||||
TIMINGOK,
|
||||
NOAGC2,
|
||||
AGC2OK,
|
||||
NOCARRIER,
|
||||
CARRIEROK,
|
||||
NODATA,
|
||||
FALSELOCK,
|
||||
DATAOK,
|
||||
OUTOFRANGE,
|
||||
RANGEOK,
|
||||
DVBS2_DEMOD_LOCK,
|
||||
DVBS2_DEMOD_NOLOCK,
|
||||
DVBS2_FEC_LOCK,
|
||||
DVBS2_FEC_NOLOCK
|
||||
};
|
||||
|
||||
enum stb0899_modcod {
|
||||
STB0899_DUMMY_PLF,
|
||||
STB0899_QPSK_14,
|
||||
STB0899_QPSK_13,
|
||||
STB0899_QPSK_25,
|
||||
STB0899_QPSK_12,
|
||||
STB0899_QPSK_35,
|
||||
STB0899_QPSK_23,
|
||||
STB0899_QPSK_34,
|
||||
STB0899_QPSK_45,
|
||||
STB0899_QPSK_56,
|
||||
STB0899_QPSK_89,
|
||||
STB0899_QPSK_910,
|
||||
STB0899_8PSK_35,
|
||||
STB0899_8PSK_23,
|
||||
STB0899_8PSK_34,
|
||||
STB0899_8PSK_56,
|
||||
STB0899_8PSK_89,
|
||||
STB0899_8PSK_910,
|
||||
STB0899_16APSK_23,
|
||||
STB0899_16APSK_34,
|
||||
STB0899_16APSK_45,
|
||||
STB0899_16APSK_56,
|
||||
STB0899_16APSK_89,
|
||||
STB0899_16APSK_910,
|
||||
STB0899_32APSK_34,
|
||||
STB0899_32APSK_45,
|
||||
STB0899_32APSK_56,
|
||||
STB0899_32APSK_89,
|
||||
STB0899_32APSK_910
|
||||
};
|
||||
|
||||
enum stb0899_frame {
|
||||
STB0899_LONG_FRAME,
|
||||
STB0899_SHORT_FRAME
|
||||
};
|
||||
|
||||
enum stb0899_alpha {
|
||||
RRC_20,
|
||||
RRC_25,
|
||||
RRC_35
|
||||
};
|
||||
|
||||
struct stb0899_tab {
|
||||
s32 real;
|
||||
s32 read;
|
||||
};
|
||||
|
||||
enum stb0899_fec {
|
||||
STB0899_FEC_1_2 = 13,
|
||||
STB0899_FEC_2_3 = 18,
|
||||
STB0899_FEC_3_4 = 21,
|
||||
STB0899_FEC_5_6 = 24,
|
||||
STB0899_FEC_6_7 = 25,
|
||||
STB0899_FEC_7_8 = 26
|
||||
};
|
||||
|
||||
struct stb0899_params {
|
||||
u32 freq; /* Frequency */
|
||||
u32 srate; /* Symbol rate */
|
||||
enum fe_code_rate fecrate;
|
||||
};
|
||||
|
||||
struct stb0899_internal {
|
||||
u32 master_clk;
|
||||
u32 freq; /* Demod internal Frequency */
|
||||
u32 srate; /* Demod internal Symbol rate */
|
||||
enum stb0899_fec fecrate; /* Demod internal FEC rate */
|
||||
u32 srch_range; /* Demod internal Search Range */
|
||||
u32 sub_range; /* Demod current sub range (Hz) */
|
||||
u32 tuner_step; /* Tuner step (Hz) */
|
||||
u32 tuner_offst; /* Relative offset to carrier (Hz) */
|
||||
u32 tuner_bw; /* Current bandwidth of the tuner (Hz) */
|
||||
|
||||
s32 mclk; /* Masterclock Divider factor (binary) */
|
||||
s32 rolloff; /* Current RollOff of the filter (x100) */
|
||||
|
||||
s16 derot_freq; /* Current derotator frequency (Hz) */
|
||||
s16 derot_percent;
|
||||
|
||||
s16 direction; /* Current derotator search direction */
|
||||
s16 derot_step; /* Derotator step (binary value) */
|
||||
s16 t_derot; /* Derotator time constant (ms) */
|
||||
s16 t_data; /* Data recovery time constant (ms) */
|
||||
s16 sub_dir; /* Direction of the next sub range */
|
||||
|
||||
s16 t_agc1; /* Agc1 time constant (ms) */
|
||||
s16 t_agc2; /* Agc2 time constant (ms) */
|
||||
|
||||
u32 lock; /* Demod internal lock state */
|
||||
enum stb0899_status status; /* Demod internal status */
|
||||
|
||||
/* DVB-S2 */
|
||||
s32 agc_gain; /* RF AGC Gain */
|
||||
s32 center_freq; /* Nominal carrier frequency */
|
||||
s32 av_frame_coarse; /* Coarse carrier freq search frames */
|
||||
s32 av_frame_fine; /* Fine carrier freq search frames */
|
||||
|
||||
s16 step_size; /* Carrier frequency search step size */
|
||||
|
||||
enum stb0899_alpha rrc_alpha;
|
||||
enum stb0899_inversion inversion;
|
||||
enum stb0899_modcod modcod;
|
||||
u8 pilots; /* Pilots found */
|
||||
|
||||
enum stb0899_frame frame_length;
|
||||
u8 v_status; /* VSTATUS */
|
||||
u8 err_ctrl; /* ERRCTRLn */
|
||||
};
|
||||
|
||||
struct stb0899_state {
|
||||
struct i2c_adapter *i2c;
|
||||
struct stb0899_config *config;
|
||||
struct dvb_frontend frontend;
|
||||
|
||||
u32 *verbose; /* Cached module verbosity level */
|
||||
|
||||
struct stb0899_internal internal; /* Device internal parameters */
|
||||
|
||||
/* cached params from API */
|
||||
enum fe_delivery_system delsys;
|
||||
struct stb0899_params params;
|
||||
|
||||
u32 rx_freq; /* DiSEqC 2.0 receiver freq */
|
||||
struct mutex search_lock;
|
||||
};
|
||||
/* stb0899.c */
|
||||
extern int stb0899_read_reg(struct stb0899_state *state,
|
||||
unsigned int reg);
|
||||
|
||||
extern u32 _stb0899_read_s2reg(struct stb0899_state *state,
|
||||
u32 stb0899_i2cdev,
|
||||
u32 stb0899_base_addr,
|
||||
u16 stb0899_reg_offset);
|
||||
|
||||
extern int stb0899_read_regs(struct stb0899_state *state,
|
||||
unsigned int reg, u8 *buf,
|
||||
u32 count);
|
||||
|
||||
extern int stb0899_write_regs(struct stb0899_state *state,
|
||||
unsigned int reg, u8 *data,
|
||||
u32 count);
|
||||
|
||||
extern int stb0899_write_reg(struct stb0899_state *state,
|
||||
unsigned int reg,
|
||||
u8 data);
|
||||
|
||||
extern int stb0899_write_s2reg(struct stb0899_state *state,
|
||||
u32 stb0899_i2cdev,
|
||||
u32 stb0899_base_addr,
|
||||
u16 stb0899_reg_offset,
|
||||
u32 stb0899_data);
|
||||
|
||||
extern int stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
|
||||
|
||||
|
||||
#define STB0899_READ_S2REG(DEVICE, REG) (_stb0899_read_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG))
|
||||
//#define STB0899_WRITE_S2REG(DEVICE, REG, DATA) (_stb0899_write_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG, DATA))
|
||||
|
||||
/* stb0899_algo.c */
|
||||
extern enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state);
|
||||
extern enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state);
|
||||
extern long stb0899_carr_width(struct stb0899_state *state);
|
||||
|
||||
#endif //__STB0899_PRIV_H
|
||||
2027
drivers/media/dvb/frontends/stb0899_reg.h
Normal file
2027
drivers/media/dvb/frontends/stb0899_reg.h
Normal file
File diff suppressed because it is too large
Load diff
545
drivers/media/dvb/frontends/stb6100.c
Normal file
545
drivers/media/dvb/frontends/stb6100.c
Normal file
|
|
@ -0,0 +1,545 @@
|
|||
/*
|
||||
STB6100 Silicon Tuner
|
||||
Copyright (C) Manu Abraham (abraham.manu@gmail.com)
|
||||
|
||||
Copyright (C) ST Microelectronics
|
||||
|
||||
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/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "stb6100.h"
|
||||
|
||||
static unsigned int verbose;
|
||||
module_param(verbose, int, 0644);
|
||||
|
||||
|
||||
#define FE_ERROR 0
|
||||
#define FE_NOTICE 1
|
||||
#define FE_INFO 2
|
||||
#define FE_DEBUG 3
|
||||
|
||||
#define dprintk(x, y, z, format, arg...) do { \
|
||||
if (z) { \
|
||||
if ((x > FE_ERROR) && (x > y)) \
|
||||
printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \
|
||||
else if ((x > FE_NOTICE) && (x > y)) \
|
||||
printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \
|
||||
else if ((x > FE_INFO) && (x > y)) \
|
||||
printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \
|
||||
else if ((x > FE_DEBUG) && (x > y)) \
|
||||
printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \
|
||||
} else { \
|
||||
if (x > y) \
|
||||
printk(format, ##arg); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
struct stb6100_lkup {
|
||||
u32 val_low;
|
||||
u32 val_high;
|
||||
u8 reg;
|
||||
};
|
||||
|
||||
static int stb6100_release(struct dvb_frontend *fe);
|
||||
|
||||
static const struct stb6100_lkup lkup[] = {
|
||||
{ 0, 950000, 0x0a },
|
||||
{ 950000, 1000000, 0x0a },
|
||||
{ 1000000, 1075000, 0x0c },
|
||||
{ 1075000, 1200000, 0x00 },
|
||||
{ 1200000, 1300000, 0x01 },
|
||||
{ 1300000, 1370000, 0x02 },
|
||||
{ 1370000, 1470000, 0x04 },
|
||||
{ 1470000, 1530000, 0x05 },
|
||||
{ 1530000, 1650000, 0x06 },
|
||||
{ 1650000, 1800000, 0x08 },
|
||||
{ 1800000, 1950000, 0x0a },
|
||||
{ 1950000, 2150000, 0x0c },
|
||||
{ 2150000, 9999999, 0x0c },
|
||||
{ 0, 0, 0x00 }
|
||||
};
|
||||
|
||||
/* Register names for easy debugging. */
|
||||
static const char *stb6100_regnames[] = {
|
||||
[STB6100_LD] = "LD",
|
||||
[STB6100_VCO] = "VCO",
|
||||
[STB6100_NI] = "NI",
|
||||
[STB6100_NF_LSB] = "NF",
|
||||
[STB6100_K] = "K",
|
||||
[STB6100_G] = "G",
|
||||
[STB6100_F] = "F",
|
||||
[STB6100_DLB] = "DLB",
|
||||
[STB6100_TEST1] = "TEST1",
|
||||
[STB6100_FCCK] = "FCCK",
|
||||
[STB6100_LPEN] = "LPEN",
|
||||
[STB6100_TEST3] = "TEST3",
|
||||
};
|
||||
|
||||
/* Template for normalisation, i.e. setting unused or undocumented
|
||||
* bits as required according to the documentation.
|
||||
*/
|
||||
struct stb6100_regmask {
|
||||
u8 mask;
|
||||
u8 set;
|
||||
};
|
||||
|
||||
static const struct stb6100_regmask stb6100_template[] = {
|
||||
[STB6100_LD] = { 0xff, 0x00 },
|
||||
[STB6100_VCO] = { 0xff, 0x00 },
|
||||
[STB6100_NI] = { 0xff, 0x00 },
|
||||
[STB6100_NF_LSB] = { 0xff, 0x00 },
|
||||
[STB6100_K] = { 0xc7, 0x38 },
|
||||
[STB6100_G] = { 0xef, 0x10 },
|
||||
[STB6100_F] = { 0x1f, 0xc0 },
|
||||
[STB6100_DLB] = { 0x38, 0xc4 },
|
||||
[STB6100_TEST1] = { 0x00, 0x8f },
|
||||
[STB6100_FCCK] = { 0x40, 0x0d },
|
||||
[STB6100_LPEN] = { 0xf0, 0x0b },
|
||||
[STB6100_TEST3] = { 0x00, 0xde },
|
||||
};
|
||||
|
||||
static void stb6100_normalise_regs(u8 regs[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < STB6100_NUMREGS; i++)
|
||||
regs[i] = (regs[i] & stb6100_template[i].mask) | stb6100_template[i].set;
|
||||
}
|
||||
|
||||
static int stb6100_read_regs(struct stb6100_state *state, u8 regs[])
|
||||
{
|
||||
int rc;
|
||||
struct i2c_msg msg = {
|
||||
.addr = state->config->tuner_address,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = regs,
|
||||
.len = STB6100_NUMREGS
|
||||
};
|
||||
|
||||
rc = i2c_transfer(state->i2c, &msg, 1);
|
||||
if (unlikely(rc != 1)) {
|
||||
dprintk(verbose, FE_ERROR, 1, "Read (0x%x) err, rc=[%d]",
|
||||
state->config->tuner_address, rc);
|
||||
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
if (unlikely(verbose > FE_DEBUG)) {
|
||||
int i;
|
||||
|
||||
dprintk(verbose, FE_DEBUG, 1, " Read from 0x%02x", state->config->tuner_address);
|
||||
for (i = 0; i < STB6100_NUMREGS; i++)
|
||||
dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[i], regs[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stb6100_read_reg(struct stb6100_state *state, u8 reg)
|
||||
{
|
||||
u8 regs[STB6100_NUMREGS];
|
||||
int rc;
|
||||
|
||||
if (unlikely(reg >= STB6100_NUMREGS)) {
|
||||
dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((rc = stb6100_read_regs(state, regs)) < 0)
|
||||
return rc;
|
||||
return (unsigned int)regs[reg];
|
||||
}
|
||||
|
||||
static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int start, int len)
|
||||
{
|
||||
int rc;
|
||||
u8 cmdbuf[len + 1];
|
||||
struct i2c_msg msg = {
|
||||
.addr = state->config->tuner_address,
|
||||
.flags = 0,
|
||||
.buf = cmdbuf,
|
||||
.len = len + 1
|
||||
};
|
||||
|
||||
if (unlikely(start < 1 || start + len > STB6100_NUMREGS)) {
|
||||
dprintk(verbose, FE_ERROR, 1, "Invalid register range %d:%d",
|
||||
start, len);
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(&cmdbuf[1], buf, len);
|
||||
cmdbuf[0] = start;
|
||||
|
||||
if (unlikely(verbose > FE_DEBUG)) {
|
||||
int i;
|
||||
|
||||
dprintk(verbose, FE_DEBUG, 1, " Write @ 0x%02x: [%d:%d]", state->config->tuner_address, start, len);
|
||||
for (i = 0; i < len; i++)
|
||||
dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[start + i], buf[i]);
|
||||
}
|
||||
rc = i2c_transfer(state->i2c, &msg, 1);
|
||||
if (unlikely(rc != 1)) {
|
||||
dprintk(verbose, FE_ERROR, 1, "(0x%x) write err [%d:%d], rc=[%d]",
|
||||
(unsigned int)state->config->tuner_address, start, len, rc);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data)
|
||||
{
|
||||
if (unlikely(reg >= STB6100_NUMREGS)) {
|
||||
dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
data = (data & stb6100_template[reg].mask) | stb6100_template[reg].set;
|
||||
return stb6100_write_reg_range(state, &data, reg, 1);
|
||||
}
|
||||
|
||||
static int stb6100_write_regs(struct stb6100_state *state, u8 regs[])
|
||||
{
|
||||
stb6100_normalise_regs(regs);
|
||||
return stb6100_write_reg_range(state, ®s[1], 1, STB6100_NUMREGS - 1);
|
||||
}
|
||||
|
||||
static int stb6100_get_status(struct dvb_frontend *fe, u32 *status)
|
||||
{
|
||||
int rc;
|
||||
struct stb6100_state *state = fe->tuner_priv;
|
||||
|
||||
if ((rc = stb6100_read_reg(state, STB6100_LD)) < 0)
|
||||
return rc;
|
||||
|
||||
return (rc & STB6100_LD_LOCK) ? TUNER_STATUS_LOCKED : 0;
|
||||
}
|
||||
|
||||
static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
|
||||
{
|
||||
int rc;
|
||||
u8 f;
|
||||
struct stb6100_state *state = fe->tuner_priv;
|
||||
|
||||
if ((rc = stb6100_read_reg(state, STB6100_F)) < 0)
|
||||
return rc;
|
||||
f = rc & STB6100_F_F;
|
||||
|
||||
state->status.bandwidth = (f + 5) * 2000; /* x2 for ZIF */
|
||||
|
||||
*bandwidth = state->bandwidth = state->status.bandwidth * 1000;
|
||||
dprintk(verbose, FE_DEBUG, 1, "bandwidth = %u Hz", state->bandwidth);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
|
||||
{
|
||||
u32 tmp;
|
||||
int rc;
|
||||
struct stb6100_state *state = fe->tuner_priv;
|
||||
|
||||
dprintk(verbose, FE_DEBUG, 1, "set bandwidth to %u Hz", bandwidth);
|
||||
|
||||
bandwidth /= 2; /* ZIF */
|
||||
|
||||
if (bandwidth >= 36000000) /* F[4:0] BW/2 max =31+5=36 mhz for F=31 */
|
||||
tmp = 31;
|
||||
else if (bandwidth <= 5000000) /* bw/2 min = 5Mhz for F=0 */
|
||||
tmp = 0;
|
||||
else /* if 5 < bw/2 < 36 */
|
||||
tmp = (bandwidth + 500000) / 1000000 - 5;
|
||||
|
||||
/* Turn on LPF bandwidth setting clock control,
|
||||
* set bandwidth, wait 10ms, turn off.
|
||||
*/
|
||||
if ((rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d | STB6100_FCCK_FCCK)) < 0)
|
||||
return rc;
|
||||
if ((rc = stb6100_write_reg(state, STB6100_F, 0xc0 | tmp)) < 0)
|
||||
return rc;
|
||||
msleep(1);
|
||||
if ((rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d)) < 0)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
|
||||
{
|
||||
int rc;
|
||||
u32 nint, nfrac, fvco;
|
||||
int psd2, odiv;
|
||||
struct stb6100_state *state = fe->tuner_priv;
|
||||
u8 regs[STB6100_NUMREGS];
|
||||
|
||||
if ((rc = stb6100_read_regs(state, regs)) < 0)
|
||||
return rc;
|
||||
|
||||
odiv = (regs[STB6100_VCO] & STB6100_VCO_ODIV) >> STB6100_VCO_ODIV_SHIFT;
|
||||
psd2 = (regs[STB6100_K] & STB6100_K_PSD2) >> STB6100_K_PSD2_SHIFT;
|
||||
nint = regs[STB6100_NI];
|
||||
nfrac = ((regs[STB6100_K] & STB6100_K_NF_MSB) << 8) | regs[STB6100_NF_LSB];
|
||||
fvco = (nfrac * state->reference >> (9 - psd2)) + (nint * state->reference << psd2);
|
||||
*frequency = state->frequency = fvco >> (odiv + 1);
|
||||
|
||||
dprintk(verbose, FE_DEBUG, 1,
|
||||
"frequency = %u kHz, odiv = %u, psd2 = %u, fxtal = %u kHz, fvco = %u kHz, N(I) = %u, N(F) = %u",
|
||||
state->frequency, odiv, psd2, state->reference, fvco, nint, nfrac);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
|
||||
{
|
||||
int rc;
|
||||
const struct stb6100_lkup *ptr;
|
||||
struct stb6100_state *state = fe->tuner_priv;
|
||||
struct dvb_frontend_parameters p;
|
||||
|
||||
u32 srate = 0, fvco, nint, nfrac;
|
||||
u8 regs[STB6100_NUMREGS];
|
||||
u8 g, psd2, odiv;
|
||||
|
||||
if ((rc = stb6100_read_regs(state, regs)) < 0)
|
||||
return rc;
|
||||
|
||||
if (fe->ops.get_frontend) {
|
||||
dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters");
|
||||
fe->ops.get_frontend(fe, &p);
|
||||
}
|
||||
srate = p.u.qpsk.symbol_rate;
|
||||
|
||||
regs[STB6100_DLB] = 0xdc;
|
||||
/* Disable LPEN */
|
||||
regs[STB6100_LPEN] &= ~STB6100_LPEN_LPEN; /* PLL Loop disabled */
|
||||
|
||||
if ((rc = stb6100_write_regs(state, regs)) < 0)
|
||||
return rc;
|
||||
|
||||
/* Baseband gain. */
|
||||
if (srate >= 15000000)
|
||||
g = 9; // +4 dB
|
||||
else if (srate >= 5000000)
|
||||
g = 11; // +8 dB
|
||||
else
|
||||
g = 14; // +14 dB
|
||||
|
||||
regs[STB6100_G] = (regs[STB6100_G] & ~STB6100_G_G) | g;
|
||||
regs[STB6100_G] &= ~STB6100_G_GCT; /* mask GCT */
|
||||
regs[STB6100_G] |= (1 << 5); /* 2Vp-p Mode */
|
||||
|
||||
/* VCO divide ratio (LO divide ratio, VCO prescaler enable). */
|
||||
if (frequency <= 1075000)
|
||||
odiv = 1;
|
||||
else
|
||||
odiv = 0;
|
||||
regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_ODIV) | (odiv << STB6100_VCO_ODIV_SHIFT);
|
||||
|
||||
if ((frequency > 1075000) && (frequency <= 1325000))
|
||||
psd2 = 0;
|
||||
else
|
||||
psd2 = 1;
|
||||
regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_PSD2) | (psd2 << STB6100_K_PSD2_SHIFT);
|
||||
|
||||
/* OSM */
|
||||
for (ptr = lkup;
|
||||
(ptr->val_high != 0) && !CHKRANGE(frequency, ptr->val_low, ptr->val_high);
|
||||
ptr++);
|
||||
if (ptr->val_high == 0) {
|
||||
printk(KERN_ERR "%s: frequency out of range: %u kHz\n", __func__, frequency);
|
||||
return -EINVAL;
|
||||
}
|
||||
regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_OSM) | ptr->reg;
|
||||
|
||||
/* F(VCO) = F(LO) * (ODIV == 0 ? 2 : 4) */
|
||||
fvco = frequency << (1 + odiv);
|
||||
/* N(I) = floor(f(VCO) / (f(XTAL) * (PSD2 ? 2 : 1))) */
|
||||
nint = fvco / (state->reference << psd2);
|
||||
/* N(F) = round(f(VCO) / f(XTAL) * (PSD2 ? 2 : 1) - N(I)) * 2 ^ 9 */
|
||||
nfrac = (((fvco - (nint * state->reference << psd2)) << (9 - psd2)) + state->reference / 2) / state->reference;
|
||||
dprintk(verbose, FE_DEBUG, 1,
|
||||
"frequency = %u, srate = %u, g = %u, odiv = %u, psd2 = %u, fxtal = %u, osm = %u, fvco = %u, N(I) = %u, N(F) = %u",
|
||||
frequency, srate, (unsigned int)g, (unsigned int)odiv,
|
||||
(unsigned int)psd2, state->reference,
|
||||
ptr->reg, fvco, nint, nfrac);
|
||||
regs[STB6100_NI] = nint;
|
||||
regs[STB6100_NF_LSB] = nfrac;
|
||||
regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_NF_MSB) | ((nfrac >> 8) & STB6100_K_NF_MSB);
|
||||
regs[STB6100_VCO] |= STB6100_VCO_OSCH; /* VCO search enabled */
|
||||
regs[STB6100_VCO] |= STB6100_VCO_OCK; /* VCO search clock off */
|
||||
regs[STB6100_FCCK] |= STB6100_FCCK_FCCK; /* LPF BW setting clock enabled */
|
||||
regs[STB6100_LPEN] &= ~STB6100_LPEN_LPEN; /* PLL loop disabled */
|
||||
/* Power up. */
|
||||
regs[STB6100_LPEN] |= STB6100_LPEN_SYNP | STB6100_LPEN_OSCP | STB6100_LPEN_BEN;
|
||||
|
||||
msleep(2);
|
||||
if ((rc = stb6100_write_regs(state, regs)) < 0)
|
||||
return rc;
|
||||
|
||||
msleep(2);
|
||||
regs[STB6100_LPEN] |= STB6100_LPEN_LPEN; /* PLL loop enabled */
|
||||
if ((rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN])) < 0)
|
||||
return rc;
|
||||
|
||||
regs[STB6100_VCO] &= ~STB6100_VCO_OCK; /* VCO fast search */
|
||||
if ((rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO])) < 0)
|
||||
return rc;
|
||||
|
||||
msleep(10); /* wait for LO to lock */
|
||||
regs[STB6100_VCO] &= ~STB6100_VCO_OSCH; /* vco search disabled */
|
||||
regs[STB6100_VCO] |= STB6100_VCO_OCK; /* search clock off */
|
||||
if ((rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO])) < 0)
|
||||
return rc;
|
||||
regs[STB6100_FCCK] &= ~STB6100_FCCK_FCCK; /* LPF BW clock disabled */
|
||||
stb6100_normalise_regs(regs);
|
||||
if ((rc = stb6100_write_reg_range(state, ®s[1], 1, STB6100_NUMREGS - 3)) < 0)
|
||||
return rc;
|
||||
|
||||
msleep(100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stb6100_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
/* TODO: power down */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stb6100_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct stb6100_state *state = fe->tuner_priv;
|
||||
struct tuner_state *status = &state->status;
|
||||
|
||||
status->tunerstep = 125000;
|
||||
status->ifreq = 0;
|
||||
status->refclock = 27000000; /* Hz */
|
||||
status->iqsense = 1;
|
||||
status->bandwidth = 36000; /* kHz */
|
||||
state->bandwidth = status->bandwidth * 1000; /* MHz */
|
||||
state->reference = status->refclock / 1000; /* kHz */
|
||||
|
||||
/* Set default bandwidth. */
|
||||
return stb6100_set_bandwidth(fe, status->bandwidth);
|
||||
}
|
||||
|
||||
static int stb6100_get_state(struct dvb_frontend *fe,
|
||||
enum tuner_param param,
|
||||
struct tuner_state *state)
|
||||
{
|
||||
switch (param) {
|
||||
case DVBFE_TUNER_FREQUENCY:
|
||||
stb6100_get_frequency(fe, &state->frequency);
|
||||
break;
|
||||
case DVBFE_TUNER_TUNERSTEP:
|
||||
break;
|
||||
case DVBFE_TUNER_IFFREQ:
|
||||
break;
|
||||
case DVBFE_TUNER_BANDWIDTH:
|
||||
stb6100_get_bandwidth(fe, &state->bandwidth);
|
||||
break;
|
||||
case DVBFE_TUNER_REFCLOCK:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stb6100_set_state(struct dvb_frontend *fe,
|
||||
enum tuner_param param,
|
||||
struct tuner_state *state)
|
||||
{
|
||||
struct stb6100_state *tstate = fe->tuner_priv;
|
||||
|
||||
switch (param) {
|
||||
case DVBFE_TUNER_FREQUENCY:
|
||||
stb6100_set_frequency(fe, state->frequency);
|
||||
tstate->frequency = state->frequency;
|
||||
break;
|
||||
case DVBFE_TUNER_TUNERSTEP:
|
||||
break;
|
||||
case DVBFE_TUNER_IFFREQ:
|
||||
break;
|
||||
case DVBFE_TUNER_BANDWIDTH:
|
||||
stb6100_set_bandwidth(fe, state->bandwidth);
|
||||
tstate->bandwidth = state->bandwidth;
|
||||
break;
|
||||
case DVBFE_TUNER_REFCLOCK:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_tuner_ops stb6100_ops = {
|
||||
.info = {
|
||||
.name = "STB6100 Silicon Tuner",
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_step = 0,
|
||||
},
|
||||
|
||||
.init = stb6100_init,
|
||||
.sleep = stb6100_sleep,
|
||||
.get_status = stb6100_get_status,
|
||||
.get_state = stb6100_get_state,
|
||||
.set_state = stb6100_set_state,
|
||||
.release = stb6100_release
|
||||
};
|
||||
|
||||
struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
|
||||
struct stb6100_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct stb6100_state *state = NULL;
|
||||
|
||||
state = kzalloc(sizeof (struct stb6100_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
goto error;
|
||||
|
||||
state->config = config;
|
||||
state->i2c = i2c;
|
||||
state->frontend = fe;
|
||||
state->reference = config->refclock / 1000; /* kHz */
|
||||
fe->tuner_priv = state;
|
||||
fe->ops.tuner_ops = stb6100_ops;
|
||||
|
||||
printk("%s: Attaching STB6100 \n", __func__);
|
||||
return fe;
|
||||
|
||||
error:
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int stb6100_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct stb6100_state *state = fe->tuner_priv;
|
||||
|
||||
fe->tuner_priv = NULL;
|
||||
kfree(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(stb6100_attach);
|
||||
MODULE_PARM_DESC(verbose, "Set Verbosity level");
|
||||
|
||||
MODULE_AUTHOR("Manu Abraham");
|
||||
MODULE_DESCRIPTION("STB6100 Silicon tuner");
|
||||
MODULE_LICENSE("GPL");
|
||||
115
drivers/media/dvb/frontends/stb6100.h
Normal file
115
drivers/media/dvb/frontends/stb6100.h
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
STB6100 Silicon Tuner
|
||||
Copyright (C) Manu Abraham (abraham.manu@gmail.com)
|
||||
|
||||
Copyright (C) ST Microelectronics
|
||||
|
||||
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 __STB_6100_REG_H
|
||||
#define __STB_6100_REG_H
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include "dvb_frontend.h"
|
||||
|
||||
#define STB6100_LD 0x00
|
||||
#define STB6100_LD_LOCK (1 << 0)
|
||||
|
||||
#define STB6100_VCO 0x01
|
||||
#define STB6100_VCO_OSCH (0x01 << 7)
|
||||
#define STB6100_VCO_OSCH_SHIFT 7
|
||||
#define STB6100_VCO_OCK (0x03 << 5)
|
||||
#define STB6100_VCO_OCK_SHIFT 5
|
||||
#define STB6100_VCO_ODIV (0x01 << 4)
|
||||
#define STB6100_VCO_ODIV_SHIFT 4
|
||||
#define STB6100_VCO_OSM (0x0f << 0)
|
||||
|
||||
#define STB6100_NI 0x02
|
||||
#define STB6100_NF_LSB 0x03
|
||||
|
||||
#define STB6100_K 0x04
|
||||
#define STB6100_K_PSD2 (0x01 << 2)
|
||||
#define STB6100_K_PSD2_SHIFT 2
|
||||
#define STB6100_K_NF_MSB (0x03 << 0)
|
||||
|
||||
#define STB6100_G 0x05
|
||||
#define STB6100_G_G (0x0f << 0)
|
||||
#define STB6100_G_GCT (0x07 << 5)
|
||||
|
||||
#define STB6100_F 0x06
|
||||
#define STB6100_F_F (0x1f << 0)
|
||||
|
||||
#define STB6100_DLB 0x07
|
||||
|
||||
#define STB6100_TEST1 0x08
|
||||
|
||||
#define STB6100_FCCK 0x09
|
||||
#define STB6100_FCCK_FCCK (0x01 << 6)
|
||||
|
||||
#define STB6100_LPEN 0x0a
|
||||
#define STB6100_LPEN_LPEN (0x01 << 4)
|
||||
#define STB6100_LPEN_SYNP (0x01 << 5)
|
||||
#define STB6100_LPEN_OSCP (0x01 << 6)
|
||||
#define STB6100_LPEN_BEN (0x01 << 7)
|
||||
|
||||
#define STB6100_TEST3 0x0b
|
||||
|
||||
#define STB6100_NUMREGS 0x0c
|
||||
|
||||
|
||||
#define INRANGE(val, x, y) (((x <= val) && (val <= y)) || \
|
||||
((y <= val) && (val <= x)) ? 1 : 0)
|
||||
|
||||
#define CHKRANGE(val, x, y) (((val >= x) && (val < y)) ? 1 : 0)
|
||||
|
||||
struct stb6100_config {
|
||||
u8 tuner_address;
|
||||
u32 refclock;
|
||||
};
|
||||
|
||||
struct stb6100_state {
|
||||
struct i2c_adapter *i2c;
|
||||
|
||||
const struct stb6100_config *config;
|
||||
struct dvb_tuner_ops ops;
|
||||
struct dvb_frontend *frontend;
|
||||
struct tuner_state status;
|
||||
|
||||
u32 frequency;
|
||||
u32 srate;
|
||||
u32 bandwidth;
|
||||
u32 reference;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_STB6100) || (defined(CONFIG_DVB_STB6100_MODULE) && defined(MODULE))
|
||||
|
||||
extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
|
||||
struct stb6100_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
|
||||
#else
|
||||
|
||||
static inline struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
|
||||
struct stb6100_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif //CONFIG_DVB_STB6100
|
||||
|
||||
#endif
|
||||
108
drivers/media/dvb/frontends/stb6100_cfg.h
Normal file
108
drivers/media/dvb/frontends/stb6100_cfg.h
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
STB6100 Silicon Tuner
|
||||
Copyright (C) Manu Abraham (abraham.manu@gmail.com)
|
||||
|
||||
Copyright (C) ST Microelectronics
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
|
||||
{
|
||||
struct dvb_frontend_ops *frontend_ops = NULL;
|
||||
struct dvb_tuner_ops *tuner_ops = NULL;
|
||||
struct tuner_state t_state;
|
||||
int err = 0;
|
||||
|
||||
if (&fe->ops)
|
||||
frontend_ops = &fe->ops;
|
||||
if (&frontend_ops->tuner_ops)
|
||||
tuner_ops = &frontend_ops->tuner_ops;
|
||||
if (tuner_ops->get_state) {
|
||||
if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
|
||||
printk("%s: Invalid parameter\n", __func__);
|
||||
return err;
|
||||
}
|
||||
*frequency = t_state.frequency;
|
||||
printk("%s: Frequency=%d\n", __func__, t_state.frequency);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
|
||||
{
|
||||
struct dvb_frontend_ops *frontend_ops = NULL;
|
||||
struct dvb_tuner_ops *tuner_ops = NULL;
|
||||
struct tuner_state t_state;
|
||||
int err = 0;
|
||||
|
||||
t_state.frequency = frequency;
|
||||
if (&fe->ops)
|
||||
frontend_ops = &fe->ops;
|
||||
if (&frontend_ops->tuner_ops)
|
||||
tuner_ops = &frontend_ops->tuner_ops;
|
||||
if (tuner_ops->set_state) {
|
||||
if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
|
||||
printk("%s: Invalid parameter\n", __func__);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
printk("%s: Frequency=%d\n", __func__, t_state.frequency);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
|
||||
{
|
||||
struct dvb_frontend_ops *frontend_ops = &fe->ops;
|
||||
struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
|
||||
struct tuner_state t_state;
|
||||
int err = 0;
|
||||
|
||||
if (&fe->ops)
|
||||
frontend_ops = &fe->ops;
|
||||
if (&frontend_ops->tuner_ops)
|
||||
tuner_ops = &frontend_ops->tuner_ops;
|
||||
if (tuner_ops->get_state) {
|
||||
if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
|
||||
printk("%s: Invalid parameter\n", __func__);
|
||||
return err;
|
||||
}
|
||||
*bandwidth = t_state.bandwidth;
|
||||
}
|
||||
printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
|
||||
{
|
||||
struct dvb_frontend_ops *frontend_ops = NULL;
|
||||
struct dvb_tuner_ops *tuner_ops = NULL;
|
||||
struct tuner_state t_state;
|
||||
int err = 0;
|
||||
|
||||
t_state.bandwidth = bandwidth;
|
||||
if (&fe->ops)
|
||||
frontend_ops = &fe->ops;
|
||||
if (&frontend_ops->tuner_ops)
|
||||
tuner_ops = &frontend_ops->tuner_ops;
|
||||
if (tuner_ops->set_state) {
|
||||
if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
|
||||
printk("%s: Invalid parameter\n", __func__);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
|
||||
return 0;
|
||||
}
|
||||
230
drivers/media/dvb/frontends/tda8261.c
Normal file
230
drivers/media/dvb/frontends/tda8261.c
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
TDA8261 8PSK/QPSK tuner driver
|
||||
Copyright (C) Manu Abraham (abraham.manu@gmail.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/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "tda8261.h"
|
||||
|
||||
struct tda8261_state {
|
||||
struct dvb_frontend *fe;
|
||||
struct i2c_adapter *i2c;
|
||||
const struct tda8261_config *config;
|
||||
|
||||
/* state cache */
|
||||
u32 frequency;
|
||||
u32 bandwidth;
|
||||
};
|
||||
|
||||
static int tda8261_read(struct tda8261_state *state, u8 *buf)
|
||||
{
|
||||
const struct tda8261_config *config = state->config;
|
||||
int err = 0;
|
||||
struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD,.buf = buf, .len = 2 };
|
||||
|
||||
if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1)
|
||||
printk("%s: read error, err=%d\n", __func__, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tda8261_write(struct tda8261_state *state, u8 *buf)
|
||||
{
|
||||
const struct tda8261_config *config = state->config;
|
||||
int err = 0;
|
||||
struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = 4 };
|
||||
|
||||
if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1)
|
||||
printk("%s: write error, err=%d\n", __func__, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tda8261_get_status(struct dvb_frontend *fe, u32 *status)
|
||||
{
|
||||
struct tda8261_state *state = fe->tuner_priv;
|
||||
u8 result = 0;
|
||||
int err = 0;
|
||||
|
||||
*status = 0;
|
||||
|
||||
if ((err = tda8261_read(state, &result)) < 0) {
|
||||
printk("%s: I/O Error\n", __func__);
|
||||
return err;
|
||||
}
|
||||
if ((result >> 6) & 0x01) {
|
||||
printk("%s: Tuner Phase Locked\n", __func__);
|
||||
*status = 1;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const u32 div_tab[] = { 2000, 1000, 500, 250, 125 }; /* kHz */
|
||||
static const u8 ref_div[] = { 0x00, 0x01, 0x02, 0x05, 0x07 };
|
||||
|
||||
static int tda8261_get_state(struct dvb_frontend *fe,
|
||||
enum tuner_param param,
|
||||
struct tuner_state *tstate)
|
||||
{
|
||||
struct tda8261_state *state = fe->tuner_priv;
|
||||
int err = 0;
|
||||
|
||||
switch (param) {
|
||||
case DVBFE_TUNER_FREQUENCY:
|
||||
tstate->frequency = state->frequency;
|
||||
break;
|
||||
case DVBFE_TUNER_BANDWIDTH:
|
||||
tstate->bandwidth = 40000000; /* FIXME! need to calculate Bandwidth */
|
||||
break;
|
||||
default:
|
||||
printk("%s: Unknown parameter (param=%d)\n", __func__, param);
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tda8261_set_state(struct dvb_frontend *fe,
|
||||
enum tuner_param param,
|
||||
struct tuner_state *tstate)
|
||||
{
|
||||
struct tda8261_state *state = fe->tuner_priv;
|
||||
const struct tda8261_config *config = state->config;
|
||||
u32 frequency, N, status = 0;
|
||||
u8 buf[4];
|
||||
int err = 0;
|
||||
|
||||
if (param & DVBFE_TUNER_FREQUENCY) {
|
||||
/**
|
||||
* N = Max VCO Frequency / Channel Spacing
|
||||
* Max VCO Frequency = VCO frequency + (channel spacing - 1)
|
||||
* (to account for half channel spacing on either side)
|
||||
*/
|
||||
frequency = tstate->frequency;
|
||||
if ((frequency < 950000) || (frequency > 2150000)) {
|
||||
printk("%s: Frequency beyond limits, frequency=%d\n", __func__, frequency);
|
||||
return -EINVAL;
|
||||
}
|
||||
N = (frequency + (div_tab[config->step_size] - 1)) / div_tab[config->step_size];
|
||||
printk("%s: Step size=%d, Divider=%d, PG=0x%02x (%d)\n",
|
||||
__func__, config->step_size, div_tab[config->step_size], N, N);
|
||||
|
||||
buf[0] = (N >> 8) & 0xff;
|
||||
buf[1] = N & 0xff;
|
||||
buf[2] = (0x01 << 7) | ((ref_div[config->step_size] & 0x07) << 1);
|
||||
|
||||
if (frequency < 1450000)
|
||||
buf[3] = 0x00;
|
||||
if (frequency < 2000000)
|
||||
buf[3] = 0x40;
|
||||
if (frequency < 2150000)
|
||||
buf[3] = 0x80;
|
||||
|
||||
/* Set params */
|
||||
if ((err = tda8261_write(state, buf)) < 0) {
|
||||
printk("%s: I/O Error\n", __func__);
|
||||
return err;
|
||||
}
|
||||
/* sleep for some time */
|
||||
printk("%s: Waiting to Phase LOCK\n", __func__);
|
||||
msleep(20);
|
||||
/* check status */
|
||||
if ((err = tda8261_get_status(fe, &status)) < 0) {
|
||||
printk("%s: I/O Error\n", __func__);
|
||||
return err;
|
||||
}
|
||||
if (status == 1) {
|
||||
printk("%s: Tuner Phase locked: status=%d\n", __func__, status);
|
||||
state->frequency = frequency; /* cache successful state */
|
||||
} else {
|
||||
printk("%s: No Phase lock: status=%d\n", __func__, status);
|
||||
}
|
||||
} else {
|
||||
printk("%s: Unknown parameter (param=%d)\n", __func__, param);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda8261_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct tda8261_state *state = fe->tuner_priv;
|
||||
|
||||
fe->tuner_priv = NULL;
|
||||
kfree(state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_tuner_ops tda8261_ops = {
|
||||
|
||||
.info = {
|
||||
.name = "TDA8261",
|
||||
// .tuner_name = NULL,
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_step = 0
|
||||
},
|
||||
|
||||
.set_state = tda8261_set_state,
|
||||
.get_state = tda8261_get_state,
|
||||
.get_status = tda8261_get_status,
|
||||
.release = tda8261_release
|
||||
};
|
||||
|
||||
struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
|
||||
const struct tda8261_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct tda8261_state *state = NULL;
|
||||
|
||||
if ((state = kzalloc(sizeof (struct tda8261_state), GFP_KERNEL)) == NULL)
|
||||
goto exit;
|
||||
|
||||
state->config = config;
|
||||
state->i2c = i2c;
|
||||
state->fe = fe;
|
||||
fe->tuner_priv = state;
|
||||
fe->ops.tuner_ops = tda8261_ops;
|
||||
|
||||
fe->ops.tuner_ops.info.frequency_step = div_tab[config->step_size];
|
||||
// fe->ops.tuner_ops.tuner_name = &config->buf;
|
||||
|
||||
// printk("%s: Attaching %s TDA8261 8PSK/QPSK tuner\n",
|
||||
// __func__, fe->ops.tuner_ops.tuner_name);
|
||||
printk("%s: Attaching TDA8261 8PSK/QPSK tuner\n", __func__);
|
||||
|
||||
return fe;
|
||||
|
||||
exit:
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(tda8261_attach);
|
||||
MODULE_PARM_DESC(verbose, "Set verbosity level");
|
||||
|
||||
MODULE_AUTHOR("Manu Abraham");
|
||||
MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner");
|
||||
MODULE_LICENSE("GPL");
|
||||
55
drivers/media/dvb/frontends/tda8261.h
Normal file
55
drivers/media/dvb/frontends/tda8261.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
TDA8261 8PSK/QPSK tuner driver
|
||||
Copyright (C) Manu Abraham (abraham.manu@gmail.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 __TDA8261_H
|
||||
#define __TDA8261_H
|
||||
|
||||
enum tda8261_step {
|
||||
TDA8261_STEP_2000 = 0, /* 2000 kHz */
|
||||
TDA8261_STEP_1000, /* 1000 kHz */
|
||||
TDA8261_STEP_500, /* 500 kHz */
|
||||
TDA8261_STEP_250, /* 250 kHz */
|
||||
TDA8261_STEP_125 /* 125 kHz */
|
||||
};
|
||||
|
||||
struct tda8261_config {
|
||||
// u8 buf[16];
|
||||
u8 addr;
|
||||
enum tda8261_step step_size;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_TDA8261) || (defined(CONFIG_DVB_TDA8261_MODULE) && defined(MODULE))
|
||||
|
||||
extern struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
|
||||
const struct tda8261_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
|
||||
#else
|
||||
|
||||
static inline struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
|
||||
const struct tda8261_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif //CONFIG_DVB_TDA8261
|
||||
|
||||
#endif// __TDA8261_H
|
||||
84
drivers/media/dvb/frontends/tda8261_cfg.h
Normal file
84
drivers/media/dvb/frontends/tda8261_cfg.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
TDA8261 8PSK/QPSK tuner driver
|
||||
Copyright (C) Manu Abraham (abraham.manu@gmail.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.
|
||||
*/
|
||||
|
||||
static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency)
|
||||
{
|
||||
struct dvb_frontend_ops *frontend_ops = NULL;
|
||||
struct dvb_tuner_ops *tuner_ops = NULL;
|
||||
struct tuner_state t_state;
|
||||
int err = 0;
|
||||
|
||||
if (&fe->ops)
|
||||
frontend_ops = &fe->ops;
|
||||
if (&frontend_ops->tuner_ops)
|
||||
tuner_ops = &frontend_ops->tuner_ops;
|
||||
if (tuner_ops->get_state) {
|
||||
if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
|
||||
printk("%s: Invalid parameter\n", __func__);
|
||||
return err;
|
||||
}
|
||||
*frequency = t_state.frequency;
|
||||
printk("%s: Frequency=%d\n", __func__, t_state.frequency);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda8261_set_frequency(struct dvb_frontend *fe, u32 frequency)
|
||||
{
|
||||
struct dvb_frontend_ops *frontend_ops = NULL;
|
||||
struct dvb_tuner_ops *tuner_ops = NULL;
|
||||
struct tuner_state t_state;
|
||||
int err = 0;
|
||||
|
||||
t_state.frequency = frequency;
|
||||
if (&fe->ops)
|
||||
frontend_ops = &fe->ops;
|
||||
if (&frontend_ops->tuner_ops)
|
||||
tuner_ops = &frontend_ops->tuner_ops;
|
||||
if (tuner_ops->set_state) {
|
||||
if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
|
||||
printk("%s: Invalid parameter\n", __func__);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
printk("%s: Frequency=%d\n", __func__, t_state.frequency);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tda8261_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
|
||||
{
|
||||
struct dvb_frontend_ops *frontend_ops = &fe->ops;
|
||||
struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
|
||||
struct tuner_state t_state;
|
||||
int err = 0;
|
||||
|
||||
if (&fe->ops)
|
||||
frontend_ops = &fe->ops;
|
||||
if (&frontend_ops->tuner_ops)
|
||||
tuner_ops = &frontend_ops->tuner_ops;
|
||||
if (tuner_ops->get_state) {
|
||||
if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
|
||||
printk("%s: Invalid parameter\n", __func__);
|
||||
return err;
|
||||
}
|
||||
*bandwidth = t_state.bandwidth;
|
||||
}
|
||||
printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -220,15 +220,18 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
|
|||
/* These are extrapolated from the 7 and 8MHz values */
|
||||
zl10353_single_write(fe, MCLK_RATIO, 0x97);
|
||||
zl10353_single_write(fe, 0x64, 0x34);
|
||||
zl10353_single_write(fe, 0xcc, 0xdd);
|
||||
break;
|
||||
case BANDWIDTH_7_MHZ:
|
||||
zl10353_single_write(fe, MCLK_RATIO, 0x86);
|
||||
zl10353_single_write(fe, 0x64, 0x35);
|
||||
zl10353_single_write(fe, 0xcc, 0x73);
|
||||
break;
|
||||
case BANDWIDTH_8_MHZ:
|
||||
default:
|
||||
zl10353_single_write(fe, MCLK_RATIO, 0x75);
|
||||
zl10353_single_write(fe, 0x64, 0x36);
|
||||
zl10353_single_write(fe, 0xcc, 0x73);
|
||||
}
|
||||
|
||||
zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate);
|
||||
|
|
|
|||
|
|
@ -38,6 +38,16 @@ struct usb_device_id smsusb_id_table[] = {
|
|||
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
|
||||
{ USB_DEVICE(0x2040, 0x1801),
|
||||
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
|
||||
{ USB_DEVICE(0x2040, 0x2000),
|
||||
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
|
||||
{ USB_DEVICE(0x2040, 0x2009),
|
||||
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 },
|
||||
{ USB_DEVICE(0x2040, 0x200a),
|
||||
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
|
||||
{ USB_DEVICE(0x2040, 0x2010),
|
||||
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
|
||||
{ USB_DEVICE(0x2040, 0x2019),
|
||||
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
|
||||
{ USB_DEVICE(0x2040, 0x5500),
|
||||
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
|
||||
{ USB_DEVICE(0x2040, 0x5510),
|
||||
|
|
@ -96,6 +106,21 @@ static struct sms_board sms_boards[] = {
|
|||
.name = "Hauppauge WinTV MiniStick",
|
||||
.type = SMS_NOVA_B0,
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
|
||||
.led_power = 26,
|
||||
.led_lo = 27,
|
||||
.led_hi = 28,
|
||||
},
|
||||
[SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = {
|
||||
.name = "Hauppauge WinTV MiniCard",
|
||||
.type = SMS_NOVA_B0,
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
|
||||
.lna_ctrl = 29,
|
||||
},
|
||||
[SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
|
||||
.name = "Hauppauge WinTV MiniCard",
|
||||
.type = SMS_NOVA_B0,
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
|
||||
.lna_ctrl = 1,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -106,3 +131,88 @@ struct sms_board *sms_get_board(int id)
|
|||
return &sms_boards[id];
|
||||
}
|
||||
|
||||
static int sms_set_gpio(struct smscore_device_t *coredev, u32 pin, int enable)
|
||||
{
|
||||
int ret;
|
||||
struct smscore_gpio_config gpioconfig = {
|
||||
.direction = SMS_GPIO_DIRECTION_OUTPUT,
|
||||
.pullupdown = SMS_GPIO_PULLUPDOWN_NONE,
|
||||
.inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,
|
||||
.outputslewrate = SMS_GPIO_OUTPUTSLEWRATE_FAST,
|
||||
.outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA,
|
||||
};
|
||||
|
||||
if (pin == 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = smscore_configure_gpio(coredev, pin, &gpioconfig);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return smscore_set_gpio(coredev, pin, enable);
|
||||
}
|
||||
|
||||
int sms_board_setup(struct smscore_device_t *coredev)
|
||||
{
|
||||
int board_id = smscore_get_board_id(coredev);
|
||||
struct sms_board *board = sms_get_board(board_id);
|
||||
|
||||
switch (board_id) {
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
|
||||
/* turn off all LEDs */
|
||||
sms_set_gpio(coredev, board->led_power, 0);
|
||||
sms_set_gpio(coredev, board->led_hi, 0);
|
||||
sms_set_gpio(coredev, board->led_lo, 0);
|
||||
break;
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
|
||||
/* turn off LNA */
|
||||
sms_set_gpio(coredev, board->lna_ctrl, 0);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sms_board_power(struct smscore_device_t *coredev, int onoff)
|
||||
{
|
||||
int board_id = smscore_get_board_id(coredev);
|
||||
struct sms_board *board = sms_get_board(board_id);
|
||||
|
||||
switch (board_id) {
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
|
||||
/* power LED */
|
||||
sms_set_gpio(coredev,
|
||||
board->led_power, onoff ? 1 : 0);
|
||||
break;
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
|
||||
/* LNA */
|
||||
sms_set_gpio(coredev,
|
||||
board->lna_ctrl, onoff ? 1 : 0);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sms_board_led_feedback(struct smscore_device_t *coredev, int led)
|
||||
{
|
||||
int board_id = smscore_get_board_id(coredev);
|
||||
struct sms_board *board = sms_get_board(board_id);
|
||||
|
||||
/* dont touch GPIO if LEDs are already set */
|
||||
if (smscore_led_state(coredev, -1) == led)
|
||||
return 0;
|
||||
|
||||
switch (board_id) {
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
|
||||
sms_set_gpio(coredev,
|
||||
board->led_lo, (led & SMS_LED_LO) ? 1 : 0);
|
||||
sms_set_gpio(coredev,
|
||||
board->led_hi, (led & SMS_LED_HI) ? 1 : 0);
|
||||
|
||||
smscore_led_state(coredev, led);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,14 +32,27 @@
|
|||
#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6
|
||||
#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7
|
||||
#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
|
||||
#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9
|
||||
#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10
|
||||
|
||||
struct sms_board {
|
||||
enum sms_device_type_st type;
|
||||
char *name, *fw[DEVICE_MODE_MAX];
|
||||
|
||||
/* gpios */
|
||||
int led_power, led_hi, led_lo, lna_ctrl;
|
||||
};
|
||||
|
||||
struct sms_board *sms_get_board(int id);
|
||||
|
||||
int sms_board_setup(struct smscore_device_t *coredev);
|
||||
|
||||
#define SMS_LED_OFF 0
|
||||
#define SMS_LED_LO 1
|
||||
#define SMS_LED_HI 2
|
||||
int sms_board_led_feedback(struct smscore_device_t *coredev, int led);
|
||||
int sms_board_power(struct smscore_device_t *coredev, int onoff);
|
||||
|
||||
extern struct usb_device_id smsusb_id_table[];
|
||||
|
||||
#endif /* __SMS_CARDS_H__ */
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ struct smscore_device_t {
|
|||
struct completion init_device_done, reload_start_done, resume_done;
|
||||
|
||||
int board_id;
|
||||
int led_state;
|
||||
};
|
||||
|
||||
void smscore_set_board_id(struct smscore_device_t *core, int id)
|
||||
|
|
@ -98,6 +99,13 @@ void smscore_set_board_id(struct smscore_device_t *core, int id)
|
|||
core->board_id = id;
|
||||
}
|
||||
|
||||
int smscore_led_state(struct smscore_device_t *core, int led)
|
||||
{
|
||||
if (led >= 0)
|
||||
core->led_state = led;
|
||||
return core->led_state;
|
||||
}
|
||||
|
||||
int smscore_get_board_id(struct smscore_device_t *core)
|
||||
{
|
||||
return core->board_id;
|
||||
|
|
@ -1187,6 +1195,76 @@ int smsclient_sendrequest(struct smscore_client_t *client,
|
|||
}
|
||||
|
||||
|
||||
int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
|
||||
struct smscore_gpio_config *pinconfig)
|
||||
{
|
||||
struct {
|
||||
struct SmsMsgHdr_ST hdr;
|
||||
u32 data[6];
|
||||
} msg;
|
||||
|
||||
if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
|
||||
msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
|
||||
msg.hdr.msgDstId = HIF_TASK;
|
||||
msg.hdr.msgFlags = 0;
|
||||
msg.hdr.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
|
||||
msg.hdr.msgLength = sizeof(msg);
|
||||
|
||||
msg.data[0] = pin;
|
||||
msg.data[1] = pinconfig->pullupdown;
|
||||
|
||||
/* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */
|
||||
msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0;
|
||||
|
||||
switch (pinconfig->outputdriving) {
|
||||
case SMS_GPIO_OUTPUTDRIVING_16mA:
|
||||
msg.data[3] = 7; /* Nova - 16mA */
|
||||
break;
|
||||
case SMS_GPIO_OUTPUTDRIVING_12mA:
|
||||
msg.data[3] = 5; /* Nova - 11mA */
|
||||
break;
|
||||
case SMS_GPIO_OUTPUTDRIVING_8mA:
|
||||
msg.data[3] = 3; /* Nova - 7mA */
|
||||
break;
|
||||
case SMS_GPIO_OUTPUTDRIVING_4mA:
|
||||
default:
|
||||
msg.data[3] = 2; /* Nova - 4mA */
|
||||
break;
|
||||
}
|
||||
|
||||
msg.data[4] = pinconfig->direction;
|
||||
msg.data[5] = 0;
|
||||
} else /* TODO: SMS_DEVICE_FAMILY1 */
|
||||
return -EINVAL;
|
||||
|
||||
return coredev->sendrequest_handler(coredev->context,
|
||||
&msg, sizeof(msg));
|
||||
}
|
||||
|
||||
int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
|
||||
{
|
||||
struct {
|
||||
struct SmsMsgHdr_ST hdr;
|
||||
u32 data[3];
|
||||
} msg;
|
||||
|
||||
if (pin > MAX_GPIO_PIN_NUMBER)
|
||||
return -EINVAL;
|
||||
|
||||
msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
|
||||
msg.hdr.msgDstId = HIF_TASK;
|
||||
msg.hdr.msgFlags = 0;
|
||||
msg.hdr.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
|
||||
msg.hdr.msgLength = sizeof(msg);
|
||||
|
||||
msg.data[0] = pin;
|
||||
msg.data[1] = level ? 1 : 0;
|
||||
msg.data[2] = 0;
|
||||
|
||||
return coredev->sendrequest_handler(coredev->context,
|
||||
&msg, sizeof(msg));
|
||||
}
|
||||
|
||||
static int __init smscore_module_init(void)
|
||||
{
|
||||
int rc = 0;
|
||||
|
|
|
|||
|
|
@ -186,6 +186,8 @@ struct smsclient_params_t {
|
|||
#define MSG_SW_RELOAD_EXEC_REQ 704
|
||||
#define MSG_SW_RELOAD_EXEC_RES 705
|
||||
#define MSG_SMS_SPI_INT_LINE_SET_REQ 710
|
||||
#define MSG_SMS_GPIO_CONFIG_EX_REQ 712
|
||||
#define MSG_SMS_GPIO_CONFIG_EX_RES 713
|
||||
#define MSG_SMS_ISDBT_TUNE_REQ 776
|
||||
#define MSG_SMS_ISDBT_TUNE_RES 777
|
||||
|
||||
|
|
@ -341,6 +343,32 @@ struct SmsMsgStatisticsInfo_ST {
|
|||
};
|
||||
|
||||
|
||||
struct smscore_gpio_config {
|
||||
#define SMS_GPIO_DIRECTION_INPUT 0
|
||||
#define SMS_GPIO_DIRECTION_OUTPUT 1
|
||||
u8 direction;
|
||||
|
||||
#define SMS_GPIO_PULLUPDOWN_NONE 0
|
||||
#define SMS_GPIO_PULLUPDOWN_PULLDOWN 1
|
||||
#define SMS_GPIO_PULLUPDOWN_PULLUP 2
|
||||
#define SMS_GPIO_PULLUPDOWN_KEEPER 3
|
||||
u8 pullupdown;
|
||||
|
||||
#define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL 0
|
||||
#define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1
|
||||
u8 inputcharacteristics;
|
||||
|
||||
#define SMS_GPIO_OUTPUTSLEWRATE_FAST 0
|
||||
#define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1
|
||||
u8 outputslewrate;
|
||||
|
||||
#define SMS_GPIO_OUTPUTDRIVING_4mA 0
|
||||
#define SMS_GPIO_OUTPUTDRIVING_8mA 1
|
||||
#define SMS_GPIO_OUTPUTDRIVING_12mA 2
|
||||
#define SMS_GPIO_OUTPUTDRIVING_16mA 3
|
||||
u8 outputdriving;
|
||||
};
|
||||
|
||||
struct smsdvb_client_t {
|
||||
struct list_head entry;
|
||||
|
||||
|
|
@ -353,7 +381,7 @@ struct smsdvb_client_t {
|
|||
struct dvb_frontend frontend;
|
||||
|
||||
fe_status_t fe_status;
|
||||
int fe_ber, fe_snr, fe_signal_strength;
|
||||
int fe_ber, fe_snr, fe_unc, fe_signal_strength;
|
||||
|
||||
struct completion tune_done, stat_done;
|
||||
|
||||
|
|
@ -396,9 +424,15 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
|
|||
extern void smscore_putbuffer(struct smscore_device_t *coredev,
|
||||
struct smscore_buffer_t *cb);
|
||||
|
||||
int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
|
||||
struct smscore_gpio_config *pinconfig);
|
||||
int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level);
|
||||
|
||||
void smscore_set_board_id(struct smscore_device_t *core, int id);
|
||||
int smscore_get_board_id(struct smscore_device_t *core);
|
||||
|
||||
int smscore_led_state(struct smscore_device_t *core, int led);
|
||||
|
||||
/* smsdvb.c */
|
||||
int smsdvb_register(void);
|
||||
void smsdvb_unregister(void);
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
|
|||
|
||||
client->fe_snr = p->Stat.SNR;
|
||||
client->fe_ber = p->Stat.BER;
|
||||
client->fe_unc = p->Stat.BERErrorCount;
|
||||
|
||||
if (p->Stat.InBandPwr < -95)
|
||||
client->fe_signal_strength = 0;
|
||||
|
|
@ -72,6 +73,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
|
|||
client->fe_status = 0;
|
||||
client->fe_snr =
|
||||
client->fe_ber =
|
||||
client->fe_unc =
|
||||
client->fe_signal_strength = 0;
|
||||
}
|
||||
|
||||
|
|
@ -165,8 +167,18 @@ static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
|
|||
struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
|
||||
DVBT_BDA_CONTROL_MSG_ID,
|
||||
HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 };
|
||||
return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
|
||||
&client->stat_done);
|
||||
int ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
|
||||
&client->stat_done);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (client->fe_status & FE_HAS_LOCK)
|
||||
sms_board_led_feedback(client->coredev,
|
||||
(client->fe_unc == 0) ?
|
||||
SMS_LED_HI : SMS_LED_LO);
|
||||
else
|
||||
sms_board_led_feedback(client->coredev, SMS_LED_OFF);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
|
||||
|
|
@ -217,6 +229,18 @@ static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
{
|
||||
struct smsdvb_client_t *client =
|
||||
container_of(fe, struct smsdvb_client_t, frontend);
|
||||
int rc = smsdvb_send_statistics_request(client);
|
||||
|
||||
if (!rc)
|
||||
*ucblocks = client->fe_unc;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_tune_settings *tune)
|
||||
{
|
||||
|
|
@ -273,6 +297,28 @@ static int smsdvb_get_frontend(struct dvb_frontend *fe,
|
|||
/* todo: */
|
||||
memcpy(fep, &client->fe_params,
|
||||
sizeof(struct dvb_frontend_parameters));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smsdvb_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct smsdvb_client_t *client =
|
||||
container_of(fe, struct smsdvb_client_t, frontend);
|
||||
|
||||
sms_board_power(client->coredev, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smsdvb_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct smsdvb_client_t *client =
|
||||
container_of(fe, struct smsdvb_client_t, frontend);
|
||||
|
||||
sms_board_led_feedback(client->coredev, SMS_LED_OFF);
|
||||
sms_board_power(client->coredev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -308,6 +354,10 @@ static struct dvb_frontend_ops smsdvb_fe_ops = {
|
|||
.read_ber = smsdvb_read_ber,
|
||||
.read_signal_strength = smsdvb_read_signal_strength,
|
||||
.read_snr = smsdvb_read_snr,
|
||||
.read_ucblocks = smsdvb_read_ucblocks,
|
||||
|
||||
.init = smsdvb_init,
|
||||
.sleep = smsdvb_sleep,
|
||||
};
|
||||
|
||||
static int smsdvb_hotplug(struct smscore_device_t *coredev,
|
||||
|
|
@ -402,6 +452,8 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
|
|||
|
||||
sms_info("success");
|
||||
|
||||
sms_board_setup(coredev);
|
||||
|
||||
return 0;
|
||||
|
||||
client_error:
|
||||
|
|
|
|||
|
|
@ -432,11 +432,56 @@ static void smsusb_disconnect(struct usb_interface *intf)
|
|||
smsusb_term_device(intf);
|
||||
}
|
||||
|
||||
static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
|
||||
{
|
||||
struct smsusb_device_t *dev =
|
||||
(struct smsusb_device_t *)usb_get_intfdata(intf);
|
||||
printk(KERN_INFO "%s Entering status %d.\n", __func__, msg.event);
|
||||
smsusb_stop_streaming(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smsusb_resume(struct usb_interface *intf)
|
||||
{
|
||||
int rc, i;
|
||||
struct smsusb_device_t *dev =
|
||||
(struct smsusb_device_t *)usb_get_intfdata(intf);
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
|
||||
printk(KERN_INFO "%s Entering.\n", __func__);
|
||||
usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
|
||||
usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
|
||||
|
||||
for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
|
||||
printk(KERN_INFO "endpoint %d %02x %02x %d\n", i,
|
||||
intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
|
||||
intf->cur_altsetting->endpoint[i].desc.bmAttributes,
|
||||
intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
|
||||
|
||||
if (intf->num_altsetting > 0) {
|
||||
rc = usb_set_interface(udev,
|
||||
intf->cur_altsetting->desc.
|
||||
bInterfaceNumber, 0);
|
||||
if (rc < 0) {
|
||||
printk(KERN_INFO
|
||||
"%s usb_set_interface failed, rc %d\n",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
smsusb_start_streaming(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_driver smsusb_driver = {
|
||||
.name = "sms1xxx",
|
||||
.probe = smsusb_probe,
|
||||
.disconnect = smsusb_disconnect,
|
||||
.id_table = smsusb_id_table,
|
||||
|
||||
.suspend = smsusb_suspend,
|
||||
.resume = smsusb_resume,
|
||||
};
|
||||
|
||||
int smsusb_register(void)
|
||||
|
|
|
|||
|
|
@ -104,6 +104,8 @@ config DVB_BUDGET_CI
|
|||
select DVB_STV0297 if !DVB_FE_CUSTOMISE
|
||||
select DVB_STV0299 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
|
||||
select DVB_STB0899 if !DVB_FE_CUSTOMISE
|
||||
select DVB_STB6100 if !DVB_FE_CUSTOMISE
|
||||
select DVB_LNBP21 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE
|
||||
|
|
@ -131,6 +133,8 @@ config DVB_BUDGET_AV
|
|||
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA10021 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
|
||||
select DVB_STB0899 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA8261 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TUA6100 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Support for simple SAA7146 based DVB cards
|
||||
|
|
|
|||
|
|
@ -35,6 +35,11 @@
|
|||
|
||||
#include "budget.h"
|
||||
#include "stv0299.h"
|
||||
#include "stb0899_drv.h"
|
||||
#include "stb0899_reg.h"
|
||||
#include "stb0899_cfg.h"
|
||||
#include "tda8261.h"
|
||||
#include "tda8261_cfg.h"
|
||||
#include "tda1002x.h"
|
||||
#include "tda1004x.h"
|
||||
#include "tua6100.h"
|
||||
|
|
@ -882,6 +887,281 @@ static struct stv0299_config philips_sd1878_config = {
|
|||
.set_symbol_rate = philips_sd1878_ci_set_symbol_rate,
|
||||
};
|
||||
|
||||
/* KNC1 DVB-S (STB0899) Inittab */
|
||||
static const struct stb0899_s1_reg knc1_stb0899_s1_init_1[] = {
|
||||
|
||||
{ STB0899_DEV_ID , 0x81 },
|
||||
{ STB0899_DISCNTRL1 , 0x32 },
|
||||
{ STB0899_DISCNTRL2 , 0x80 },
|
||||
{ STB0899_DISRX_ST0 , 0x04 },
|
||||
{ STB0899_DISRX_ST1 , 0x00 },
|
||||
{ STB0899_DISPARITY , 0x00 },
|
||||
{ STB0899_DISFIFO , 0x00 },
|
||||
{ STB0899_DISSTATUS , 0x20 },
|
||||
{ STB0899_DISF22 , 0x8c },
|
||||
{ STB0899_DISF22RX , 0x9a },
|
||||
{ STB0899_SYSREG , 0x0b },
|
||||
{ STB0899_ACRPRESC , 0x11 },
|
||||
{ STB0899_ACRDIV1 , 0x0a },
|
||||
{ STB0899_ACRDIV2 , 0x05 },
|
||||
{ STB0899_DACR1 , 0x00 },
|
||||
{ STB0899_DACR2 , 0x00 },
|
||||
{ STB0899_OUTCFG , 0x00 },
|
||||
{ STB0899_MODECFG , 0x00 },
|
||||
{ STB0899_IRQSTATUS_3 , 0x30 },
|
||||
{ STB0899_IRQSTATUS_2 , 0x00 },
|
||||
{ STB0899_IRQSTATUS_1 , 0x00 },
|
||||
{ STB0899_IRQSTATUS_0 , 0x00 },
|
||||
{ STB0899_IRQMSK_3 , 0xf3 },
|
||||
{ STB0899_IRQMSK_2 , 0xfc },
|
||||
{ STB0899_IRQMSK_1 , 0xff },
|
||||
{ STB0899_IRQMSK_0 , 0xff },
|
||||
{ STB0899_IRQCFG , 0x00 },
|
||||
{ STB0899_I2CCFG , 0x88 },
|
||||
{ STB0899_I2CRPT , 0x58 }, /* Repeater=8, Stop=disabled */
|
||||
{ STB0899_IOPVALUE5 , 0x00 },
|
||||
{ STB0899_IOPVALUE4 , 0x20 },
|
||||
{ STB0899_IOPVALUE3 , 0xc9 },
|
||||
{ STB0899_IOPVALUE2 , 0x90 },
|
||||
{ STB0899_IOPVALUE1 , 0x40 },
|
||||
{ STB0899_IOPVALUE0 , 0x00 },
|
||||
{ STB0899_GPIO00CFG , 0x82 },
|
||||
{ STB0899_GPIO01CFG , 0x82 },
|
||||
{ STB0899_GPIO02CFG , 0x82 },
|
||||
{ STB0899_GPIO03CFG , 0x82 },
|
||||
{ STB0899_GPIO04CFG , 0x82 },
|
||||
{ STB0899_GPIO05CFG , 0x82 },
|
||||
{ STB0899_GPIO06CFG , 0x82 },
|
||||
{ STB0899_GPIO07CFG , 0x82 },
|
||||
{ STB0899_GPIO08CFG , 0x82 },
|
||||
{ STB0899_GPIO09CFG , 0x82 },
|
||||
{ STB0899_GPIO10CFG , 0x82 },
|
||||
{ STB0899_GPIO11CFG , 0x82 },
|
||||
{ STB0899_GPIO12CFG , 0x82 },
|
||||
{ STB0899_GPIO13CFG , 0x82 },
|
||||
{ STB0899_GPIO14CFG , 0x82 },
|
||||
{ STB0899_GPIO15CFG , 0x82 },
|
||||
{ STB0899_GPIO16CFG , 0x82 },
|
||||
{ STB0899_GPIO17CFG , 0x82 },
|
||||
{ STB0899_GPIO18CFG , 0x82 },
|
||||
{ STB0899_GPIO19CFG , 0x82 },
|
||||
{ STB0899_GPIO20CFG , 0x82 },
|
||||
{ STB0899_SDATCFG , 0xb8 },
|
||||
{ STB0899_SCLTCFG , 0xba },
|
||||
{ STB0899_AGCRFCFG , 0x08 }, /* 0x1c */
|
||||
{ STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */
|
||||
{ STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */
|
||||
{ STB0899_DIRCLKCFG , 0x82 },
|
||||
{ STB0899_CLKOUT27CFG , 0x7e },
|
||||
{ STB0899_STDBYCFG , 0x82 },
|
||||
{ STB0899_CS0CFG , 0x82 },
|
||||
{ STB0899_CS1CFG , 0x82 },
|
||||
{ STB0899_DISEQCOCFG , 0x20 },
|
||||
{ STB0899_GPIO32CFG , 0x82 },
|
||||
{ STB0899_GPIO33CFG , 0x82 },
|
||||
{ STB0899_GPIO34CFG , 0x82 },
|
||||
{ STB0899_GPIO35CFG , 0x82 },
|
||||
{ STB0899_GPIO36CFG , 0x82 },
|
||||
{ STB0899_GPIO37CFG , 0x82 },
|
||||
{ STB0899_GPIO38CFG , 0x82 },
|
||||
{ STB0899_GPIO39CFG , 0x82 },
|
||||
{ STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
|
||||
{ STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
|
||||
{ STB0899_FILTCTRL , 0x00 },
|
||||
{ STB0899_SYSCTRL , 0x00 },
|
||||
{ STB0899_STOPCLK1 , 0x20 },
|
||||
{ STB0899_STOPCLK2 , 0x00 },
|
||||
{ STB0899_INTBUFSTATUS , 0x00 },
|
||||
{ STB0899_INTBUFCTRL , 0x0a },
|
||||
{ 0xffff , 0xff },
|
||||
};
|
||||
|
||||
static const struct stb0899_s1_reg knc1_stb0899_s1_init_3[] = {
|
||||
{ STB0899_DEMOD , 0x00 },
|
||||
{ STB0899_RCOMPC , 0xc9 },
|
||||
{ STB0899_AGC1CN , 0x41 },
|
||||
{ STB0899_AGC1REF , 0x08 },
|
||||
{ STB0899_RTC , 0x7a },
|
||||
{ STB0899_TMGCFG , 0x4e },
|
||||
{ STB0899_AGC2REF , 0x33 },
|
||||
{ STB0899_TLSR , 0x84 },
|
||||
{ STB0899_CFD , 0xee },
|
||||
{ STB0899_ACLC , 0x87 },
|
||||
{ STB0899_BCLC , 0x94 },
|
||||
{ STB0899_EQON , 0x41 },
|
||||
{ STB0899_LDT , 0xdd },
|
||||
{ STB0899_LDT2 , 0xc9 },
|
||||
{ STB0899_EQUALREF , 0xb4 },
|
||||
{ STB0899_TMGRAMP , 0x10 },
|
||||
{ STB0899_TMGTHD , 0x30 },
|
||||
{ STB0899_IDCCOMP , 0xfb },
|
||||
{ STB0899_QDCCOMP , 0x03 },
|
||||
{ STB0899_POWERI , 0x3b },
|
||||
{ STB0899_POWERQ , 0x3d },
|
||||
{ STB0899_RCOMP , 0x81 },
|
||||
{ STB0899_AGCIQIN , 0x80 },
|
||||
{ STB0899_AGC2I1 , 0x04 },
|
||||
{ STB0899_AGC2I2 , 0xf5 },
|
||||
{ STB0899_TLIR , 0x25 },
|
||||
{ STB0899_RTF , 0x80 },
|
||||
{ STB0899_DSTATUS , 0x00 },
|
||||
{ STB0899_LDI , 0xca },
|
||||
{ STB0899_CFRM , 0xf1 },
|
||||
{ STB0899_CFRL , 0xf3 },
|
||||
{ STB0899_NIRM , 0x2a },
|
||||
{ STB0899_NIRL , 0x05 },
|
||||
{ STB0899_ISYMB , 0x17 },
|
||||
{ STB0899_QSYMB , 0xfa },
|
||||
{ STB0899_SFRH , 0x2f },
|
||||
{ STB0899_SFRM , 0x68 },
|
||||
{ STB0899_SFRL , 0x40 },
|
||||
{ STB0899_SFRUPH , 0x2f },
|
||||
{ STB0899_SFRUPM , 0x68 },
|
||||
{ STB0899_SFRUPL , 0x40 },
|
||||
{ STB0899_EQUAI1 , 0xfd },
|
||||
{ STB0899_EQUAQ1 , 0x04 },
|
||||
{ STB0899_EQUAI2 , 0x0f },
|
||||
{ STB0899_EQUAQ2 , 0xff },
|
||||
{ STB0899_EQUAI3 , 0xdf },
|
||||
{ STB0899_EQUAQ3 , 0xfa },
|
||||
{ STB0899_EQUAI4 , 0x37 },
|
||||
{ STB0899_EQUAQ4 , 0x0d },
|
||||
{ STB0899_EQUAI5 , 0xbd },
|
||||
{ STB0899_EQUAQ5 , 0xf7 },
|
||||
{ STB0899_DSTATUS2 , 0x00 },
|
||||
{ STB0899_VSTATUS , 0x00 },
|
||||
{ STB0899_VERROR , 0xff },
|
||||
{ STB0899_IQSWAP , 0x2a },
|
||||
{ STB0899_ECNT1M , 0x00 },
|
||||
{ STB0899_ECNT1L , 0x00 },
|
||||
{ STB0899_ECNT2M , 0x00 },
|
||||
{ STB0899_ECNT2L , 0x00 },
|
||||
{ STB0899_ECNT3M , 0x00 },
|
||||
{ STB0899_ECNT3L , 0x00 },
|
||||
{ STB0899_FECAUTO1 , 0x06 },
|
||||
{ STB0899_FECM , 0x01 },
|
||||
{ STB0899_VTH12 , 0xf0 },
|
||||
{ STB0899_VTH23 , 0xa0 },
|
||||
{ STB0899_VTH34 , 0x78 },
|
||||
{ STB0899_VTH56 , 0x4e },
|
||||
{ STB0899_VTH67 , 0x48 },
|
||||
{ STB0899_VTH78 , 0x38 },
|
||||
{ STB0899_PRVIT , 0xff },
|
||||
{ STB0899_VITSYNC , 0x19 },
|
||||
{ STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
|
||||
{ STB0899_TSULC , 0x42 },
|
||||
{ STB0899_RSLLC , 0x40 },
|
||||
{ STB0899_TSLPL , 0x12 },
|
||||
{ STB0899_TSCFGH , 0x0c },
|
||||
{ STB0899_TSCFGM , 0x00 },
|
||||
{ STB0899_TSCFGL , 0x0c },
|
||||
{ STB0899_TSOUT , 0x0d }, /* 0x0d for CAM */
|
||||
{ STB0899_RSSYNCDEL , 0x00 },
|
||||
{ STB0899_TSINHDELH , 0x02 },
|
||||
{ STB0899_TSINHDELM , 0x00 },
|
||||
{ STB0899_TSINHDELL , 0x00 },
|
||||
{ STB0899_TSLLSTKM , 0x00 },
|
||||
{ STB0899_TSLLSTKL , 0x00 },
|
||||
{ STB0899_TSULSTKM , 0x00 },
|
||||
{ STB0899_TSULSTKL , 0xab },
|
||||
{ STB0899_PCKLENUL , 0x00 },
|
||||
{ STB0899_PCKLENLL , 0xcc },
|
||||
{ STB0899_RSPCKLEN , 0xcc },
|
||||
{ STB0899_TSSTATUS , 0x80 },
|
||||
{ STB0899_ERRCTRL1 , 0xb6 },
|
||||
{ STB0899_ERRCTRL2 , 0x96 },
|
||||
{ STB0899_ERRCTRL3 , 0x89 },
|
||||
{ STB0899_DMONMSK1 , 0x27 },
|
||||
{ STB0899_DMONMSK0 , 0x03 },
|
||||
{ STB0899_DEMAPVIT , 0x5c },
|
||||
{ STB0899_PLPARM , 0x1f },
|
||||
{ STB0899_PDELCTRL , 0x48 },
|
||||
{ STB0899_PDELCTRL2 , 0x00 },
|
||||
{ STB0899_BBHCTRL1 , 0x00 },
|
||||
{ STB0899_BBHCTRL2 , 0x00 },
|
||||
{ STB0899_HYSTTHRESH , 0x77 },
|
||||
{ STB0899_MATCSTM , 0x00 },
|
||||
{ STB0899_MATCSTL , 0x00 },
|
||||
{ STB0899_UPLCSTM , 0x00 },
|
||||
{ STB0899_UPLCSTL , 0x00 },
|
||||
{ STB0899_DFLCSTM , 0x00 },
|
||||
{ STB0899_DFLCSTL , 0x00 },
|
||||
{ STB0899_SYNCCST , 0x00 },
|
||||
{ STB0899_SYNCDCSTM , 0x00 },
|
||||
{ STB0899_SYNCDCSTL , 0x00 },
|
||||
{ STB0899_ISI_ENTRY , 0x00 },
|
||||
{ STB0899_ISI_BIT_EN , 0x00 },
|
||||
{ STB0899_MATSTRM , 0x00 },
|
||||
{ STB0899_MATSTRL , 0x00 },
|
||||
{ STB0899_UPLSTRM , 0x00 },
|
||||
{ STB0899_UPLSTRL , 0x00 },
|
||||
{ STB0899_DFLSTRM , 0x00 },
|
||||
{ STB0899_DFLSTRL , 0x00 },
|
||||
{ STB0899_SYNCSTR , 0x00 },
|
||||
{ STB0899_SYNCDSTRM , 0x00 },
|
||||
{ STB0899_SYNCDSTRL , 0x00 },
|
||||
{ STB0899_CFGPDELSTATUS1 , 0x10 },
|
||||
{ STB0899_CFGPDELSTATUS2 , 0x00 },
|
||||
{ STB0899_BBFERRORM , 0x00 },
|
||||
{ STB0899_BBFERRORL , 0x00 },
|
||||
{ STB0899_UPKTERRORM , 0x00 },
|
||||
{ STB0899_UPKTERRORL , 0x00 },
|
||||
{ 0xffff , 0xff },
|
||||
};
|
||||
|
||||
/* STB0899 demodulator config for the KNC1 and clones */
|
||||
static struct stb0899_config knc1_dvbs2_config = {
|
||||
.init_dev = knc1_stb0899_s1_init_1,
|
||||
.init_s2_demod = stb0899_s2_init_2,
|
||||
.init_s1_demod = knc1_stb0899_s1_init_3,
|
||||
.init_s2_fec = stb0899_s2_init_4,
|
||||
.init_tst = stb0899_s1_init_5,
|
||||
|
||||
.postproc = NULL,
|
||||
|
||||
.demod_address = 0x68,
|
||||
// .ts_output_mode = STB0899_OUT_PARALLEL, /* types = SERIAL/PARALLEL */
|
||||
.block_sync_mode = STB0899_SYNC_FORCED, /* DSS, SYNC_FORCED/UNSYNCED */
|
||||
// .ts_pfbit_toggle = STB0899_MPEG_NORMAL, /* DirecTV, MPEG toggling seq */
|
||||
|
||||
.xtal_freq = 27000000,
|
||||
.inversion = IQ_SWAP_OFF, /* 1 */
|
||||
|
||||
.lo_clk = 76500000,
|
||||
.hi_clk = 90000000,
|
||||
|
||||
.esno_ave = STB0899_DVBS2_ESNO_AVE,
|
||||
.esno_quant = STB0899_DVBS2_ESNO_QUANT,
|
||||
.avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE,
|
||||
.avframes_fine = STB0899_DVBS2_AVFRAMES_FINE,
|
||||
.miss_threshold = STB0899_DVBS2_MISS_THRESHOLD,
|
||||
.uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
|
||||
.uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
|
||||
.uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF,
|
||||
.sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
|
||||
|
||||
.btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS,
|
||||
.btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
|
||||
.crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS,
|
||||
.ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER,
|
||||
|
||||
.tuner_get_frequency = tda8261_get_frequency,
|
||||
.tuner_set_frequency = tda8261_set_frequency,
|
||||
.tuner_set_bandwidth = NULL,
|
||||
.tuner_get_bandwidth = tda8261_get_bandwidth,
|
||||
.tuner_set_rfsiggain = NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* SD1878/SHA tuner config
|
||||
* 1F, Single I/P, Horizontal mount, High Sensitivity
|
||||
*/
|
||||
static const struct tda8261_config sd1878c_config = {
|
||||
// .name = "SD1878/SHA",
|
||||
.addr = 0x60,
|
||||
.step_size = TDA8261_STEP_1000 /* kHz */
|
||||
};
|
||||
|
||||
static u8 read_pwm(struct budget_av *budget_av)
|
||||
{
|
||||
u8 b = 0xff;
|
||||
|
|
@ -905,8 +1185,11 @@ static u8 read_pwm(struct budget_av *budget_av)
|
|||
#define SUBID_DVBS_TV_STAR 0x0014
|
||||
#define SUBID_DVBS_TV_STAR_PLUS_X4 0x0015
|
||||
#define SUBID_DVBS_TV_STAR_CI 0x0016
|
||||
#define SUBID_DVBS2_KNC1 0x0018
|
||||
#define SUBID_DVBS2_KNC1_OEM 0x0019
|
||||
#define SUBID_DVBS_EASYWATCH_1 0x001a
|
||||
#define SUBID_DVBS_EASYWATCH_2 0x001b
|
||||
#define SUBID_DVBS2_EASYWATCH 0x001d
|
||||
#define SUBID_DVBS_EASYWATCH 0x001e
|
||||
|
||||
#define SUBID_DVBC_EASYWATCH 0x002a
|
||||
|
|
@ -941,6 +1224,9 @@ static void frontend_init(struct budget_av *budget_av)
|
|||
case SUBID_DVBT_KNC1_PLUS:
|
||||
case SUBID_DVBC_EASYWATCH:
|
||||
case SUBID_DVBC_KNC1_PLUS_MK3:
|
||||
case SUBID_DVBS2_KNC1:
|
||||
case SUBID_DVBS2_KNC1_OEM:
|
||||
case SUBID_DVBS2_EASYWATCH:
|
||||
saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
|
||||
break;
|
||||
}
|
||||
|
|
@ -993,7 +1279,14 @@ static void frontend_init(struct budget_av *budget_av)
|
|||
fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
|
||||
}
|
||||
break;
|
||||
case SUBID_DVBS2_KNC1:
|
||||
case SUBID_DVBS2_KNC1_OEM:
|
||||
case SUBID_DVBS2_EASYWATCH:
|
||||
budget_av->reinitialise_demod = 1;
|
||||
if ((fe = dvb_attach(stb0899_attach, &knc1_dvbs2_config, &budget_av->budget.i2c_adap)))
|
||||
dvb_attach(tda8261_attach, fe, &sd1878c_config, &budget_av->budget.i2c_adap);
|
||||
|
||||
break;
|
||||
case SUBID_DVBS_CINERGY1200:
|
||||
fe = dvb_attach(stv0299_attach, &cinergy_1200s_config,
|
||||
&budget_av->budget.i2c_adap);
|
||||
|
|
@ -1260,6 +1553,8 @@ static struct saa7146_ext_vv vv_data = {
|
|||
static struct saa7146_extension budget_extension;
|
||||
|
||||
MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S);
|
||||
MAKE_BUDGET_INFO(knc1s2,"KNC1 DVB-S2", BUDGET_KNC1S2);
|
||||
MAKE_BUDGET_INFO(sates2,"Satelco EasyWatch DVB-S2", BUDGET_KNC1S2);
|
||||
MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);
|
||||
MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
|
||||
MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
|
||||
|
|
@ -1290,6 +1585,9 @@ static struct pci_device_id pci_tbl[] = {
|
|||
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
|
||||
MAKE_EXTENSION_PCI(knc1spx4, 0x1894, 0x0015),
|
||||
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
|
||||
MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0018),
|
||||
MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0019),
|
||||
MAKE_EXTENSION_PCI(sates2, 0x1894, 0x001d),
|
||||
MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
|
||||
MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
|
||||
MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b),
|
||||
|
|
|
|||
|
|
@ -43,6 +43,11 @@
|
|||
#include "stv0299.h"
|
||||
#include "stv0297.h"
|
||||
#include "tda1004x.h"
|
||||
#include "stb0899_drv.h"
|
||||
#include "stb0899_reg.h"
|
||||
#include "stb0899_cfg.h"
|
||||
#include "stb6100.h"
|
||||
#include "stb6100_cfg.h"
|
||||
#include "lnbp21.h"
|
||||
#include "bsbe1.h"
|
||||
#include "bsru6.h"
|
||||
|
|
@ -1071,7 +1076,271 @@ static struct tda10023_config tda10023_config = {
|
|||
.deltaf = 0xa511,
|
||||
};
|
||||
|
||||
/* TT S2-3200 DVB-S (STB0899) Inittab */
|
||||
static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = {
|
||||
|
||||
{ STB0899_DEV_ID , 0x81 },
|
||||
{ STB0899_DISCNTRL1 , 0x32 },
|
||||
{ STB0899_DISCNTRL2 , 0x80 },
|
||||
{ STB0899_DISRX_ST0 , 0x04 },
|
||||
{ STB0899_DISRX_ST1 , 0x00 },
|
||||
{ STB0899_DISPARITY , 0x00 },
|
||||
{ STB0899_DISFIFO , 0x00 },
|
||||
{ STB0899_DISSTATUS , 0x20 },
|
||||
{ STB0899_DISF22 , 0x8c },
|
||||
{ STB0899_DISF22RX , 0x9a },
|
||||
{ STB0899_SYSREG , 0x0b },
|
||||
{ STB0899_ACRPRESC , 0x11 },
|
||||
{ STB0899_ACRDIV1 , 0x0a },
|
||||
{ STB0899_ACRDIV2 , 0x05 },
|
||||
{ STB0899_DACR1 , 0x00 },
|
||||
{ STB0899_DACR2 , 0x00 },
|
||||
{ STB0899_OUTCFG , 0x00 },
|
||||
{ STB0899_MODECFG , 0x00 },
|
||||
{ STB0899_IRQSTATUS_3 , 0x30 },
|
||||
{ STB0899_IRQSTATUS_2 , 0x00 },
|
||||
{ STB0899_IRQSTATUS_1 , 0x00 },
|
||||
{ STB0899_IRQSTATUS_0 , 0x00 },
|
||||
{ STB0899_IRQMSK_3 , 0xf3 },
|
||||
{ STB0899_IRQMSK_2 , 0xfc },
|
||||
{ STB0899_IRQMSK_1 , 0xff },
|
||||
{ STB0899_IRQMSK_0 , 0xff },
|
||||
{ STB0899_IRQCFG , 0x00 },
|
||||
{ STB0899_I2CCFG , 0x88 },
|
||||
{ STB0899_I2CRPT , 0x48 }, /* 12k Pullup, Repeater=16, Stop=disabled */
|
||||
{ STB0899_IOPVALUE5 , 0x00 },
|
||||
{ STB0899_IOPVALUE4 , 0x20 },
|
||||
{ STB0899_IOPVALUE3 , 0xc9 },
|
||||
{ STB0899_IOPVALUE2 , 0x90 },
|
||||
{ STB0899_IOPVALUE1 , 0x40 },
|
||||
{ STB0899_IOPVALUE0 , 0x00 },
|
||||
{ STB0899_GPIO00CFG , 0x82 },
|
||||
{ STB0899_GPIO01CFG , 0x82 },
|
||||
{ STB0899_GPIO02CFG , 0x82 },
|
||||
{ STB0899_GPIO03CFG , 0x82 },
|
||||
{ STB0899_GPIO04CFG , 0x82 },
|
||||
{ STB0899_GPIO05CFG , 0x82 },
|
||||
{ STB0899_GPIO06CFG , 0x82 },
|
||||
{ STB0899_GPIO07CFG , 0x82 },
|
||||
{ STB0899_GPIO08CFG , 0x82 },
|
||||
{ STB0899_GPIO09CFG , 0x82 },
|
||||
{ STB0899_GPIO10CFG , 0x82 },
|
||||
{ STB0899_GPIO11CFG , 0x82 },
|
||||
{ STB0899_GPIO12CFG , 0x82 },
|
||||
{ STB0899_GPIO13CFG , 0x82 },
|
||||
{ STB0899_GPIO14CFG , 0x82 },
|
||||
{ STB0899_GPIO15CFG , 0x82 },
|
||||
{ STB0899_GPIO16CFG , 0x82 },
|
||||
{ STB0899_GPIO17CFG , 0x82 },
|
||||
{ STB0899_GPIO18CFG , 0x82 },
|
||||
{ STB0899_GPIO19CFG , 0x82 },
|
||||
{ STB0899_GPIO20CFG , 0x82 },
|
||||
{ STB0899_SDATCFG , 0xb8 },
|
||||
{ STB0899_SCLTCFG , 0xba },
|
||||
{ STB0899_AGCRFCFG , 0x1c }, /* 0x11 */
|
||||
{ STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */
|
||||
{ STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */
|
||||
{ STB0899_DIRCLKCFG , 0x82 },
|
||||
{ STB0899_CLKOUT27CFG , 0x7e },
|
||||
{ STB0899_STDBYCFG , 0x82 },
|
||||
{ STB0899_CS0CFG , 0x82 },
|
||||
{ STB0899_CS1CFG , 0x82 },
|
||||
{ STB0899_DISEQCOCFG , 0x20 },
|
||||
{ STB0899_GPIO32CFG , 0x82 },
|
||||
{ STB0899_GPIO33CFG , 0x82 },
|
||||
{ STB0899_GPIO34CFG , 0x82 },
|
||||
{ STB0899_GPIO35CFG , 0x82 },
|
||||
{ STB0899_GPIO36CFG , 0x82 },
|
||||
{ STB0899_GPIO37CFG , 0x82 },
|
||||
{ STB0899_GPIO38CFG , 0x82 },
|
||||
{ STB0899_GPIO39CFG , 0x82 },
|
||||
{ STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
|
||||
{ STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
|
||||
{ STB0899_FILTCTRL , 0x00 },
|
||||
{ STB0899_SYSCTRL , 0x00 },
|
||||
{ STB0899_STOPCLK1 , 0x20 },
|
||||
{ STB0899_STOPCLK2 , 0x00 },
|
||||
{ STB0899_INTBUFSTATUS , 0x00 },
|
||||
{ STB0899_INTBUFCTRL , 0x0a },
|
||||
{ 0xffff , 0xff },
|
||||
};
|
||||
|
||||
static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = {
|
||||
{ STB0899_DEMOD , 0x00 },
|
||||
{ STB0899_RCOMPC , 0xc9 },
|
||||
{ STB0899_AGC1CN , 0x41 },
|
||||
{ STB0899_AGC1REF , 0x10 },
|
||||
{ STB0899_RTC , 0x7a },
|
||||
{ STB0899_TMGCFG , 0x4e },
|
||||
{ STB0899_AGC2REF , 0x34 },
|
||||
{ STB0899_TLSR , 0x84 },
|
||||
{ STB0899_CFD , 0xc7 },
|
||||
{ STB0899_ACLC , 0x87 },
|
||||
{ STB0899_BCLC , 0x94 },
|
||||
{ STB0899_EQON , 0x41 },
|
||||
{ STB0899_LDT , 0xdd },
|
||||
{ STB0899_LDT2 , 0xc9 },
|
||||
{ STB0899_EQUALREF , 0xb4 },
|
||||
{ STB0899_TMGRAMP , 0x10 },
|
||||
{ STB0899_TMGTHD , 0x30 },
|
||||
{ STB0899_IDCCOMP , 0xfb },
|
||||
{ STB0899_QDCCOMP , 0x03 },
|
||||
{ STB0899_POWERI , 0x3b },
|
||||
{ STB0899_POWERQ , 0x3d },
|
||||
{ STB0899_RCOMP , 0x81 },
|
||||
{ STB0899_AGCIQIN , 0x80 },
|
||||
{ STB0899_AGC2I1 , 0x04 },
|
||||
{ STB0899_AGC2I2 , 0xf5 },
|
||||
{ STB0899_TLIR , 0x25 },
|
||||
{ STB0899_RTF , 0x80 },
|
||||
{ STB0899_DSTATUS , 0x00 },
|
||||
{ STB0899_LDI , 0xca },
|
||||
{ STB0899_CFRM , 0xf1 },
|
||||
{ STB0899_CFRL , 0xf3 },
|
||||
{ STB0899_NIRM , 0x2a },
|
||||
{ STB0899_NIRL , 0x05 },
|
||||
{ STB0899_ISYMB , 0x17 },
|
||||
{ STB0899_QSYMB , 0xfa },
|
||||
{ STB0899_SFRH , 0x2f },
|
||||
{ STB0899_SFRM , 0x68 },
|
||||
{ STB0899_SFRL , 0x40 },
|
||||
{ STB0899_SFRUPH , 0x2f },
|
||||
{ STB0899_SFRUPM , 0x68 },
|
||||
{ STB0899_SFRUPL , 0x40 },
|
||||
{ STB0899_EQUAI1 , 0xfd },
|
||||
{ STB0899_EQUAQ1 , 0x04 },
|
||||
{ STB0899_EQUAI2 , 0x0f },
|
||||
{ STB0899_EQUAQ2 , 0xff },
|
||||
{ STB0899_EQUAI3 , 0xdf },
|
||||
{ STB0899_EQUAQ3 , 0xfa },
|
||||
{ STB0899_EQUAI4 , 0x37 },
|
||||
{ STB0899_EQUAQ4 , 0x0d },
|
||||
{ STB0899_EQUAI5 , 0xbd },
|
||||
{ STB0899_EQUAQ5 , 0xf7 },
|
||||
{ STB0899_DSTATUS2 , 0x00 },
|
||||
{ STB0899_VSTATUS , 0x00 },
|
||||
{ STB0899_VERROR , 0xff },
|
||||
{ STB0899_IQSWAP , 0x2a },
|
||||
{ STB0899_ECNT1M , 0x00 },
|
||||
{ STB0899_ECNT1L , 0x00 },
|
||||
{ STB0899_ECNT2M , 0x00 },
|
||||
{ STB0899_ECNT2L , 0x00 },
|
||||
{ STB0899_ECNT3M , 0x00 },
|
||||
{ STB0899_ECNT3L , 0x00 },
|
||||
{ STB0899_FECAUTO1 , 0x06 },
|
||||
{ STB0899_FECM , 0x01 },
|
||||
{ STB0899_VTH12 , 0xf0 },
|
||||
{ STB0899_VTH23 , 0xa0 },
|
||||
{ STB0899_VTH34 , 0x78 },
|
||||
{ STB0899_VTH56 , 0x4e },
|
||||
{ STB0899_VTH67 , 0x48 },
|
||||
{ STB0899_VTH78 , 0x38 },
|
||||
{ STB0899_PRVIT , 0xff },
|
||||
{ STB0899_VITSYNC , 0x19 },
|
||||
{ STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
|
||||
{ STB0899_TSULC , 0x42 },
|
||||
{ STB0899_RSLLC , 0x40 },
|
||||
{ STB0899_TSLPL , 0x12 },
|
||||
{ STB0899_TSCFGH , 0x0c },
|
||||
{ STB0899_TSCFGM , 0x00 },
|
||||
{ STB0899_TSCFGL , 0x0c },
|
||||
{ STB0899_TSOUT , 0x0d }, /* 0x0d for CAM */
|
||||
{ STB0899_RSSYNCDEL , 0x00 },
|
||||
{ STB0899_TSINHDELH , 0x02 },
|
||||
{ STB0899_TSINHDELM , 0x00 },
|
||||
{ STB0899_TSINHDELL , 0x00 },
|
||||
{ STB0899_TSLLSTKM , 0x00 },
|
||||
{ STB0899_TSLLSTKL , 0x00 },
|
||||
{ STB0899_TSULSTKM , 0x00 },
|
||||
{ STB0899_TSULSTKL , 0xab },
|
||||
{ STB0899_PCKLENUL , 0x00 },
|
||||
{ STB0899_PCKLENLL , 0xcc },
|
||||
{ STB0899_RSPCKLEN , 0xcc },
|
||||
{ STB0899_TSSTATUS , 0x80 },
|
||||
{ STB0899_ERRCTRL1 , 0xb6 },
|
||||
{ STB0899_ERRCTRL2 , 0x96 },
|
||||
{ STB0899_ERRCTRL3 , 0x89 },
|
||||
{ STB0899_DMONMSK1 , 0x27 },
|
||||
{ STB0899_DMONMSK0 , 0x03 },
|
||||
{ STB0899_DEMAPVIT , 0x5c },
|
||||
{ STB0899_PLPARM , 0x1f },
|
||||
{ STB0899_PDELCTRL , 0x48 },
|
||||
{ STB0899_PDELCTRL2 , 0x00 },
|
||||
{ STB0899_BBHCTRL1 , 0x00 },
|
||||
{ STB0899_BBHCTRL2 , 0x00 },
|
||||
{ STB0899_HYSTTHRESH , 0x77 },
|
||||
{ STB0899_MATCSTM , 0x00 },
|
||||
{ STB0899_MATCSTL , 0x00 },
|
||||
{ STB0899_UPLCSTM , 0x00 },
|
||||
{ STB0899_UPLCSTL , 0x00 },
|
||||
{ STB0899_DFLCSTM , 0x00 },
|
||||
{ STB0899_DFLCSTL , 0x00 },
|
||||
{ STB0899_SYNCCST , 0x00 },
|
||||
{ STB0899_SYNCDCSTM , 0x00 },
|
||||
{ STB0899_SYNCDCSTL , 0x00 },
|
||||
{ STB0899_ISI_ENTRY , 0x00 },
|
||||
{ STB0899_ISI_BIT_EN , 0x00 },
|
||||
{ STB0899_MATSTRM , 0x00 },
|
||||
{ STB0899_MATSTRL , 0x00 },
|
||||
{ STB0899_UPLSTRM , 0x00 },
|
||||
{ STB0899_UPLSTRL , 0x00 },
|
||||
{ STB0899_DFLSTRM , 0x00 },
|
||||
{ STB0899_DFLSTRL , 0x00 },
|
||||
{ STB0899_SYNCSTR , 0x00 },
|
||||
{ STB0899_SYNCDSTRM , 0x00 },
|
||||
{ STB0899_SYNCDSTRL , 0x00 },
|
||||
{ STB0899_CFGPDELSTATUS1 , 0x10 },
|
||||
{ STB0899_CFGPDELSTATUS2 , 0x00 },
|
||||
{ STB0899_BBFERRORM , 0x00 },
|
||||
{ STB0899_BBFERRORL , 0x00 },
|
||||
{ STB0899_UPKTERRORM , 0x00 },
|
||||
{ STB0899_UPKTERRORL , 0x00 },
|
||||
{ 0xffff , 0xff },
|
||||
};
|
||||
|
||||
static struct stb0899_config tt3200_config = {
|
||||
.init_dev = tt3200_stb0899_s1_init_1,
|
||||
.init_s2_demod = stb0899_s2_init_2,
|
||||
.init_s1_demod = tt3200_stb0899_s1_init_3,
|
||||
.init_s2_fec = stb0899_s2_init_4,
|
||||
.init_tst = stb0899_s1_init_5,
|
||||
|
||||
.postproc = NULL,
|
||||
|
||||
.demod_address = 0x68,
|
||||
|
||||
.xtal_freq = 27000000,
|
||||
.inversion = IQ_SWAP_ON, /* 1 */
|
||||
|
||||
.lo_clk = 76500000,
|
||||
.hi_clk = 99000000,
|
||||
|
||||
.esno_ave = STB0899_DVBS2_ESNO_AVE,
|
||||
.esno_quant = STB0899_DVBS2_ESNO_QUANT,
|
||||
.avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE,
|
||||
.avframes_fine = STB0899_DVBS2_AVFRAMES_FINE,
|
||||
.miss_threshold = STB0899_DVBS2_MISS_THRESHOLD,
|
||||
.uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
|
||||
.uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
|
||||
.uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF,
|
||||
.sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
|
||||
|
||||
.btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS,
|
||||
.btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
|
||||
.crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS,
|
||||
.ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER,
|
||||
|
||||
.tuner_get_frequency = stb6100_get_frequency,
|
||||
.tuner_set_frequency = stb6100_set_frequency,
|
||||
.tuner_set_bandwidth = stb6100_set_bandwidth,
|
||||
.tuner_get_bandwidth = stb6100_get_bandwidth,
|
||||
.tuner_set_rfsiggain = NULL
|
||||
};
|
||||
|
||||
struct stb6100_config tt3200_stb6100_config = {
|
||||
.tuner_address = 0x60,
|
||||
.refclock = 27000000,
|
||||
};
|
||||
|
||||
static void frontend_init(struct budget_ci *budget_ci)
|
||||
{
|
||||
|
|
@ -1152,6 +1421,46 @@ static void frontend_init(struct budget_ci *budget_ci)
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1019: // TT S2-3200 PCI
|
||||
/*
|
||||
* NOTE! on some STB0899 versions, the internal PLL takes a longer time
|
||||
* to settle, aka LOCK. On the older revisions of the chip, we don't see
|
||||
* this, as a result on the newer chips the entire clock tree, will not
|
||||
* be stable after a freshly POWER 'ed up situation.
|
||||
* In this case, we should RESET the STB0899 (Active LOW) and wait for
|
||||
* PLL stabilization.
|
||||
*
|
||||
* On the TT S2 3200 and clones, the STB0899 demodulator's RESETB is
|
||||
* connected to the SAA7146 GPIO, GPIO2, Pin 142
|
||||
*/
|
||||
/* Reset Demodulator */
|
||||
saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTLO);
|
||||
/* Wait for everything to die */
|
||||
msleep(50);
|
||||
/* Pull it up out of Reset state */
|
||||
saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTHI);
|
||||
/* Wait for PLL to stabilize */
|
||||
msleep(250);
|
||||
/*
|
||||
* PLL state should be stable now. Ideally, we should check
|
||||
* for PLL LOCK status. But well, never mind!
|
||||
*/
|
||||
budget_ci->budget.dvb_frontend = dvb_attach(stb0899_attach, &tt3200_config, &budget_ci->budget.i2c_adap);
|
||||
if (budget_ci->budget.dvb_frontend) {
|
||||
if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) {
|
||||
if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) {
|
||||
printk("%s: No LNBP21 found!\n", __FUNCTION__);
|
||||
dvb_frontend_detach(budget_ci->budget.dvb_frontend);
|
||||
budget_ci->budget.dvb_frontend = NULL;
|
||||
}
|
||||
} else {
|
||||
dvb_frontend_detach(budget_ci->budget.dvb_frontend);
|
||||
budget_ci->budget.dvb_frontend = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (budget_ci->budget.dvb_frontend == NULL) {
|
||||
|
|
@ -1242,6 +1551,7 @@ MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
|
|||
MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
|
||||
MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
|
||||
MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT);
|
||||
MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT);
|
||||
|
||||
static struct pci_device_id pci_tbl[] = {
|
||||
MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
|
||||
|
|
@ -1251,6 +1561,7 @@ static struct pci_device_id pci_tbl[] = {
|
|||
MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
|
||||
MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
|
||||
MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a),
|
||||
MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019),
|
||||
{
|
||||
.vendor = 0,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ static struct saa7146_pci_extension_data x_var = { \
|
|||
#define BUDGET_CIN1200C_MK3 15
|
||||
#define BUDGET_KNC1C_MK3 16
|
||||
#define BUDGET_KNC1CP_MK3 17
|
||||
#define BUDGET_KNC1S2 18
|
||||
|
||||
#define BUDGET_VIDEO_PORTA 0
|
||||
#define BUDGET_VIDEO_PORTB 1
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/* A driver for the D-Link DSB-R100 USB radio. The R100 plugs
|
||||
into both the USB and an analog audio input, so this thing
|
||||
/* A driver for the D-Link DSB-R100 USB radio and Gemtek USB Radio 21.
|
||||
The device plugs into both the USB and an analog audio input, so this thing
|
||||
only deals with initialisation and frequency setting, the
|
||||
audio data has to be handled by a sound driver.
|
||||
|
||||
|
|
@ -33,6 +33,10 @@
|
|||
|
||||
History:
|
||||
|
||||
Version 0.44:
|
||||
Add suspend/resume functions, fix unplug of device,
|
||||
a lot of cleanups and fixes by Alexey Klimov <klimov.linux@gmail.com>
|
||||
|
||||
Version 0.43:
|
||||
Oliver Neukum: avoided DMA coherency issue
|
||||
|
||||
|
|
@ -93,8 +97,8 @@
|
|||
*/
|
||||
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
|
||||
|
||||
#define DRIVER_VERSION "v0.41"
|
||||
#define RADIO_VERSION KERNEL_VERSION(0,4,1)
|
||||
#define DRIVER_VERSION "v0.44"
|
||||
#define RADIO_VERSION KERNEL_VERSION(0, 4, 4)
|
||||
|
||||
static struct v4l2_queryctrl radio_qctrl[] = {
|
||||
{
|
||||
|
|
@ -104,7 +108,27 @@ static struct v4l2_queryctrl radio_qctrl[] = {
|
|||
.maximum = 1,
|
||||
.default_value = 1,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
}
|
||||
},
|
||||
/* HINT: the disabled controls are only here to satify kradio and such apps */
|
||||
{ .id = V4L2_CID_AUDIO_VOLUME,
|
||||
.flags = V4L2_CTRL_FLAG_DISABLED,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_AUDIO_BALANCE,
|
||||
.flags = V4L2_CTRL_FLAG_DISABLED,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_AUDIO_BASS,
|
||||
.flags = V4L2_CTRL_FLAG_DISABLED,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_AUDIO_TREBLE,
|
||||
.flags = V4L2_CTRL_FLAG_DISABLED,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_AUDIO_LOUDNESS,
|
||||
.flags = V4L2_CTRL_FLAG_DISABLED,
|
||||
},
|
||||
};
|
||||
|
||||
#define DRIVER_AUTHOR "Markus Demleitner <[email protected]>"
|
||||
|
|
@ -125,12 +149,16 @@ devices, that would be 76 and 91. */
|
|||
#define FREQ_MAX 108.0
|
||||
#define FREQ_MUL 16000
|
||||
|
||||
#define videodev_to_radio(d) container_of(d, struct dsbr100_device, videodev)
|
||||
|
||||
static int usb_dsbr100_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id);
|
||||
static void usb_dsbr100_disconnect(struct usb_interface *intf);
|
||||
static int usb_dsbr100_open(struct inode *inode, struct file *file);
|
||||
static int usb_dsbr100_close(struct inode *inode, struct file *file);
|
||||
static int usb_dsbr100_suspend(struct usb_interface *intf,
|
||||
pm_message_t message);
|
||||
static int usb_dsbr100_resume(struct usb_interface *intf);
|
||||
|
||||
static int radio_nr = -1;
|
||||
module_param(radio_nr, int, 0);
|
||||
|
|
@ -138,8 +166,9 @@ module_param(radio_nr, int, 0);
|
|||
/* Data for one (physical) device */
|
||||
struct dsbr100_device {
|
||||
struct usb_device *usbdev;
|
||||
struct video_device *videodev;
|
||||
struct video_device videodev;
|
||||
u8 *transfer_buffer;
|
||||
struct mutex lock; /* buffer locking */
|
||||
int curfreq;
|
||||
int stereo;
|
||||
int users;
|
||||
|
|
@ -147,7 +176,6 @@ struct dsbr100_device {
|
|||
int muted;
|
||||
};
|
||||
|
||||
|
||||
static struct usb_device_id usb_dsbr100_device_table [] = {
|
||||
{ USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
|
||||
{ } /* Terminating entry */
|
||||
|
|
@ -157,10 +185,14 @@ MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
|
|||
|
||||
/* USB subsystem interface */
|
||||
static struct usb_driver usb_dsbr100_driver = {
|
||||
.name = "dsbr100",
|
||||
.probe = usb_dsbr100_probe,
|
||||
.disconnect = usb_dsbr100_disconnect,
|
||||
.id_table = usb_dsbr100_device_table,
|
||||
.name = "dsbr100",
|
||||
.probe = usb_dsbr100_probe,
|
||||
.disconnect = usb_dsbr100_disconnect,
|
||||
.id_table = usb_dsbr100_device_table,
|
||||
.suspend = usb_dsbr100_suspend,
|
||||
.resume = usb_dsbr100_resume,
|
||||
.reset_resume = usb_dsbr100_resume,
|
||||
.supports_autosuspend = 0,
|
||||
};
|
||||
|
||||
/* Low-level device interface begins here */
|
||||
|
|
@ -168,95 +200,190 @@ static struct usb_driver usb_dsbr100_driver = {
|
|||
/* switch on radio */
|
||||
static int dsbr100_start(struct dsbr100_device *radio)
|
||||
{
|
||||
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
|
||||
USB_REQ_GET_STATUS,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
0x00, 0xC7, radio->transfer_buffer, 8, 300) < 0 ||
|
||||
usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
|
||||
DSB100_ONOFF,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
0x01, 0x00, radio->transfer_buffer, 8, 300) < 0)
|
||||
return -1;
|
||||
radio->muted=0;
|
||||
return (radio->transfer_buffer)[0];
|
||||
}
|
||||
int retval;
|
||||
int request;
|
||||
|
||||
mutex_lock(&radio->lock);
|
||||
|
||||
retval = usb_control_msg(radio->usbdev,
|
||||
usb_rcvctrlpipe(radio->usbdev, 0),
|
||||
USB_REQ_GET_STATUS,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
0x00, 0xC7, radio->transfer_buffer, 8, 300);
|
||||
|
||||
if (retval < 0) {
|
||||
request = USB_REQ_GET_STATUS;
|
||||
goto usb_control_msg_failed;
|
||||
}
|
||||
|
||||
retval = usb_control_msg(radio->usbdev,
|
||||
usb_rcvctrlpipe(radio->usbdev, 0),
|
||||
DSB100_ONOFF,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
0x01, 0x00, radio->transfer_buffer, 8, 300);
|
||||
|
||||
if (retval < 0) {
|
||||
request = DSB100_ONOFF;
|
||||
goto usb_control_msg_failed;
|
||||
}
|
||||
|
||||
radio->muted = 0;
|
||||
mutex_unlock(&radio->lock);
|
||||
return (radio->transfer_buffer)[0];
|
||||
|
||||
usb_control_msg_failed:
|
||||
mutex_unlock(&radio->lock);
|
||||
dev_err(&radio->usbdev->dev,
|
||||
"%s - usb_control_msg returned %i, request %i\n",
|
||||
__func__, retval, request);
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
/* switch off radio */
|
||||
static int dsbr100_stop(struct dsbr100_device *radio)
|
||||
{
|
||||
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
|
||||
USB_REQ_GET_STATUS,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
0x16, 0x1C, radio->transfer_buffer, 8, 300) < 0 ||
|
||||
usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
|
||||
DSB100_ONOFF,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
0x00, 0x00, radio->transfer_buffer, 8, 300) < 0)
|
||||
return -1;
|
||||
radio->muted=1;
|
||||
int retval;
|
||||
int request;
|
||||
|
||||
mutex_lock(&radio->lock);
|
||||
|
||||
retval = usb_control_msg(radio->usbdev,
|
||||
usb_rcvctrlpipe(radio->usbdev, 0),
|
||||
USB_REQ_GET_STATUS,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
0x16, 0x1C, radio->transfer_buffer, 8, 300);
|
||||
|
||||
if (retval < 0) {
|
||||
request = USB_REQ_GET_STATUS;
|
||||
goto usb_control_msg_failed;
|
||||
}
|
||||
|
||||
retval = usb_control_msg(radio->usbdev,
|
||||
usb_rcvctrlpipe(radio->usbdev, 0),
|
||||
DSB100_ONOFF,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
0x00, 0x00, radio->transfer_buffer, 8, 300);
|
||||
|
||||
if (retval < 0) {
|
||||
request = DSB100_ONOFF;
|
||||
goto usb_control_msg_failed;
|
||||
}
|
||||
|
||||
radio->muted = 1;
|
||||
mutex_unlock(&radio->lock);
|
||||
return (radio->transfer_buffer)[0];
|
||||
|
||||
usb_control_msg_failed:
|
||||
mutex_unlock(&radio->lock);
|
||||
dev_err(&radio->usbdev->dev,
|
||||
"%s - usb_control_msg returned %i, request %i\n",
|
||||
__func__, retval, request);
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
|
||||
static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
|
||||
{
|
||||
int retval;
|
||||
int request;
|
||||
|
||||
freq = (freq / 16 * 80) / 1000 + 856;
|
||||
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
|
||||
DSB100_TUNE,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
(freq >> 8) & 0x00ff, freq & 0xff,
|
||||
radio->transfer_buffer, 8, 300) < 0 ||
|
||||
usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
|
||||
USB_REQ_GET_STATUS,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
0x96, 0xB7, radio->transfer_buffer, 8, 300) < 0 ||
|
||||
usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
|
||||
USB_REQ_GET_STATUS,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
0x00, 0x24, radio->transfer_buffer, 8, 300) < 0) {
|
||||
radio->stereo = -1;
|
||||
return -1;
|
||||
mutex_lock(&radio->lock);
|
||||
|
||||
retval = usb_control_msg(radio->usbdev,
|
||||
usb_rcvctrlpipe(radio->usbdev, 0),
|
||||
DSB100_TUNE,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
(freq >> 8) & 0x00ff, freq & 0xff,
|
||||
radio->transfer_buffer, 8, 300);
|
||||
|
||||
if (retval < 0) {
|
||||
request = DSB100_TUNE;
|
||||
goto usb_control_msg_failed;
|
||||
}
|
||||
|
||||
retval = usb_control_msg(radio->usbdev,
|
||||
usb_rcvctrlpipe(radio->usbdev, 0),
|
||||
USB_REQ_GET_STATUS,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
0x96, 0xB7, radio->transfer_buffer, 8, 300);
|
||||
|
||||
if (retval < 0) {
|
||||
request = USB_REQ_GET_STATUS;
|
||||
goto usb_control_msg_failed;
|
||||
}
|
||||
|
||||
retval = usb_control_msg(radio->usbdev,
|
||||
usb_rcvctrlpipe(radio->usbdev, 0),
|
||||
USB_REQ_GET_STATUS,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
0x00, 0x24, radio->transfer_buffer, 8, 300);
|
||||
|
||||
if (retval < 0) {
|
||||
request = USB_REQ_GET_STATUS;
|
||||
goto usb_control_msg_failed;
|
||||
}
|
||||
|
||||
radio->stereo = !((radio->transfer_buffer)[0] & 0x01);
|
||||
mutex_unlock(&radio->lock);
|
||||
return (radio->transfer_buffer)[0];
|
||||
|
||||
usb_control_msg_failed:
|
||||
radio->stereo = -1;
|
||||
mutex_unlock(&radio->lock);
|
||||
dev_err(&radio->usbdev->dev,
|
||||
"%s - usb_control_msg returned %i, request %i\n",
|
||||
__func__, retval, request);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* return the device status. This is, in effect, just whether it
|
||||
sees a stereo signal or not. Pity. */
|
||||
static void dsbr100_getstat(struct dsbr100_device *radio)
|
||||
{
|
||||
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
|
||||
int retval;
|
||||
|
||||
mutex_lock(&radio->lock);
|
||||
|
||||
retval = usb_control_msg(radio->usbdev,
|
||||
usb_rcvctrlpipe(radio->usbdev, 0),
|
||||
USB_REQ_GET_STATUS,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
0x00 , 0x24, radio->transfer_buffer, 8, 300) < 0)
|
||||
radio->stereo = -1;
|
||||
else
|
||||
radio->stereo = !(radio->transfer_buffer[0] & 0x01);
|
||||
}
|
||||
0x00 , 0x24, radio->transfer_buffer, 8, 300);
|
||||
|
||||
if (retval < 0) {
|
||||
radio->stereo = -1;
|
||||
dev_err(&radio->usbdev->dev,
|
||||
"%s - usb_control_msg returned %i, request %i\n",
|
||||
__func__, retval, USB_REQ_GET_STATUS);
|
||||
} else {
|
||||
radio->stereo = !(radio->transfer_buffer[0] & 0x01);
|
||||
}
|
||||
|
||||
mutex_unlock(&radio->lock);
|
||||
}
|
||||
|
||||
/* USB subsystem interface begins here */
|
||||
|
||||
/* handle unplugging of the device, release data structures
|
||||
if nothing keeps us from doing it. If something is still
|
||||
keeping us busy, the release callback of v4l will take care
|
||||
of releasing it. */
|
||||
/*
|
||||
* Handle unplugging of the device.
|
||||
* We call video_unregister_device in any case.
|
||||
* The last function called in this procedure is
|
||||
* usb_dsbr100_video_device_release
|
||||
*/
|
||||
static void usb_dsbr100_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct dsbr100_device *radio = usb_get_intfdata(intf);
|
||||
|
||||
usb_set_intfdata (intf, NULL);
|
||||
if (radio) {
|
||||
video_unregister_device(radio->videodev);
|
||||
radio->videodev = NULL;
|
||||
if (radio->users) {
|
||||
kfree(radio->transfer_buffer);
|
||||
kfree(radio);
|
||||
} else {
|
||||
radio->removed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&radio->lock);
|
||||
radio->removed = 1;
|
||||
mutex_unlock(&radio->lock);
|
||||
|
||||
video_unregister_device(&radio->videodev);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -276,6 +403,10 @@ static int vidioc_g_tuner(struct file *file, void *priv,
|
|||
{
|
||||
struct dsbr100_device *radio = video_drvdata(file);
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -297,6 +428,12 @@ static int vidioc_g_tuner(struct file *file, void *priv,
|
|||
static int vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
struct dsbr100_device *radio = video_drvdata(file);
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -307,9 +444,15 @@ static int vidioc_s_frequency(struct file *file, void *priv,
|
|||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct dsbr100_device *radio = video_drvdata(file);
|
||||
int retval;
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
radio->curfreq = f->frequency;
|
||||
if (dsbr100_setfreq(radio, radio->curfreq) == -1)
|
||||
retval = dsbr100_setfreq(radio, radio->curfreq);
|
||||
if (retval < 0)
|
||||
dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -319,6 +462,10 @@ static int vidioc_g_frequency(struct file *file, void *priv,
|
|||
{
|
||||
struct dsbr100_device *radio = video_drvdata(file);
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = radio->curfreq;
|
||||
return 0;
|
||||
|
|
@ -343,6 +490,10 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
|
|||
{
|
||||
struct dsbr100_device *radio = video_drvdata(file);
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value = radio->muted;
|
||||
|
|
@ -355,17 +506,24 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
|
|||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct dsbr100_device *radio = video_drvdata(file);
|
||||
int retval;
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value) {
|
||||
if (dsbr100_stop(radio) == -1) {
|
||||
retval = dsbr100_stop(radio);
|
||||
if (retval < 0) {
|
||||
dev_warn(&radio->usbdev->dev,
|
||||
"Radio did not respond properly\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
} else {
|
||||
if (dsbr100_start(radio) == -1) {
|
||||
retval = dsbr100_start(radio);
|
||||
if (retval < 0) {
|
||||
dev_warn(&radio->usbdev->dev,
|
||||
"Radio did not respond properly\n");
|
||||
return -EBUSY;
|
||||
|
|
@ -417,7 +575,8 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file)
|
|||
radio->users = 1;
|
||||
radio->muted = 1;
|
||||
|
||||
if (dsbr100_start(radio) < 0) {
|
||||
retval = dsbr100_start(radio);
|
||||
if (retval < 0) {
|
||||
dev_warn(&radio->usbdev->dev,
|
||||
"Radio did not start up properly\n");
|
||||
radio->users = 0;
|
||||
|
|
@ -426,9 +585,9 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file)
|
|||
}
|
||||
|
||||
retval = dsbr100_setfreq(radio, radio->curfreq);
|
||||
|
||||
if (retval == -1)
|
||||
printk(KERN_WARNING KBUILD_MODNAME ": Set frequency failed\n");
|
||||
if (retval < 0)
|
||||
dev_warn(&radio->usbdev->dev,
|
||||
"set frequency failed\n");
|
||||
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
|
|
@ -437,17 +596,62 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file)
|
|||
static int usb_dsbr100_close(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dsbr100_device *radio = video_drvdata(file);
|
||||
int retval;
|
||||
|
||||
if (!radio)
|
||||
return -ENODEV;
|
||||
|
||||
radio->users = 0;
|
||||
if (radio->removed) {
|
||||
kfree(radio->transfer_buffer);
|
||||
kfree(radio);
|
||||
if (!radio->removed) {
|
||||
retval = dsbr100_stop(radio);
|
||||
if (retval < 0) {
|
||||
dev_warn(&radio->usbdev->dev,
|
||||
"dsbr100_stop failed\n");
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Suspend device - stop device. */
|
||||
static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
|
||||
{
|
||||
struct dsbr100_device *radio = usb_get_intfdata(intf);
|
||||
int retval;
|
||||
|
||||
retval = dsbr100_stop(radio);
|
||||
if (retval < 0)
|
||||
dev_warn(&intf->dev, "dsbr100_stop failed\n");
|
||||
|
||||
dev_info(&intf->dev, "going into suspend..\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Resume device - start device. */
|
||||
static int usb_dsbr100_resume(struct usb_interface *intf)
|
||||
{
|
||||
struct dsbr100_device *radio = usb_get_intfdata(intf);
|
||||
int retval;
|
||||
|
||||
retval = dsbr100_start(radio);
|
||||
if (retval < 0)
|
||||
dev_warn(&intf->dev, "dsbr100_start failed\n");
|
||||
|
||||
dev_info(&intf->dev, "coming out of suspend..\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* free data structures */
|
||||
static void usb_dsbr100_video_device_release(struct video_device *videodev)
|
||||
{
|
||||
struct dsbr100_device *radio = videodev_to_radio(videodev);
|
||||
|
||||
kfree(radio->transfer_buffer);
|
||||
kfree(radio);
|
||||
}
|
||||
|
||||
/* File system interface */
|
||||
static const struct file_operations usb_dsbr100_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
|
|
@ -476,19 +680,19 @@ static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
|
|||
};
|
||||
|
||||
/* V4L2 interface */
|
||||
static struct video_device dsbr100_videodev_template = {
|
||||
static struct video_device dsbr100_videodev_data = {
|
||||
.name = "D-Link DSB-R 100",
|
||||
.fops = &usb_dsbr100_fops,
|
||||
.ioctl_ops = &usb_dsbr100_ioctl_ops,
|
||||
.release = video_device_release,
|
||||
.release = usb_dsbr100_video_device_release,
|
||||
};
|
||||
|
||||
/* check if the device is present and register with v4l and
|
||||
usb if it is */
|
||||
/* check if the device is present and register with v4l and usb if it is */
|
||||
static int usb_dsbr100_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct dsbr100_device *radio;
|
||||
int retval;
|
||||
|
||||
radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL);
|
||||
|
||||
|
|
@ -501,23 +705,18 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
|
|||
kfree(radio);
|
||||
return -ENOMEM;
|
||||
}
|
||||
radio->videodev = video_device_alloc();
|
||||
|
||||
if (!(radio->videodev)) {
|
||||
kfree(radio->transfer_buffer);
|
||||
kfree(radio);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy(radio->videodev, &dsbr100_videodev_template,
|
||||
sizeof(dsbr100_videodev_template));
|
||||
mutex_init(&radio->lock);
|
||||
radio->videodev = dsbr100_videodev_data;
|
||||
|
||||
radio->removed = 0;
|
||||
radio->users = 0;
|
||||
radio->usbdev = interface_to_usbdev(intf);
|
||||
radio->curfreq = FREQ_MIN * FREQ_MUL;
|
||||
video_set_drvdata(radio->videodev, radio);
|
||||
if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr) < 0) {
|
||||
dev_warn(&intf->dev, "Could not register video device\n");
|
||||
video_device_release(radio->videodev);
|
||||
video_set_drvdata(&radio->videodev, radio);
|
||||
retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr);
|
||||
if (retval < 0) {
|
||||
dev_err(&intf->dev, "couldn't register video device\n");
|
||||
kfree(radio->transfer_buffer);
|
||||
kfree(radio);
|
||||
return -EIO;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* radiotrack (radioreveal) driver for Linux radio support
|
||||
* (c) 1997 M. Kirkwood
|
||||
* Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
|
||||
* Converted to new API by Alan Cox <Alan.Cox@linux.org>
|
||||
* Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
|
||||
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
|
||||
*
|
||||
* History:
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
* 2002-01-17 Adam Belay <ambx1@neo.rr.com>
|
||||
* Updated to latest pnp code
|
||||
*
|
||||
* 2003-01-31 Alan Cox <alan@redhat.com>
|
||||
* 2003-01-31 Alan Cox <alan@lxorguk.ukuu.org.uk>
|
||||
* Cleaned up locking, delay code, general odds and ends
|
||||
*
|
||||
* 2006-07-30 Hans J. Koch <koch@hjk-az.de>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
|
||||
*
|
||||
* Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
|
||||
* Converted to new API by Alan Cox <Alan.Cox@linux.org>
|
||||
* Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
|
||||
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
|
||||
*
|
||||
* TODO: Allow for more than one of these foolish entities :-)
|
||||
|
|
|
|||
|
|
@ -72,6 +72,11 @@ MODULE_LICENSE("GPL");
|
|||
#define USB_AMRADIO_VENDOR 0x07ca
|
||||
#define USB_AMRADIO_PRODUCT 0xb800
|
||||
|
||||
/* dev_warn macro with driver name */
|
||||
#define MR800_DRIVER_NAME "radio-mr800"
|
||||
#define amradio_dev_warn(dev, fmt, arg...) \
|
||||
dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg)
|
||||
|
||||
/* Probably USB_TIMEOUT should be modified in module parameter */
|
||||
#define BUFFER_LENGTH 8
|
||||
#define USB_TIMEOUT 500
|
||||
|
|
@ -154,14 +159,14 @@ MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
|
|||
|
||||
/* USB subsystem interface */
|
||||
static struct usb_driver usb_amradio_driver = {
|
||||
.name = "radio-mr800",
|
||||
.name = MR800_DRIVER_NAME,
|
||||
.probe = usb_amradio_probe,
|
||||
.disconnect = usb_amradio_disconnect,
|
||||
.suspend = usb_amradio_suspend,
|
||||
.resume = usb_amradio_resume,
|
||||
.reset_resume = usb_amradio_resume,
|
||||
.id_table = usb_amradio_device_table,
|
||||
.supports_autosuspend = 1,
|
||||
.supports_autosuspend = 0,
|
||||
};
|
||||
|
||||
/* switch on radio. Send 8 bytes to device. */
|
||||
|
|
@ -202,6 +207,10 @@ static int amradio_stop(struct amradio_device *radio)
|
|||
int retval;
|
||||
int size;
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
mutex_lock(&radio->lock);
|
||||
|
||||
radio->buffer[0] = 0x00;
|
||||
|
|
@ -235,6 +244,10 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
|
|||
int size;
|
||||
unsigned short freq_send = 0x13 + (freq >> 3) / 25;
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
mutex_lock(&radio->lock);
|
||||
|
||||
radio->buffer[0] = 0x00;
|
||||
|
|
@ -288,18 +301,12 @@ static void usb_amradio_disconnect(struct usb_interface *intf)
|
|||
{
|
||||
struct amradio_device *radio = usb_get_intfdata(intf);
|
||||
|
||||
usb_set_intfdata(intf, NULL);
|
||||
mutex_lock(&radio->lock);
|
||||
radio->removed = 1;
|
||||
mutex_unlock(&radio->lock);
|
||||
|
||||
if (radio) {
|
||||
video_unregister_device(radio->videodev);
|
||||
radio->videodev = NULL;
|
||||
if (radio->users) {
|
||||
kfree(radio->buffer);
|
||||
kfree(radio);
|
||||
} else {
|
||||
radio->removed = 1;
|
||||
}
|
||||
}
|
||||
usb_set_intfdata(intf, NULL);
|
||||
video_unregister_device(radio->videodev);
|
||||
}
|
||||
|
||||
/* vidioc_querycap - query device capabilities */
|
||||
|
|
@ -320,6 +327,10 @@ static int vidioc_g_tuner(struct file *file, void *priv,
|
|||
{
|
||||
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -346,6 +357,12 @@ static int vidioc_g_tuner(struct file *file, void *priv,
|
|||
static int vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
|
|
@ -357,9 +374,14 @@ static int vidioc_s_frequency(struct file *file, void *priv,
|
|||
{
|
||||
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
radio->curfreq = f->frequency;
|
||||
if (amradio_setfreq(radio, radio->curfreq) < 0)
|
||||
warn("Set frequency failed");
|
||||
amradio_dev_warn(&radio->videodev->dev,
|
||||
"set frequency failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -369,6 +391,10 @@ static int vidioc_g_frequency(struct file *file, void *priv,
|
|||
{
|
||||
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = radio->curfreq;
|
||||
return 0;
|
||||
|
|
@ -382,8 +408,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
|
|||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -396,6 +421,10 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
|
|||
{
|
||||
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value = radio->muted;
|
||||
|
|
@ -410,16 +439,22 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
|
|||
{
|
||||
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value) {
|
||||
if (amradio_stop(radio) < 0) {
|
||||
warn("amradio_stop() failed");
|
||||
amradio_dev_warn(&radio->videodev->dev,
|
||||
"amradio_stop failed\n");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (amradio_start(radio) < 0) {
|
||||
warn("amradio_start() failed");
|
||||
amradio_dev_warn(&radio->videodev->dev,
|
||||
"amradio_start failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -475,30 +510,38 @@ static int usb_amradio_open(struct inode *inode, struct file *file)
|
|||
radio->muted = 1;
|
||||
|
||||
if (amradio_start(radio) < 0) {
|
||||
warn("Radio did not start up properly");
|
||||
amradio_dev_warn(&radio->videodev->dev,
|
||||
"radio did not start up properly\n");
|
||||
radio->users = 0;
|
||||
unlock_kernel();
|
||||
return -EIO;
|
||||
}
|
||||
if (amradio_setfreq(radio, radio->curfreq) < 0)
|
||||
warn("Set frequency failed");
|
||||
amradio_dev_warn(&radio->videodev->dev,
|
||||
"set frequency failed\n");
|
||||
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*close device - free driver structures */
|
||||
/*close device */
|
||||
static int usb_amradio_close(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
|
||||
int retval;
|
||||
|
||||
if (!radio)
|
||||
return -ENODEV;
|
||||
|
||||
radio->users = 0;
|
||||
if (radio->removed) {
|
||||
kfree(radio->buffer);
|
||||
kfree(radio);
|
||||
|
||||
if (!radio->removed) {
|
||||
retval = amradio_stop(radio);
|
||||
if (retval < 0)
|
||||
amradio_dev_warn(&radio->videodev->dev,
|
||||
"amradio_stop failed\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -508,9 +551,9 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
|
|||
struct amradio_device *radio = usb_get_intfdata(intf);
|
||||
|
||||
if (amradio_stop(radio) < 0)
|
||||
warn("amradio_stop() failed");
|
||||
dev_warn(&intf->dev, "amradio_stop failed\n");
|
||||
|
||||
info("radio-mr800: Going into suspend..");
|
||||
dev_info(&intf->dev, "going into suspend..\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -521,9 +564,9 @@ static int usb_amradio_resume(struct usb_interface *intf)
|
|||
struct amradio_device *radio = usb_get_intfdata(intf);
|
||||
|
||||
if (amradio_start(radio) < 0)
|
||||
warn("amradio_start() failed");
|
||||
dev_warn(&intf->dev, "amradio_start failed\n");
|
||||
|
||||
info("radio-mr800: Coming out of suspend..");
|
||||
dev_info(&intf->dev, "coming out of suspend..\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -555,12 +598,24 @@ static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
|
|||
.vidioc_s_input = vidioc_s_input,
|
||||
};
|
||||
|
||||
static void usb_amradio_device_release(struct video_device *videodev)
|
||||
{
|
||||
struct amradio_device *radio = video_get_drvdata(videodev);
|
||||
|
||||
/* we call v4l to free radio->videodev */
|
||||
video_device_release(videodev);
|
||||
|
||||
/* free rest memory */
|
||||
kfree(radio->buffer);
|
||||
kfree(radio);
|
||||
}
|
||||
|
||||
/* V4L2 interface */
|
||||
static struct video_device amradio_videodev_template = {
|
||||
.name = "AverMedia MR 800 USB FM Radio",
|
||||
.fops = &usb_amradio_fops,
|
||||
.ioctl_ops = &usb_amradio_ioctl_ops,
|
||||
.release = video_device_release,
|
||||
.release = usb_amradio_device_release,
|
||||
};
|
||||
|
||||
/* check if the device is present and register with v4l and
|
||||
|
|
@ -602,7 +657,7 @@ static int usb_amradio_probe(struct usb_interface *intf,
|
|||
|
||||
video_set_drvdata(radio->videodev, radio);
|
||||
if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
|
||||
warn("Could not register video device");
|
||||
dev_warn(&intf->dev, "could not register video device\n");
|
||||
video_device_release(radio->videodev);
|
||||
kfree(radio->buffer);
|
||||
kfree(radio);
|
||||
|
|
@ -617,9 +672,13 @@ static int __init amradio_init(void)
|
|||
{
|
||||
int retval = usb_register(&usb_amradio_driver);
|
||||
|
||||
info(DRIVER_VERSION " " DRIVER_DESC);
|
||||
pr_info(KBUILD_MODNAME
|
||||
": version " DRIVER_VERSION " " DRIVER_DESC "\n");
|
||||
|
||||
if (retval)
|
||||
err("usb_register failed. Error number %d", retval);
|
||||
pr_err(KBUILD_MODNAME
|
||||
": usb_register failed. Error number %d\n", retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
|
||||
*
|
||||
* Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
|
||||
* Converted to new API by Alan Cox <Alan.Cox@linux.org>
|
||||
* Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
|
||||
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
|
||||
*
|
||||
* TODO: Allow for more than one of these foolish entities :-)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* (c) 1997 M. Kirkwood
|
||||
* (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz
|
||||
*
|
||||
* Fitted to new interface by Alan Cox <alan.cox@linux.org>
|
||||
* Fitted to new interface by Alan Cox <alan@lxorguk.ukuu.org.uk>
|
||||
* Made working and cleaned up functions <mikael.hedin@irf.se>
|
||||
* Support for ISAPnP by Ladislav Michl <ladis@psi.cz>
|
||||
*
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ config VIDEO_MSP3400
|
|||
|
||||
config VIDEO_CS5345
|
||||
tristate "Cirrus Logic CS5345 audio ADC"
|
||||
depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
---help---
|
||||
Support for the Cirrus Logic CS5345 24-bit, 192 kHz
|
||||
stereo A/D converter.
|
||||
|
|
@ -204,7 +204,7 @@ config VIDEO_CS53L32A
|
|||
|
||||
config VIDEO_M52790
|
||||
tristate "Mitsubishi M52790 A/V switch"
|
||||
depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
---help---
|
||||
Support for the Mitsubishi M52790 A/V switch.
|
||||
|
||||
|
|
@ -242,7 +242,7 @@ config VIDEO_WM8739
|
|||
|
||||
config VIDEO_VP27SMPX
|
||||
tristate "Panasonic VP27s internal MPX"
|
||||
depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
---help---
|
||||
Support for the internal MPX of the Panasonic VP27s tuner.
|
||||
|
||||
|
|
@ -361,6 +361,17 @@ config VIDEO_SAA7191
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called saa7191.
|
||||
|
||||
config VIDEO_TVP514X
|
||||
tristate "Texas Instruments TVP514x video decoder"
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
---help---
|
||||
This is a Video4Linux2 sensor-level driver for the TI TVP5146/47
|
||||
decoder. It is currently working with the TI OMAP3 camera
|
||||
controller.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tvp514x.
|
||||
|
||||
config VIDEO_TVP5150
|
||||
tristate "Texas Instruments TVP5150 video decoder"
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
|
|
@ -387,7 +398,7 @@ comment "MPEG video encoders"
|
|||
|
||||
config VIDEO_CX2341X
|
||||
tristate "Conexant CX2341x MPEG encoders"
|
||||
depends on VIDEO_V4L2 && EXPERIMENTAL && VIDEO_V4L2_COMMON
|
||||
depends on VIDEO_V4L2 && VIDEO_V4L2_COMMON
|
||||
---help---
|
||||
Support for the Conexant CX23416 MPEG encoders
|
||||
and CX23415 MPEG encoder/decoders.
|
||||
|
|
@ -725,10 +736,16 @@ config MT9M001_PCA9536_SWITCH
|
|||
extender to switch between 8 and 10 bit datawidth modes
|
||||
|
||||
config SOC_CAMERA_MT9M111
|
||||
tristate "mt9m111 support"
|
||||
tristate "mt9m111 and mt9m112 support"
|
||||
depends on SOC_CAMERA && I2C
|
||||
help
|
||||
This driver supports MT9M111 cameras from Micron
|
||||
This driver supports MT9M111 and MT9M112 cameras from Micron
|
||||
|
||||
config SOC_CAMERA_MT9T031
|
||||
tristate "mt9t031 support"
|
||||
depends on SOC_CAMERA && I2C
|
||||
help
|
||||
This driver supports MT9T031 cameras from Micron.
|
||||
|
||||
config SOC_CAMERA_MT9V022
|
||||
tristate "mt9v022 support"
|
||||
|
|
@ -744,12 +761,24 @@ config MT9V022_PCA9536_SWITCH
|
|||
Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
|
||||
extender to switch between 8 and 10 bit datawidth modes
|
||||
|
||||
config SOC_CAMERA_TW9910
|
||||
tristate "tw9910 support"
|
||||
depends on SOC_CAMERA && I2C
|
||||
help
|
||||
This is a tw9910 video driver
|
||||
|
||||
config SOC_CAMERA_PLATFORM
|
||||
tristate "platform camera support"
|
||||
depends on SOC_CAMERA
|
||||
help
|
||||
This is a generic SoC camera platform driver, useful for testing
|
||||
|
||||
config SOC_CAMERA_OV772X
|
||||
tristate "ov772x camera support"
|
||||
depends on SOC_CAMERA && I2C
|
||||
help
|
||||
This is a ov772x camera driver
|
||||
|
||||
config VIDEO_PXA27x
|
||||
tristate "PXA27x Quick Capture Interface driver"
|
||||
depends on VIDEO_DEV && PXA27x && SOC_CAMERA
|
||||
|
|
@ -764,6 +793,13 @@ config VIDEO_SH_MOBILE_CEU
|
|||
---help---
|
||||
This is a v4l2 driver for the SuperH Mobile CEU Interface
|
||||
|
||||
config VIDEO_OMAP2
|
||||
tristate "OMAP2 Camera Capture Interface driver"
|
||||
depends on VIDEO_DEV && ARCH_OMAP2
|
||||
select VIDEOBUF_DMA_SG
|
||||
---help---
|
||||
This is a v4l2 driver for the TI OMAP2 camera capture interface
|
||||
|
||||
#
|
||||
# USB Multimedia device configuration
|
||||
#
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@ msp3400-objs := msp3400-driver.o msp3400-kthreads.o
|
|||
|
||||
stkwebcam-objs := stk-webcam.o stk-sensor.o
|
||||
|
||||
videodev-objs := v4l2-dev.o v4l2-ioctl.o
|
||||
omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_DEV) += videodev.o compat_ioctl32.o v4l2-int-device.o
|
||||
videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-subdev.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-compat-ioctl32.o v4l2-int-device.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o
|
||||
|
||||
|
|
@ -25,6 +27,7 @@ obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
|
|||
obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
|
||||
obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
|
||||
obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
|
||||
obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
|
||||
obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
|
||||
|
|
@ -66,6 +69,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/
|
|||
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
|
||||
obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
|
||||
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
|
||||
obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
|
||||
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
|
||||
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
|
||||
obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
|
||||
|
|
@ -129,11 +133,15 @@ obj-$(CONFIG_VIDEO_CX23885) += cx23885/
|
|||
|
||||
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
|
||||
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
|
||||
obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o
|
||||
obj-$(CONFIG_SOC_CAMERA) += soc_camera.o
|
||||
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
|
||||
obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
|
||||
obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
|
||||
obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
|
||||
obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o
|
||||
obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o
|
||||
obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_AU0828) += au0828/
|
||||
|
||||
|
|
|
|||
|
|
@ -396,8 +396,7 @@ out_up:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ar_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
static int ar_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct ar_device *ar = video_get_drvdata(dev);
|
||||
|
|
@ -543,7 +542,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file,
|
|||
static int ar_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
return video_usercopy(inode, file, cmd, arg, ar_do_ioctl);
|
||||
return video_usercopy(file, cmd, arg, ar_do_ioctl);
|
||||
}
|
||||
|
||||
#if USE_INT
|
||||
|
|
|
|||
|
|
@ -1,274 +0,0 @@
|
|||
/* Driver for Bt832 CMOS Camera Video Processor
|
||||
i2c-addresses: 0x88 or 0x8a
|
||||
|
||||
The BT832 interfaces to a Quartzsight Digital Camera (352x288, 25 or 30 fps)
|
||||
via a 9 pin connector ( 4-wire SDATA, 2-wire i2c, SCLK, VCC, GND).
|
||||
It outputs an 8-bit 4:2:2 YUV or YCrCb video signal which can be directly
|
||||
connected to bt848/bt878 GPIO pins on this purpose.
|
||||
(see: VLSI Vision Ltd. www.vvl.co.uk for camera datasheets)
|
||||
|
||||
Supported Cards:
|
||||
- Pixelview Rev.4E: 0x8a
|
||||
GPIO 0x400000 toggles Bt832 RESET, and the chip changes to i2c 0x88 !
|
||||
|
||||
(c) Gunther Mayer, 2002
|
||||
|
||||
STATUS:
|
||||
- detect chip and hexdump
|
||||
- reset chip and leave low power mode
|
||||
- detect camera present
|
||||
|
||||
TODO:
|
||||
- make it work (find correct setup for Bt832 and Bt878)
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/videodev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <media/v4l2-common.h>
|
||||
|
||||
#include "bttv.h"
|
||||
#include "bt832.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = { I2C_ADDR_BT832_ALT1>>1, I2C_ADDR_BT832_ALT2>>1,
|
||||
I2C_CLIENT_END };
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
int debug; /* debug output */
|
||||
module_param(debug, int, 0644);
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static int bt832_detach(struct i2c_client *client);
|
||||
|
||||
|
||||
static struct i2c_driver driver;
|
||||
static struct i2c_client client_template;
|
||||
|
||||
struct bt832 {
|
||||
struct i2c_client client;
|
||||
};
|
||||
|
||||
int bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf)
|
||||
{
|
||||
int i,rc;
|
||||
buf[0]=0x80; // start at register 0 with auto-increment
|
||||
if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
|
||||
v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 1)\n",rc);
|
||||
|
||||
for(i=0;i<65;i++)
|
||||
buf[i]=0;
|
||||
if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
|
||||
v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 65)\n",rc);
|
||||
|
||||
// Note: On READ the first byte is the current index
|
||||
// (e.g. 0x80, what we just wrote)
|
||||
|
||||
if(debug>1) {
|
||||
int i;
|
||||
v4l_dbg(2, debug,i2c_client_s,"hexdump:");
|
||||
for(i=1;i<65;i++) {
|
||||
if(i!=1) {
|
||||
if(((i-1)%8)==0) printk(" ");
|
||||
if(((i-1)%16)==0) {
|
||||
printk("\n");
|
||||
v4l_dbg(2, debug,i2c_client_s,"hexdump:");
|
||||
}
|
||||
}
|
||||
printk(" %02x",buf[i]);
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return: 1 (is a bt832), 0 (No bt832 here)
|
||||
int bt832_init(struct i2c_client *i2c_client_s)
|
||||
{
|
||||
unsigned char *buf;
|
||||
int rc;
|
||||
|
||||
buf=kmalloc(65,GFP_KERNEL);
|
||||
if (!buf) {
|
||||
v4l_err(&t->client,
|
||||
"Unable to allocate memory. Detaching.\n");
|
||||
return 0;
|
||||
}
|
||||
bt832_hexdump(i2c_client_s,buf);
|
||||
|
||||
if(buf[0x40] != 0x31) {
|
||||
v4l_err(i2c_client_s,"This i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
|
||||
kfree(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
v4l_err(i2c_client_s,"Write 0 tp VPSTATUS\n");
|
||||
buf[0]=BT832_VP_STATUS; // Reg.52
|
||||
buf[1]= 0x00;
|
||||
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
|
||||
v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
|
||||
|
||||
bt832_hexdump(i2c_client_s,buf);
|
||||
|
||||
|
||||
// Leave low power mode:
|
||||
v4l_err(i2c_client_s,"leave low power mode.\n");
|
||||
buf[0]=BT832_CAM_SETUP0; //0x39 57
|
||||
buf[1]=0x08;
|
||||
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
|
||||
v4l_err(i2c_client_s,"i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
|
||||
|
||||
bt832_hexdump(i2c_client_s,buf);
|
||||
|
||||
v4l_info(i2c_client_s,"Write 0 tp VPSTATUS\n");
|
||||
buf[0]=BT832_VP_STATUS; // Reg.52
|
||||
buf[1]= 0x00;
|
||||
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
|
||||
v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
|
||||
|
||||
bt832_hexdump(i2c_client_s,buf);
|
||||
|
||||
|
||||
// Enable Output
|
||||
v4l_info(i2c_client_s,"Enable Output\n");
|
||||
buf[0]=BT832_VP_CONTROL1; // Reg.40
|
||||
buf[1]= 0x27 & (~0x01); // Default | !skip
|
||||
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
|
||||
v4l_err(i2c_client_s,"i2c i/o error EO: rc == %d (should be 2)\n",rc);
|
||||
|
||||
bt832_hexdump(i2c_client_s,buf);
|
||||
|
||||
|
||||
// for testing (even works when no camera attached)
|
||||
v4l_info(i2c_client_s,"*** Generate NTSC M Bars *****\n");
|
||||
buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
|
||||
buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
|
||||
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
|
||||
v4l_info(i2c_client_s,"i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
|
||||
|
||||
v4l_info(i2c_client_s,"Camera Present: %s\n",
|
||||
(buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");
|
||||
|
||||
bt832_hexdump(i2c_client_s,buf);
|
||||
kfree(buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
|
||||
{
|
||||
struct bt832 *t;
|
||||
|
||||
client_template.adapter = adap;
|
||||
client_template.addr = addr;
|
||||
|
||||
if (NULL == (t = kzalloc(sizeof(*t), GFP_KERNEL)))
|
||||
return -ENOMEM;
|
||||
t->client = client_template;
|
||||
i2c_set_clientdata(&t->client, t);
|
||||
i2c_attach_client(&t->client);
|
||||
|
||||
v4l_info(&t->client,"chip found @ 0x%x\n", addr<<1);
|
||||
|
||||
if(! bt832_init(&t->client)) {
|
||||
bt832_detach(&t->client);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt832_probe(struct i2c_adapter *adap)
|
||||
{
|
||||
if (adap->class & I2C_CLASS_TV_ANALOG)
|
||||
return i2c_probe(adap, &addr_data, bt832_attach);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt832_detach(struct i2c_client *client)
|
||||
{
|
||||
struct bt832 *t = i2c_get_clientdata(client);
|
||||
|
||||
v4l_info(&t->client,"dettach\n");
|
||||
i2c_detach_client(client);
|
||||
kfree(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
|
||||
{
|
||||
struct bt832 *t = i2c_get_clientdata(client);
|
||||
|
||||
if (debug>1)
|
||||
v4l_i2c_print_ioctl(&t->client,cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case BT832_HEXDUMP: {
|
||||
unsigned char *buf;
|
||||
buf = kmalloc(65, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
v4l_err(&t->client,
|
||||
"Unable to allocate memory\n");
|
||||
break;
|
||||
}
|
||||
bt832_hexdump(&t->client,buf);
|
||||
kfree(buf);
|
||||
}
|
||||
break;
|
||||
case BT832_REATTACH:
|
||||
v4l_info(&t->client,"re-attach\n");
|
||||
i2c_del_driver(&driver);
|
||||
i2c_add_driver(&driver);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static struct i2c_driver driver = {
|
||||
.driver = {
|
||||
.name = "bt832",
|
||||
},
|
||||
.id = 0, /* FIXME */
|
||||
.attach_adapter = bt832_probe,
|
||||
.detach_client = bt832_detach,
|
||||
.command = bt832_command,
|
||||
};
|
||||
static struct i2c_client client_template =
|
||||
{
|
||||
.name = "bt832",
|
||||
.driver = &driver,
|
||||
};
|
||||
|
||||
|
||||
static int __init bt832_init_module(void)
|
||||
{
|
||||
return i2c_add_driver(&driver);
|
||||
}
|
||||
|
||||
static void __exit bt832_cleanup_module(void)
|
||||
{
|
||||
i2c_del_driver(&driver);
|
||||
}
|
||||
|
||||
module_init(bt832_init_module);
|
||||
module_exit(bt832_cleanup_module);
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
|
|
@ -1,305 +0,0 @@
|
|||
/* Bt832 CMOS Camera Video Processor (VP)
|
||||
|
||||
The Bt832 CMOS Camera Video Processor chip connects a Quartsight CMOS
|
||||
color digital camera directly to video capture devices via an 8-bit,
|
||||
4:2:2 YUV or YCrCb video interface.
|
||||
|
||||
i2c addresses: 0x88 or 0x8a
|
||||
*/
|
||||
|
||||
/* The 64 registers: */
|
||||
|
||||
// Input Processor
|
||||
#define BT832_OFFSET 0
|
||||
#define BT832_RCOMP 1
|
||||
#define BT832_G1COMP 2
|
||||
#define BT832_G2COMP 3
|
||||
#define BT832_BCOMP 4
|
||||
// Exposures:
|
||||
#define BT832_FINEH 5
|
||||
#define BT832_FINEL 6
|
||||
#define BT832_COARSEH 7
|
||||
#define BT832_COARSEL 8
|
||||
#define BT832_CAMGAIN 9
|
||||
// Main Processor:
|
||||
#define BT832_M00 10
|
||||
#define BT832_M01 11
|
||||
#define BT832_M02 12
|
||||
#define BT832_M10 13
|
||||
#define BT832_M11 14
|
||||
#define BT832_M12 15
|
||||
#define BT832_M20 16
|
||||
#define BT832_M21 17
|
||||
#define BT832_M22 18
|
||||
#define BT832_APCOR 19
|
||||
#define BT832_GAMCOR 20
|
||||
// Level Accumulator Inputs
|
||||
#define BT832_VPCONTROL2 21
|
||||
#define BT832_ZONECODE0 22
|
||||
#define BT832_ZONECODE1 23
|
||||
#define BT832_ZONECODE2 24
|
||||
#define BT832_ZONECODE3 25
|
||||
// Level Accumulator Outputs:
|
||||
#define BT832_RACC 26
|
||||
#define BT832_GACC 27
|
||||
#define BT832_BACC 28
|
||||
#define BT832_BLACKACC 29
|
||||
#define BT832_EXP_AGC 30
|
||||
#define BT832_LACC0 31
|
||||
#define BT832_LACC1 32
|
||||
#define BT832_LACC2 33
|
||||
#define BT832_LACC3 34
|
||||
#define BT832_LACC4 35
|
||||
#define BT832_LACC5 36
|
||||
#define BT832_LACC6 37
|
||||
#define BT832_LACC7 38
|
||||
// System:
|
||||
#define BT832_VP_CONTROL0 39
|
||||
#define BT832_VP_CONTROL1 40
|
||||
#define BT832_THRESH 41
|
||||
#define BT832_VP_TESTCONTROL0 42
|
||||
#define BT832_VP_DMCODE 43
|
||||
#define BT832_ACB_CONFIG 44
|
||||
#define BT832_ACB_GNBASE 45
|
||||
#define BT832_ACB_MU 46
|
||||
#define BT832_CAM_TEST0 47
|
||||
#define BT832_AEC_CONFIG 48
|
||||
#define BT832_AEC_TL 49
|
||||
#define BT832_AEC_TC 50
|
||||
#define BT832_AEC_TH 51
|
||||
// Status:
|
||||
#define BT832_VP_STATUS 52
|
||||
#define BT832_VP_LINECOUNT 53
|
||||
#define BT832_CAM_DEVICEL 54 // e.g. 0x19
|
||||
#define BT832_CAM_DEVICEH 55 // e.g. 0x40 == 0x194 Mask0, 0x194 = 404 decimal (VVL-404 camera)
|
||||
#define BT832_CAM_STATUS 56
|
||||
#define BT832_56_CAMERA_PRESENT 0x20
|
||||
//Camera Setups:
|
||||
#define BT832_CAM_SETUP0 57
|
||||
#define BT832_CAM_SETUP1 58
|
||||
#define BT832_CAM_SETUP2 59
|
||||
#define BT832_CAM_SETUP3 60
|
||||
// System:
|
||||
#define BT832_DEFCOR 61
|
||||
#define BT832_VP_TESTCONTROL1 62
|
||||
#define BT832_DEVICE_ID 63
|
||||
# define BT832_DEVICE_ID__31 0x31 // Bt832 has ID 0x31
|
||||
|
||||
/* STMicroelectronivcs VV5404 camera module
|
||||
i2c: 0x20: sensor address
|
||||
i2c: 0xa0: eeprom for ccd defect map
|
||||
*/
|
||||
#define VV5404_device_h 0x00 // 0x19
|
||||
#define VV5404_device_l 0x01 // 0x40
|
||||
#define VV5404_status0 0x02
|
||||
#define VV5404_linecountc 0x03 // current line counter
|
||||
#define VV5404_linecountl 0x04
|
||||
#define VV5404_setup0 0x10
|
||||
#define VV5404_setup1 0x11
|
||||
#define VV5404_setup2 0x12
|
||||
#define VV5404_setup4 0x14
|
||||
#define VV5404_setup5 0x15
|
||||
#define VV5404_fine_h 0x20 // fine exposure
|
||||
#define VV5404_fine_l 0x21
|
||||
#define VV5404_coarse_h 0x22 //coarse exposure
|
||||
#define VV5404_coarse_l 0x23
|
||||
#define VV5404_gain 0x24 // ADC pre-amp gain setting
|
||||
#define VV5404_clk_div 0x25
|
||||
#define VV5404_cr 0x76 // control register
|
||||
#define VV5404_as0 0x77 // ADC setup register
|
||||
|
||||
|
||||
// IOCTL
|
||||
#define BT832_HEXDUMP _IOR('b',1,int)
|
||||
#define BT832_REATTACH _IOR('b',2,int)
|
||||
|
||||
/* from BT8x8VXD/capdrv/dialogs.cpp */
|
||||
|
||||
/*
|
||||
typedef enum { SVI, Logitech, Rockwell } CAMERA;
|
||||
|
||||
static COMBOBOX_ENTRY gwCameraOptions[] =
|
||||
{
|
||||
{ SVI, "Silicon Vision 512N" },
|
||||
{ Logitech, "Logitech VideoMan 1.3" },
|
||||
{ Rockwell, "Rockwell QuartzSight PCI 1.0" }
|
||||
};
|
||||
|
||||
// SRAM table values
|
||||
//===========================================================================
|
||||
typedef enum { TGB_NTSC624, TGB_NTSC780, TGB_NTSC858, TGB_NTSC392 } TimeGenByte;
|
||||
|
||||
BYTE SRAMTable[][ 60 ] =
|
||||
{
|
||||
// TGB_NTSC624
|
||||
{
|
||||
0x33, // size of table = 51
|
||||
0x0E, 0xC0, 0x00, 0x00, 0x90, 0x02, 0x03, 0x10, 0x03, 0x06,
|
||||
0x10, 0x04, 0x12, 0x12, 0x05, 0x02, 0x13, 0x04, 0x19, 0x00,
|
||||
0x04, 0x39, 0x00, 0x06, 0x59, 0x08, 0x03, 0x85, 0x08, 0x07,
|
||||
0x03, 0x50, 0x00, 0x91, 0x40, 0x00, 0x11, 0x01, 0x01, 0x4D,
|
||||
0x0D, 0x02, 0x03, 0x11, 0x01, 0x05, 0x37, 0x00, 0x37, 0x21, 0x00
|
||||
},
|
||||
// TGB_NTSC780
|
||||
{
|
||||
0x33, // size of table = 51
|
||||
0x0e, 0xc0, 0x00, 0x00, 0x90, 0xe2, 0x03, 0x10, 0x03, 0x06,
|
||||
0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
|
||||
0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x85, 0x08, 0x97,
|
||||
0x03, 0x50, 0x50, 0xaf, 0x40, 0x30, 0x5f, 0x01, 0xf1, 0x7f,
|
||||
0x0d, 0xf2, 0x03, 0x11, 0xf1, 0x05, 0x37, 0x30, 0x85, 0x21, 0x50
|
||||
},
|
||||
// TGB_NTSC858
|
||||
{
|
||||
0x33, // size of table = 51
|
||||
0x0c, 0xc0, 0x00, 0x00, 0x90, 0xc2, 0x03, 0x10, 0x03, 0x06,
|
||||
0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
|
||||
0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x83, 0x08, 0x97,
|
||||
0x03, 0x50, 0x30, 0xc0, 0x40, 0x30, 0x86, 0x01, 0x01, 0xa6,
|
||||
0x0d, 0x62, 0x03, 0x11, 0x61, 0x05, 0x37, 0x30, 0xac, 0x21, 0x50
|
||||
},
|
||||
// TGB_NTSC392
|
||||
// This table has been modified to be used for Fusion Rev D
|
||||
{
|
||||
0x2A, // size of table = 42
|
||||
0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
|
||||
0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
|
||||
0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
|
||||
0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
|
||||
0x20, 0x00
|
||||
}
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
// This is the structure of the camera specifications
|
||||
//===========================================================================
|
||||
typedef struct tag_cameraSpec
|
||||
{
|
||||
SignalFormat signal; // which digital signal format the camera has
|
||||
VideoFormat vidFormat; // video standard
|
||||
SyncVideoRef syncRef; // which sync video reference is used
|
||||
State syncOutput; // enable sync output for sync video input?
|
||||
DecInputClk iClk; // which input clock is used
|
||||
TimeGenByte tgb; // which timing generator byte does the camera use
|
||||
int HReset; // select 64, 48, 32, or 16 CLKx1 for HReset
|
||||
PLLFreq pllFreq; // what synthesized frequency to set PLL to
|
||||
VSIZEPARMS vSize; // video size the camera produces
|
||||
int lineCount; // expected total number of half-line per frame - 1
|
||||
BOOL interlace; // interlace signal?
|
||||
} CameraSpec;
|
||||
|
||||
//===========================================================================
|
||||
// <UPDATE REQUIRED>
|
||||
// Camera specifications database. Update this table whenever camera spec
|
||||
// has been changed or added/deleted supported camera models
|
||||
//===========================================================================
|
||||
static CameraSpec dbCameraSpec[ N_CAMERAOPTIONS ] =
|
||||
{ // Silicon Vision 512N
|
||||
{ Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC624, 64, KHz19636,
|
||||
// Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
|
||||
{ 512, 0x64, 480, 0x13, 240 }, 0, TRUE
|
||||
},
|
||||
// Logitech VideoMan 1.3
|
||||
{ Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC780, 64, KHz24545,
|
||||
// Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
|
||||
{ 640, 0x80, 480, 0x1A, 240 }, 0, TRUE
|
||||
},
|
||||
// Rockwell QuartzSight
|
||||
// Note: Fusion Rev D (rev ID 0x02) and later supports 16 pixels for HReset which is preferable.
|
||||
// Use 32 for earlier version of hardware. Clkx1_HDELAY also changed from 0x27 to 0x20.
|
||||
{ Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC392, 16, KHz28636,
|
||||
// Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
|
||||
{ 352, 0x20, 576, 0x08, 288 }, 607, FALSE
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
/*
|
||||
The corresponding APIs required to be invoked are:
|
||||
SetConnector( ConCamera, TRUE/FALSE );
|
||||
SetSignalFormat( spec.signal );
|
||||
SetVideoFormat( spec.vidFormat );
|
||||
SetSyncVideoRef( spec.syncRef );
|
||||
SetEnableSyncOutput( spec.syncOutput );
|
||||
SetTimGenByte( SRAMTable[ spec.tgb ], SRAMTableSize[ spec.tgb ] );
|
||||
SetHReset( spec.HReset );
|
||||
SetPLL( spec.pllFreq );
|
||||
SetDecInputClock( spec.iClk );
|
||||
SetVideoInfo( spec.vSize );
|
||||
SetTotalLineCount( spec.lineCount );
|
||||
SetInterlaceMode( spec.interlace );
|
||||
*/
|
||||
|
||||
/* from web:
|
||||
Video Sampling
|
||||
Digital video is a sampled form of analog video. The most common sampling schemes in use today are:
|
||||
Pixel Clock Horiz Horiz Vert
|
||||
Rate Total Active
|
||||
NTSC square pixel 12.27 MHz 780 640 525
|
||||
NTSC CCIR-601 13.5 MHz 858 720 525
|
||||
NTSC 4FSc 14.32 MHz 910 768 525
|
||||
PAL square pixel 14.75 MHz 944 768 625
|
||||
PAL CCIR-601 13.5 MHz 864 720 625
|
||||
PAL 4FSc 17.72 MHz 1135 948 625
|
||||
|
||||
For the CCIR-601 standards, the sampling is based on a static orthogonal sampling grid. The luminance component (Y) is sampled at 13.5 MHz, while the two color difference signals, Cr and Cb are sampled at half that, or 6.75 MHz. The Cr and Cb samples are colocated with alternate Y samples, and they are taken at the same position on each line, such that one sample is coincident with the 50% point of the falling edge of analog sync. The samples are coded to either 8 or 10 bits per component.
|
||||
*/
|
||||
|
||||
/* from DScaler:*/
|
||||
/*
|
||||
//===========================================================================
|
||||
// CCIR656 Digital Input Support: The tables were taken from DScaler proyect
|
||||
//
|
||||
// 13 Dec 2000 - Michael Eskin, Conexant Systems - Initial version
|
||||
//
|
||||
|
||||
//===========================================================================
|
||||
// Timing generator SRAM table values for CCIR601 720x480 NTSC
|
||||
//===========================================================================
|
||||
// For NTSC CCIR656
|
||||
BYTE BtCard::SRAMTable_NTSC[] =
|
||||
{
|
||||
// SRAM Timing Table for NTSC
|
||||
0x0c, 0xc0, 0x00,
|
||||
0x00, 0x90, 0xc2,
|
||||
0x03, 0x10, 0x03,
|
||||
0x06, 0x10, 0x34,
|
||||
0x12, 0x12, 0x65,
|
||||
0x02, 0x13, 0x24,
|
||||
0x19, 0x00, 0x24,
|
||||
0x39, 0x00, 0x96,
|
||||
0x59, 0x08, 0x93,
|
||||
0x83, 0x08, 0x97,
|
||||
0x03, 0x50, 0x30,
|
||||
0xc0, 0x40, 0x30,
|
||||
0x86, 0x01, 0x01,
|
||||
0xa6, 0x0d, 0x62,
|
||||
0x03, 0x11, 0x61,
|
||||
0x05, 0x37, 0x30,
|
||||
0xac, 0x21, 0x50
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
// Timing generator SRAM table values for CCIR601 720x576 NTSC
|
||||
//===========================================================================
|
||||
// For PAL CCIR656
|
||||
BYTE BtCard::SRAMTable_PAL[] =
|
||||
{
|
||||
// SRAM Timing Table for PAL
|
||||
0x36, 0x11, 0x01,
|
||||
0x00, 0x90, 0x02,
|
||||
0x05, 0x10, 0x04,
|
||||
0x16, 0x14, 0x05,
|
||||
0x11, 0x00, 0x04,
|
||||
0x12, 0xc0, 0x00,
|
||||
0x31, 0x00, 0x06,
|
||||
0x51, 0x08, 0x03,
|
||||
0x89, 0x08, 0x07,
|
||||
0xc0, 0x44, 0x00,
|
||||
0x81, 0x01, 0x01,
|
||||
0xa9, 0x0d, 0x02,
|
||||
0x02, 0x50, 0x03,
|
||||
0x37, 0x3d, 0x00,
|
||||
0xaf, 0x21, 0x00,
|
||||
};
|
||||
*/
|
||||
|
|
@ -44,7 +44,6 @@
|
|||
|
||||
/* fwd decl */
|
||||
static void boot_msp34xx(struct bttv *btv, int pin);
|
||||
static void boot_bt832(struct bttv *btv);
|
||||
static void hauppauge_eeprom(struct bttv *btv);
|
||||
static void avermedia_eeprom(struct bttv *btv);
|
||||
static void osprey_eeprom(struct bttv *btv, const u8 ee[256]);
|
||||
|
|
@ -2217,9 +2216,9 @@ struct tvcard bttv_tvcards[] = {
|
|||
.tuner_addr = ADDR_UNSET,
|
||||
.radio_addr = ADDR_UNSET,
|
||||
},
|
||||
[BTTV_BOARD_VD009X1_MINIDIN] = {
|
||||
[BTTV_BOARD_VD009X1_VD011_MINIDIN] = {
|
||||
/* [email protected] */
|
||||
.name = "PHYTEC VD-009-X1 MiniDIN (bt878)",
|
||||
.name = "PHYTEC VD-009-X1 VD-011 MiniDIN (bt878)",
|
||||
.video_inputs = 4,
|
||||
.audio_inputs = 0,
|
||||
.tuner = UNSET, /* card has no tuner */
|
||||
|
|
@ -2227,14 +2226,14 @@ struct tvcard bttv_tvcards[] = {
|
|||
.gpiomask = 0x00,
|
||||
.muxsel = { 2, 3, 1, 0 },
|
||||
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
|
||||
.needs_tvaudio = 1,
|
||||
.needs_tvaudio = 0,
|
||||
.pll = PLL_28,
|
||||
.tuner_type = UNSET,
|
||||
.tuner_addr = ADDR_UNSET,
|
||||
.radio_addr = ADDR_UNSET,
|
||||
},
|
||||
[BTTV_BOARD_VD009X1_COMBI] = {
|
||||
.name = "PHYTEC VD-009-X1 Combi (bt878)",
|
||||
[BTTV_BOARD_VD009X1_VD011_COMBI] = {
|
||||
.name = "PHYTEC VD-009-X1 VD-011 Combi (bt878)",
|
||||
.video_inputs = 4,
|
||||
.audio_inputs = 0,
|
||||
.tuner = UNSET, /* card has no tuner */
|
||||
|
|
@ -2242,7 +2241,7 @@ struct tvcard bttv_tvcards[] = {
|
|||
.gpiomask = 0x00,
|
||||
.muxsel = { 2, 3, 1, 1 },
|
||||
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
|
||||
.needs_tvaudio = 1,
|
||||
.needs_tvaudio = 0,
|
||||
.pll = PLL_28,
|
||||
.tuner_type = UNSET,
|
||||
.tuner_addr = ADDR_UNSET,
|
||||
|
|
@ -3061,6 +3060,54 @@ struct tvcard bttv_tvcards[] = {
|
|||
.pll = PLL_28,
|
||||
.has_radio = 1,
|
||||
.has_remote = 1,
|
||||
},
|
||||
[BTTV_BOARD_VD012] = {
|
||||
/* [email protected] */
|
||||
.name = "PHYTEC VD-012 (bt878)",
|
||||
.video_inputs = 4,
|
||||
.audio_inputs = 0,
|
||||
.tuner = UNSET, /* card has no tuner */
|
||||
.svhs = UNSET, /* card has no s-video */
|
||||
.gpiomask = 0x00,
|
||||
.muxsel = { 0, 2, 3, 1 },
|
||||
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
|
||||
.needs_tvaudio = 0,
|
||||
.pll = PLL_28,
|
||||
.tuner_type = UNSET,
|
||||
.tuner_addr = ADDR_UNSET,
|
||||
.radio_addr = ADDR_UNSET,
|
||||
},
|
||||
[BTTV_BOARD_VD012_X1] = {
|
||||
/* [email protected] */
|
||||
.name = "PHYTEC VD-012-X1 (bt878)",
|
||||
.video_inputs = 4,
|
||||
.audio_inputs = 0,
|
||||
.tuner = UNSET, /* card has no tuner */
|
||||
.svhs = 3,
|
||||
.gpiomask = 0x00,
|
||||
.muxsel = { 2, 3, 1 },
|
||||
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
|
||||
.needs_tvaudio = 0,
|
||||
.pll = PLL_28,
|
||||
.tuner_type = UNSET,
|
||||
.tuner_addr = ADDR_UNSET,
|
||||
.radio_addr = ADDR_UNSET,
|
||||
},
|
||||
[BTTV_BOARD_VD012_X2] = {
|
||||
/* [email protected] */
|
||||
.name = "PHYTEC VD-012-X2 (bt878)",
|
||||
.video_inputs = 4,
|
||||
.audio_inputs = 0,
|
||||
.tuner = UNSET, /* card has no tuner */
|
||||
.svhs = 3,
|
||||
.gpiomask = 0x00,
|
||||
.muxsel = { 3, 2, 1 },
|
||||
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
|
||||
.needs_tvaudio = 0,
|
||||
.pll = PLL_28,
|
||||
.tuner_type = UNSET,
|
||||
.tuner_addr = ADDR_UNSET,
|
||||
.radio_addr = ADDR_UNSET,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -3673,13 +3720,6 @@ void __devinit bttv_init_card2(struct bttv *btv)
|
|||
if (bttv_tvcards[btv->c.type].audio_mode_gpio)
|
||||
btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio;
|
||||
|
||||
if (bttv_tvcards[btv->c.type].digital_mode == DIGITAL_MODE_CAMERA) {
|
||||
/* detect Bt832 chip for quartzsight digital camera */
|
||||
if ((bttv_I2CRead(btv, I2C_ADDR_BT832_ALT1, "Bt832") >=0) ||
|
||||
(bttv_I2CRead(btv, I2C_ADDR_BT832_ALT2, "Bt832") >=0))
|
||||
boot_bt832(btv);
|
||||
}
|
||||
|
||||
if (!autoload)
|
||||
return;
|
||||
|
||||
|
|
@ -4075,10 +4115,6 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin)
|
|||
"init [%d]\n", btv->c.nr, pin);
|
||||
}
|
||||
|
||||
static void __devinit boot_bt832(struct bttv *btv)
|
||||
{
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* Imagenation L-Model PXC200 Framegrabber */
|
||||
/* This is basically the same procedure as
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv)
|
|||
struct bttv_sub_driver *sub = to_bttv_sub_drv(drv);
|
||||
int len = strlen(sub->wanted);
|
||||
|
||||
if (0 == strncmp(dev->bus_id, sub->wanted, len))
|
||||
if (0 == strncmp(dev_name(dev), sub->wanted, len))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -91,15 +91,14 @@ int bttv_sub_add_device(struct bttv_core *core, char *name)
|
|||
sub->dev.parent = &core->pci->dev;
|
||||
sub->dev.bus = &bttv_sub_bus_type;
|
||||
sub->dev.release = release_sub_device;
|
||||
snprintf(sub->dev.bus_id,sizeof(sub->dev.bus_id),"%s%d",
|
||||
name, core->nr);
|
||||
dev_set_name(&sub->dev, "%s%d", name, core->nr);
|
||||
|
||||
err = device_register(&sub->dev);
|
||||
if (0 != err) {
|
||||
kfree(sub);
|
||||
return err;
|
||||
}
|
||||
printk("bttv%d: add subdevice \"%s\"\n", core->nr, sub->dev.bus_id);
|
||||
printk("bttv%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev));
|
||||
list_add_tail(&sub->list,&core->subs);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,8 +130,8 @@
|
|||
#define BTTV_BOARD_XGUARD 0x67
|
||||
#define BTTV_BOARD_NEBULA_DIGITV 0x68
|
||||
#define BTTV_BOARD_PV143 0x69
|
||||
#define BTTV_BOARD_VD009X1_MINIDIN 0x6a
|
||||
#define BTTV_BOARD_VD009X1_COMBI 0x6b
|
||||
#define BTTV_BOARD_VD009X1_VD011_MINIDIN 0x6a
|
||||
#define BTTV_BOARD_VD009X1_VD011_COMBI 0x6b
|
||||
#define BTTV_BOARD_VD009_MINIDIN 0x6c
|
||||
#define BTTV_BOARD_VD009_COMBI 0x6d
|
||||
#define BTTV_BOARD_IVC100 0x6e
|
||||
|
|
@ -177,6 +177,10 @@
|
|||
#define BTTV_BOARD_GEOVISION_GV600 0x96
|
||||
#define BTTV_BOARD_KOZUMI_KTV_01C 0x97
|
||||
#define BTTV_BOARD_ENLTV_FM_2 0x98
|
||||
#define BTTV_BOARD_VD012 0x99
|
||||
#define BTTV_BOARD_VD012_X1 0x9a
|
||||
#define BTTV_BOARD_VD012_X2 0x9b
|
||||
|
||||
|
||||
/* more card-specific defines */
|
||||
#define PT2254_L_CHANNEL 0x10
|
||||
|
|
@ -308,7 +312,7 @@ struct bttv_sub_device {
|
|||
|
||||
struct bttv_sub_driver {
|
||||
struct device_driver drv;
|
||||
char wanted[BUS_ID_SIZE];
|
||||
char wanted[20];
|
||||
int (*probe)(struct bttv_sub_device *sub);
|
||||
void (*remove)(struct bttv_sub_device *sub);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -459,7 +459,7 @@ struct bttv {
|
|||
};
|
||||
|
||||
/* our devices */
|
||||
#define BTTV_MAX 16
|
||||
#define BTTV_MAX 32
|
||||
extern unsigned int bttv_num;
|
||||
extern struct bttv bttvs[BTTV_MAX];
|
||||
|
||||
|
|
|
|||
|
|
@ -706,8 +706,7 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l
|
|||
* Video4linux interfacing
|
||||
*/
|
||||
|
||||
static int qcam_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
static int qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct qcam_device *qcam=(struct qcam_device *)dev;
|
||||
|
|
@ -867,7 +866,7 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
|
|||
static int qcam_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return video_usercopy(inode, file, cmd, arg, qcam_do_ioctl);
|
||||
return video_usercopy(file, cmd, arg, qcam_do_ioctl);
|
||||
}
|
||||
|
||||
static ssize_t qcam_read(struct file *file, char __user *buf,
|
||||
|
|
|
|||
|
|
@ -500,8 +500,7 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
|
|||
* Video4linux interfacing
|
||||
*/
|
||||
|
||||
static int qcam_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
static int qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct qcam_device *qcam=(struct qcam_device *)dev;
|
||||
|
|
@ -667,9 +666,9 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
|
|||
}
|
||||
|
||||
static int qcam_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return video_usercopy(inode, file, cmd, arg, qcam_do_ioctl);
|
||||
return video_usercopy(file, cmd, arg, qcam_do_ioctl);
|
||||
}
|
||||
|
||||
static ssize_t qcam_read(struct file *file, char __user *buf,
|
||||
|
|
|
|||
|
|
@ -3333,8 +3333,7 @@ static ssize_t cpia_read(struct file *file, char __user *buf,
|
|||
return cam->decompressed_frame.count;
|
||||
}
|
||||
|
||||
static int cpia_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int ioctlnr, void *arg)
|
||||
static int cpia_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
||||
{
|
||||
struct video_device *dev = file->private_data;
|
||||
struct cam_data *cam = video_get_drvdata(dev);
|
||||
|
|
@ -3347,9 +3346,9 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
|
|||
if (mutex_lock_interruptible(&cam->busy_lock))
|
||||
return -EINTR;
|
||||
|
||||
//DBG("cpia_ioctl: %u\n", ioctlnr);
|
||||
/* DBG("cpia_ioctl: %u\n", cmd); */
|
||||
|
||||
switch (ioctlnr) {
|
||||
switch (cmd) {
|
||||
/* query capabilities */
|
||||
case VIDIOCGCAP:
|
||||
{
|
||||
|
|
@ -3724,7 +3723,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
|
|||
static int cpia_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return video_usercopy(inode, file, cmd, arg, cpia_do_ioctl);
|
||||
return video_usercopy(file, cmd, arg, cpia_do_ioctl);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Stripped of 2.4 stuff ready for main kernel submit by
|
||||
* Alan Cox <alan@redhat.com>
|
||||
* Alan Cox <alan@lxorguk.ukuu.org.uk>
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Stripped of 2.4 stuff ready for main kernel submit by
|
||||
* Alan Cox <alan@redhat.com>
|
||||
* Alan Cox <alan@lxorguk.ukuu.org.uk>
|
||||
****************************************************************************/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Stripped of 2.4 stuff ready for main kernel submit by
|
||||
* Alan Cox <alan@redhat.com>
|
||||
* Alan Cox <alan@lxorguk.ukuu.org.uk>
|
||||
****************************************************************************/
|
||||
|
||||
#include <linux/version.h>
|
||||
|
|
@ -1572,8 +1572,7 @@ static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file)
|
|||
* cpia2_ioctl
|
||||
*
|
||||
*****************************************************************************/
|
||||
static int cpia2_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int ioctl_nr, void *arg)
|
||||
static int cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
||||
{
|
||||
struct camera_data *cam = video_drvdata(file);
|
||||
int retval = 0;
|
||||
|
|
@ -1591,7 +1590,7 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file,
|
|||
}
|
||||
|
||||
/* Priority check */
|
||||
switch (ioctl_nr) {
|
||||
switch (cmd) {
|
||||
case VIDIOCSWIN:
|
||||
case VIDIOCMCAPTURE:
|
||||
case VIDIOC_S_FMT:
|
||||
|
|
@ -1618,7 +1617,7 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file,
|
|||
break;
|
||||
}
|
||||
|
||||
switch (ioctl_nr) {
|
||||
switch (cmd) {
|
||||
case VIDIOCGCAP: /* query capabilities */
|
||||
retval = ioctl_cap_query(arg, cam);
|
||||
break;
|
||||
|
|
@ -1683,7 +1682,7 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file,
|
|||
case VIDIOC_ENUMINPUT:
|
||||
case VIDIOC_G_INPUT:
|
||||
case VIDIOC_S_INPUT:
|
||||
retval = ioctl_input(ioctl_nr, arg,cam);
|
||||
retval = ioctl_input(cmd, arg, cam);
|
||||
break;
|
||||
|
||||
case VIDIOC_ENUM_FMT:
|
||||
|
|
@ -1843,9 +1842,9 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file,
|
|||
}
|
||||
|
||||
static int cpia2_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int ioctl_nr, unsigned long iarg)
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return video_usercopy(inode, file, ioctl_nr, iarg, cpia2_do_ioctl);
|
||||
return video_usercopy(file, cmd, arg, cpia2_do_ioctl);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-i2c-drv.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
#include <media/v4l2-i2c-drv.h>
|
||||
|
||||
MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
|
||||
MODULE_AUTHOR("Hans Verkuil");
|
||||
|
|
@ -40,111 +40,143 @@ MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On");
|
|||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static inline int cs5345_write(struct i2c_client *client, u8 reg, u8 value)
|
||||
static inline int cs5345_write(struct v4l2_subdev *sd, u8 reg, u8 value)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static inline int cs5345_read(struct i2c_client *client, u8 reg)
|
||||
static inline int cs5345_read(struct v4l2_subdev *sd, u8 reg)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static int cs5345_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
|
||||
{
|
||||
if ((route->input & 0xf) > 6) {
|
||||
v4l2_err(sd, "Invalid input %d.\n", route->input);
|
||||
return -EINVAL;
|
||||
}
|
||||
cs5345_write(sd, 0x09, route->input & 0xf);
|
||||
cs5345_write(sd, 0x05, route->input & 0xf0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs5345_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
|
||||
{
|
||||
if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
|
||||
ctrl->value = (cs5345_read(sd, 0x04) & 0x08) != 0;
|
||||
return 0;
|
||||
}
|
||||
if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
|
||||
return -EINVAL;
|
||||
ctrl->value = cs5345_read(sd, 0x07) & 0x3f;
|
||||
if (ctrl->value >= 32)
|
||||
ctrl->value = ctrl->value - 64;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs5345_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
|
||||
{
|
||||
if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
|
||||
cs5345_write(sd, 0x04, ctrl->value ? 0x80 : 0);
|
||||
return 0;
|
||||
}
|
||||
if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
|
||||
return -EINVAL;
|
||||
if (ctrl->value > 24 || ctrl->value < -24)
|
||||
return -EINVAL;
|
||||
cs5345_write(sd, 0x07, ((u8)ctrl->value) & 0x3f);
|
||||
cs5345_write(sd, 0x08, ((u8)ctrl->value) & 0x3f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
static int cs5345_g_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
if (!v4l2_chip_match_i2c_client(client,
|
||||
reg->match_type, reg->match_chip))
|
||||
return -EINVAL;
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
reg->val = cs5345_read(sd, reg->reg & 0x1f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs5345_s_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
if (!v4l2_chip_match_i2c_client(client,
|
||||
reg->match_type, reg->match_chip))
|
||||
return -EINVAL;
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
cs5345_write(sd, reg->reg & 0x1f, reg->val & 0xff);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int cs5345_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_CS5345, 0);
|
||||
}
|
||||
|
||||
static int cs5345_log_status(struct v4l2_subdev *sd)
|
||||
{
|
||||
u8 v = cs5345_read(sd, 0x09) & 7;
|
||||
u8 m = cs5345_read(sd, 0x04);
|
||||
int vol = cs5345_read(sd, 0x08) & 0x3f;
|
||||
|
||||
v4l2_info(sd, "Input: %d%s\n", v,
|
||||
(m & 0x80) ? " (muted)" : "");
|
||||
if (vol >= 32)
|
||||
vol = vol - 64;
|
||||
v4l2_info(sd, "Volume: %d dB\n", vol);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg)
|
||||
{
|
||||
struct v4l2_routing *route = arg;
|
||||
struct v4l2_control *ctrl = arg;
|
||||
|
||||
switch (cmd) {
|
||||
case VIDIOC_INT_G_AUDIO_ROUTING:
|
||||
route->input = cs5345_read(client, 0x09) & 7;
|
||||
route->input |= cs5345_read(client, 0x05) & 0x70;
|
||||
route->output = 0;
|
||||
break;
|
||||
|
||||
case VIDIOC_INT_S_AUDIO_ROUTING:
|
||||
if ((route->input & 0xf) > 6) {
|
||||
v4l_err(client, "Invalid input %d.\n", route->input);
|
||||
return -EINVAL;
|
||||
}
|
||||
cs5345_write(client, 0x09, route->input & 0xf);
|
||||
cs5345_write(client, 0x05, route->input & 0xf0);
|
||||
break;
|
||||
|
||||
case VIDIOC_G_CTRL:
|
||||
if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
|
||||
ctrl->value = (cs5345_read(client, 0x04) & 0x08) != 0;
|
||||
break;
|
||||
}
|
||||
if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
|
||||
return -EINVAL;
|
||||
ctrl->value = cs5345_read(client, 0x07) & 0x3f;
|
||||
if (ctrl->value >= 32)
|
||||
ctrl->value = ctrl->value - 64;
|
||||
break;
|
||||
|
||||
case VIDIOC_S_CTRL:
|
||||
break;
|
||||
if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
|
||||
cs5345_write(client, 0x04, ctrl->value ? 0x80 : 0);
|
||||
break;
|
||||
}
|
||||
if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
|
||||
return -EINVAL;
|
||||
if (ctrl->value > 24 || ctrl->value < -24)
|
||||
return -EINVAL;
|
||||
cs5345_write(client, 0x07, ((u8)ctrl->value) & 0x3f);
|
||||
cs5345_write(client, 0x08, ((u8)ctrl->value) & 0x3f);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
case VIDIOC_DBG_G_REGISTER:
|
||||
case VIDIOC_DBG_S_REGISTER:
|
||||
{
|
||||
struct v4l2_register *reg = arg;
|
||||
|
||||
if (!v4l2_chip_match_i2c_client(client,
|
||||
reg->match_type, reg->match_chip))
|
||||
return -EINVAL;
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
if (cmd == VIDIOC_DBG_G_REGISTER)
|
||||
reg->val = cs5345_read(client, reg->reg & 0x1f);
|
||||
else
|
||||
cs5345_write(client, reg->reg & 0x1f, reg->val & 0xff);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case VIDIOC_G_CHIP_IDENT:
|
||||
return v4l2_chip_ident_i2c_client(client,
|
||||
arg, V4L2_IDENT_CS5345, 0);
|
||||
|
||||
case VIDIOC_LOG_STATUS:
|
||||
{
|
||||
u8 v = cs5345_read(client, 0x09) & 7;
|
||||
u8 m = cs5345_read(client, 0x04);
|
||||
int vol = cs5345_read(client, 0x08) & 0x3f;
|
||||
|
||||
v4l_info(client, "Input: %d%s\n", v,
|
||||
(m & 0x80) ? " (muted)" : "");
|
||||
if (vol >= 32)
|
||||
vol = vol - 64;
|
||||
v4l_info(client, "Volume: %d dB\n", vol);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static const struct v4l2_subdev_core_ops cs5345_core_ops = {
|
||||
.log_status = cs5345_log_status,
|
||||
.g_chip_ident = cs5345_g_chip_ident,
|
||||
.g_ctrl = cs5345_g_ctrl,
|
||||
.s_ctrl = cs5345_s_ctrl,
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
.g_register = cs5345_g_register,
|
||||
.s_register = cs5345_s_register,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_audio_ops cs5345_audio_ops = {
|
||||
.s_routing = cs5345_s_routing,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops cs5345_ops = {
|
||||
.core = &cs5345_core_ops,
|
||||
.audio = &cs5345_audio_ops,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static int cs5345_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct v4l2_subdev *sd;
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -EIO;
|
||||
|
|
@ -152,9 +184,25 @@ static int cs5345_probe(struct i2c_client *client,
|
|||
v4l_info(client, "chip found @ 0x%x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
cs5345_write(client, 0x02, 0x00);
|
||||
cs5345_write(client, 0x04, 0x01);
|
||||
cs5345_write(client, 0x09, 0x01);
|
||||
sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
|
||||
if (sd == NULL)
|
||||
return -ENOMEM;
|
||||
v4l2_i2c_subdev_init(sd, client, &cs5345_ops);
|
||||
|
||||
cs5345_write(sd, 0x02, 0x00);
|
||||
cs5345_write(sd, 0x04, 0x01);
|
||||
cs5345_write(sd, 0x09, 0x01);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static int cs5345_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
kfree(sd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -171,5 +219,6 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
|
|||
.driverid = I2C_DRIVERID_CS5345,
|
||||
.command = cs5345_command,
|
||||
.probe = cs5345_probe,
|
||||
.remove = cs5345_remove,
|
||||
.id_table = cs5345_id,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-id.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
#include <media/v4l2-i2c-drv-legacy.h>
|
||||
|
||||
|
|
@ -47,86 +47,106 @@ I2C_CLIENT_INSMOD;
|
|||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static int cs53l32a_write(struct i2c_client *client, u8 reg, u8 value)
|
||||
static int cs53l32a_write(struct v4l2_subdev *sd, u8 reg, u8 value)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static int cs53l32a_read(struct i2c_client *client, u8 reg)
|
||||
static int cs53l32a_read(struct v4l2_subdev *sd, u8 reg)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static int cs53l32a_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
|
||||
{
|
||||
/* There are 2 physical inputs, but the second input can be
|
||||
placed in two modes, the first mode bypasses the PGA (gain),
|
||||
the second goes through the PGA. Hence there are three
|
||||
possible inputs to choose from. */
|
||||
if (route->input > 2) {
|
||||
v4l2_err(sd, "Invalid input %d.\n", route->input);
|
||||
return -EINVAL;
|
||||
}
|
||||
cs53l32a_write(sd, 0x01, 0x01 + (route->input << 4));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs53l32a_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
|
||||
{
|
||||
if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
|
||||
ctrl->value = (cs53l32a_read(sd, 0x03) & 0xc0) != 0;
|
||||
return 0;
|
||||
}
|
||||
if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
|
||||
return -EINVAL;
|
||||
ctrl->value = (s8)cs53l32a_read(sd, 0x04);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs53l32a_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
|
||||
{
|
||||
if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
|
||||
cs53l32a_write(sd, 0x03, ctrl->value ? 0xf0 : 0x30);
|
||||
return 0;
|
||||
}
|
||||
if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
|
||||
return -EINVAL;
|
||||
if (ctrl->value > 12 || ctrl->value < -96)
|
||||
return -EINVAL;
|
||||
cs53l32a_write(sd, 0x04, (u8) ctrl->value);
|
||||
cs53l32a_write(sd, 0x05, (u8) ctrl->value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs53l32a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return v4l2_chip_ident_i2c_client(client,
|
||||
chip, V4L2_IDENT_CS53l32A, 0);
|
||||
}
|
||||
|
||||
static int cs53l32a_log_status(struct v4l2_subdev *sd)
|
||||
{
|
||||
u8 v = cs53l32a_read(sd, 0x01);
|
||||
u8 m = cs53l32a_read(sd, 0x03);
|
||||
s8 vol = cs53l32a_read(sd, 0x04);
|
||||
|
||||
v4l2_info(sd, "Input: %d%s\n", (v >> 4) & 3,
|
||||
(m & 0xC0) ? " (muted)" : "");
|
||||
v4l2_info(sd, "Volume: %d dB\n", vol);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
|
||||
{
|
||||
struct v4l2_routing *route = arg;
|
||||
struct v4l2_control *ctrl = arg;
|
||||
|
||||
switch (cmd) {
|
||||
case VIDIOC_INT_G_AUDIO_ROUTING:
|
||||
route->input = (cs53l32a_read(client, 0x01) >> 4) & 3;
|
||||
route->output = 0;
|
||||
break;
|
||||
|
||||
case VIDIOC_INT_S_AUDIO_ROUTING:
|
||||
/* There are 2 physical inputs, but the second input can be
|
||||
placed in two modes, the first mode bypasses the PGA (gain),
|
||||
the second goes through the PGA. Hence there are three
|
||||
possible inputs to choose from. */
|
||||
if (route->input > 2) {
|
||||
v4l_err(client, "Invalid input %d.\n", route->input);
|
||||
return -EINVAL;
|
||||
}
|
||||
cs53l32a_write(client, 0x01, 0x01 + (route->input << 4));
|
||||
break;
|
||||
|
||||
case VIDIOC_G_CTRL:
|
||||
if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
|
||||
ctrl->value = (cs53l32a_read(client, 0x03) & 0xc0) != 0;
|
||||
break;
|
||||
}
|
||||
if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
|
||||
return -EINVAL;
|
||||
ctrl->value = (s8)cs53l32a_read(client, 0x04);
|
||||
break;
|
||||
|
||||
case VIDIOC_S_CTRL:
|
||||
if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
|
||||
cs53l32a_write(client, 0x03, ctrl->value ? 0xf0 : 0x30);
|
||||
break;
|
||||
}
|
||||
if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
|
||||
return -EINVAL;
|
||||
if (ctrl->value > 12 || ctrl->value < -96)
|
||||
return -EINVAL;
|
||||
cs53l32a_write(client, 0x04, (u8) ctrl->value);
|
||||
cs53l32a_write(client, 0x05, (u8) ctrl->value);
|
||||
break;
|
||||
|
||||
case VIDIOC_G_CHIP_IDENT:
|
||||
return v4l2_chip_ident_i2c_client(client,
|
||||
arg, V4L2_IDENT_CS53l32A, 0);
|
||||
|
||||
case VIDIOC_LOG_STATUS:
|
||||
{
|
||||
u8 v = cs53l32a_read(client, 0x01);
|
||||
u8 m = cs53l32a_read(client, 0x03);
|
||||
s8 vol = cs53l32a_read(client, 0x04);
|
||||
|
||||
v4l_info(client, "Input: %d%s\n", (v >> 4) & 3,
|
||||
(m & 0xC0) ? " (muted)" : "");
|
||||
v4l_info(client, "Volume: %d dB\n", vol);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static const struct v4l2_subdev_core_ops cs53l32a_core_ops = {
|
||||
.log_status = cs53l32a_log_status,
|
||||
.g_chip_ident = cs53l32a_g_chip_ident,
|
||||
.g_ctrl = cs53l32a_g_ctrl,
|
||||
.s_ctrl = cs53l32a_s_ctrl,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_audio_ops cs53l32a_audio_ops = {
|
||||
.s_routing = cs53l32a_s_routing,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops cs53l32a_ops = {
|
||||
.core = &cs53l32a_core_ops,
|
||||
.audio = &cs53l32a_audio_ops,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/* i2c implementation */
|
||||
|
||||
/*
|
||||
|
|
@ -137,6 +157,7 @@ static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
|
|||
static int cs53l32a_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct v4l2_subdev *sd;
|
||||
int i;
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
|
|
@ -149,32 +170,46 @@ static int cs53l32a_probe(struct i2c_client *client,
|
|||
v4l_info(client, "chip found @ 0x%x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
for (i = 1; i <= 7; i++) {
|
||||
u8 v = cs53l32a_read(client, i);
|
||||
sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
|
||||
if (sd == NULL)
|
||||
return -ENOMEM;
|
||||
v4l2_i2c_subdev_init(sd, client, &cs53l32a_ops);
|
||||
|
||||
v4l_dbg(1, debug, client, "Read Reg %d %02x\n", i, v);
|
||||
for (i = 1; i <= 7; i++) {
|
||||
u8 v = cs53l32a_read(sd, i);
|
||||
|
||||
v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v);
|
||||
}
|
||||
|
||||
/* Set cs53l32a internal register for Adaptec 2010/2410 setup */
|
||||
|
||||
cs53l32a_write(client, 0x01, (u8) 0x21);
|
||||
cs53l32a_write(client, 0x02, (u8) 0x29);
|
||||
cs53l32a_write(client, 0x03, (u8) 0x30);
|
||||
cs53l32a_write(client, 0x04, (u8) 0x00);
|
||||
cs53l32a_write(client, 0x05, (u8) 0x00);
|
||||
cs53l32a_write(client, 0x06, (u8) 0x00);
|
||||
cs53l32a_write(client, 0x07, (u8) 0x00);
|
||||
cs53l32a_write(sd, 0x01, (u8) 0x21);
|
||||
cs53l32a_write(sd, 0x02, (u8) 0x29);
|
||||
cs53l32a_write(sd, 0x03, (u8) 0x30);
|
||||
cs53l32a_write(sd, 0x04, (u8) 0x00);
|
||||
cs53l32a_write(sd, 0x05, (u8) 0x00);
|
||||
cs53l32a_write(sd, 0x06, (u8) 0x00);
|
||||
cs53l32a_write(sd, 0x07, (u8) 0x00);
|
||||
|
||||
/* Display results, should be 0x21,0x29,0x30,0x00,0x00,0x00,0x00 */
|
||||
|
||||
for (i = 1; i <= 7; i++) {
|
||||
u8 v = cs53l32a_read(client, i);
|
||||
u8 v = cs53l32a_read(sd, i);
|
||||
|
||||
v4l_dbg(1, debug, client, "Read Reg %d %02x\n", i, v);
|
||||
v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs53l32a_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
kfree(sd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id cs53l32a_id[] = {
|
||||
{ "cs53l32a", 0 },
|
||||
{ }
|
||||
|
|
@ -185,6 +220,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
|
|||
.name = "cs53l32a",
|
||||
.driverid = I2C_DRIVERID_CS53L32A,
|
||||
.command = cs53l32a_command,
|
||||
.remove = cs53l32a_remove,
|
||||
.probe = cs53l32a_probe,
|
||||
.id_table = cs53l32a_id,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* Derived from cx25840-audio.c
|
||||
*
|
||||
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
|
||||
* Copyright (C) 2008 Andy Walls <awalls@radix.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
|
@ -30,98 +31,165 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
|
|||
if (freq != 32000 && freq != 44100 && freq != 48000)
|
||||
return -EINVAL;
|
||||
|
||||
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
|
||||
cx18_av_write(cx, 0x127, 0x50);
|
||||
/*
|
||||
* The PLL parameters are based on the external crystal frequency that
|
||||
* would ideally be:
|
||||
*
|
||||
* NTSC Color subcarrier freq * 8 =
|
||||
* 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
|
||||
*
|
||||
* The accidents of history and rationale that explain from where this
|
||||
* combination of magic numbers originate can be found in:
|
||||
*
|
||||
* [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in
|
||||
* the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80
|
||||
*
|
||||
* [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the
|
||||
* NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83
|
||||
*
|
||||
* As Mike Bradley has rightly pointed out, it's not the exact crystal
|
||||
* frequency that matters, only that all parts of the driver and
|
||||
* firmware are using the same value (close to the ideal value).
|
||||
*
|
||||
* Since I have a strong suspicion that, if the firmware ever assumes a
|
||||
* crystal value at all, it will assume 28.636360 MHz, the crystal
|
||||
* freq used in calculations in this driver will be:
|
||||
*
|
||||
* xtal_freq = 28.636360 MHz
|
||||
*
|
||||
* an error of less than 0.13 ppm which is way, way better than any off
|
||||
* the shelf crystal will have for accuracy anyway.
|
||||
*
|
||||
* Below I aim to run the PLLs' VCOs near 400 MHz to minimze error.
|
||||
*
|
||||
* Many thanks to Jeff Campbell and Mike Bradley for their extensive
|
||||
* investigation, experimentation, testing, and suggested solutions of
|
||||
* of audio/video sync problems with SVideo and CVBS captures.
|
||||
*/
|
||||
|
||||
if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
|
||||
switch (freq) {
|
||||
case 32000:
|
||||
/* VID_PLL and AUX_PLL */
|
||||
cx18_av_write4(cx, 0x108, 0x1408040f);
|
||||
/*
|
||||
* VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
|
||||
* AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20
|
||||
*/
|
||||
cx18_av_write4(cx, 0x108, 0x200d040f);
|
||||
|
||||
/* AUX_PLL_FRAC */
|
||||
/* 0x8.9504318a * 28,636,363.636 / 0x14 = 32000 * 384 */
|
||||
cx18_av_write4(cx, 0x110, 0x012a0863);
|
||||
/* VID_PLL Fraction = 0x2be2fe */
|
||||
/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
|
||||
cx18_av_write4(cx, 0x10c, 0x002be2fe);
|
||||
|
||||
/* AUX_PLL Fraction = 0x176740c */
|
||||
/* xtal * 0xd.bb3a060/0x20 = 32000 * 384: 393 MHz p-pd*/
|
||||
cx18_av_write4(cx, 0x110, 0x0176740c);
|
||||
|
||||
/* src3/4/6_ctl */
|
||||
/* 0x1.f77f = (4 * 15734.26) / 32000 */
|
||||
/* 0x1.f77f = (4 * xtal/8*2/455) / 32000 */
|
||||
cx18_av_write4(cx, 0x900, 0x0801f77f);
|
||||
cx18_av_write4(cx, 0x904, 0x0801f77f);
|
||||
cx18_av_write4(cx, 0x90c, 0x0801f77f);
|
||||
|
||||
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
|
||||
cx18_av_write(cx, 0x127, 0x54);
|
||||
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */
|
||||
cx18_av_write(cx, 0x127, 0x60);
|
||||
|
||||
/* AUD_COUNT = 0x2fff = 8 samples * 4 * 384 - 1 */
|
||||
cx18_av_write4(cx, 0x12c, 0x11202fff);
|
||||
|
||||
/*
|
||||
* EN_AV_LOCK = 1
|
||||
* EN_AV_LOCK = 0
|
||||
* VID_COUNT = 0x0d2ef8 = 107999.000 * 8 =
|
||||
* ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8
|
||||
*/
|
||||
cx18_av_write4(cx, 0x128, 0xa10d2ef8);
|
||||
cx18_av_write4(cx, 0x128, 0xa00d2ef8);
|
||||
break;
|
||||
|
||||
case 44100:
|
||||
/* VID_PLL and AUX_PLL */
|
||||
cx18_av_write4(cx, 0x108, 0x1009040f);
|
||||
/*
|
||||
* VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
|
||||
* AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x18
|
||||
*/
|
||||
cx18_av_write4(cx, 0x108, 0x180e040f);
|
||||
|
||||
/* AUX_PLL_FRAC */
|
||||
/* 0x9.7635e7 * 28,636,363.63 / 0x10 = 44100 * 384 */
|
||||
cx18_av_write4(cx, 0x110, 0x00ec6bce);
|
||||
/* VID_PLL Fraction = 0x2be2fe */
|
||||
/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
|
||||
cx18_av_write4(cx, 0x10c, 0x002be2fe);
|
||||
|
||||
/* AUX_PLL Fraction = 0x062a1f2 */
|
||||
/* xtal * 0xe.3150f90/0x18 = 44100 * 384: 406 MHz p-pd*/
|
||||
cx18_av_write4(cx, 0x110, 0x0062a1f2);
|
||||
|
||||
/* src3/4/6_ctl */
|
||||
/* 0x1.6d59 = (4 * 15734.26) / 44100 */
|
||||
/* 0x1.6d59 = (4 * xtal/8*2/455) / 44100 */
|
||||
cx18_av_write4(cx, 0x900, 0x08016d59);
|
||||
cx18_av_write4(cx, 0x904, 0x08016d59);
|
||||
cx18_av_write4(cx, 0x90c, 0x08016d59);
|
||||
|
||||
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x18 */
|
||||
cx18_av_write(cx, 0x127, 0x58);
|
||||
|
||||
/* AUD_COUNT = 0x92ff = 49 samples * 2 * 384 - 1 */
|
||||
cx18_av_write4(cx, 0x12c, 0x112092ff);
|
||||
|
||||
/*
|
||||
* EN_AV_LOCK = 1
|
||||
* EN_AV_LOCK = 0
|
||||
* VID_COUNT = 0x1d4bf8 = 239999.000 * 8 =
|
||||
* ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8
|
||||
*/
|
||||
cx18_av_write4(cx, 0x128, 0xa11d4bf8);
|
||||
cx18_av_write4(cx, 0x128, 0xa01d4bf8);
|
||||
break;
|
||||
|
||||
case 48000:
|
||||
/* VID_PLL and AUX_PLL */
|
||||
cx18_av_write4(cx, 0x108, 0x100a040f);
|
||||
/*
|
||||
* VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
|
||||
* AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x16
|
||||
*/
|
||||
cx18_av_write4(cx, 0x108, 0x160e040f);
|
||||
|
||||
/* AUX_PLL_FRAC */
|
||||
/* 0xa.4c6b6ea * 28,636,363.63 / 0x10 = 48000 * 384 */
|
||||
cx18_av_write4(cx, 0x110, 0x0098d6dd);
|
||||
/* VID_PLL Fraction = 0x2be2fe */
|
||||
/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
|
||||
cx18_av_write4(cx, 0x10c, 0x002be2fe);
|
||||
|
||||
/* AUX_PLL Fraction = 0x05227ad */
|
||||
/* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz p-pd*/
|
||||
cx18_av_write4(cx, 0x110, 0x005227ad);
|
||||
|
||||
/* src3/4/6_ctl */
|
||||
/* 0x1.4faa = (4 * 15734.26) / 48000 */
|
||||
/* 0x1.4faa = (4 * xtal/8*2/455) / 48000 */
|
||||
cx18_av_write4(cx, 0x900, 0x08014faa);
|
||||
cx18_av_write4(cx, 0x904, 0x08014faa);
|
||||
cx18_av_write4(cx, 0x90c, 0x08014faa);
|
||||
|
||||
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
|
||||
cx18_av_write(cx, 0x127, 0x56);
|
||||
|
||||
/* AUD_COUNT = 0x5fff = 4 samples * 16 * 384 - 1 */
|
||||
cx18_av_write4(cx, 0x12c, 0x11205fff);
|
||||
|
||||
/*
|
||||
* EN_AV_LOCK = 1
|
||||
* EN_AV_LOCK = 0
|
||||
* VID_COUNT = 0x1193f8 = 143999.000 * 8 =
|
||||
* ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8
|
||||
*/
|
||||
cx18_av_write4(cx, 0x128, 0xa11193f8);
|
||||
cx18_av_write4(cx, 0x128, 0xa01193f8);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (freq) {
|
||||
case 32000:
|
||||
/* VID_PLL and AUX_PLL */
|
||||
cx18_av_write4(cx, 0x108, 0x1e08040f);
|
||||
/*
|
||||
* VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
|
||||
* AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x30
|
||||
*/
|
||||
cx18_av_write4(cx, 0x108, 0x300d040f);
|
||||
|
||||
/* AUX_PLL_FRAC */
|
||||
/* 0x8.9504318 * 28,636,363.63 / 0x1e = 32000 * 256 */
|
||||
cx18_av_write4(cx, 0x110, 0x012a0863);
|
||||
/* VID_PLL Fraction = 0x2be2fe */
|
||||
/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
|
||||
cx18_av_write4(cx, 0x10c, 0x002be2fe);
|
||||
|
||||
/* AUX_PLL Fraction = 0x176740c */
|
||||
/* xtal * 0xd.bb3a060/0x30 = 32000 * 256: 393 MHz p-pd*/
|
||||
cx18_av_write4(cx, 0x110, 0x0176740c);
|
||||
|
||||
/* src1_ctl */
|
||||
/* 0x1.0000 = 32000/32000 */
|
||||
|
|
@ -133,27 +201,34 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
|
|||
cx18_av_write4(cx, 0x904, 0x08020000);
|
||||
cx18_av_write4(cx, 0x90c, 0x08020000);
|
||||
|
||||
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
|
||||
cx18_av_write(cx, 0x127, 0x54);
|
||||
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x30 */
|
||||
cx18_av_write(cx, 0x127, 0x70);
|
||||
|
||||
/* AUD_COUNT = 0x1fff = 8 samples * 4 * 256 - 1 */
|
||||
cx18_av_write4(cx, 0x12c, 0x11201fff);
|
||||
|
||||
/*
|
||||
* EN_AV_LOCK = 1
|
||||
* EN_AV_LOCK = 0
|
||||
* VID_COUNT = 0x0d2ef8 = 107999.000 * 8 =
|
||||
* ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8
|
||||
*/
|
||||
cx18_av_write4(cx, 0x128, 0xa10d2ef8);
|
||||
cx18_av_write4(cx, 0x128, 0xa00d2ef8);
|
||||
break;
|
||||
|
||||
case 44100:
|
||||
/* VID_PLL and AUX_PLL */
|
||||
cx18_av_write4(cx, 0x108, 0x1809040f);
|
||||
/*
|
||||
* VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
|
||||
* AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x24
|
||||
*/
|
||||
cx18_av_write4(cx, 0x108, 0x240e040f);
|
||||
|
||||
/* AUX_PLL_FRAC */
|
||||
/* 0x9.7635e74 * 28,636,363.63 / 0x18 = 44100 * 256 */
|
||||
cx18_av_write4(cx, 0x110, 0x00ec6bce);
|
||||
/* VID_PLL Fraction = 0x2be2fe */
|
||||
/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
|
||||
cx18_av_write4(cx, 0x10c, 0x002be2fe);
|
||||
|
||||
/* AUX_PLL Fraction = 0x062a1f2 */
|
||||
/* xtal * 0xe.3150f90/0x24 = 44100 * 256: 406 MHz p-pd*/
|
||||
cx18_av_write4(cx, 0x110, 0x0062a1f2);
|
||||
|
||||
/* src1_ctl */
|
||||
/* 0x1.60cd = 44100/32000 */
|
||||
|
|
@ -165,24 +240,34 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
|
|||
cx18_av_write4(cx, 0x904, 0x08017385);
|
||||
cx18_av_write4(cx, 0x90c, 0x08017385);
|
||||
|
||||
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x24 */
|
||||
cx18_av_write(cx, 0x127, 0x64);
|
||||
|
||||
/* AUD_COUNT = 0x61ff = 49 samples * 2 * 256 - 1 */
|
||||
cx18_av_write4(cx, 0x12c, 0x112061ff);
|
||||
|
||||
/*
|
||||
* EN_AV_LOCK = 1
|
||||
* EN_AV_LOCK = 0
|
||||
* VID_COUNT = 0x1d4bf8 = 239999.000 * 8 =
|
||||
* ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8
|
||||
*/
|
||||
cx18_av_write4(cx, 0x128, 0xa11d4bf8);
|
||||
cx18_av_write4(cx, 0x128, 0xa01d4bf8);
|
||||
break;
|
||||
|
||||
case 48000:
|
||||
/* VID_PLL and AUX_PLL */
|
||||
cx18_av_write4(cx, 0x108, 0x180a040f);
|
||||
/*
|
||||
* VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
|
||||
* AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20
|
||||
*/
|
||||
cx18_av_write4(cx, 0x108, 0x200d040f);
|
||||
|
||||
/* AUX_PLL_FRAC */
|
||||
/* 0xa.4c6b6ea * 28,636,363.63 / 0x18 = 48000 * 256 */
|
||||
cx18_av_write4(cx, 0x110, 0x0098d6dd);
|
||||
/* VID_PLL Fraction = 0x2be2fe */
|
||||
/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
|
||||
cx18_av_write4(cx, 0x10c, 0x002be2fe);
|
||||
|
||||
/* AUX_PLL Fraction = 0x176740c */
|
||||
/* xtal * 0xd.bb3a060/0x20 = 48000 * 256: 393 MHz p-pd*/
|
||||
cx18_av_write4(cx, 0x110, 0x0176740c);
|
||||
|
||||
/* src1_ctl */
|
||||
/* 0x1.8000 = 48000/32000 */
|
||||
|
|
@ -194,15 +279,18 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
|
|||
cx18_av_write4(cx, 0x904, 0x08015555);
|
||||
cx18_av_write4(cx, 0x90c, 0x08015555);
|
||||
|
||||
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */
|
||||
cx18_av_write(cx, 0x127, 0x60);
|
||||
|
||||
/* AUD_COUNT = 0x3fff = 4 samples * 16 * 256 - 1 */
|
||||
cx18_av_write4(cx, 0x12c, 0x11203fff);
|
||||
|
||||
/*
|
||||
* EN_AV_LOCK = 1
|
||||
* EN_AV_LOCK = 0
|
||||
* VID_COUNT = 0x1193f8 = 143999.000 * 8 =
|
||||
* ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8
|
||||
*/
|
||||
cx18_av_write4(cx, 0x128, 0xa11193f8);
|
||||
cx18_av_write4(cx, 0x128, 0xa01193f8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -215,12 +303,15 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
|
|||
void cx18_av_audio_set_path(struct cx18 *cx)
|
||||
{
|
||||
struct cx18_av_state *state = &cx->av_state;
|
||||
u8 v;
|
||||
|
||||
/* stop microcontroller */
|
||||
cx18_av_and_or(cx, 0x803, ~0x10, 0);
|
||||
v = cx18_av_read(cx, 0x803) & ~0x10;
|
||||
cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
|
||||
|
||||
/* assert soft reset */
|
||||
cx18_av_and_or(cx, 0x810, ~0x1, 0x01);
|
||||
v = cx18_av_read(cx, 0x810) | 0x01;
|
||||
cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
|
||||
|
||||
/* Mute everything to prevent the PFFT! */
|
||||
cx18_av_write(cx, 0x8d3, 0x1f);
|
||||
|
|
@ -240,12 +331,14 @@ void cx18_av_audio_set_path(struct cx18 *cx)
|
|||
set_audclk_freq(cx, state->audclk_freq);
|
||||
|
||||
/* deassert soft reset */
|
||||
cx18_av_and_or(cx, 0x810, ~0x1, 0x00);
|
||||
v = cx18_av_read(cx, 0x810) & ~0x01;
|
||||
cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
|
||||
|
||||
if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
|
||||
/* When the microcontroller detects the
|
||||
* audio format, it will unmute the lines */
|
||||
cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
|
||||
v = cx18_av_read(cx, 0x803) | 0x10;
|
||||
cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -347,19 +440,23 @@ static int get_mute(struct cx18 *cx)
|
|||
static void set_mute(struct cx18 *cx, int mute)
|
||||
{
|
||||
struct cx18_av_state *state = &cx->av_state;
|
||||
u8 v;
|
||||
|
||||
if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
|
||||
/* Must turn off microcontroller in order to mute sound.
|
||||
* Not sure if this is the best method, but it does work.
|
||||
* If the microcontroller is running, then it will undo any
|
||||
* changes to the mute register. */
|
||||
v = cx18_av_read(cx, 0x803);
|
||||
if (mute) {
|
||||
/* disable microcontroller */
|
||||
cx18_av_and_or(cx, 0x803, ~0x10, 0x00);
|
||||
v &= ~0x10;
|
||||
cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
|
||||
cx18_av_write(cx, 0x8d3, 0x1f);
|
||||
} else {
|
||||
/* enable microcontroller */
|
||||
cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
|
||||
v |= 0x10;
|
||||
cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
|
||||
}
|
||||
} else {
|
||||
/* SRC1_MUTE_EN */
|
||||
|
|
@ -375,16 +472,26 @@ int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg)
|
|||
|
||||
switch (cmd) {
|
||||
case VIDIOC_INT_AUDIO_CLOCK_FREQ:
|
||||
{
|
||||
u8 v;
|
||||
if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
|
||||
cx18_av_and_or(cx, 0x803, ~0x10, 0);
|
||||
v = cx18_av_read(cx, 0x803) & ~0x10;
|
||||
cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
|
||||
cx18_av_write(cx, 0x8d3, 0x1f);
|
||||
}
|
||||
cx18_av_and_or(cx, 0x810, ~0x1, 1);
|
||||
v = cx18_av_read(cx, 0x810) | 0x1;
|
||||
cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
|
||||
|
||||
retval = set_audclk_freq(cx, *(u32 *)arg);
|
||||
cx18_av_and_or(cx, 0x810, ~0x1, 0);
|
||||
if (state->aud_input > CX18_AV_AUDIO_SERIAL2)
|
||||
cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
|
||||
|
||||
v = cx18_av_read(cx, 0x810) & ~0x1;
|
||||
cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
|
||||
if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
|
||||
v = cx18_av_read(cx, 0x803) | 0x10;
|
||||
cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
case VIDIOC_G_CTRL:
|
||||
switch (ctrl->id) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* Derived from cx25840-core.c
|
||||
*
|
||||
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
|
||||
* Copyright (C) 2008 Andy Walls <awalls@radix.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
|
@ -36,12 +37,31 @@ int cx18_av_write(struct cx18 *cx, u16 addr, u8 value)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int cx18_av_write_expect(struct cx18 *cx, u16 addr, u8 value, u8 eval, u8 mask)
|
||||
{
|
||||
u32 reg = 0xc40000 + (addr & ~3);
|
||||
int shift = (addr & 3) * 8;
|
||||
u32 x = cx18_read_reg(cx, reg);
|
||||
|
||||
x = (x & ~((u32)0xff << shift)) | ((u32)value << shift);
|
||||
cx18_write_reg_expect(cx, x, reg,
|
||||
((u32)eval << shift), ((u32)mask << shift));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value)
|
||||
{
|
||||
cx18_write_reg(cx, value, 0xc40000 + addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
cx18_av_write4_expect(struct cx18 *cx, u16 addr, u32 value, u32 eval, u32 mask)
|
||||
{
|
||||
cx18_write_reg_expect(cx, value, 0xc40000 + addr, eval, mask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value)
|
||||
{
|
||||
cx18_write_reg_noretry(cx, value, 0xc40000 + addr);
|
||||
|
|
@ -61,11 +81,6 @@ u32 cx18_av_read4(struct cx18 *cx, u16 addr)
|
|||
return cx18_read_reg(cx, 0xc40000 + addr);
|
||||
}
|
||||
|
||||
u32 cx18_av_read4_noretry(struct cx18 *cx, u16 addr)
|
||||
{
|
||||
return cx18_read_reg_noretry(cx, 0xc40000 + addr);
|
||||
}
|
||||
|
||||
int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask,
|
||||
u8 or_value)
|
||||
{
|
||||
|
|
@ -98,14 +113,16 @@ static void cx18_av_initialize(struct cx18 *cx)
|
|||
|
||||
cx18_av_loadfw(cx);
|
||||
/* Stop 8051 code execution */
|
||||
cx18_av_write4(cx, CXADEC_DL_CTL, 0x03000000);
|
||||
cx18_av_write4_expect(cx, CXADEC_DL_CTL, 0x03000000,
|
||||
0x03000000, 0x13000000);
|
||||
|
||||
/* initallize the PLL by toggling sleep bit */
|
||||
v = cx18_av_read4(cx, CXADEC_HOST_REG1);
|
||||
/* enable sleep mode */
|
||||
cx18_av_write4(cx, CXADEC_HOST_REG1, v | 1);
|
||||
/* enable sleep mode - register appears to be read only... */
|
||||
cx18_av_write4_expect(cx, CXADEC_HOST_REG1, v | 1, v, 0xfffe);
|
||||
/* disable sleep mode */
|
||||
cx18_av_write4(cx, CXADEC_HOST_REG1, v & 0xfffe);
|
||||
cx18_av_write4_expect(cx, CXADEC_HOST_REG1, v & 0xfffe,
|
||||
v & 0xfffe, 0xffff);
|
||||
|
||||
/* initialize DLLs */
|
||||
v = cx18_av_read4(cx, CXADEC_DLL1_DIAG_CTRL) & 0xE1FFFEFF;
|
||||
|
|
@ -125,9 +142,10 @@ static void cx18_av_initialize(struct cx18 *cx)
|
|||
|
||||
v = cx18_av_read4(cx, CXADEC_AFE_DIAG_CTRL3) | 1;
|
||||
/* enable TUNE_FIL_RST */
|
||||
cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v);
|
||||
cx18_av_write4_expect(cx, CXADEC_AFE_DIAG_CTRL3, v, v, 0x03009F0F);
|
||||
/* disable TUNE_FIL_RST */
|
||||
cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v & 0xFFFFFFFE);
|
||||
cx18_av_write4_expect(cx, CXADEC_AFE_DIAG_CTRL3,
|
||||
v & 0xFFFFFFFE, v & 0xFFFFFFFE, 0x03009F0F);
|
||||
|
||||
/* enable 656 output */
|
||||
cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x040C00);
|
||||
|
|
@ -251,10 +269,9 @@ void cx18_av_std_setup(struct cx18 *cx)
|
|||
pll_int, pll_frac, pll_post);
|
||||
|
||||
if (pll_post) {
|
||||
int fin, fsc;
|
||||
int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac);
|
||||
int fin, fsc, pll;
|
||||
|
||||
pll >>= 25;
|
||||
pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25;
|
||||
pll /= pll_post;
|
||||
CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
|
||||
pll / 1000000, pll % 1000000);
|
||||
|
|
@ -324,6 +341,7 @@ static void input_change(struct cx18 *cx)
|
|||
{
|
||||
struct cx18_av_state *state = &cx->av_state;
|
||||
v4l2_std_id std = state->std;
|
||||
u8 v;
|
||||
|
||||
/* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */
|
||||
cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
|
||||
|
|
@ -333,31 +351,34 @@ static void input_change(struct cx18 *cx)
|
|||
if (std & V4L2_STD_525_60) {
|
||||
if (std == V4L2_STD_NTSC_M_JP) {
|
||||
/* Japan uses EIAJ audio standard */
|
||||
cx18_av_write(cx, 0x808, 0xf7);
|
||||
cx18_av_write(cx, 0x80b, 0x02);
|
||||
cx18_av_write_expect(cx, 0x808, 0xf7, 0xf7, 0xff);
|
||||
cx18_av_write_expect(cx, 0x80b, 0x02, 0x02, 0x3f);
|
||||
} else if (std == V4L2_STD_NTSC_M_KR) {
|
||||
/* South Korea uses A2 audio standard */
|
||||
cx18_av_write(cx, 0x808, 0xf8);
|
||||
cx18_av_write(cx, 0x80b, 0x03);
|
||||
cx18_av_write_expect(cx, 0x808, 0xf8, 0xf8, 0xff);
|
||||
cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f);
|
||||
} else {
|
||||
/* Others use the BTSC audio standard */
|
||||
cx18_av_write(cx, 0x808, 0xf6);
|
||||
cx18_av_write(cx, 0x80b, 0x01);
|
||||
cx18_av_write_expect(cx, 0x808, 0xf6, 0xf6, 0xff);
|
||||
cx18_av_write_expect(cx, 0x80b, 0x01, 0x01, 0x3f);
|
||||
}
|
||||
} else if (std & V4L2_STD_PAL) {
|
||||
/* Follow tuner change procedure for PAL */
|
||||
cx18_av_write(cx, 0x808, 0xff);
|
||||
cx18_av_write(cx, 0x80b, 0x03);
|
||||
cx18_av_write_expect(cx, 0x808, 0xff, 0xff, 0xff);
|
||||
cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f);
|
||||
} else if (std & V4L2_STD_SECAM) {
|
||||
/* Select autodetect for SECAM */
|
||||
cx18_av_write(cx, 0x808, 0xff);
|
||||
cx18_av_write(cx, 0x80b, 0x03);
|
||||
cx18_av_write_expect(cx, 0x808, 0xff, 0xff, 0xff);
|
||||
cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f);
|
||||
}
|
||||
|
||||
if (cx18_av_read(cx, 0x803) & 0x10) {
|
||||
v = cx18_av_read(cx, 0x803);
|
||||
if (v & 0x10) {
|
||||
/* restart audio decoder microcontroller */
|
||||
cx18_av_and_or(cx, 0x803, ~0x10, 0x00);
|
||||
cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
|
||||
v &= ~0x10;
|
||||
cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
|
||||
v |= 0x10;
|
||||
cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -368,6 +389,7 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
|
|||
u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 &&
|
||||
vid_input <= CX18_AV_COMPOSITE8);
|
||||
u8 reg;
|
||||
u8 v;
|
||||
|
||||
CX18_DEBUG_INFO("decoder set video input %d, audio input %d\n",
|
||||
vid_input, aud_input);
|
||||
|
|
@ -413,16 +435,23 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
cx18_av_write(cx, 0x103, reg);
|
||||
cx18_av_write_expect(cx, 0x103, reg, reg, 0xf7);
|
||||
/* Set INPUT_MODE to Composite (0) or S-Video (1) */
|
||||
cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02);
|
||||
|
||||
/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
|
||||
cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
|
||||
v = cx18_av_read(cx, 0x102);
|
||||
if (reg & 0x80)
|
||||
v &= ~0x2;
|
||||
else
|
||||
v |= 0x2;
|
||||
/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
|
||||
if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
|
||||
cx18_av_and_or(cx, 0x102, ~0x4, 4);
|
||||
v |= 0x4;
|
||||
else
|
||||
cx18_av_and_or(cx, 0x102, ~0x4, 0);
|
||||
v &= ~0x4;
|
||||
cx18_av_write_expect(cx, 0x102, v, v, 0x17);
|
||||
|
||||
/*cx18_av_and_or4(cx, 0x104, ~0x001b4180, 0x00004180);*/
|
||||
|
||||
state->vid_input = vid_input;
|
||||
|
|
@ -799,40 +828,47 @@ int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg)
|
|||
}
|
||||
|
||||
case VIDIOC_S_TUNER:
|
||||
{
|
||||
u8 v;
|
||||
|
||||
if (state->radio)
|
||||
break;
|
||||
|
||||
v = cx18_av_read(cx, 0x809);
|
||||
v &= ~0xf;
|
||||
|
||||
switch (vt->audmode) {
|
||||
case V4L2_TUNER_MODE_MONO:
|
||||
/* mono -> mono
|
||||
stereo -> mono
|
||||
bilingual -> lang1 */
|
||||
cx18_av_and_or(cx, 0x809, ~0xf, 0x00);
|
||||
break;
|
||||
case V4L2_TUNER_MODE_STEREO:
|
||||
case V4L2_TUNER_MODE_LANG1:
|
||||
/* mono -> mono
|
||||
stereo -> stereo
|
||||
bilingual -> lang1 */
|
||||
cx18_av_and_or(cx, 0x809, ~0xf, 0x04);
|
||||
v |= 0x4;
|
||||
break;
|
||||
case V4L2_TUNER_MODE_LANG1_LANG2:
|
||||
/* mono -> mono
|
||||
stereo -> stereo
|
||||
bilingual -> lang1/lang2 */
|
||||
cx18_av_and_or(cx, 0x809, ~0xf, 0x07);
|
||||
v |= 0x7;
|
||||
break;
|
||||
case V4L2_TUNER_MODE_LANG2:
|
||||
/* mono -> mono
|
||||
stereo -> stereo
|
||||
bilingual -> lang2 */
|
||||
cx18_av_and_or(cx, 0x809, ~0xf, 0x01);
|
||||
v |= 0x1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
cx18_av_write_expect(cx, 0x809, v, v, 0xff);
|
||||
state->audmode = vt->audmode;
|
||||
break;
|
||||
}
|
||||
|
||||
case VIDIOC_G_FMT:
|
||||
return get_v4lfmt(cx, (struct v4l2_format *)arg);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* Derived from cx25840-core.h
|
||||
*
|
||||
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
|
||||
* Copyright (C) 2008 Andy Walls <awalls@radix.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
|
@ -302,9 +303,11 @@ struct cx18_av_state {
|
|||
int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
|
||||
int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value);
|
||||
int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value);
|
||||
int cx18_av_write_expect(struct cx18 *cx, u16 addr, u8 value, u8 eval, u8 mask);
|
||||
int cx18_av_write4_expect(struct cx18 *cx, u16 addr, u32 value, u32 eval,
|
||||
u32 mask);
|
||||
u8 cx18_av_read(struct cx18 *cx, u16 addr);
|
||||
u32 cx18_av_read4(struct cx18 *cx, u16 addr);
|
||||
u32 cx18_av_read4_noretry(struct cx18 *cx, u16 addr);
|
||||
int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
|
||||
int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
|
||||
int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
* cx18 ADEC firmware functions
|
||||
*
|
||||
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
|
||||
* Copyright (C) 2008 Andy Walls <awalls@radix.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
|
@ -43,11 +44,13 @@ int cx18_av_loadfw(struct cx18 *cx)
|
|||
/* The firmware load often has byte errors, so allow for several
|
||||
retries, both at byte level and at the firmware load level. */
|
||||
while (retries1 < 5) {
|
||||
cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
|
||||
cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6);
|
||||
cx18_av_write4_expect(cx, CXADEC_CHIP_CTRL, 0x00010000,
|
||||
0x00008430, 0xffffffff); /* cx25843 */
|
||||
cx18_av_write_expect(cx, CXADEC_STD_DET_CTL, 0xf6, 0xf6, 0xff);
|
||||
|
||||
/* Reset the Mako core (Register is undocumented.) */
|
||||
cx18_av_write4(cx, 0x8100, 0x00010000);
|
||||
/* Reset the Mako core, Register is alias of CXADEC_CHIP_CTRL */
|
||||
cx18_av_write4_expect(cx, 0x8100, 0x00010000,
|
||||
0x00008430, 0xffffffff); /* cx25843 */
|
||||
|
||||
/* Put the 8051 in reset and enable firmware upload */
|
||||
cx18_av_write4_noretry(cx, CXADEC_DL_CTL, 0x0F000000);
|
||||
|
|
@ -61,13 +64,12 @@ int cx18_av_loadfw(struct cx18 *cx)
|
|||
int retries2;
|
||||
int unrec_err = 0;
|
||||
|
||||
for (retries2 = 0; retries2 < CX18_MAX_MMIO_RETRIES;
|
||||
for (retries2 = 0; retries2 < CX18_MAX_MMIO_WR_RETRIES;
|
||||
retries2++) {
|
||||
cx18_av_write4_noretry(cx, CXADEC_DL_CTL,
|
||||
dl_control);
|
||||
udelay(10);
|
||||
value = cx18_av_read4_noretry(cx,
|
||||
CXADEC_DL_CTL);
|
||||
value = cx18_av_read4(cx, CXADEC_DL_CTL);
|
||||
if (value == dl_control)
|
||||
break;
|
||||
/* Check if we can correct the byte by changing
|
||||
|
|
@ -78,9 +80,7 @@ int cx18_av_loadfw(struct cx18 *cx)
|
|||
break;
|
||||
}
|
||||
}
|
||||
cx18_log_write_retries(cx, retries2,
|
||||
cx->reg_mem + 0xc40000 + CXADEC_DL_CTL);
|
||||
if (unrec_err || retries2 >= CX18_MAX_MMIO_RETRIES)
|
||||
if (unrec_err || retries2 >= CX18_MAX_MMIO_WR_RETRIES)
|
||||
break;
|
||||
}
|
||||
if (i == size)
|
||||
|
|
@ -93,7 +93,8 @@ int cx18_av_loadfw(struct cx18 *cx)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size);
|
||||
cx18_av_write4_expect(cx, CXADEC_DL_CTL,
|
||||
0x13000000 | fw->size, 0x13000000, 0x13000000);
|
||||
|
||||
/* Output to the 416 */
|
||||
cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000);
|
||||
|
|
@ -118,7 +119,8 @@ int cx18_av_loadfw(struct cx18 *cx)
|
|||
passthrough */
|
||||
cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5000B687);
|
||||
|
||||
cx18_av_write4(cx, CXADEC_STD_DET_CTL, 0x000000F6);
|
||||
cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, 0x000000F6, 0x000000F6,
|
||||
0x3F00FFFF);
|
||||
/* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */
|
||||
|
||||
/* Set bit 0 in register 0x9CC to signify that this is MiniMe. */
|
||||
|
|
@ -136,7 +138,7 @@ int cx18_av_loadfw(struct cx18 *cx)
|
|||
v |= 0xFF; /* Auto by default */
|
||||
v |= 0x400; /* Stereo by default */
|
||||
v |= 0x14000000;
|
||||
cx18_av_write4(cx, CXADEC_STD_DET_CTL, v);
|
||||
cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, v, v, 0x3F00FFFF);
|
||||
|
||||
release_firmware(fw);
|
||||
|
||||
|
|
|
|||
|
|
@ -141,10 +141,11 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
|
|||
u8 lcr[24];
|
||||
|
||||
fmt = arg;
|
||||
if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
|
||||
if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE &&
|
||||
fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE)
|
||||
return -EINVAL;
|
||||
svbi = &fmt->fmt.sliced;
|
||||
if (svbi->service_set == 0) {
|
||||
if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
|
||||
/* raw VBI */
|
||||
memset(svbi, 0, sizeof(*svbi));
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* Derived from ivtv-cards.c
|
||||
*
|
||||
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
|
||||
* Copyright (C) 2008 Andy Walls <awalls@radix.net>
|
||||
*
|
||||
* 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
|
||||
|
|
@ -50,7 +51,7 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = {
|
|||
static const struct cx18_card cx18_card_hvr1600_esmt = {
|
||||
.type = CX18_CARD_HVR_1600_ESMT,
|
||||
.name = "Hauppauge HVR-1600",
|
||||
.comment = "VBI is not yet supported\n",
|
||||
.comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
|
||||
.v4l2_capabilities = CX18_CAP_ENCODER,
|
||||
.hw_audio_ctrl = CX18_HW_CX23418,
|
||||
.hw_muxer = CX18_HW_CS5345,
|
||||
|
|
@ -96,7 +97,7 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
|
|||
static const struct cx18_card cx18_card_hvr1600_samsung = {
|
||||
.type = CX18_CARD_HVR_1600_SAMSUNG,
|
||||
.name = "Hauppauge HVR-1600 (Preproduction)",
|
||||
.comment = "VBI is not yet supported\n",
|
||||
.comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
|
||||
.v4l2_capabilities = CX18_CAP_ENCODER,
|
||||
.hw_audio_ctrl = CX18_HW_CX23418,
|
||||
.hw_muxer = CX18_HW_CS5345,
|
||||
|
|
@ -151,7 +152,7 @@ static const struct cx18_card_pci_info cx18_pci_h900[] = {
|
|||
static const struct cx18_card cx18_card_h900 = {
|
||||
.type = CX18_CARD_COMPRO_H900,
|
||||
.name = "Compro VideoMate H900",
|
||||
.comment = "VBI is not yet supported\n",
|
||||
.comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
|
||||
.v4l2_capabilities = CX18_CAP_ENCODER,
|
||||
.hw_audio_ctrl = CX18_HW_CX23418,
|
||||
.hw_all = CX18_HW_TUNER,
|
||||
|
|
@ -248,7 +249,7 @@ static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = {
|
|||
static const struct cx18_card cx18_card_cnxt_raptor_pal = {
|
||||
.type = CX18_CARD_CNXT_RAPTOR_PAL,
|
||||
.name = "Conexant Raptor PAL/SECAM",
|
||||
.comment = "VBI is not yet supported\n",
|
||||
.comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
|
||||
.v4l2_capabilities = CX18_CAP_ENCODER,
|
||||
.hw_audio_ctrl = CX18_HW_CX23418,
|
||||
.hw_muxer = CX18_HW_GPIO,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* Derived from ivtv-cards.c
|
||||
*
|
||||
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
|
||||
* Copyright (C) 2008 Andy Walls <awalls@radix.net>
|
||||
*
|
||||
* 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
|
||||
|
|
@ -47,8 +48,9 @@
|
|||
|
||||
/* V4L2 capability aliases */
|
||||
#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
|
||||
V4L2_CAP_AUDIO | V4L2_CAP_READWRITE)
|
||||
/* | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */
|
||||
V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | \
|
||||
V4L2_CAP_VBI_CAPTURE)
|
||||
/* | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */
|
||||
|
||||
struct cx18_card_video_input {
|
||||
u8 video_type; /* video input type */
|
||||
|
|
|
|||
|
|
@ -259,6 +259,7 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
|
|||
return err;
|
||||
}
|
||||
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
|
||||
struct cx18_api_func_private priv;
|
||||
struct cx2341x_mpeg_params p = cx->params;
|
||||
int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing),
|
||||
c, VIDIOC_S_EXT_CTRLS);
|
||||
|
|
@ -278,7 +279,9 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
|
|||
fmt.fmt.pix.height = cx->params.height;
|
||||
cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
|
||||
}
|
||||
err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
|
||||
priv.cx = cx;
|
||||
priv.s = &cx->streams[id->type];
|
||||
err = cx2341x_update(&priv, cx18_api_func, &cx->params, &p);
|
||||
if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
|
||||
err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
|
||||
cx->params = p;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue