mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -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: (222 commits) V4L/DVB (13033): pt1: Don't use a deprecated DMA_BIT_MASK macro V4L/DVB (13029): radio-si4713: remove #include <linux/version.h> V4L/DVB (13027): go7007: convert printks to v4l2_info V4L/DVB (13026): s2250-board: Implement brightness and contrast controls V4L/DVB (13025): s2250-board: Fix memory leaks V4L/DVB (13024): go7007: Implement vidioc_g_std and vidioc_querystd V4L/DVB (13023): go7007: Merge struct gofh and go declarations V4L/DVB (13022): go7007: Fix mpeg controls V4L/DVB (13021): go7007: Fix whitespace and line lengths V4L/DVB (13020): go7007: Updates to Kconfig and Makefile V4L/DVB (13019): video: initial support for ADV7180 V4L/DVB (13018): kzalloc failure ignored in au8522_probe() V4L/DVB (13017): gspca: kmalloc failure ignored in sd_start() V4L/DVB (13016): kmalloc failure ignored in lgdt3304_attach() and s921_attach() V4L/DVB (13015): kmalloc failure ignored in m920x_firmware_download() V4L/DVB (13014): Add support for Compro VideoMate E800 (DVB-T part only) V4L/DVB (13013): FM TX: si4713: Kconfig: Fixed two typos. V4L/DVB (13012): uvc: introduce missing kfree V4L/DVB (13011): Change tuner type of BeholdTV cards V4L/DVB (13009): gspca - stv06xx-hdcs: Reduce exposure range ...
This commit is contained in:
commit
c720f5655d
361 changed files with 86808 additions and 4033 deletions
|
|
@ -210,7 +210,8 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len)
|
|||
tda18271_i2c_gate_ctrl(fe, 0);
|
||||
|
||||
if (ret != 1)
|
||||
tda_err("ERROR: i2c_transfer returned: %d\n", ret);
|
||||
tda_err("ERROR: idx = 0x%x, len = %d, "
|
||||
"i2c_transfer returned: %d\n", idx, len, ret);
|
||||
|
||||
return (ret == 1 ? 0 : ret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,27 @@ static LIST_HEAD(hybrid_tuner_instance_list);
|
|||
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
||||
static int tda18271_toggle_output(struct dvb_frontend *fe, int standby)
|
||||
{
|
||||
struct tda18271_priv *priv = fe->tuner_priv;
|
||||
|
||||
int ret = tda18271_set_standby_mode(fe, standby ? 1 : 0,
|
||||
priv->output_opt & TDA18271_OUTPUT_LT_OFF ? 1 : 0,
|
||||
priv->output_opt & TDA18271_OUTPUT_XT_OFF ? 1 : 0);
|
||||
|
||||
if (tda_fail(ret))
|
||||
goto fail;
|
||||
|
||||
tda_dbg("%s mode: xtal oscillator %s, slave tuner loop thru %s\n",
|
||||
standby ? "standby" : "active",
|
||||
priv->output_opt & TDA18271_OUTPUT_XT_OFF ? "off" : "on",
|
||||
priv->output_opt & TDA18271_OUTPUT_LT_OFF ? "off" : "on");
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
||||
static inline int charge_pump_source(struct dvb_frontend *fe, int force)
|
||||
{
|
||||
struct tda18271_priv *priv = fe->tuner_priv;
|
||||
|
|
@ -271,7 +292,7 @@ static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe,
|
|||
tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt);
|
||||
|
||||
/* calculate temperature compensation */
|
||||
rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal);
|
||||
rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal) / 1000;
|
||||
|
||||
regs[R_EB14] = approx + rfcal_comp;
|
||||
ret = tda18271_write_regs(fe, R_EB14, 1);
|
||||
|
|
@ -800,7 +821,7 @@ static int tda18271_init(struct dvb_frontend *fe)
|
|||
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
/* power up */
|
||||
/* full power up */
|
||||
ret = tda18271_set_standby_mode(fe, 0, 0, 0);
|
||||
if (tda_fail(ret))
|
||||
goto fail;
|
||||
|
|
@ -818,6 +839,21 @@ fail:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int tda18271_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct tda18271_priv *priv = fe->tuner_priv;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
/* enter standby mode, with required output features enabled */
|
||||
ret = tda18271_toggle_output(fe, 1);
|
||||
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static int tda18271_agc(struct dvb_frontend *fe)
|
||||
|
|
@ -827,8 +863,9 @@ static int tda18271_agc(struct dvb_frontend *fe)
|
|||
|
||||
switch (priv->config) {
|
||||
case 0:
|
||||
/* no LNA */
|
||||
tda_dbg("no agc configuration provided\n");
|
||||
/* no external agc configuration required */
|
||||
if (tda18271_debug & DBG_ADV)
|
||||
tda_dbg("no agc configuration provided\n");
|
||||
break;
|
||||
case 3:
|
||||
/* switch with GPIO of saa713x */
|
||||
|
|
@ -1010,22 +1047,6 @@ fail:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int tda18271_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct tda18271_priv *priv = fe->tuner_priv;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
/* standby mode w/ slave tuner output
|
||||
* & loop thru & xtal oscillator on */
|
||||
ret = tda18271_set_standby_mode(fe, 1, 0, 0);
|
||||
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tda18271_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct tda18271_priv *priv = fe->tuner_priv;
|
||||
|
|
@ -1199,6 +1220,9 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
|
|||
priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
|
||||
priv->role = (cfg) ? cfg->role : TDA18271_MASTER;
|
||||
priv->config = (cfg) ? cfg->config : 0;
|
||||
priv->small_i2c = (cfg) ? cfg->small_i2c : 0;
|
||||
priv->output_opt = (cfg) ?
|
||||
cfg->output_opt : TDA18271_OUTPUT_LT_XT_ON;
|
||||
|
||||
/* tda18271_cal_on_startup == -1 when cal
|
||||
* module option is unset */
|
||||
|
|
@ -1216,9 +1240,6 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
|
|||
|
||||
fe->tuner_priv = priv;
|
||||
|
||||
if (cfg)
|
||||
priv->small_i2c = cfg->small_i2c;
|
||||
|
||||
if (tda_fail(tda18271_get_id(fe)))
|
||||
goto fail;
|
||||
|
||||
|
|
@ -1238,9 +1259,19 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
|
|||
/* existing tuner instance */
|
||||
fe->tuner_priv = priv;
|
||||
|
||||
/* allow dvb driver to override i2c gate setting */
|
||||
if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG))
|
||||
priv->gate = cfg->gate;
|
||||
/* allow dvb driver to override configuration settings */
|
||||
if (cfg) {
|
||||
if (cfg->gate != TDA18271_GATE_ANALOG)
|
||||
priv->gate = cfg->gate;
|
||||
if (cfg->role)
|
||||
priv->role = cfg->role;
|
||||
if (cfg->config)
|
||||
priv->config = cfg->config;
|
||||
if (cfg->small_i2c)
|
||||
priv->small_i2c = cfg->small_i2c;
|
||||
if (cfg->output_opt)
|
||||
priv->output_opt = cfg->output_opt;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -962,10 +962,9 @@ struct tda18271_cid_target_map {
|
|||
static struct tda18271_cid_target_map tda18271_cid_target[] = {
|
||||
{ .rfmax = 46000, .target = 0x04, .limit = 1800 },
|
||||
{ .rfmax = 52200, .target = 0x0a, .limit = 1500 },
|
||||
{ .rfmax = 79100, .target = 0x01, .limit = 4000 },
|
||||
{ .rfmax = 70100, .target = 0x01, .limit = 4000 },
|
||||
{ .rfmax = 136800, .target = 0x18, .limit = 4000 },
|
||||
{ .rfmax = 156700, .target = 0x18, .limit = 4000 },
|
||||
{ .rfmax = 156700, .target = 0x18, .limit = 4000 },
|
||||
{ .rfmax = 186250, .target = 0x0a, .limit = 4000 },
|
||||
{ .rfmax = 230000, .target = 0x0a, .limit = 4000 },
|
||||
{ .rfmax = 345000, .target = 0x18, .limit = 4000 },
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ struct tda18271_priv {
|
|||
enum tda18271_role role;
|
||||
enum tda18271_i2c_gate gate;
|
||||
enum tda18271_ver id;
|
||||
enum tda18271_output_options output_opt;
|
||||
|
||||
unsigned int config; /* interface to saa713x / tda829x */
|
||||
unsigned int tm_rfcal;
|
||||
|
|
|
|||
|
|
@ -67,6 +67,17 @@ enum tda18271_i2c_gate {
|
|||
TDA18271_GATE_DIGITAL,
|
||||
};
|
||||
|
||||
enum tda18271_output_options {
|
||||
/* slave tuner output & loop thru & xtal oscillator always on */
|
||||
TDA18271_OUTPUT_LT_XT_ON = 0,
|
||||
|
||||
/* slave tuner output loop thru off */
|
||||
TDA18271_OUTPUT_LT_OFF = 1,
|
||||
|
||||
/* xtal oscillator off */
|
||||
TDA18271_OUTPUT_XT_OFF = 2,
|
||||
};
|
||||
|
||||
struct tda18271_config {
|
||||
/* override default if freq / std settings (optional) */
|
||||
struct tda18271_std_map *std_map;
|
||||
|
|
@ -77,6 +88,9 @@ struct tda18271_config {
|
|||
/* use i2c gate provided by analog or digital demod */
|
||||
enum tda18271_i2c_gate gate;
|
||||
|
||||
/* output options that can be disabled */
|
||||
enum tda18271_output_options output_opt;
|
||||
|
||||
/* force rf tracking filter calibration on startup */
|
||||
unsigned int rf_cal_on_startup:1;
|
||||
|
||||
|
|
|
|||
|
|
@ -1320,6 +1320,23 @@ static struct tuner_params tuner_partsnic_pti_5nf05_params[] = {
|
|||
},
|
||||
};
|
||||
|
||||
/* --------- TUNER_PHILIPS_CU1216L - DVB-C NIM ------------------------- */
|
||||
|
||||
static struct tuner_range tuner_cu1216l_ranges[] = {
|
||||
{ 16 * 160.25 /*MHz*/, 0xce, 0x01 },
|
||||
{ 16 * 444.25 /*MHz*/, 0xce, 0x02 },
|
||||
{ 16 * 999.99 , 0xce, 0x04 },
|
||||
};
|
||||
|
||||
static struct tuner_params tuner_philips_cu1216l_params[] = {
|
||||
{
|
||||
.type = TUNER_PARAM_TYPE_DIGITAL,
|
||||
.ranges = tuner_cu1216l_ranges,
|
||||
.count = ARRAY_SIZE(tuner_cu1216l_ranges),
|
||||
.iffreq = 16 * 36.125, /*MHz*/
|
||||
},
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
struct tunertype tuners[] = {
|
||||
|
|
@ -1778,6 +1795,16 @@ struct tunertype tuners[] = {
|
|||
.params = tuner_partsnic_pti_5nf05_params,
|
||||
.count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_params),
|
||||
},
|
||||
[TUNER_PHILIPS_CU1216L] = {
|
||||
.name = "Philips CU1216L",
|
||||
.params = tuner_philips_cu1216l_params,
|
||||
.count = ARRAY_SIZE(tuner_philips_cu1216l_params),
|
||||
.stepsize = 62500,
|
||||
},
|
||||
[TUNER_NXP_TDA18271] = {
|
||||
.name = "NXP TDA18271",
|
||||
/* see tda18271-fe.c for details */
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(tuners);
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,10 @@ comment "Supported FireWire (IEEE 1394) Adapters"
|
|||
depends on DVB_CORE && IEEE1394
|
||||
source "drivers/media/dvb/firewire/Kconfig"
|
||||
|
||||
comment "Supported Earthsoft PT1 Adapters"
|
||||
depends on DVB_CORE && PCI && I2C
|
||||
source "drivers/media/dvb/pt1/Kconfig"
|
||||
|
||||
comment "Supported DVB Frontends"
|
||||
depends on DVB_CORE
|
||||
source "drivers/media/dvb/frontends/Kconfig"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@
|
|||
# Makefile for the kernel multimedia device drivers.
|
||||
#
|
||||
|
||||
obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/
|
||||
obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/ pt1/
|
||||
|
||||
obj-$(CONFIG_DVB_FIREDTV) += firewire/
|
||||
|
|
|
|||
|
|
@ -850,6 +850,49 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(&(fe->dtv_property_cache), 0,
|
||||
sizeof(struct dtv_frontend_properties));
|
||||
|
||||
fe->dtv_property_cache.state = DTV_CLEAR;
|
||||
fe->dtv_property_cache.delivery_system = SYS_UNDEFINED;
|
||||
fe->dtv_property_cache.inversion = INVERSION_AUTO;
|
||||
fe->dtv_property_cache.fec_inner = FEC_AUTO;
|
||||
fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
|
||||
fe->dtv_property_cache.bandwidth_hz = BANDWIDTH_AUTO;
|
||||
fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
|
||||
fe->dtv_property_cache.hierarchy = HIERARCHY_AUTO;
|
||||
fe->dtv_property_cache.symbol_rate = QAM_AUTO;
|
||||
fe->dtv_property_cache.code_rate_HP = FEC_AUTO;
|
||||
fe->dtv_property_cache.code_rate_LP = FEC_AUTO;
|
||||
|
||||
fe->dtv_property_cache.isdbt_partial_reception = -1;
|
||||
fe->dtv_property_cache.isdbt_sb_mode = -1;
|
||||
fe->dtv_property_cache.isdbt_sb_subchannel = -1;
|
||||
fe->dtv_property_cache.isdbt_sb_segment_idx = -1;
|
||||
fe->dtv_property_cache.isdbt_sb_segment_count = -1;
|
||||
fe->dtv_property_cache.isdbt_layer_enabled = 0x7;
|
||||
for (i = 0; i < 3; i++) {
|
||||
fe->dtv_property_cache.layer[i].fec = FEC_AUTO;
|
||||
fe->dtv_property_cache.layer[i].modulation = QAM_AUTO;
|
||||
fe->dtv_property_cache.layer[i].interleaving = -1;
|
||||
fe->dtv_property_cache.layer[i].segment_count = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define _DTV_CMD(n, s, b) \
|
||||
[n] = { \
|
||||
.name = #n, \
|
||||
.cmd = n, \
|
||||
.set = s,\
|
||||
.buffer = b \
|
||||
}
|
||||
|
||||
static struct dtv_cmds_h dtv_cmds[] = {
|
||||
[DTV_TUNE] = {
|
||||
.name = "DTV_TUNE",
|
||||
|
|
@ -949,6 +992,47 @@ static struct dtv_cmds_h dtv_cmds[] = {
|
|||
.cmd = DTV_TRANSMISSION_MODE,
|
||||
.set = 1,
|
||||
},
|
||||
|
||||
_DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERA_FEC, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERB_FEC, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERC_FEC, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0),
|
||||
|
||||
_DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 0, 0),
|
||||
_DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 0, 0),
|
||||
_DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 0, 0),
|
||||
_DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 0, 0),
|
||||
_DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 0, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 0, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERA_FEC, 0, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 0, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 0, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 0, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERB_FEC, 0, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 0, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 0, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 0, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERC_FEC, 0, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 0, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 0, 0),
|
||||
_DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0, 0),
|
||||
|
||||
_DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),
|
||||
|
||||
/* Get */
|
||||
[DTV_DISEQC_SLAVE_REPLY] = {
|
||||
.name = "DTV_DISEQC_SLAVE_REPLY",
|
||||
|
|
@ -956,6 +1040,7 @@ static struct dtv_cmds_h dtv_cmds[] = {
|
|||
.set = 0,
|
||||
.buffer = 1,
|
||||
},
|
||||
|
||||
[DTV_API_VERSION] = {
|
||||
.name = "DTV_API_VERSION",
|
||||
.cmd = DTV_API_VERSION,
|
||||
|
|
@ -1165,14 +1250,21 @@ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
|
|||
if(c->delivery_system == SYS_ISDBT) {
|
||||
/* Fake out a generic DVB-T request so we pass validation in the ioctl */
|
||||
p->frequency = c->frequency;
|
||||
p->inversion = INVERSION_AUTO;
|
||||
p->inversion = c->inversion;
|
||||
p->u.ofdm.constellation = QAM_AUTO;
|
||||
p->u.ofdm.code_rate_HP = FEC_AUTO;
|
||||
p->u.ofdm.code_rate_LP = FEC_AUTO;
|
||||
p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
|
||||
p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
|
||||
p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
|
||||
p->u.ofdm.hierarchy_information = HIERARCHY_AUTO;
|
||||
if (c->bandwidth_hz == 8000000)
|
||||
p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
|
||||
else if (c->bandwidth_hz == 7000000)
|
||||
p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
|
||||
else if (c->bandwidth_hz == 6000000)
|
||||
p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
|
||||
else
|
||||
p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1274,6 +1366,65 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
|
|||
case DTV_HIERARCHY:
|
||||
tvp->u.data = fe->dtv_property_cache.hierarchy;
|
||||
break;
|
||||
|
||||
/* ISDB-T Support here */
|
||||
case DTV_ISDBT_PARTIAL_RECEPTION:
|
||||
tvp->u.data = fe->dtv_property_cache.isdbt_partial_reception;
|
||||
break;
|
||||
case DTV_ISDBT_SOUND_BROADCASTING:
|
||||
tvp->u.data = fe->dtv_property_cache.isdbt_sb_mode;
|
||||
break;
|
||||
case DTV_ISDBT_SB_SUBCHANNEL_ID:
|
||||
tvp->u.data = fe->dtv_property_cache.isdbt_sb_subchannel;
|
||||
break;
|
||||
case DTV_ISDBT_SB_SEGMENT_IDX:
|
||||
tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_idx;
|
||||
break;
|
||||
case DTV_ISDBT_SB_SEGMENT_COUNT:
|
||||
tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_count;
|
||||
break;
|
||||
case DTV_ISDBT_LAYER_ENABLED:
|
||||
tvp->u.data = fe->dtv_property_cache.isdbt_layer_enabled;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERA_FEC:
|
||||
tvp->u.data = fe->dtv_property_cache.layer[0].fec;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERA_MODULATION:
|
||||
tvp->u.data = fe->dtv_property_cache.layer[0].modulation;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
|
||||
tvp->u.data = fe->dtv_property_cache.layer[0].segment_count;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
|
||||
tvp->u.data = fe->dtv_property_cache.layer[0].interleaving;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERB_FEC:
|
||||
tvp->u.data = fe->dtv_property_cache.layer[1].fec;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERB_MODULATION:
|
||||
tvp->u.data = fe->dtv_property_cache.layer[1].modulation;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
|
||||
tvp->u.data = fe->dtv_property_cache.layer[1].segment_count;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
|
||||
tvp->u.data = fe->dtv_property_cache.layer[1].interleaving;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERC_FEC:
|
||||
tvp->u.data = fe->dtv_property_cache.layer[2].fec;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERC_MODULATION:
|
||||
tvp->u.data = fe->dtv_property_cache.layer[2].modulation;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
|
||||
tvp->u.data = fe->dtv_property_cache.layer[2].segment_count;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
|
||||
tvp->u.data = fe->dtv_property_cache.layer[2].interleaving;
|
||||
break;
|
||||
case DTV_ISDBS_TS_ID:
|
||||
tvp->u.data = fe->dtv_property_cache.isdbs_ts_id;
|
||||
break;
|
||||
default:
|
||||
r = -1;
|
||||
}
|
||||
|
|
@ -1302,10 +1453,8 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
|
|||
/* Reset a cache of data specific to the frontend here. This does
|
||||
* not effect hardware.
|
||||
*/
|
||||
dvb_frontend_clear_cache(fe);
|
||||
dprintk("%s() Flushing property cache\n", __func__);
|
||||
memset(&fe->dtv_property_cache, 0, sizeof(struct dtv_frontend_properties));
|
||||
fe->dtv_property_cache.state = tvp->cmd;
|
||||
fe->dtv_property_cache.delivery_system = SYS_UNDEFINED;
|
||||
break;
|
||||
case DTV_TUNE:
|
||||
/* interpret the cache of data, build either a traditional frontend
|
||||
|
|
@ -1371,6 +1520,65 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
|
|||
case DTV_HIERARCHY:
|
||||
fe->dtv_property_cache.hierarchy = tvp->u.data;
|
||||
break;
|
||||
|
||||
/* ISDB-T Support here */
|
||||
case DTV_ISDBT_PARTIAL_RECEPTION:
|
||||
fe->dtv_property_cache.isdbt_partial_reception = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBT_SOUND_BROADCASTING:
|
||||
fe->dtv_property_cache.isdbt_sb_mode = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBT_SB_SUBCHANNEL_ID:
|
||||
fe->dtv_property_cache.isdbt_sb_subchannel = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBT_SB_SEGMENT_IDX:
|
||||
fe->dtv_property_cache.isdbt_sb_segment_idx = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBT_SB_SEGMENT_COUNT:
|
||||
fe->dtv_property_cache.isdbt_sb_segment_count = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYER_ENABLED:
|
||||
fe->dtv_property_cache.isdbt_layer_enabled = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERA_FEC:
|
||||
fe->dtv_property_cache.layer[0].fec = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERA_MODULATION:
|
||||
fe->dtv_property_cache.layer[0].modulation = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
|
||||
fe->dtv_property_cache.layer[0].segment_count = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
|
||||
fe->dtv_property_cache.layer[0].interleaving = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERB_FEC:
|
||||
fe->dtv_property_cache.layer[1].fec = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERB_MODULATION:
|
||||
fe->dtv_property_cache.layer[1].modulation = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
|
||||
fe->dtv_property_cache.layer[1].segment_count = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
|
||||
fe->dtv_property_cache.layer[1].interleaving = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERC_FEC:
|
||||
fe->dtv_property_cache.layer[2].fec = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERC_MODULATION:
|
||||
fe->dtv_property_cache.layer[2].modulation = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
|
||||
fe->dtv_property_cache.layer[2].segment_count = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
|
||||
fe->dtv_property_cache.layer[2].interleaving = tvp->u.data;
|
||||
break;
|
||||
case DTV_ISDBS_TS_ID:
|
||||
fe->dtv_property_cache.isdbs_ts_id = tvp->u.data;
|
||||
break;
|
||||
default:
|
||||
r = -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -341,6 +341,23 @@ struct dtv_frontend_properties {
|
|||
fe_rolloff_t rolloff;
|
||||
|
||||
fe_delivery_system_t delivery_system;
|
||||
|
||||
/* ISDB-T specifics */
|
||||
u8 isdbt_partial_reception;
|
||||
u8 isdbt_sb_mode;
|
||||
u8 isdbt_sb_subchannel;
|
||||
u32 isdbt_sb_segment_idx;
|
||||
u32 isdbt_sb_segment_count;
|
||||
u8 isdbt_layer_enabled;
|
||||
struct {
|
||||
u8 segment_count;
|
||||
fe_code_rate_t fec;
|
||||
fe_modulation_t modulation;
|
||||
u8 interleaving;
|
||||
} layer[3];
|
||||
|
||||
/* ISDB-T specifics */
|
||||
u32 isdbs_ts_id;
|
||||
};
|
||||
|
||||
struct dvb_frontend {
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ config DVB_USB_DIB0700
|
|||
depends on DVB_USB
|
||||
select DVB_DIB7000P if !DVB_FE_CUSTOMISE
|
||||
select DVB_DIB7000M if !DVB_FE_CUSTOMISE
|
||||
select DVB_DIB8000 if !DVB_FE_CUSTOMISE
|
||||
select DVB_DIB3000MC if !DVB_FE_CUSTOMISE
|
||||
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
|
||||
select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
|
||||
|
|
@ -87,7 +88,7 @@ config DVB_USB_DIB0700
|
|||
Avermedia and other big and small companies.
|
||||
|
||||
For an up-to-date list of devices supported by this driver, have a look
|
||||
on the Linux-DVB Wiki at www.linuxtv.org.
|
||||
on the LinuxTV Wiki at www.linuxtv.org.
|
||||
|
||||
Say Y if you own such a device and want to use it. You should build it as
|
||||
a module.
|
||||
|
|
@ -315,3 +316,9 @@ config DVB_USB_CE6230
|
|||
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver
|
||||
|
||||
config DVB_USB_FRIIO
|
||||
tristate "Friio ISDB-T USB2.0 Receiver support"
|
||||
depends on DVB_USB
|
||||
help
|
||||
Say Y here to support the Japanese DTV receiver Friio.
|
||||
|
|
|
|||
|
|
@ -79,6 +79,9 @@ obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
|
|||
dvb-usb-ce6230-objs = ce6230.o
|
||||
obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o
|
||||
|
||||
dvb-usb-friio-objs = friio.o friio-fe.o
|
||||
obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o
|
||||
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
|
||||
# due to tuner-xc3028
|
||||
EXTRA_CFLAGS += -Idrivers/media/common/tuners
|
||||
|
|
|
|||
|
|
@ -61,10 +61,13 @@ static struct af9013_config af9015_af9013_config[] = {
|
|||
|
||||
static int af9015_rw_udev(struct usb_device *udev, struct req_t *req)
|
||||
{
|
||||
#define BUF_LEN 63
|
||||
#define REQ_HDR_LEN 8 /* send header size */
|
||||
#define ACK_HDR_LEN 2 /* rece header size */
|
||||
int act_len, ret;
|
||||
u8 buf[64];
|
||||
u8 buf[BUF_LEN];
|
||||
u8 write = 1;
|
||||
u8 msg_len = 8;
|
||||
u8 msg_len = REQ_HDR_LEN;
|
||||
static u8 seq; /* packet sequence number */
|
||||
|
||||
if (mutex_lock_interruptible(&af9015_usb_mutex) < 0)
|
||||
|
|
@ -94,7 +97,7 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req)
|
|||
break;
|
||||
case WRITE_MEMORY:
|
||||
if (((req->addr & 0xff00) == 0xff00) ||
|
||||
((req->addr & 0xae00) == 0xae00))
|
||||
((req->addr & 0xff00) == 0xae00))
|
||||
buf[0] = WRITE_VIRTUAL_MEMORY;
|
||||
case WRITE_VIRTUAL_MEMORY:
|
||||
case COPY_FIRMWARE:
|
||||
|
|
@ -107,17 +110,26 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req)
|
|||
goto error_unlock;
|
||||
}
|
||||
|
||||
/* buffer overflow check */
|
||||
if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) ||
|
||||
(!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) {
|
||||
err("too much data; cmd:%d len:%d", req->cmd, req->data_len);
|
||||
ret = -EINVAL;
|
||||
goto error_unlock;
|
||||
}
|
||||
|
||||
/* write requested */
|
||||
if (write) {
|
||||
memcpy(&buf[8], req->data, req->data_len);
|
||||
memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len);
|
||||
msg_len += req->data_len;
|
||||
}
|
||||
|
||||
deb_xfer(">>> ");
|
||||
debug_dump(buf, msg_len, deb_xfer);
|
||||
|
||||
/* send req */
|
||||
ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len,
|
||||
&act_len, AF9015_USB_TIMEOUT);
|
||||
&act_len, AF9015_USB_TIMEOUT);
|
||||
if (ret)
|
||||
err("bulk message failed:%d (%d/%d)", ret, msg_len, act_len);
|
||||
else
|
||||
|
|
@ -130,10 +142,14 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req)
|
|||
if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB)
|
||||
goto exit_unlock;
|
||||
|
||||
/* receive ack and data if read req */
|
||||
msg_len = 1 + 1 + req->data_len; /* seq + status + data len */
|
||||
/* write receives seq + status = 2 bytes
|
||||
read receives seq + status + data = 2 + N bytes */
|
||||
msg_len = ACK_HDR_LEN;
|
||||
if (!write)
|
||||
msg_len += req->data_len;
|
||||
|
||||
ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len,
|
||||
&act_len, AF9015_USB_TIMEOUT);
|
||||
&act_len, AF9015_USB_TIMEOUT);
|
||||
if (ret) {
|
||||
err("recv bulk message failed:%d", ret);
|
||||
ret = -1;
|
||||
|
|
@ -159,7 +175,7 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req)
|
|||
|
||||
/* read request, copy returned data to return buf */
|
||||
if (!write)
|
||||
memcpy(req->data, &buf[2], req->data_len);
|
||||
memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len);
|
||||
|
||||
error_unlock:
|
||||
exit_unlock:
|
||||
|
|
@ -369,12 +385,14 @@ static int af9015_init_endpoint(struct dvb_usb_device *d)
|
|||
u8 packet_size;
|
||||
deb_info("%s: USB speed:%d\n", __func__, d->udev->speed);
|
||||
|
||||
/* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0.
|
||||
We use smaller - about 1/4 from the original, 5 and 87. */
|
||||
#define TS_PACKET_SIZE 188
|
||||
|
||||
#define TS_USB20_PACKET_COUNT 348
|
||||
#define TS_USB20_PACKET_COUNT 87
|
||||
#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT)
|
||||
|
||||
#define TS_USB11_PACKET_COUNT 21
|
||||
#define TS_USB11_PACKET_COUNT 5
|
||||
#define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT)
|
||||
|
||||
#define TS_USB20_MAX_PACKET_SIZE 512
|
||||
|
|
@ -868,13 +886,13 @@ static int af9015_read_config(struct usb_device *udev)
|
|||
/* USB1.1 set smaller buffersize and disable 2nd adapter */
|
||||
if (udev->speed == USB_SPEED_FULL) {
|
||||
af9015_properties[i].adapter[0].stream.u.bulk.buffersize
|
||||
= TS_USB11_MAX_PACKET_SIZE;
|
||||
= TS_USB11_FRAME_SIZE;
|
||||
/* disable 2nd adapter because we don't have
|
||||
PID-filters */
|
||||
af9015_config.dual_mode = 0;
|
||||
} else {
|
||||
af9015_properties[i].adapter[0].stream.u.bulk.buffersize
|
||||
= TS_USB20_MAX_PACKET_SIZE;
|
||||
= TS_USB20_FRAME_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1310,7 +1328,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
|
|||
.u = {
|
||||
.bulk = {
|
||||
.buffersize =
|
||||
TS_USB20_MAX_PACKET_SIZE,
|
||||
TS_USB20_FRAME_SIZE,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -1416,7 +1434,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
|
|||
.u = {
|
||||
.bulk = {
|
||||
.buffersize =
|
||||
TS_USB20_MAX_PACKET_SIZE,
|
||||
TS_USB20_FRAME_SIZE,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -1522,7 +1540,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
|
|||
.u = {
|
||||
.bulk = {
|
||||
.buffersize =
|
||||
TS_USB20_MAX_PACKET_SIZE,
|
||||
TS_USB20_FRAME_SIZE,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -203,11 +203,11 @@ static struct i2c_algorithm anysee_i2c_algo = {
|
|||
|
||||
static int anysee_mt352_demod_init(struct dvb_frontend *fe)
|
||||
{
|
||||
static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 };
|
||||
static u8 reset [] = { RESET, 0x80 };
|
||||
static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
|
||||
static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 };
|
||||
static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
|
||||
static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x28 };
|
||||
static u8 reset[] = { RESET, 0x80 };
|
||||
static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 };
|
||||
static u8 agc_cfg[] = { AGC_TARGET, 0x28, 0x20 };
|
||||
static u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 };
|
||||
static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
|
||||
|
||||
mt352_write(fe, clock_config, sizeof(clock_config));
|
||||
|
|
@ -485,7 +485,7 @@ static int anysee_probe(struct usb_interface *intf,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct usb_device_id anysee_table [] = {
|
||||
static struct usb_device_id anysee_table[] = {
|
||||
{ USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) },
|
||||
{ USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE) },
|
||||
{ } /* Terminating entry */
|
||||
|
|
@ -511,7 +511,7 @@ static struct dvb_usb_device_properties anysee_properties = {
|
|||
.endpoint = 0x82,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 512,
|
||||
.buffersize = (16*512),
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ static struct dvb_usb_device_properties ce6230_properties = {
|
|||
.endpoint = 0x82,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 512,
|
||||
.buffersize = (16*512),
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@
|
|||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 2.
|
||||
*
|
||||
* Copyright (C) 2005-7 DiBcom, SA
|
||||
* Copyright (C) 2005-9 DiBcom, SA et al
|
||||
*/
|
||||
#include "dib0700.h"
|
||||
|
||||
#include "dib3000mc.h"
|
||||
#include "dib7000m.h"
|
||||
#include "dib7000p.h"
|
||||
#include "dib8000.h"
|
||||
#include "mt2060.h"
|
||||
#include "mt2266.h"
|
||||
#include "tuner-xc2028.h"
|
||||
|
|
@ -1098,11 +1099,13 @@ static struct dibx000_agc_config dib7070_agc_config = {
|
|||
|
||||
static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
|
||||
{
|
||||
deb_info("reset: %d", onoff);
|
||||
return dib7000p_set_gpio(fe, 8, 0, !onoff);
|
||||
}
|
||||
|
||||
static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
|
||||
{
|
||||
deb_info("sleep: %d", onoff);
|
||||
return dib7000p_set_gpio(fe, 9, 0, onoff);
|
||||
}
|
||||
|
||||
|
|
@ -1112,16 +1115,26 @@ static struct dib0070_config dib7070p_dib0070_config[2] = {
|
|||
.reset = dib7070_tuner_reset,
|
||||
.sleep = dib7070_tuner_sleep,
|
||||
.clock_khz = 12000,
|
||||
.clock_pad_drive = 4
|
||||
.clock_pad_drive = 4,
|
||||
.charge_pump = 2,
|
||||
}, {
|
||||
.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
|
||||
.reset = dib7070_tuner_reset,
|
||||
.sleep = dib7070_tuner_sleep,
|
||||
.clock_khz = 12000,
|
||||
|
||||
.charge_pump = 2,
|
||||
}
|
||||
};
|
||||
|
||||
static struct dib0070_config dib7770p_dib0070_config = {
|
||||
.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
|
||||
.reset = dib7070_tuner_reset,
|
||||
.sleep = dib7070_tuner_sleep,
|
||||
.clock_khz = 12000,
|
||||
.clock_pad_drive = 0,
|
||||
.flip_chip = 1,
|
||||
};
|
||||
|
||||
static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
||||
|
|
@ -1139,6 +1152,45 @@ static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_fronte
|
|||
return state->set_param_save(fe, fep);
|
||||
}
|
||||
|
||||
static int dib7770_set_param_override(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
||||
struct dib0700_adapter_state *state = adap->priv;
|
||||
|
||||
u16 offset;
|
||||
u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
|
||||
switch (band) {
|
||||
case BAND_VHF:
|
||||
dib7000p_set_gpio(fe, 0, 0, 1);
|
||||
offset = 850;
|
||||
break;
|
||||
case BAND_UHF:
|
||||
default:
|
||||
dib7000p_set_gpio(fe, 0, 0, 0);
|
||||
offset = 250;
|
||||
break;
|
||||
}
|
||||
deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
|
||||
dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
|
||||
return state->set_param_save(fe, fep);
|
||||
}
|
||||
|
||||
static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dib0700_adapter_state *st = adap->priv;
|
||||
struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe,
|
||||
DIBX000_I2C_INTERFACE_TUNER, 1);
|
||||
|
||||
if (dvb_attach(dib0070_attach, adap->fe, tun_i2c,
|
||||
&dib7770p_dib0070_config) == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
st->set_param_save = adap->fe->ops.tuner_ops.set_params;
|
||||
adap->fe->ops.tuner_ops.set_params = dib7770_set_param_override;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dib0700_adapter_state *st = adap->priv;
|
||||
|
|
@ -1217,6 +1269,306 @@ static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
|
|||
return adap->fe == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
/* DIB807x generic */
|
||||
static struct dibx000_agc_config dib807x_agc_config[2] = {
|
||||
{
|
||||
BAND_VHF,
|
||||
/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
|
||||
* P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
|
||||
* P_agc_inv_pwm2=0,P_agc_inh_dc_rv_est=0,
|
||||
* P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
|
||||
* P_agc_write=0 */
|
||||
(0 << 15) | (0 << 14) | (7 << 11) | (0 << 10) | (0 << 9) |
|
||||
(0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) |
|
||||
(0 << 0), /* setup*/
|
||||
|
||||
600, /* inv_gain*/
|
||||
10, /* time_stabiliz*/
|
||||
|
||||
0, /* alpha_level*/
|
||||
118, /* thlock*/
|
||||
|
||||
0, /* wbd_inv*/
|
||||
3530, /* wbd_ref*/
|
||||
1, /* wbd_sel*/
|
||||
5, /* wbd_alpha*/
|
||||
|
||||
65535, /* agc1_max*/
|
||||
0, /* agc1_min*/
|
||||
|
||||
65535, /* agc2_max*/
|
||||
0, /* agc2_min*/
|
||||
|
||||
0, /* agc1_pt1*/
|
||||
40, /* agc1_pt2*/
|
||||
183, /* agc1_pt3*/
|
||||
206, /* agc1_slope1*/
|
||||
255, /* agc1_slope2*/
|
||||
72, /* agc2_pt1*/
|
||||
152, /* agc2_pt2*/
|
||||
88, /* agc2_slope1*/
|
||||
90, /* agc2_slope2*/
|
||||
|
||||
17, /* alpha_mant*/
|
||||
27, /* alpha_exp*/
|
||||
23, /* beta_mant*/
|
||||
51, /* beta_exp*/
|
||||
|
||||
0, /* perform_agc_softsplit*/
|
||||
}, {
|
||||
BAND_UHF,
|
||||
/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
|
||||
* P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
|
||||
* P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
|
||||
* P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
|
||||
* P_agc_write=0 */
|
||||
(0 << 15) | (0 << 14) | (1 << 11) | (0 << 10) | (0 << 9) |
|
||||
(0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) |
|
||||
(0 << 0), /* setup */
|
||||
|
||||
600, /* inv_gain*/
|
||||
10, /* time_stabiliz*/
|
||||
|
||||
0, /* alpha_level*/
|
||||
118, /* thlock*/
|
||||
|
||||
0, /* wbd_inv*/
|
||||
3530, /* wbd_ref*/
|
||||
1, /* wbd_sel*/
|
||||
5, /* wbd_alpha*/
|
||||
|
||||
65535, /* agc1_max*/
|
||||
0, /* agc1_min*/
|
||||
|
||||
65535, /* agc2_max*/
|
||||
0, /* agc2_min*/
|
||||
|
||||
0, /* agc1_pt1*/
|
||||
40, /* agc1_pt2*/
|
||||
183, /* agc1_pt3*/
|
||||
206, /* agc1_slope1*/
|
||||
255, /* agc1_slope2*/
|
||||
72, /* agc2_pt1*/
|
||||
152, /* agc2_pt2*/
|
||||
88, /* agc2_slope1*/
|
||||
90, /* agc2_slope2*/
|
||||
|
||||
17, /* alpha_mant*/
|
||||
27, /* alpha_exp*/
|
||||
23, /* beta_mant*/
|
||||
51, /* beta_exp*/
|
||||
|
||||
0, /* perform_agc_softsplit*/
|
||||
}
|
||||
};
|
||||
|
||||
static struct dibx000_bandwidth_config dib807x_bw_config_12_mhz = {
|
||||
60000, 15000, /* internal, sampling*/
|
||||
1, 20, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass*/
|
||||
0, 0, 1, 1, 2, /* misc: refdiv, bypclk_div, IO_CLK_en_core,
|
||||
ADClkSrc, modulo */
|
||||
(3 << 14) | (1 << 12) | (599 << 0), /* sad_cfg: refsel, sel, freq_15k*/
|
||||
(0 << 25) | 0, /* ifreq = 0.000000 MHz*/
|
||||
18179755, /* timf*/
|
||||
12000000, /* xtal_hz*/
|
||||
};
|
||||
|
||||
static struct dib8000_config dib807x_dib8000_config[2] = {
|
||||
{
|
||||
.output_mpeg2_in_188_bytes = 1,
|
||||
|
||||
.agc_config_count = 2,
|
||||
.agc = dib807x_agc_config,
|
||||
.pll = &dib807x_bw_config_12_mhz,
|
||||
.tuner_is_baseband = 1,
|
||||
|
||||
.gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
|
||||
.gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
|
||||
.gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
|
||||
|
||||
.hostbus_diversity = 1,
|
||||
.div_cfg = 1,
|
||||
.agc_control = &dib0070_ctrl_agc_filter,
|
||||
.output_mode = OUTMODE_MPEG2_FIFO,
|
||||
.drives = 0x2d98,
|
||||
}, {
|
||||
.output_mpeg2_in_188_bytes = 1,
|
||||
|
||||
.agc_config_count = 2,
|
||||
.agc = dib807x_agc_config,
|
||||
.pll = &dib807x_bw_config_12_mhz,
|
||||
.tuner_is_baseband = 1,
|
||||
|
||||
.gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
|
||||
.gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
|
||||
.gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
|
||||
|
||||
.hostbus_diversity = 1,
|
||||
.agc_control = &dib0070_ctrl_agc_filter,
|
||||
.output_mode = OUTMODE_MPEG2_FIFO,
|
||||
.drives = 0x2d98,
|
||||
}
|
||||
};
|
||||
|
||||
static int dib807x_tuner_reset(struct dvb_frontend *fe, int onoff)
|
||||
{
|
||||
return dib8000_set_gpio(fe, 5, 0, !onoff);
|
||||
}
|
||||
|
||||
static int dib807x_tuner_sleep(struct dvb_frontend *fe, int onoff)
|
||||
{
|
||||
return dib8000_set_gpio(fe, 0, 0, onoff);
|
||||
}
|
||||
|
||||
static const struct dib0070_wbd_gain_cfg dib8070_wbd_gain_cfg[] = {
|
||||
{ 240, 7},
|
||||
{ 0xffff, 6},
|
||||
};
|
||||
|
||||
static struct dib0070_config dib807x_dib0070_config[2] = {
|
||||
{
|
||||
.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
|
||||
.reset = dib807x_tuner_reset,
|
||||
.sleep = dib807x_tuner_sleep,
|
||||
.clock_khz = 12000,
|
||||
.clock_pad_drive = 4,
|
||||
.vga_filter = 1,
|
||||
.force_crystal_mode = 1,
|
||||
.enable_third_order_filter = 1,
|
||||
.charge_pump = 0,
|
||||
.wbd_gain = dib8070_wbd_gain_cfg,
|
||||
.osc_buffer_state = 0,
|
||||
.freq_offset_khz_uhf = -100,
|
||||
.freq_offset_khz_vhf = -100,
|
||||
}, {
|
||||
.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
|
||||
.reset = dib807x_tuner_reset,
|
||||
.sleep = dib807x_tuner_sleep,
|
||||
.clock_khz = 12000,
|
||||
.clock_pad_drive = 2,
|
||||
.vga_filter = 1,
|
||||
.force_crystal_mode = 1,
|
||||
.enable_third_order_filter = 1,
|
||||
.charge_pump = 0,
|
||||
.wbd_gain = dib8070_wbd_gain_cfg,
|
||||
.osc_buffer_state = 0,
|
||||
.freq_offset_khz_uhf = -25,
|
||||
.freq_offset_khz_vhf = -25,
|
||||
}
|
||||
};
|
||||
|
||||
static int dib807x_set_param_override(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
||||
struct dib0700_adapter_state *state = adap->priv;
|
||||
|
||||
u16 offset = dib0070_wbd_offset(fe);
|
||||
u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
|
||||
switch (band) {
|
||||
case BAND_VHF:
|
||||
offset += 750;
|
||||
break;
|
||||
case BAND_UHF: /* fall-thru wanted */
|
||||
default:
|
||||
offset += 250; break;
|
||||
}
|
||||
deb_info("WBD for DiB8000: %d\n", offset);
|
||||
dib8000_set_wbd_ref(fe, offset);
|
||||
|
||||
return state->set_param_save(fe, fep);
|
||||
}
|
||||
|
||||
static int dib807x_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dib0700_adapter_state *st = adap->priv;
|
||||
struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe,
|
||||
DIBX000_I2C_INTERFACE_TUNER, 1);
|
||||
|
||||
if (adap->id == 0) {
|
||||
if (dvb_attach(dib0070_attach, adap->fe, tun_i2c,
|
||||
&dib807x_dib0070_config[0]) == NULL)
|
||||
return -ENODEV;
|
||||
} else {
|
||||
if (dvb_attach(dib0070_attach, adap->fe, tun_i2c,
|
||||
&dib807x_dib0070_config[1]) == NULL)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
st->set_param_save = adap->fe->ops.tuner_ops.set_params;
|
||||
adap->fe->ops.tuner_ops.set_params = dib807x_set_param_override;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* STK807x */
|
||||
static int stk807x_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
|
||||
msleep(10);
|
||||
dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
|
||||
dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
|
||||
dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
|
||||
|
||||
dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
|
||||
|
||||
dib0700_ctrl_clock(adap->dev, 72, 1);
|
||||
|
||||
msleep(10);
|
||||
dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
|
||||
msleep(10);
|
||||
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
|
||||
|
||||
dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
|
||||
0x80);
|
||||
|
||||
adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80,
|
||||
&dib807x_dib8000_config[0]);
|
||||
|
||||
return adap->fe == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
/* STK807xPVR */
|
||||
static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
|
||||
msleep(30);
|
||||
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
|
||||
msleep(500);
|
||||
dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
|
||||
dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
|
||||
dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
|
||||
|
||||
dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
|
||||
|
||||
dib0700_ctrl_clock(adap->dev, 72, 1);
|
||||
|
||||
msleep(10);
|
||||
dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
|
||||
msleep(10);
|
||||
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
|
||||
|
||||
/* initialize IC 0 */
|
||||
dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x80);
|
||||
|
||||
adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80,
|
||||
&dib807x_dib8000_config[0]);
|
||||
|
||||
return adap->fe == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
/* initialize IC 1 */
|
||||
dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x82);
|
||||
|
||||
adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82,
|
||||
&dib807x_dib8000_config[1]);
|
||||
|
||||
return adap->fe == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
|
||||
/* STK7070PD */
|
||||
static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
|
||||
{
|
||||
|
|
@ -1500,7 +1852,15 @@ struct usb_device_id dib0700_usb_id_table[] = {
|
|||
{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T3) },
|
||||
{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T5) },
|
||||
{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D) },
|
||||
{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D_2) },
|
||||
/* 55 */{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D_2) },
|
||||
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73A) },
|
||||
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73ESE) },
|
||||
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV282E) },
|
||||
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7770P) },
|
||||
/* 60 */{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS_2) },
|
||||
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XPVR) },
|
||||
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XP) },
|
||||
{ USB_DEVICE(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD) },
|
||||
{ 0 } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
|
||||
|
|
@ -1565,7 +1925,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
{ NULL },
|
||||
},
|
||||
{ "Leadtek Winfast DTV Dongle (STK7700P based)",
|
||||
{ &dib0700_usb_id_table[8], &dib0700_usb_id_table[34] },
|
||||
{ &dib0700_usb_id_table[8] },
|
||||
{ NULL },
|
||||
},
|
||||
{ "AVerMedia AVerTV DVB-T Express",
|
||||
|
|
@ -1762,6 +2122,41 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
.rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
|
||||
.rc_query = dib0700_rc_query
|
||||
|
||||
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.frontend_attach = stk7070p_frontend_attach,
|
||||
.tuner_attach = dib7070p_tuner_attach,
|
||||
|
||||
DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
|
||||
|
||||
.size_of_priv = sizeof(struct dib0700_adapter_state),
|
||||
},
|
||||
},
|
||||
|
||||
.num_device_descs = 3,
|
||||
.devices = {
|
||||
{ "Pinnacle PCTV 73A",
|
||||
{ &dib0700_usb_id_table[56], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ "Pinnacle PCTV 73e SE",
|
||||
{ &dib0700_usb_id_table[57], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ "Pinnacle PCTV 282e",
|
||||
{ &dib0700_usb_id_table[58], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
},
|
||||
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_key_map = dib0700_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
|
||||
.rc_query = dib0700_rc_query
|
||||
|
||||
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
|
||||
|
||||
.num_adapters = 2,
|
||||
|
|
@ -1927,6 +2322,102 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
{ NULL },
|
||||
},
|
||||
},
|
||||
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.frontend_attach = stk7070p_frontend_attach,
|
||||
.tuner_attach = dib7770p_tuner_attach,
|
||||
|
||||
DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
|
||||
|
||||
.size_of_priv =
|
||||
sizeof(struct dib0700_adapter_state),
|
||||
},
|
||||
},
|
||||
|
||||
.num_device_descs = 2,
|
||||
.devices = {
|
||||
{ "DiBcom STK7770P reference design",
|
||||
{ &dib0700_usb_id_table[59], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ "Terratec Cinergy T USB XXS (HD)",
|
||||
{ &dib0700_usb_id_table[34], &dib0700_usb_id_table[60] },
|
||||
{ NULL },
|
||||
},
|
||||
},
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_key_map = dib0700_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
|
||||
.rc_query = dib0700_rc_query
|
||||
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.frontend_attach = stk807x_frontend_attach,
|
||||
.tuner_attach = dib807x_tuner_attach,
|
||||
|
||||
DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
|
||||
|
||||
.size_of_priv =
|
||||
sizeof(struct dib0700_adapter_state),
|
||||
},
|
||||
},
|
||||
|
||||
.num_device_descs = 2,
|
||||
.devices = {
|
||||
{ "DiBcom STK807xP reference design",
|
||||
{ &dib0700_usb_id_table[62], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ "Prolink Pixelview SBTVD",
|
||||
{ &dib0700_usb_id_table[63], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
},
|
||||
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_key_map = dib0700_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
|
||||
.rc_query = dib0700_rc_query
|
||||
|
||||
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
|
||||
.num_adapters = 2,
|
||||
.adapter = {
|
||||
{
|
||||
.frontend_attach = stk807xpvr_frontend_attach0,
|
||||
.tuner_attach = dib807x_tuner_attach,
|
||||
|
||||
DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
|
||||
|
||||
.size_of_priv =
|
||||
sizeof(struct dib0700_adapter_state),
|
||||
},
|
||||
{
|
||||
.frontend_attach = stk807xpvr_frontend_attach1,
|
||||
.tuner_attach = dib807x_tuner_attach,
|
||||
|
||||
DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
|
||||
|
||||
.size_of_priv =
|
||||
sizeof(struct dib0700_adapter_state),
|
||||
},
|
||||
},
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "DiBcom STK807xPVR reference design",
|
||||
{ &dib0700_usb_id_table[61], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
},
|
||||
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_key_map = dib0700_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
|
||||
.rc_query = dib0700_rc_query
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
#define USB_VID_MSI_2 0x1462
|
||||
#define USB_VID_OPERA1 0x695c
|
||||
#define USB_VID_PINNACLE 0x2304
|
||||
#define USB_VID_PIXELVIEW 0x1554
|
||||
#define USB_VID_TECHNOTREND 0x0b48
|
||||
#define USB_VID_TERRATEC 0x0ccd
|
||||
#define USB_VID_TELESTAR 0x10b9
|
||||
|
|
@ -59,6 +60,7 @@
|
|||
#define USB_VID_YUAN 0x1164
|
||||
#define USB_VID_XTENSIONS 0x1ae7
|
||||
#define USB_VID_HUMAX_COEX 0x10b9
|
||||
#define USB_VID_774 0x7a69
|
||||
|
||||
/* Product IDs */
|
||||
#define USB_PID_ADSTECH_USB2_COLD 0xa333
|
||||
|
|
@ -95,7 +97,10 @@
|
|||
#define USB_PID_DIBCOM_STK7700_U7000 0x7001
|
||||
#define USB_PID_DIBCOM_STK7070P 0x1ebc
|
||||
#define USB_PID_DIBCOM_STK7070PD 0x1ebe
|
||||
#define USB_PID_DIBCOM_STK807XP 0x1f90
|
||||
#define USB_PID_DIBCOM_STK807XPVR 0x1f98
|
||||
#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131
|
||||
#define USB_PID_DIBCOM_STK7770P 0x1e80
|
||||
#define USB_PID_DPOSH_M9206_COLD 0x9206
|
||||
#define USB_PID_DPOSH_M9206_WARM 0xa090
|
||||
#define USB_PID_UNIWILL_STK7700P 0x6003
|
||||
|
|
@ -184,6 +189,7 @@
|
|||
#define USB_PID_TERRATEC_CINERGY_HT_EXPRESS 0x0060
|
||||
#define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062
|
||||
#define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078
|
||||
#define USB_PID_TERRATEC_CINERGY_T_XXS_2 0x00ab
|
||||
#define USB_PID_TERRATEC_T3 0x10a0
|
||||
#define USB_PID_TERRATEC_T5 0x10a1
|
||||
#define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e
|
||||
|
|
@ -195,6 +201,10 @@
|
|||
#define USB_PID_PINNACLE_PCTV73E 0x0237
|
||||
#define USB_PID_PINNACLE_PCTV801E 0x023a
|
||||
#define USB_PID_PINNACLE_PCTV801E_SE 0x023b
|
||||
#define USB_PID_PINNACLE_PCTV73A 0x0243
|
||||
#define USB_PID_PINNACLE_PCTV73ESE 0x0245
|
||||
#define USB_PID_PINNACLE_PCTV282E 0x0248
|
||||
#define USB_PID_PIXELVIEW_SBTVD 0x5010
|
||||
#define USB_PID_PCTV_200E 0x020e
|
||||
#define USB_PID_PCTV_400E 0x020f
|
||||
#define USB_PID_PCTV_450E 0x0222
|
||||
|
|
@ -265,5 +275,6 @@
|
|||
#define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020
|
||||
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000
|
||||
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001
|
||||
#define USB_PID_FRIIO_WHITE 0x0001
|
||||
|
||||
#endif
|
||||
|
|
|
|||
483
drivers/media/dvb/dvb-usb/friio-fe.c
Normal file
483
drivers/media/dvb/dvb-usb/friio-fe.c
Normal file
|
|
@ -0,0 +1,483 @@
|
|||
/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
|
||||
*
|
||||
* Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
|
||||
*
|
||||
* This module is based off the the gl861 and vp702x modules.
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "friio.h"
|
||||
|
||||
struct jdvbt90502_state {
|
||||
struct i2c_adapter *i2c;
|
||||
struct dvb_frontend frontend;
|
||||
struct jdvbt90502_config config;
|
||||
};
|
||||
|
||||
/* NOTE: TC90502 has 16bit register-address? */
|
||||
/* register 0x0100 is used for reading PLL status, so reg is u16 here */
|
||||
static int jdvbt90502_reg_read(struct jdvbt90502_state *state,
|
||||
const u16 reg, u8 *buf, const size_t count)
|
||||
{
|
||||
int ret;
|
||||
u8 wbuf[3];
|
||||
struct i2c_msg msg[2];
|
||||
|
||||
wbuf[0] = reg & 0xFF;
|
||||
wbuf[1] = 0;
|
||||
wbuf[2] = reg >> 8;
|
||||
|
||||
msg[0].addr = state->config.demod_address;
|
||||
msg[0].flags = 0;
|
||||
msg[0].buf = wbuf;
|
||||
msg[0].len = sizeof(wbuf);
|
||||
|
||||
msg[1].addr = msg[0].addr;
|
||||
msg[1].flags = I2C_M_RD;
|
||||
msg[1].buf = buf;
|
||||
msg[1].len = count;
|
||||
|
||||
ret = i2c_transfer(state->i2c, msg, 2);
|
||||
if (ret != 2) {
|
||||
deb_fe(" reg read failed.\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* currently 16bit register-address is not used, so reg is u8 here */
|
||||
static int jdvbt90502_single_reg_write(struct jdvbt90502_state *state,
|
||||
const u8 reg, const u8 val)
|
||||
{
|
||||
struct i2c_msg msg;
|
||||
u8 wbuf[2];
|
||||
|
||||
wbuf[0] = reg;
|
||||
wbuf[1] = val;
|
||||
|
||||
msg.addr = state->config.demod_address;
|
||||
msg.flags = 0;
|
||||
msg.buf = wbuf;
|
||||
msg.len = sizeof(wbuf);
|
||||
|
||||
if (i2c_transfer(state->i2c, &msg, 1) != 1) {
|
||||
deb_fe(" reg write failed.");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _jdvbt90502_write(struct dvb_frontend *fe, u8 *buf, int len)
|
||||
{
|
||||
struct jdvbt90502_state *state = fe->demodulator_priv;
|
||||
int err, i;
|
||||
for (i = 0; i < len - 1; i++) {
|
||||
err = jdvbt90502_single_reg_write(state,
|
||||
buf[0] + i, buf[i + 1]);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* read pll status byte via the demodulator's I2C register */
|
||||
/* note: Win box reads it by 8B block at the I2C addr 0x30 from reg:0x80 */
|
||||
static int jdvbt90502_pll_read(struct jdvbt90502_state *state, u8 *result)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* +1 for reading */
|
||||
u8 pll_addr_byte = (state->config.pll_address << 1) + 1;
|
||||
|
||||
*result = 0;
|
||||
|
||||
ret = jdvbt90502_single_reg_write(state, JDVBT90502_2ND_I2C_REG,
|
||||
pll_addr_byte);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = jdvbt90502_reg_read(state, 0x0100, result, 1);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
deb_fe("PLL read val:%02x\n", *result);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
deb_fe("%s:ret == %d\n", __func__, ret);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
|
||||
/* set pll frequency via the demodulator's I2C register */
|
||||
static int jdvbt90502_pll_set_freq(struct jdvbt90502_state *state, u32 freq)
|
||||
{
|
||||
int ret;
|
||||
int retry;
|
||||
u8 res1;
|
||||
u8 res2[9];
|
||||
|
||||
u8 pll_freq_cmd[PLL_CMD_LEN];
|
||||
u8 pll_agc_cmd[PLL_CMD_LEN];
|
||||
struct i2c_msg msg[2];
|
||||
u32 f;
|
||||
|
||||
deb_fe("%s: freq=%d, step=%d\n", __func__, freq,
|
||||
state->frontend.ops.info.frequency_stepsize);
|
||||
/* freq -> oscilator frequency conversion. */
|
||||
/* freq: 473,000,000 + n*6,000,000 (no 1/7MHz shift to center freq) */
|
||||
/* add 400[1/7 MHZ] = 57.142857MHz. 57MHz for the IF, */
|
||||
/* 1/7MHz for center freq shift */
|
||||
f = freq / state->frontend.ops.info.frequency_stepsize;
|
||||
f += 400;
|
||||
pll_freq_cmd[DEMOD_REDIRECT_REG] = JDVBT90502_2ND_I2C_REG; /* 0xFE */
|
||||
pll_freq_cmd[ADDRESS_BYTE] = state->config.pll_address << 1;
|
||||
pll_freq_cmd[DIVIDER_BYTE1] = (f >> 8) & 0x7F;
|
||||
pll_freq_cmd[DIVIDER_BYTE2] = f & 0xFF;
|
||||
pll_freq_cmd[CONTROL_BYTE] = 0xB2; /* ref.divider:28, 4MHz/28=1/7MHz */
|
||||
pll_freq_cmd[BANDSWITCH_BYTE] = 0x08; /* UHF band */
|
||||
|
||||
msg[0].addr = state->config.demod_address;
|
||||
msg[0].flags = 0;
|
||||
msg[0].buf = pll_freq_cmd;
|
||||
msg[0].len = sizeof(pll_freq_cmd);
|
||||
|
||||
ret = i2c_transfer(state->i2c, &msg[0], 1);
|
||||
if (ret != 1)
|
||||
goto error;
|
||||
|
||||
udelay(50);
|
||||
|
||||
pll_agc_cmd[DEMOD_REDIRECT_REG] = pll_freq_cmd[DEMOD_REDIRECT_REG];
|
||||
pll_agc_cmd[ADDRESS_BYTE] = pll_freq_cmd[ADDRESS_BYTE];
|
||||
pll_agc_cmd[DIVIDER_BYTE1] = pll_freq_cmd[DIVIDER_BYTE1];
|
||||
pll_agc_cmd[DIVIDER_BYTE2] = pll_freq_cmd[DIVIDER_BYTE2];
|
||||
pll_agc_cmd[CONTROL_BYTE] = 0x9A; /* AGC_CTRL instead of BANDSWITCH */
|
||||
pll_agc_cmd[AGC_CTRL_BYTE] = 0x50;
|
||||
/* AGC Time Constant 2s, AGC take-over point:103dBuV(lowest) */
|
||||
|
||||
msg[1].addr = msg[0].addr;
|
||||
msg[1].flags = 0;
|
||||
msg[1].buf = pll_agc_cmd;
|
||||
msg[1].len = sizeof(pll_agc_cmd);
|
||||
|
||||
ret = i2c_transfer(state->i2c, &msg[1], 1);
|
||||
if (ret != 1)
|
||||
goto error;
|
||||
|
||||
/* I don't know what these cmds are for, */
|
||||
/* but the USB log on a windows box contains them */
|
||||
ret = jdvbt90502_single_reg_write(state, 0x01, 0x40);
|
||||
ret |= jdvbt90502_single_reg_write(state, 0x01, 0x00);
|
||||
if (ret)
|
||||
goto error;
|
||||
udelay(100);
|
||||
|
||||
/* wait for the demod to be ready? */
|
||||
#define RETRY_COUNT 5
|
||||
for (retry = 0; retry < RETRY_COUNT; retry++) {
|
||||
ret = jdvbt90502_reg_read(state, 0x0096, &res1, 1);
|
||||
if (ret)
|
||||
goto error;
|
||||
/* if (res1 != 0x00) goto error; */
|
||||
ret = jdvbt90502_reg_read(state, 0x00B0, res2, sizeof(res2));
|
||||
if (ret)
|
||||
goto error;
|
||||
if (res2[0] >= 0xA7)
|
||||
break;
|
||||
msleep(100);
|
||||
}
|
||||
if (retry >= RETRY_COUNT) {
|
||||
deb_fe("%s: FE does not get ready after freq setting.\n",
|
||||
__func__);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
error:
|
||||
deb_fe("%s:ret == %d\n", __func__, ret);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
static int jdvbt90502_read_status(struct dvb_frontend *fe, fe_status_t *state)
|
||||
{
|
||||
u8 result;
|
||||
int ret;
|
||||
|
||||
*state = FE_HAS_SIGNAL;
|
||||
|
||||
ret = jdvbt90502_pll_read(fe->demodulator_priv, &result);
|
||||
if (ret) {
|
||||
deb_fe("%s:ret == %d\n", __func__, ret);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
*state = FE_HAS_SIGNAL
|
||||
| FE_HAS_CARRIER
|
||||
| FE_HAS_VITERBI
|
||||
| FE_HAS_SYNC;
|
||||
|
||||
if (result & PLL_STATUS_LOCKED)
|
||||
*state |= FE_HAS_LOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jdvbt90502_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
*ber = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jdvbt90502_read_signal_strength(struct dvb_frontend *fe,
|
||||
u16 *strength)
|
||||
{
|
||||
int ret;
|
||||
u8 rbuf[37];
|
||||
|
||||
*strength = 0;
|
||||
|
||||
/* status register (incl. signal strength) : 0x89 */
|
||||
/* TODO: read just the necessary registers [0x8B..0x8D]? */
|
||||
ret = jdvbt90502_reg_read(fe->demodulator_priv, 0x0089,
|
||||
rbuf, sizeof(rbuf));
|
||||
|
||||
if (ret) {
|
||||
deb_fe("%s:ret == %d\n", __func__, ret);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
/* signal_strength: rbuf[2-4] (24bit BE), use lower 16bit for now. */
|
||||
*strength = (rbuf[3] << 8) + rbuf[4];
|
||||
if (rbuf[2])
|
||||
*strength = 0xffff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jdvbt90502_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
*snr = 0x0101;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jdvbt90502_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
{
|
||||
*ucblocks = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jdvbt90502_get_tune_settings(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_tune_settings *fs)
|
||||
{
|
||||
fs->min_delay_ms = 500;
|
||||
fs->step_size = 0;
|
||||
fs->max_drift = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jdvbt90502_get_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *p)
|
||||
{
|
||||
p->inversion = INVERSION_AUTO;
|
||||
p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
|
||||
p->u.ofdm.code_rate_HP = FEC_AUTO;
|
||||
p->u.ofdm.code_rate_LP = FEC_AUTO;
|
||||
p->u.ofdm.constellation = QAM_64;
|
||||
p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
|
||||
p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
|
||||
p->u.ofdm.hierarchy_information = HIERARCHY_AUTO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jdvbt90502_set_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *p)
|
||||
{
|
||||
/**
|
||||
* NOTE: ignore all the paramters except frequency.
|
||||
* others should be fixed to the proper value for ISDB-T,
|
||||
* but don't check here.
|
||||
*/
|
||||
|
||||
struct jdvbt90502_state *state = fe->demodulator_priv;
|
||||
int ret;
|
||||
|
||||
deb_fe("%s: Freq:%d\n", __func__, p->frequency);
|
||||
|
||||
ret = jdvbt90502_pll_set_freq(state, p->frequency);
|
||||
if (ret) {
|
||||
deb_fe("%s:ret == %d\n", __func__, ret);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jdvbt90502_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
deb_fe("%s called.\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* (reg, val) commad list to initialize this module.
|
||||
* captured on a Windows box.
|
||||
*/
|
||||
static u8 init_code[][2] = {
|
||||
{0x01, 0x40},
|
||||
{0x04, 0x38},
|
||||
{0x05, 0x40},
|
||||
{0x07, 0x40},
|
||||
{0x0F, 0x4F},
|
||||
{0x11, 0x21},
|
||||
{0x12, 0x0B},
|
||||
{0x13, 0x2F},
|
||||
{0x14, 0x31},
|
||||
{0x16, 0x02},
|
||||
{0x21, 0xC4},
|
||||
{0x22, 0x20},
|
||||
{0x2C, 0x79},
|
||||
{0x2D, 0x34},
|
||||
{0x2F, 0x00},
|
||||
{0x30, 0x28},
|
||||
{0x31, 0x31},
|
||||
{0x32, 0xDF},
|
||||
{0x38, 0x01},
|
||||
{0x39, 0x78},
|
||||
{0x3B, 0x33},
|
||||
{0x3C, 0x33},
|
||||
{0x48, 0x90},
|
||||
{0x51, 0x68},
|
||||
{0x5E, 0x38},
|
||||
{0x71, 0x00},
|
||||
{0x72, 0x08},
|
||||
{0x77, 0x00},
|
||||
{0xC0, 0x21},
|
||||
{0xC1, 0x10},
|
||||
{0xE4, 0x1A},
|
||||
{0xEA, 0x1F},
|
||||
{0x77, 0x00},
|
||||
{0x71, 0x00},
|
||||
{0x71, 0x00},
|
||||
{0x76, 0x0C},
|
||||
};
|
||||
|
||||
const static int init_code_len = sizeof(init_code) / sizeof(u8[2]);
|
||||
|
||||
static int jdvbt90502_init(struct dvb_frontend *fe)
|
||||
{
|
||||
int i = -1;
|
||||
int ret;
|
||||
struct i2c_msg msg;
|
||||
|
||||
struct jdvbt90502_state *state = fe->demodulator_priv;
|
||||
|
||||
deb_fe("%s called.\n", __func__);
|
||||
|
||||
msg.addr = state->config.demod_address;
|
||||
msg.flags = 0;
|
||||
msg.len = 2;
|
||||
for (i = 0; i < init_code_len; i++) {
|
||||
msg.buf = init_code[i];
|
||||
ret = i2c_transfer(state->i2c, &msg, 1);
|
||||
if (ret != 1)
|
||||
goto error;
|
||||
}
|
||||
msleep(100);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
deb_fe("%s: init_code[%d] failed. ret==%d\n", __func__, i, ret);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
|
||||
static void jdvbt90502_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct jdvbt90502_state *state = fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
|
||||
static struct dvb_frontend_ops jdvbt90502_ops;
|
||||
|
||||
struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d)
|
||||
{
|
||||
struct jdvbt90502_state *state = NULL;
|
||||
|
||||
deb_info("%s called.\n", __func__);
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
state = kzalloc(sizeof(struct jdvbt90502_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
goto error;
|
||||
|
||||
/* setup the state */
|
||||
state->i2c = &d->i2c_adap;
|
||||
memcpy(&state->config, &friio_fe_config, sizeof(friio_fe_config));
|
||||
|
||||
/* create dvb_frontend */
|
||||
memcpy(&state->frontend.ops, &jdvbt90502_ops,
|
||||
sizeof(jdvbt90502_ops));
|
||||
state->frontend.demodulator_priv = state;
|
||||
|
||||
if (jdvbt90502_init(&state->frontend) < 0)
|
||||
goto error;
|
||||
|
||||
return &state->frontend;
|
||||
|
||||
error:
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops jdvbt90502_ops = {
|
||||
|
||||
.info = {
|
||||
.name = "Comtech JDVBT90502 ISDB-T",
|
||||
.type = FE_OFDM,
|
||||
.frequency_min = 473000000, /* UHF 13ch, center */
|
||||
.frequency_max = 767142857, /* UHF 62ch, center */
|
||||
.frequency_stepsize = JDVBT90502_PLL_CLK /
|
||||
JDVBT90502_PLL_DIVIDER,
|
||||
.frequency_tolerance = 0,
|
||||
|
||||
/* NOTE: this driver ignores all parameters but frequency. */
|
||||
.caps = FE_CAN_INVERSION_AUTO |
|
||||
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
|
||||
FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
|
||||
FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
|
||||
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,
|
||||
},
|
||||
|
||||
.release = jdvbt90502_release,
|
||||
|
||||
.init = jdvbt90502_init,
|
||||
.sleep = jdvbt90502_sleep,
|
||||
.write = _jdvbt90502_write,
|
||||
|
||||
.set_frontend = jdvbt90502_set_frontend,
|
||||
.get_frontend = jdvbt90502_get_frontend,
|
||||
.get_tune_settings = jdvbt90502_get_tune_settings,
|
||||
|
||||
.read_status = jdvbt90502_read_status,
|
||||
.read_ber = jdvbt90502_read_ber,
|
||||
.read_signal_strength = jdvbt90502_read_signal_strength,
|
||||
.read_snr = jdvbt90502_read_snr,
|
||||
.read_ucblocks = jdvbt90502_read_ucblocks,
|
||||
};
|
||||
525
drivers/media/dvb/dvb-usb/friio.c
Normal file
525
drivers/media/dvb/dvb-usb/friio.c
Normal file
|
|
@ -0,0 +1,525 @@
|
|||
/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
|
||||
*
|
||||
* Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
|
||||
*
|
||||
* This module is based off the the gl861 and vp702x modules.
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "friio.h"
|
||||
|
||||
/* debug */
|
||||
int dvb_usb_friio_debug;
|
||||
module_param_named(debug, dvb_usb_friio_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug,
|
||||
"set debugging level (1=info,2=xfer,4=rc,8=fe (or-able))."
|
||||
DVB_USB_DEBUG_STATUS);
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
/**
|
||||
* Indirect I2C access to the PLL via FE.
|
||||
* whole I2C protocol data to the PLL is sent via the FE's I2C register.
|
||||
* This is done by a control msg to the FE with the I2C data accompanied, and
|
||||
* a specific USB request number is assigned for that purpose.
|
||||
*
|
||||
* this func sends wbuf[1..] to the I2C register wbuf[0] at addr (= at FE).
|
||||
* TODO: refoctored, smarter i2c functions.
|
||||
*/
|
||||
static int gl861_i2c_ctrlmsg_data(struct dvb_usb_device *d, u8 addr,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
u16 index = wbuf[0]; /* must be JDVBT90502_2ND_I2C_REG(=0xFE) */
|
||||
u16 value = addr << (8 + 1);
|
||||
int wo = (rbuf == NULL || rlen == 0); /* write only */
|
||||
u8 req, type;
|
||||
|
||||
deb_xfer("write to PLL:0x%02x via FE reg:0x%02x, len:%d\n",
|
||||
wbuf[1], wbuf[0], wlen - 1);
|
||||
|
||||
if (wo && wlen >= 2) {
|
||||
req = GL861_REQ_I2C_DATA_CTRL_WRITE;
|
||||
type = GL861_WRITE;
|
||||
udelay(20);
|
||||
return usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
|
||||
req, type, value, index,
|
||||
&wbuf[1], wlen - 1, 2000);
|
||||
}
|
||||
|
||||
deb_xfer("not supported ctrl-msg, aborting.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* normal I2C access (without extra data arguments).
|
||||
* write to the register wbuf[0] at I2C address addr with the value wbuf[1],
|
||||
* or read from the register wbuf[0].
|
||||
* register address can be 16bit (wbuf[2]<<8 | wbuf[0]) if wlen==3
|
||||
*/
|
||||
static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
u16 index;
|
||||
u16 value = addr << (8 + 1);
|
||||
int wo = (rbuf == NULL || rlen == 0); /* write-only */
|
||||
u8 req, type;
|
||||
unsigned int pipe;
|
||||
|
||||
/* special case for the indirect I2C access to the PLL via FE, */
|
||||
if (addr == friio_fe_config.demod_address &&
|
||||
wbuf[0] == JDVBT90502_2ND_I2C_REG)
|
||||
return gl861_i2c_ctrlmsg_data(d, addr, wbuf, wlen, rbuf, rlen);
|
||||
|
||||
if (wo) {
|
||||
req = GL861_REQ_I2C_WRITE;
|
||||
type = GL861_WRITE;
|
||||
pipe = usb_sndctrlpipe(d->udev, 0);
|
||||
} else { /* rw */
|
||||
req = GL861_REQ_I2C_READ;
|
||||
type = GL861_READ;
|
||||
pipe = usb_rcvctrlpipe(d->udev, 0);
|
||||
}
|
||||
|
||||
switch (wlen) {
|
||||
case 1:
|
||||
index = wbuf[0];
|
||||
break;
|
||||
case 2:
|
||||
index = wbuf[0];
|
||||
value = value + wbuf[1];
|
||||
break;
|
||||
case 3:
|
||||
/* special case for 16bit register-address */
|
||||
index = (wbuf[2] << 8) | wbuf[0];
|
||||
value = value + wbuf[1];
|
||||
break;
|
||||
default:
|
||||
deb_xfer("wlen = %x, aborting.", wlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
msleep(1);
|
||||
return usb_control_msg(d->udev, pipe, req, type,
|
||||
value, index, rbuf, rlen, 2000);
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i;
|
||||
|
||||
|
||||
if (num > 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* write/read request */
|
||||
if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) {
|
||||
if (gl861_i2c_msg(d, msg[i].addr,
|
||||
msg[i].buf, msg[i].len,
|
||||
msg[i + 1].buf, msg[i + 1].len) < 0)
|
||||
break;
|
||||
i++;
|
||||
} else
|
||||
if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, NULL, 0) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 gl861_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
|
||||
static int friio_ext_ctl(struct dvb_usb_adapter *adap,
|
||||
u32 sat_color, int lnb_on)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
struct i2c_msg msg;
|
||||
u8 buf[2];
|
||||
u32 mask;
|
||||
u8 lnb = (lnb_on) ? FRIIO_CTL_LNB : 0;
|
||||
|
||||
msg.addr = 0x00;
|
||||
msg.flags = 0;
|
||||
msg.len = 2;
|
||||
msg.buf = buf;
|
||||
|
||||
buf[0] = 0x00;
|
||||
|
||||
/* send 2bit header (&B10) */
|
||||
buf[1] = lnb | FRIIO_CTL_LED | FRIIO_CTL_STROBE;
|
||||
ret = gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
|
||||
buf[1] |= FRIIO_CTL_CLK;
|
||||
ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
|
||||
|
||||
buf[1] = lnb | FRIIO_CTL_STROBE;
|
||||
ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
|
||||
buf[1] |= FRIIO_CTL_CLK;
|
||||
ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
|
||||
|
||||
/* send 32bit(satur, R, G, B) data in serial */
|
||||
mask = 1 << 31;
|
||||
for (i = 0; i < 32; i++) {
|
||||
buf[1] = lnb | FRIIO_CTL_STROBE;
|
||||
if (sat_color & mask)
|
||||
buf[1] |= FRIIO_CTL_LED;
|
||||
ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
|
||||
buf[1] |= FRIIO_CTL_CLK;
|
||||
ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
|
||||
mask >>= 1;
|
||||
}
|
||||
|
||||
/* set the strobe off */
|
||||
buf[1] = lnb;
|
||||
ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
|
||||
buf[1] |= FRIIO_CTL_CLK;
|
||||
ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
|
||||
|
||||
return (ret == 70);
|
||||
}
|
||||
|
||||
|
||||
static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
|
||||
|
||||
/* TODO: move these init cmds to the FE's init routine? */
|
||||
static u8 streaming_init_cmds[][2] = {
|
||||
{0x33, 0x08},
|
||||
{0x37, 0x40},
|
||||
{0x3A, 0x1F},
|
||||
{0x3B, 0xFF},
|
||||
{0x3C, 0x1F},
|
||||
{0x3D, 0xFF},
|
||||
{0x38, 0x00},
|
||||
{0x35, 0x00},
|
||||
{0x39, 0x00},
|
||||
{0x36, 0x00},
|
||||
};
|
||||
static int cmdlen = sizeof(streaming_init_cmds) / 2;
|
||||
|
||||
/*
|
||||
* Command sequence in this init function is a replay
|
||||
* of the captured USB commands from the Windows proprietary driver.
|
||||
*/
|
||||
static int friio_initialize(struct dvb_usb_device *d)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
int retry = 0;
|
||||
u8 rbuf[2];
|
||||
u8 wbuf[3];
|
||||
|
||||
deb_info("%s called.\n", __func__);
|
||||
|
||||
/* use gl861_i2c_msg instead of gl861_i2c_xfer(), */
|
||||
/* because the i2c device is not set up yet. */
|
||||
wbuf[0] = 0x11;
|
||||
wbuf[1] = 0x02;
|
||||
ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
msleep(2);
|
||||
|
||||
wbuf[0] = 0x11;
|
||||
wbuf[1] = 0x00;
|
||||
ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
msleep(1);
|
||||
|
||||
/* following msgs should be in the FE's init code? */
|
||||
/* cmd sequence to identify the device type? (friio black/white) */
|
||||
wbuf[0] = 0x03;
|
||||
wbuf[1] = 0x80;
|
||||
/* can't use gl861_i2c_cmd, as the register-addr is 16bit(0x0100) */
|
||||
ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
|
||||
GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE,
|
||||
0x1200, 0x0100, wbuf, 2, 2000);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
msleep(2);
|
||||
wbuf[0] = 0x00;
|
||||
wbuf[2] = 0x01; /* reg.0x0100 */
|
||||
wbuf[1] = 0x00;
|
||||
ret = gl861_i2c_msg(d, 0x12 >> 1, wbuf, 3, rbuf, 2);
|
||||
/* my Friio White returns 0xffff. */
|
||||
if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff)
|
||||
goto error;
|
||||
|
||||
msleep(2);
|
||||
wbuf[0] = 0x03;
|
||||
wbuf[1] = 0x80;
|
||||
ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
|
||||
GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE,
|
||||
0x9000, 0x0100, wbuf, 2, 2000);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
msleep(2);
|
||||
wbuf[0] = 0x00;
|
||||
wbuf[2] = 0x01; /* reg.0x0100 */
|
||||
wbuf[1] = 0x00;
|
||||
ret = gl861_i2c_msg(d, 0x90 >> 1, wbuf, 3, rbuf, 2);
|
||||
/* my Friio White returns 0xffff again. */
|
||||
if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff)
|
||||
goto error;
|
||||
|
||||
msleep(1);
|
||||
|
||||
restart:
|
||||
/* ============ start DEMOD init cmds ================== */
|
||||
/* read PLL status to clear the POR bit */
|
||||
wbuf[0] = JDVBT90502_2ND_I2C_REG;
|
||||
wbuf[1] = (FRIIO_PLL_ADDR << 1) + 1; /* +1 for reading */
|
||||
ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, NULL, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
msleep(5);
|
||||
/* note: DEMODULATOR has 16bit register-address. */
|
||||
wbuf[0] = 0x00;
|
||||
wbuf[2] = 0x01; /* reg addr: 0x0100 */
|
||||
wbuf[1] = 0x00; /* val: not used */
|
||||
ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 3, rbuf, 1);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
/*
|
||||
msleep(1);
|
||||
wbuf[0] = 0x80;
|
||||
wbuf[1] = 0x00;
|
||||
ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, rbuf, 1);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
*/
|
||||
if (rbuf[0] & 0x80) { /* still in PowerOnReset state? */
|
||||
if (++retry > 3) {
|
||||
deb_info("failed to get the correct"
|
||||
" FE demod status:0x%02x\n", rbuf[0]);
|
||||
goto error;
|
||||
}
|
||||
msleep(100);
|
||||
goto restart;
|
||||
}
|
||||
|
||||
/* TODO: check return value in rbuf */
|
||||
/* =========== end DEMOD init cmds ===================== */
|
||||
msleep(1);
|
||||
|
||||
wbuf[0] = 0x30;
|
||||
wbuf[1] = 0x04;
|
||||
ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
msleep(2);
|
||||
/* following 2 cmds unnecessary? */
|
||||
wbuf[0] = 0x00;
|
||||
wbuf[1] = 0x01;
|
||||
ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
wbuf[0] = 0x06;
|
||||
wbuf[1] = 0x0F;
|
||||
ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
/* some streaming ctl cmds (maybe) */
|
||||
msleep(10);
|
||||
for (i = 0; i < cmdlen; i++) {
|
||||
ret = gl861_i2c_msg(d, 0x00, streaming_init_cmds[i], 2,
|
||||
NULL, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
msleep(1);
|
||||
}
|
||||
msleep(20);
|
||||
|
||||
/* change the LED color etc. */
|
||||
ret = friio_streaming_ctrl(&d->adapter[0], 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
deb_info("%s:ret == %d\n", __func__, ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
|
||||
static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
int ret;
|
||||
|
||||
deb_info("%s called.(%d)\n", __func__, onoff);
|
||||
|
||||
/* set the LED color and saturation (and LNB on) */
|
||||
if (onoff)
|
||||
ret = friio_ext_ctl(adap, 0x6400ff64, 1);
|
||||
else
|
||||
ret = friio_ext_ctl(adap, 0x96ff00ff, 1);
|
||||
|
||||
if (ret != 1) {
|
||||
deb_info("%s failed to send cmdx. ret==%d\n", __func__, ret);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int friio_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if (friio_initialize(adap->dev) < 0)
|
||||
return -EIO;
|
||||
|
||||
adap->fe = jdvbt90502_attach(adap->dev);
|
||||
if (adap->fe == NULL)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties friio_properties;
|
||||
|
||||
static int friio_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct dvb_usb_device *d;
|
||||
struct usb_host_interface *alt;
|
||||
int ret;
|
||||
|
||||
if (intf->num_altsetting < GL861_ALTSETTING_COUNT)
|
||||
return -ENODEV;
|
||||
|
||||
alt = usb_altnum_to_altsetting(intf, FRIIO_BULK_ALTSETTING);
|
||||
if (alt == NULL) {
|
||||
deb_rc("not alt found!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = usb_set_interface(interface_to_usbdev(intf),
|
||||
alt->desc.bInterfaceNumber,
|
||||
alt->desc.bAlternateSetting);
|
||||
if (ret != 0) {
|
||||
deb_rc("failed to set alt-setting!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dvb_usb_device_init(intf, &friio_properties,
|
||||
THIS_MODULE, &d, adapter_nr);
|
||||
if (ret == 0)
|
||||
friio_streaming_ctrl(&d->adapter[0], 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct jdvbt90502_config friio_fe_config = {
|
||||
.demod_address = FRIIO_DEMOD_ADDR,
|
||||
.pll_address = FRIIO_PLL_ADDR,
|
||||
};
|
||||
|
||||
static struct i2c_algorithm gl861_i2c_algo = {
|
||||
.master_xfer = gl861_i2c_xfer,
|
||||
.functionality = gl861_i2c_func,
|
||||
};
|
||||
|
||||
static struct usb_device_id friio_table[] = {
|
||||
{ USB_DEVICE(USB_VID_774, USB_PID_FRIIO_WHITE) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, friio_table);
|
||||
|
||||
|
||||
static struct dvb_usb_device_properties friio_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
|
||||
.size_of_priv = 0,
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
/* caps:0 => no pid filter, 188B TS packet */
|
||||
/* GL861 has a HW pid filter, but no info available. */
|
||||
{
|
||||
.caps = 0,
|
||||
|
||||
.frontend_attach = friio_frontend_attach,
|
||||
.streaming_ctrl = friio_streaming_ctrl,
|
||||
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
/* count <= MAX_NO_URBS_FOR_DATA_STREAM(10) */
|
||||
.count = 8,
|
||||
.endpoint = 0x01,
|
||||
.u = {
|
||||
/* GL861 has 6KB buf inside */
|
||||
.bulk = {
|
||||
.buffersize = 16384,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
.i2c_algo = &gl861_i2c_algo,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{
|
||||
.name = "774 Friio ISDB-T USB2.0",
|
||||
.cold_ids = { NULL },
|
||||
.warm_ids = { &friio_table[0], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver friio_driver = {
|
||||
.name = "dvb_usb_friio",
|
||||
.probe = friio_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = friio_table,
|
||||
};
|
||||
|
||||
|
||||
/* module stuff */
|
||||
static int __init friio_module_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_register(&friio_driver);
|
||||
if (ret)
|
||||
err("usb_register failed. Error number %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void __exit friio_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&friio_driver);
|
||||
}
|
||||
|
||||
module_init(friio_module_init);
|
||||
module_exit(friio_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Akihiro Tsukada <[email protected]>");
|
||||
MODULE_DESCRIPTION("Driver for Friio ISDB-T USB2.0 Receiver");
|
||||
MODULE_VERSION("0.2");
|
||||
MODULE_LICENSE("GPL");
|
||||
99
drivers/media/dvb/dvb-usb/friio.h
Normal file
99
drivers/media/dvb/dvb-usb/friio.h
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
|
||||
*
|
||||
* Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
|
||||
*
|
||||
* This module is based off the the gl861 and vp702x modules.
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#ifndef _DVB_USB_FRIIO_H_
|
||||
#define _DVB_USB_FRIIO_H_
|
||||
|
||||
/**
|
||||
* Friio Components
|
||||
* USB hub: AU4254
|
||||
* USB controller(+ TS dmx & streaming): GL861
|
||||
* Frontend: comtech JDVBT-90502
|
||||
* (tuner PLL: tua6034, I2C addr:(0xC0 >> 1))
|
||||
* (OFDM demodulator: TC90502, I2C addr:(0x30 >> 1))
|
||||
* LED x3 (+LNB) controll: PIC 16F676
|
||||
* EEPROM: 24C08
|
||||
*
|
||||
* (USB smart card reader: AU9522)
|
||||
*
|
||||
*/
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "friio"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
extern int dvb_usb_friio_debug;
|
||||
#define deb_info(args...) dprintk(dvb_usb_friio_debug, 0x01, args)
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_friio_debug, 0x02, args)
|
||||
#define deb_rc(args...) dprintk(dvb_usb_friio_debug, 0x04, args)
|
||||
#define deb_fe(args...) dprintk(dvb_usb_friio_debug, 0x08, args)
|
||||
|
||||
/* Vendor requests */
|
||||
#define GL861_WRITE 0x40
|
||||
#define GL861_READ 0xc0
|
||||
|
||||
/* command bytes */
|
||||
#define GL861_REQ_I2C_WRITE 0x01
|
||||
#define GL861_REQ_I2C_READ 0x02
|
||||
/* For control msg with data argument */
|
||||
/* Used for accessing the PLL on the secondary I2C bus of FE via GL861 */
|
||||
#define GL861_REQ_I2C_DATA_CTRL_WRITE 0x03
|
||||
|
||||
#define GL861_ALTSETTING_COUNT 2
|
||||
#define FRIIO_BULK_ALTSETTING 0
|
||||
#define FRIIO_ISOC_ALTSETTING 1
|
||||
|
||||
/* LED & LNB control via PIC. */
|
||||
/* basically, it's serial control with clock and strobe. */
|
||||
/* write the below 4bit control data to the reg 0x00 at the I2C addr 0x00 */
|
||||
/* when controlling the LEDs, 32bit(saturation, R, G, B) is sent on the bit3*/
|
||||
#define FRIIO_CTL_LNB (1 << 0)
|
||||
#define FRIIO_CTL_STROBE (1 << 1)
|
||||
#define FRIIO_CTL_CLK (1 << 2)
|
||||
#define FRIIO_CTL_LED (1 << 3)
|
||||
|
||||
/* Front End related */
|
||||
|
||||
#define FRIIO_DEMOD_ADDR (0x30 >> 1)
|
||||
#define FRIIO_PLL_ADDR (0xC0 >> 1)
|
||||
|
||||
#define JDVBT90502_PLL_CLK 4000000
|
||||
#define JDVBT90502_PLL_DIVIDER 28
|
||||
|
||||
#define JDVBT90502_2ND_I2C_REG 0xFE
|
||||
|
||||
/* byte index for pll i2c command data structure*/
|
||||
/* see datasheet for tua6034 */
|
||||
#define DEMOD_REDIRECT_REG 0
|
||||
#define ADDRESS_BYTE 1
|
||||
#define DIVIDER_BYTE1 2
|
||||
#define DIVIDER_BYTE2 3
|
||||
#define CONTROL_BYTE 4
|
||||
#define BANDSWITCH_BYTE 5
|
||||
#define AGC_CTRL_BYTE 5
|
||||
#define PLL_CMD_LEN 6
|
||||
|
||||
/* bit masks for PLL STATUS response */
|
||||
#define PLL_STATUS_POR_MODE 0x80 /* 1: Power on Reset (test) Mode */
|
||||
#define PLL_STATUS_LOCKED 0x40 /* 1: locked */
|
||||
#define PLL_STATUS_AGC_ACTIVE 0x08 /* 1:active */
|
||||
#define PLL_STATUS_TESTMODE 0x07 /* digital output level (5 level) */
|
||||
/* 0.15Vcc step 0x00: < 0.15Vcc, ..., 0x04: >= 0.6Vcc (<= 1Vcc) */
|
||||
|
||||
|
||||
struct jdvbt90502_config {
|
||||
u8 demod_address; /* i2c addr for demodulator IC */
|
||||
u8 pll_address; /* PLL addr on the secondary i2c*/
|
||||
};
|
||||
extern struct jdvbt90502_config friio_fe_config;
|
||||
|
||||
extern struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d);
|
||||
#endif
|
||||
|
|
@ -337,6 +337,8 @@ static int m920x_firmware_download(struct usb_device *udev, const struct firmwar
|
|||
int i, pass, ret = 0;
|
||||
|
||||
buff = kmalloc(65536, GFP_KERNEL);
|
||||
if (buff == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if ((ret = m920x_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -484,6 +484,14 @@ config DVB_S921
|
|||
AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module.
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_DIB8000
|
||||
tristate "DiBcom 8000MB/MC"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
A driver for DiBcom's DiB8000 ISDB-T/ISDB-Tsb demodulator.
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
comment "Digital terrestrial only tuners/PLL"
|
||||
depends on DVB_CORE
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o
|
|||
obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o
|
||||
obj-$(CONFIG_DVB_DIB7000M) += dib7000m.o dibx000_common.o
|
||||
obj-$(CONFIG_DVB_DIB7000P) += dib7000p.o dibx000_common.o
|
||||
obj-$(CONFIG_DVB_DIB8000) += dib8000.o dibx000_common.o
|
||||
obj-$(CONFIG_DVB_MT312) += mt312.o
|
||||
obj-$(CONFIG_DVB_VES1820) += ves1820.o
|
||||
obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
|
||||
|
|
|
|||
|
|
@ -792,6 +792,11 @@ static int au8522_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
demod_config = kzalloc(sizeof(struct au8522_config), GFP_KERNEL);
|
||||
if (demod_config == NULL) {
|
||||
if (instance == 1)
|
||||
kfree(state);
|
||||
return -ENOMEM;
|
||||
}
|
||||
demod_config->demod_address = 0x8e >> 1;
|
||||
|
||||
state->config = demod_config;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -15,6 +15,11 @@ struct i2c_adapter;
|
|||
|
||||
#define DEFAULT_DIB0070_I2C_ADDRESS 0x60
|
||||
|
||||
struct dib0070_wbd_gain_cfg {
|
||||
u16 freq;
|
||||
u16 wbd_gain_val;
|
||||
};
|
||||
|
||||
struct dib0070_config {
|
||||
u8 i2c_address;
|
||||
|
||||
|
|
@ -26,26 +31,28 @@ struct dib0070_config {
|
|||
int freq_offset_khz_uhf;
|
||||
int freq_offset_khz_vhf;
|
||||
|
||||
u8 osc_buffer_state; /* 0= normal, 1= tri-state */
|
||||
u32 clock_khz;
|
||||
u8 clock_pad_drive; /* (Drive + 1) * 2mA */
|
||||
u8 osc_buffer_state; /* 0= normal, 1= tri-state */
|
||||
u32 clock_khz;
|
||||
u8 clock_pad_drive; /* (Drive + 1) * 2mA */
|
||||
|
||||
u8 invert_iq; /* invert Q - in case I or Q is inverted on the board */
|
||||
u8 invert_iq; /* invert Q - in case I or Q is inverted on the board */
|
||||
|
||||
u8 force_crystal_mode; /* if == 0 -> decision is made in the driver default: <24 -> 2, >=24 -> 1 */
|
||||
u8 force_crystal_mode; /* if == 0 -> decision is made in the driver default: <24 -> 2, >=24 -> 1 */
|
||||
|
||||
u8 flip_chip;
|
||||
u8 enable_third_order_filter;
|
||||
u8 charge_pump;
|
||||
|
||||
const struct dib0070_wbd_gain_cfg *wbd_gain;
|
||||
|
||||
u8 vga_filter;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_TUNER_DIB0070) || (defined(CONFIG_DVB_TUNER_DIB0070_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c,
|
||||
struct dib0070_config *cfg);
|
||||
extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg);
|
||||
extern u16 dib0070_wbd_offset(struct dvb_frontend *);
|
||||
#else
|
||||
static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c,
|
||||
struct dib0070_config *cfg)
|
||||
static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
|
|
@ -57,5 +64,6 @@ static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe)
|
|||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, u8 open);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#include "dvb_math.h"
|
||||
#include "dvb_frontend.h"
|
||||
|
||||
#include "dib7000p.h"
|
||||
|
|
@ -1217,7 +1218,37 @@ static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
|
|||
|
||||
static int dib7000p_read_snr(struct dvb_frontend* fe, u16 *snr)
|
||||
{
|
||||
*snr = 0x0000;
|
||||
struct dib7000p_state *state = fe->demodulator_priv;
|
||||
u16 val;
|
||||
s32 signal_mant, signal_exp, noise_mant, noise_exp;
|
||||
u32 result = 0;
|
||||
|
||||
val = dib7000p_read_word(state, 479);
|
||||
noise_mant = (val >> 4) & 0xff;
|
||||
noise_exp = ((val & 0xf) << 2);
|
||||
val = dib7000p_read_word(state, 480);
|
||||
noise_exp += ((val >> 14) & 0x3);
|
||||
if ((noise_exp & 0x20) != 0)
|
||||
noise_exp -= 0x40;
|
||||
|
||||
signal_mant = (val >> 6) & 0xFF;
|
||||
signal_exp = (val & 0x3F);
|
||||
if ((signal_exp & 0x20) != 0)
|
||||
signal_exp -= 0x40;
|
||||
|
||||
if (signal_mant != 0)
|
||||
result = intlog10(2) * 10 * signal_exp + 10 *
|
||||
intlog10(signal_mant);
|
||||
else
|
||||
result = intlog10(2) * 10 * signal_exp - 100;
|
||||
|
||||
if (noise_mant != 0)
|
||||
result -= intlog10(2) * 10 * noise_exp + 10 *
|
||||
intlog10(noise_mant);
|
||||
else
|
||||
result -= intlog10(2) * 10 * noise_exp - 100;
|
||||
|
||||
*snr = result / ((1 << 24) / 10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
2277
drivers/media/dvb/frontends/dib8000.c
Normal file
2277
drivers/media/dvb/frontends/dib8000.c
Normal file
File diff suppressed because it is too large
Load diff
79
drivers/media/dvb/frontends/dib8000.h
Normal file
79
drivers/media/dvb/frontends/dib8000.h
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#ifndef DIB8000_H
|
||||
#define DIB8000_H
|
||||
|
||||
#include "dibx000_common.h"
|
||||
|
||||
struct dib8000_config {
|
||||
u8 output_mpeg2_in_188_bytes;
|
||||
u8 hostbus_diversity;
|
||||
u8 tuner_is_baseband;
|
||||
int (*update_lna) (struct dvb_frontend *, u16 agc_global);
|
||||
|
||||
u8 agc_config_count;
|
||||
struct dibx000_agc_config *agc;
|
||||
struct dibx000_bandwidth_config *pll;
|
||||
|
||||
#define DIB8000_GPIO_DEFAULT_DIRECTIONS 0xffff
|
||||
u16 gpio_dir;
|
||||
#define DIB8000_GPIO_DEFAULT_VALUES 0x0000
|
||||
u16 gpio_val;
|
||||
#define DIB8000_GPIO_PWM_POS0(v) ((v & 0xf) << 12)
|
||||
#define DIB8000_GPIO_PWM_POS1(v) ((v & 0xf) << 8 )
|
||||
#define DIB8000_GPIO_PWM_POS2(v) ((v & 0xf) << 4 )
|
||||
#define DIB8000_GPIO_PWM_POS3(v) (v & 0xf)
|
||||
#define DIB8000_GPIO_DEFAULT_PWM_POS 0xffff
|
||||
u16 gpio_pwm_pos;
|
||||
u16 pwm_freq_div;
|
||||
|
||||
void (*agc_control) (struct dvb_frontend *, u8 before);
|
||||
|
||||
u16 drives;
|
||||
u16 diversity_delay;
|
||||
u8 div_cfg;
|
||||
u8 output_mode;
|
||||
u8 refclksel;
|
||||
};
|
||||
|
||||
#define DEFAULT_DIB8000_I2C_ADDRESS 18
|
||||
|
||||
#if defined(CONFIG_DVB_DIB8000) || (defined(CONFIG_DVB_DIB8000_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg);
|
||||
extern struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
|
||||
|
||||
extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr);
|
||||
|
||||
extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
|
||||
extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value);
|
||||
#else
|
||||
static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface i, int x)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -15,29 +15,31 @@ static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
|
|||
(val >> 8) & 0xff, val & 0xff,
|
||||
};
|
||||
struct i2c_msg msg = {
|
||||
.addr = mst->i2c_addr, .flags = 0, .buf = b, .len = 4
|
||||
.addr = mst->i2c_addr,.flags = 0,.buf = b,.len = 4
|
||||
};
|
||||
return i2c_transfer(mst->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
|
||||
}
|
||||
|
||||
|
||||
static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf)
|
||||
static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst,
|
||||
enum dibx000_i2c_interface intf)
|
||||
{
|
||||
if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) {
|
||||
dprintk("selecting interface: %d\n",intf);
|
||||
dprintk("selecting interface: %d\n", intf);
|
||||
mst->selected_interface = intf;
|
||||
return dibx000_write_word(mst, mst->base_reg + 4, intf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4], u8 addr, int onoff)
|
||||
static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4],
|
||||
u8 addr, int onoff)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
|
||||
if (onoff)
|
||||
val = addr << 8; // bit 7 = use master or not, if 0, the gate is open
|
||||
val = addr << 8; // bit 7 = use master or not, if 0, the gate is open
|
||||
else
|
||||
val = 1 << 7;
|
||||
|
||||
|
|
@ -45,7 +47,7 @@ static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4], u8 ad
|
|||
val <<= 1;
|
||||
|
||||
tx[0] = (((mst->base_reg + 1) >> 8) & 0xff);
|
||||
tx[1] = ( (mst->base_reg + 1) & 0xff);
|
||||
tx[1] = ((mst->base_reg + 1) & 0xff);
|
||||
tx[2] = val >> 8;
|
||||
tx[3] = val & 0xff;
|
||||
|
||||
|
|
@ -57,59 +59,78 @@ static u32 dibx000_i2c_func(struct i2c_adapter *adapter)
|
|||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
|
||||
static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap,
|
||||
struct i2c_msg msg[], int num)
|
||||
{
|
||||
struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
|
||||
struct i2c_msg m[2 + num];
|
||||
u8 tx_open[4], tx_close[4];
|
||||
|
||||
memset(m,0, sizeof(struct i2c_msg) * (2 + num));
|
||||
memset(m, 0, sizeof(struct i2c_msg) * (2 + num));
|
||||
|
||||
dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
|
||||
|
||||
dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1);
|
||||
dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1);
|
||||
m[0].addr = mst->i2c_addr;
|
||||
m[0].buf = tx_open;
|
||||
m[0].len = 4;
|
||||
m[0].buf = tx_open;
|
||||
m[0].len = 4;
|
||||
|
||||
memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
|
||||
|
||||
dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0);
|
||||
m[num+1].addr = mst->i2c_addr;
|
||||
m[num+1].buf = tx_close;
|
||||
m[num+1].len = 4;
|
||||
m[num + 1].addr = mst->i2c_addr;
|
||||
m[num + 1].buf = tx_close;
|
||||
m[num + 1].len = 4;
|
||||
|
||||
return i2c_transfer(mst->i2c_adap, m, 2+num) == 2 + num ? num : -EIO;
|
||||
return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
|
||||
.master_xfer = dibx000_i2c_gated_tuner_xfer,
|
||||
.master_xfer = dibx000_i2c_gated_tuner_xfer,
|
||||
.functionality = dibx000_i2c_func,
|
||||
};
|
||||
|
||||
struct i2c_adapter * dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf, int gating)
|
||||
struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst,
|
||||
enum dibx000_i2c_interface intf,
|
||||
int gating)
|
||||
{
|
||||
struct i2c_adapter *i2c = NULL;
|
||||
|
||||
switch (intf) {
|
||||
case DIBX000_I2C_INTERFACE_TUNER:
|
||||
if (gating)
|
||||
i2c = &mst->gated_tuner_i2c_adap;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n");
|
||||
break;
|
||||
case DIBX000_I2C_INTERFACE_TUNER:
|
||||
if (gating)
|
||||
i2c = &mst->gated_tuner_i2c_adap;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return i2c;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(dibx000_get_i2c_adapter);
|
||||
|
||||
static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char *name, struct dibx000_i2c_master *mst)
|
||||
void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst)
|
||||
{
|
||||
/* initialize the i2c-master by closing the gate */
|
||||
u8 tx[4];
|
||||
struct i2c_msg m = {.addr = mst->i2c_addr,.buf = tx,.len = 4 };
|
||||
|
||||
dibx000_i2c_gate_ctrl(mst, tx, 0, 0);
|
||||
i2c_transfer(mst->i2c_adap, &m, 1);
|
||||
mst->selected_interface = 0xff; // the first time force a select of the I2C
|
||||
dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(dibx000_reset_i2c_master);
|
||||
|
||||
static int i2c_adapter_init(struct i2c_adapter *i2c_adap,
|
||||
struct i2c_algorithm *algo, const char *name,
|
||||
struct dibx000_i2c_master *mst)
|
||||
{
|
||||
strncpy(i2c_adap->name, name, sizeof(i2c_adap->name));
|
||||
i2c_adap->class = I2C_CLASS_TV_DIGITAL,
|
||||
i2c_adap->algo = algo;
|
||||
i2c_adap->class = I2C_CLASS_TV_DIGITAL, i2c_adap->algo = algo;
|
||||
i2c_adap->algo_data = NULL;
|
||||
i2c_set_adapdata(i2c_adap, mst);
|
||||
if (i2c_add_adapter(i2c_adap) < 0)
|
||||
|
|
@ -117,34 +138,40 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *
|
|||
return 0;
|
||||
}
|
||||
|
||||
int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, struct i2c_adapter *i2c_adap, u8 i2c_addr)
|
||||
int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev,
|
||||
struct i2c_adapter *i2c_adap, u8 i2c_addr)
|
||||
{
|
||||
u8 tx[4];
|
||||
struct i2c_msg m = { .addr = i2c_addr >> 1, .buf = tx, .len = 4 };
|
||||
struct i2c_msg m = {.addr = i2c_addr >> 1,.buf = tx,.len = 4 };
|
||||
|
||||
mst->device_rev = device_rev;
|
||||
mst->i2c_adap = i2c_adap;
|
||||
mst->i2c_addr = i2c_addr >> 1;
|
||||
mst->i2c_adap = i2c_adap;
|
||||
mst->i2c_addr = i2c_addr >> 1;
|
||||
|
||||
if (device_rev == DIB7000P)
|
||||
if (device_rev == DIB7000P || device_rev == DIB8000)
|
||||
mst->base_reg = 1024;
|
||||
else
|
||||
mst->base_reg = 768;
|
||||
|
||||
if (i2c_adapter_init(&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo, "DiBX000 tuner I2C bus", mst) != 0)
|
||||
printk(KERN_ERR "DiBX000: could not initialize the tuner i2c_adapter\n");
|
||||
if (i2c_adapter_init
|
||||
(&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo,
|
||||
"DiBX000 tuner I2C bus", mst) != 0)
|
||||
printk(KERN_ERR
|
||||
"DiBX000: could not initialize the tuner i2c_adapter\n");
|
||||
|
||||
/* initialize the i2c-master by closing the gate */
|
||||
dibx000_i2c_gate_ctrl(mst, tx, 0, 0);
|
||||
|
||||
return i2c_transfer(i2c_adap, &m, 1) == 1;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(dibx000_init_i2c_master);
|
||||
|
||||
void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst)
|
||||
{
|
||||
i2c_del_adapter(&mst->gated_tuner_i2c_adap);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(dibx000_exit_i2c_master);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <[email protected]>");
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#define DIBX000_COMMON_H
|
||||
|
||||
enum dibx000_i2c_interface {
|
||||
DIBX000_I2C_INTERFACE_TUNER = 0,
|
||||
DIBX000_I2C_INTERFACE_TUNER = 0,
|
||||
DIBX000_I2C_INTERFACE_GPIO_1_2 = 1,
|
||||
DIBX000_I2C_INTERFACE_GPIO_3_4 = 2
|
||||
};
|
||||
|
|
@ -12,22 +12,29 @@ struct dibx000_i2c_master {
|
|||
#define DIB7000 2
|
||||
#define DIB7000P 11
|
||||
#define DIB7000MC 12
|
||||
#define DIB8000 13
|
||||
u16 device_rev;
|
||||
|
||||
enum dibx000_i2c_interface selected_interface;
|
||||
|
||||
// struct i2c_adapter tuner_i2c_adap;
|
||||
struct i2c_adapter gated_tuner_i2c_adap;
|
||||
// struct i2c_adapter tuner_i2c_adap;
|
||||
struct i2c_adapter gated_tuner_i2c_adap;
|
||||
|
||||
struct i2c_adapter *i2c_adap;
|
||||
u8 i2c_addr;
|
||||
u8 i2c_addr;
|
||||
|
||||
u16 base_reg;
|
||||
};
|
||||
|
||||
extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, struct i2c_adapter *i2c_adap, u8 i2c_addr);
|
||||
extern struct i2c_adapter * dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf, int gating);
|
||||
extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst,
|
||||
u16 device_rev, struct i2c_adapter *i2c_adap,
|
||||
u8 i2c_addr);
|
||||
extern struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master
|
||||
*mst,
|
||||
enum dibx000_i2c_interface
|
||||
intf, int gating);
|
||||
extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst);
|
||||
extern void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst);
|
||||
|
||||
#define BAND_LBAND 0x01
|
||||
#define BAND_UHF 0x02
|
||||
|
|
@ -41,18 +48,18 @@ extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst);
|
|||
(freq_kHz) <= 2000000 ? BAND_LBAND : BAND_SBAND )
|
||||
|
||||
struct dibx000_agc_config {
|
||||
/* defines the capabilities of this AGC-setting - using the BAND_-defines*/
|
||||
u8 band_caps;
|
||||
/* defines the capabilities of this AGC-setting - using the BAND_-defines */
|
||||
u8 band_caps;
|
||||
|
||||
u16 setup;
|
||||
|
||||
u16 inv_gain;
|
||||
u16 time_stabiliz;
|
||||
|
||||
u8 alpha_level;
|
||||
u8 alpha_level;
|
||||
u16 thlock;
|
||||
|
||||
u8 wbd_inv;
|
||||
u8 wbd_inv;
|
||||
u16 wbd_ref;
|
||||
u8 wbd_sel;
|
||||
u8 wbd_alpha;
|
||||
|
|
@ -92,8 +99,8 @@ struct dibx000_agc_config {
|
|||
};
|
||||
|
||||
struct dibx000_bandwidth_config {
|
||||
u32 internal;
|
||||
u32 sampling;
|
||||
u32 internal;
|
||||
u32 sampling;
|
||||
|
||||
u8 pll_prediv;
|
||||
u8 pll_ratio;
|
||||
|
|
|
|||
|
|
@ -363,6 +363,8 @@ struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
|
|||
|
||||
struct lgdt3304_state *state;
|
||||
state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
return NULL;
|
||||
state->addr = config->i2c_address;
|
||||
state->i2c = i2c;
|
||||
|
||||
|
|
|
|||
|
|
@ -169,6 +169,8 @@ struct dvb_frontend* s921_attach(const struct s921_config *config,
|
|||
|
||||
struct s921_state *state;
|
||||
state = kzalloc(sizeof(struct s921_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
return NULL;
|
||||
|
||||
state->addr = config->i2c_address;
|
||||
state->i2c = i2c;
|
||||
|
|
|
|||
12
drivers/media/dvb/pt1/Kconfig
Normal file
12
drivers/media/dvb/pt1/Kconfig
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
config DVB_PT1
|
||||
tristate "PT1 cards"
|
||||
depends on DVB_CORE && PCI && I2C
|
||||
help
|
||||
Support for Earthsoft PT1 PCI cards.
|
||||
|
||||
Since these cards have no MPEG decoder onboard, they transmit
|
||||
only compressed MPEG data over the PCI bus, so you need
|
||||
an external software decoder to watch TV on your computer.
|
||||
|
||||
Say Y or M if you own such a device and want to use it.
|
||||
|
||||
5
drivers/media/dvb/pt1/Makefile
Normal file
5
drivers/media/dvb/pt1/Makefile
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
earth-pt1-objs := pt1.o va1j5jf8007s.o va1j5jf8007t.o
|
||||
|
||||
obj-$(CONFIG_DVB_PT1) += earth-pt1.o
|
||||
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -Idrivers/media/dvb/frontends
|
||||
1056
drivers/media/dvb/pt1/pt1.c
Normal file
1056
drivers/media/dvb/pt1/pt1.c
Normal file
File diff suppressed because it is too large
Load diff
658
drivers/media/dvb/pt1/va1j5jf8007s.c
Normal file
658
drivers/media/dvb/pt1/va1j5jf8007s.c
Normal file
|
|
@ -0,0 +1,658 @@
|
|||
/*
|
||||
* ISDB-S driver for VA1J5JF8007
|
||||
*
|
||||
* Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
|
||||
*
|
||||
* based on pt1dvr - http://pt1dvr.sourceforge.jp/
|
||||
* by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include "dvb_frontend.h"
|
||||
#include "va1j5jf8007s.h"
|
||||
|
||||
enum va1j5jf8007s_tune_state {
|
||||
VA1J5JF8007S_IDLE,
|
||||
VA1J5JF8007S_SET_FREQUENCY_1,
|
||||
VA1J5JF8007S_SET_FREQUENCY_2,
|
||||
VA1J5JF8007S_SET_FREQUENCY_3,
|
||||
VA1J5JF8007S_CHECK_FREQUENCY,
|
||||
VA1J5JF8007S_SET_MODULATION,
|
||||
VA1J5JF8007S_CHECK_MODULATION,
|
||||
VA1J5JF8007S_SET_TS_ID,
|
||||
VA1J5JF8007S_CHECK_TS_ID,
|
||||
VA1J5JF8007S_TRACK,
|
||||
};
|
||||
|
||||
struct va1j5jf8007s_state {
|
||||
const struct va1j5jf8007s_config *config;
|
||||
struct i2c_adapter *adap;
|
||||
struct dvb_frontend fe;
|
||||
enum va1j5jf8007s_tune_state tune_state;
|
||||
};
|
||||
|
||||
static int va1j5jf8007s_get_frontend_algo(struct dvb_frontend *fe)
|
||||
{
|
||||
return DVBFE_ALGO_HW;
|
||||
}
|
||||
|
||||
static int
|
||||
va1j5jf8007s_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
{
|
||||
struct va1j5jf8007s_state *state;
|
||||
|
||||
state = fe->demodulator_priv;
|
||||
|
||||
switch (state->tune_state) {
|
||||
case VA1J5JF8007S_IDLE:
|
||||
case VA1J5JF8007S_SET_FREQUENCY_1:
|
||||
case VA1J5JF8007S_SET_FREQUENCY_2:
|
||||
case VA1J5JF8007S_SET_FREQUENCY_3:
|
||||
case VA1J5JF8007S_CHECK_FREQUENCY:
|
||||
*status = 0;
|
||||
return 0;
|
||||
|
||||
|
||||
case VA1J5JF8007S_SET_MODULATION:
|
||||
case VA1J5JF8007S_CHECK_MODULATION:
|
||||
*status |= FE_HAS_SIGNAL;
|
||||
return 0;
|
||||
|
||||
case VA1J5JF8007S_SET_TS_ID:
|
||||
case VA1J5JF8007S_CHECK_TS_ID:
|
||||
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
|
||||
return 0;
|
||||
|
||||
case VA1J5JF8007S_TRACK:
|
||||
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BUG();
|
||||
}
|
||||
|
||||
struct va1j5jf8007s_cb_map {
|
||||
u32 frequency;
|
||||
u8 cb;
|
||||
};
|
||||
|
||||
static const struct va1j5jf8007s_cb_map va1j5jf8007s_cb_maps[] = {
|
||||
{ 986000, 0xb2 },
|
||||
{ 1072000, 0xd2 },
|
||||
{ 1154000, 0xe2 },
|
||||
{ 1291000, 0x20 },
|
||||
{ 1447000, 0x40 },
|
||||
{ 1615000, 0x60 },
|
||||
{ 1791000, 0x80 },
|
||||
{ 1972000, 0xa0 },
|
||||
};
|
||||
|
||||
static u8 va1j5jf8007s_lookup_cb(u32 frequency)
|
||||
{
|
||||
int i;
|
||||
const struct va1j5jf8007s_cb_map *map;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(va1j5jf8007s_cb_maps); i++) {
|
||||
map = &va1j5jf8007s_cb_maps[i];
|
||||
if (frequency < map->frequency)
|
||||
return map->cb;
|
||||
}
|
||||
return 0xc0;
|
||||
}
|
||||
|
||||
static int va1j5jf8007s_set_frequency_1(struct va1j5jf8007s_state *state)
|
||||
{
|
||||
u32 frequency;
|
||||
u16 word;
|
||||
u8 buf[6];
|
||||
struct i2c_msg msg;
|
||||
|
||||
frequency = state->fe.dtv_property_cache.frequency;
|
||||
|
||||
word = (frequency + 500) / 1000;
|
||||
if (frequency < 1072000)
|
||||
word = (word << 1 & ~0x1f) | (word & 0x0f);
|
||||
|
||||
buf[0] = 0xfe;
|
||||
buf[1] = 0xc0;
|
||||
buf[2] = 0x40 | word >> 8;
|
||||
buf[3] = word;
|
||||
buf[4] = 0xe0;
|
||||
buf[5] = va1j5jf8007s_lookup_cb(frequency);
|
||||
|
||||
msg.addr = state->config->demod_address;
|
||||
msg.flags = 0;
|
||||
msg.len = sizeof(buf);
|
||||
msg.buf = buf;
|
||||
|
||||
if (i2c_transfer(state->adap, &msg, 1) != 1)
|
||||
return -EREMOTEIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int va1j5jf8007s_set_frequency_2(struct va1j5jf8007s_state *state)
|
||||
{
|
||||
u8 buf[3];
|
||||
struct i2c_msg msg;
|
||||
|
||||
buf[0] = 0xfe;
|
||||
buf[1] = 0xc0;
|
||||
buf[2] = 0xe4;
|
||||
|
||||
msg.addr = state->config->demod_address;
|
||||
msg.flags = 0;
|
||||
msg.len = sizeof(buf);
|
||||
msg.buf = buf;
|
||||
|
||||
if (i2c_transfer(state->adap, &msg, 1) != 1)
|
||||
return -EREMOTEIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int va1j5jf8007s_set_frequency_3(struct va1j5jf8007s_state *state)
|
||||
{
|
||||
u32 frequency;
|
||||
u8 buf[4];
|
||||
struct i2c_msg msg;
|
||||
|
||||
frequency = state->fe.dtv_property_cache.frequency;
|
||||
|
||||
buf[0] = 0xfe;
|
||||
buf[1] = 0xc0;
|
||||
buf[2] = 0xf4;
|
||||
buf[3] = va1j5jf8007s_lookup_cb(frequency) | 0x4;
|
||||
|
||||
msg.addr = state->config->demod_address;
|
||||
msg.flags = 0;
|
||||
msg.len = sizeof(buf);
|
||||
msg.buf = buf;
|
||||
|
||||
if (i2c_transfer(state->adap, &msg, 1) != 1)
|
||||
return -EREMOTEIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
va1j5jf8007s_check_frequency(struct va1j5jf8007s_state *state, int *lock)
|
||||
{
|
||||
u8 addr;
|
||||
u8 write_buf[2], read_buf[1];
|
||||
struct i2c_msg msgs[2];
|
||||
|
||||
addr = state->config->demod_address;
|
||||
|
||||
write_buf[0] = 0xfe;
|
||||
write_buf[1] = 0xc1;
|
||||
|
||||
msgs[0].addr = addr;
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].len = sizeof(write_buf);
|
||||
msgs[0].buf = write_buf;
|
||||
|
||||
msgs[1].addr = addr;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].len = sizeof(read_buf);
|
||||
msgs[1].buf = read_buf;
|
||||
|
||||
if (i2c_transfer(state->adap, msgs, 2) != 2)
|
||||
return -EREMOTEIO;
|
||||
|
||||
*lock = read_buf[0] & 0x40;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int va1j5jf8007s_set_modulation(struct va1j5jf8007s_state *state)
|
||||
{
|
||||
u8 buf[2];
|
||||
struct i2c_msg msg;
|
||||
|
||||
buf[0] = 0x03;
|
||||
buf[1] = 0x01;
|
||||
|
||||
msg.addr = state->config->demod_address;
|
||||
msg.flags = 0;
|
||||
msg.len = sizeof(buf);
|
||||
msg.buf = buf;
|
||||
|
||||
if (i2c_transfer(state->adap, &msg, 1) != 1)
|
||||
return -EREMOTEIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
va1j5jf8007s_check_modulation(struct va1j5jf8007s_state *state, int *lock)
|
||||
{
|
||||
u8 addr;
|
||||
u8 write_buf[1], read_buf[1];
|
||||
struct i2c_msg msgs[2];
|
||||
|
||||
addr = state->config->demod_address;
|
||||
|
||||
write_buf[0] = 0xc3;
|
||||
|
||||
msgs[0].addr = addr;
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].len = sizeof(write_buf);
|
||||
msgs[0].buf = write_buf;
|
||||
|
||||
msgs[1].addr = addr;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].len = sizeof(read_buf);
|
||||
msgs[1].buf = read_buf;
|
||||
|
||||
if (i2c_transfer(state->adap, msgs, 2) != 2)
|
||||
return -EREMOTEIO;
|
||||
|
||||
*lock = !(read_buf[0] & 0x10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
va1j5jf8007s_set_ts_id(struct va1j5jf8007s_state *state)
|
||||
{
|
||||
u32 ts_id;
|
||||
u8 buf[3];
|
||||
struct i2c_msg msg;
|
||||
|
||||
ts_id = state->fe.dtv_property_cache.isdbs_ts_id;
|
||||
if (!ts_id)
|
||||
return 0;
|
||||
|
||||
buf[0] = 0x8f;
|
||||
buf[1] = ts_id >> 8;
|
||||
buf[2] = ts_id;
|
||||
|
||||
msg.addr = state->config->demod_address;
|
||||
msg.flags = 0;
|
||||
msg.len = sizeof(buf);
|
||||
msg.buf = buf;
|
||||
|
||||
if (i2c_transfer(state->adap, &msg, 1) != 1)
|
||||
return -EREMOTEIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
va1j5jf8007s_check_ts_id(struct va1j5jf8007s_state *state, int *lock)
|
||||
{
|
||||
u8 addr;
|
||||
u8 write_buf[1], read_buf[2];
|
||||
struct i2c_msg msgs[2];
|
||||
u32 ts_id;
|
||||
|
||||
ts_id = state->fe.dtv_property_cache.isdbs_ts_id;
|
||||
if (!ts_id) {
|
||||
*lock = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr = state->config->demod_address;
|
||||
|
||||
write_buf[0] = 0xe6;
|
||||
|
||||
msgs[0].addr = addr;
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].len = sizeof(write_buf);
|
||||
msgs[0].buf = write_buf;
|
||||
|
||||
msgs[1].addr = addr;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].len = sizeof(read_buf);
|
||||
msgs[1].buf = read_buf;
|
||||
|
||||
if (i2c_transfer(state->adap, msgs, 2) != 2)
|
||||
return -EREMOTEIO;
|
||||
|
||||
*lock = (read_buf[0] << 8 | read_buf[1]) == ts_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
va1j5jf8007s_tune(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *params,
|
||||
unsigned int mode_flags, unsigned int *delay,
|
||||
fe_status_t *status)
|
||||
{
|
||||
struct va1j5jf8007s_state *state;
|
||||
int ret;
|
||||
int lock;
|
||||
|
||||
state = fe->demodulator_priv;
|
||||
|
||||
if (params != NULL)
|
||||
state->tune_state = VA1J5JF8007S_SET_FREQUENCY_1;
|
||||
|
||||
switch (state->tune_state) {
|
||||
case VA1J5JF8007S_IDLE:
|
||||
*delay = 3 * HZ;
|
||||
*status = 0;
|
||||
return 0;
|
||||
|
||||
case VA1J5JF8007S_SET_FREQUENCY_1:
|
||||
ret = va1j5jf8007s_set_frequency_1(state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
state->tune_state = VA1J5JF8007S_SET_FREQUENCY_2;
|
||||
*delay = 0;
|
||||
*status = 0;
|
||||
return 0;
|
||||
|
||||
case VA1J5JF8007S_SET_FREQUENCY_2:
|
||||
ret = va1j5jf8007s_set_frequency_2(state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
state->tune_state = VA1J5JF8007S_SET_FREQUENCY_3;
|
||||
*delay = (HZ + 99) / 100;
|
||||
*status = 0;
|
||||
return 0;
|
||||
|
||||
case VA1J5JF8007S_SET_FREQUENCY_3:
|
||||
ret = va1j5jf8007s_set_frequency_3(state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
state->tune_state = VA1J5JF8007S_CHECK_FREQUENCY;
|
||||
*delay = 0;
|
||||
*status = 0;
|
||||
return 0;
|
||||
|
||||
case VA1J5JF8007S_CHECK_FREQUENCY:
|
||||
ret = va1j5jf8007s_check_frequency(state, &lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!lock) {
|
||||
*delay = (HZ + 999) / 1000;
|
||||
*status = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
state->tune_state = VA1J5JF8007S_SET_MODULATION;
|
||||
*delay = 0;
|
||||
*status = FE_HAS_SIGNAL;
|
||||
return 0;
|
||||
|
||||
case VA1J5JF8007S_SET_MODULATION:
|
||||
ret = va1j5jf8007s_set_modulation(state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
state->tune_state = VA1J5JF8007S_CHECK_MODULATION;
|
||||
*delay = 0;
|
||||
*status = FE_HAS_SIGNAL;
|
||||
return 0;
|
||||
|
||||
case VA1J5JF8007S_CHECK_MODULATION:
|
||||
ret = va1j5jf8007s_check_modulation(state, &lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!lock) {
|
||||
*delay = (HZ + 49) / 50;
|
||||
*status = FE_HAS_SIGNAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
state->tune_state = VA1J5JF8007S_SET_TS_ID;
|
||||
*delay = 0;
|
||||
*status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
|
||||
return 0;
|
||||
|
||||
case VA1J5JF8007S_SET_TS_ID:
|
||||
ret = va1j5jf8007s_set_ts_id(state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
state->tune_state = VA1J5JF8007S_CHECK_TS_ID;
|
||||
return 0;
|
||||
|
||||
case VA1J5JF8007S_CHECK_TS_ID:
|
||||
ret = va1j5jf8007s_check_ts_id(state, &lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!lock) {
|
||||
*delay = (HZ + 99) / 100;
|
||||
*status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
state->tune_state = VA1J5JF8007S_TRACK;
|
||||
/* fall through */
|
||||
|
||||
case VA1J5JF8007S_TRACK:
|
||||
*delay = 3 * HZ;
|
||||
*status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BUG();
|
||||
}
|
||||
|
||||
static int va1j5jf8007s_init_frequency(struct va1j5jf8007s_state *state)
|
||||
{
|
||||
u8 buf[4];
|
||||
struct i2c_msg msg;
|
||||
|
||||
buf[0] = 0xfe;
|
||||
buf[1] = 0xc0;
|
||||
buf[2] = 0xf0;
|
||||
buf[3] = 0x04;
|
||||
|
||||
msg.addr = state->config->demod_address;
|
||||
msg.flags = 0;
|
||||
msg.len = sizeof(buf);
|
||||
msg.buf = buf;
|
||||
|
||||
if (i2c_transfer(state->adap, &msg, 1) != 1)
|
||||
return -EREMOTEIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int va1j5jf8007s_set_sleep(struct va1j5jf8007s_state *state, int sleep)
|
||||
{
|
||||
u8 buf[2];
|
||||
struct i2c_msg msg;
|
||||
|
||||
buf[0] = 0x17;
|
||||
buf[1] = sleep ? 0x01 : 0x00;
|
||||
|
||||
msg.addr = state->config->demod_address;
|
||||
msg.flags = 0;
|
||||
msg.len = sizeof(buf);
|
||||
msg.buf = buf;
|
||||
|
||||
if (i2c_transfer(state->adap, &msg, 1) != 1)
|
||||
return -EREMOTEIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int va1j5jf8007s_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct va1j5jf8007s_state *state;
|
||||
int ret;
|
||||
|
||||
state = fe->demodulator_priv;
|
||||
|
||||
ret = va1j5jf8007s_init_frequency(state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return va1j5jf8007s_set_sleep(state, 1);
|
||||
}
|
||||
|
||||
static int va1j5jf8007s_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct va1j5jf8007s_state *state;
|
||||
|
||||
state = fe->demodulator_priv;
|
||||
state->tune_state = VA1J5JF8007S_IDLE;
|
||||
|
||||
return va1j5jf8007s_set_sleep(state, 0);
|
||||
}
|
||||
|
||||
static void va1j5jf8007s_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct va1j5jf8007s_state *state;
|
||||
state = fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops va1j5jf8007s_ops = {
|
||||
.info = {
|
||||
.name = "VA1J5JF8007 ISDB-S",
|
||||
.type = FE_QPSK,
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_stepsize = 1000,
|
||||
.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO |
|
||||
FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
|
||||
FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
|
||||
},
|
||||
|
||||
.get_frontend_algo = va1j5jf8007s_get_frontend_algo,
|
||||
.read_status = va1j5jf8007s_read_status,
|
||||
.tune = va1j5jf8007s_tune,
|
||||
.sleep = va1j5jf8007s_sleep,
|
||||
.init = va1j5jf8007s_init,
|
||||
.release = va1j5jf8007s_release,
|
||||
};
|
||||
|
||||
static int va1j5jf8007s_prepare_1(struct va1j5jf8007s_state *state)
|
||||
{
|
||||
u8 addr;
|
||||
u8 write_buf[1], read_buf[1];
|
||||
struct i2c_msg msgs[2];
|
||||
|
||||
addr = state->config->demod_address;
|
||||
|
||||
write_buf[0] = 0x07;
|
||||
|
||||
msgs[0].addr = addr;
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].len = sizeof(write_buf);
|
||||
msgs[0].buf = write_buf;
|
||||
|
||||
msgs[1].addr = addr;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].len = sizeof(read_buf);
|
||||
msgs[1].buf = read_buf;
|
||||
|
||||
if (i2c_transfer(state->adap, msgs, 2) != 2)
|
||||
return -EREMOTEIO;
|
||||
|
||||
if (read_buf[0] != 0x41)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const u8 va1j5jf8007s_prepare_bufs[][2] = {
|
||||
{0x04, 0x02}, {0x0d, 0x55}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01},
|
||||
{0x1c, 0x0a}, {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0},
|
||||
{0x52, 0x89}, {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69},
|
||||
{0x87, 0x04}, {0x8e, 0x02}, {0xa3, 0xf7}, {0xa5, 0xc0},
|
||||
};
|
||||
|
||||
static int va1j5jf8007s_prepare_2(struct va1j5jf8007s_state *state)
|
||||
{
|
||||
u8 addr;
|
||||
u8 buf[2];
|
||||
struct i2c_msg msg;
|
||||
int i;
|
||||
|
||||
addr = state->config->demod_address;
|
||||
|
||||
msg.addr = addr;
|
||||
msg.flags = 0;
|
||||
msg.len = 2;
|
||||
msg.buf = buf;
|
||||
for (i = 0; i < ARRAY_SIZE(va1j5jf8007s_prepare_bufs); i++) {
|
||||
memcpy(buf, va1j5jf8007s_prepare_bufs[i], sizeof(buf));
|
||||
if (i2c_transfer(state->adap, &msg, 1) != 1)
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* must be called after va1j5jf8007t_attach */
|
||||
int va1j5jf8007s_prepare(struct dvb_frontend *fe)
|
||||
{
|
||||
struct va1j5jf8007s_state *state;
|
||||
int ret;
|
||||
|
||||
state = fe->demodulator_priv;
|
||||
|
||||
ret = va1j5jf8007s_prepare_1(state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = va1j5jf8007s_prepare_2(state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return va1j5jf8007s_init_frequency(state);
|
||||
}
|
||||
|
||||
struct dvb_frontend *
|
||||
va1j5jf8007s_attach(const struct va1j5jf8007s_config *config,
|
||||
struct i2c_adapter *adap)
|
||||
{
|
||||
struct va1j5jf8007s_state *state;
|
||||
struct dvb_frontend *fe;
|
||||
u8 buf[2];
|
||||
struct i2c_msg msg;
|
||||
|
||||
state = kzalloc(sizeof(struct va1j5jf8007s_state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return NULL;
|
||||
|
||||
state->config = config;
|
||||
state->adap = adap;
|
||||
|
||||
fe = &state->fe;
|
||||
memcpy(&fe->ops, &va1j5jf8007s_ops, sizeof(struct dvb_frontend_ops));
|
||||
fe->demodulator_priv = state;
|
||||
|
||||
buf[0] = 0x01;
|
||||
buf[1] = 0x80;
|
||||
|
||||
msg.addr = state->config->demod_address;
|
||||
msg.flags = 0;
|
||||
msg.len = sizeof(buf);
|
||||
msg.buf = buf;
|
||||
|
||||
if (i2c_transfer(state->adap, &msg, 1) != 1) {
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fe;
|
||||
}
|
||||
40
drivers/media/dvb/pt1/va1j5jf8007s.h
Normal file
40
drivers/media/dvb/pt1/va1j5jf8007s.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* ISDB-S driver for VA1J5JF8007
|
||||
*
|
||||
* Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
|
||||
*
|
||||
* based on pt1dvr - http://pt1dvr.sourceforge.jp/
|
||||
* by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
|
||||
*
|
||||
* 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 VA1J5JF8007S_H
|
||||
#define VA1J5JF8007S_H
|
||||
|
||||
struct va1j5jf8007s_config {
|
||||
u8 demod_address;
|
||||
};
|
||||
|
||||
struct i2c_adapter;
|
||||
|
||||
struct dvb_frontend *
|
||||
va1j5jf8007s_attach(const struct va1j5jf8007s_config *config,
|
||||
struct i2c_adapter *adap);
|
||||
|
||||
/* must be called after va1j5jf8007t_attach */
|
||||
int va1j5jf8007s_prepare(struct dvb_frontend *fe);
|
||||
|
||||
#endif
|
||||
468
drivers/media/dvb/pt1/va1j5jf8007t.c
Normal file
468
drivers/media/dvb/pt1/va1j5jf8007t.c
Normal file
|
|
@ -0,0 +1,468 @@
|
|||
/*
|
||||
* ISDB-T driver for VA1J5JF8007
|
||||
*
|
||||
* Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
|
||||
*
|
||||
* based on pt1dvr - http://pt1dvr.sourceforge.jp/
|
||||
* by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include "dvb_frontend.h"
|
||||
#include "dvb_math.h"
|
||||
#include "va1j5jf8007t.h"
|
||||
|
||||
enum va1j5jf8007t_tune_state {
|
||||
VA1J5JF8007T_IDLE,
|
||||
VA1J5JF8007T_SET_FREQUENCY,
|
||||
VA1J5JF8007T_CHECK_FREQUENCY,
|
||||
VA1J5JF8007T_SET_MODULATION,
|
||||
VA1J5JF8007T_CHECK_MODULATION,
|
||||
VA1J5JF8007T_TRACK,
|
||||
VA1J5JF8007T_ABORT,
|
||||
};
|
||||
|
||||
struct va1j5jf8007t_state {
|
||||
const struct va1j5jf8007t_config *config;
|
||||
struct i2c_adapter *adap;
|
||||
struct dvb_frontend fe;
|
||||
enum va1j5jf8007t_tune_state tune_state;
|
||||
};
|
||||
|
||||
static int va1j5jf8007t_get_frontend_algo(struct dvb_frontend *fe)
|
||||
{
|
||||
return DVBFE_ALGO_HW;
|
||||
}
|
||||
|
||||
static int
|
||||
va1j5jf8007t_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
{
|
||||
struct va1j5jf8007t_state *state;
|
||||
|
||||
state = fe->demodulator_priv;
|
||||
|
||||
switch (state->tune_state) {
|
||||
case VA1J5JF8007T_IDLE:
|
||||
case VA1J5JF8007T_SET_FREQUENCY:
|
||||
case VA1J5JF8007T_CHECK_FREQUENCY:
|
||||
*status = 0;
|
||||
return 0;
|
||||
|
||||
|
||||
case VA1J5JF8007T_SET_MODULATION:
|
||||
case VA1J5JF8007T_CHECK_MODULATION:
|
||||
case VA1J5JF8007T_ABORT:
|
||||
*status |= FE_HAS_SIGNAL;
|
||||
return 0;
|
||||
|
||||
case VA1J5JF8007T_TRACK:
|
||||
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BUG();
|
||||
}
|
||||
|
||||
struct va1j5jf8007t_cb_map {
|
||||
u32 frequency;
|
||||
u8 cb;
|
||||
};
|
||||
|
||||
static const struct va1j5jf8007t_cb_map va1j5jf8007t_cb_maps[] = {
|
||||
{ 90000000, 0x80 },
|
||||
{ 140000000, 0x81 },
|
||||
{ 170000000, 0xa1 },
|
||||
{ 220000000, 0x62 },
|
||||
{ 330000000, 0xa2 },
|
||||
{ 402000000, 0xe2 },
|
||||
{ 450000000, 0x64 },
|
||||
{ 550000000, 0x84 },
|
||||
{ 600000000, 0xa4 },
|
||||
{ 700000000, 0xc4 },
|
||||
};
|
||||
|
||||
static u8 va1j5jf8007t_lookup_cb(u32 frequency)
|
||||
{
|
||||
int i;
|
||||
const struct va1j5jf8007t_cb_map *map;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(va1j5jf8007t_cb_maps); i++) {
|
||||
map = &va1j5jf8007t_cb_maps[i];
|
||||
if (frequency < map->frequency)
|
||||
return map->cb;
|
||||
}
|
||||
return 0xe4;
|
||||
}
|
||||
|
||||
static int va1j5jf8007t_set_frequency(struct va1j5jf8007t_state *state)
|
||||
{
|
||||
u32 frequency;
|
||||
u16 word;
|
||||
u8 buf[6];
|
||||
struct i2c_msg msg;
|
||||
|
||||
frequency = state->fe.dtv_property_cache.frequency;
|
||||
|
||||
word = (frequency + 71428) / 142857 + 399;
|
||||
buf[0] = 0xfe;
|
||||
buf[1] = 0xc2;
|
||||
buf[2] = word >> 8;
|
||||
buf[3] = word;
|
||||
buf[4] = 0x80;
|
||||
buf[5] = va1j5jf8007t_lookup_cb(frequency);
|
||||
|
||||
msg.addr = state->config->demod_address;
|
||||
msg.flags = 0;
|
||||
msg.len = sizeof(buf);
|
||||
msg.buf = buf;
|
||||
|
||||
if (i2c_transfer(state->adap, &msg, 1) != 1)
|
||||
return -EREMOTEIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
va1j5jf8007t_check_frequency(struct va1j5jf8007t_state *state, int *lock)
|
||||
{
|
||||
u8 addr;
|
||||
u8 write_buf[2], read_buf[1];
|
||||
struct i2c_msg msgs[2];
|
||||
|
||||
addr = state->config->demod_address;
|
||||
|
||||
write_buf[0] = 0xfe;
|
||||
write_buf[1] = 0xc3;
|
||||
|
||||
msgs[0].addr = addr;
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].len = sizeof(write_buf);
|
||||
msgs[0].buf = write_buf;
|
||||
|
||||
msgs[1].addr = addr;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].len = sizeof(read_buf);
|
||||
msgs[1].buf = read_buf;
|
||||
|
||||
if (i2c_transfer(state->adap, msgs, 2) != 2)
|
||||
return -EREMOTEIO;
|
||||
|
||||
*lock = read_buf[0] & 0x40;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int va1j5jf8007t_set_modulation(struct va1j5jf8007t_state *state)
|
||||
{
|
||||
u8 buf[2];
|
||||
struct i2c_msg msg;
|
||||
|
||||
buf[0] = 0x01;
|
||||
buf[1] = 0x40;
|
||||
|
||||
msg.addr = state->config->demod_address;
|
||||
msg.flags = 0;
|
||||
msg.len = sizeof(buf);
|
||||
msg.buf = buf;
|
||||
|
||||
if (i2c_transfer(state->adap, &msg, 1) != 1)
|
||||
return -EREMOTEIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int va1j5jf8007t_check_modulation(struct va1j5jf8007t_state *state,
|
||||
int *lock, int *retry)
|
||||
{
|
||||
u8 addr;
|
||||
u8 write_buf[1], read_buf[1];
|
||||
struct i2c_msg msgs[2];
|
||||
|
||||
addr = state->config->demod_address;
|
||||
|
||||
write_buf[0] = 0x80;
|
||||
|
||||
msgs[0].addr = addr;
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].len = sizeof(write_buf);
|
||||
msgs[0].buf = write_buf;
|
||||
|
||||
msgs[1].addr = addr;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].len = sizeof(read_buf);
|
||||
msgs[1].buf = read_buf;
|
||||
|
||||
if (i2c_transfer(state->adap, msgs, 2) != 2)
|
||||
return -EREMOTEIO;
|
||||
|
||||
*lock = !(read_buf[0] & 0x10);
|
||||
*retry = read_buf[0] & 0x80;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
va1j5jf8007t_tune(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *params,
|
||||
unsigned int mode_flags, unsigned int *delay,
|
||||
fe_status_t *status)
|
||||
{
|
||||
struct va1j5jf8007t_state *state;
|
||||
int ret;
|
||||
int lock, retry;
|
||||
|
||||
state = fe->demodulator_priv;
|
||||
|
||||
if (params != NULL)
|
||||
state->tune_state = VA1J5JF8007T_SET_FREQUENCY;
|
||||
|
||||
switch (state->tune_state) {
|
||||
case VA1J5JF8007T_IDLE:
|
||||
*delay = 3 * HZ;
|
||||
*status = 0;
|
||||
return 0;
|
||||
|
||||
case VA1J5JF8007T_SET_FREQUENCY:
|
||||
ret = va1j5jf8007t_set_frequency(state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
state->tune_state = VA1J5JF8007T_CHECK_FREQUENCY;
|
||||
*delay = 0;
|
||||
*status = 0;
|
||||
return 0;
|
||||
|
||||
case VA1J5JF8007T_CHECK_FREQUENCY:
|
||||
ret = va1j5jf8007t_check_frequency(state, &lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!lock) {
|
||||
*delay = (HZ + 999) / 1000;
|
||||
*status = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
state->tune_state = VA1J5JF8007T_SET_MODULATION;
|
||||
*delay = 0;
|
||||
*status = FE_HAS_SIGNAL;
|
||||
return 0;
|
||||
|
||||
case VA1J5JF8007T_SET_MODULATION:
|
||||
ret = va1j5jf8007t_set_modulation(state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
state->tune_state = VA1J5JF8007T_CHECK_MODULATION;
|
||||
*delay = 0;
|
||||
*status = FE_HAS_SIGNAL;
|
||||
return 0;
|
||||
|
||||
case VA1J5JF8007T_CHECK_MODULATION:
|
||||
ret = va1j5jf8007t_check_modulation(state, &lock, &retry);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!lock) {
|
||||
if (!retry) {
|
||||
state->tune_state = VA1J5JF8007T_ABORT;
|
||||
*delay = 3 * HZ;
|
||||
*status = FE_HAS_SIGNAL;
|
||||
return 0;
|
||||
}
|
||||
*delay = (HZ + 999) / 1000;
|
||||
*status = FE_HAS_SIGNAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
state->tune_state = VA1J5JF8007T_TRACK;
|
||||
/* fall through */
|
||||
|
||||
case VA1J5JF8007T_TRACK:
|
||||
*delay = 3 * HZ;
|
||||
*status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
|
||||
return 0;
|
||||
|
||||
case VA1J5JF8007T_ABORT:
|
||||
*delay = 3 * HZ;
|
||||
*status = FE_HAS_SIGNAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BUG();
|
||||
}
|
||||
|
||||
static int va1j5jf8007t_init_frequency(struct va1j5jf8007t_state *state)
|
||||
{
|
||||
u8 buf[7];
|
||||
struct i2c_msg msg;
|
||||
|
||||
buf[0] = 0xfe;
|
||||
buf[1] = 0xc2;
|
||||
buf[2] = 0x01;
|
||||
buf[3] = 0x8f;
|
||||
buf[4] = 0xc1;
|
||||
buf[5] = 0x80;
|
||||
buf[6] = 0x80;
|
||||
|
||||
msg.addr = state->config->demod_address;
|
||||
msg.flags = 0;
|
||||
msg.len = sizeof(buf);
|
||||
msg.buf = buf;
|
||||
|
||||
if (i2c_transfer(state->adap, &msg, 1) != 1)
|
||||
return -EREMOTEIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int va1j5jf8007t_set_sleep(struct va1j5jf8007t_state *state, int sleep)
|
||||
{
|
||||
u8 buf[2];
|
||||
struct i2c_msg msg;
|
||||
|
||||
buf[0] = 0x03;
|
||||
buf[1] = sleep ? 0x90 : 0x80;
|
||||
|
||||
msg.addr = state->config->demod_address;
|
||||
msg.flags = 0;
|
||||
msg.len = sizeof(buf);
|
||||
msg.buf = buf;
|
||||
|
||||
if (i2c_transfer(state->adap, &msg, 1) != 1)
|
||||
return -EREMOTEIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int va1j5jf8007t_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct va1j5jf8007t_state *state;
|
||||
int ret;
|
||||
|
||||
state = fe->demodulator_priv;
|
||||
|
||||
ret = va1j5jf8007t_init_frequency(state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return va1j5jf8007t_set_sleep(state, 1);
|
||||
}
|
||||
|
||||
static int va1j5jf8007t_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct va1j5jf8007t_state *state;
|
||||
|
||||
state = fe->demodulator_priv;
|
||||
state->tune_state = VA1J5JF8007T_IDLE;
|
||||
|
||||
return va1j5jf8007t_set_sleep(state, 0);
|
||||
}
|
||||
|
||||
static void va1j5jf8007t_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct va1j5jf8007t_state *state;
|
||||
state = fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops va1j5jf8007t_ops = {
|
||||
.info = {
|
||||
.name = "VA1J5JF8007 ISDB-T",
|
||||
.type = FE_OFDM,
|
||||
.frequency_min = 90000000,
|
||||
.frequency_max = 770000000,
|
||||
.frequency_stepsize = 142857,
|
||||
.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO |
|
||||
FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
|
||||
FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
|
||||
},
|
||||
|
||||
.get_frontend_algo = va1j5jf8007t_get_frontend_algo,
|
||||
.read_status = va1j5jf8007t_read_status,
|
||||
.tune = va1j5jf8007t_tune,
|
||||
.sleep = va1j5jf8007t_sleep,
|
||||
.init = va1j5jf8007t_init,
|
||||
.release = va1j5jf8007t_release,
|
||||
};
|
||||
|
||||
static const u8 va1j5jf8007t_prepare_bufs[][2] = {
|
||||
{0x03, 0x90}, {0x14, 0x8f}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2},
|
||||
{0x22, 0x83}, {0x31, 0x0d}, {0x32, 0xe0}, {0x39, 0xd3}, {0x3a, 0x00},
|
||||
{0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x02}, {0x76, 0x4e}, {0x77, 0x03},
|
||||
{0xef, 0x01}
|
||||
};
|
||||
|
||||
int va1j5jf8007t_prepare(struct dvb_frontend *fe)
|
||||
{
|
||||
struct va1j5jf8007t_state *state;
|
||||
u8 buf[2];
|
||||
struct i2c_msg msg;
|
||||
int i;
|
||||
|
||||
state = fe->demodulator_priv;
|
||||
|
||||
msg.addr = state->config->demod_address;
|
||||
msg.flags = 0;
|
||||
msg.len = sizeof(buf);
|
||||
msg.buf = buf;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(va1j5jf8007t_prepare_bufs); i++) {
|
||||
memcpy(buf, va1j5jf8007t_prepare_bufs[i], sizeof(buf));
|
||||
if (i2c_transfer(state->adap, &msg, 1) != 1)
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return va1j5jf8007t_init_frequency(state);
|
||||
}
|
||||
|
||||
struct dvb_frontend *
|
||||
va1j5jf8007t_attach(const struct va1j5jf8007t_config *config,
|
||||
struct i2c_adapter *adap)
|
||||
{
|
||||
struct va1j5jf8007t_state *state;
|
||||
struct dvb_frontend *fe;
|
||||
u8 buf[2];
|
||||
struct i2c_msg msg;
|
||||
|
||||
state = kzalloc(sizeof(struct va1j5jf8007t_state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return NULL;
|
||||
|
||||
state->config = config;
|
||||
state->adap = adap;
|
||||
|
||||
fe = &state->fe;
|
||||
memcpy(&fe->ops, &va1j5jf8007t_ops, sizeof(struct dvb_frontend_ops));
|
||||
fe->demodulator_priv = state;
|
||||
|
||||
buf[0] = 0x01;
|
||||
buf[1] = 0x80;
|
||||
|
||||
msg.addr = state->config->demod_address;
|
||||
msg.flags = 0;
|
||||
msg.len = sizeof(buf);
|
||||
msg.buf = buf;
|
||||
|
||||
if (i2c_transfer(state->adap, &msg, 1) != 1) {
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fe;
|
||||
}
|
||||
40
drivers/media/dvb/pt1/va1j5jf8007t.h
Normal file
40
drivers/media/dvb/pt1/va1j5jf8007t.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* ISDB-T driver for VA1J5JF8007
|
||||
*
|
||||
* Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
|
||||
*
|
||||
* based on pt1dvr - http://pt1dvr.sourceforge.jp/
|
||||
* by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
|
||||
*
|
||||
* 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 VA1J5JF8007T_H
|
||||
#define VA1J5JF8007T_H
|
||||
|
||||
struct va1j5jf8007t_config {
|
||||
u8 demod_address;
|
||||
};
|
||||
|
||||
struct i2c_adapter;
|
||||
|
||||
struct dvb_frontend *
|
||||
va1j5jf8007t_attach(const struct va1j5jf8007t_config *config,
|
||||
struct i2c_adapter *adap);
|
||||
|
||||
/* must be called after va1j5jf8007s_attach */
|
||||
int va1j5jf8007t_prepare(struct dvb_frontend *fe);
|
||||
|
||||
#endif
|
||||
|
|
@ -346,7 +346,7 @@ config RADIO_SI4713
|
|||
---help---
|
||||
Say Y here if you want support to Si4713 FM Radio Transmitter.
|
||||
This device can transmit audio through FM. It can transmit
|
||||
EDS and EBDS signals as well. This module is the v4l2 radio
|
||||
RDS and RBDS signals as well. This module is the v4l2 radio
|
||||
interface for the i2c driver of this device.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
|
|
|||
|
|
@ -265,6 +265,15 @@ config VIDEO_SAA6588
|
|||
|
||||
comment "Video decoders"
|
||||
|
||||
config VIDEO_ADV7180
|
||||
tristate "Analog Devices ADV7180 decoder"
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
---help---
|
||||
Support for the Analog Devices ADV7180 video decoder.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called adv7180.
|
||||
|
||||
config VIDEO_BT819
|
||||
tristate "BT819A VideoStream decoder"
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
|
|
@ -493,6 +502,39 @@ config VIDEO_UPD64083
|
|||
|
||||
endmenu # encoder / decoder chips
|
||||
|
||||
config DISPLAY_DAVINCI_DM646X_EVM
|
||||
tristate "DM646x EVM Video Display"
|
||||
depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
|
||||
select VIDEOBUF_DMA_CONTIG
|
||||
select VIDEO_DAVINCI_VPIF
|
||||
select VIDEO_ADV7343
|
||||
select VIDEO_THS7303
|
||||
help
|
||||
Support for DM6467 based display device.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called vpif_display.
|
||||
|
||||
config CAPTURE_DAVINCI_DM646X_EVM
|
||||
tristate "DM646x EVM Video Capture"
|
||||
depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
|
||||
select VIDEOBUF_DMA_CONTIG
|
||||
select VIDEO_DAVINCI_VPIF
|
||||
help
|
||||
Support for DM6467 based capture device.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called vpif_capture.
|
||||
|
||||
config VIDEO_DAVINCI_VPIF
|
||||
tristate "DaVinci VPIF Driver"
|
||||
depends on DISPLAY_DAVINCI_DM646X_EVM
|
||||
help
|
||||
Support for DaVinci VPIF Driver.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called vpif.
|
||||
|
||||
config VIDEO_VIVI
|
||||
tristate "Virtual Video Driver"
|
||||
depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
|
||||
|
|
@ -505,6 +547,55 @@ config VIDEO_VIVI
|
|||
Say Y here if you want to test video apps or debug V4L devices.
|
||||
In doubt, say N.
|
||||
|
||||
config VIDEO_VPSS_SYSTEM
|
||||
tristate "VPSS System module driver"
|
||||
depends on ARCH_DAVINCI
|
||||
help
|
||||
Support for vpss system module for video driver
|
||||
default y
|
||||
|
||||
config VIDEO_VPFE_CAPTURE
|
||||
tristate "VPFE Video Capture Driver"
|
||||
depends on VIDEO_V4L2 && ARCH_DAVINCI
|
||||
select VIDEOBUF_DMA_CONTIG
|
||||
help
|
||||
Support for DMXXXX VPFE based frame grabber. This is the
|
||||
common V4L2 module for following DMXXX SoCs from Texas
|
||||
Instruments:- DM6446 & DM355.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called vpfe-capture.
|
||||
|
||||
config VIDEO_DM6446_CCDC
|
||||
tristate "DM6446 CCDC HW module"
|
||||
depends on ARCH_DAVINCI_DM644x && VIDEO_VPFE_CAPTURE
|
||||
select VIDEO_VPSS_SYSTEM
|
||||
default y
|
||||
help
|
||||
Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
|
||||
with decoder modules such as TVP5146 over BT656 or
|
||||
sensor module such as MT9T001 over a raw interface. This
|
||||
module configures the interface and CCDC/ISIF to do
|
||||
video frame capture from slave decoders.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called vpfe.
|
||||
|
||||
config VIDEO_DM355_CCDC
|
||||
tristate "DM355 CCDC HW module"
|
||||
depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE
|
||||
select VIDEO_VPSS_SYSTEM
|
||||
default y
|
||||
help
|
||||
Enables DM355 CCD hw module. DM355 CCDC hw interfaces
|
||||
with decoder modules such as TVP5146 over BT656 or
|
||||
sensor module such as MT9T001 over a raw interface. This
|
||||
module configures the interface and CCDC/ISIF to do
|
||||
video frame capture from a slave decoders
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called vpfe.
|
||||
|
||||
source "drivers/media/video/bt8xx/Kconfig"
|
||||
|
||||
config VIDEO_PMS
|
||||
|
|
@ -690,6 +781,8 @@ source "drivers/media/video/ivtv/Kconfig"
|
|||
|
||||
source "drivers/media/video/cx18/Kconfig"
|
||||
|
||||
source "drivers/media/video/saa7164/Kconfig"
|
||||
|
||||
config VIDEO_M32R_AR
|
||||
tristate "AR devices"
|
||||
depends on M32R && VIDEO_V4L1
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
|
|||
obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
|
||||
obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o
|
||||
obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o
|
||||
obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o
|
||||
obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o
|
||||
obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
|
||||
obj-$(CONFIG_VIDEO_BT819) += bt819.o
|
||||
|
|
@ -154,12 +155,17 @@ obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
|
|||
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
|
||||
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
|
||||
|
||||
obj-$(CONFIG_ARCH_DAVINCI) += davinci/
|
||||
|
||||
obj-$(CONFIG_VIDEO_AU0828) += au0828/
|
||||
|
||||
obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/
|
||||
obj-$(CONFIG_VIDEO_SAA7164) += saa7164/
|
||||
|
||||
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
|
||||
|
||||
obj-$(CONFIG_ARCH_DAVINCI) += davinci/
|
||||
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
|
||||
EXTRA_CFLAGS += -Idrivers/media/common/tuners
|
||||
|
|
|
|||
202
drivers/media/video/adv7180.c
Normal file
202
drivers/media/video/adv7180.c
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* adv7180.c Analog Devices ADV7180 video decoder driver
|
||||
* Copyright (c) 2009 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-id.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
|
||||
#define DRIVER_NAME "adv7180"
|
||||
|
||||
#define ADV7180_INPUT_CONTROL_REG 0x00
|
||||
#define ADV7180_INPUT_CONTROL_PAL_BG_NTSC_J_SECAM 0x00
|
||||
#define ADV7180_AUTODETECT_ENABLE_REG 0x07
|
||||
#define ADV7180_AUTODETECT_DEFAULT 0x7f
|
||||
|
||||
|
||||
#define ADV7180_STATUS1_REG 0x10
|
||||
#define ADV7180_STATUS1_AUTOD_MASK 0x70
|
||||
#define ADV7180_STATUS1_AUTOD_NTSM_M_J 0x00
|
||||
#define ADV7180_STATUS1_AUTOD_NTSC_4_43 0x10
|
||||
#define ADV7180_STATUS1_AUTOD_PAL_M 0x20
|
||||
#define ADV7180_STATUS1_AUTOD_PAL_60 0x30
|
||||
#define ADV7180_STATUS1_AUTOD_PAL_B_G 0x40
|
||||
#define ADV7180_STATUS1_AUTOD_SECAM 0x50
|
||||
#define ADV7180_STATUS1_AUTOD_PAL_COMB 0x60
|
||||
#define ADV7180_STATUS1_AUTOD_SECAM_525 0x70
|
||||
|
||||
#define ADV7180_IDENT_REG 0x11
|
||||
#define ADV7180_ID_7180 0x18
|
||||
|
||||
|
||||
struct adv7180_state {
|
||||
struct v4l2_subdev sd;
|
||||
};
|
||||
|
||||
static v4l2_std_id determine_norm(struct i2c_client *client)
|
||||
{
|
||||
u8 status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
|
||||
|
||||
switch (status1 & ADV7180_STATUS1_AUTOD_MASK) {
|
||||
case ADV7180_STATUS1_AUTOD_NTSM_M_J:
|
||||
return V4L2_STD_NTSC_M_JP;
|
||||
case ADV7180_STATUS1_AUTOD_NTSC_4_43:
|
||||
return V4L2_STD_NTSC_443;
|
||||
case ADV7180_STATUS1_AUTOD_PAL_M:
|
||||
return V4L2_STD_PAL_M;
|
||||
case ADV7180_STATUS1_AUTOD_PAL_60:
|
||||
return V4L2_STD_PAL_60;
|
||||
case ADV7180_STATUS1_AUTOD_PAL_B_G:
|
||||
return V4L2_STD_PAL;
|
||||
case ADV7180_STATUS1_AUTOD_SECAM:
|
||||
return V4L2_STD_SECAM;
|
||||
case ADV7180_STATUS1_AUTOD_PAL_COMB:
|
||||
return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N;
|
||||
case ADV7180_STATUS1_AUTOD_SECAM_525:
|
||||
return V4L2_STD_SECAM;
|
||||
default:
|
||||
return V4L2_STD_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static inline struct adv7180_state *to_state(struct v4l2_subdev *sd)
|
||||
{
|
||||
return container_of(sd, struct adv7180_state, sd);
|
||||
}
|
||||
|
||||
static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
*std = determine_norm(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7180_g_chip_ident(struct v4l2_subdev *sd,
|
||||
struct v4l2_dbg_chip_ident *chip)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7180, 0);
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_video_ops adv7180_video_ops = {
|
||||
.querystd = adv7180_querystd,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_core_ops adv7180_core_ops = {
|
||||
.g_chip_ident = adv7180_g_chip_ident,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops adv7180_ops = {
|
||||
.core = &adv7180_core_ops,
|
||||
.video = &adv7180_video_ops,
|
||||
};
|
||||
|
||||
/*
|
||||
* Generic i2c probe
|
||||
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
|
||||
*/
|
||||
|
||||
static int adv7180_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adv7180_state *state;
|
||||
struct v4l2_subdev *sd;
|
||||
int ret;
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -EIO;
|
||||
|
||||
v4l_info(client, "chip found @ 0x%02x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
state = kzalloc(sizeof(struct adv7180_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
return -ENOMEM;
|
||||
sd = &state->sd;
|
||||
v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
|
||||
|
||||
/* Initialize adv7180 */
|
||||
/* enable autodetection */
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
|
||||
ADV7180_INPUT_CONTROL_PAL_BG_NTSC_J_SECAM);
|
||||
if (ret > 0)
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
ADV7180_AUTODETECT_ENABLE_REG,
|
||||
ADV7180_AUTODETECT_DEFAULT);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR DRIVER_NAME
|
||||
": Failed to communicate to chip: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7180_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
kfree(to_state(sd));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adv7180_id[] = {
|
||||
{DRIVER_NAME, 0},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, adv7180_id);
|
||||
|
||||
static struct i2c_driver adv7180_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRIVER_NAME,
|
||||
},
|
||||
.probe = adv7180_probe,
|
||||
.remove = adv7180_remove,
|
||||
.id_table = adv7180_id,
|
||||
};
|
||||
|
||||
static __init int adv7180_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adv7180_driver);
|
||||
}
|
||||
|
||||
static __exit void adv7180_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adv7180_driver);
|
||||
}
|
||||
|
||||
module_init(adv7180_init);
|
||||
module_exit(adv7180_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver");
|
||||
MODULE_AUTHOR("Mocean Laboratories");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
|
|
@ -24,7 +24,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include <media/adv7343.h>
|
||||
#include <media/v4l2-device.h>
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ void au0828_card_setup(struct au0828_dev *dev)
|
|||
be abstracted out if we ever need to support a different
|
||||
demod) */
|
||||
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
|
||||
"au8522", "au8522", 0x8e >> 1);
|
||||
"au8522", "au8522", 0x8e >> 1, NULL);
|
||||
if (sd == NULL)
|
||||
printk(KERN_ERR "analog subdev registration failed\n");
|
||||
}
|
||||
|
|
@ -221,7 +221,7 @@ void au0828_card_setup(struct au0828_dev *dev)
|
|||
if (dev->board.tuner_type != TUNER_ABSENT) {
|
||||
/* Load the tuner module, which does the attach */
|
||||
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
|
||||
"tuner", "tuner", dev->board.tuner_addr);
|
||||
"tuner", "tuner", dev->board.tuner_addr, NULL);
|
||||
if (sd == NULL)
|
||||
printk(KERN_ERR "tuner subdev registration fail\n");
|
||||
|
||||
|
|
|
|||
|
|
@ -3524,8 +3524,8 @@ void __devinit bttv_init_card2(struct bttv *btv)
|
|||
};
|
||||
struct v4l2_subdev *sd;
|
||||
|
||||
sd = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
|
||||
&btv->c.i2c_adap, "saa6588", "saa6588", addrs);
|
||||
sd = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
|
||||
&btv->c.i2c_adap, "saa6588", "saa6588", 0, addrs);
|
||||
btv->has_saa6588 = (sd != NULL);
|
||||
}
|
||||
|
||||
|
|
@ -3549,8 +3549,8 @@ void __devinit bttv_init_card2(struct bttv *btv)
|
|||
I2C_CLIENT_END
|
||||
};
|
||||
|
||||
btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
|
||||
&btv->c.i2c_adap, "msp3400", "msp3400", addrs);
|
||||
btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
|
||||
&btv->c.i2c_adap, "msp3400", "msp3400", 0, addrs);
|
||||
if (btv->sd_msp34xx)
|
||||
return;
|
||||
goto no_audio;
|
||||
|
|
@ -3563,16 +3563,16 @@ void __devinit bttv_init_card2(struct bttv *btv)
|
|||
I2C_CLIENT_END
|
||||
};
|
||||
|
||||
if (v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
|
||||
&btv->c.i2c_adap, "tda7432", "tda7432", addrs))
|
||||
if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
|
||||
&btv->c.i2c_adap, "tda7432", "tda7432", 0, addrs))
|
||||
return;
|
||||
goto no_audio;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
/* The user specified that we should probe for tvaudio */
|
||||
btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
|
||||
&btv->c.i2c_adap, "tvaudio", "tvaudio", tvaudio_addrs());
|
||||
btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
|
||||
&btv->c.i2c_adap, "tvaudio", "tvaudio", 0, tvaudio_addrs());
|
||||
if (btv->sd_tvaudio)
|
||||
return;
|
||||
goto no_audio;
|
||||
|
|
@ -3591,13 +3591,13 @@ void __devinit bttv_init_card2(struct bttv *btv)
|
|||
it really is a msp3400, so it will return NULL when the device
|
||||
found is really something else (e.g. a tea6300). */
|
||||
if (!bttv_tvcards[btv->c.type].no_msp34xx) {
|
||||
btv->sd_msp34xx = v4l2_i2c_new_probed_subdev_addr(&btv->c.v4l2_dev,
|
||||
btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
|
||||
&btv->c.i2c_adap, "msp3400", "msp3400",
|
||||
I2C_ADDR_MSP3400 >> 1);
|
||||
0, I2C_ADDRS(I2C_ADDR_MSP3400 >> 1));
|
||||
} else if (bttv_tvcards[btv->c.type].msp34xx_alt) {
|
||||
btv->sd_msp34xx = v4l2_i2c_new_probed_subdev_addr(&btv->c.v4l2_dev,
|
||||
btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
|
||||
&btv->c.i2c_adap, "msp3400", "msp3400",
|
||||
I2C_ADDR_MSP3400_ALT >> 1);
|
||||
0, I2C_ADDRS(I2C_ADDR_MSP3400_ALT >> 1));
|
||||
}
|
||||
|
||||
/* If we found a msp34xx, then we're done. */
|
||||
|
|
@ -3611,14 +3611,14 @@ void __devinit bttv_init_card2(struct bttv *btv)
|
|||
I2C_CLIENT_END
|
||||
};
|
||||
|
||||
if (v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
|
||||
&btv->c.i2c_adap, "tda7432", "tda7432", addrs))
|
||||
if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
|
||||
&btv->c.i2c_adap, "tda7432", "tda7432", 0, addrs))
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now see if we can find one of the tvaudio devices. */
|
||||
btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
|
||||
&btv->c.i2c_adap, "tvaudio", "tvaudio", tvaudio_addrs());
|
||||
btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
|
||||
&btv->c.i2c_adap, "tvaudio", "tvaudio", 0, tvaudio_addrs());
|
||||
if (btv->sd_tvaudio)
|
||||
return;
|
||||
|
||||
|
|
@ -3641,15 +3641,15 @@ void __devinit bttv_init_tuner(struct bttv *btv)
|
|||
|
||||
/* Load tuner module before issuing tuner config call! */
|
||||
if (bttv_tvcards[btv->c.type].has_radio)
|
||||
v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
|
||||
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
|
||||
&btv->c.i2c_adap, "tuner", "tuner",
|
||||
v4l2_i2c_tuner_addrs(ADDRS_RADIO));
|
||||
v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
|
||||
0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
|
||||
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
|
||||
&btv->c.i2c_adap, "tuner", "tuner",
|
||||
v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
|
||||
v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
|
||||
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
|
||||
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
|
||||
&btv->c.i2c_adap, "tuner", "tuner",
|
||||
v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
|
||||
0, v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
|
||||
|
||||
tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
|
||||
tun_setup.type = btv->tuner_type;
|
||||
|
|
|
|||
|
|
@ -1955,7 +1955,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
|
|||
|
||||
cam->sensor_addr = 0x42;
|
||||
cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, &cam->i2c_adapter,
|
||||
"ov7670", "ov7670", cam->sensor_addr);
|
||||
"ov7670", "ov7670", cam->sensor_addr, NULL);
|
||||
if (cam->sensor == NULL) {
|
||||
ret = -ENODEV;
|
||||
goto out_smbus;
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ MODULE_PARM_DESC(enc_pcm_bufs,
|
|||
"Number of encoder PCM buffers\n"
|
||||
"\t\t\tDefault is computed from other enc_pcm_* parameters");
|
||||
|
||||
MODULE_PARM_DESC(cx18_first_minor, "Set kernel number assigned to first card");
|
||||
MODULE_PARM_DESC(cx18_first_minor, "Set device node number assigned to first card");
|
||||
|
||||
MODULE_AUTHOR("Hans Verkuil");
|
||||
MODULE_DESCRIPTION("CX23418 driver");
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ static int cx18_i2c_new_ir(struct i2c_adapter *adap, u32 hw, const char *type,
|
|||
/* Our default information for ir-kbd-i2c.c to use */
|
||||
switch (hw) {
|
||||
case CX18_HW_Z8F0811_IR_RX_HAUP:
|
||||
info.platform_data = &z8f0811_ir_init_data;
|
||||
info.platform_data = (void *) &z8f0811_ir_init_data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -139,16 +139,16 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
|
|||
|
||||
if (hw == CX18_HW_TUNER) {
|
||||
/* special tuner group handling */
|
||||
sd = v4l2_i2c_new_probed_subdev(&cx->v4l2_dev,
|
||||
adap, mod, type, cx->card_i2c->radio);
|
||||
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
|
||||
adap, mod, type, 0, cx->card_i2c->radio);
|
||||
if (sd != NULL)
|
||||
sd->grp_id = hw;
|
||||
sd = v4l2_i2c_new_probed_subdev(&cx->v4l2_dev,
|
||||
adap, mod, type, cx->card_i2c->demod);
|
||||
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
|
||||
adap, mod, type, 0, cx->card_i2c->demod);
|
||||
if (sd != NULL)
|
||||
sd->grp_id = hw;
|
||||
sd = v4l2_i2c_new_probed_subdev(&cx->v4l2_dev,
|
||||
adap, mod, type, cx->card_i2c->tv);
|
||||
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
|
||||
adap, mod, type, 0, cx->card_i2c->tv);
|
||||
if (sd != NULL)
|
||||
sd->grp_id = hw;
|
||||
return sd != NULL ? 0 : -1;
|
||||
|
|
@ -162,7 +162,7 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
|
|||
return -1;
|
||||
|
||||
/* It's an I2C device other than an analog tuner or IR chip */
|
||||
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, mod, type, hw_addrs[idx]);
|
||||
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, mod, type, hw_addrs[idx], NULL);
|
||||
if (sd != NULL)
|
||||
sd->grp_id = hw;
|
||||
return sd != NULL ? 0 : -1;
|
||||
|
|
|
|||
|
|
@ -245,9 +245,9 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
|
|||
video_set_drvdata(s->video_dev, s);
|
||||
|
||||
/* Register device. First try the desired minor, then any free one. */
|
||||
ret = video_register_device(s->video_dev, vfl_type, num);
|
||||
ret = video_register_device_no_warn(s->video_dev, vfl_type, num);
|
||||
if (ret < 0) {
|
||||
CX18_ERR("Couldn't register v4l2 device for %s kernel number %d\n",
|
||||
CX18_ERR("Couldn't register v4l2 device for %s (device node number %d)\n",
|
||||
s->name, num);
|
||||
video_device_release(s->video_dev);
|
||||
s->video_dev = NULL;
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ void cx231xx_card_setup(struct cx231xx *dev)
|
|||
if (dev->board.decoder == CX231XX_AVDECODER) {
|
||||
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
|
||||
&dev->i2c_bus[0].i2c_adap,
|
||||
"cx25840", "cx25840", 0x88 >> 1);
|
||||
"cx25840", "cx25840", 0x88 >> 1, NULL);
|
||||
if (dev->sd_cx25840 == NULL)
|
||||
cx231xx_info("cx25840 subdev registration failure\n");
|
||||
cx25840_call(dev, core, load_fw);
|
||||
|
|
@ -323,7 +323,7 @@ void cx231xx_card_setup(struct cx231xx *dev)
|
|||
if (dev->board.tuner_type != TUNER_ABSENT) {
|
||||
dev->sd_tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev,
|
||||
&dev->i2c_bus[1].i2c_adap,
|
||||
"tuner", "tuner", 0xc2 >> 1);
|
||||
"tuner", "tuner", 0xc2 >> 1, NULL);
|
||||
if (dev->sd_tuner == NULL)
|
||||
cx231xx_info("tuner subdev registration failure\n");
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,6 @@ struct netup_ci_state {
|
|||
void *priv;
|
||||
};
|
||||
|
||||
struct mutex gpio_mutex;/* Two CiMax's uses same GPIO lines */
|
||||
|
||||
int netup_read_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg,
|
||||
u8 *buf, int len)
|
||||
|
|
@ -183,10 +182,11 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot,
|
|||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&gpio_mutex);
|
||||
mutex_lock(&dev->gpio_lock);
|
||||
|
||||
/* write addr */
|
||||
cx_write(MC417_OEN, NETUP_EN_ALL);
|
||||
msleep(2);
|
||||
cx_write(MC417_RWD, NETUP_CTRL_OFF |
|
||||
NETUP_ADLO | (0xff & addr));
|
||||
cx_clear(MC417_RWD, NETUP_ADLO);
|
||||
|
|
@ -194,9 +194,10 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot,
|
|||
NETUP_ADHI | (0xff & (addr >> 8)));
|
||||
cx_clear(MC417_RWD, NETUP_ADHI);
|
||||
|
||||
if (read) /* data in */
|
||||
if (read) { /* data in */
|
||||
cx_write(MC417_OEN, NETUP_EN_ALL | NETUP_DATA);
|
||||
else /* data out */
|
||||
msleep(2);
|
||||
} else /* data out */
|
||||
cx_write(MC417_RWD, NETUP_CTRL_OFF | data);
|
||||
|
||||
/* choose chip */
|
||||
|
|
@ -206,7 +207,7 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot,
|
|||
cx_clear(MC417_RWD, (read) ? NETUP_RD : NETUP_WR);
|
||||
mem = netup_ci_get_mem(dev);
|
||||
|
||||
mutex_unlock(&gpio_mutex);
|
||||
mutex_unlock(&dev->gpio_lock);
|
||||
|
||||
if (!read)
|
||||
if (mem < 0)
|
||||
|
|
@ -403,7 +404,6 @@ int netup_ci_init(struct cx23885_tsport *port)
|
|||
switch (port->nr) {
|
||||
case 1:
|
||||
state->ci_i2c_addr = 0x40;
|
||||
mutex_init(&gpio_mutex);
|
||||
break;
|
||||
case 2:
|
||||
state->ci_i2c_addr = 0x41;
|
||||
|
|
|
|||
|
|
@ -210,6 +210,10 @@ struct cx23885_board cx23885_boards[] = {
|
|||
.portb = CX23885_MPEG_ENCODER,
|
||||
.portc = CX23885_MPEG_DVB,
|
||||
},
|
||||
[CX23885_BOARD_COMPRO_VIDEOMATE_E800] = {
|
||||
.name = "Compro VideoMate E800",
|
||||
.portc = CX23885_MPEG_DVB,
|
||||
},
|
||||
};
|
||||
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
|
||||
|
||||
|
|
@ -341,6 +345,10 @@ struct cx23885_subid cx23885_subids[] = {
|
|||
.subvendor = 0x0070,
|
||||
.subdevice = 0x8541,
|
||||
.card = CX23885_BOARD_HAUPPAUGE_HVR1850,
|
||||
}, {
|
||||
.subvendor = 0x1858,
|
||||
.subdevice = 0xe800,
|
||||
.card = CX23885_BOARD_COMPRO_VIDEOMATE_E800,
|
||||
},
|
||||
};
|
||||
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
|
||||
|
|
@ -536,6 +544,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
|
|||
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
|
||||
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
|
||||
case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
|
||||
case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
|
||||
/* Tuner Reset Command */
|
||||
bitmask = 0x04;
|
||||
break;
|
||||
|
|
@ -687,6 +696,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
|
|||
break;
|
||||
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
|
||||
case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
|
||||
case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
|
||||
/* GPIO-2 xc3028 tuner reset */
|
||||
|
||||
/* The following GPIO's are on the internal AVCore (cx25840) */
|
||||
|
|
@ -911,6 +921,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
|
|||
case CX23885_BOARD_HAUPPAUGE_HVR1255:
|
||||
case CX23885_BOARD_HAUPPAUGE_HVR1210:
|
||||
case CX23885_BOARD_HAUPPAUGE_HVR1850:
|
||||
case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
|
||||
default:
|
||||
ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
|
||||
ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
|
||||
|
|
@ -927,9 +938,10 @@ void cx23885_card_setup(struct cx23885_dev *dev)
|
|||
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
|
||||
case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
|
||||
case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
|
||||
case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
|
||||
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
|
||||
&dev->i2c_bus[2].i2c_adap,
|
||||
"cx25840", "cx25840", 0x88 >> 1);
|
||||
"cx25840", "cx25840", 0x88 >> 1, NULL);
|
||||
v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -758,6 +758,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
|
|||
int i;
|
||||
|
||||
mutex_init(&dev->lock);
|
||||
mutex_init(&dev->gpio_lock);
|
||||
|
||||
atomic_inc(&dev->refcount);
|
||||
|
||||
|
|
|
|||
|
|
@ -255,15 +255,18 @@ static struct tda18271_std_map hauppauge_hvr1200_tda18271_std_map = {
|
|||
static struct tda18271_config hauppauge_tda18271_config = {
|
||||
.std_map = &hauppauge_tda18271_std_map,
|
||||
.gate = TDA18271_GATE_ANALOG,
|
||||
.output_opt = TDA18271_OUTPUT_LT_OFF,
|
||||
};
|
||||
|
||||
static struct tda18271_config hauppauge_hvr1200_tuner_config = {
|
||||
.std_map = &hauppauge_hvr1200_tda18271_std_map,
|
||||
.gate = TDA18271_GATE_ANALOG,
|
||||
.output_opt = TDA18271_OUTPUT_LT_OFF,
|
||||
};
|
||||
|
||||
static struct tda18271_config hauppauge_hvr1210_tuner_config = {
|
||||
.gate = TDA18271_GATE_DIGITAL,
|
||||
.output_opt = TDA18271_OUTPUT_LT_OFF,
|
||||
};
|
||||
|
||||
static struct tda18271_std_map hauppauge_hvr127x_std_map = {
|
||||
|
|
@ -275,6 +278,7 @@ static struct tda18271_std_map hauppauge_hvr127x_std_map = {
|
|||
|
||||
static struct tda18271_config hauppauge_hvr127x_config = {
|
||||
.std_map = &hauppauge_hvr127x_std_map,
|
||||
.output_opt = TDA18271_OUTPUT_LT_OFF,
|
||||
};
|
||||
|
||||
static struct lgdt3305_config hauppauge_lgdt3305_config = {
|
||||
|
|
@ -743,6 +747,7 @@ static int dvb_register(struct cx23885_tsport *port)
|
|||
}
|
||||
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
|
||||
case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
|
||||
case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
|
||||
i2c_bus = &dev->i2c_bus[0];
|
||||
|
||||
fe0->dvb.frontend = dvb_attach(zl10353_attach,
|
||||
|
|
|
|||
|
|
@ -1521,11 +1521,11 @@ int cx23885_video_register(struct cx23885_dev *dev)
|
|||
if (dev->tuner_addr)
|
||||
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
|
||||
&dev->i2c_bus[1].i2c_adap,
|
||||
"tuner", "tuner", dev->tuner_addr);
|
||||
"tuner", "tuner", dev->tuner_addr, NULL);
|
||||
else
|
||||
sd = v4l2_i2c_new_probed_subdev(&dev->v4l2_dev,
|
||||
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
|
||||
&dev->i2c_bus[1].i2c_adap,
|
||||
"tuner", "tuner", v4l2_i2c_tuner_addrs(ADDRS_TV));
|
||||
"tuner", "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV));
|
||||
if (sd) {
|
||||
struct tuner_setup tun_setup;
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
#define CX23885_BOARD_MYGICA_X8506 22
|
||||
#define CX23885_BOARD_MAGICPRO_PROHDTVE2 23
|
||||
#define CX23885_BOARD_HAUPPAUGE_HVR1850 24
|
||||
#define CX23885_BOARD_COMPRO_VIDEOMATE_E800 25
|
||||
|
||||
#define GPIO_0 0x00000001
|
||||
#define GPIO_1 0x00000002
|
||||
|
|
@ -325,6 +326,7 @@ struct cx23885_dev {
|
|||
|
||||
int nr;
|
||||
struct mutex lock;
|
||||
struct mutex gpio_lock;
|
||||
|
||||
/* board details */
|
||||
unsigned int board;
|
||||
|
|
|
|||
|
|
@ -97,11 +97,11 @@ void netup_get_card_info(struct i2c_adapter *i2c_adap,
|
|||
{
|
||||
int i, j;
|
||||
|
||||
cinfo->rev = netup_eeprom_read(i2c_adap, 13);
|
||||
cinfo->rev = netup_eeprom_read(i2c_adap, 63);
|
||||
|
||||
for (i = 0, j = 0; i < 6; i++, j++)
|
||||
for (i = 64, j = 0; i < 70; i++, j++)
|
||||
cinfo->port[0].mac[j] = netup_eeprom_read(i2c_adap, i);
|
||||
|
||||
for (i = 6, j = 0; i < 12; i++, j++)
|
||||
for (i = 70, j = 0; i < 76; i++, j++)
|
||||
cinfo->port[1].mac[j] = netup_eeprom_read(i2c_adap, i);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3439,20 +3439,20 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
|
|||
The radio_type is sometimes missing, or set to UNSET but
|
||||
later code configures a tea5767.
|
||||
*/
|
||||
v4l2_i2c_new_probed_subdev(&core->v4l2_dev, &core->i2c_adap,
|
||||
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
|
||||
"tuner", "tuner",
|
||||
v4l2_i2c_tuner_addrs(ADDRS_RADIO));
|
||||
0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
|
||||
if (has_demod)
|
||||
v4l2_i2c_new_probed_subdev(&core->v4l2_dev,
|
||||
v4l2_i2c_new_subdev(&core->v4l2_dev,
|
||||
&core->i2c_adap, "tuner", "tuner",
|
||||
v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
|
||||
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
|
||||
if (core->board.tuner_addr == ADDR_UNSET) {
|
||||
v4l2_i2c_new_probed_subdev(&core->v4l2_dev,
|
||||
v4l2_i2c_new_subdev(&core->v4l2_dev,
|
||||
&core->i2c_adap, "tuner", "tuner",
|
||||
has_demod ? tv_addrs + 4 : tv_addrs);
|
||||
0, has_demod ? tv_addrs + 4 : tv_addrs);
|
||||
} else {
|
||||
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
|
||||
"tuner", "tuner", core->board.tuner_addr);
|
||||
"tuner", "tuner", core->board.tuner_addr, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1881,14 +1881,14 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
|
|||
|
||||
if (core->board.audio_chip == V4L2_IDENT_WM8775)
|
||||
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
|
||||
"wm8775", "wm8775", 0x36 >> 1);
|
||||
"wm8775", "wm8775", 0x36 >> 1, NULL);
|
||||
|
||||
if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
|
||||
/* This probes for a tda9874 as is used on some
|
||||
Pixelview Ultra boards. */
|
||||
v4l2_i2c_new_probed_subdev_addr(&core->v4l2_dev,
|
||||
v4l2_i2c_new_subdev(&core->v4l2_dev,
|
||||
&core->i2c_adap,
|
||||
"tvaudio", "tvaudio", 0xb0 >> 1);
|
||||
"tvaudio", "tvaudio", 0, I2C_ADDRS(0xb0 >> 1));
|
||||
}
|
||||
|
||||
switch (core->boardnr) {
|
||||
|
|
|
|||
17
drivers/media/video/davinci/Makefile
Normal file
17
drivers/media/video/davinci/Makefile
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#
|
||||
# Makefile for the davinci video device drivers.
|
||||
#
|
||||
|
||||
# VPIF
|
||||
obj-$(CONFIG_VIDEO_DAVINCI_VPIF) += vpif.o
|
||||
|
||||
#DM646x EVM Display driver
|
||||
obj-$(CONFIG_DISPLAY_DAVINCI_DM646X_EVM) += vpif_display.o
|
||||
#DM646x EVM Capture driver
|
||||
obj-$(CONFIG_CAPTURE_DAVINCI_DM646X_EVM) += vpif_capture.o
|
||||
|
||||
# Capture: DM6446 and DM355
|
||||
obj-$(CONFIG_VIDEO_VPSS_SYSTEM) += vpss.o
|
||||
obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o
|
||||
obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o
|
||||
obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o
|
||||
110
drivers/media/video/davinci/ccdc_hw_device.h
Normal file
110
drivers/media/video/davinci/ccdc_hw_device.h
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2009 Texas Instruments Inc
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* ccdc device API
|
||||
*/
|
||||
#ifndef _CCDC_HW_DEVICE_H
|
||||
#define _CCDC_HW_DEVICE_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/device.h>
|
||||
#include <media/davinci/vpfe_types.h>
|
||||
#include <media/davinci/ccdc_types.h>
|
||||
|
||||
/*
|
||||
* ccdc hw operations
|
||||
*/
|
||||
struct ccdc_hw_ops {
|
||||
/* Pointer to initialize function to initialize ccdc device */
|
||||
int (*open) (struct device *dev);
|
||||
/* Pointer to deinitialize function */
|
||||
int (*close) (struct device *dev);
|
||||
/* set ccdc base address */
|
||||
void (*set_ccdc_base)(void *base, int size);
|
||||
/* Pointer to function to enable or disable ccdc */
|
||||
void (*enable) (int en);
|
||||
/* reset sbl. only for 6446 */
|
||||
void (*reset) (void);
|
||||
/* enable output to sdram */
|
||||
void (*enable_out_to_sdram) (int en);
|
||||
/* Pointer to function to set hw parameters */
|
||||
int (*set_hw_if_params) (struct vpfe_hw_if_param *param);
|
||||
/* get interface parameters */
|
||||
int (*get_hw_if_params) (struct vpfe_hw_if_param *param);
|
||||
/*
|
||||
* Pointer to function to set parameters. Used
|
||||
* for implementing VPFE_S_CCDC_PARAMS
|
||||
*/
|
||||
int (*set_params) (void *params);
|
||||
/*
|
||||
* Pointer to function to get parameter. Used
|
||||
* for implementing VPFE_G_CCDC_PARAMS
|
||||
*/
|
||||
int (*get_params) (void *params);
|
||||
/* Pointer to function to configure ccdc */
|
||||
int (*configure) (void);
|
||||
|
||||
/* Pointer to function to set buffer type */
|
||||
int (*set_buftype) (enum ccdc_buftype buf_type);
|
||||
/* Pointer to function to get buffer type */
|
||||
enum ccdc_buftype (*get_buftype) (void);
|
||||
/* Pointer to function to set frame format */
|
||||
int (*set_frame_format) (enum ccdc_frmfmt frm_fmt);
|
||||
/* Pointer to function to get frame format */
|
||||
enum ccdc_frmfmt (*get_frame_format) (void);
|
||||
/* enumerate hw pix formats */
|
||||
int (*enum_pix)(u32 *hw_pix, int i);
|
||||
/* Pointer to function to set buffer type */
|
||||
u32 (*get_pixel_format) (void);
|
||||
/* Pointer to function to get pixel format. */
|
||||
int (*set_pixel_format) (u32 pixfmt);
|
||||
/* Pointer to function to set image window */
|
||||
int (*set_image_window) (struct v4l2_rect *win);
|
||||
/* Pointer to function to set image window */
|
||||
void (*get_image_window) (struct v4l2_rect *win);
|
||||
/* Pointer to function to get line length */
|
||||
unsigned int (*get_line_length) (void);
|
||||
|
||||
/* Query CCDC control IDs */
|
||||
int (*queryctrl)(struct v4l2_queryctrl *qctrl);
|
||||
/* Set CCDC control */
|
||||
int (*set_control)(struct v4l2_control *ctrl);
|
||||
/* Get CCDC control */
|
||||
int (*get_control)(struct v4l2_control *ctrl);
|
||||
|
||||
/* Pointer to function to set frame buffer address */
|
||||
void (*setfbaddr) (unsigned long addr);
|
||||
/* Pointer to function to get field id */
|
||||
int (*getfid) (void);
|
||||
};
|
||||
|
||||
struct ccdc_hw_device {
|
||||
/* ccdc device name */
|
||||
char name[32];
|
||||
/* module owner */
|
||||
struct module *owner;
|
||||
/* hw ops */
|
||||
struct ccdc_hw_ops hw_ops;
|
||||
};
|
||||
|
||||
/* Used by CCDC module to register & unregister with vpfe capture driver */
|
||||
int vpfe_register_ccdc_device(struct ccdc_hw_device *dev);
|
||||
void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
978
drivers/media/video/davinci/dm355_ccdc.c
Normal file
978
drivers/media/video/davinci/dm355_ccdc.c
Normal file
|
|
@ -0,0 +1,978 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2009 Texas Instruments Inc
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* CCDC hardware module for DM355
|
||||
* ------------------------------
|
||||
*
|
||||
* This module is for configuring DM355 CCD controller of VPFE to capture
|
||||
* Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
|
||||
* such as Defect Pixel Correction, Color Space Conversion etc to
|
||||
* pre-process the Bayer RGB data, before writing it to SDRAM. This
|
||||
* module also allows application to configure individual
|
||||
* module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL.
|
||||
* To do so, application include dm355_ccdc.h and vpfe_capture.h header
|
||||
* files. The setparams() API is called by vpfe_capture driver
|
||||
* to configure module parameters
|
||||
*
|
||||
* TODO: 1) Raw bayer parameter settings and bayer capture
|
||||
* 2) Split module parameter structure to module specific ioctl structs
|
||||
* 3) add support for lense shading correction
|
||||
* 4) investigate if enum used for user space type definition
|
||||
* to be replaced by #defines or integer
|
||||
*/
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/davinci/dm355_ccdc.h>
|
||||
#include <media/davinci/vpss.h>
|
||||
#include "dm355_ccdc_regs.h"
|
||||
#include "ccdc_hw_device.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("CCDC Driver for DM355");
|
||||
MODULE_AUTHOR("Texas Instruments");
|
||||
|
||||
static struct device *dev;
|
||||
|
||||
/* Object for CCDC raw mode */
|
||||
static struct ccdc_params_raw ccdc_hw_params_raw = {
|
||||
.pix_fmt = CCDC_PIXFMT_RAW,
|
||||
.frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
|
||||
.win = CCDC_WIN_VGA,
|
||||
.fid_pol = VPFE_PINPOL_POSITIVE,
|
||||
.vd_pol = VPFE_PINPOL_POSITIVE,
|
||||
.hd_pol = VPFE_PINPOL_POSITIVE,
|
||||
.gain = {
|
||||
.r_ye = 256,
|
||||
.gb_g = 256,
|
||||
.gr_cy = 256,
|
||||
.b_mg = 256
|
||||
},
|
||||
.config_params = {
|
||||
.datasft = 2,
|
||||
.data_sz = CCDC_DATA_10BITS,
|
||||
.mfilt1 = CCDC_NO_MEDIAN_FILTER1,
|
||||
.mfilt2 = CCDC_NO_MEDIAN_FILTER2,
|
||||
.alaw = {
|
||||
.gama_wd = 2,
|
||||
},
|
||||
.blk_clamp = {
|
||||
.sample_pixel = 1,
|
||||
.dc_sub = 25
|
||||
},
|
||||
.col_pat_field0 = {
|
||||
.olop = CCDC_GREEN_BLUE,
|
||||
.olep = CCDC_BLUE,
|
||||
.elop = CCDC_RED,
|
||||
.elep = CCDC_GREEN_RED
|
||||
},
|
||||
.col_pat_field1 = {
|
||||
.olop = CCDC_GREEN_BLUE,
|
||||
.olep = CCDC_BLUE,
|
||||
.elop = CCDC_RED,
|
||||
.elep = CCDC_GREEN_RED
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/* Object for CCDC ycbcr mode */
|
||||
static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = {
|
||||
.win = CCDC_WIN_PAL,
|
||||
.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
|
||||
.frm_fmt = CCDC_FRMFMT_INTERLACED,
|
||||
.fid_pol = VPFE_PINPOL_POSITIVE,
|
||||
.vd_pol = VPFE_PINPOL_POSITIVE,
|
||||
.hd_pol = VPFE_PINPOL_POSITIVE,
|
||||
.bt656_enable = 1,
|
||||
.pix_order = CCDC_PIXORDER_CBYCRY,
|
||||
.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
|
||||
};
|
||||
|
||||
static enum vpfe_hw_if_type ccdc_if_type;
|
||||
static void *__iomem ccdc_base_addr;
|
||||
static int ccdc_addr_size;
|
||||
|
||||
/* Raw Bayer formats */
|
||||
static u32 ccdc_raw_bayer_pix_formats[] =
|
||||
{V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
|
||||
|
||||
/* Raw YUV formats */
|
||||
static u32 ccdc_raw_yuv_pix_formats[] =
|
||||
{V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
|
||||
|
||||
/* register access routines */
|
||||
static inline u32 regr(u32 offset)
|
||||
{
|
||||
return __raw_readl(ccdc_base_addr + offset);
|
||||
}
|
||||
|
||||
static inline void regw(u32 val, u32 offset)
|
||||
{
|
||||
__raw_writel(val, ccdc_base_addr + offset);
|
||||
}
|
||||
|
||||
static void ccdc_set_ccdc_base(void *addr, int size)
|
||||
{
|
||||
ccdc_base_addr = addr;
|
||||
ccdc_addr_size = size;
|
||||
}
|
||||
|
||||
static void ccdc_enable(int en)
|
||||
{
|
||||
unsigned int temp;
|
||||
temp = regr(SYNCEN);
|
||||
temp &= (~CCDC_SYNCEN_VDHDEN_MASK);
|
||||
temp |= (en & CCDC_SYNCEN_VDHDEN_MASK);
|
||||
regw(temp, SYNCEN);
|
||||
}
|
||||
|
||||
static void ccdc_enable_output_to_sdram(int en)
|
||||
{
|
||||
unsigned int temp;
|
||||
temp = regr(SYNCEN);
|
||||
temp &= (~(CCDC_SYNCEN_WEN_MASK));
|
||||
temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK);
|
||||
regw(temp, SYNCEN);
|
||||
}
|
||||
|
||||
static void ccdc_config_gain_offset(void)
|
||||
{
|
||||
/* configure gain */
|
||||
regw(ccdc_hw_params_raw.gain.r_ye, RYEGAIN);
|
||||
regw(ccdc_hw_params_raw.gain.gr_cy, GRCYGAIN);
|
||||
regw(ccdc_hw_params_raw.gain.gb_g, GBGGAIN);
|
||||
regw(ccdc_hw_params_raw.gain.b_mg, BMGGAIN);
|
||||
/* configure offset */
|
||||
regw(ccdc_hw_params_raw.ccdc_offset, OFFSET);
|
||||
}
|
||||
|
||||
/*
|
||||
* ccdc_restore_defaults()
|
||||
* This function restore power on defaults in the ccdc registers
|
||||
*/
|
||||
static int ccdc_restore_defaults(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
dev_dbg(dev, "\nstarting ccdc_restore_defaults...");
|
||||
/* set all registers to zero */
|
||||
for (i = 0; i <= CCDC_REG_LAST; i += 4)
|
||||
regw(0, i);
|
||||
|
||||
/* now override the values with power on defaults in registers */
|
||||
regw(MODESET_DEFAULT, MODESET);
|
||||
/* no culling support */
|
||||
regw(CULH_DEFAULT, CULH);
|
||||
regw(CULV_DEFAULT, CULV);
|
||||
/* Set default Gain and Offset */
|
||||
ccdc_hw_params_raw.gain.r_ye = GAIN_DEFAULT;
|
||||
ccdc_hw_params_raw.gain.gb_g = GAIN_DEFAULT;
|
||||
ccdc_hw_params_raw.gain.gr_cy = GAIN_DEFAULT;
|
||||
ccdc_hw_params_raw.gain.b_mg = GAIN_DEFAULT;
|
||||
ccdc_config_gain_offset();
|
||||
regw(OUTCLIP_DEFAULT, OUTCLIP);
|
||||
regw(LSCCFG2_DEFAULT, LSCCFG2);
|
||||
/* select ccdc input */
|
||||
if (vpss_select_ccdc_source(VPSS_CCDCIN)) {
|
||||
dev_dbg(dev, "\ncouldn't select ccdc input source");
|
||||
return -EFAULT;
|
||||
}
|
||||
/* select ccdc clock */
|
||||
if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) {
|
||||
dev_dbg(dev, "\ncouldn't enable ccdc clock");
|
||||
return -EFAULT;
|
||||
}
|
||||
dev_dbg(dev, "\nEnd of ccdc_restore_defaults...");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ccdc_open(struct device *device)
|
||||
{
|
||||
dev = device;
|
||||
return ccdc_restore_defaults();
|
||||
}
|
||||
|
||||
static int ccdc_close(struct device *device)
|
||||
{
|
||||
/* disable clock */
|
||||
vpss_enable_clock(VPSS_CCDC_CLOCK, 0);
|
||||
/* do nothing for now */
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* ccdc_setwin()
|
||||
* This function will configure the window size to
|
||||
* be capture in CCDC reg.
|
||||
*/
|
||||
static void ccdc_setwin(struct v4l2_rect *image_win,
|
||||
enum ccdc_frmfmt frm_fmt, int ppc)
|
||||
{
|
||||
int horz_start, horz_nr_pixels;
|
||||
int vert_start, vert_nr_lines;
|
||||
int mid_img = 0;
|
||||
|
||||
dev_dbg(dev, "\nStarting ccdc_setwin...");
|
||||
|
||||
/*
|
||||
* ppc - per pixel count. indicates how many pixels per cell
|
||||
* output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
|
||||
* raw capture this is 1
|
||||
*/
|
||||
horz_start = image_win->left << (ppc - 1);
|
||||
horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
|
||||
|
||||
/* Writing the horizontal info into the registers */
|
||||
regw(horz_start, SPH);
|
||||
regw(horz_nr_pixels, NPH);
|
||||
vert_start = image_win->top;
|
||||
|
||||
if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
|
||||
vert_nr_lines = (image_win->height >> 1) - 1;
|
||||
vert_start >>= 1;
|
||||
/* Since first line doesn't have any data */
|
||||
vert_start += 1;
|
||||
/* configure VDINT0 and VDINT1 */
|
||||
regw(vert_start, VDINT0);
|
||||
} else {
|
||||
/* Since first line doesn't have any data */
|
||||
vert_start += 1;
|
||||
vert_nr_lines = image_win->height - 1;
|
||||
/* configure VDINT0 and VDINT1 */
|
||||
mid_img = vert_start + (image_win->height / 2);
|
||||
regw(vert_start, VDINT0);
|
||||
regw(mid_img, VDINT1);
|
||||
}
|
||||
regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0);
|
||||
regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1);
|
||||
regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV);
|
||||
dev_dbg(dev, "\nEnd of ccdc_setwin...");
|
||||
}
|
||||
|
||||
static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
|
||||
{
|
||||
if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT ||
|
||||
ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) {
|
||||
dev_dbg(dev, "Invalid value of data shift\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 ||
|
||||
ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) {
|
||||
dev_dbg(dev, "Invalid value of median filter1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 ||
|
||||
ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) {
|
||||
dev_dbg(dev, "Invalid value of median filter2\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((ccdcparam->med_filt_thres < 0) ||
|
||||
(ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) {
|
||||
dev_dbg(dev, "Invalid value of median filter thresold\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ccdcparam->data_sz < CCDC_DATA_16BITS ||
|
||||
ccdcparam->data_sz > CCDC_DATA_8BITS) {
|
||||
dev_dbg(dev, "Invalid value of data size\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ccdcparam->alaw.enable) {
|
||||
if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 ||
|
||||
ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) {
|
||||
dev_dbg(dev, "Invalid value of ALAW\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ccdcparam->blk_clamp.b_clamp_enable) {
|
||||
if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS ||
|
||||
ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) {
|
||||
dev_dbg(dev, "Invalid value of sample pixel\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES ||
|
||||
ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) {
|
||||
dev_dbg(dev, "Invalid value of sample lines\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parameter operations */
|
||||
static int ccdc_set_params(void __user *params)
|
||||
{
|
||||
struct ccdc_config_params_raw ccdc_raw_params;
|
||||
int x;
|
||||
|
||||
/* only raw module parameters can be set through the IOCTL */
|
||||
if (ccdc_if_type != VPFE_RAW_BAYER)
|
||||
return -EINVAL;
|
||||
|
||||
x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
|
||||
if (x) {
|
||||
dev_dbg(dev, "ccdc_set_params: error in copying ccdc"
|
||||
"params, %d\n", x);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!validate_ccdc_param(&ccdc_raw_params)) {
|
||||
memcpy(&ccdc_hw_params_raw.config_params,
|
||||
&ccdc_raw_params,
|
||||
sizeof(ccdc_raw_params));
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* This function will configure CCDC for YCbCr video capture */
|
||||
static void ccdc_config_ycbcr(void)
|
||||
{
|
||||
struct ccdc_params_ycbcr *params = &ccdc_hw_params_ycbcr;
|
||||
u32 temp;
|
||||
|
||||
/* first set the CCDC power on defaults values in all registers */
|
||||
dev_dbg(dev, "\nStarting ccdc_config_ycbcr...");
|
||||
ccdc_restore_defaults();
|
||||
|
||||
/* configure pixel format & video frame format */
|
||||
temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) <<
|
||||
CCDC_INPUT_MODE_SHIFT) |
|
||||
((params->frm_fmt & CCDC_FRM_FMT_MASK) <<
|
||||
CCDC_FRM_FMT_SHIFT));
|
||||
|
||||
/* setup BT.656 sync mode */
|
||||
if (params->bt656_enable) {
|
||||
regw(CCDC_REC656IF_BT656_EN, REC656IF);
|
||||
/*
|
||||
* configure the FID, VD, HD pin polarity fld,hd pol positive,
|
||||
* vd negative, 8-bit pack mode
|
||||
*/
|
||||
temp |= CCDC_VD_POL_NEGATIVE;
|
||||
} else { /* y/c external sync mode */
|
||||
temp |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
|
||||
CCDC_FID_POL_SHIFT) |
|
||||
((params->hd_pol & CCDC_HD_POL_MASK) <<
|
||||
CCDC_HD_POL_SHIFT) |
|
||||
((params->vd_pol & CCDC_VD_POL_MASK) <<
|
||||
CCDC_VD_POL_SHIFT));
|
||||
}
|
||||
|
||||
/* pack the data to 8-bit */
|
||||
temp |= CCDC_DATA_PACK_ENABLE;
|
||||
|
||||
regw(temp, MODESET);
|
||||
|
||||
/* configure video window */
|
||||
ccdc_setwin(¶ms->win, params->frm_fmt, 2);
|
||||
|
||||
/* configure the order of y cb cr in SD-RAM */
|
||||
temp = (params->pix_order << CCDC_Y8POS_SHIFT);
|
||||
temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC;
|
||||
regw(temp, CCDCFG);
|
||||
|
||||
/*
|
||||
* configure the horizontal line offset. This is done by rounding up
|
||||
* width to a multiple of 16 pixels and multiply by two to account for
|
||||
* y:cb:cr 4:2:2 data
|
||||
*/
|
||||
regw(((params->win.width * 2 + 31) >> 5), HSIZE);
|
||||
|
||||
/* configure the memory line offset */
|
||||
if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) {
|
||||
/* two fields are interleaved in memory */
|
||||
regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST);
|
||||
}
|
||||
|
||||
dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* ccdc_config_black_clamp()
|
||||
* configure parameters for Optical Black Clamp
|
||||
*/
|
||||
static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (!bclamp->b_clamp_enable) {
|
||||
/* configure DCSub */
|
||||
regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB);
|
||||
regw(0x0000, CLAMP);
|
||||
return;
|
||||
}
|
||||
/* Enable the Black clamping, set sample lines and pixels */
|
||||
val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) |
|
||||
((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
|
||||
CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE;
|
||||
regw(val, CLAMP);
|
||||
|
||||
/* If Black clamping is enable then make dcsub 0 */
|
||||
val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK)
|
||||
<< CCDC_NUM_LINE_CALC_SHIFT;
|
||||
regw(val, DCSUB);
|
||||
}
|
||||
|
||||
/*
|
||||
* ccdc_config_black_compense()
|
||||
* configure parameters for Black Compensation
|
||||
*/
|
||||
static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = (bcomp->b & CCDC_BLK_COMP_MASK) |
|
||||
((bcomp->gb & CCDC_BLK_COMP_MASK) <<
|
||||
CCDC_BLK_COMP_GB_COMP_SHIFT);
|
||||
regw(val, BLKCMP1);
|
||||
|
||||
val = ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
|
||||
CCDC_BLK_COMP_GR_COMP_SHIFT) |
|
||||
((bcomp->r & CCDC_BLK_COMP_MASK) <<
|
||||
CCDC_BLK_COMP_R_COMP_SHIFT);
|
||||
regw(val, BLKCMP0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ccdc_write_dfc_entry()
|
||||
* write an entry in the dfc table.
|
||||
*/
|
||||
int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
|
||||
{
|
||||
/* TODO This is to be re-visited and adjusted */
|
||||
#define DFC_WRITE_WAIT_COUNT 1000
|
||||
u32 val, count = DFC_WRITE_WAIT_COUNT;
|
||||
|
||||
regw(dfc->dft_corr_vert[index], DFCMEM0);
|
||||
regw(dfc->dft_corr_horz[index], DFCMEM1);
|
||||
regw(dfc->dft_corr_sub1[index], DFCMEM2);
|
||||
regw(dfc->dft_corr_sub2[index], DFCMEM3);
|
||||
regw(dfc->dft_corr_sub3[index], DFCMEM4);
|
||||
/* set WR bit to write */
|
||||
val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK;
|
||||
regw(val, DFCMEMCTL);
|
||||
|
||||
/*
|
||||
* Assume, it is very short. If we get an error, we need to
|
||||
* adjust this value
|
||||
*/
|
||||
while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK)
|
||||
count--;
|
||||
/*
|
||||
* TODO We expect the count to be non-zero to be successful. Adjust
|
||||
* the count if write requires more time
|
||||
*/
|
||||
|
||||
if (count) {
|
||||
dev_err(dev, "defect table write timeout !!!\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ccdc_config_vdfc()
|
||||
* configure parameters for Vertical Defect Correction
|
||||
*/
|
||||
static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc)
|
||||
{
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
/* Configure General Defect Correction. The table used is from IPIPE */
|
||||
val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK;
|
||||
|
||||
/* Configure Vertical Defect Correction if needed */
|
||||
if (!dfc->ver_dft_en) {
|
||||
/* Enable only General Defect Correction */
|
||||
regw(val, DFCCTL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dfc->table_size > CCDC_DFT_TABLE_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
val |= CCDC_DFCCTL_VDFC_DISABLE;
|
||||
val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) <<
|
||||
CCDC_DFCCTL_VDFCSL_SHIFT;
|
||||
val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) <<
|
||||
CCDC_DFCCTL_VDFCUDA_SHIFT;
|
||||
val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) <<
|
||||
CCDC_DFCCTL_VDFLSFT_SHIFT;
|
||||
regw(val , DFCCTL);
|
||||
|
||||
/* clear address ptr to offset 0 */
|
||||
val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT;
|
||||
|
||||
/* write defect table entries */
|
||||
for (i = 0; i < dfc->table_size; i++) {
|
||||
/* increment address for non zero index */
|
||||
if (i != 0)
|
||||
val = CCDC_DFCMEMCTL_INC_ADDR;
|
||||
regw(val, DFCMEMCTL);
|
||||
if (ccdc_write_dfc_entry(i, dfc) < 0)
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* update saturation level and enable dfc */
|
||||
regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT);
|
||||
val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK <<
|
||||
CCDC_DFCCTL_VDFCEN_SHIFT);
|
||||
regw(val, DFCCTL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ccdc_config_csc()
|
||||
* configure parameters for color space conversion
|
||||
* Each register CSCM0-7 has two values in S8Q5 format.
|
||||
*/
|
||||
static void ccdc_config_csc(struct ccdc_csc *csc)
|
||||
{
|
||||
u32 val1, val2;
|
||||
int i;
|
||||
|
||||
if (!csc->enable)
|
||||
return;
|
||||
|
||||
/* Enable the CSC sub-module */
|
||||
regw(CCDC_CSC_ENABLE, CSCCTL);
|
||||
|
||||
/* Converting the co-eff as per the format of the register */
|
||||
for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) {
|
||||
if ((i % 2) == 0) {
|
||||
/* CSCM - LSB */
|
||||
val1 = (csc->coeff[i].integer &
|
||||
CCDC_CSC_COEF_INTEG_MASK)
|
||||
<< CCDC_CSC_COEF_INTEG_SHIFT;
|
||||
/*
|
||||
* convert decimal part to binary. Use 2 decimal
|
||||
* precision, user values range from .00 - 0.99
|
||||
*/
|
||||
val1 |= (((csc->coeff[i].decimal &
|
||||
CCDC_CSC_COEF_DECIMAL_MASK) *
|
||||
CCDC_CSC_DEC_MAX) / 100);
|
||||
} else {
|
||||
|
||||
/* CSCM - MSB */
|
||||
val2 = (csc->coeff[i].integer &
|
||||
CCDC_CSC_COEF_INTEG_MASK)
|
||||
<< CCDC_CSC_COEF_INTEG_SHIFT;
|
||||
val2 |= (((csc->coeff[i].decimal &
|
||||
CCDC_CSC_COEF_DECIMAL_MASK) *
|
||||
CCDC_CSC_DEC_MAX) / 100);
|
||||
val2 <<= CCDC_CSCM_MSB_SHIFT;
|
||||
val2 |= val1;
|
||||
regw(val2, (CSCM0 + ((i - 1) << 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ccdc_config_color_patterns()
|
||||
* configure parameters for color patterns
|
||||
*/
|
||||
static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0,
|
||||
struct ccdc_col_pat *pat1)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) |
|
||||
(pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) |
|
||||
(pat1->elop << 12) | (pat1->elep << 14));
|
||||
regw(val, COLPTN);
|
||||
}
|
||||
|
||||
/* This function will configure CCDC for Raw mode image capture */
|
||||
static int ccdc_config_raw(void)
|
||||
{
|
||||
struct ccdc_params_raw *params = &ccdc_hw_params_raw;
|
||||
struct ccdc_config_params_raw *config_params =
|
||||
&ccdc_hw_params_raw.config_params;
|
||||
unsigned int val;
|
||||
|
||||
dev_dbg(dev, "\nStarting ccdc_config_raw...");
|
||||
|
||||
/* restore power on defaults to register */
|
||||
ccdc_restore_defaults();
|
||||
|
||||
/* CCDCFG register:
|
||||
* set CCD Not to swap input since input is RAW data
|
||||
* set FID detection function to Latch at V-Sync
|
||||
* set WENLOG - ccdc valid area to AND
|
||||
* set TRGSEL to WENBIT
|
||||
* set EXTRG to DISABLE
|
||||
* disable latching function on VSYNC - shadowed registers
|
||||
*/
|
||||
regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC |
|
||||
CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN |
|
||||
CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG);
|
||||
|
||||
/*
|
||||
* Set VDHD direction to input, input type to raw input
|
||||
* normal data polarity, do not use external WEN
|
||||
*/
|
||||
val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL |
|
||||
CCDC_EXWEN_DISABLE);
|
||||
|
||||
/*
|
||||
* Configure the vertical sync polarity (MODESET.VDPOL), horizontal
|
||||
* sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL),
|
||||
* frame format(progressive or interlace), & pixel format (Input mode)
|
||||
*/
|
||||
val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
|
||||
((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
|
||||
((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
|
||||
((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
|
||||
((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT));
|
||||
|
||||
/* set pack for alaw compression */
|
||||
if ((config_params->data_sz == CCDC_DATA_8BITS) ||
|
||||
config_params->alaw.enable)
|
||||
val |= CCDC_DATA_PACK_ENABLE;
|
||||
|
||||
/* Configure for LPF */
|
||||
if (config_params->lpf_enable)
|
||||
val |= (config_params->lpf_enable & CCDC_LPF_MASK) <<
|
||||
CCDC_LPF_SHIFT;
|
||||
|
||||
/* Configure the data shift */
|
||||
val |= (config_params->datasft & CCDC_DATASFT_MASK) <<
|
||||
CCDC_DATASFT_SHIFT;
|
||||
regw(val , MODESET);
|
||||
dev_dbg(dev, "\nWriting 0x%x to MODESET...\n", val);
|
||||
|
||||
/* Configure the Median Filter threshold */
|
||||
regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT);
|
||||
|
||||
/* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */
|
||||
val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT |
|
||||
CCDC_CFA_MOSAIC;
|
||||
|
||||
/* Enable and configure aLaw register if needed */
|
||||
if (config_params->alaw.enable) {
|
||||
val |= (CCDC_ALAW_ENABLE |
|
||||
((config_params->alaw.gama_wd &
|
||||
CCDC_ALAW_GAMA_WD_MASK) <<
|
||||
CCDC_GAMMAWD_INPUT_SHIFT));
|
||||
}
|
||||
|
||||
/* Configure Median filter1 & filter2 */
|
||||
val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) |
|
||||
(config_params->mfilt2 << CCDC_MFILT2_SHIFT));
|
||||
|
||||
regw(val, GAMMAWD);
|
||||
dev_dbg(dev, "\nWriting 0x%x to GAMMAWD...\n", val);
|
||||
|
||||
/* configure video window */
|
||||
ccdc_setwin(¶ms->win, params->frm_fmt, 1);
|
||||
|
||||
/* Optical Clamp Averaging */
|
||||
ccdc_config_black_clamp(&config_params->blk_clamp);
|
||||
|
||||
/* Black level compensation */
|
||||
ccdc_config_black_compense(&config_params->blk_comp);
|
||||
|
||||
/* Vertical Defect Correction if needed */
|
||||
if (ccdc_config_vdfc(&config_params->vertical_dft) < 0)
|
||||
return -EFAULT;
|
||||
|
||||
/* color space conversion */
|
||||
ccdc_config_csc(&config_params->csc);
|
||||
|
||||
/* color pattern */
|
||||
ccdc_config_color_patterns(&config_params->col_pat_field0,
|
||||
&config_params->col_pat_field1);
|
||||
|
||||
/* Configure the Gain & offset control */
|
||||
ccdc_config_gain_offset();
|
||||
|
||||
dev_dbg(dev, "\nWriting %x to COLPTN...\n", val);
|
||||
|
||||
/* Configure DATAOFST register */
|
||||
val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) <<
|
||||
CCDC_DATAOFST_H_SHIFT;
|
||||
val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) <<
|
||||
CCDC_DATAOFST_V_SHIFT;
|
||||
regw(val, DATAOFST);
|
||||
|
||||
/* configuring HSIZE register */
|
||||
val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) <<
|
||||
CCDC_HSIZE_FLIP_SHIFT;
|
||||
|
||||
/* If pack 8 is enable then 1 pixel will take 1 byte */
|
||||
if ((config_params->data_sz == CCDC_DATA_8BITS) ||
|
||||
config_params->alaw.enable) {
|
||||
val |= (((params->win.width) + 31) >> 5) &
|
||||
CCDC_HSIZE_VAL_MASK;
|
||||
|
||||
/* adjust to multiple of 32 */
|
||||
dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n",
|
||||
(((params->win.width) + 31) >> 5) &
|
||||
CCDC_HSIZE_VAL_MASK);
|
||||
} else {
|
||||
/* else one pixel will take 2 byte */
|
||||
val |= (((params->win.width * 2) + 31) >> 5) &
|
||||
CCDC_HSIZE_VAL_MASK;
|
||||
|
||||
dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n",
|
||||
(((params->win.width * 2) + 31) >> 5) &
|
||||
CCDC_HSIZE_VAL_MASK);
|
||||
}
|
||||
regw(val, HSIZE);
|
||||
|
||||
/* Configure SDOFST register */
|
||||
if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
|
||||
if (params->image_invert_enable) {
|
||||
/* For interlace inverse mode */
|
||||
regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST);
|
||||
dev_dbg(dev, "\nWriting %x to SDOFST...\n",
|
||||
CCDC_SDOFST_INTERLACE_INVERSE);
|
||||
} else {
|
||||
/* For interlace non inverse mode */
|
||||
regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST);
|
||||
dev_dbg(dev, "\nWriting %x to SDOFST...\n",
|
||||
CCDC_SDOFST_INTERLACE_NORMAL);
|
||||
}
|
||||
} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
|
||||
if (params->image_invert_enable) {
|
||||
/* For progessive inverse mode */
|
||||
regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST);
|
||||
dev_dbg(dev, "\nWriting %x to SDOFST...\n",
|
||||
CCDC_SDOFST_PROGRESSIVE_INVERSE);
|
||||
} else {
|
||||
/* For progessive non inverse mode */
|
||||
regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST);
|
||||
dev_dbg(dev, "\nWriting %x to SDOFST...\n",
|
||||
CCDC_SDOFST_PROGRESSIVE_NORMAL);
|
||||
}
|
||||
}
|
||||
dev_dbg(dev, "\nend of ccdc_config_raw...");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ccdc_configure(void)
|
||||
{
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER)
|
||||
return ccdc_config_raw();
|
||||
else
|
||||
ccdc_config_ycbcr();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ccdc_set_buftype(enum ccdc_buftype buf_type)
|
||||
{
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER)
|
||||
ccdc_hw_params_raw.buf_type = buf_type;
|
||||
else
|
||||
ccdc_hw_params_ycbcr.buf_type = buf_type;
|
||||
return 0;
|
||||
}
|
||||
static enum ccdc_buftype ccdc_get_buftype(void)
|
||||
{
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER)
|
||||
return ccdc_hw_params_raw.buf_type;
|
||||
return ccdc_hw_params_ycbcr.buf_type;
|
||||
}
|
||||
|
||||
static int ccdc_enum_pix(u32 *pix, int i)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER) {
|
||||
if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
|
||||
*pix = ccdc_raw_bayer_pix_formats[i];
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
|
||||
*pix = ccdc_raw_yuv_pix_formats[i];
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ccdc_set_pixel_format(u32 pixfmt)
|
||||
{
|
||||
struct ccdc_a_law *alaw =
|
||||
&ccdc_hw_params_raw.config_params.alaw;
|
||||
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER) {
|
||||
ccdc_hw_params_raw.pix_fmt = CCDC_PIXFMT_RAW;
|
||||
if (pixfmt == V4L2_PIX_FMT_SBGGR8)
|
||||
alaw->enable = 1;
|
||||
else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (pixfmt == V4L2_PIX_FMT_YUYV)
|
||||
ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
|
||||
else if (pixfmt == V4L2_PIX_FMT_UYVY)
|
||||
ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static u32 ccdc_get_pixel_format(void)
|
||||
{
|
||||
struct ccdc_a_law *alaw =
|
||||
&ccdc_hw_params_raw.config_params.alaw;
|
||||
u32 pixfmt;
|
||||
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER)
|
||||
if (alaw->enable)
|
||||
pixfmt = V4L2_PIX_FMT_SBGGR8;
|
||||
else
|
||||
pixfmt = V4L2_PIX_FMT_SBGGR16;
|
||||
else {
|
||||
if (ccdc_hw_params_ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
|
||||
pixfmt = V4L2_PIX_FMT_YUYV;
|
||||
else
|
||||
pixfmt = V4L2_PIX_FMT_UYVY;
|
||||
}
|
||||
return pixfmt;
|
||||
}
|
||||
static int ccdc_set_image_window(struct v4l2_rect *win)
|
||||
{
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER)
|
||||
ccdc_hw_params_raw.win = *win;
|
||||
else
|
||||
ccdc_hw_params_ycbcr.win = *win;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ccdc_get_image_window(struct v4l2_rect *win)
|
||||
{
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER)
|
||||
*win = ccdc_hw_params_raw.win;
|
||||
else
|
||||
*win = ccdc_hw_params_ycbcr.win;
|
||||
}
|
||||
|
||||
static unsigned int ccdc_get_line_length(void)
|
||||
{
|
||||
struct ccdc_config_params_raw *config_params =
|
||||
&ccdc_hw_params_raw.config_params;
|
||||
unsigned int len;
|
||||
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER) {
|
||||
if ((config_params->alaw.enable) ||
|
||||
(config_params->data_sz == CCDC_DATA_8BITS))
|
||||
len = ccdc_hw_params_raw.win.width;
|
||||
else
|
||||
len = ccdc_hw_params_raw.win.width * 2;
|
||||
} else
|
||||
len = ccdc_hw_params_ycbcr.win.width * 2;
|
||||
return ALIGN(len, 32);
|
||||
}
|
||||
|
||||
static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
|
||||
{
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER)
|
||||
ccdc_hw_params_raw.frm_fmt = frm_fmt;
|
||||
else
|
||||
ccdc_hw_params_ycbcr.frm_fmt = frm_fmt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum ccdc_frmfmt ccdc_get_frame_format(void)
|
||||
{
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER)
|
||||
return ccdc_hw_params_raw.frm_fmt;
|
||||
else
|
||||
return ccdc_hw_params_ycbcr.frm_fmt;
|
||||
}
|
||||
|
||||
static int ccdc_getfid(void)
|
||||
{
|
||||
return (regr(MODESET) >> 15) & 1;
|
||||
}
|
||||
|
||||
/* misc operations */
|
||||
static inline void ccdc_setfbaddr(unsigned long addr)
|
||||
{
|
||||
regw((addr >> 21) & 0x007f, STADRH);
|
||||
regw((addr >> 5) & 0x0ffff, STADRL);
|
||||
}
|
||||
|
||||
static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
|
||||
{
|
||||
ccdc_if_type = params->if_type;
|
||||
|
||||
switch (params->if_type) {
|
||||
case VPFE_BT656:
|
||||
case VPFE_YCBCR_SYNC_16:
|
||||
case VPFE_YCBCR_SYNC_8:
|
||||
ccdc_hw_params_ycbcr.vd_pol = params->vdpol;
|
||||
ccdc_hw_params_ycbcr.hd_pol = params->hdpol;
|
||||
break;
|
||||
default:
|
||||
/* TODO add support for raw bayer here */
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ccdc_hw_device ccdc_hw_dev = {
|
||||
.name = "DM355 CCDC",
|
||||
.owner = THIS_MODULE,
|
||||
.hw_ops = {
|
||||
.open = ccdc_open,
|
||||
.close = ccdc_close,
|
||||
.set_ccdc_base = ccdc_set_ccdc_base,
|
||||
.enable = ccdc_enable,
|
||||
.enable_out_to_sdram = ccdc_enable_output_to_sdram,
|
||||
.set_hw_if_params = ccdc_set_hw_if_params,
|
||||
.set_params = ccdc_set_params,
|
||||
.configure = ccdc_configure,
|
||||
.set_buftype = ccdc_set_buftype,
|
||||
.get_buftype = ccdc_get_buftype,
|
||||
.enum_pix = ccdc_enum_pix,
|
||||
.set_pixel_format = ccdc_set_pixel_format,
|
||||
.get_pixel_format = ccdc_get_pixel_format,
|
||||
.set_frame_format = ccdc_set_frame_format,
|
||||
.get_frame_format = ccdc_get_frame_format,
|
||||
.set_image_window = ccdc_set_image_window,
|
||||
.get_image_window = ccdc_get_image_window,
|
||||
.get_line_length = ccdc_get_line_length,
|
||||
.setfbaddr = ccdc_setfbaddr,
|
||||
.getfid = ccdc_getfid,
|
||||
},
|
||||
};
|
||||
|
||||
static int dm355_ccdc_init(void)
|
||||
{
|
||||
printk(KERN_NOTICE "dm355_ccdc_init\n");
|
||||
if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0)
|
||||
return -1;
|
||||
printk(KERN_NOTICE "%s is registered with vpfe.\n",
|
||||
ccdc_hw_dev.name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dm355_ccdc_exit(void)
|
||||
{
|
||||
vpfe_unregister_ccdc_device(&ccdc_hw_dev);
|
||||
}
|
||||
|
||||
module_init(dm355_ccdc_init);
|
||||
module_exit(dm355_ccdc_exit);
|
||||
310
drivers/media/video/davinci/dm355_ccdc_regs.h
Normal file
310
drivers/media/video/davinci/dm355_ccdc_regs.h
Normal file
|
|
@ -0,0 +1,310 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2009 Texas Instruments Inc
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef _DM355_CCDC_REGS_H
|
||||
#define _DM355_CCDC_REGS_H
|
||||
|
||||
/**************************************************************************\
|
||||
* Register OFFSET Definitions
|
||||
\**************************************************************************/
|
||||
#define SYNCEN 0x00
|
||||
#define MODESET 0x04
|
||||
#define HDWIDTH 0x08
|
||||
#define VDWIDTH 0x0c
|
||||
#define PPLN 0x10
|
||||
#define LPFR 0x14
|
||||
#define SPH 0x18
|
||||
#define NPH 0x1c
|
||||
#define SLV0 0x20
|
||||
#define SLV1 0x24
|
||||
#define NLV 0x28
|
||||
#define CULH 0x2c
|
||||
#define CULV 0x30
|
||||
#define HSIZE 0x34
|
||||
#define SDOFST 0x38
|
||||
#define STADRH 0x3c
|
||||
#define STADRL 0x40
|
||||
#define CLAMP 0x44
|
||||
#define DCSUB 0x48
|
||||
#define COLPTN 0x4c
|
||||
#define BLKCMP0 0x50
|
||||
#define BLKCMP1 0x54
|
||||
#define MEDFILT 0x58
|
||||
#define RYEGAIN 0x5c
|
||||
#define GRCYGAIN 0x60
|
||||
#define GBGGAIN 0x64
|
||||
#define BMGGAIN 0x68
|
||||
#define OFFSET 0x6c
|
||||
#define OUTCLIP 0x70
|
||||
#define VDINT0 0x74
|
||||
#define VDINT1 0x78
|
||||
#define RSV0 0x7c
|
||||
#define GAMMAWD 0x80
|
||||
#define REC656IF 0x84
|
||||
#define CCDCFG 0x88
|
||||
#define FMTCFG 0x8c
|
||||
#define FMTPLEN 0x90
|
||||
#define FMTSPH 0x94
|
||||
#define FMTLNH 0x98
|
||||
#define FMTSLV 0x9c
|
||||
#define FMTLNV 0xa0
|
||||
#define FMTRLEN 0xa4
|
||||
#define FMTHCNT 0xa8
|
||||
#define FMT_ADDR_PTR_B 0xac
|
||||
#define FMT_ADDR_PTR(i) (FMT_ADDR_PTR_B + (i * 4))
|
||||
#define FMTPGM_VF0 0xcc
|
||||
#define FMTPGM_VF1 0xd0
|
||||
#define FMTPGM_AP0 0xd4
|
||||
#define FMTPGM_AP1 0xd8
|
||||
#define FMTPGM_AP2 0xdc
|
||||
#define FMTPGM_AP3 0xe0
|
||||
#define FMTPGM_AP4 0xe4
|
||||
#define FMTPGM_AP5 0xe8
|
||||
#define FMTPGM_AP6 0xec
|
||||
#define FMTPGM_AP7 0xf0
|
||||
#define LSCCFG1 0xf4
|
||||
#define LSCCFG2 0xf8
|
||||
#define LSCH0 0xfc
|
||||
#define LSCV0 0x100
|
||||
#define LSCKH 0x104
|
||||
#define LSCKV 0x108
|
||||
#define LSCMEMCTL 0x10c
|
||||
#define LSCMEMD 0x110
|
||||
#define LSCMEMQ 0x114
|
||||
#define DFCCTL 0x118
|
||||
#define DFCVSAT 0x11c
|
||||
#define DFCMEMCTL 0x120
|
||||
#define DFCMEM0 0x124
|
||||
#define DFCMEM1 0x128
|
||||
#define DFCMEM2 0x12c
|
||||
#define DFCMEM3 0x130
|
||||
#define DFCMEM4 0x134
|
||||
#define CSCCTL 0x138
|
||||
#define CSCM0 0x13c
|
||||
#define CSCM1 0x140
|
||||
#define CSCM2 0x144
|
||||
#define CSCM3 0x148
|
||||
#define CSCM4 0x14c
|
||||
#define CSCM5 0x150
|
||||
#define CSCM6 0x154
|
||||
#define CSCM7 0x158
|
||||
#define DATAOFST 0x15c
|
||||
#define CCDC_REG_LAST DATAOFST
|
||||
/**************************************************************
|
||||
* Define for various register bit mask and shifts for CCDC
|
||||
*
|
||||
**************************************************************/
|
||||
#define CCDC_RAW_IP_MODE 0
|
||||
#define CCDC_VDHDOUT_INPUT 0
|
||||
#define CCDC_YCINSWP_RAW (0 << 4)
|
||||
#define CCDC_EXWEN_DISABLE 0
|
||||
#define CCDC_DATAPOL_NORMAL 0
|
||||
#define CCDC_CCDCFG_FIDMD_LATCH_VSYNC 0
|
||||
#define CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC (1 << 6)
|
||||
#define CCDC_CCDCFG_WENLOG_AND 0
|
||||
#define CCDC_CCDCFG_TRGSEL_WEN 0
|
||||
#define CCDC_CCDCFG_EXTRG_DISABLE 0
|
||||
#define CCDC_CFA_MOSAIC 0
|
||||
#define CCDC_Y8POS_SHIFT 11
|
||||
|
||||
#define CCDC_VDC_DFCVSAT_MASK 0x3fff
|
||||
#define CCDC_DATAOFST_MASK 0x0ff
|
||||
#define CCDC_DATAOFST_H_SHIFT 0
|
||||
#define CCDC_DATAOFST_V_SHIFT 8
|
||||
#define CCDC_GAMMAWD_CFA_MASK 1
|
||||
#define CCDC_GAMMAWD_CFA_SHIFT 5
|
||||
#define CCDC_GAMMAWD_INPUT_SHIFT 2
|
||||
#define CCDC_FID_POL_MASK 1
|
||||
#define CCDC_FID_POL_SHIFT 4
|
||||
#define CCDC_HD_POL_MASK 1
|
||||
#define CCDC_HD_POL_SHIFT 3
|
||||
#define CCDC_VD_POL_MASK 1
|
||||
#define CCDC_VD_POL_SHIFT 2
|
||||
#define CCDC_VD_POL_NEGATIVE (1 << 2)
|
||||
#define CCDC_FRM_FMT_MASK 1
|
||||
#define CCDC_FRM_FMT_SHIFT 7
|
||||
#define CCDC_DATA_SZ_MASK 7
|
||||
#define CCDC_DATA_SZ_SHIFT 8
|
||||
#define CCDC_VDHDOUT_MASK 1
|
||||
#define CCDC_VDHDOUT_SHIFT 0
|
||||
#define CCDC_EXWEN_MASK 1
|
||||
#define CCDC_EXWEN_SHIFT 5
|
||||
#define CCDC_INPUT_MODE_MASK 3
|
||||
#define CCDC_INPUT_MODE_SHIFT 12
|
||||
#define CCDC_PIX_FMT_MASK 3
|
||||
#define CCDC_PIX_FMT_SHIFT 12
|
||||
#define CCDC_DATAPOL_MASK 1
|
||||
#define CCDC_DATAPOL_SHIFT 6
|
||||
#define CCDC_WEN_ENABLE (1 << 1)
|
||||
#define CCDC_VDHDEN_ENABLE (1 << 16)
|
||||
#define CCDC_LPF_ENABLE (1 << 14)
|
||||
#define CCDC_ALAW_ENABLE 1
|
||||
#define CCDC_ALAW_GAMA_WD_MASK 7
|
||||
#define CCDC_REC656IF_BT656_EN 3
|
||||
|
||||
#define CCDC_FMTCFG_FMTMODE_MASK 3
|
||||
#define CCDC_FMTCFG_FMTMODE_SHIFT 1
|
||||
#define CCDC_FMTCFG_LNUM_MASK 3
|
||||
#define CCDC_FMTCFG_LNUM_SHIFT 4
|
||||
#define CCDC_FMTCFG_ADDRINC_MASK 7
|
||||
#define CCDC_FMTCFG_ADDRINC_SHIFT 8
|
||||
|
||||
#define CCDC_CCDCFG_FIDMD_SHIFT 6
|
||||
#define CCDC_CCDCFG_WENLOG_SHIFT 8
|
||||
#define CCDC_CCDCFG_TRGSEL_SHIFT 9
|
||||
#define CCDC_CCDCFG_EXTRG_SHIFT 10
|
||||
#define CCDC_CCDCFG_MSBINVI_SHIFT 13
|
||||
|
||||
#define CCDC_HSIZE_FLIP_SHIFT 12
|
||||
#define CCDC_HSIZE_FLIP_MASK 1
|
||||
#define CCDC_HSIZE_VAL_MASK 0xFFF
|
||||
#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249
|
||||
#define CCDC_SDOFST_INTERLACE_INVERSE 0x4B6D
|
||||
#define CCDC_SDOFST_INTERLACE_NORMAL 0x0B6D
|
||||
#define CCDC_SDOFST_PROGRESSIVE_INVERSE 0x4000
|
||||
#define CCDC_SDOFST_PROGRESSIVE_NORMAL 0
|
||||
#define CCDC_START_PX_HOR_MASK 0x7FFF
|
||||
#define CCDC_NUM_PX_HOR_MASK 0x7FFF
|
||||
#define CCDC_START_VER_ONE_MASK 0x7FFF
|
||||
#define CCDC_START_VER_TWO_MASK 0x7FFF
|
||||
#define CCDC_NUM_LINES_VER 0x7FFF
|
||||
|
||||
#define CCDC_BLK_CLAMP_ENABLE (1 << 15)
|
||||
#define CCDC_BLK_SGAIN_MASK 0x1F
|
||||
#define CCDC_BLK_ST_PXL_MASK 0x1FFF
|
||||
#define CCDC_BLK_SAMPLE_LN_MASK 3
|
||||
#define CCDC_BLK_SAMPLE_LN_SHIFT 13
|
||||
|
||||
#define CCDC_NUM_LINE_CALC_MASK 3
|
||||
#define CCDC_NUM_LINE_CALC_SHIFT 14
|
||||
|
||||
#define CCDC_BLK_DC_SUB_MASK 0x3FFF
|
||||
#define CCDC_BLK_COMP_MASK 0xFF
|
||||
#define CCDC_BLK_COMP_GB_COMP_SHIFT 8
|
||||
#define CCDC_BLK_COMP_GR_COMP_SHIFT 0
|
||||
#define CCDC_BLK_COMP_R_COMP_SHIFT 8
|
||||
#define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15)
|
||||
#define CCDC_LATCH_ON_VSYNC_ENABLE (0 << 15)
|
||||
#define CCDC_FPC_ENABLE (1 << 15)
|
||||
#define CCDC_FPC_FPC_NUM_MASK 0x7FFF
|
||||
#define CCDC_DATA_PACK_ENABLE (1 << 11)
|
||||
#define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF
|
||||
#define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF
|
||||
#define CCDC_FMT_HORZ_FMTSPH_SHIFT 16
|
||||
#define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF
|
||||
#define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF
|
||||
#define CCDC_FMT_VERT_FMTSLV_SHIFT 16
|
||||
#define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF
|
||||
#define CCDC_VP_OUT_VERT_NUM_SHIFT 17
|
||||
#define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF
|
||||
#define CCDC_VP_OUT_HORZ_NUM_SHIFT 4
|
||||
#define CCDC_VP_OUT_HORZ_ST_MASK 0xF
|
||||
|
||||
#define CCDC_CSC_COEF_INTEG_MASK 7
|
||||
#define CCDC_CSC_COEF_DECIMAL_MASK 0x1f
|
||||
#define CCDC_CSC_COEF_INTEG_SHIFT 5
|
||||
#define CCDC_CSCM_MSB_SHIFT 8
|
||||
#define CCDC_CSC_ENABLE 1
|
||||
#define CCDC_CSC_DEC_MAX 32
|
||||
|
||||
#define CCDC_MFILT1_SHIFT 10
|
||||
#define CCDC_MFILT2_SHIFT 8
|
||||
#define CCDC_MED_FILT_THRESH 0x3FFF
|
||||
#define CCDC_LPF_MASK 1
|
||||
#define CCDC_LPF_SHIFT 14
|
||||
#define CCDC_OFFSET_MASK 0x3FF
|
||||
#define CCDC_DATASFT_MASK 7
|
||||
#define CCDC_DATASFT_SHIFT 8
|
||||
|
||||
#define CCDC_DF_ENABLE 1
|
||||
|
||||
#define CCDC_FMTPLEN_P0_MASK 0xF
|
||||
#define CCDC_FMTPLEN_P1_MASK 0xF
|
||||
#define CCDC_FMTPLEN_P2_MASK 7
|
||||
#define CCDC_FMTPLEN_P3_MASK 7
|
||||
#define CCDC_FMTPLEN_P0_SHIFT 0
|
||||
#define CCDC_FMTPLEN_P1_SHIFT 4
|
||||
#define CCDC_FMTPLEN_P2_SHIFT 8
|
||||
#define CCDC_FMTPLEN_P3_SHIFT 12
|
||||
|
||||
#define CCDC_FMTSPH_MASK 0x1FFF
|
||||
#define CCDC_FMTLNH_MASK 0x1FFF
|
||||
#define CCDC_FMTSLV_MASK 0x1FFF
|
||||
#define CCDC_FMTLNV_MASK 0x7FFF
|
||||
#define CCDC_FMTRLEN_MASK 0x1FFF
|
||||
#define CCDC_FMTHCNT_MASK 0x1FFF
|
||||
|
||||
#define CCDC_ADP_INIT_MASK 0x1FFF
|
||||
#define CCDC_ADP_LINE_SHIFT 13
|
||||
#define CCDC_ADP_LINE_MASK 3
|
||||
#define CCDC_FMTPGN_APTR_MASK 7
|
||||
|
||||
#define CCDC_DFCCTL_GDFCEN_MASK 1
|
||||
#define CCDC_DFCCTL_VDFCEN_MASK 1
|
||||
#define CCDC_DFCCTL_VDFC_DISABLE (0 << 4)
|
||||
#define CCDC_DFCCTL_VDFCEN_SHIFT 4
|
||||
#define CCDC_DFCCTL_VDFCSL_MASK 3
|
||||
#define CCDC_DFCCTL_VDFCSL_SHIFT 5
|
||||
#define CCDC_DFCCTL_VDFCUDA_MASK 1
|
||||
#define CCDC_DFCCTL_VDFCUDA_SHIFT 7
|
||||
#define CCDC_DFCCTL_VDFLSFT_MASK 3
|
||||
#define CCDC_DFCCTL_VDFLSFT_SHIFT 8
|
||||
#define CCDC_DFCMEMCTL_DFCMARST_MASK 1
|
||||
#define CCDC_DFCMEMCTL_DFCMARST_SHIFT 2
|
||||
#define CCDC_DFCMEMCTL_DFCMWR_MASK 1
|
||||
#define CCDC_DFCMEMCTL_DFCMWR_SHIFT 0
|
||||
#define CCDC_DFCMEMCTL_INC_ADDR (0 << 2)
|
||||
|
||||
#define CCDC_LSCCFG_GFTSF_MASK 7
|
||||
#define CCDC_LSCCFG_GFTSF_SHIFT 1
|
||||
#define CCDC_LSCCFG_GFTINV_MASK 0xf
|
||||
#define CCDC_LSCCFG_GFTINV_SHIFT 4
|
||||
#define CCDC_LSC_GFTABLE_SEL_MASK 3
|
||||
#define CCDC_LSC_GFTABLE_EPEL_SHIFT 8
|
||||
#define CCDC_LSC_GFTABLE_OPEL_SHIFT 10
|
||||
#define CCDC_LSC_GFTABLE_EPOL_SHIFT 12
|
||||
#define CCDC_LSC_GFTABLE_OPOL_SHIFT 14
|
||||
#define CCDC_LSC_GFMODE_MASK 3
|
||||
#define CCDC_LSC_GFMODE_SHIFT 4
|
||||
#define CCDC_LSC_DISABLE 0
|
||||
#define CCDC_LSC_ENABLE 1
|
||||
#define CCDC_LSC_TABLE1_SLC 0
|
||||
#define CCDC_LSC_TABLE2_SLC 1
|
||||
#define CCDC_LSC_TABLE3_SLC 2
|
||||
#define CCDC_LSC_MEMADDR_RESET (1 << 2)
|
||||
#define CCDC_LSC_MEMADDR_INCR (0 << 2)
|
||||
#define CCDC_LSC_FRAC_MASK_T1 0xFF
|
||||
#define CCDC_LSC_INT_MASK 3
|
||||
#define CCDC_LSC_FRAC_MASK 0x3FFF
|
||||
#define CCDC_LSC_CENTRE_MASK 0x3FFF
|
||||
#define CCDC_LSC_COEF_MASK 0xff
|
||||
#define CCDC_LSC_COEFL_SHIFT 0
|
||||
#define CCDC_LSC_COEFU_SHIFT 8
|
||||
#define CCDC_GAIN_MASK 0x7FF
|
||||
#define CCDC_SYNCEN_VDHDEN_MASK (1 << 0)
|
||||
#define CCDC_SYNCEN_WEN_MASK (1 << 1)
|
||||
#define CCDC_SYNCEN_WEN_SHIFT 1
|
||||
|
||||
/* Power on Defaults in hardware */
|
||||
#define MODESET_DEFAULT 0x200
|
||||
#define CULH_DEFAULT 0xFFFF
|
||||
#define CULV_DEFAULT 0xFF
|
||||
#define GAIN_DEFAULT 256
|
||||
#define OUTCLIP_DEFAULT 0x3FFF
|
||||
#define LSCCFG2_DEFAULT 0xE
|
||||
|
||||
#endif
|
||||
878
drivers/media/video/davinci/dm644x_ccdc.c
Normal file
878
drivers/media/video/davinci/dm644x_ccdc.c
Normal file
|
|
@ -0,0 +1,878 @@
|
|||
/*
|
||||
* Copyright (C) 2006-2009 Texas Instruments Inc
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* CCDC hardware module for DM6446
|
||||
* ------------------------------
|
||||
*
|
||||
* This module is for configuring CCD controller of DM6446 VPFE to capture
|
||||
* Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
|
||||
* such as Defect Pixel Correction, Color Space Conversion etc to
|
||||
* pre-process the Raw Bayer RGB data, before writing it to SDRAM. This
|
||||
* module also allows application to configure individual
|
||||
* module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL.
|
||||
* To do so, application includes dm644x_ccdc.h and vpfe_capture.h header
|
||||
* files. The setparams() API is called by vpfe_capture driver
|
||||
* to configure module parameters. This file is named DM644x so that other
|
||||
* variants such DM6443 may be supported using the same module.
|
||||
*
|
||||
* TODO: Test Raw bayer parameter settings and bayer capture
|
||||
* Split module parameter structure to module specific ioctl structs
|
||||
* investigate if enum used for user space type definition
|
||||
* to be replaced by #defines or integer
|
||||
*/
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/davinci/dm644x_ccdc.h>
|
||||
#include <media/davinci/vpss.h>
|
||||
#include "dm644x_ccdc_regs.h"
|
||||
#include "ccdc_hw_device.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("CCDC Driver for DM6446");
|
||||
MODULE_AUTHOR("Texas Instruments");
|
||||
|
||||
static struct device *dev;
|
||||
|
||||
/* Object for CCDC raw mode */
|
||||
static struct ccdc_params_raw ccdc_hw_params_raw = {
|
||||
.pix_fmt = CCDC_PIXFMT_RAW,
|
||||
.frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
|
||||
.win = CCDC_WIN_VGA,
|
||||
.fid_pol = VPFE_PINPOL_POSITIVE,
|
||||
.vd_pol = VPFE_PINPOL_POSITIVE,
|
||||
.hd_pol = VPFE_PINPOL_POSITIVE,
|
||||
.config_params = {
|
||||
.data_sz = CCDC_DATA_10BITS,
|
||||
},
|
||||
};
|
||||
|
||||
/* Object for CCDC ycbcr mode */
|
||||
static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = {
|
||||
.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
|
||||
.frm_fmt = CCDC_FRMFMT_INTERLACED,
|
||||
.win = CCDC_WIN_PAL,
|
||||
.fid_pol = VPFE_PINPOL_POSITIVE,
|
||||
.vd_pol = VPFE_PINPOL_POSITIVE,
|
||||
.hd_pol = VPFE_PINPOL_POSITIVE,
|
||||
.bt656_enable = 1,
|
||||
.pix_order = CCDC_PIXORDER_CBYCRY,
|
||||
.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
|
||||
};
|
||||
|
||||
#define CCDC_MAX_RAW_YUV_FORMATS 2
|
||||
|
||||
/* Raw Bayer formats */
|
||||
static u32 ccdc_raw_bayer_pix_formats[] =
|
||||
{V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
|
||||
|
||||
/* Raw YUV formats */
|
||||
static u32 ccdc_raw_yuv_pix_formats[] =
|
||||
{V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
|
||||
|
||||
static void *__iomem ccdc_base_addr;
|
||||
static int ccdc_addr_size;
|
||||
static enum vpfe_hw_if_type ccdc_if_type;
|
||||
|
||||
/* register access routines */
|
||||
static inline u32 regr(u32 offset)
|
||||
{
|
||||
return __raw_readl(ccdc_base_addr + offset);
|
||||
}
|
||||
|
||||
static inline void regw(u32 val, u32 offset)
|
||||
{
|
||||
__raw_writel(val, ccdc_base_addr + offset);
|
||||
}
|
||||
|
||||
static void ccdc_set_ccdc_base(void *addr, int size)
|
||||
{
|
||||
ccdc_base_addr = addr;
|
||||
ccdc_addr_size = size;
|
||||
}
|
||||
|
||||
static void ccdc_enable(int flag)
|
||||
{
|
||||
regw(flag, CCDC_PCR);
|
||||
}
|
||||
|
||||
static void ccdc_enable_vport(int flag)
|
||||
{
|
||||
if (flag)
|
||||
/* enable video port */
|
||||
regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG);
|
||||
else
|
||||
regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG);
|
||||
}
|
||||
|
||||
/*
|
||||
* ccdc_setwin()
|
||||
* This function will configure the window size
|
||||
* to be capture in CCDC reg
|
||||
*/
|
||||
void ccdc_setwin(struct v4l2_rect *image_win,
|
||||
enum ccdc_frmfmt frm_fmt,
|
||||
int ppc)
|
||||
{
|
||||
int horz_start, horz_nr_pixels;
|
||||
int vert_start, vert_nr_lines;
|
||||
int val = 0, mid_img = 0;
|
||||
|
||||
dev_dbg(dev, "\nStarting ccdc_setwin...");
|
||||
/*
|
||||
* ppc - per pixel count. indicates how many pixels per cell
|
||||
* output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
|
||||
* raw capture this is 1
|
||||
*/
|
||||
horz_start = image_win->left << (ppc - 1);
|
||||
horz_nr_pixels = (image_win->width << (ppc - 1)) - 1;
|
||||
regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels,
|
||||
CCDC_HORZ_INFO);
|
||||
|
||||
vert_start = image_win->top;
|
||||
|
||||
if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
|
||||
vert_nr_lines = (image_win->height >> 1) - 1;
|
||||
vert_start >>= 1;
|
||||
/* Since first line doesn't have any data */
|
||||
vert_start += 1;
|
||||
/* configure VDINT0 */
|
||||
val = (vert_start << CCDC_VDINT_VDINT0_SHIFT);
|
||||
regw(val, CCDC_VDINT);
|
||||
|
||||
} else {
|
||||
/* Since first line doesn't have any data */
|
||||
vert_start += 1;
|
||||
vert_nr_lines = image_win->height - 1;
|
||||
/*
|
||||
* configure VDINT0 and VDINT1. VDINT1 will be at half
|
||||
* of image height
|
||||
*/
|
||||
mid_img = vert_start + (image_win->height / 2);
|
||||
val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) |
|
||||
(mid_img & CCDC_VDINT_VDINT1_MASK);
|
||||
regw(val, CCDC_VDINT);
|
||||
|
||||
}
|
||||
regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start,
|
||||
CCDC_VERT_START);
|
||||
regw(vert_nr_lines, CCDC_VERT_LINES);
|
||||
dev_dbg(dev, "\nEnd of ccdc_setwin...");
|
||||
}
|
||||
|
||||
static void ccdc_readregs(void)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
|
||||
val = regr(CCDC_ALAW);
|
||||
dev_notice(dev, "\nReading 0x%x to ALAW...\n", val);
|
||||
val = regr(CCDC_CLAMP);
|
||||
dev_notice(dev, "\nReading 0x%x to CLAMP...\n", val);
|
||||
val = regr(CCDC_DCSUB);
|
||||
dev_notice(dev, "\nReading 0x%x to DCSUB...\n", val);
|
||||
val = regr(CCDC_BLKCMP);
|
||||
dev_notice(dev, "\nReading 0x%x to BLKCMP...\n", val);
|
||||
val = regr(CCDC_FPC_ADDR);
|
||||
dev_notice(dev, "\nReading 0x%x to FPC_ADDR...\n", val);
|
||||
val = regr(CCDC_FPC);
|
||||
dev_notice(dev, "\nReading 0x%x to FPC...\n", val);
|
||||
val = regr(CCDC_FMTCFG);
|
||||
dev_notice(dev, "\nReading 0x%x to FMTCFG...\n", val);
|
||||
val = regr(CCDC_COLPTN);
|
||||
dev_notice(dev, "\nReading 0x%x to COLPTN...\n", val);
|
||||
val = regr(CCDC_FMT_HORZ);
|
||||
dev_notice(dev, "\nReading 0x%x to FMT_HORZ...\n", val);
|
||||
val = regr(CCDC_FMT_VERT);
|
||||
dev_notice(dev, "\nReading 0x%x to FMT_VERT...\n", val);
|
||||
val = regr(CCDC_HSIZE_OFF);
|
||||
dev_notice(dev, "\nReading 0x%x to HSIZE_OFF...\n", val);
|
||||
val = regr(CCDC_SDOFST);
|
||||
dev_notice(dev, "\nReading 0x%x to SDOFST...\n", val);
|
||||
val = regr(CCDC_VP_OUT);
|
||||
dev_notice(dev, "\nReading 0x%x to VP_OUT...\n", val);
|
||||
val = regr(CCDC_SYN_MODE);
|
||||
dev_notice(dev, "\nReading 0x%x to SYN_MODE...\n", val);
|
||||
val = regr(CCDC_HORZ_INFO);
|
||||
dev_notice(dev, "\nReading 0x%x to HORZ_INFO...\n", val);
|
||||
val = regr(CCDC_VERT_START);
|
||||
dev_notice(dev, "\nReading 0x%x to VERT_START...\n", val);
|
||||
val = regr(CCDC_VERT_LINES);
|
||||
dev_notice(dev, "\nReading 0x%x to VERT_LINES...\n", val);
|
||||
}
|
||||
|
||||
static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
|
||||
{
|
||||
if (ccdcparam->alaw.enable) {
|
||||
if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) ||
|
||||
(ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) ||
|
||||
(ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) {
|
||||
dev_dbg(dev, "\nInvalid data line select");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params)
|
||||
{
|
||||
struct ccdc_config_params_raw *config_params =
|
||||
&ccdc_hw_params_raw.config_params;
|
||||
unsigned int *fpc_virtaddr = NULL;
|
||||
unsigned int *fpc_physaddr = NULL;
|
||||
|
||||
memcpy(config_params, raw_params, sizeof(*raw_params));
|
||||
/*
|
||||
* allocate memory for fault pixel table and copy the user
|
||||
* values to the table
|
||||
*/
|
||||
if (!config_params->fault_pxl.enable)
|
||||
return 0;
|
||||
|
||||
fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;
|
||||
fpc_virtaddr = (unsigned int *)phys_to_virt(
|
||||
(unsigned long)fpc_physaddr);
|
||||
/*
|
||||
* Allocate memory for FPC table if current
|
||||
* FPC table buffer is not big enough to
|
||||
* accomodate FPC Number requested
|
||||
*/
|
||||
if (raw_params->fault_pxl.fp_num != config_params->fault_pxl.fp_num) {
|
||||
if (fpc_physaddr != NULL) {
|
||||
free_pages((unsigned long)fpc_physaddr,
|
||||
get_order
|
||||
(config_params->fault_pxl.fp_num *
|
||||
FP_NUM_BYTES));
|
||||
}
|
||||
|
||||
/* Allocate memory for FPC table */
|
||||
fpc_virtaddr =
|
||||
(unsigned int *)__get_free_pages(GFP_KERNEL | GFP_DMA,
|
||||
get_order(raw_params->
|
||||
fault_pxl.fp_num *
|
||||
FP_NUM_BYTES));
|
||||
|
||||
if (fpc_virtaddr == NULL) {
|
||||
dev_dbg(dev,
|
||||
"\nUnable to allocate memory for FPC");
|
||||
return -EFAULT;
|
||||
}
|
||||
fpc_physaddr =
|
||||
(unsigned int *)virt_to_phys((void *)fpc_virtaddr);
|
||||
}
|
||||
|
||||
/* Copy number of fault pixels and FPC table */
|
||||
config_params->fault_pxl.fp_num = raw_params->fault_pxl.fp_num;
|
||||
if (copy_from_user(fpc_virtaddr,
|
||||
(void __user *)raw_params->fault_pxl.fpc_table_addr,
|
||||
config_params->fault_pxl.fp_num * FP_NUM_BYTES)) {
|
||||
dev_dbg(dev, "\n copy_from_user failed");
|
||||
return -EFAULT;
|
||||
}
|
||||
config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ccdc_close(struct device *dev)
|
||||
{
|
||||
struct ccdc_config_params_raw *config_params =
|
||||
&ccdc_hw_params_raw.config_params;
|
||||
unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL;
|
||||
|
||||
fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;
|
||||
|
||||
if (fpc_physaddr != NULL) {
|
||||
fpc_virtaddr = (unsigned int *)
|
||||
phys_to_virt((unsigned long)fpc_physaddr);
|
||||
free_pages((unsigned long)fpc_virtaddr,
|
||||
get_order(config_params->fault_pxl.fp_num *
|
||||
FP_NUM_BYTES));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ccdc_restore_defaults()
|
||||
* This function will write defaults to all CCDC registers
|
||||
*/
|
||||
static void ccdc_restore_defaults(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* disable CCDC */
|
||||
ccdc_enable(0);
|
||||
/* set all registers to default value */
|
||||
for (i = 4; i <= 0x94; i += 4)
|
||||
regw(0, i);
|
||||
regw(CCDC_NO_CULLING, CCDC_CULLING);
|
||||
regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW);
|
||||
}
|
||||
|
||||
static int ccdc_open(struct device *device)
|
||||
{
|
||||
dev = device;
|
||||
ccdc_restore_defaults();
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER)
|
||||
ccdc_enable_vport(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ccdc_sbl_reset(void)
|
||||
{
|
||||
vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O);
|
||||
}
|
||||
|
||||
/* Parameter operations */
|
||||
static int ccdc_set_params(void __user *params)
|
||||
{
|
||||
struct ccdc_config_params_raw ccdc_raw_params;
|
||||
int x;
|
||||
|
||||
if (ccdc_if_type != VPFE_RAW_BAYER)
|
||||
return -EINVAL;
|
||||
|
||||
x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
|
||||
if (x) {
|
||||
dev_dbg(dev, "ccdc_set_params: error in copying"
|
||||
"ccdc params, %d\n", x);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!validate_ccdc_param(&ccdc_raw_params)) {
|
||||
if (!ccdc_update_raw_params(&ccdc_raw_params))
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ccdc_config_ycbcr()
|
||||
* This function will configure CCDC for YCbCr video capture
|
||||
*/
|
||||
void ccdc_config_ycbcr(void)
|
||||
{
|
||||
struct ccdc_params_ycbcr *params = &ccdc_hw_params_ycbcr;
|
||||
u32 syn_mode;
|
||||
|
||||
dev_dbg(dev, "\nStarting ccdc_config_ycbcr...");
|
||||
/*
|
||||
* first restore the CCDC registers to default values
|
||||
* This is important since we assume default values to be set in
|
||||
* a lot of registers that we didn't touch
|
||||
*/
|
||||
ccdc_restore_defaults();
|
||||
|
||||
/*
|
||||
* configure pixel format, frame format, configure video frame
|
||||
* format, enable output to SDRAM, enable internal timing generator
|
||||
* and 8bit pack mode
|
||||
*/
|
||||
syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) <<
|
||||
CCDC_SYN_MODE_INPMOD_SHIFT) |
|
||||
((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) <<
|
||||
CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE |
|
||||
CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE);
|
||||
|
||||
/* setup BT.656 sync mode */
|
||||
if (params->bt656_enable) {
|
||||
regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF);
|
||||
|
||||
/*
|
||||
* configure the FID, VD, HD pin polarity,
|
||||
* fld,hd pol positive, vd negative, 8-bit data
|
||||
*/
|
||||
syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE | CCDC_SYN_MODE_8BITS;
|
||||
} else {
|
||||
/* y/c external sync mode */
|
||||
syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
|
||||
CCDC_FID_POL_SHIFT) |
|
||||
((params->hd_pol & CCDC_HD_POL_MASK) <<
|
||||
CCDC_HD_POL_SHIFT) |
|
||||
((params->vd_pol & CCDC_VD_POL_MASK) <<
|
||||
CCDC_VD_POL_SHIFT));
|
||||
}
|
||||
regw(syn_mode, CCDC_SYN_MODE);
|
||||
|
||||
/* configure video window */
|
||||
ccdc_setwin(¶ms->win, params->frm_fmt, 2);
|
||||
|
||||
/*
|
||||
* configure the order of y cb cr in SDRAM, and disable latch
|
||||
* internal register on vsync
|
||||
*/
|
||||
regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
|
||||
CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
|
||||
|
||||
/*
|
||||
* configure the horizontal line offset. This should be a
|
||||
* on 32 byte bondary. So clear LSB 5 bits
|
||||
*/
|
||||
regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF);
|
||||
|
||||
/* configure the memory line offset */
|
||||
if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)
|
||||
/* two fields are interleaved in memory */
|
||||
regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST);
|
||||
|
||||
ccdc_sbl_reset();
|
||||
dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n");
|
||||
ccdc_readregs();
|
||||
}
|
||||
|
||||
static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (!bclamp->enable) {
|
||||
/* configure DCSub */
|
||||
val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK;
|
||||
regw(val, CCDC_DCSUB);
|
||||
dev_dbg(dev, "\nWriting 0x%x to DCSUB...\n", val);
|
||||
regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP);
|
||||
dev_dbg(dev, "\nWriting 0x0000 to CLAMP...\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Configure gain, Start pixel, No of line to be avg,
|
||||
* No of pixel/line to be avg, & Enable the Black clamping
|
||||
*/
|
||||
val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) |
|
||||
((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) <<
|
||||
CCDC_BLK_ST_PXL_SHIFT) |
|
||||
((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) <<
|
||||
CCDC_BLK_SAMPLE_LINE_SHIFT) |
|
||||
((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
|
||||
CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE);
|
||||
regw(val, CCDC_CLAMP);
|
||||
dev_dbg(dev, "\nWriting 0x%x to CLAMP...\n", val);
|
||||
/* If Black clamping is enable then make dcsub 0 */
|
||||
regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB);
|
||||
dev_dbg(dev, "\nWriting 0x00000000 to DCSUB...\n");
|
||||
}
|
||||
|
||||
static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = ((bcomp->b & CCDC_BLK_COMP_MASK) |
|
||||
((bcomp->gb & CCDC_BLK_COMP_MASK) <<
|
||||
CCDC_BLK_COMP_GB_COMP_SHIFT) |
|
||||
((bcomp->gr & CCDC_BLK_COMP_MASK) <<
|
||||
CCDC_BLK_COMP_GR_COMP_SHIFT) |
|
||||
((bcomp->r & CCDC_BLK_COMP_MASK) <<
|
||||
CCDC_BLK_COMP_R_COMP_SHIFT));
|
||||
regw(val, CCDC_BLKCMP);
|
||||
}
|
||||
|
||||
static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* Initially disable FPC */
|
||||
val = CCDC_FPC_DISABLE;
|
||||
regw(val, CCDC_FPC);
|
||||
|
||||
if (!fpc->enable)
|
||||
return;
|
||||
|
||||
/* Configure Fault pixel if needed */
|
||||
regw(fpc->fpc_table_addr, CCDC_FPC_ADDR);
|
||||
dev_dbg(dev, "\nWriting 0x%x to FPC_ADDR...\n",
|
||||
(fpc->fpc_table_addr));
|
||||
/* Write the FPC params with FPC disable */
|
||||
val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK;
|
||||
regw(val, CCDC_FPC);
|
||||
|
||||
dev_dbg(dev, "\nWriting 0x%x to FPC...\n", val);
|
||||
/* read the FPC register */
|
||||
val = regr(CCDC_FPC) | CCDC_FPC_ENABLE;
|
||||
regw(val, CCDC_FPC);
|
||||
dev_dbg(dev, "\nWriting 0x%x to FPC...\n", val);
|
||||
}
|
||||
|
||||
/*
|
||||
* ccdc_config_raw()
|
||||
* This function will configure CCDC for Raw capture mode
|
||||
*/
|
||||
void ccdc_config_raw(void)
|
||||
{
|
||||
struct ccdc_params_raw *params = &ccdc_hw_params_raw;
|
||||
struct ccdc_config_params_raw *config_params =
|
||||
&ccdc_hw_params_raw.config_params;
|
||||
unsigned int syn_mode = 0;
|
||||
unsigned int val;
|
||||
|
||||
dev_dbg(dev, "\nStarting ccdc_config_raw...");
|
||||
|
||||
/* Reset CCDC */
|
||||
ccdc_restore_defaults();
|
||||
|
||||
/* Disable latching function registers on VSYNC */
|
||||
regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
|
||||
|
||||
/*
|
||||
* Configure the vertical sync polarity(SYN_MODE.VDPOL),
|
||||
* horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity
|
||||
* (SYN_MODE.FLDPOL), frame format(progressive or interlace),
|
||||
* data size(SYNMODE.DATSIZ), &pixel format (Input mode), output
|
||||
* SDRAM, enable internal timing generator
|
||||
*/
|
||||
syn_mode =
|
||||
(((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
|
||||
((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
|
||||
((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
|
||||
((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
|
||||
((config_params->data_sz & CCDC_DATA_SZ_MASK) <<
|
||||
CCDC_DATA_SZ_SHIFT) |
|
||||
((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) |
|
||||
CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE);
|
||||
|
||||
/* Enable and configure aLaw register if needed */
|
||||
if (config_params->alaw.enable) {
|
||||
val = ((config_params->alaw.gama_wd &
|
||||
CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE);
|
||||
regw(val, CCDC_ALAW);
|
||||
dev_dbg(dev, "\nWriting 0x%x to ALAW...\n", val);
|
||||
}
|
||||
|
||||
/* Configure video window */
|
||||
ccdc_setwin(¶ms->win, params->frm_fmt, CCDC_PPC_RAW);
|
||||
|
||||
/* Configure Black Clamp */
|
||||
ccdc_config_black_clamp(&config_params->blk_clamp);
|
||||
|
||||
/* Configure Black level compensation */
|
||||
ccdc_config_black_compense(&config_params->blk_comp);
|
||||
|
||||
/* Configure Fault Pixel Correction */
|
||||
ccdc_config_fpc(&config_params->fault_pxl);
|
||||
|
||||
/* If data size is 8 bit then pack the data */
|
||||
if ((config_params->data_sz == CCDC_DATA_8BITS) ||
|
||||
config_params->alaw.enable)
|
||||
syn_mode |= CCDC_DATA_PACK_ENABLE;
|
||||
|
||||
#ifdef CONFIG_DM644X_VIDEO_PORT_ENABLE
|
||||
/* enable video port */
|
||||
val = CCDC_ENABLE_VIDEO_PORT;
|
||||
#else
|
||||
/* disable video port */
|
||||
val = CCDC_DISABLE_VIDEO_PORT;
|
||||
#endif
|
||||
|
||||
if (config_params->data_sz == CCDC_DATA_8BITS)
|
||||
val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK)
|
||||
<< CCDC_FMTCFG_VPIN_SHIFT;
|
||||
else
|
||||
val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK)
|
||||
<< CCDC_FMTCFG_VPIN_SHIFT;
|
||||
/* Write value in FMTCFG */
|
||||
regw(val, CCDC_FMTCFG);
|
||||
|
||||
dev_dbg(dev, "\nWriting 0x%x to FMTCFG...\n", val);
|
||||
/* Configure the color pattern according to mt9t001 sensor */
|
||||
regw(CCDC_COLPTN_VAL, CCDC_COLPTN);
|
||||
|
||||
dev_dbg(dev, "\nWriting 0xBB11BB11 to COLPTN...\n");
|
||||
/*
|
||||
* Configure Data formatter(Video port) pixel selection
|
||||
* (FMT_HORZ, FMT_VERT)
|
||||
*/
|
||||
val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) <<
|
||||
CCDC_FMT_HORZ_FMTSPH_SHIFT) |
|
||||
(params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK);
|
||||
regw(val, CCDC_FMT_HORZ);
|
||||
|
||||
dev_dbg(dev, "\nWriting 0x%x to FMT_HORZ...\n", val);
|
||||
val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK)
|
||||
<< CCDC_FMT_VERT_FMTSLV_SHIFT;
|
||||
if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
|
||||
val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK;
|
||||
else
|
||||
val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK;
|
||||
|
||||
dev_dbg(dev, "\nparams->win.height 0x%x ...\n",
|
||||
params->win.height);
|
||||
regw(val, CCDC_FMT_VERT);
|
||||
|
||||
dev_dbg(dev, "\nWriting 0x%x to FMT_VERT...\n", val);
|
||||
|
||||
dev_dbg(dev, "\nbelow regw(val, FMT_VERT)...");
|
||||
|
||||
/*
|
||||
* Configure Horizontal offset register. If pack 8 is enabled then
|
||||
* 1 pixel will take 1 byte
|
||||
*/
|
||||
if ((config_params->data_sz == CCDC_DATA_8BITS) ||
|
||||
config_params->alaw.enable)
|
||||
regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) &
|
||||
CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF);
|
||||
else
|
||||
/* else one pixel will take 2 byte */
|
||||
regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) +
|
||||
CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK,
|
||||
CCDC_HSIZE_OFF);
|
||||
|
||||
/* Set value for SDOFST */
|
||||
if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
|
||||
if (params->image_invert_enable) {
|
||||
/* For intelace inverse mode */
|
||||
regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST);
|
||||
dev_dbg(dev, "\nWriting 0x4B6D to SDOFST...\n");
|
||||
}
|
||||
|
||||
else {
|
||||
/* For intelace non inverse mode */
|
||||
regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST);
|
||||
dev_dbg(dev, "\nWriting 0x0249 to SDOFST...\n");
|
||||
}
|
||||
} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
|
||||
regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST);
|
||||
dev_dbg(dev, "\nWriting 0x0000 to SDOFST...\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure video port pixel selection (VPOUT)
|
||||
* Here -1 is to make the height value less than FMT_VERT.FMTLNV
|
||||
*/
|
||||
if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
|
||||
val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK))
|
||||
<< CCDC_VP_OUT_VERT_NUM_SHIFT;
|
||||
else
|
||||
val =
|
||||
((((params->win.height >> CCDC_INTERLACED_HEIGHT_SHIFT) -
|
||||
1) & CCDC_VP_OUT_VERT_NUM_MASK)) <<
|
||||
CCDC_VP_OUT_VERT_NUM_SHIFT;
|
||||
|
||||
val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK)
|
||||
<< CCDC_VP_OUT_HORZ_NUM_SHIFT;
|
||||
val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK;
|
||||
regw(val, CCDC_VP_OUT);
|
||||
|
||||
dev_dbg(dev, "\nWriting 0x%x to VP_OUT...\n", val);
|
||||
regw(syn_mode, CCDC_SYN_MODE);
|
||||
dev_dbg(dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode);
|
||||
|
||||
ccdc_sbl_reset();
|
||||
dev_dbg(dev, "\nend of ccdc_config_raw...");
|
||||
ccdc_readregs();
|
||||
}
|
||||
|
||||
static int ccdc_configure(void)
|
||||
{
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER)
|
||||
ccdc_config_raw();
|
||||
else
|
||||
ccdc_config_ycbcr();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ccdc_set_buftype(enum ccdc_buftype buf_type)
|
||||
{
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER)
|
||||
ccdc_hw_params_raw.buf_type = buf_type;
|
||||
else
|
||||
ccdc_hw_params_ycbcr.buf_type = buf_type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum ccdc_buftype ccdc_get_buftype(void)
|
||||
{
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER)
|
||||
return ccdc_hw_params_raw.buf_type;
|
||||
return ccdc_hw_params_ycbcr.buf_type;
|
||||
}
|
||||
|
||||
static int ccdc_enum_pix(u32 *pix, int i)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER) {
|
||||
if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
|
||||
*pix = ccdc_raw_bayer_pix_formats[i];
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
|
||||
*pix = ccdc_raw_yuv_pix_formats[i];
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ccdc_set_pixel_format(u32 pixfmt)
|
||||
{
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER) {
|
||||
ccdc_hw_params_raw.pix_fmt = CCDC_PIXFMT_RAW;
|
||||
if (pixfmt == V4L2_PIX_FMT_SBGGR8)
|
||||
ccdc_hw_params_raw.config_params.alaw.enable = 1;
|
||||
else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (pixfmt == V4L2_PIX_FMT_YUYV)
|
||||
ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
|
||||
else if (pixfmt == V4L2_PIX_FMT_UYVY)
|
||||
ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 ccdc_get_pixel_format(void)
|
||||
{
|
||||
struct ccdc_a_law *alaw =
|
||||
&ccdc_hw_params_raw.config_params.alaw;
|
||||
u32 pixfmt;
|
||||
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER)
|
||||
if (alaw->enable)
|
||||
pixfmt = V4L2_PIX_FMT_SBGGR8;
|
||||
else
|
||||
pixfmt = V4L2_PIX_FMT_SBGGR16;
|
||||
else {
|
||||
if (ccdc_hw_params_ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
|
||||
pixfmt = V4L2_PIX_FMT_YUYV;
|
||||
else
|
||||
pixfmt = V4L2_PIX_FMT_UYVY;
|
||||
}
|
||||
return pixfmt;
|
||||
}
|
||||
|
||||
static int ccdc_set_image_window(struct v4l2_rect *win)
|
||||
{
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER)
|
||||
ccdc_hw_params_raw.win = *win;
|
||||
else
|
||||
ccdc_hw_params_ycbcr.win = *win;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ccdc_get_image_window(struct v4l2_rect *win)
|
||||
{
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER)
|
||||
*win = ccdc_hw_params_raw.win;
|
||||
else
|
||||
*win = ccdc_hw_params_ycbcr.win;
|
||||
}
|
||||
|
||||
static unsigned int ccdc_get_line_length(void)
|
||||
{
|
||||
struct ccdc_config_params_raw *config_params =
|
||||
&ccdc_hw_params_raw.config_params;
|
||||
unsigned int len;
|
||||
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER) {
|
||||
if ((config_params->alaw.enable) ||
|
||||
(config_params->data_sz == CCDC_DATA_8BITS))
|
||||
len = ccdc_hw_params_raw.win.width;
|
||||
else
|
||||
len = ccdc_hw_params_raw.win.width * 2;
|
||||
} else
|
||||
len = ccdc_hw_params_ycbcr.win.width * 2;
|
||||
return ALIGN(len, 32);
|
||||
}
|
||||
|
||||
static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
|
||||
{
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER)
|
||||
ccdc_hw_params_raw.frm_fmt = frm_fmt;
|
||||
else
|
||||
ccdc_hw_params_ycbcr.frm_fmt = frm_fmt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum ccdc_frmfmt ccdc_get_frame_format(void)
|
||||
{
|
||||
if (ccdc_if_type == VPFE_RAW_BAYER)
|
||||
return ccdc_hw_params_raw.frm_fmt;
|
||||
else
|
||||
return ccdc_hw_params_ycbcr.frm_fmt;
|
||||
}
|
||||
|
||||
static int ccdc_getfid(void)
|
||||
{
|
||||
return (regr(CCDC_SYN_MODE) >> 15) & 1;
|
||||
}
|
||||
|
||||
/* misc operations */
|
||||
static inline void ccdc_setfbaddr(unsigned long addr)
|
||||
{
|
||||
regw(addr & 0xffffffe0, CCDC_SDR_ADDR);
|
||||
}
|
||||
|
||||
static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
|
||||
{
|
||||
ccdc_if_type = params->if_type;
|
||||
|
||||
switch (params->if_type) {
|
||||
case VPFE_BT656:
|
||||
case VPFE_YCBCR_SYNC_16:
|
||||
case VPFE_YCBCR_SYNC_8:
|
||||
ccdc_hw_params_ycbcr.vd_pol = params->vdpol;
|
||||
ccdc_hw_params_ycbcr.hd_pol = params->hdpol;
|
||||
break;
|
||||
default:
|
||||
/* TODO add support for raw bayer here */
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ccdc_hw_device ccdc_hw_dev = {
|
||||
.name = "DM6446 CCDC",
|
||||
.owner = THIS_MODULE,
|
||||
.hw_ops = {
|
||||
.open = ccdc_open,
|
||||
.close = ccdc_close,
|
||||
.set_ccdc_base = ccdc_set_ccdc_base,
|
||||
.reset = ccdc_sbl_reset,
|
||||
.enable = ccdc_enable,
|
||||
.set_hw_if_params = ccdc_set_hw_if_params,
|
||||
.set_params = ccdc_set_params,
|
||||
.configure = ccdc_configure,
|
||||
.set_buftype = ccdc_set_buftype,
|
||||
.get_buftype = ccdc_get_buftype,
|
||||
.enum_pix = ccdc_enum_pix,
|
||||
.set_pixel_format = ccdc_set_pixel_format,
|
||||
.get_pixel_format = ccdc_get_pixel_format,
|
||||
.set_frame_format = ccdc_set_frame_format,
|
||||
.get_frame_format = ccdc_get_frame_format,
|
||||
.set_image_window = ccdc_set_image_window,
|
||||
.get_image_window = ccdc_get_image_window,
|
||||
.get_line_length = ccdc_get_line_length,
|
||||
.setfbaddr = ccdc_setfbaddr,
|
||||
.getfid = ccdc_getfid,
|
||||
},
|
||||
};
|
||||
|
||||
static int dm644x_ccdc_init(void)
|
||||
{
|
||||
printk(KERN_NOTICE "dm644x_ccdc_init\n");
|
||||
if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0)
|
||||
return -1;
|
||||
printk(KERN_NOTICE "%s is registered with vpfe.\n",
|
||||
ccdc_hw_dev.name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dm644x_ccdc_exit(void)
|
||||
{
|
||||
vpfe_unregister_ccdc_device(&ccdc_hw_dev);
|
||||
}
|
||||
|
||||
module_init(dm644x_ccdc_init);
|
||||
module_exit(dm644x_ccdc_exit);
|
||||
145
drivers/media/video/davinci/dm644x_ccdc_regs.h
Normal file
145
drivers/media/video/davinci/dm644x_ccdc_regs.h
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright (C) 2006-2009 Texas Instruments Inc
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef _DM644X_CCDC_REGS_H
|
||||
#define _DM644X_CCDC_REGS_H
|
||||
|
||||
/**************************************************************************\
|
||||
* Register OFFSET Definitions
|
||||
\**************************************************************************/
|
||||
#define CCDC_PID 0x0
|
||||
#define CCDC_PCR 0x4
|
||||
#define CCDC_SYN_MODE 0x8
|
||||
#define CCDC_HD_VD_WID 0xc
|
||||
#define CCDC_PIX_LINES 0x10
|
||||
#define CCDC_HORZ_INFO 0x14
|
||||
#define CCDC_VERT_START 0x18
|
||||
#define CCDC_VERT_LINES 0x1c
|
||||
#define CCDC_CULLING 0x20
|
||||
#define CCDC_HSIZE_OFF 0x24
|
||||
#define CCDC_SDOFST 0x28
|
||||
#define CCDC_SDR_ADDR 0x2c
|
||||
#define CCDC_CLAMP 0x30
|
||||
#define CCDC_DCSUB 0x34
|
||||
#define CCDC_COLPTN 0x38
|
||||
#define CCDC_BLKCMP 0x3c
|
||||
#define CCDC_FPC 0x40
|
||||
#define CCDC_FPC_ADDR 0x44
|
||||
#define CCDC_VDINT 0x48
|
||||
#define CCDC_ALAW 0x4c
|
||||
#define CCDC_REC656IF 0x50
|
||||
#define CCDC_CCDCFG 0x54
|
||||
#define CCDC_FMTCFG 0x58
|
||||
#define CCDC_FMT_HORZ 0x5c
|
||||
#define CCDC_FMT_VERT 0x60
|
||||
#define CCDC_FMT_ADDR0 0x64
|
||||
#define CCDC_FMT_ADDR1 0x68
|
||||
#define CCDC_FMT_ADDR2 0x6c
|
||||
#define CCDC_FMT_ADDR3 0x70
|
||||
#define CCDC_FMT_ADDR4 0x74
|
||||
#define CCDC_FMT_ADDR5 0x78
|
||||
#define CCDC_FMT_ADDR6 0x7c
|
||||
#define CCDC_FMT_ADDR7 0x80
|
||||
#define CCDC_PRGEVEN_0 0x84
|
||||
#define CCDC_PRGEVEN_1 0x88
|
||||
#define CCDC_PRGODD_0 0x8c
|
||||
#define CCDC_PRGODD_1 0x90
|
||||
#define CCDC_VP_OUT 0x94
|
||||
|
||||
|
||||
/***************************************************************
|
||||
* Define for various register bit mask and shifts for CCDC
|
||||
****************************************************************/
|
||||
#define CCDC_FID_POL_MASK 1
|
||||
#define CCDC_FID_POL_SHIFT 4
|
||||
#define CCDC_HD_POL_MASK 1
|
||||
#define CCDC_HD_POL_SHIFT 3
|
||||
#define CCDC_VD_POL_MASK 1
|
||||
#define CCDC_VD_POL_SHIFT 2
|
||||
#define CCDC_HSIZE_OFF_MASK 0xffffffe0
|
||||
#define CCDC_32BYTE_ALIGN_VAL 31
|
||||
#define CCDC_FRM_FMT_MASK 0x1
|
||||
#define CCDC_FRM_FMT_SHIFT 7
|
||||
#define CCDC_DATA_SZ_MASK 7
|
||||
#define CCDC_DATA_SZ_SHIFT 8
|
||||
#define CCDC_PIX_FMT_MASK 3
|
||||
#define CCDC_PIX_FMT_SHIFT 12
|
||||
#define CCDC_VP2SDR_DISABLE 0xFFFBFFFF
|
||||
#define CCDC_WEN_ENABLE (1 << 17)
|
||||
#define CCDC_SDR2RSZ_DISABLE 0xFFF7FFFF
|
||||
#define CCDC_VDHDEN_ENABLE (1 << 16)
|
||||
#define CCDC_LPF_ENABLE (1 << 14)
|
||||
#define CCDC_ALAW_ENABLE (1 << 3)
|
||||
#define CCDC_ALAW_GAMA_WD_MASK 7
|
||||
#define CCDC_BLK_CLAMP_ENABLE (1 << 31)
|
||||
#define CCDC_BLK_SGAIN_MASK 0x1F
|
||||
#define CCDC_BLK_ST_PXL_MASK 0x7FFF
|
||||
#define CCDC_BLK_ST_PXL_SHIFT 10
|
||||
#define CCDC_BLK_SAMPLE_LN_MASK 7
|
||||
#define CCDC_BLK_SAMPLE_LN_SHIFT 28
|
||||
#define CCDC_BLK_SAMPLE_LINE_MASK 7
|
||||
#define CCDC_BLK_SAMPLE_LINE_SHIFT 25
|
||||
#define CCDC_BLK_DC_SUB_MASK 0x03FFF
|
||||
#define CCDC_BLK_COMP_MASK 0xFF
|
||||
#define CCDC_BLK_COMP_GB_COMP_SHIFT 8
|
||||
#define CCDC_BLK_COMP_GR_COMP_SHIFT 16
|
||||
#define CCDC_BLK_COMP_R_COMP_SHIFT 24
|
||||
#define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15)
|
||||
#define CCDC_FPC_ENABLE (1 << 15)
|
||||
#define CCDC_FPC_DISABLE 0
|
||||
#define CCDC_FPC_FPC_NUM_MASK 0x7FFF
|
||||
#define CCDC_DATA_PACK_ENABLE (1 << 11)
|
||||
#define CCDC_FMTCFG_VPIN_MASK 7
|
||||
#define CCDC_FMTCFG_VPIN_SHIFT 12
|
||||
#define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF
|
||||
#define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF
|
||||
#define CCDC_FMT_HORZ_FMTSPH_SHIFT 16
|
||||
#define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF
|
||||
#define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF
|
||||
#define CCDC_FMT_VERT_FMTSLV_SHIFT 16
|
||||
#define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF
|
||||
#define CCDC_VP_OUT_VERT_NUM_SHIFT 17
|
||||
#define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF
|
||||
#define CCDC_VP_OUT_HORZ_NUM_SHIFT 4
|
||||
#define CCDC_VP_OUT_HORZ_ST_MASK 0xF
|
||||
#define CCDC_HORZ_INFO_SPH_SHIFT 16
|
||||
#define CCDC_VERT_START_SLV0_SHIFT 16
|
||||
#define CCDC_VDINT_VDINT0_SHIFT 16
|
||||
#define CCDC_VDINT_VDINT1_MASK 0xFFFF
|
||||
#define CCDC_PPC_RAW 1
|
||||
#define CCDC_DCSUB_DEFAULT_VAL 0
|
||||
#define CCDC_CLAMP_DEFAULT_VAL 0
|
||||
#define CCDC_ENABLE_VIDEO_PORT 0x8000
|
||||
#define CCDC_DISABLE_VIDEO_PORT 0
|
||||
#define CCDC_COLPTN_VAL 0xBB11BB11
|
||||
#define CCDC_TWO_BYTES_PER_PIXEL 2
|
||||
#define CCDC_INTERLACED_IMAGE_INVERT 0x4B6D
|
||||
#define CCDC_INTERLACED_NO_IMAGE_INVERT 0x0249
|
||||
#define CCDC_PROGRESSIVE_IMAGE_INVERT 0x4000
|
||||
#define CCDC_PROGRESSIVE_NO_IMAGE_INVERT 0
|
||||
#define CCDC_INTERLACED_HEIGHT_SHIFT 1
|
||||
#define CCDC_SYN_MODE_INPMOD_SHIFT 12
|
||||
#define CCDC_SYN_MODE_INPMOD_MASK 3
|
||||
#define CCDC_SYN_MODE_8BITS (7 << 8)
|
||||
#define CCDC_SYN_FLDMODE_MASK 1
|
||||
#define CCDC_SYN_FLDMODE_SHIFT 7
|
||||
#define CCDC_REC656IF_BT656_EN 3
|
||||
#define CCDC_SYN_MODE_VD_POL_NEGATIVE (1 << 2)
|
||||
#define CCDC_CCDCFG_Y8POS_SHIFT 11
|
||||
#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249
|
||||
#define CCDC_NO_CULLING 0xffff00ff
|
||||
#endif
|
||||
2124
drivers/media/video/davinci/vpfe_capture.c
Normal file
2124
drivers/media/video/davinci/vpfe_capture.c
Normal file
File diff suppressed because it is too large
Load diff
296
drivers/media/video/davinci/vpif.c
Normal file
296
drivers/media/video/davinci/vpif.c
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
* vpif - DM646x Video Port Interface driver
|
||||
* VPIF is a receiver and transmitter for video data. It has two channels(0, 1)
|
||||
* that receiveing video byte stream and two channels(2, 3) for video output.
|
||||
* The hardware supports SDTV, HDTV formats, raw data capture.
|
||||
* Currently, the driver supports NTSC and PAL standards.
|
||||
*
|
||||
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2.
|
||||
*
|
||||
* This program is distributed .as is. WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/io.h>
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#include "vpif.h"
|
||||
|
||||
MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define VPIF_CH0_MAX_MODES (22)
|
||||
#define VPIF_CH1_MAX_MODES (02)
|
||||
#define VPIF_CH2_MAX_MODES (15)
|
||||
#define VPIF_CH3_MAX_MODES (02)
|
||||
|
||||
static resource_size_t res_len;
|
||||
static struct resource *res;
|
||||
spinlock_t vpif_lock;
|
||||
|
||||
void __iomem *vpif_base;
|
||||
|
||||
static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val)
|
||||
{
|
||||
if (val)
|
||||
vpif_set_bit(reg, bit);
|
||||
else
|
||||
vpif_clr_bit(reg, bit);
|
||||
}
|
||||
|
||||
/* This structure is used to keep track of VPIF size register's offsets */
|
||||
struct vpif_registers {
|
||||
u32 h_cfg, v_cfg_00, v_cfg_01, v_cfg_02, v_cfg, ch_ctrl;
|
||||
u32 line_offset, vanc0_strt, vanc0_size, vanc1_strt;
|
||||
u32 vanc1_size, width_mask, len_mask;
|
||||
u8 max_modes;
|
||||
};
|
||||
|
||||
static const struct vpif_registers vpifregs[VPIF_NUM_CHANNELS] = {
|
||||
/* Channel0 */
|
||||
{
|
||||
VPIF_CH0_H_CFG, VPIF_CH0_V_CFG_00, VPIF_CH0_V_CFG_01,
|
||||
VPIF_CH0_V_CFG_02, VPIF_CH0_V_CFG_03, VPIF_CH0_CTRL,
|
||||
VPIF_CH0_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF,
|
||||
VPIF_CH0_MAX_MODES,
|
||||
},
|
||||
/* Channel1 */
|
||||
{
|
||||
VPIF_CH1_H_CFG, VPIF_CH1_V_CFG_00, VPIF_CH1_V_CFG_01,
|
||||
VPIF_CH1_V_CFG_02, VPIF_CH1_V_CFG_03, VPIF_CH1_CTRL,
|
||||
VPIF_CH1_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF,
|
||||
VPIF_CH1_MAX_MODES,
|
||||
},
|
||||
/* Channel2 */
|
||||
{
|
||||
VPIF_CH2_H_CFG, VPIF_CH2_V_CFG_00, VPIF_CH2_V_CFG_01,
|
||||
VPIF_CH2_V_CFG_02, VPIF_CH2_V_CFG_03, VPIF_CH2_CTRL,
|
||||
VPIF_CH2_IMG_ADD_OFST, VPIF_CH2_VANC0_STRT, VPIF_CH2_VANC0_SIZE,
|
||||
VPIF_CH2_VANC1_STRT, VPIF_CH2_VANC1_SIZE, 0x7FF, 0x7FF,
|
||||
VPIF_CH2_MAX_MODES
|
||||
},
|
||||
/* Channel3 */
|
||||
{
|
||||
VPIF_CH3_H_CFG, VPIF_CH3_V_CFG_00, VPIF_CH3_V_CFG_01,
|
||||
VPIF_CH3_V_CFG_02, VPIF_CH3_V_CFG_03, VPIF_CH3_CTRL,
|
||||
VPIF_CH3_IMG_ADD_OFST, VPIF_CH3_VANC0_STRT, VPIF_CH3_VANC0_SIZE,
|
||||
VPIF_CH3_VANC1_STRT, VPIF_CH3_VANC1_SIZE, 0x7FF, 0x7FF,
|
||||
VPIF_CH3_MAX_MODES
|
||||
},
|
||||
};
|
||||
|
||||
/* vpif_set_mode_info:
|
||||
* This function is used to set horizontal and vertical config parameters
|
||||
* As per the standard in the channel, configure the values of L1, L3,
|
||||
* L5, L7 L9, L11 in VPIF Register , also write width and height
|
||||
*/
|
||||
static void vpif_set_mode_info(const struct vpif_channel_config_params *config,
|
||||
u8 channel_id, u8 config_channel_id)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = (config->eav2sav & vpifregs[config_channel_id].width_mask);
|
||||
value <<= VPIF_CH_LEN_SHIFT;
|
||||
value |= (config->sav2eav & vpifregs[config_channel_id].width_mask);
|
||||
regw(value, vpifregs[channel_id].h_cfg);
|
||||
|
||||
value = (config->l1 & vpifregs[config_channel_id].len_mask);
|
||||
value <<= VPIF_CH_LEN_SHIFT;
|
||||
value |= (config->l3 & vpifregs[config_channel_id].len_mask);
|
||||
regw(value, vpifregs[channel_id].v_cfg_00);
|
||||
|
||||
value = (config->l5 & vpifregs[config_channel_id].len_mask);
|
||||
value <<= VPIF_CH_LEN_SHIFT;
|
||||
value |= (config->l7 & vpifregs[config_channel_id].len_mask);
|
||||
regw(value, vpifregs[channel_id].v_cfg_01);
|
||||
|
||||
value = (config->l9 & vpifregs[config_channel_id].len_mask);
|
||||
value <<= VPIF_CH_LEN_SHIFT;
|
||||
value |= (config->l11 & vpifregs[config_channel_id].len_mask);
|
||||
regw(value, vpifregs[channel_id].v_cfg_02);
|
||||
|
||||
value = (config->vsize & vpifregs[config_channel_id].len_mask);
|
||||
regw(value, vpifregs[channel_id].v_cfg);
|
||||
}
|
||||
|
||||
/* config_vpif_params
|
||||
* Function to set the parameters of a channel
|
||||
* Mainly modifies the channel ciontrol register
|
||||
* It sets frame format, yc mux mode
|
||||
*/
|
||||
static void config_vpif_params(struct vpif_params *vpifparams,
|
||||
u8 channel_id, u8 found)
|
||||
{
|
||||
const struct vpif_channel_config_params *config = &vpifparams->std_info;
|
||||
u32 value, ch_nip, reg;
|
||||
u8 start, end;
|
||||
int i;
|
||||
|
||||
start = channel_id;
|
||||
end = channel_id + found;
|
||||
|
||||
for (i = start; i < end; i++) {
|
||||
reg = vpifregs[i].ch_ctrl;
|
||||
if (channel_id < 2)
|
||||
ch_nip = VPIF_CAPTURE_CH_NIP;
|
||||
else
|
||||
ch_nip = VPIF_DISPLAY_CH_NIP;
|
||||
|
||||
vpif_wr_bit(reg, ch_nip, config->frm_fmt);
|
||||
vpif_wr_bit(reg, VPIF_CH_YC_MUX_BIT, config->ycmux_mode);
|
||||
vpif_wr_bit(reg, VPIF_CH_INPUT_FIELD_FRAME_BIT,
|
||||
vpifparams->video_params.storage_mode);
|
||||
|
||||
/* Set raster scanning SDR Format */
|
||||
vpif_clr_bit(reg, VPIF_CH_SDR_FMT_BIT);
|
||||
vpif_wr_bit(reg, VPIF_CH_DATA_MODE_BIT, config->capture_format);
|
||||
|
||||
if (channel_id > 1) /* Set the Pixel enable bit */
|
||||
vpif_set_bit(reg, VPIF_DISPLAY_PIX_EN_BIT);
|
||||
else if (config->capture_format) {
|
||||
/* Set the polarity of various pins */
|
||||
vpif_wr_bit(reg, VPIF_CH_FID_POLARITY_BIT,
|
||||
vpifparams->iface.fid_pol);
|
||||
vpif_wr_bit(reg, VPIF_CH_V_VALID_POLARITY_BIT,
|
||||
vpifparams->iface.vd_pol);
|
||||
vpif_wr_bit(reg, VPIF_CH_H_VALID_POLARITY_BIT,
|
||||
vpifparams->iface.hd_pol);
|
||||
|
||||
value = regr(reg);
|
||||
/* Set data width */
|
||||
value &= ((~(unsigned int)(0x3)) <<
|
||||
VPIF_CH_DATA_WIDTH_BIT);
|
||||
value |= ((vpifparams->params.data_sz) <<
|
||||
VPIF_CH_DATA_WIDTH_BIT);
|
||||
regw(value, reg);
|
||||
}
|
||||
|
||||
/* Write the pitch in the driver */
|
||||
regw((vpifparams->video_params.hpitch),
|
||||
vpifregs[i].line_offset);
|
||||
}
|
||||
}
|
||||
|
||||
/* vpif_set_video_params
|
||||
* This function is used to set video parameters in VPIF register
|
||||
*/
|
||||
int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id)
|
||||
{
|
||||
const struct vpif_channel_config_params *config = &vpifparams->std_info;
|
||||
int found = 1;
|
||||
|
||||
vpif_set_mode_info(config, channel_id, channel_id);
|
||||
if (!config->ycmux_mode) {
|
||||
/* YC are on separate channels (HDTV formats) */
|
||||
vpif_set_mode_info(config, channel_id + 1, channel_id);
|
||||
found = 2;
|
||||
}
|
||||
|
||||
config_vpif_params(vpifparams, channel_id, found);
|
||||
|
||||
regw(0x80, VPIF_REQ_SIZE);
|
||||
regw(0x01, VPIF_EMULATION_CTRL);
|
||||
|
||||
return found;
|
||||
}
|
||||
EXPORT_SYMBOL(vpif_set_video_params);
|
||||
|
||||
void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams,
|
||||
u8 channel_id)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = 0x3F8 & (vbiparams->hstart0);
|
||||
value |= 0x3FFFFFF & ((vbiparams->vstart0) << 16);
|
||||
regw(value, vpifregs[channel_id].vanc0_strt);
|
||||
|
||||
value = 0x3F8 & (vbiparams->hstart1);
|
||||
value |= 0x3FFFFFF & ((vbiparams->vstart1) << 16);
|
||||
regw(value, vpifregs[channel_id].vanc1_strt);
|
||||
|
||||
value = 0x3F8 & (vbiparams->hsize0);
|
||||
value |= 0x3FFFFFF & ((vbiparams->vsize0) << 16);
|
||||
regw(value, vpifregs[channel_id].vanc0_size);
|
||||
|
||||
value = 0x3F8 & (vbiparams->hsize1);
|
||||
value |= 0x3FFFFFF & ((vbiparams->vsize1) << 16);
|
||||
regw(value, vpifregs[channel_id].vanc1_size);
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(vpif_set_vbi_display_params);
|
||||
|
||||
int vpif_channel_getfid(u8 channel_id)
|
||||
{
|
||||
return (regr(vpifregs[channel_id].ch_ctrl) & VPIF_CH_FID_MASK)
|
||||
>> VPIF_CH_FID_SHIFT;
|
||||
}
|
||||
EXPORT_SYMBOL(vpif_channel_getfid);
|
||||
|
||||
static int __init vpif_probe(struct platform_device *pdev)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENOENT;
|
||||
|
||||
res_len = res->end - res->start + 1;
|
||||
|
||||
res = request_mem_region(res->start, res_len, res->name);
|
||||
if (!res)
|
||||
return -EBUSY;
|
||||
|
||||
vpif_base = ioremap(res->start, res_len);
|
||||
if (!vpif_base) {
|
||||
status = -EBUSY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
spin_lock_init(&vpif_lock);
|
||||
dev_info(&pdev->dev, "vpif probe success\n");
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
release_mem_region(res->start, res_len);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int vpif_remove(struct platform_device *pdev)
|
||||
{
|
||||
iounmap(vpif_base);
|
||||
release_mem_region(res->start, res_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver vpif_driver = {
|
||||
.driver = {
|
||||
.name = "vpif",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.remove = __devexit_p(vpif_remove),
|
||||
.probe = vpif_probe,
|
||||
};
|
||||
|
||||
static void vpif_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&vpif_driver);
|
||||
}
|
||||
|
||||
static int __init vpif_init(void)
|
||||
{
|
||||
return platform_driver_register(&vpif_driver);
|
||||
}
|
||||
subsys_initcall(vpif_init);
|
||||
module_exit(vpif_exit);
|
||||
|
||||
642
drivers/media/video/davinci/vpif.h
Normal file
642
drivers/media/video/davinci/vpif.h
Normal file
|
|
@ -0,0 +1,642 @@
|
|||
/*
|
||||
* VPIF header file
|
||||
*
|
||||
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2.
|
||||
*
|
||||
* This program is distributed .as is. WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef VPIF_H
|
||||
#define VPIF_H
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/dm646x.h>
|
||||
|
||||
/* Maximum channel allowed */
|
||||
#define VPIF_NUM_CHANNELS (4)
|
||||
#define VPIF_CAPTURE_NUM_CHANNELS (2)
|
||||
#define VPIF_DISPLAY_NUM_CHANNELS (2)
|
||||
|
||||
/* Macros to read/write registers */
|
||||
extern void __iomem *vpif_base;
|
||||
extern spinlock_t vpif_lock;
|
||||
|
||||
#define regr(reg) readl((reg) + vpif_base)
|
||||
#define regw(value, reg) writel(value, (reg + vpif_base))
|
||||
|
||||
/* Register Addresss Offsets */
|
||||
#define VPIF_PID (0x0000)
|
||||
#define VPIF_CH0_CTRL (0x0004)
|
||||
#define VPIF_CH1_CTRL (0x0008)
|
||||
#define VPIF_CH2_CTRL (0x000C)
|
||||
#define VPIF_CH3_CTRL (0x0010)
|
||||
|
||||
#define VPIF_INTEN (0x0020)
|
||||
#define VPIF_INTEN_SET (0x0024)
|
||||
#define VPIF_INTEN_CLR (0x0028)
|
||||
#define VPIF_STATUS (0x002C)
|
||||
#define VPIF_STATUS_CLR (0x0030)
|
||||
#define VPIF_EMULATION_CTRL (0x0034)
|
||||
#define VPIF_REQ_SIZE (0x0038)
|
||||
|
||||
#define VPIF_CH0_TOP_STRT_ADD_LUMA (0x0040)
|
||||
#define VPIF_CH0_BTM_STRT_ADD_LUMA (0x0044)
|
||||
#define VPIF_CH0_TOP_STRT_ADD_CHROMA (0x0048)
|
||||
#define VPIF_CH0_BTM_STRT_ADD_CHROMA (0x004c)
|
||||
#define VPIF_CH0_TOP_STRT_ADD_HANC (0x0050)
|
||||
#define VPIF_CH0_BTM_STRT_ADD_HANC (0x0054)
|
||||
#define VPIF_CH0_TOP_STRT_ADD_VANC (0x0058)
|
||||
#define VPIF_CH0_BTM_STRT_ADD_VANC (0x005c)
|
||||
#define VPIF_CH0_SP_CFG (0x0060)
|
||||
#define VPIF_CH0_IMG_ADD_OFST (0x0064)
|
||||
#define VPIF_CH0_HANC_ADD_OFST (0x0068)
|
||||
#define VPIF_CH0_H_CFG (0x006c)
|
||||
#define VPIF_CH0_V_CFG_00 (0x0070)
|
||||
#define VPIF_CH0_V_CFG_01 (0x0074)
|
||||
#define VPIF_CH0_V_CFG_02 (0x0078)
|
||||
#define VPIF_CH0_V_CFG_03 (0x007c)
|
||||
|
||||
#define VPIF_CH1_TOP_STRT_ADD_LUMA (0x0080)
|
||||
#define VPIF_CH1_BTM_STRT_ADD_LUMA (0x0084)
|
||||
#define VPIF_CH1_TOP_STRT_ADD_CHROMA (0x0088)
|
||||
#define VPIF_CH1_BTM_STRT_ADD_CHROMA (0x008c)
|
||||
#define VPIF_CH1_TOP_STRT_ADD_HANC (0x0090)
|
||||
#define VPIF_CH1_BTM_STRT_ADD_HANC (0x0094)
|
||||
#define VPIF_CH1_TOP_STRT_ADD_VANC (0x0098)
|
||||
#define VPIF_CH1_BTM_STRT_ADD_VANC (0x009c)
|
||||
#define VPIF_CH1_SP_CFG (0x00a0)
|
||||
#define VPIF_CH1_IMG_ADD_OFST (0x00a4)
|
||||
#define VPIF_CH1_HANC_ADD_OFST (0x00a8)
|
||||
#define VPIF_CH1_H_CFG (0x00ac)
|
||||
#define VPIF_CH1_V_CFG_00 (0x00b0)
|
||||
#define VPIF_CH1_V_CFG_01 (0x00b4)
|
||||
#define VPIF_CH1_V_CFG_02 (0x00b8)
|
||||
#define VPIF_CH1_V_CFG_03 (0x00bc)
|
||||
|
||||
#define VPIF_CH2_TOP_STRT_ADD_LUMA (0x00c0)
|
||||
#define VPIF_CH2_BTM_STRT_ADD_LUMA (0x00c4)
|
||||
#define VPIF_CH2_TOP_STRT_ADD_CHROMA (0x00c8)
|
||||
#define VPIF_CH2_BTM_STRT_ADD_CHROMA (0x00cc)
|
||||
#define VPIF_CH2_TOP_STRT_ADD_HANC (0x00d0)
|
||||
#define VPIF_CH2_BTM_STRT_ADD_HANC (0x00d4)
|
||||
#define VPIF_CH2_TOP_STRT_ADD_VANC (0x00d8)
|
||||
#define VPIF_CH2_BTM_STRT_ADD_VANC (0x00dc)
|
||||
#define VPIF_CH2_SP_CFG (0x00e0)
|
||||
#define VPIF_CH2_IMG_ADD_OFST (0x00e4)
|
||||
#define VPIF_CH2_HANC_ADD_OFST (0x00e8)
|
||||
#define VPIF_CH2_H_CFG (0x00ec)
|
||||
#define VPIF_CH2_V_CFG_00 (0x00f0)
|
||||
#define VPIF_CH2_V_CFG_01 (0x00f4)
|
||||
#define VPIF_CH2_V_CFG_02 (0x00f8)
|
||||
#define VPIF_CH2_V_CFG_03 (0x00fc)
|
||||
#define VPIF_CH2_HANC0_STRT (0x0100)
|
||||
#define VPIF_CH2_HANC0_SIZE (0x0104)
|
||||
#define VPIF_CH2_HANC1_STRT (0x0108)
|
||||
#define VPIF_CH2_HANC1_SIZE (0x010c)
|
||||
#define VPIF_CH2_VANC0_STRT (0x0110)
|
||||
#define VPIF_CH2_VANC0_SIZE (0x0114)
|
||||
#define VPIF_CH2_VANC1_STRT (0x0118)
|
||||
#define VPIF_CH2_VANC1_SIZE (0x011c)
|
||||
|
||||
#define VPIF_CH3_TOP_STRT_ADD_LUMA (0x0140)
|
||||
#define VPIF_CH3_BTM_STRT_ADD_LUMA (0x0144)
|
||||
#define VPIF_CH3_TOP_STRT_ADD_CHROMA (0x0148)
|
||||
#define VPIF_CH3_BTM_STRT_ADD_CHROMA (0x014c)
|
||||
#define VPIF_CH3_TOP_STRT_ADD_HANC (0x0150)
|
||||
#define VPIF_CH3_BTM_STRT_ADD_HANC (0x0154)
|
||||
#define VPIF_CH3_TOP_STRT_ADD_VANC (0x0158)
|
||||
#define VPIF_CH3_BTM_STRT_ADD_VANC (0x015c)
|
||||
#define VPIF_CH3_SP_CFG (0x0160)
|
||||
#define VPIF_CH3_IMG_ADD_OFST (0x0164)
|
||||
#define VPIF_CH3_HANC_ADD_OFST (0x0168)
|
||||
#define VPIF_CH3_H_CFG (0x016c)
|
||||
#define VPIF_CH3_V_CFG_00 (0x0170)
|
||||
#define VPIF_CH3_V_CFG_01 (0x0174)
|
||||
#define VPIF_CH3_V_CFG_02 (0x0178)
|
||||
#define VPIF_CH3_V_CFG_03 (0x017c)
|
||||
#define VPIF_CH3_HANC0_STRT (0x0180)
|
||||
#define VPIF_CH3_HANC0_SIZE (0x0184)
|
||||
#define VPIF_CH3_HANC1_STRT (0x0188)
|
||||
#define VPIF_CH3_HANC1_SIZE (0x018c)
|
||||
#define VPIF_CH3_VANC0_STRT (0x0190)
|
||||
#define VPIF_CH3_VANC0_SIZE (0x0194)
|
||||
#define VPIF_CH3_VANC1_STRT (0x0198)
|
||||
#define VPIF_CH3_VANC1_SIZE (0x019c)
|
||||
|
||||
#define VPIF_IODFT_CTRL (0x01c0)
|
||||
|
||||
/* Functions for bit Manipulation */
|
||||
static inline void vpif_set_bit(u32 reg, u32 bit)
|
||||
{
|
||||
regw((regr(reg)) | (0x01 << bit), reg);
|
||||
}
|
||||
|
||||
static inline void vpif_clr_bit(u32 reg, u32 bit)
|
||||
{
|
||||
regw(((regr(reg)) & ~(0x01 << bit)), reg);
|
||||
}
|
||||
|
||||
/* Macro for Generating mask */
|
||||
#ifdef GENERATE_MASK
|
||||
#undef GENERATE_MASK
|
||||
#endif
|
||||
|
||||
#define GENERATE_MASK(bits, pos) \
|
||||
((((0xFFFFFFFF) << (32 - bits)) >> (32 - bits)) << pos)
|
||||
|
||||
/* Bit positions in the channel control registers */
|
||||
#define VPIF_CH_DATA_MODE_BIT (2)
|
||||
#define VPIF_CH_YC_MUX_BIT (3)
|
||||
#define VPIF_CH_SDR_FMT_BIT (4)
|
||||
#define VPIF_CH_HANC_EN_BIT (8)
|
||||
#define VPIF_CH_VANC_EN_BIT (9)
|
||||
|
||||
#define VPIF_CAPTURE_CH_NIP (10)
|
||||
#define VPIF_DISPLAY_CH_NIP (11)
|
||||
|
||||
#define VPIF_DISPLAY_PIX_EN_BIT (10)
|
||||
|
||||
#define VPIF_CH_INPUT_FIELD_FRAME_BIT (12)
|
||||
|
||||
#define VPIF_CH_FID_POLARITY_BIT (15)
|
||||
#define VPIF_CH_V_VALID_POLARITY_BIT (14)
|
||||
#define VPIF_CH_H_VALID_POLARITY_BIT (13)
|
||||
#define VPIF_CH_DATA_WIDTH_BIT (28)
|
||||
|
||||
#define VPIF_CH_CLK_EDGE_CTRL_BIT (31)
|
||||
|
||||
/* Mask various length */
|
||||
#define VPIF_CH_EAVSAV_MASK GENERATE_MASK(13, 0)
|
||||
#define VPIF_CH_LEN_MASK GENERATE_MASK(12, 0)
|
||||
#define VPIF_CH_WIDTH_MASK GENERATE_MASK(13, 0)
|
||||
#define VPIF_CH_LEN_SHIFT (16)
|
||||
|
||||
/* VPIF masks for registers */
|
||||
#define VPIF_REQ_SIZE_MASK (0x1ff)
|
||||
|
||||
/* bit posotion of interrupt vpif_ch_intr register */
|
||||
#define VPIF_INTEN_FRAME_CH0 (0x00000001)
|
||||
#define VPIF_INTEN_FRAME_CH1 (0x00000002)
|
||||
#define VPIF_INTEN_FRAME_CH2 (0x00000004)
|
||||
#define VPIF_INTEN_FRAME_CH3 (0x00000008)
|
||||
|
||||
/* bit position of clock and channel enable in vpif_chn_ctrl register */
|
||||
|
||||
#define VPIF_CH0_CLK_EN (0x00000002)
|
||||
#define VPIF_CH0_EN (0x00000001)
|
||||
#define VPIF_CH1_CLK_EN (0x00000002)
|
||||
#define VPIF_CH1_EN (0x00000001)
|
||||
#define VPIF_CH2_CLK_EN (0x00000002)
|
||||
#define VPIF_CH2_EN (0x00000001)
|
||||
#define VPIF_CH3_CLK_EN (0x00000002)
|
||||
#define VPIF_CH3_EN (0x00000001)
|
||||
#define VPIF_CH_CLK_EN (0x00000002)
|
||||
#define VPIF_CH_EN (0x00000001)
|
||||
|
||||
#define VPIF_INT_TOP (0x00)
|
||||
#define VPIF_INT_BOTTOM (0x01)
|
||||
#define VPIF_INT_BOTH (0x02)
|
||||
|
||||
#define VPIF_CH0_INT_CTRL_SHIFT (6)
|
||||
#define VPIF_CH1_INT_CTRL_SHIFT (6)
|
||||
#define VPIF_CH2_INT_CTRL_SHIFT (6)
|
||||
#define VPIF_CH3_INT_CTRL_SHIFT (6)
|
||||
#define VPIF_CH_INT_CTRL_SHIFT (6)
|
||||
|
||||
/* enabled interrupt on both the fields on vpid_ch0_ctrl register */
|
||||
#define channel0_intr_assert() (regw((regr(VPIF_CH0_CTRL)|\
|
||||
(VPIF_INT_BOTH << VPIF_CH0_INT_CTRL_SHIFT)), VPIF_CH0_CTRL))
|
||||
|
||||
/* enabled interrupt on both the fields on vpid_ch1_ctrl register */
|
||||
#define channel1_intr_assert() (regw((regr(VPIF_CH1_CTRL)|\
|
||||
(VPIF_INT_BOTH << VPIF_CH1_INT_CTRL_SHIFT)), VPIF_CH1_CTRL))
|
||||
|
||||
/* enabled interrupt on both the fields on vpid_ch0_ctrl register */
|
||||
#define channel2_intr_assert() (regw((regr(VPIF_CH2_CTRL)|\
|
||||
(VPIF_INT_BOTH << VPIF_CH2_INT_CTRL_SHIFT)), VPIF_CH2_CTRL))
|
||||
|
||||
/* enabled interrupt on both the fields on vpid_ch1_ctrl register */
|
||||
#define channel3_intr_assert() (regw((regr(VPIF_CH3_CTRL)|\
|
||||
(VPIF_INT_BOTH << VPIF_CH3_INT_CTRL_SHIFT)), VPIF_CH3_CTRL))
|
||||
|
||||
#define VPIF_CH_FID_MASK (0x20)
|
||||
#define VPIF_CH_FID_SHIFT (5)
|
||||
|
||||
#define VPIF_NTSC_VBI_START_FIELD0 (1)
|
||||
#define VPIF_NTSC_VBI_START_FIELD1 (263)
|
||||
#define VPIF_PAL_VBI_START_FIELD0 (624)
|
||||
#define VPIF_PAL_VBI_START_FIELD1 (311)
|
||||
|
||||
#define VPIF_NTSC_HBI_START_FIELD0 (1)
|
||||
#define VPIF_NTSC_HBI_START_FIELD1 (263)
|
||||
#define VPIF_PAL_HBI_START_FIELD0 (624)
|
||||
#define VPIF_PAL_HBI_START_FIELD1 (311)
|
||||
|
||||
#define VPIF_NTSC_VBI_COUNT_FIELD0 (20)
|
||||
#define VPIF_NTSC_VBI_COUNT_FIELD1 (19)
|
||||
#define VPIF_PAL_VBI_COUNT_FIELD0 (24)
|
||||
#define VPIF_PAL_VBI_COUNT_FIELD1 (25)
|
||||
|
||||
#define VPIF_NTSC_HBI_COUNT_FIELD0 (263)
|
||||
#define VPIF_NTSC_HBI_COUNT_FIELD1 (262)
|
||||
#define VPIF_PAL_HBI_COUNT_FIELD0 (312)
|
||||
#define VPIF_PAL_HBI_COUNT_FIELD1 (313)
|
||||
|
||||
#define VPIF_NTSC_VBI_SAMPLES_PER_LINE (720)
|
||||
#define VPIF_PAL_VBI_SAMPLES_PER_LINE (720)
|
||||
#define VPIF_NTSC_HBI_SAMPLES_PER_LINE (268)
|
||||
#define VPIF_PAL_HBI_SAMPLES_PER_LINE (280)
|
||||
|
||||
#define VPIF_CH_VANC_EN (0x20)
|
||||
#define VPIF_DMA_REQ_SIZE (0x080)
|
||||
#define VPIF_EMULATION_DISABLE (0x01)
|
||||
|
||||
extern u8 irq_vpif_capture_channel[VPIF_NUM_CHANNELS];
|
||||
|
||||
/* inline function to enable/disable channel0 */
|
||||
static inline void enable_channel0(int enable)
|
||||
{
|
||||
if (enable)
|
||||
regw((regr(VPIF_CH0_CTRL) | (VPIF_CH0_EN)), VPIF_CH0_CTRL);
|
||||
else
|
||||
regw((regr(VPIF_CH0_CTRL) & (~VPIF_CH0_EN)), VPIF_CH0_CTRL);
|
||||
}
|
||||
|
||||
/* inline function to enable/disable channel1 */
|
||||
static inline void enable_channel1(int enable)
|
||||
{
|
||||
if (enable)
|
||||
regw((regr(VPIF_CH1_CTRL) | (VPIF_CH1_EN)), VPIF_CH1_CTRL);
|
||||
else
|
||||
regw((regr(VPIF_CH1_CTRL) & (~VPIF_CH1_EN)), VPIF_CH1_CTRL);
|
||||
}
|
||||
|
||||
/* inline function to enable interrupt for channel0 */
|
||||
static inline void channel0_intr_enable(int enable)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&vpif_lock, flags);
|
||||
|
||||
if (enable) {
|
||||
regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN);
|
||||
regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET);
|
||||
|
||||
regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH0), VPIF_INTEN);
|
||||
regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0),
|
||||
VPIF_INTEN_SET);
|
||||
} else {
|
||||
regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH0)), VPIF_INTEN);
|
||||
regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0),
|
||||
VPIF_INTEN_SET);
|
||||
}
|
||||
spin_unlock_irqrestore(&vpif_lock, flags);
|
||||
}
|
||||
|
||||
/* inline function to enable interrupt for channel1 */
|
||||
static inline void channel1_intr_enable(int enable)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&vpif_lock, flags);
|
||||
|
||||
if (enable) {
|
||||
regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN);
|
||||
regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET);
|
||||
|
||||
regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH1), VPIF_INTEN);
|
||||
regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1),
|
||||
VPIF_INTEN_SET);
|
||||
} else {
|
||||
regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH1)), VPIF_INTEN);
|
||||
regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1),
|
||||
VPIF_INTEN_SET);
|
||||
}
|
||||
spin_unlock_irqrestore(&vpif_lock, flags);
|
||||
}
|
||||
|
||||
/* inline function to set buffer addresses in case of Y/C non mux mode */
|
||||
static inline void ch0_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma,
|
||||
unsigned long btm_strt_luma,
|
||||
unsigned long top_strt_chroma,
|
||||
unsigned long btm_strt_chroma)
|
||||
{
|
||||
regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA);
|
||||
regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA);
|
||||
regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA);
|
||||
regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA);
|
||||
}
|
||||
|
||||
/* inline function to set buffer addresses in VPIF registers for video data */
|
||||
static inline void ch0_set_videobuf_addr(unsigned long top_strt_luma,
|
||||
unsigned long btm_strt_luma,
|
||||
unsigned long top_strt_chroma,
|
||||
unsigned long btm_strt_chroma)
|
||||
{
|
||||
regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA);
|
||||
regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA);
|
||||
regw(top_strt_chroma, VPIF_CH0_TOP_STRT_ADD_CHROMA);
|
||||
regw(btm_strt_chroma, VPIF_CH0_BTM_STRT_ADD_CHROMA);
|
||||
}
|
||||
|
||||
static inline void ch1_set_videobuf_addr(unsigned long top_strt_luma,
|
||||
unsigned long btm_strt_luma,
|
||||
unsigned long top_strt_chroma,
|
||||
unsigned long btm_strt_chroma)
|
||||
{
|
||||
|
||||
regw(top_strt_luma, VPIF_CH1_TOP_STRT_ADD_LUMA);
|
||||
regw(btm_strt_luma, VPIF_CH1_BTM_STRT_ADD_LUMA);
|
||||
regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA);
|
||||
regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA);
|
||||
}
|
||||
|
||||
static inline void ch0_set_vbi_addr(unsigned long top_vbi,
|
||||
unsigned long btm_vbi, unsigned long a, unsigned long b)
|
||||
{
|
||||
regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_VANC);
|
||||
regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_VANC);
|
||||
}
|
||||
|
||||
static inline void ch0_set_hbi_addr(unsigned long top_vbi,
|
||||
unsigned long btm_vbi, unsigned long a, unsigned long b)
|
||||
{
|
||||
regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_HANC);
|
||||
regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_HANC);
|
||||
}
|
||||
|
||||
static inline void ch1_set_vbi_addr(unsigned long top_vbi,
|
||||
unsigned long btm_vbi, unsigned long a, unsigned long b)
|
||||
{
|
||||
regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_VANC);
|
||||
regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_VANC);
|
||||
}
|
||||
|
||||
static inline void ch1_set_hbi_addr(unsigned long top_vbi,
|
||||
unsigned long btm_vbi, unsigned long a, unsigned long b)
|
||||
{
|
||||
regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_HANC);
|
||||
regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_HANC);
|
||||
}
|
||||
|
||||
/* Inline function to enable raw vbi in the given channel */
|
||||
static inline void disable_raw_feature(u8 channel_id, u8 index)
|
||||
{
|
||||
u32 ctrl_reg;
|
||||
if (0 == channel_id)
|
||||
ctrl_reg = VPIF_CH0_CTRL;
|
||||
else
|
||||
ctrl_reg = VPIF_CH1_CTRL;
|
||||
|
||||
if (1 == index)
|
||||
vpif_clr_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT);
|
||||
else
|
||||
vpif_clr_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT);
|
||||
}
|
||||
|
||||
static inline void enable_raw_feature(u8 channel_id, u8 index)
|
||||
{
|
||||
u32 ctrl_reg;
|
||||
if (0 == channel_id)
|
||||
ctrl_reg = VPIF_CH0_CTRL;
|
||||
else
|
||||
ctrl_reg = VPIF_CH1_CTRL;
|
||||
|
||||
if (1 == index)
|
||||
vpif_set_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT);
|
||||
else
|
||||
vpif_set_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT);
|
||||
}
|
||||
|
||||
/* inline function to enable/disable channel2 */
|
||||
static inline void enable_channel2(int enable)
|
||||
{
|
||||
if (enable) {
|
||||
regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL);
|
||||
regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_EN)), VPIF_CH2_CTRL);
|
||||
} else {
|
||||
regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL);
|
||||
regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_EN)), VPIF_CH2_CTRL);
|
||||
}
|
||||
}
|
||||
|
||||
/* inline function to enable/disable channel3 */
|
||||
static inline void enable_channel3(int enable)
|
||||
{
|
||||
if (enable) {
|
||||
regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL);
|
||||
regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_EN)), VPIF_CH3_CTRL);
|
||||
} else {
|
||||
regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL);
|
||||
regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_EN)), VPIF_CH3_CTRL);
|
||||
}
|
||||
}
|
||||
|
||||
/* inline function to enable interrupt for channel2 */
|
||||
static inline void channel2_intr_enable(int enable)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&vpif_lock, flags);
|
||||
|
||||
if (enable) {
|
||||
regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN);
|
||||
regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET);
|
||||
regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH2), VPIF_INTEN);
|
||||
regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2),
|
||||
VPIF_INTEN_SET);
|
||||
} else {
|
||||
regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH2)), VPIF_INTEN);
|
||||
regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2),
|
||||
VPIF_INTEN_SET);
|
||||
}
|
||||
spin_unlock_irqrestore(&vpif_lock, flags);
|
||||
}
|
||||
|
||||
/* inline function to enable interrupt for channel3 */
|
||||
static inline void channel3_intr_enable(int enable)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&vpif_lock, flags);
|
||||
|
||||
if (enable) {
|
||||
regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN);
|
||||
regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET);
|
||||
|
||||
regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH3), VPIF_INTEN);
|
||||
regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3),
|
||||
VPIF_INTEN_SET);
|
||||
} else {
|
||||
regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH3)), VPIF_INTEN);
|
||||
regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3),
|
||||
VPIF_INTEN_SET);
|
||||
}
|
||||
spin_unlock_irqrestore(&vpif_lock, flags);
|
||||
}
|
||||
|
||||
/* inline function to enable raw vbi data for channel2 */
|
||||
static inline void channel2_raw_enable(int enable, u8 index)
|
||||
{
|
||||
u32 mask;
|
||||
|
||||
if (1 == index)
|
||||
mask = VPIF_CH_VANC_EN_BIT;
|
||||
else
|
||||
mask = VPIF_CH_HANC_EN_BIT;
|
||||
|
||||
if (enable)
|
||||
vpif_set_bit(VPIF_CH2_CTRL, mask);
|
||||
else
|
||||
vpif_clr_bit(VPIF_CH2_CTRL, mask);
|
||||
}
|
||||
|
||||
/* inline function to enable raw vbi data for channel3*/
|
||||
static inline void channel3_raw_enable(int enable, u8 index)
|
||||
{
|
||||
u32 mask;
|
||||
|
||||
if (1 == index)
|
||||
mask = VPIF_CH_VANC_EN_BIT;
|
||||
else
|
||||
mask = VPIF_CH_HANC_EN_BIT;
|
||||
|
||||
if (enable)
|
||||
vpif_set_bit(VPIF_CH3_CTRL, mask);
|
||||
else
|
||||
vpif_clr_bit(VPIF_CH3_CTRL, mask);
|
||||
}
|
||||
|
||||
/* inline function to set buffer addresses in case of Y/C non mux mode */
|
||||
static inline void ch2_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma,
|
||||
unsigned long btm_strt_luma,
|
||||
unsigned long top_strt_chroma,
|
||||
unsigned long btm_strt_chroma)
|
||||
{
|
||||
regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA);
|
||||
regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA);
|
||||
regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA);
|
||||
regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA);
|
||||
}
|
||||
|
||||
/* inline function to set buffer addresses in VPIF registers for video data */
|
||||
static inline void ch2_set_videobuf_addr(unsigned long top_strt_luma,
|
||||
unsigned long btm_strt_luma,
|
||||
unsigned long top_strt_chroma,
|
||||
unsigned long btm_strt_chroma)
|
||||
{
|
||||
regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA);
|
||||
regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA);
|
||||
regw(top_strt_chroma, VPIF_CH2_TOP_STRT_ADD_CHROMA);
|
||||
regw(btm_strt_chroma, VPIF_CH2_BTM_STRT_ADD_CHROMA);
|
||||
}
|
||||
|
||||
static inline void ch3_set_videobuf_addr(unsigned long top_strt_luma,
|
||||
unsigned long btm_strt_luma,
|
||||
unsigned long top_strt_chroma,
|
||||
unsigned long btm_strt_chroma)
|
||||
{
|
||||
regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_LUMA);
|
||||
regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_LUMA);
|
||||
regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA);
|
||||
regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA);
|
||||
}
|
||||
|
||||
/* inline function to set buffer addresses in VPIF registers for vbi data */
|
||||
static inline void ch2_set_vbi_addr(unsigned long top_strt_luma,
|
||||
unsigned long btm_strt_luma,
|
||||
unsigned long top_strt_chroma,
|
||||
unsigned long btm_strt_chroma)
|
||||
{
|
||||
regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_VANC);
|
||||
regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_VANC);
|
||||
}
|
||||
|
||||
static inline void ch3_set_vbi_addr(unsigned long top_strt_luma,
|
||||
unsigned long btm_strt_luma,
|
||||
unsigned long top_strt_chroma,
|
||||
unsigned long btm_strt_chroma)
|
||||
{
|
||||
regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_VANC);
|
||||
regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_VANC);
|
||||
}
|
||||
|
||||
#define VPIF_MAX_NAME (30)
|
||||
|
||||
/* This structure will store size parameters as per the mode selected by user */
|
||||
struct vpif_channel_config_params {
|
||||
char name[VPIF_MAX_NAME]; /* Name of the mode */
|
||||
u16 width; /* Indicates width of the image */
|
||||
u16 height; /* Indicates height of the image */
|
||||
u8 fps;
|
||||
u8 frm_fmt; /* Indicates whether this is interlaced
|
||||
* or progressive format */
|
||||
u8 ycmux_mode; /* Indicates whether this mode requires
|
||||
* single or two channels */
|
||||
u16 eav2sav; /* length of sav 2 eav */
|
||||
u16 sav2eav; /* length of sav 2 eav */
|
||||
u16 l1, l3, l5, l7, l9, l11; /* Other parameter configurations */
|
||||
u16 vsize; /* Vertical size of the image */
|
||||
u8 capture_format; /* Indicates whether capture format
|
||||
* is in BT or in CCD/CMOS */
|
||||
u8 vbi_supported; /* Indicates whether this mode
|
||||
* supports capturing vbi or not */
|
||||
u8 hd_sd;
|
||||
v4l2_std_id stdid;
|
||||
};
|
||||
|
||||
struct vpif_video_params;
|
||||
struct vpif_params;
|
||||
struct vpif_vbi_params;
|
||||
|
||||
int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id);
|
||||
void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams,
|
||||
u8 channel_id);
|
||||
int vpif_channel_getfid(u8 channel_id);
|
||||
|
||||
enum data_size {
|
||||
_8BITS = 0,
|
||||
_10BITS,
|
||||
_12BITS,
|
||||
};
|
||||
|
||||
/* Structure for vpif parameters for raw vbi data */
|
||||
struct vpif_vbi_params {
|
||||
__u32 hstart0; /* Horizontal start of raw vbi data for first field */
|
||||
__u32 vstart0; /* Vertical start of raw vbi data for first field */
|
||||
__u32 hsize0; /* Horizontal size of raw vbi data for first field */
|
||||
__u32 vsize0; /* Vertical size of raw vbi data for first field */
|
||||
__u32 hstart1; /* Horizontal start of raw vbi data for second field */
|
||||
__u32 vstart1; /* Vertical start of raw vbi data for second field */
|
||||
__u32 hsize1; /* Horizontal size of raw vbi data for second field */
|
||||
__u32 vsize1; /* Vertical size of raw vbi data for second field */
|
||||
};
|
||||
|
||||
/* structure for vpif parameters */
|
||||
struct vpif_video_params {
|
||||
__u8 storage_mode; /* Indicates field or frame mode */
|
||||
unsigned long hpitch;
|
||||
v4l2_std_id stdid;
|
||||
};
|
||||
|
||||
struct vpif_params {
|
||||
struct vpif_interface iface;
|
||||
struct vpif_video_params video_params;
|
||||
struct vpif_channel_config_params std_info;
|
||||
union param {
|
||||
struct vpif_vbi_params vbi_params;
|
||||
enum data_size data_sz;
|
||||
} params;
|
||||
};
|
||||
|
||||
#endif /* End of #ifndef VPIF_H */
|
||||
|
||||
2168
drivers/media/video/davinci/vpif_capture.c
Normal file
2168
drivers/media/video/davinci/vpif_capture.c
Normal file
File diff suppressed because it is too large
Load diff
165
drivers/media/video/davinci/vpif_capture.h
Normal file
165
drivers/media/video/davinci/vpif_capture.h
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Texas Instruments Inc
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef VPIF_CAPTURE_H
|
||||
#define VPIF_CAPTURE_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/* Header files */
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/version.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/videobuf-core.h>
|
||||
#include <media/videobuf-dma-contig.h>
|
||||
#include <mach/dm646x.h>
|
||||
|
||||
#include "vpif.h"
|
||||
|
||||
/* Macros */
|
||||
#define VPIF_MAJOR_RELEASE 0
|
||||
#define VPIF_MINOR_RELEASE 0
|
||||
#define VPIF_BUILD 1
|
||||
#define VPIF_CAPTURE_VERSION_CODE ((VPIF_MAJOR_RELEASE << 16) | \
|
||||
(VPIF_MINOR_RELEASE << 8) | VPIF_BUILD)
|
||||
|
||||
#define VPIF_VALID_FIELD(field) (((V4L2_FIELD_ANY == field) || \
|
||||
(V4L2_FIELD_NONE == field)) || \
|
||||
(((V4L2_FIELD_INTERLACED == field) || \
|
||||
(V4L2_FIELD_SEQ_TB == field)) || \
|
||||
(V4L2_FIELD_SEQ_BT == field)))
|
||||
|
||||
#define VPIF_CAPTURE_MAX_DEVICES 2
|
||||
#define VPIF_VIDEO_INDEX 0
|
||||
#define VPIF_NUMBER_OF_OBJECTS 1
|
||||
|
||||
/* Enumerated data type to give id to each device per channel */
|
||||
enum vpif_channel_id {
|
||||
VPIF_CHANNEL0_VIDEO = 0,
|
||||
VPIF_CHANNEL1_VIDEO,
|
||||
};
|
||||
|
||||
struct video_obj {
|
||||
enum v4l2_field buf_field;
|
||||
/* Currently selected or default standard */
|
||||
v4l2_std_id stdid;
|
||||
/* This is to track the last input that is passed to application */
|
||||
u32 input_idx;
|
||||
};
|
||||
|
||||
struct common_obj {
|
||||
/* Pointer pointing to current v4l2_buffer */
|
||||
struct videobuf_buffer *cur_frm;
|
||||
/* Pointer pointing to current v4l2_buffer */
|
||||
struct videobuf_buffer *next_frm;
|
||||
/*
|
||||
* This field keeps track of type of buffer exchange mechanism
|
||||
* user has selected
|
||||
*/
|
||||
enum v4l2_memory memory;
|
||||
/* Used to store pixel format */
|
||||
struct v4l2_format fmt;
|
||||
/* Buffer queue used in video-buf */
|
||||
struct videobuf_queue buffer_queue;
|
||||
/* Queue of filled frames */
|
||||
struct list_head dma_queue;
|
||||
/* Used in video-buf */
|
||||
spinlock_t irqlock;
|
||||
/* lock used to access this structure */
|
||||
struct mutex lock;
|
||||
/* number of users performing IO */
|
||||
u32 io_usrs;
|
||||
/* Indicates whether streaming started */
|
||||
u8 started;
|
||||
/* Function pointer to set the addresses */
|
||||
void (*set_addr) (unsigned long, unsigned long, unsigned long,
|
||||
unsigned long);
|
||||
/* offset where Y top starts from the starting of the buffer */
|
||||
u32 ytop_off;
|
||||
/* offset where Y bottom starts from the starting of the buffer */
|
||||
u32 ybtm_off;
|
||||
/* offset where C top starts from the starting of the buffer */
|
||||
u32 ctop_off;
|
||||
/* offset where C bottom starts from the starting of the buffer */
|
||||
u32 cbtm_off;
|
||||
/* Indicates width of the image data */
|
||||
u32 width;
|
||||
/* Indicates height of the image data */
|
||||
u32 height;
|
||||
};
|
||||
|
||||
struct channel_obj {
|
||||
/* Identifies video device for this channel */
|
||||
struct video_device *video_dev;
|
||||
/* Used to keep track of state of the priority */
|
||||
struct v4l2_prio_state prio;
|
||||
/* number of open instances of the channel */
|
||||
int usrs;
|
||||
/* Indicates id of the field which is being displayed */
|
||||
u32 field_id;
|
||||
/* flag to indicate whether decoder is initialized */
|
||||
u8 initialized;
|
||||
/* Identifies channel */
|
||||
enum vpif_channel_id channel_id;
|
||||
/* index into sd table */
|
||||
int curr_sd_index;
|
||||
/* ptr to current sub device information */
|
||||
struct vpif_subdev_info *curr_subdev_info;
|
||||
/* vpif configuration params */
|
||||
struct vpif_params vpifparams;
|
||||
/* common object array */
|
||||
struct common_obj common[VPIF_NUMBER_OF_OBJECTS];
|
||||
/* video object */
|
||||
struct video_obj video;
|
||||
};
|
||||
|
||||
/* File handle structure */
|
||||
struct vpif_fh {
|
||||
/* pointer to channel object for opened device */
|
||||
struct channel_obj *channel;
|
||||
/* Indicates whether this file handle is doing IO */
|
||||
u8 io_allowed[VPIF_NUMBER_OF_OBJECTS];
|
||||
/* Used to keep track priority of this instance */
|
||||
enum v4l2_priority prio;
|
||||
/* Used to indicate channel is initialize or not */
|
||||
u8 initialized;
|
||||
};
|
||||
|
||||
struct vpif_device {
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct channel_obj *dev[VPIF_CAPTURE_NUM_CHANNELS];
|
||||
struct v4l2_subdev **sd;
|
||||
};
|
||||
|
||||
struct vpif_config_params {
|
||||
u8 min_numbuffers;
|
||||
u8 numbuffers[VPIF_CAPTURE_NUM_CHANNELS];
|
||||
s8 device_type;
|
||||
u32 min_bufsize[VPIF_CAPTURE_NUM_CHANNELS];
|
||||
u32 channel_bufsize[VPIF_CAPTURE_NUM_CHANNELS];
|
||||
u8 default_device[VPIF_CAPTURE_NUM_CHANNELS];
|
||||
u8 max_device_type;
|
||||
};
|
||||
/* Struct which keeps track of the line numbers for the sliced vbi service */
|
||||
struct vpif_service_line {
|
||||
u16 service_id;
|
||||
u16 service_line[2];
|
||||
};
|
||||
#endif /* End of __KERNEL__ */
|
||||
#endif /* VPIF_CAPTURE_H */
|
||||
1656
drivers/media/video/davinci/vpif_display.c
Normal file
1656
drivers/media/video/davinci/vpif_display.c
Normal file
File diff suppressed because it is too large
Load diff
175
drivers/media/video/davinci/vpif_display.h
Normal file
175
drivers/media/video/davinci/vpif_display.h
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* DM646x display header file
|
||||
*
|
||||
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2.
|
||||
*
|
||||
* This program is distributed .as is. WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef DAVINCIHD_DISPLAY_H
|
||||
#define DAVINCIHD_DISPLAY_H
|
||||
|
||||
/* Header files */
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/version.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/videobuf-core.h>
|
||||
#include <media/videobuf-dma-contig.h>
|
||||
|
||||
#include "vpif.h"
|
||||
|
||||
/* Macros */
|
||||
#define VPIF_MAJOR_RELEASE (0)
|
||||
#define VPIF_MINOR_RELEASE (0)
|
||||
#define VPIF_BUILD (1)
|
||||
|
||||
#define VPIF_DISPLAY_VERSION_CODE \
|
||||
((VPIF_MAJOR_RELEASE << 16) | (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD)
|
||||
|
||||
#define VPIF_VALID_FIELD(field) \
|
||||
(((V4L2_FIELD_ANY == field) || (V4L2_FIELD_NONE == field)) || \
|
||||
(((V4L2_FIELD_INTERLACED == field) || (V4L2_FIELD_SEQ_TB == field)) || \
|
||||
(V4L2_FIELD_SEQ_BT == field)))
|
||||
|
||||
#define VPIF_DISPLAY_MAX_DEVICES (2)
|
||||
#define VPIF_SLICED_BUF_SIZE (256)
|
||||
#define VPIF_SLICED_MAX_SERVICES (3)
|
||||
#define VPIF_VIDEO_INDEX (0)
|
||||
#define VPIF_VBI_INDEX (1)
|
||||
#define VPIF_HBI_INDEX (2)
|
||||
|
||||
/* Setting it to 1 as HBI/VBI support yet to be added , else 3*/
|
||||
#define VPIF_NUMOBJECTS (1)
|
||||
|
||||
/* Macros */
|
||||
#define ISALIGNED(a) (0 == ((a) & 7))
|
||||
|
||||
/* enumerated data types */
|
||||
/* Enumerated data type to give id to each device per channel */
|
||||
enum vpif_channel_id {
|
||||
VPIF_CHANNEL2_VIDEO = 0, /* Channel2 Video */
|
||||
VPIF_CHANNEL3_VIDEO, /* Channel3 Video */
|
||||
};
|
||||
|
||||
/* structures */
|
||||
|
||||
struct video_obj {
|
||||
enum v4l2_field buf_field;
|
||||
u32 latest_only; /* indicate whether to return
|
||||
* most recent displayed frame only */
|
||||
v4l2_std_id stdid; /* Currently selected or default
|
||||
* standard */
|
||||
u32 output_id; /* Current output id */
|
||||
};
|
||||
|
||||
struct vbi_obj {
|
||||
int num_services;
|
||||
struct vpif_vbi_params vbiparams; /* vpif parameters for the raw
|
||||
* vbi data */
|
||||
};
|
||||
|
||||
struct common_obj {
|
||||
/* Buffer specific parameters */
|
||||
u8 *fbuffers[VIDEO_MAX_FRAME]; /* List of buffer pointers for
|
||||
* storing frames */
|
||||
u32 numbuffers; /* number of buffers */
|
||||
struct videobuf_buffer *cur_frm; /* Pointer pointing to current
|
||||
* videobuf_buffer */
|
||||
struct videobuf_buffer *next_frm; /* Pointer pointing to next
|
||||
* videobuf_buffer */
|
||||
enum v4l2_memory memory; /* This field keeps track of
|
||||
* type of buffer exchange
|
||||
* method user has selected */
|
||||
struct v4l2_format fmt; /* Used to store the format */
|
||||
struct videobuf_queue buffer_queue; /* Buffer queue used in
|
||||
* video-buf */
|
||||
struct list_head dma_queue; /* Queue of filled frames */
|
||||
spinlock_t irqlock; /* Used in video-buf */
|
||||
|
||||
/* channel specific parameters */
|
||||
struct mutex lock; /* lock used to access this
|
||||
* structure */
|
||||
u32 io_usrs; /* number of users performing
|
||||
* IO */
|
||||
u8 started; /* Indicates whether streaming
|
||||
* started */
|
||||
u32 ytop_off; /* offset of Y top from the
|
||||
* starting of the buffer */
|
||||
u32 ybtm_off; /* offset of Y bottom from the
|
||||
* starting of the buffer */
|
||||
u32 ctop_off; /* offset of C top from the
|
||||
* starting of the buffer */
|
||||
u32 cbtm_off; /* offset of C bottom from the
|
||||
* starting of the buffer */
|
||||
/* Function pointer to set the addresses */
|
||||
void (*set_addr) (unsigned long, unsigned long,
|
||||
unsigned long, unsigned long);
|
||||
u32 height;
|
||||
u32 width;
|
||||
};
|
||||
|
||||
struct channel_obj {
|
||||
/* V4l2 specific parameters */
|
||||
struct video_device *video_dev; /* Identifies video device for
|
||||
* this channel */
|
||||
struct v4l2_prio_state prio; /* Used to keep track of state of
|
||||
* the priority */
|
||||
atomic_t usrs; /* number of open instances of
|
||||
* the channel */
|
||||
u32 field_id; /* Indicates id of the field
|
||||
* which is being displayed */
|
||||
u8 initialized; /* flag to indicate whether
|
||||
* encoder is initialized */
|
||||
|
||||
enum vpif_channel_id channel_id;/* Identifies channel */
|
||||
struct vpif_params vpifparams;
|
||||
struct common_obj common[VPIF_NUMOBJECTS];
|
||||
struct video_obj video;
|
||||
struct vbi_obj vbi;
|
||||
};
|
||||
|
||||
/* File handle structure */
|
||||
struct vpif_fh {
|
||||
struct channel_obj *channel; /* pointer to channel object for
|
||||
* opened device */
|
||||
u8 io_allowed[VPIF_NUMOBJECTS]; /* Indicates whether this file handle
|
||||
* is doing IO */
|
||||
enum v4l2_priority prio; /* Used to keep track priority of
|
||||
* this instance */
|
||||
u8 initialized; /* Used to keep track of whether this
|
||||
* file handle has initialized
|
||||
* channel or not */
|
||||
};
|
||||
|
||||
/* vpif device structure */
|
||||
struct vpif_device {
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct channel_obj *dev[VPIF_DISPLAY_NUM_CHANNELS];
|
||||
struct v4l2_subdev **sd;
|
||||
|
||||
};
|
||||
|
||||
struct vpif_config_params {
|
||||
u32 min_bufsize[VPIF_DISPLAY_NUM_CHANNELS];
|
||||
u32 channel_bufsize[VPIF_DISPLAY_NUM_CHANNELS];
|
||||
u8 numbuffers[VPIF_DISPLAY_NUM_CHANNELS];
|
||||
u8 min_numbuffers;
|
||||
};
|
||||
|
||||
/* Struct which keeps track of the line numbers for the sliced vbi service */
|
||||
struct vpif_service_line {
|
||||
u16 service_id;
|
||||
u16 service_line[2];
|
||||
u16 enc_service_id;
|
||||
u8 bytestowrite;
|
||||
};
|
||||
|
||||
#endif /* DAVINCIHD_DISPLAY_H */
|
||||
301
drivers/media/video/davinci/vpss.c
Normal file
301
drivers/media/video/davinci/vpss.c
Normal file
|
|
@ -0,0 +1,301 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Texas Instruments.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* common vpss driver for all video drivers.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/io.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <media/davinci/vpss.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("VPSS Driver");
|
||||
MODULE_AUTHOR("Texas Instruments");
|
||||
|
||||
/* DM644x defines */
|
||||
#define DM644X_SBL_PCR_VPSS (4)
|
||||
|
||||
/* vpss BL register offsets */
|
||||
#define DM355_VPSSBL_CCDCMUX 0x1c
|
||||
/* vpss CLK register offsets */
|
||||
#define DM355_VPSSCLK_CLKCTRL 0x04
|
||||
/* masks and shifts */
|
||||
#define VPSS_HSSISEL_SHIFT 4
|
||||
|
||||
/*
|
||||
* vpss operations. Depends on platform. Not all functions are available
|
||||
* on all platforms. The api, first check if a functio is available before
|
||||
* invoking it. In the probe, the function ptrs are intialized based on
|
||||
* vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc.
|
||||
*/
|
||||
struct vpss_hw_ops {
|
||||
/* enable clock */
|
||||
int (*enable_clock)(enum vpss_clock_sel clock_sel, int en);
|
||||
/* select input to ccdc */
|
||||
void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel);
|
||||
/* clear wbl overlflow bit */
|
||||
int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel);
|
||||
};
|
||||
|
||||
/* vpss configuration */
|
||||
struct vpss_oper_config {
|
||||
__iomem void *vpss_bl_regs_base;
|
||||
__iomem void *vpss_regs_base;
|
||||
struct resource *r1;
|
||||
resource_size_t len1;
|
||||
struct resource *r2;
|
||||
resource_size_t len2;
|
||||
char vpss_name[32];
|
||||
spinlock_t vpss_lock;
|
||||
struct vpss_hw_ops hw_ops;
|
||||
};
|
||||
|
||||
static struct vpss_oper_config oper_cfg;
|
||||
|
||||
/* register access routines */
|
||||
static inline u32 bl_regr(u32 offset)
|
||||
{
|
||||
return __raw_readl(oper_cfg.vpss_bl_regs_base + offset);
|
||||
}
|
||||
|
||||
static inline void bl_regw(u32 val, u32 offset)
|
||||
{
|
||||
__raw_writel(val, oper_cfg.vpss_bl_regs_base + offset);
|
||||
}
|
||||
|
||||
static inline u32 vpss_regr(u32 offset)
|
||||
{
|
||||
return __raw_readl(oper_cfg.vpss_regs_base + offset);
|
||||
}
|
||||
|
||||
static inline void vpss_regw(u32 val, u32 offset)
|
||||
{
|
||||
__raw_writel(val, oper_cfg.vpss_regs_base + offset);
|
||||
}
|
||||
|
||||
static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
|
||||
{
|
||||
bl_regw(src_sel << VPSS_HSSISEL_SHIFT, DM355_VPSSBL_CCDCMUX);
|
||||
}
|
||||
|
||||
int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
|
||||
{
|
||||
if (!oper_cfg.hw_ops.select_ccdc_source)
|
||||
return -1;
|
||||
|
||||
dm355_select_ccdc_source(src_sel);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(vpss_select_ccdc_source);
|
||||
|
||||
static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
|
||||
{
|
||||
u32 mask = 1, val;
|
||||
|
||||
if (wbl_sel < VPSS_PCR_AEW_WBL_0 ||
|
||||
wbl_sel > VPSS_PCR_CCDC_WBL_O)
|
||||
return -1;
|
||||
|
||||
/* writing a 0 clear the overflow */
|
||||
mask = ~(mask << wbl_sel);
|
||||
val = bl_regr(DM644X_SBL_PCR_VPSS) & mask;
|
||||
bl_regw(val, DM644X_SBL_PCR_VPSS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
|
||||
{
|
||||
if (!oper_cfg.hw_ops.clear_wbl_overflow)
|
||||
return -1;
|
||||
|
||||
return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel);
|
||||
}
|
||||
EXPORT_SYMBOL(vpss_clear_wbl_overflow);
|
||||
|
||||
/*
|
||||
* dm355_enable_clock - Enable VPSS Clock
|
||||
* @clock_sel: CLock to be enabled/disabled
|
||||
* @en: enable/disable flag
|
||||
*
|
||||
* This is called to enable or disable a vpss clock
|
||||
*/
|
||||
static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 utemp, mask = 0x1, shift = 0;
|
||||
|
||||
switch (clock_sel) {
|
||||
case VPSS_VPBE_CLOCK:
|
||||
/* nothing since lsb */
|
||||
break;
|
||||
case VPSS_VENC_CLOCK_SEL:
|
||||
shift = 2;
|
||||
break;
|
||||
case VPSS_CFALD_CLOCK:
|
||||
shift = 3;
|
||||
break;
|
||||
case VPSS_H3A_CLOCK:
|
||||
shift = 4;
|
||||
break;
|
||||
case VPSS_IPIPE_CLOCK:
|
||||
shift = 5;
|
||||
break;
|
||||
case VPSS_CCDC_CLOCK:
|
||||
shift = 6;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "dm355_enable_clock:"
|
||||
" Invalid selector: %d\n", clock_sel);
|
||||
return -1;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&oper_cfg.vpss_lock, flags);
|
||||
utemp = vpss_regr(DM355_VPSSCLK_CLKCTRL);
|
||||
if (!en)
|
||||
utemp &= ~(mask << shift);
|
||||
else
|
||||
utemp |= (mask << shift);
|
||||
|
||||
vpss_regw(utemp, DM355_VPSSCLK_CLKCTRL);
|
||||
spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en)
|
||||
{
|
||||
if (!oper_cfg.hw_ops.enable_clock)
|
||||
return -1;
|
||||
|
||||
return oper_cfg.hw_ops.enable_clock(clock_sel, en);
|
||||
}
|
||||
EXPORT_SYMBOL(vpss_enable_clock);
|
||||
|
||||
static int __init vpss_probe(struct platform_device *pdev)
|
||||
{
|
||||
int status, dm355 = 0;
|
||||
|
||||
if (!pdev->dev.platform_data) {
|
||||
dev_err(&pdev->dev, "no platform data\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
strcpy(oper_cfg.vpss_name, pdev->dev.platform_data);
|
||||
|
||||
if (!strcmp(oper_cfg.vpss_name, "dm355_vpss"))
|
||||
dm355 = 1;
|
||||
else if (strcmp(oper_cfg.vpss_name, "dm644x_vpss")) {
|
||||
dev_err(&pdev->dev, "vpss driver not supported on"
|
||||
" this platform\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "%s vpss probed\n", oper_cfg.vpss_name);
|
||||
oper_cfg.r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!oper_cfg.r1)
|
||||
return -ENOENT;
|
||||
|
||||
oper_cfg.len1 = oper_cfg.r1->end - oper_cfg.r1->start + 1;
|
||||
|
||||
oper_cfg.r1 = request_mem_region(oper_cfg.r1->start, oper_cfg.len1,
|
||||
oper_cfg.r1->name);
|
||||
if (!oper_cfg.r1)
|
||||
return -EBUSY;
|
||||
|
||||
oper_cfg.vpss_bl_regs_base = ioremap(oper_cfg.r1->start, oper_cfg.len1);
|
||||
if (!oper_cfg.vpss_bl_regs_base) {
|
||||
status = -EBUSY;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
if (dm355) {
|
||||
oper_cfg.r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!oper_cfg.r2) {
|
||||
status = -ENOENT;
|
||||
goto fail2;
|
||||
}
|
||||
oper_cfg.len2 = oper_cfg.r2->end - oper_cfg.r2->start + 1;
|
||||
oper_cfg.r2 = request_mem_region(oper_cfg.r2->start,
|
||||
oper_cfg.len2,
|
||||
oper_cfg.r2->name);
|
||||
if (!oper_cfg.r2) {
|
||||
status = -EBUSY;
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
oper_cfg.vpss_regs_base = ioremap(oper_cfg.r2->start,
|
||||
oper_cfg.len2);
|
||||
if (!oper_cfg.vpss_regs_base) {
|
||||
status = -EBUSY;
|
||||
goto fail3;
|
||||
}
|
||||
}
|
||||
|
||||
if (dm355) {
|
||||
oper_cfg.hw_ops.enable_clock = dm355_enable_clock;
|
||||
oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source;
|
||||
} else
|
||||
oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow;
|
||||
|
||||
spin_lock_init(&oper_cfg.vpss_lock);
|
||||
dev_info(&pdev->dev, "%s vpss probe success\n", oper_cfg.vpss_name);
|
||||
return 0;
|
||||
|
||||
fail3:
|
||||
release_mem_region(oper_cfg.r2->start, oper_cfg.len2);
|
||||
fail2:
|
||||
iounmap(oper_cfg.vpss_bl_regs_base);
|
||||
fail1:
|
||||
release_mem_region(oper_cfg.r1->start, oper_cfg.len1);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int vpss_remove(struct platform_device *pdev)
|
||||
{
|
||||
iounmap(oper_cfg.vpss_bl_regs_base);
|
||||
release_mem_region(oper_cfg.r1->start, oper_cfg.len1);
|
||||
if (!strcmp(oper_cfg.vpss_name, "dm355_vpss")) {
|
||||
iounmap(oper_cfg.vpss_regs_base);
|
||||
release_mem_region(oper_cfg.r2->start, oper_cfg.len2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver vpss_driver = {
|
||||
.driver = {
|
||||
.name = "vpss",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.remove = __devexit_p(vpss_remove),
|
||||
.probe = vpss_probe,
|
||||
};
|
||||
|
||||
static void vpss_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&vpss_driver);
|
||||
}
|
||||
|
||||
static int __init vpss_init(void)
|
||||
{
|
||||
return platform_driver_register(&vpss_driver);
|
||||
}
|
||||
subsys_initcall(vpss_init);
|
||||
module_exit(vpss_exit);
|
||||
|
|
@ -36,6 +36,7 @@ config VIDEO_EM28XX_DVB
|
|||
depends on VIDEO_EM28XX && DVB_CORE
|
||||
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
|
||||
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
|
||||
select VIDEOBUF_DVB
|
||||
---help---
|
||||
This adds support for DVB cards based on the
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \
|
||||
em28xx-input.o
|
||||
em28xx-input.o em28xx-vbi.o
|
||||
|
||||
em28xx-alsa-objs := em28xx-audio.o
|
||||
|
||||
|
|
|
|||
|
|
@ -170,6 +170,19 @@ static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = {
|
|||
{ -1, -1, -1, -1},
|
||||
};
|
||||
|
||||
/* eb1a:2868 Reddo DVB-C USB TV Box
|
||||
GPIO4 - CU1216L NIM
|
||||
Other GPIOs seems to be don't care. */
|
||||
static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = {
|
||||
{EM28XX_R08_GPIO, 0xfe, 0xff, 10},
|
||||
{EM28XX_R08_GPIO, 0xde, 0xff, 10},
|
||||
{EM28XX_R08_GPIO, 0xfe, 0xff, 10},
|
||||
{EM28XX_R08_GPIO, 0xff, 0xff, 10},
|
||||
{EM28XX_R08_GPIO, 0x7f, 0xff, 10},
|
||||
{EM28XX_R08_GPIO, 0x6f, 0xff, 10},
|
||||
{EM28XX_R08_GPIO, 0xff, 0xff, 10},
|
||||
{-1, -1, -1, -1},
|
||||
};
|
||||
|
||||
/* Callback for the most boards */
|
||||
static struct em28xx_reg_seq default_tuner_gpio[] = {
|
||||
|
|
@ -1566,6 +1579,14 @@ struct em28xx_board em28xx_boards[] = {
|
|||
.gpio = evga_indtube_analog,
|
||||
} },
|
||||
},
|
||||
/* eb1a:2868 Empia EM2870 + Philips CU1216L NIM (Philips TDA10023 +
|
||||
Infineon TUA6034) */
|
||||
[EM2870_BOARD_REDDO_DVB_C_USB_BOX] = {
|
||||
.name = "Reddo DVB-C USB TV Box",
|
||||
.tuner_type = TUNER_ABSENT,
|
||||
.has_dvb = 1,
|
||||
.dvb_gpio = reddo_dvb_c_usb_box,
|
||||
},
|
||||
};
|
||||
const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
|
||||
|
||||
|
|
@ -1593,6 +1614,8 @@ struct usb_device_id em28xx_id_table[] = {
|
|||
.driver_info = EM2820_BOARD_UNKNOWN },
|
||||
{ USB_DEVICE(0xeb1a, 0x2883),
|
||||
.driver_info = EM2820_BOARD_UNKNOWN },
|
||||
{ USB_DEVICE(0xeb1a, 0x2868),
|
||||
.driver_info = EM2820_BOARD_UNKNOWN },
|
||||
{ USB_DEVICE(0xeb1a, 0xe300),
|
||||
.driver_info = EM2861_BOARD_KWORLD_PVRTV_300U },
|
||||
{ USB_DEVICE(0xeb1a, 0xe303),
|
||||
|
|
@ -1696,6 +1719,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = {
|
|||
{0x166a0441, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028},
|
||||
{0xcee44a99, EM2882_BOARD_EVGA_INDTUBE, TUNER_XC2028},
|
||||
{0xb8846b20, EM2881_BOARD_PINNACLE_HYBRID_PRO, TUNER_XC2028},
|
||||
{0x63f653bd, EM2870_BOARD_REDDO_DVB_C_USB_BOX, TUNER_ABSENT},
|
||||
};
|
||||
|
||||
/* I2C devicelist hash table for devices with generic USB IDs */
|
||||
|
|
@ -2348,55 +2372,55 @@ void em28xx_card_setup(struct em28xx *dev)
|
|||
|
||||
/* request some modules */
|
||||
if (dev->board.has_msp34xx)
|
||||
v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
|
||||
"msp3400", "msp3400", msp3400_addrs);
|
||||
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
|
||||
"msp3400", "msp3400", 0, msp3400_addrs);
|
||||
|
||||
if (dev->board.decoder == EM28XX_SAA711X)
|
||||
v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
|
||||
"saa7115", "saa7115_auto", saa711x_addrs);
|
||||
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
|
||||
"saa7115", "saa7115_auto", 0, saa711x_addrs);
|
||||
|
||||
if (dev->board.decoder == EM28XX_TVP5150)
|
||||
v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
|
||||
"tvp5150", "tvp5150", tvp5150_addrs);
|
||||
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
|
||||
"tvp5150", "tvp5150", 0, tvp5150_addrs);
|
||||
|
||||
if (dev->em28xx_sensor == EM28XX_MT9V011) {
|
||||
struct v4l2_subdev *sd;
|
||||
|
||||
sd = v4l2_i2c_new_probed_subdev(&dev->v4l2_dev,
|
||||
&dev->i2c_adap, "mt9v011", "mt9v011", mt9v011_addrs);
|
||||
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
|
||||
&dev->i2c_adap, "mt9v011", "mt9v011", 0, mt9v011_addrs);
|
||||
v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal);
|
||||
}
|
||||
|
||||
|
||||
if (dev->board.adecoder == EM28XX_TVAUDIO)
|
||||
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
|
||||
"tvaudio", "tvaudio", dev->board.tvaudio_addr);
|
||||
"tvaudio", "tvaudio", dev->board.tvaudio_addr, NULL);
|
||||
|
||||
if (dev->board.tuner_type != TUNER_ABSENT) {
|
||||
int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
|
||||
|
||||
if (dev->board.radio.type)
|
||||
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
|
||||
"tuner", "tuner", dev->board.radio_addr);
|
||||
"tuner", "tuner", dev->board.radio_addr, NULL);
|
||||
|
||||
if (has_demod)
|
||||
v4l2_i2c_new_probed_subdev(&dev->v4l2_dev,
|
||||
v4l2_i2c_new_subdev(&dev->v4l2_dev,
|
||||
&dev->i2c_adap, "tuner", "tuner",
|
||||
v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
|
||||
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
|
||||
if (dev->tuner_addr == 0) {
|
||||
enum v4l2_i2c_tuner_type type =
|
||||
has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
|
||||
struct v4l2_subdev *sd;
|
||||
|
||||
sd = v4l2_i2c_new_probed_subdev(&dev->v4l2_dev,
|
||||
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
|
||||
&dev->i2c_adap, "tuner", "tuner",
|
||||
v4l2_i2c_tuner_addrs(type));
|
||||
0, v4l2_i2c_tuner_addrs(type));
|
||||
|
||||
if (sd)
|
||||
dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
|
||||
} else {
|
||||
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
|
||||
"tuner", "tuner", dev->tuner_addr);
|
||||
"tuner", "tuner", dev->tuner_addr, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2570,7 +2594,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
|
|||
* Default format, used for tvp5150 or saa711x output formats
|
||||
*/
|
||||
dev->vinmode = 0x10;
|
||||
dev->vinctl = 0x11;
|
||||
dev->vinctl = EM28XX_VINCTRL_INTERLACED |
|
||||
EM28XX_VINCTRL_CCIR656_ENABLE;
|
||||
|
||||
/* Do board specific init and eeprom reading */
|
||||
em28xx_card_setup(dev);
|
||||
|
|
@ -2589,6 +2614,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
|
|||
/* init video dma queues */
|
||||
INIT_LIST_HEAD(&dev->vidq.active);
|
||||
INIT_LIST_HEAD(&dev->vidq.queued);
|
||||
INIT_LIST_HEAD(&dev->vbiq.active);
|
||||
INIT_LIST_HEAD(&dev->vbiq.queued);
|
||||
|
||||
|
||||
if (dev->board.has_msp34xx) {
|
||||
|
|
|
|||
|
|
@ -54,6 +54,10 @@ static int alt = EM28XX_PINOUT;
|
|||
module_param(alt, int, 0644);
|
||||
MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
|
||||
|
||||
static unsigned int disable_vbi;
|
||||
module_param(disable_vbi, int, 0644);
|
||||
MODULE_PARM_DESC(disable_vbi, "disable vbi support");
|
||||
|
||||
/* FIXME */
|
||||
#define em28xx_isocdbg(fmt, arg...) do {\
|
||||
if (core_debug) \
|
||||
|
|
@ -648,9 +652,24 @@ int em28xx_capture_start(struct em28xx *dev, int start)
|
|||
return rc;
|
||||
}
|
||||
|
||||
int em28xx_vbi_supported(struct em28xx *dev)
|
||||
{
|
||||
/* Modprobe option to manually disable */
|
||||
if (disable_vbi == 1)
|
||||
return 0;
|
||||
|
||||
if (dev->chip_id == CHIP_ID_EM2860 ||
|
||||
dev->chip_id == CHIP_ID_EM2883)
|
||||
return 1;
|
||||
|
||||
/* Version of em28xx that does not support VBI */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int em28xx_set_outfmt(struct em28xx *dev)
|
||||
{
|
||||
int ret;
|
||||
u8 vinctrl;
|
||||
|
||||
ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT,
|
||||
dev->format->reg | 0x20, 0xff);
|
||||
|
|
@ -661,7 +680,16 @@ int em28xx_set_outfmt(struct em28xx *dev)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, dev->vinctl);
|
||||
vinctrl = dev->vinctl;
|
||||
if (em28xx_vbi_supported(dev) == 1) {
|
||||
vinctrl |= EM28XX_VINCTRL_VBI_RAW;
|
||||
em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
|
||||
em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
|
||||
em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, 0xb4);
|
||||
em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, 0x0c);
|
||||
}
|
||||
|
||||
return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
|
||||
}
|
||||
|
||||
static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
|
||||
|
|
@ -732,7 +760,14 @@ int em28xx_resolution_set(struct em28xx *dev)
|
|||
|
||||
|
||||
em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
|
||||
em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
|
||||
|
||||
/* If we don't set the start position to 4 in VBI mode, we end up
|
||||
with line 21 being YUYV encoded instead of being in 8-bit
|
||||
greyscale */
|
||||
if (em28xx_vbi_supported(dev) == 1)
|
||||
em28xx_capture_area_set(dev, 0, 4, width >> 2, height >> 2);
|
||||
else
|
||||
em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
|
||||
|
||||
return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
|
||||
}
|
||||
|
|
@ -844,8 +879,7 @@ EXPORT_SYMBOL_GPL(em28xx_set_mode);
|
|||
*/
|
||||
static void em28xx_irq_callback(struct urb *urb)
|
||||
{
|
||||
struct em28xx_dmaqueue *dma_q = urb->context;
|
||||
struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
|
||||
struct em28xx *dev = urb->context;
|
||||
int rc, i;
|
||||
|
||||
switch (urb->status) {
|
||||
|
|
@ -930,6 +964,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
|
|||
int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
|
||||
{
|
||||
struct em28xx_dmaqueue *dma_q = &dev->vidq;
|
||||
struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
|
||||
int i;
|
||||
int sb_size, pipe;
|
||||
struct urb *urb;
|
||||
|
|
@ -959,7 +994,8 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
|
|||
}
|
||||
|
||||
dev->isoc_ctl.max_pkt_size = max_pkt_size;
|
||||
dev->isoc_ctl.buf = NULL;
|
||||
dev->isoc_ctl.vid_buf = NULL;
|
||||
dev->isoc_ctl.vbi_buf = NULL;
|
||||
|
||||
sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
|
||||
|
||||
|
|
@ -994,7 +1030,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
|
|||
|
||||
usb_fill_int_urb(urb, dev->udev, pipe,
|
||||
dev->isoc_ctl.transfer_buffer[i], sb_size,
|
||||
em28xx_irq_callback, dma_q, 1);
|
||||
em28xx_irq_callback, dev, 1);
|
||||
|
||||
urb->number_of_packets = max_packets;
|
||||
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
|
||||
|
|
@ -1009,6 +1045,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
|
|||
}
|
||||
|
||||
init_waitqueue_head(&dma_q->wq);
|
||||
init_waitqueue_head(&vbi_dma_q->wq);
|
||||
|
||||
em28xx_capture_start(dev, 1);
|
||||
|
||||
|
|
@ -1094,7 +1131,7 @@ struct em28xx *em28xx_get_device(int minor,
|
|||
list_for_each_entry(h, &em28xx_devlist, devlist) {
|
||||
if (h->vdev->minor == minor)
|
||||
dev = h;
|
||||
if (h->vbi_dev->minor == minor) {
|
||||
if (h->vbi_dev && h->vbi_dev->minor == minor) {
|
||||
dev = h;
|
||||
*fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "s5h1409.h"
|
||||
#include "mt352.h"
|
||||
#include "mt352_priv.h" /* FIXME */
|
||||
#include "tda1002x.h"
|
||||
|
||||
MODULE_DESCRIPTION("driver for em28xx based DVB cards");
|
||||
MODULE_AUTHOR("Mauro Carvalho Chehab <[email protected]>");
|
||||
|
|
@ -295,6 +296,11 @@ static struct mt352_config terratec_xs_mt352_cfg = {
|
|||
.demod_init = mt352_terratec_xs_init,
|
||||
};
|
||||
|
||||
static struct tda10023_config em28xx_tda10023_config = {
|
||||
.demod_address = 0x0c,
|
||||
.invert = 1,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static int attach_xc3028(u8 addr, struct em28xx *dev)
|
||||
|
|
@ -549,6 +555,19 @@ static int dvb_init(struct em28xx *dev)
|
|||
}
|
||||
break;
|
||||
#endif
|
||||
case EM2870_BOARD_REDDO_DVB_C_USB_BOX:
|
||||
/* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */
|
||||
dvb->frontend = dvb_attach(tda10023_attach,
|
||||
&em28xx_tda10023_config,
|
||||
&dev->i2c_adap, 0x48);
|
||||
if (dvb->frontend) {
|
||||
if (!dvb_attach(simple_tuner_attach, dvb->frontend,
|
||||
&dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) {
|
||||
result = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
|
||||
" isn't supported yet\n",
|
||||
|
|
|
|||
|
|
@ -86,7 +86,19 @@
|
|||
#define EM28XX_XCLK_FREQUENCY_24MHZ 0x0b
|
||||
|
||||
#define EM28XX_R10_VINMODE 0x10
|
||||
|
||||
#define EM28XX_R11_VINCTRL 0x11
|
||||
|
||||
/* em28xx Video Input Control Register 0x11 */
|
||||
#define EM28XX_VINCTRL_VBI_SLICED 0x80
|
||||
#define EM28XX_VINCTRL_VBI_RAW 0x40
|
||||
#define EM28XX_VINCTRL_VOUT_MODE_IN 0x20 /* HREF,VREF,VACT in output */
|
||||
#define EM28XX_VINCTRL_CCIR656_ENABLE 0x10
|
||||
#define EM28XX_VINCTRL_VBI_16BIT_RAW 0x08 /* otherwise 8-bit raw */
|
||||
#define EM28XX_VINCTRL_FID_ON_HREF 0x04
|
||||
#define EM28XX_VINCTRL_DUAL_EDGE_STROBE 0x02
|
||||
#define EM28XX_VINCTRL_INTERLACED 0x01
|
||||
|
||||
#define EM28XX_R12_VINENABLE 0x12 /* */
|
||||
|
||||
#define EM28XX_R14_GAMMA 0x14
|
||||
|
|
@ -135,6 +147,10 @@
|
|||
#define EM28XX_R31_HSCALEHIGH 0x31
|
||||
#define EM28XX_R32_VSCALELOW 0x32
|
||||
#define EM28XX_R33_VSCALEHIGH 0x33
|
||||
#define EM28XX_R34_VBI_START_H 0x34
|
||||
#define EM28XX_R35_VBI_START_V 0x35
|
||||
#define EM28XX_R36_VBI_WIDTH 0x36
|
||||
#define EM28XX_R37_VBI_HEIGHT 0x37
|
||||
|
||||
#define EM28XX_R40_AC97LSB 0x40
|
||||
#define EM28XX_R41_AC97MSB 0x41
|
||||
|
|
|
|||
142
drivers/media/video/em28xx/em28xx-vbi.c
Normal file
142
drivers/media/video/em28xx/em28xx-vbi.c
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
em28xx-vbi.c - VBI driver for em28xx
|
||||
|
||||
Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
|
||||
|
||||
This work was sponsored by EyeMagnet Limited.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "em28xx.h"
|
||||
|
||||
static unsigned int vbibufs = 5;
|
||||
module_param(vbibufs, int, 0644);
|
||||
MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
|
||||
|
||||
static unsigned int vbi_debug;
|
||||
module_param(vbi_debug, int, 0644);
|
||||
MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
|
||||
|
||||
#define dprintk(level, fmt, arg...) if (vbi_debug >= level) \
|
||||
printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg)
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static void
|
||||
free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
|
||||
{
|
||||
struct em28xx_fh *fh = vq->priv_data;
|
||||
struct em28xx *dev = fh->dev;
|
||||
unsigned long flags = 0;
|
||||
if (in_interrupt())
|
||||
BUG();
|
||||
|
||||
/* We used to wait for the buffer to finish here, but this didn't work
|
||||
because, as we were keeping the state as VIDEOBUF_QUEUED,
|
||||
videobuf_queue_cancel marked it as finished for us.
|
||||
(Also, it could wedge forever if the hardware was misconfigured.)
|
||||
|
||||
This should be safe; by the time we get here, the buffer isn't
|
||||
queued anymore. If we ever start marking the buffers as
|
||||
VIDEOBUF_ACTIVE, it won't be, though.
|
||||
*/
|
||||
spin_lock_irqsave(&dev->slock, flags);
|
||||
if (dev->isoc_ctl.vbi_buf == buf)
|
||||
dev->isoc_ctl.vbi_buf = NULL;
|
||||
spin_unlock_irqrestore(&dev->slock, flags);
|
||||
|
||||
videobuf_vmalloc_free(&buf->vb);
|
||||
buf->vb.state = VIDEOBUF_NEEDS_INIT;
|
||||
}
|
||||
|
||||
static int
|
||||
vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
|
||||
{
|
||||
*size = 720 * 12 * 2;
|
||||
if (0 == *count)
|
||||
*count = vbibufs;
|
||||
if (*count < 2)
|
||||
*count = 2;
|
||||
if (*count > 32)
|
||||
*count = 32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
|
||||
enum v4l2_field field)
|
||||
{
|
||||
struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
|
||||
int rc = 0;
|
||||
unsigned int size;
|
||||
|
||||
size = 720 * 12 * 2;
|
||||
|
||||
buf->vb.size = size;
|
||||
|
||||
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
|
||||
return -EINVAL;
|
||||
|
||||
buf->vb.width = 720;
|
||||
buf->vb.height = 12;
|
||||
buf->vb.field = field;
|
||||
|
||||
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
|
||||
rc = videobuf_iolock(q, &buf->vb, NULL);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
buf->vb.state = VIDEOBUF_PREPARED;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
free_buffer(q, buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
|
||||
{
|
||||
struct em28xx_buffer *buf = container_of(vb,
|
||||
struct em28xx_buffer,
|
||||
vb);
|
||||
struct em28xx_fh *fh = vq->priv_data;
|
||||
struct em28xx *dev = fh->dev;
|
||||
struct em28xx_dmaqueue *vbiq = &dev->vbiq;
|
||||
|
||||
buf->vb.state = VIDEOBUF_QUEUED;
|
||||
list_add_tail(&buf->vb.queue, &vbiq->active);
|
||||
}
|
||||
|
||||
static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
|
||||
{
|
||||
struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
|
||||
free_buffer(q, buf);
|
||||
}
|
||||
|
||||
struct videobuf_queue_ops em28xx_vbi_qops = {
|
||||
.buf_setup = vbi_setup,
|
||||
.buf_prepare = vbi_prepare,
|
||||
.buf_queue = vbi_queue,
|
||||
.buf_release = vbi_release,
|
||||
};
|
||||
|
|
@ -163,7 +163,24 @@ static inline void buffer_filled(struct em28xx *dev,
|
|||
buf->vb.field_count++;
|
||||
do_gettimeofday(&buf->vb.ts);
|
||||
|
||||
dev->isoc_ctl.buf = NULL;
|
||||
dev->isoc_ctl.vid_buf = NULL;
|
||||
|
||||
list_del(&buf->vb.queue);
|
||||
wake_up(&buf->vb.done);
|
||||
}
|
||||
|
||||
static inline void vbi_buffer_filled(struct em28xx *dev,
|
||||
struct em28xx_dmaqueue *dma_q,
|
||||
struct em28xx_buffer *buf)
|
||||
{
|
||||
/* Advice that buffer was filled */
|
||||
em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
|
||||
|
||||
buf->vb.state = VIDEOBUF_DONE;
|
||||
buf->vb.field_count++;
|
||||
do_gettimeofday(&buf->vb.ts);
|
||||
|
||||
dev->isoc_ctl.vbi_buf = NULL;
|
||||
|
||||
list_del(&buf->vb.queue);
|
||||
wake_up(&buf->vb.done);
|
||||
|
|
@ -239,7 +256,8 @@ static void em28xx_copy_video(struct em28xx *dev,
|
|||
|
||||
if ((char *)startwrite + lencopy > (char *)outp +
|
||||
buf->vb.size) {
|
||||
em28xx_isocdbg("Overflow of %zi bytes past buffer end (2)\n",
|
||||
em28xx_isocdbg("Overflow of %zi bytes past buffer end"
|
||||
"(2)\n",
|
||||
((char *)startwrite + lencopy) -
|
||||
((char *)outp + buf->vb.size));
|
||||
lencopy = remain = (char *)outp + buf->vb.size -
|
||||
|
|
@ -256,6 +274,63 @@ static void em28xx_copy_video(struct em28xx *dev,
|
|||
dma_q->pos += len;
|
||||
}
|
||||
|
||||
static void em28xx_copy_vbi(struct em28xx *dev,
|
||||
struct em28xx_dmaqueue *dma_q,
|
||||
struct em28xx_buffer *buf,
|
||||
unsigned char *p,
|
||||
unsigned char *outp, unsigned long len)
|
||||
{
|
||||
void *startwrite, *startread;
|
||||
int offset;
|
||||
int bytesperline = 720;
|
||||
|
||||
if (dev == NULL) {
|
||||
em28xx_isocdbg("dev is null\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dma_q == NULL) {
|
||||
em28xx_isocdbg("dma_q is null\n");
|
||||
return;
|
||||
}
|
||||
if (buf == NULL) {
|
||||
return;
|
||||
}
|
||||
if (p == NULL) {
|
||||
em28xx_isocdbg("p is null\n");
|
||||
return;
|
||||
}
|
||||
if (outp == NULL) {
|
||||
em28xx_isocdbg("outp is null\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dma_q->pos + len > buf->vb.size)
|
||||
len = buf->vb.size - dma_q->pos;
|
||||
|
||||
if ((p[0] == 0x33 && p[1] == 0x95) ||
|
||||
(p[0] == 0x88 && p[1] == 0x88)) {
|
||||
/* Header field, advance past it */
|
||||
p += 4;
|
||||
} else {
|
||||
len += 4;
|
||||
}
|
||||
|
||||
startread = p;
|
||||
|
||||
startwrite = outp + dma_q->pos;
|
||||
offset = dma_q->pos;
|
||||
|
||||
/* Make sure the bottom field populates the second half of the frame */
|
||||
if (buf->top_field == 0) {
|
||||
startwrite += bytesperline * 0x0c;
|
||||
offset += bytesperline * 0x0c;
|
||||
}
|
||||
|
||||
memcpy(startwrite, startread, len);
|
||||
dma_q->pos += len;
|
||||
}
|
||||
|
||||
static inline void print_err_status(struct em28xx *dev,
|
||||
int packet, int status)
|
||||
{
|
||||
|
|
@ -306,7 +381,7 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
|
|||
|
||||
if (list_empty(&dma_q->active)) {
|
||||
em28xx_isocdbg("No active queue to serve\n");
|
||||
dev->isoc_ctl.buf = NULL;
|
||||
dev->isoc_ctl.vid_buf = NULL;
|
||||
*buf = NULL;
|
||||
return;
|
||||
}
|
||||
|
|
@ -318,7 +393,34 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
|
|||
outp = videobuf_to_vmalloc(&(*buf)->vb);
|
||||
memset(outp, 0, (*buf)->vb.size);
|
||||
|
||||
dev->isoc_ctl.buf = *buf;
|
||||
dev->isoc_ctl.vid_buf = *buf;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* video-buf generic routine to get the next available VBI buffer
|
||||
*/
|
||||
static inline void vbi_get_next_buf(struct em28xx_dmaqueue *dma_q,
|
||||
struct em28xx_buffer **buf)
|
||||
{
|
||||
struct em28xx *dev = container_of(dma_q, struct em28xx, vbiq);
|
||||
char *outp;
|
||||
|
||||
if (list_empty(&dma_q->active)) {
|
||||
em28xx_isocdbg("No active queue to serve\n");
|
||||
dev->isoc_ctl.vbi_buf = NULL;
|
||||
*buf = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the next buffer */
|
||||
*buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
|
||||
/* Cleans up buffer - Usefull for testing for frame/URB loss */
|
||||
outp = videobuf_to_vmalloc(&(*buf)->vb);
|
||||
memset(outp, 0x00, (*buf)->vb.size);
|
||||
|
||||
dev->isoc_ctl.vbi_buf = *buf;
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -329,7 +431,7 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
|
|||
static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
|
||||
{
|
||||
struct em28xx_buffer *buf;
|
||||
struct em28xx_dmaqueue *dma_q = urb->context;
|
||||
struct em28xx_dmaqueue *dma_q = &dev->vidq;
|
||||
unsigned char *outp = NULL;
|
||||
int i, len = 0, rc = 1;
|
||||
unsigned char *p;
|
||||
|
|
@ -346,7 +448,7 @@ static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
buf = dev->isoc_ctl.buf;
|
||||
buf = dev->isoc_ctl.vid_buf;
|
||||
if (buf != NULL)
|
||||
outp = videobuf_to_vmalloc(&buf->vb);
|
||||
|
||||
|
|
@ -410,6 +512,153 @@ static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* Version of isoc handler that takes into account a mixture of video and
|
||||
VBI data */
|
||||
static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb)
|
||||
{
|
||||
struct em28xx_buffer *buf, *vbi_buf;
|
||||
struct em28xx_dmaqueue *dma_q = &dev->vidq;
|
||||
struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
|
||||
unsigned char *outp = NULL;
|
||||
unsigned char *vbioutp = NULL;
|
||||
int i, len = 0, rc = 1;
|
||||
unsigned char *p;
|
||||
int vbi_size;
|
||||
|
||||
if (!dev)
|
||||
return 0;
|
||||
|
||||
if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
|
||||
return 0;
|
||||
|
||||
if (urb->status < 0) {
|
||||
print_err_status(dev, -1, urb->status);
|
||||
if (urb->status == -ENOENT)
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf = dev->isoc_ctl.vid_buf;
|
||||
if (buf != NULL)
|
||||
outp = videobuf_to_vmalloc(&buf->vb);
|
||||
|
||||
vbi_buf = dev->isoc_ctl.vbi_buf;
|
||||
if (vbi_buf != NULL)
|
||||
vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
|
||||
|
||||
for (i = 0; i < urb->number_of_packets; i++) {
|
||||
int status = urb->iso_frame_desc[i].status;
|
||||
|
||||
if (status < 0) {
|
||||
print_err_status(dev, i, status);
|
||||
if (urb->iso_frame_desc[i].status != -EPROTO)
|
||||
continue;
|
||||
}
|
||||
|
||||
len = urb->iso_frame_desc[i].actual_length - 4;
|
||||
|
||||
if (urb->iso_frame_desc[i].actual_length <= 0) {
|
||||
/* em28xx_isocdbg("packet %d is empty",i); - spammy */
|
||||
continue;
|
||||
}
|
||||
if (urb->iso_frame_desc[i].actual_length >
|
||||
dev->max_pkt_size) {
|
||||
em28xx_isocdbg("packet bigger than packet size");
|
||||
continue;
|
||||
}
|
||||
|
||||
p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
|
||||
|
||||
/* capture type 0 = vbi start
|
||||
capture type 1 = video start
|
||||
capture type 2 = video in progress */
|
||||
if (p[0] == 0x33 && p[1] == 0x95) {
|
||||
dev->capture_type = 0;
|
||||
dev->vbi_read = 0;
|
||||
em28xx_isocdbg("VBI START HEADER!!!\n");
|
||||
dev->cur_field = p[2];
|
||||
}
|
||||
|
||||
/* FIXME: get rid of hard-coded value */
|
||||
vbi_size = 720 * 0x0c;
|
||||
|
||||
if (dev->capture_type == 0) {
|
||||
if (dev->vbi_read >= vbi_size) {
|
||||
/* We've already read all the VBI data, so
|
||||
treat the rest as video */
|
||||
em28xx_isocdbg("dev->vbi_read > vbi_size\n");
|
||||
} else if ((dev->vbi_read + len) < vbi_size) {
|
||||
/* This entire frame is VBI data */
|
||||
if (dev->vbi_read == 0 &&
|
||||
(!(dev->cur_field & 1))) {
|
||||
/* Brand new frame */
|
||||
if (vbi_buf != NULL)
|
||||
vbi_buffer_filled(dev,
|
||||
vbi_dma_q,
|
||||
vbi_buf);
|
||||
vbi_get_next_buf(vbi_dma_q, &vbi_buf);
|
||||
if (vbi_buf == NULL)
|
||||
vbioutp = NULL;
|
||||
else
|
||||
vbioutp = videobuf_to_vmalloc(
|
||||
&vbi_buf->vb);
|
||||
}
|
||||
|
||||
if (dev->vbi_read == 0) {
|
||||
vbi_dma_q->pos = 0;
|
||||
if (vbi_buf != NULL) {
|
||||
if (dev->cur_field & 1)
|
||||
vbi_buf->top_field = 0;
|
||||
else
|
||||
vbi_buf->top_field = 1;
|
||||
}
|
||||
}
|
||||
|
||||
dev->vbi_read += len;
|
||||
em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
|
||||
vbioutp, len);
|
||||
} else {
|
||||
/* Some of this frame is VBI data and some is
|
||||
video data */
|
||||
int vbi_data_len = vbi_size - dev->vbi_read;
|
||||
dev->vbi_read += vbi_data_len;
|
||||
em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
|
||||
vbioutp, vbi_data_len);
|
||||
dev->capture_type = 1;
|
||||
p += vbi_data_len;
|
||||
len -= vbi_data_len;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->capture_type == 1) {
|
||||
dev->capture_type = 2;
|
||||
em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
|
||||
len, (p[2] & 1) ? "odd" : "even");
|
||||
|
||||
if (dev->progressive || !(dev->cur_field & 1)) {
|
||||
if (buf != NULL)
|
||||
buffer_filled(dev, dma_q, buf);
|
||||
get_next_buf(dma_q, &buf);
|
||||
if (buf == NULL)
|
||||
outp = NULL;
|
||||
else
|
||||
outp = videobuf_to_vmalloc(&buf->vb);
|
||||
}
|
||||
if (buf != NULL) {
|
||||
if (dev->cur_field & 1)
|
||||
buf->top_field = 0;
|
||||
else
|
||||
buf->top_field = 1;
|
||||
}
|
||||
|
||||
dma_q->pos = 0;
|
||||
}
|
||||
if (buf != NULL && dev->capture_type == 2)
|
||||
em28xx_copy_video(dev, dma_q, buf, p, outp, len);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
Videobuf operations
|
||||
------------------------------------------------------------------*/
|
||||
|
|
@ -421,7 +670,8 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
|
|||
struct em28xx *dev = fh->dev;
|
||||
struct v4l2_frequency f;
|
||||
|
||||
*size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3;
|
||||
*size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)
|
||||
>> 3;
|
||||
|
||||
if (0 == *count)
|
||||
*count = EM28XX_DEF_BUF;
|
||||
|
|
@ -458,8 +708,8 @@ static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
|
|||
VIDEOBUF_ACTIVE, it won't be, though.
|
||||
*/
|
||||
spin_lock_irqsave(&dev->slock, flags);
|
||||
if (dev->isoc_ctl.buf == buf)
|
||||
dev->isoc_ctl.buf = NULL;
|
||||
if (dev->isoc_ctl.vid_buf == buf)
|
||||
dev->isoc_ctl.vid_buf = NULL;
|
||||
spin_unlock_irqrestore(&dev->slock, flags);
|
||||
|
||||
videobuf_vmalloc_free(&buf->vb);
|
||||
|
|
@ -475,7 +725,8 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
|
|||
struct em28xx *dev = fh->dev;
|
||||
int rc = 0, urb_init = 0;
|
||||
|
||||
buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3;
|
||||
buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth
|
||||
+ 7) >> 3;
|
||||
|
||||
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
|
||||
return -EINVAL;
|
||||
|
|
@ -494,9 +745,16 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
|
|||
urb_init = 1;
|
||||
|
||||
if (urb_init) {
|
||||
rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
|
||||
EM28XX_NUM_BUFS, dev->max_pkt_size,
|
||||
em28xx_isoc_copy);
|
||||
if (em28xx_vbi_supported(dev) == 1)
|
||||
rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
|
||||
EM28XX_NUM_BUFS,
|
||||
dev->max_pkt_size,
|
||||
em28xx_isoc_copy_vbi);
|
||||
else
|
||||
rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
|
||||
EM28XX_NUM_BUFS,
|
||||
dev->max_pkt_size,
|
||||
em28xx_isoc_copy);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -578,34 +836,63 @@ static void video_mux(struct em28xx *dev, int index)
|
|||
}
|
||||
|
||||
/* Usage lock check functions */
|
||||
static int res_get(struct em28xx_fh *fh)
|
||||
{
|
||||
struct em28xx *dev = fh->dev;
|
||||
int rc = 0;
|
||||
|
||||
/* This instance already has stream_on */
|
||||
if (fh->stream_on)
|
||||
return rc;
|
||||
|
||||
if (dev->stream_on)
|
||||
return -EBUSY;
|
||||
|
||||
dev->stream_on = 1;
|
||||
fh->stream_on = 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int res_check(struct em28xx_fh *fh)
|
||||
{
|
||||
return fh->stream_on;
|
||||
}
|
||||
|
||||
static void res_free(struct em28xx_fh *fh)
|
||||
static int res_get(struct em28xx_fh *fh, unsigned int bit)
|
||||
{
|
||||
struct em28xx *dev = fh->dev;
|
||||
|
||||
fh->stream_on = 0;
|
||||
dev->stream_on = 0;
|
||||
if (fh->resources & bit)
|
||||
/* have it already allocated */
|
||||
return 1;
|
||||
|
||||
/* is it free? */
|
||||
mutex_lock(&dev->lock);
|
||||
if (dev->resources & bit) {
|
||||
/* no, someone else uses it */
|
||||
mutex_unlock(&dev->lock);
|
||||
return 0;
|
||||
}
|
||||
/* it's free, grab it */
|
||||
fh->resources |= bit;
|
||||
dev->resources |= bit;
|
||||
em28xx_videodbg("res: get %d\n", bit);
|
||||
mutex_unlock(&dev->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int res_check(struct em28xx_fh *fh, unsigned int bit)
|
||||
{
|
||||
return fh->resources & bit;
|
||||
}
|
||||
|
||||
static int res_locked(struct em28xx *dev, unsigned int bit)
|
||||
{
|
||||
return dev->resources & bit;
|
||||
}
|
||||
|
||||
static void res_free(struct em28xx_fh *fh, unsigned int bits)
|
||||
{
|
||||
struct em28xx *dev = fh->dev;
|
||||
|
||||
BUG_ON((fh->resources & bits) != bits);
|
||||
|
||||
mutex_lock(&dev->lock);
|
||||
fh->resources &= ~bits;
|
||||
dev->resources &= ~bits;
|
||||
em28xx_videodbg("res: put %d\n", bits);
|
||||
mutex_unlock(&dev->lock);
|
||||
}
|
||||
|
||||
static int get_ressource(struct em28xx_fh *fh)
|
||||
{
|
||||
switch (fh->type) {
|
||||
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
||||
return EM28XX_RESOURCE_VIDEO;
|
||||
case V4L2_BUF_TYPE_VBI_CAPTURE:
|
||||
return EM28XX_RESOURCE_VBI;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -782,7 +1069,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
|
|||
} else {
|
||||
/* width must even because of the YUYV format
|
||||
height must be even because of interlacing */
|
||||
v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0);
|
||||
v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh,
|
||||
1, 0);
|
||||
}
|
||||
|
||||
get_scale(dev, width, height, &hscale, &vscale);
|
||||
|
|
@ -848,12 +1136,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (dev->stream_on && !fh->stream_on) {
|
||||
em28xx_errdev("%s device in use by another fh\n", __func__);
|
||||
rc = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = em28xx_set_video_format(dev, f->fmt.pix.pixelformat,
|
||||
f->fmt.pix.width, f->fmt.pix.height);
|
||||
|
||||
|
|
@ -862,6 +1144,21 @@ out:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
|
||||
{
|
||||
struct em28xx_fh *fh = priv;
|
||||
struct em28xx *dev = fh->dev;
|
||||
int rc;
|
||||
|
||||
rc = check_dev(dev);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
*norm = dev->norm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
|
||||
{
|
||||
struct em28xx_fh *fh = priv;
|
||||
|
|
@ -1413,20 +1710,25 @@ static int vidioc_streamon(struct file *file, void *priv,
|
|||
{
|
||||
struct em28xx_fh *fh = priv;
|
||||
struct em28xx *dev = fh->dev;
|
||||
int rc;
|
||||
int rc = -EINVAL;
|
||||
|
||||
rc = check_dev(dev);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (unlikely(type != fh->type))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&dev->lock);
|
||||
rc = res_get(fh);
|
||||
em28xx_videodbg("vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
|
||||
fh, type, fh->resources, dev->resources);
|
||||
|
||||
if (likely(rc >= 0))
|
||||
if (unlikely(!res_get(fh, get_ressource(fh))))
|
||||
return -EBUSY;
|
||||
|
||||
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
rc = videobuf_streamon(&fh->vb_vidq);
|
||||
|
||||
mutex_unlock(&dev->lock);
|
||||
else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
|
||||
rc = videobuf_streamon(&fh->vb_vbiq);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -1442,17 +1744,22 @@ static int vidioc_streamoff(struct file *file, void *priv,
|
|||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
|
||||
fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
|
||||
return -EINVAL;
|
||||
if (type != fh->type)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&dev->lock);
|
||||
em28xx_videodbg("vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
|
||||
fh, type, fh->resources, dev->resources);
|
||||
|
||||
videobuf_streamoff(&fh->vb_vidq);
|
||||
res_free(fh);
|
||||
|
||||
mutex_unlock(&dev->lock);
|
||||
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
|
||||
videobuf_streamoff(&fh->vb_vidq);
|
||||
res_free(fh, EM28XX_RESOURCE_VIDEO);
|
||||
} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
|
||||
videobuf_streamoff(&fh->vb_vbiq);
|
||||
res_free(fh, EM28XX_RESOURCE_VBI);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1474,6 +1781,9 @@ static int vidioc_querycap(struct file *file, void *priv,
|
|||
V4L2_CAP_VIDEO_CAPTURE |
|
||||
V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
|
||||
|
||||
if (dev->vbi_dev)
|
||||
cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
|
||||
|
||||
if (dev->audio_mode.has_audio)
|
||||
cap->capabilities |= V4L2_CAP_AUDIO;
|
||||
|
||||
|
|
@ -1541,6 +1851,45 @@ static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* RAW VBI ioctls */
|
||||
|
||||
static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
|
||||
struct v4l2_format *format)
|
||||
{
|
||||
format->fmt.vbi.samples_per_line = 720;
|
||||
format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
|
||||
format->fmt.vbi.offset = 0;
|
||||
format->fmt.vbi.flags = 0;
|
||||
|
||||
/* Varies by video standard (NTSC, PAL, etc.) */
|
||||
/* FIXME: hard-coded for NTSC support */
|
||||
format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; /* FIXME: ??? */
|
||||
format->fmt.vbi.count[0] = 12;
|
||||
format->fmt.vbi.count[1] = 12;
|
||||
format->fmt.vbi.start[0] = 10;
|
||||
format->fmt.vbi.start[1] = 273;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
|
||||
struct v4l2_format *format)
|
||||
{
|
||||
format->fmt.vbi.samples_per_line = 720;
|
||||
format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
|
||||
format->fmt.vbi.offset = 0;
|
||||
format->fmt.vbi.flags = 0;
|
||||
|
||||
/* Varies by video standard (NTSC, PAL, etc.) */
|
||||
/* FIXME: hard-coded for NTSC support */
|
||||
format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; /* FIXME: ??? */
|
||||
format->fmt.vbi.count[0] = 12;
|
||||
format->fmt.vbi.count[1] = 12;
|
||||
format->fmt.vbi.start[0] = 10;
|
||||
format->fmt.vbi.start[1] = 273;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_reqbufs(struct file *file, void *priv,
|
||||
struct v4l2_requestbuffers *rb)
|
||||
|
|
@ -1553,7 +1902,10 @@ static int vidioc_reqbufs(struct file *file, void *priv,
|
|||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
return videobuf_reqbufs(&fh->vb_vidq, rb);
|
||||
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return videobuf_reqbufs(&fh->vb_vidq, rb);
|
||||
else
|
||||
return videobuf_reqbufs(&fh->vb_vbiq, rb);
|
||||
}
|
||||
|
||||
static int vidioc_querybuf(struct file *file, void *priv,
|
||||
|
|
@ -1567,7 +1919,18 @@ static int vidioc_querybuf(struct file *file, void *priv,
|
|||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
return videobuf_querybuf(&fh->vb_vidq, b);
|
||||
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return videobuf_querybuf(&fh->vb_vidq, b);
|
||||
else {
|
||||
/* FIXME: I'm not sure yet whether this is a bug in zvbi or
|
||||
the videobuf framework, but we probably shouldn't be
|
||||
returning a buffer larger than that which was asked for.
|
||||
At a minimum, it causes a crash in zvbi since it does
|
||||
a memcpy based on the source buffer length */
|
||||
int result = videobuf_querybuf(&fh->vb_vbiq, b);
|
||||
b->length = 17280;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
|
||||
|
|
@ -1580,7 +1943,10 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
|
|||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
return videobuf_qbuf(&fh->vb_vidq, b);
|
||||
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return videobuf_qbuf(&fh->vb_vidq, b);
|
||||
else
|
||||
return videobuf_qbuf(&fh->vb_vbiq, b);
|
||||
}
|
||||
|
||||
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
|
||||
|
|
@ -1593,7 +1959,12 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
|
|||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
|
||||
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags &
|
||||
O_NONBLOCK);
|
||||
else
|
||||
return videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags &
|
||||
O_NONBLOCK);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VIDEO_V4L1_COMPAT
|
||||
|
|
@ -1601,7 +1972,10 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
|
|||
{
|
||||
struct em28xx_fh *fh = priv;
|
||||
|
||||
return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
|
||||
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
|
||||
else
|
||||
return videobuf_cgmbuf(&fh->vb_vbiq, mbuf, 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -1766,8 +2140,15 @@ static int em28xx_v4l2_open(struct file *filp)
|
|||
field = V4L2_FIELD_INTERLACED;
|
||||
|
||||
videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
|
||||
NULL, &dev->slock, fh->type, field,
|
||||
sizeof(struct em28xx_buffer), fh);
|
||||
NULL, &dev->slock,
|
||||
V4L2_BUF_TYPE_VIDEO_CAPTURE, field,
|
||||
sizeof(struct em28xx_buffer), fh);
|
||||
|
||||
videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops,
|
||||
NULL, &dev->slock,
|
||||
V4L2_BUF_TYPE_VBI_CAPTURE,
|
||||
V4L2_FIELD_SEQ_TB,
|
||||
sizeof(struct em28xx_buffer), fh);
|
||||
|
||||
mutex_unlock(&dev->lock);
|
||||
|
||||
|
|
@ -1824,20 +2205,21 @@ static int em28xx_v4l2_close(struct file *filp)
|
|||
|
||||
em28xx_videodbg("users=%d\n", dev->users);
|
||||
|
||||
if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
|
||||
videobuf_stop(&fh->vb_vidq);
|
||||
res_free(fh, EM28XX_RESOURCE_VIDEO);
|
||||
}
|
||||
|
||||
mutex_lock(&dev->lock);
|
||||
if (res_check(fh))
|
||||
res_free(fh);
|
||||
if (res_check(fh, EM28XX_RESOURCE_VBI)) {
|
||||
videobuf_stop(&fh->vb_vbiq);
|
||||
res_free(fh, EM28XX_RESOURCE_VBI);
|
||||
}
|
||||
|
||||
if (dev->users == 1) {
|
||||
videobuf_stop(&fh->vb_vidq);
|
||||
videobuf_mmap_free(&fh->vb_vidq);
|
||||
|
||||
/* the device is already disconnect,
|
||||
free the remaining resources */
|
||||
if (dev->state & DEV_DISCONNECTED) {
|
||||
em28xx_release_resources(dev);
|
||||
mutex_unlock(&dev->lock);
|
||||
kfree(dev);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1858,10 +2240,12 @@ static int em28xx_v4l2_close(struct file *filp)
|
|||
"0 (error=%i)\n", errCode);
|
||||
}
|
||||
}
|
||||
|
||||
videobuf_mmap_free(&fh->vb_vidq);
|
||||
videobuf_mmap_free(&fh->vb_vbiq);
|
||||
kfree(fh);
|
||||
dev->users--;
|
||||
wake_up_interruptible_nr(&dev->open, 1);
|
||||
mutex_unlock(&dev->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1886,16 +2270,22 @@ em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
|
|||
*/
|
||||
|
||||
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
|
||||
mutex_lock(&dev->lock);
|
||||
rc = res_get(fh);
|
||||
mutex_unlock(&dev->lock);
|
||||
|
||||
if (unlikely(rc < 0))
|
||||
return rc;
|
||||
if (res_locked(dev, EM28XX_RESOURCE_VIDEO))
|
||||
return -EBUSY;
|
||||
|
||||
return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
|
||||
filp->f_flags & O_NONBLOCK);
|
||||
}
|
||||
|
||||
|
||||
if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
|
||||
if (!res_get(fh, EM28XX_RESOURCE_VBI))
|
||||
return -EBUSY;
|
||||
|
||||
return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
|
||||
filp->f_flags & O_NONBLOCK);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1913,17 +2303,17 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait)
|
|||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
mutex_lock(&dev->lock);
|
||||
rc = res_get(fh);
|
||||
mutex_unlock(&dev->lock);
|
||||
|
||||
if (unlikely(rc < 0))
|
||||
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
|
||||
if (!res_get(fh, EM28XX_RESOURCE_VIDEO))
|
||||
return POLLERR;
|
||||
return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
|
||||
} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
|
||||
if (!res_get(fh, EM28XX_RESOURCE_VBI))
|
||||
return POLLERR;
|
||||
return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
|
||||
} else {
|
||||
return POLLERR;
|
||||
|
||||
if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
|
||||
return POLLERR;
|
||||
|
||||
return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1939,14 +2329,10 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
mutex_lock(&dev->lock);
|
||||
rc = res_get(fh);
|
||||
mutex_unlock(&dev->lock);
|
||||
|
||||
if (unlikely(rc < 0))
|
||||
return rc;
|
||||
|
||||
rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
|
||||
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
|
||||
else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
|
||||
rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
|
||||
|
||||
em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
|
||||
(unsigned long)vma->vm_start,
|
||||
|
|
@ -1972,6 +2358,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
|
|||
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
|
||||
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
|
||||
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
|
||||
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
|
||||
.vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
|
||||
.vidioc_g_audio = vidioc_g_audio,
|
||||
.vidioc_s_audio = vidioc_s_audio,
|
||||
.vidioc_cropcap = vidioc_cropcap,
|
||||
|
|
@ -1984,6 +2372,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
|
|||
.vidioc_querybuf = vidioc_querybuf,
|
||||
.vidioc_qbuf = vidioc_qbuf,
|
||||
.vidioc_dqbuf = vidioc_dqbuf,
|
||||
.vidioc_g_std = vidioc_g_std,
|
||||
.vidioc_s_std = vidioc_s_std,
|
||||
.vidioc_g_parm = vidioc_g_parm,
|
||||
.vidioc_s_parm = vidioc_s_parm,
|
||||
|
|
@ -2105,13 +2494,10 @@ int em28xx_register_analog_devices(struct em28xx *dev)
|
|||
dev->mute = 1;
|
||||
dev->volume = 0x1f;
|
||||
|
||||
/* enable vbi capturing */
|
||||
|
||||
/* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */
|
||||
val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK);
|
||||
em28xx_write_reg(dev, EM28XX_R0F_XCLK,
|
||||
(EM28XX_XCLK_AUDIO_UNMUTE | val));
|
||||
em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51);
|
||||
|
||||
em28xx_set_outfmt(dev);
|
||||
em28xx_colorlevels_set_default(dev);
|
||||
|
|
@ -2134,14 +2520,17 @@ int em28xx_register_analog_devices(struct em28xx *dev)
|
|||
}
|
||||
|
||||
/* Allocate and fill vbi video_device struct */
|
||||
dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, "vbi");
|
||||
if (em28xx_vbi_supported(dev) == 1) {
|
||||
dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
|
||||
"vbi");
|
||||
|
||||
/* register v4l2 vbi video_device */
|
||||
ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
|
||||
vbi_nr[dev->devno]);
|
||||
if (ret < 0) {
|
||||
em28xx_errdev("unable to register vbi device\n");
|
||||
return ret;
|
||||
/* register v4l2 vbi video_device */
|
||||
ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
|
||||
vbi_nr[dev->devno]);
|
||||
if (ret < 0) {
|
||||
em28xx_errdev("unable to register vbi device\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
|
||||
|
|
@ -2161,8 +2550,12 @@ int em28xx_register_analog_devices(struct em28xx *dev)
|
|||
dev->radio_dev->num);
|
||||
}
|
||||
|
||||
em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n",
|
||||
dev->vdev->num, dev->vbi_dev->num);
|
||||
em28xx_info("V4L2 video device registered as /dev/video%d\n",
|
||||
dev->vdev->num);
|
||||
|
||||
if (dev->vbi_dev)
|
||||
em28xx_info("V4L2 VBI device registered as /dev/vbi%d\n",
|
||||
dev->vbi_dev->num);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@
|
|||
#define EM2882_BOARD_EVGA_INDTUBE 70
|
||||
#define EM2820_BOARD_SILVERCREST_WEBCAM 71
|
||||
#define EM2861_BOARD_GADMEI_UTV330PLUS 72
|
||||
#define EM2870_BOARD_REDDO_DVB_C_USB_BOX 73
|
||||
|
||||
/* Limits minimum and default number of buffers */
|
||||
#define EM28XX_MIN_BUF 4
|
||||
|
|
@ -214,7 +215,8 @@ struct em28xx_usb_isoc_ctl {
|
|||
int tmp_buf_len;
|
||||
|
||||
/* Stores already requested buffers */
|
||||
struct em28xx_buffer *buf;
|
||||
struct em28xx_buffer *vid_buf;
|
||||
struct em28xx_buffer *vbi_buf;
|
||||
|
||||
/* Stores the number of received fields */
|
||||
int nfields;
|
||||
|
|
@ -443,6 +445,10 @@ enum em28xx_dev_state {
|
|||
#define EM28XX_AUDIO 0x10
|
||||
#define EM28XX_DVB 0x20
|
||||
|
||||
/* em28xx resource types (used for res_get/res_lock etc */
|
||||
#define EM28XX_RESOURCE_VIDEO 0x01
|
||||
#define EM28XX_RESOURCE_VBI 0x02
|
||||
|
||||
struct em28xx_audio {
|
||||
char name[50];
|
||||
char *transfer_buffer[EM28XX_AUDIO_BUFS];
|
||||
|
|
@ -463,10 +469,11 @@ struct em28xx;
|
|||
|
||||
struct em28xx_fh {
|
||||
struct em28xx *dev;
|
||||
unsigned int stream_on:1; /* Locks streams */
|
||||
int radio;
|
||||
unsigned int resources;
|
||||
|
||||
struct videobuf_queue vb_vidq;
|
||||
struct videobuf_queue vb_vbiq;
|
||||
|
||||
enum v4l2_buf_type type;
|
||||
};
|
||||
|
|
@ -493,7 +500,6 @@ struct em28xx {
|
|||
/* Vinmode/Vinctl used at the driver */
|
||||
int vinmode, vinctl;
|
||||
|
||||
unsigned int stream_on:1; /* Locks streams */
|
||||
unsigned int has_audio_class:1;
|
||||
unsigned int has_alsa_audio:1;
|
||||
|
||||
|
|
@ -544,6 +550,12 @@ struct em28xx {
|
|||
enum em28xx_dev_state state;
|
||||
enum em28xx_io_method io;
|
||||
|
||||
/* vbi related state tracking */
|
||||
int capture_type;
|
||||
int vbi_read;
|
||||
unsigned char cur_field;
|
||||
|
||||
|
||||
struct work_struct request_module_wk;
|
||||
|
||||
/* locks */
|
||||
|
|
@ -555,10 +567,14 @@ struct em28xx {
|
|||
struct video_device *vbi_dev;
|
||||
struct video_device *radio_dev;
|
||||
|
||||
/* resources in use */
|
||||
unsigned int resources;
|
||||
|
||||
unsigned char eedata[256];
|
||||
|
||||
/* Isoc control struct */
|
||||
struct em28xx_dmaqueue vidq;
|
||||
struct em28xx_dmaqueue vbiq;
|
||||
struct em28xx_usb_isoc_ctl isoc_ctl;
|
||||
spinlock_t slock;
|
||||
|
||||
|
|
@ -639,6 +655,7 @@ int em28xx_audio_setup(struct em28xx *dev);
|
|||
|
||||
int em28xx_colorlevels_set_default(struct em28xx *dev);
|
||||
int em28xx_capture_start(struct em28xx *dev, int start);
|
||||
int em28xx_vbi_supported(struct em28xx *dev);
|
||||
int em28xx_set_outfmt(struct em28xx *dev);
|
||||
int em28xx_resolution_set(struct em28xx *dev);
|
||||
int em28xx_set_alternate(struct em28xx *dev);
|
||||
|
|
@ -686,6 +703,9 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev);
|
|||
int em28xx_ir_init(struct em28xx *dev);
|
||||
int em28xx_ir_fini(struct em28xx *dev);
|
||||
|
||||
/* Provided by em28xx-vbi.c */
|
||||
extern struct videobuf_queue_ops em28xx_vbi_qops;
|
||||
|
||||
/* printk macros */
|
||||
|
||||
#define em28xx_err(fmt, arg...) do {\
|
||||
|
|
|
|||
|
|
@ -1379,8 +1379,10 @@ et61x251_read(struct file* filp, char __user * buf,
|
|||
(!list_empty(&cam->outqueue)) ||
|
||||
(cam->state & DEV_DISCONNECTED) ||
|
||||
(cam->state & DEV_MISCONFIGURED),
|
||||
cam->module_param.frame_timeout *
|
||||
1000 * msecs_to_jiffies(1) );
|
||||
msecs_to_jiffies(
|
||||
cam->module_param.frame_timeout * 1000
|
||||
)
|
||||
);
|
||||
if (timeout < 0) {
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return timeout;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ if USB_GSPCA && VIDEO_V4L2
|
|||
|
||||
source "drivers/media/video/gspca/m5602/Kconfig"
|
||||
source "drivers/media/video/gspca/stv06xx/Kconfig"
|
||||
source "drivers/media/video/gspca/gl860/Kconfig"
|
||||
|
||||
config USB_GSPCA_CONEX
|
||||
tristate "Conexant Camera Driver"
|
||||
|
|
|
|||
|
|
@ -58,3 +58,4 @@ gspca_zc3xx-objs := zc3xx.o
|
|||
|
||||
obj-$(CONFIG_USB_M5602) += m5602/
|
||||
obj-$(CONFIG_USB_STV06XX) += stv06xx/
|
||||
obj-$(CONFIG_USB_GL860) += gl860/
|
||||
|
|
|
|||
8
drivers/media/video/gspca/gl860/Kconfig
Normal file
8
drivers/media/video/gspca/gl860/Kconfig
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
config USB_GL860
|
||||
tristate "GL860 USB Camera Driver"
|
||||
depends on VIDEO_V4L2 && USB_GSPCA
|
||||
help
|
||||
Say Y here if you want support for cameras based on the GL860 chip.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called gspca_gl860.
|
||||
10
drivers/media/video/gspca/gl860/Makefile
Normal file
10
drivers/media/video/gspca/gl860/Makefile
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
obj-$(CONFIG_USB_GL860) += gspca_gl860.o
|
||||
|
||||
gspca_gl860-objs := gl860.o \
|
||||
gl860-mi1320.o \
|
||||
gl860-ov2640.o \
|
||||
gl860-ov9655.o \
|
||||
gl860-mi2020.o
|
||||
|
||||
EXTRA_CFLAGS += -Idrivers/media/video/gspca
|
||||
|
||||
537
drivers/media/video/gspca/gl860/gl860-mi1320.c
Normal file
537
drivers/media/video/gspca/gl860/gl860-mi1320.c
Normal file
|
|
@ -0,0 +1,537 @@
|
|||
/* @file gl860-mi1320.c
|
||||
* @author Olivier LORIN from my logs
|
||||
* @date 2009-08-27
|
||||
*
|
||||
* 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
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Sensor : MI1320 */
|
||||
|
||||
#include "gl860.h"
|
||||
|
||||
static struct validx tbl_common[] = {
|
||||
{0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba51, 0x0066}, {0xba02, 0x00f1},
|
||||
{0xba05, 0x0067}, {0xba05, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1},
|
||||
{0xffff, 0xffff},
|
||||
{0xba00, 0x00f0}, {0xba02, 0x00f1}, {0xbafa, 0x0028}, {0xba02, 0x00f1},
|
||||
{0xba00, 0x00f0}, {0xba01, 0x00f1}, {0xbaf0, 0x0006}, {0xba0e, 0x00f1},
|
||||
{0xba70, 0x0006}, {0xba0e, 0x00f1},
|
||||
{0xffff, 0xffff},
|
||||
{0xba74, 0x0006}, {0xba0e, 0x00f1},
|
||||
{0xffff, 0xffff},
|
||||
{0x0061, 0x0000}, {0x0068, 0x000d},
|
||||
};
|
||||
|
||||
static struct validx tbl_init_at_startup[] = {
|
||||
{0x0000, 0x0000}, {0x0010, 0x0010},
|
||||
{35, 0xffff},
|
||||
{0x0008, 0x00c0}, {0x0001, 0x00c1}, {0x0001, 0x00c2}, {0x0020, 0x0006},
|
||||
{0x006a, 0x000d},
|
||||
};
|
||||
|
||||
static struct validx tbl_sensor_settings_common[] = {
|
||||
{0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, {0x0040, 0x0000},
|
||||
{0x006a, 0x0007}, {0x006a, 0x000d}, {0x0063, 0x0006},
|
||||
};
|
||||
static struct validx tbl_sensor_settings_1280[] = {
|
||||
{0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba5a, 0x0066}, {0xba02, 0x00f1},
|
||||
{0xba05, 0x0067}, {0xba05, 0x00f1}, {0xba20, 0x0065}, {0xba00, 0x00f1},
|
||||
};
|
||||
static struct validx tbl_sensor_settings_800[] = {
|
||||
{0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba5a, 0x0066}, {0xba02, 0x00f1},
|
||||
{0xba05, 0x0067}, {0xba05, 0x00f1}, {0xba20, 0x0065}, {0xba00, 0x00f1},
|
||||
};
|
||||
static struct validx tbl_sensor_settings_640[] = {
|
||||
{0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1},
|
||||
{0xba51, 0x0066}, {0xba02, 0x00f1}, {0xba05, 0x0067}, {0xba05, 0x00f1},
|
||||
{0xba20, 0x0065}, {0xba00, 0x00f1},
|
||||
};
|
||||
static struct validx tbl_post_unset_alt[] = {
|
||||
{0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1},
|
||||
{0x0061, 0x0000}, {0x0068, 0x000d},
|
||||
};
|
||||
|
||||
static u8 *tbl_1280[] = {
|
||||
"\x0d\x80\xf1\x08\x03\x04\xf1\x00" "\x04\x05\xf1\x02\x05\x00\xf1\xf1"
|
||||
"\x06\x00\xf1\x0d\x20\x01\xf1\x00" "\x21\x84\xf1\x00\x0d\x00\xf1\x08"
|
||||
"\xf0\x00\xf1\x01\x34\x00\xf1\x00" "\x9b\x43\xf1\x00\xa6\x05\xf1\x00"
|
||||
"\xa9\x04\xf1\x00\xa1\x05\xf1\x00" "\xa4\x04\xf1\x00\xae\x0a\xf1\x08"
|
||||
,
|
||||
"\xf0\x00\xf1\x02\x3a\x05\xf1\xf1" "\x3c\x05\xf1\xf1\x59\x01\xf1\x47"
|
||||
"\x5a\x01\xf1\x88\x5c\x0a\xf1\x06" "\x5d\x0e\xf1\x0a\x64\x5e\xf1\x1c"
|
||||
"\xd2\x00\xf1\xcf\xcb\x00\xf1\x01"
|
||||
,
|
||||
"\xd3\x02\xd4\x28\xd5\x01\xd0\x02" "\xd1\x18\xd2\xc1"
|
||||
};
|
||||
|
||||
static u8 *tbl_800[] = {
|
||||
"\x0d\x80\xf1\x08\x03\x03\xf1\xc0" "\x04\x05\xf1\x02\x05\x00\xf1\xf1"
|
||||
"\x06\x00\xf1\x0d\x20\x01\xf1\x00" "\x21\x84\xf1\x00\x0d\x00\xf1\x08"
|
||||
"\xf0\x00\xf1\x01\x34\x00\xf1\x00" "\x9b\x43\xf1\x00\xa6\x05\xf1\x00"
|
||||
"\xa9\x03\xf1\xc0\xa1\x03\xf1\x20" "\xa4\x02\xf1\x5a\xae\x0a\xf1\x08"
|
||||
,
|
||||
"\xf0\x00\xf1\x02\x3a\x05\xf1\xf1" "\x3c\x05\xf1\xf1\x59\x01\xf1\x47"
|
||||
"\x5a\x01\xf1\x88\x5c\x0a\xf1\x06" "\x5d\x0e\xf1\x0a\x64\x5e\xf1\x1c"
|
||||
"\xd2\x00\xf1\xcf\xcb\x00\xf1\x01"
|
||||
,
|
||||
"\xd3\x02\xd4\x18\xd5\x21\xd0\x02" "\xd1\x10\xd2\x59"
|
||||
};
|
||||
|
||||
static u8 *tbl_640[] = {
|
||||
"\x0d\x80\xf1\x08\x03\x04\xf1\x04" "\x04\x05\xf1\x02\x07\x01\xf1\x7c"
|
||||
"\x08\x00\xf1\x0e\x21\x80\xf1\x00" "\x0d\x00\xf1\x08\xf0\x00\xf1\x01"
|
||||
"\x34\x10\xf1\x10\x3a\x43\xf1\x00" "\xa6\x05\xf1\x02\xa9\x04\xf1\x04"
|
||||
"\xa7\x02\xf1\x81\xaa\x01\xf1\xe2" "\xae\x0c\xf1\x09"
|
||||
,
|
||||
"\xf0\x00\xf1\x02\x39\x03\xf1\xfc" "\x3b\x04\xf1\x04\x57\x01\xf1\xb6"
|
||||
"\x58\x02\xf1\x0d\x5c\x1f\xf1\x19" "\x5d\x24\xf1\x1e\x64\x5e\xf1\x1c"
|
||||
"\xd2\x00\xf1\x00\xcb\x00\xf1\x01"
|
||||
,
|
||||
"\xd3\x02\xd4\x10\xd5\x81\xd0\x02" "\xd1\x08\xd2\xe1"
|
||||
};
|
||||
|
||||
static s32 tbl_sat[] = {0x25, 0x1d, 0x15, 0x0d, 0x05, 0x4d, 0x55, 0x5d, 0x2d};
|
||||
static s32 tbl_bright[] = {0, 8, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70};
|
||||
static s32 tbl_backlight[] = {0x0e, 0x06, 0x02};
|
||||
|
||||
static s32 tbl_cntr1[] = {
|
||||
0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0, 0xc8, 0xd0, 0xe0, 0xf0};
|
||||
static s32 tbl_cntr2[] = {
|
||||
0x70, 0x68, 0x60, 0x58, 0x50, 0x48, 0x40, 0x38, 0x30, 0x20, 0x10};
|
||||
|
||||
static u8 dat_wbalNL[] =
|
||||
"\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x3b\x04\xf1\x2a\x47\x10\xf1\x10"
|
||||
"\x9d\x3c\xf1\xae\xaf\x10\xf1\x00" "\xf0\x00\xf1\x02\x2f\x91\xf1\x20"
|
||||
"\x9c\x91\xf1\x20\x37\x03\xf1\x00" "\x9d\xc5\xf1\x0f\xf0\x00\xf1\x00";
|
||||
|
||||
static u8 dat_wbalLL[] =
|
||||
"\xf0\x00\xf1\x01\x05\x00\xf1\x0c" "\x3b\x04\xf1\x2a\x47\x40\xf1\x40"
|
||||
"\x9d\x20\xf1\xae\xaf\x10\xf1\x00" "\xf0\x00\xf1\x02\x2f\xd1\xf1\x00"
|
||||
"\x9c\xd1\xf1\x00\x37\x03\xf1\x00" "\x9d\xc5\xf1\x3f\xf0\x00\xf1\x00";
|
||||
|
||||
static u8 dat_wbalBL[] =
|
||||
"\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x47\x10\xf1\x30\x9d\x3c\xf1\xae"
|
||||
"\xaf\x10\xf1\x00\xf0\x00\xf1\x02" "\x2f\x91\xf1\x20\x9c\x91\xf1\x20"
|
||||
"\x37\x03\xf1\x00\x9d\xc5\xf1\x2f" "\xf0\x00\xf1\x00";
|
||||
|
||||
static u8 dat_hvflip1[] = {0xf0, 0x00, 0xf1, 0x00};
|
||||
|
||||
static u8 s000[] =
|
||||
"\x00\x01\x07\x6a\x06\x63\x0d\x6a" "\xc0\x00\x10\x10\xc1\x03\xc2\x42"
|
||||
"\xd8\x04\x58\x00\x04\x02";
|
||||
static u8 s001[] =
|
||||
"\x0d\x00\xf1\x0b\x0d\x00\xf1\x08" "\x35\x00\xf1\x22\x68\x00\xf1\x5d"
|
||||
"\xf0\x00\xf1\x01\x06\x70\xf1\x0e" "\xf0\x00\xf1\x02\xdd\x18\xf1\xe0";
|
||||
static u8 s002[] =
|
||||
"\x05\x01\xf1\x84\x06\x00\xf1\x44" "\x07\x00\xf1\xbe\x08\x00\xf1\x1e"
|
||||
"\x20\x01\xf1\x03\x21\x84\xf1\x00" "\x22\x0d\xf1\x0f\x24\x80\xf1\x00"
|
||||
"\x34\x18\xf1\x2d\x35\x00\xf1\x22" "\x43\x83\xf1\x83\x59\x00\xf1\xff";
|
||||
static u8 s003[] =
|
||||
"\xf0\x00\xf1\x02\x39\x06\xf1\x8c" "\x3a\x06\xf1\x8c\x3b\x03\xf1\xda"
|
||||
"\x3c\x05\xf1\x30\x57\x01\xf1\x0c" "\x58\x01\xf1\x42\x59\x01\xf1\x0c"
|
||||
"\x5a\x01\xf1\x42\x5c\x13\xf1\x0e" "\x5d\x17\xf1\x12\x64\x1e\xf1\x1c";
|
||||
static u8 s004[] =
|
||||
"\xf0\x00\xf1\x02\x24\x5f\xf1\x20" "\x28\xea\xf1\x02\x5f\x41\xf1\x43";
|
||||
static u8 s005[] =
|
||||
"\x02\x00\xf1\xee\x03\x29\xf1\x1a" "\x04\x02\xf1\xa4\x09\x00\xf1\x68"
|
||||
"\x0a\x00\xf1\x2a\x0b\x00\xf1\x04" "\x0c\x00\xf1\x93\x0d\x00\xf1\x82"
|
||||
"\x0e\x00\xf1\x40\x0f\x00\xf1\x5f" "\x10\x00\xf1\x4e\x11\x00\xf1\x5b";
|
||||
static u8 s006[] =
|
||||
"\x15\x00\xf1\xc9\x16\x00\xf1\x5e" "\x17\x00\xf1\x9d\x18\x00\xf1\x06"
|
||||
"\x19\x00\xf1\x89\x1a\x00\xf1\x12" "\x1b\x00\xf1\xa1\x1c\x00\xf1\xe4"
|
||||
"\x1d\x00\xf1\x7a\x1e\x00\xf1\x64" "\xf6\x00\xf1\x5f";
|
||||
static u8 s007[] =
|
||||
"\xf0\x00\xf1\x01\x53\x09\xf1\x03" "\x54\x3d\xf1\x1c\x55\x99\xf1\x72"
|
||||
"\x56\xc1\xf1\xb1\x57\xd8\xf1\xce" "\x58\xe0\xf1\x00\xdc\x0a\xf1\x03"
|
||||
"\xdd\x45\xf1\x20\xde\xae\xf1\x82" "\xdf\xdc\xf1\xc9\xe0\xf6\xf1\xea"
|
||||
"\xe1\xff\xf1\x00";
|
||||
static u8 s008[] =
|
||||
"\xf0\x00\xf1\x01\x80\x00\xf1\x06" "\x81\xf6\xf1\x08\x82\xfb\xf1\xf7"
|
||||
"\x83\x00\xf1\xfe\xb6\x07\xf1\x03" "\xb7\x18\xf1\x0c\x84\xfb\xf1\x06"
|
||||
"\x85\xfb\xf1\xf9\x86\x00\xf1\xff" "\xb8\x07\xf1\x04\xb9\x16\xf1\x0a";
|
||||
static u8 s009[] =
|
||||
"\x87\xfa\xf1\x05\x88\xfc\xf1\xf9" "\x89\x00\xf1\xff\xba\x06\xf1\x03"
|
||||
"\xbb\x17\xf1\x09\x8a\xe8\xf1\x14" "\x8b\xf7\xf1\xf0\x8c\xfd\xf1\xfa"
|
||||
"\x8d\x00\xf1\x00\xbc\x05\xf1\x01" "\xbd\x0c\xf1\x08\xbe\x00\xf1\x14";
|
||||
static u8 s010[] =
|
||||
"\x8e\xea\xf1\x13\x8f\xf7\xf1\xf2" "\x90\xfd\xf1\xfa\x91\x00\xf1\x00"
|
||||
"\xbf\x05\xf1\x01\xc0\x0a\xf1\x08" "\xc1\x00\xf1\x0c\x92\xed\xf1\x0f"
|
||||
"\x93\xf9\xf1\xf4\x94\xfe\xf1\xfb" "\x95\x00\xf1\x00\xc2\x04\xf1\x01"
|
||||
"\xc3\x0a\xf1\x07\xc4\x00\xf1\x10";
|
||||
static u8 s011[] =
|
||||
"\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x25\x00\xf1\x55\x34\x10\xf1\x10"
|
||||
"\x35\xf0\xf1\x10\x3a\x02\xf1\x03" "\x3b\x04\xf1\x2a\x9b\x43\xf1\x00"
|
||||
"\xa4\x03\xf1\xc0\xa7\x02\xf1\x81";
|
||||
|
||||
static int mi1320_init_at_startup(struct gspca_dev *gspca_dev);
|
||||
static int mi1320_configure_alt(struct gspca_dev *gspca_dev);
|
||||
static int mi1320_init_pre_alt(struct gspca_dev *gspca_dev);
|
||||
static int mi1320_init_post_alt(struct gspca_dev *gspca_dev);
|
||||
static void mi1320_post_unset_alt(struct gspca_dev *gspca_dev);
|
||||
static int mi1320_sensor_settings(struct gspca_dev *gspca_dev);
|
||||
static int mi1320_camera_settings(struct gspca_dev *gspca_dev);
|
||||
/*==========================================================================*/
|
||||
|
||||
void mi1320_init_settings(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
sd->vcur.backlight = 0;
|
||||
sd->vcur.brightness = 0;
|
||||
sd->vcur.sharpness = 6;
|
||||
sd->vcur.contrast = 10;
|
||||
sd->vcur.gamma = 20;
|
||||
sd->vcur.hue = 0;
|
||||
sd->vcur.saturation = 6;
|
||||
sd->vcur.whitebal = 0;
|
||||
sd->vcur.mirror = 0;
|
||||
sd->vcur.flip = 0;
|
||||
sd->vcur.AC50Hz = 1;
|
||||
|
||||
sd->vmax.backlight = 2;
|
||||
sd->vmax.brightness = 8;
|
||||
sd->vmax.sharpness = 7;
|
||||
sd->vmax.contrast = 0; /* 10 but not working with tihs driver */
|
||||
sd->vmax.gamma = 40;
|
||||
sd->vmax.hue = 5 + 1;
|
||||
sd->vmax.saturation = 8;
|
||||
sd->vmax.whitebal = 2;
|
||||
sd->vmax.mirror = 1;
|
||||
sd->vmax.flip = 1;
|
||||
sd->vmax.AC50Hz = 1;
|
||||
|
||||
sd->dev_camera_settings = mi1320_camera_settings;
|
||||
sd->dev_init_at_startup = mi1320_init_at_startup;
|
||||
sd->dev_configure_alt = mi1320_configure_alt;
|
||||
sd->dev_init_pre_alt = mi1320_init_pre_alt;
|
||||
sd->dev_post_unset_alt = mi1320_post_unset_alt;
|
||||
}
|
||||
|
||||
/*==========================================================================*/
|
||||
|
||||
static void common(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
s32 n; /* reserved for FETCH macros */
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 22, s000);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 32, s001);
|
||||
n = fetch_validx(gspca_dev, tbl_common, ARRAY_SIZE(tbl_common));
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, s002);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, s003);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 16, s004);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, s005);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 44, s006);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_common,
|
||||
ARRAY_SIZE(tbl_common), n);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 52, s007);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, s008);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, s009);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 56, s010);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_common,
|
||||
ARRAY_SIZE(tbl_common), n);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, s011);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_common,
|
||||
ARRAY_SIZE(tbl_common), n);
|
||||
}
|
||||
|
||||
static int mi1320_init_at_startup(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
fetch_validx(gspca_dev, tbl_init_at_startup,
|
||||
ARRAY_SIZE(tbl_init_at_startup));
|
||||
|
||||
common(gspca_dev);
|
||||
|
||||
/* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mi1320_init_pre_alt(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
sd->mirrorMask = 0;
|
||||
|
||||
sd->vold.backlight = -1;
|
||||
sd->vold.brightness = -1;
|
||||
sd->vold.sharpness = -1;
|
||||
sd->vold.contrast = -1;
|
||||
sd->vold.saturation = -1;
|
||||
sd->vold.gamma = -1;
|
||||
sd->vold.hue = -1;
|
||||
sd->vold.whitebal = -1;
|
||||
sd->vold.mirror = -1;
|
||||
sd->vold.flip = -1;
|
||||
sd->vold.AC50Hz = -1;
|
||||
|
||||
common(gspca_dev);
|
||||
|
||||
mi1320_sensor_settings(gspca_dev);
|
||||
|
||||
mi1320_init_post_alt(gspca_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mi1320_init_post_alt(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
mi1320_camera_settings(gspca_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mi1320_sensor_settings(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
|
||||
|
||||
fetch_validx(gspca_dev, tbl_sensor_settings_common,
|
||||
ARRAY_SIZE(tbl_sensor_settings_common));
|
||||
|
||||
switch (reso) {
|
||||
case IMAGE_1280:
|
||||
fetch_validx(gspca_dev, tbl_sensor_settings_1280,
|
||||
ARRAY_SIZE(tbl_sensor_settings_1280));
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 64, tbl_1280[0]);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_1280[1]);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_1280[2]);
|
||||
break;
|
||||
|
||||
case IMAGE_800:
|
||||
fetch_validx(gspca_dev, tbl_sensor_settings_800,
|
||||
ARRAY_SIZE(tbl_sensor_settings_800));
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 64, tbl_800[0]);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_800[1]);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_800[2]);
|
||||
break;
|
||||
|
||||
default:
|
||||
fetch_validx(gspca_dev, tbl_sensor_settings_640,
|
||||
ARRAY_SIZE(tbl_sensor_settings_640));
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 60, tbl_640[0]);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_640[1]);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_640[2]);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mi1320_configure_alt(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
|
||||
|
||||
switch (reso) {
|
||||
case IMAGE_640:
|
||||
gspca_dev->alt = 3 + 1;
|
||||
break;
|
||||
|
||||
case IMAGE_800:
|
||||
case IMAGE_1280:
|
||||
gspca_dev->alt = 1 + 1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mi1320_camera_settings(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
s32 backlight = sd->vcur.backlight;
|
||||
s32 bright = sd->vcur.brightness;
|
||||
s32 sharp = sd->vcur.sharpness;
|
||||
s32 cntr = sd->vcur.contrast;
|
||||
s32 gam = sd->vcur.gamma;
|
||||
s32 hue = sd->vcur.hue;
|
||||
s32 sat = sd->vcur.saturation;
|
||||
s32 wbal = sd->vcur.whitebal;
|
||||
s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0);
|
||||
s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0);
|
||||
s32 freq = (sd->vcur.AC50Hz > 0);
|
||||
s32 i;
|
||||
|
||||
if (freq != sd->vold.AC50Hz) {
|
||||
sd->vold.AC50Hz = freq;
|
||||
|
||||
freq = 2 * (freq == 0);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba02, 0x00f1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00 , 0x005b, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba01 + freq, 0x00f1, 0, NULL);
|
||||
}
|
||||
|
||||
if (wbal != sd->vold.whitebal) {
|
||||
sd->vold.whitebal = wbal;
|
||||
if (wbal < 0 || wbal > sd->vmax.whitebal)
|
||||
wbal = 0;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (wbal == 0) { /* Normal light */
|
||||
ctrl_out(gspca_dev, 0x40, 1,
|
||||
0x0010, 0x0010, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1,
|
||||
0x0003, 0x00c1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1,
|
||||
0x0042, 0x00c2, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 3,
|
||||
0xba00, 0x0200, 48, dat_wbalNL);
|
||||
}
|
||||
|
||||
if (wbal == 1) { /* Low light */
|
||||
ctrl_out(gspca_dev, 0x40, 1,
|
||||
0x0010, 0x0010, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1,
|
||||
0x0004, 0x00c1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1,
|
||||
0x0043, 0x00c2, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 3,
|
||||
0xba00, 0x0200, 48, dat_wbalLL);
|
||||
}
|
||||
|
||||
if (wbal == 2) { /* Back light */
|
||||
ctrl_out(gspca_dev, 0x40, 1,
|
||||
0x0010, 0x0010, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1,
|
||||
0x0003, 0x00c1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1,
|
||||
0x0042, 0x00c2, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 3,
|
||||
0xba00, 0x0200, 44, dat_wbalBL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bright != sd->vold.brightness) {
|
||||
sd->vold.brightness = bright;
|
||||
if (bright < 0 || bright > sd->vmax.brightness)
|
||||
bright = 0;
|
||||
|
||||
bright = tbl_bright[bright];
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00 + bright, 0x0034, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00 + bright, 0x00f1, 0, NULL);
|
||||
}
|
||||
|
||||
if (sat != sd->vold.saturation) {
|
||||
sd->vold.saturation = sat;
|
||||
if (sat < 0 || sat > sd->vmax.saturation)
|
||||
sat = 0;
|
||||
|
||||
sat = tbl_sat[sat];
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00 , 0x0025, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00 + sat, 0x00f1, 0, NULL);
|
||||
}
|
||||
|
||||
if (sharp != sd->vold.sharpness) {
|
||||
sd->vold.sharpness = sharp;
|
||||
if (sharp < 0 || sharp > sd->vmax.sharpness)
|
||||
sharp = 0;
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00 , 0x0005, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00 + sharp, 0x00f1, 0, NULL);
|
||||
}
|
||||
|
||||
if (hue != sd->vold.hue) {
|
||||
/* 0=normal 1=NB 2="sepia" 3=negative 4=other 5=other2 */
|
||||
if (hue < 0 || hue > sd->vmax.hue)
|
||||
hue = 0;
|
||||
if (hue == sd->vmax.hue)
|
||||
sd->swapRB = 1;
|
||||
else
|
||||
sd->swapRB = 0;
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba70, 0x00e2, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00 + hue * (hue < 6), 0x00f1,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
if (backlight != sd->vold.backlight) {
|
||||
sd->vold.backlight = backlight;
|
||||
if (backlight < 0 || backlight > sd->vmax.backlight)
|
||||
backlight = 0;
|
||||
|
||||
backlight = tbl_backlight[backlight];
|
||||
for (i = 0; i < 2; i++) {
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba74, 0x0006, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba80 + backlight, 0x00f1,
|
||||
0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (hue != sd->vold.hue) {
|
||||
sd->vold.hue = hue;
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba70, 0x00e2, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00 + hue * (hue < 6), 0x00f1,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
if (mirror != sd->vold.mirror || flip != sd->vold.flip) {
|
||||
u8 dat_hvflip2[4] = {0x20, 0x01, 0xf1, 0x00};
|
||||
sd->vold.mirror = mirror;
|
||||
sd->vold.flip = flip;
|
||||
|
||||
dat_hvflip2[3] = flip + 2 * mirror;
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 4, dat_hvflip1);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 4, dat_hvflip2);
|
||||
}
|
||||
|
||||
if (gam != sd->vold.gamma) {
|
||||
sd->vold.gamma = gam;
|
||||
if (gam < 0 || gam > sd->vmax.gamma)
|
||||
gam = 0;
|
||||
|
||||
gam = 2 * gam;
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba04 , 0x003b, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba02 + gam, 0x00f1, 0, NULL);
|
||||
}
|
||||
|
||||
if (cntr != sd->vold.contrast) {
|
||||
sd->vold.contrast = cntr;
|
||||
if (cntr < 0 || cntr > sd->vmax.contrast)
|
||||
cntr = 0;
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00 + tbl_cntr1[cntr], 0x0035,
|
||||
0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0xba00 + tbl_cntr2[cntr], 0x00f1,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mi1320_post_unset_alt(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL);
|
||||
|
||||
fetch_validx(gspca_dev, tbl_post_unset_alt,
|
||||
ARRAY_SIZE(tbl_post_unset_alt));
|
||||
}
|
||||
937
drivers/media/video/gspca/gl860/gl860-mi2020.c
Normal file
937
drivers/media/video/gspca/gl860/gl860-mi2020.c
Normal file
|
|
@ -0,0 +1,937 @@
|
|||
/* @file gl860-mi2020.c
|
||||
* @author Olivier LORIN, from Ice/Soro2005's logs(A), Fret_saw/Hulkie's
|
||||
* logs(B) and Tricid"s logs(C). With the help of Kytrix/BUGabundo/Blazercist.
|
||||
* @date 2009-08-27
|
||||
*
|
||||
* 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
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Sensor : MI2020 */
|
||||
|
||||
#include "gl860.h"
|
||||
|
||||
static u8 dat_bright1[] = {0x8c, 0xa2, 0x06};
|
||||
static u8 dat_bright3[] = {0x8c, 0xa1, 0x02};
|
||||
static u8 dat_bright4[] = {0x90, 0x00, 0x0f};
|
||||
static u8 dat_bright5[] = {0x8c, 0xa1, 0x03};
|
||||
static u8 dat_bright6[] = {0x90, 0x00, 0x05};
|
||||
|
||||
static u8 dat_dummy1[] = {0x90, 0x00, 0x06};
|
||||
/*static u8 dummy2[] = {0x8c, 0xa1, 0x02};*/
|
||||
/*static u8 dummy3[] = {0x90, 0x00, 0x1f};*/
|
||||
|
||||
static u8 dat_hvflip1[] = {0x8c, 0x27, 0x19};
|
||||
static u8 dat_hvflip3[] = {0x8c, 0x27, 0x3b};
|
||||
static u8 dat_hvflip5[] = {0x8c, 0xa1, 0x03};
|
||||
static u8 dat_hvflip6[] = {0x90, 0x00, 0x06};
|
||||
|
||||
static u8 dat_freq1[] = { 0x8c, 0xa4, 0x04 };
|
||||
|
||||
static u8 dat_multi5[] = { 0x8c, 0xa1, 0x03 };
|
||||
static u8 dat_multi6[] = { 0x90, 0x00, 0x05 };
|
||||
|
||||
static struct validx tbl_common_a[] = {
|
||||
{0x0000, 0x0000},
|
||||
{1, 0xffff}, /* msleep(35); */
|
||||
{0x006a, 0x0007}, {0x0063, 0x0006}, {0x006a, 0x000d}, {0x0000, 0x00c0},
|
||||
{0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, {0x0004, 0x00d8},
|
||||
{0x0000, 0x0058}, {0x0002, 0x0004}, {0x0041, 0x0000},
|
||||
};
|
||||
|
||||
static struct validx tbl_common_b[] = {
|
||||
{0x006a, 0x0007},
|
||||
{35, 0xffff},
|
||||
{0x00ef, 0x0006},
|
||||
{35, 0xffff},
|
||||
{0x006a, 0x000d},
|
||||
{35, 0xffff},
|
||||
{0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2},
|
||||
{0x0004, 0x00d8}, {0x0000, 0x0058}, {0x0041, 0x0000},
|
||||
};
|
||||
|
||||
static struct idxdata tbl_common_c[] = {
|
||||
{0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"},
|
||||
{6, "\xff\xff\xff"}, /* 12 */
|
||||
{0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
|
||||
{2, "\xff\xff\xff"}, /* - */
|
||||
{0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\x22\x23"},
|
||||
{0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0f"}, {0x33, "\x90\x00\x0d"},
|
||||
{0x33, "\x8c\xa2\x10"}, {0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x11"},
|
||||
{0x33, "\x90\x00\x07"}, {0x33, "\xf4\x03\x1d"}, {0x35, "\xa2\x00\xe2"},
|
||||
{0x33, "\x8c\xab\x05"}, {0x33, "\x90\x00\x01"}, {0x32, "\x6e\x00\x86"},
|
||||
{0x32, "\x70\x0f\xaa"}, {0x32, "\x72\x0f\xe4"}, {0x33, "\x8c\xa3\x4a"},
|
||||
{0x33, "\x90\x00\x5a"}, {0x33, "\x8c\xa3\x4b"}, {0x33, "\x90\x00\xa6"},
|
||||
{0x33, "\x8c\xa3\x61"}, {0x33, "\x90\x00\xc8"}, {0x33, "\x8c\xa3\x62"},
|
||||
{0x33, "\x90\x00\xe1"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
|
||||
{0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
|
||||
{0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
|
||||
{0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"},
|
||||
{0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"},
|
||||
{0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"},
|
||||
{0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"},
|
||||
{0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"},
|
||||
{0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"},
|
||||
{0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"},
|
||||
{0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"},
|
||||
{0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"},
|
||||
{0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"},
|
||||
{0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"},
|
||||
{0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"},
|
||||
{0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"},
|
||||
{0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"},
|
||||
{0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"},
|
||||
{0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"},
|
||||
{0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"},
|
||||
{0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"},
|
||||
{0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"},
|
||||
{0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"},
|
||||
{0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"},
|
||||
{0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"},
|
||||
{0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"},
|
||||
{1, "\xff\xff\xff"},
|
||||
{0x33, "\x78\x00\x00"},
|
||||
{1, "\xff\xff\xff"},
|
||||
{0x35, "\xb8\x1f\x20"}, {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x10"},
|
||||
{0x33, "\x8c\xa2\x07"}, {0x33, "\x90\x00\x08"}, {0x33, "\x8c\xa2\x42"},
|
||||
{0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x4a"}, {0x33, "\x90\x00\x8c"},
|
||||
{0x35, "\xba\xfa\x08"}, {0x33, "\x8c\xa2\x02"}, {0x33, "\x90\x00\x22"},
|
||||
{0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"},
|
||||
};
|
||||
|
||||
static struct idxdata tbl_common_d[] = {
|
||||
{0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa0"}, {0x33, "\x8c\xa4\x08"},
|
||||
{0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x21"},
|
||||
{0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\xa4\x0b"},
|
||||
{0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa0"},
|
||||
{0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc0"}, {0x33, "\x8c\x24\x15"},
|
||||
{0x33, "\x90\x00\xa0"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\xc0"},
|
||||
};
|
||||
|
||||
static struct idxdata tbl_common_e[] = {
|
||||
{0x33, "\x8c\xa4\x04"}, {0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"},
|
||||
{0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"},
|
||||
{0x33, "\x8c\xa2\x0c"}, {0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"},
|
||||
{0x33, "\x90\x00\x04"}, {0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"},
|
||||
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"},
|
||||
/* msleep(53); */
|
||||
{0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"},
|
||||
{0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"},
|
||||
{0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"},
|
||||
{0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"},
|
||||
{0x33, "\x90\x02\x84"}, {0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"},
|
||||
{0x33, "\x8c\x27\x07"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"},
|
||||
{0x33, "\x90\x04\xb0"}, {0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"},
|
||||
{0x33, "\x8c\x27\x0f"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"},
|
||||
{0x33, "\x90\x04\xbd"}, {0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"},
|
||||
{0x33, "\x8c\x27\x15"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"},
|
||||
{0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"},
|
||||
{0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"},
|
||||
{0x33, "\x90\x01\x02"}, {0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"},
|
||||
{0x33, "\x8c\x27\x21"}, {0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"},
|
||||
{0x33, "\x90\x02\x85"}, {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"},
|
||||
{0x33, "\x8c\x27\x27"}, {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"},
|
||||
{0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"},
|
||||
{0x33, "\x8c\x27\x2d"}, {0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"},
|
||||
{0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"},
|
||||
{0x33, "\x8c\x27\x33"}, {0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"},
|
||||
{0x33, "\x90\x06\x4b"}, {0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"},
|
||||
{0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"},
|
||||
{0x33, "\x90\x00\x24"}, {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"},
|
||||
{0x33, "\x8c\x27\x41"}, {0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"},
|
||||
{0x33, "\x90\x04\xed"}, {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"},
|
||||
{0x33, "\x8c\x27\x51"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"},
|
||||
{0x33, "\x90\x03\x20"}, {0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"},
|
||||
{0x33, "\x8c\x27\x57"}, {0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"},
|
||||
{0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"},
|
||||
{0x33, "\x8c\x27\x63"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"},
|
||||
{0x33, "\x90\x04\xb0"}, {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"},
|
||||
{0x33, "\x8c\xa4\x08"}, {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"},
|
||||
{0x33, "\x90\x00\x21"}, {0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"},
|
||||
{0x33, "\x8c\xa4\x0b"}, {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"},
|
||||
{0x33, "\x90\x00\xa1"}, {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"},
|
||||
{0x33, "\x8c\x24\x15"},
|
||||
};
|
||||
|
||||
static struct validx tbl_init_at_startup[] = {
|
||||
{0x0000, 0x0000},
|
||||
{53, 0xffff},
|
||||
{0x0010, 0x0010},
|
||||
{53, 0xffff},
|
||||
{0x0008, 0x00c0},
|
||||
{53, 0xffff},
|
||||
{0x0001, 0x00c1},
|
||||
{53, 0xffff},
|
||||
{0x0001, 0x00c2},
|
||||
{53, 0xffff},
|
||||
{0x0020, 0x0006},
|
||||
{53, 0xffff},
|
||||
{0x006a, 0x000d},
|
||||
{53, 0xffff},
|
||||
};
|
||||
|
||||
static struct idxdata tbl_init_post_alt_low_a[] = {
|
||||
{0x33, "\x8c\x27\x15"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\x22\x2e"},
|
||||
{0x33, "\x90\x00\x81"}, {0x33, "\x8c\xa4\x08"}, {0x33, "\x90\x00\x17"},
|
||||
{0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x1a"}, {0x33, "\x8c\xa4\x0a"},
|
||||
{0x33, "\x90\x00\x1d"}, {0x33, "\x8c\xa4\x0b"}, {0x33, "\x90\x00\x20"},
|
||||
{0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\x81"}, {0x33, "\x8c\x24\x13"},
|
||||
{0x33, "\x90\x00\x9b"},
|
||||
};
|
||||
|
||||
static struct idxdata tbl_init_post_alt_low_b[] = {
|
||||
{0x33, "\x8c\x27\x03"}, {0x33, "\x90\x03\x24"}, {0x33, "\x8c\x27\x05"},
|
||||
{0x33, "\x90\x02\x58"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
|
||||
{2, "\xff\xff\xff"},
|
||||
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
|
||||
{2, "\xff\xff\xff"},
|
||||
};
|
||||
|
||||
static struct idxdata tbl_init_post_alt_low_c[] = {
|
||||
{0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
|
||||
{2, "\xff\xff\xff"},
|
||||
{0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x20"},
|
||||
{0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"},
|
||||
{0x33, "\x2e\x01\x00"}, {0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"},
|
||||
{0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x95"}, {0x33, "\x90\x01\x00"},
|
||||
{2, "\xff\xff\xff"},
|
||||
{0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"},
|
||||
{0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
|
||||
{2, "\xff\xff\xff"},
|
||||
{0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"},
|
||||
{0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
|
||||
{2, "\xff\xff\xff"}, /* - * */
|
||||
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
|
||||
{2, "\xff\xff\xff"},
|
||||
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
|
||||
{2, "\xff\xff\xff"},
|
||||
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
|
||||
{2, "\xff\xff\xff"},
|
||||
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
|
||||
{1, "\xff\xff\xff"},
|
||||
};
|
||||
|
||||
static struct idxdata tbl_init_post_alt_low_d[] = {
|
||||
{0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
|
||||
{0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
|
||||
{0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
|
||||
{0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"},
|
||||
{0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"},
|
||||
{0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"},
|
||||
{0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"},
|
||||
{0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"},
|
||||
{0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"},
|
||||
{0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"},
|
||||
{0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"},
|
||||
{0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"},
|
||||
{0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"},
|
||||
{0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"},
|
||||
{0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"},
|
||||
{0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"},
|
||||
{0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"},
|
||||
{0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"},
|
||||
{0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"},
|
||||
{0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"},
|
||||
{0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"},
|
||||
{0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"},
|
||||
{0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"},
|
||||
{0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"},
|
||||
{0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"},
|
||||
{0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"},
|
||||
/* Flip/Mirror h/v=1 */
|
||||
{0x33, "\x90\x00\x3c"}, {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"},
|
||||
{0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"}, {0x33, "\x8c\xa1\x03"},
|
||||
{0x33, "\x90\x00\x06"},
|
||||
{130, "\xff\xff\xff"},
|
||||
{0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"},
|
||||
{0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"},
|
||||
{100, "\xff\xff\xff"},
|
||||
/* ?? */
|
||||
{0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa1\x02"},
|
||||
{0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
|
||||
{0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
|
||||
/* Brigthness=70 */
|
||||
{0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x46"}, {0x33, "\x8c\xa1\x02"},
|
||||
{0x33, "\x90\x00\x0f"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
|
||||
/* Sharpness=20 */
|
||||
{0x32, "\x6c\x14\x08"},
|
||||
};
|
||||
|
||||
static struct idxdata tbl_init_post_alt_big_a[] = {
|
||||
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
|
||||
{2, "\xff\xff\xff"},
|
||||
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
|
||||
{2, "\xff\xff\xff"},
|
||||
{0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
|
||||
{0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x03"},
|
||||
{0x33, "\x90\x00\x05"},
|
||||
{2, "\xff\xff\xff"},
|
||||
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
|
||||
{2, "\xff\xff\xff"},
|
||||
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
|
||||
{2, "\xff\xff\xff"},
|
||||
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, {0x33, "\x8c\xa1\x20"},
|
||||
{0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x30"}, {0x33, "\x90\x00\x03"},
|
||||
{0x33, "\x8c\xa1\x31"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x32"},
|
||||
{0x33, "\x90\x00\x03"}, {0x33, "\x8c\xa1\x34"}, {0x33, "\x90\x00\x03"},
|
||||
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x2e\x01\x00"},
|
||||
{0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
|
||||
};
|
||||
|
||||
static struct idxdata tbl_init_post_alt_big_b[] = {
|
||||
{0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
|
||||
{0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
|
||||
{0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
|
||||
{0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"},
|
||||
{0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"},
|
||||
{0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"},
|
||||
{0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"},
|
||||
{0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"},
|
||||
{0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"},
|
||||
{0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"},
|
||||
{0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"},
|
||||
{0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"},
|
||||
{0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"},
|
||||
{0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"},
|
||||
{0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"},
|
||||
{0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"},
|
||||
{0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"},
|
||||
{0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"},
|
||||
{0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"},
|
||||
{0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"},
|
||||
{0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"},
|
||||
{0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"},
|
||||
{0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"},
|
||||
{0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"},
|
||||
{0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"},
|
||||
{0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"},
|
||||
};
|
||||
|
||||
static struct idxdata tbl_init_post_alt_big_c[] = {
|
||||
{0x33, "\x8c\xa1\x02"},
|
||||
{0x33, "\x90\x00\x1f"},
|
||||
{0x33, "\x8c\xa1\x02"},
|
||||
{0x33, "\x90\x00\x1f"},
|
||||
{0x33, "\x8c\xa1\x02"},
|
||||
{0x33, "\x90\x00\x1f"},
|
||||
{0x33, "\x8c\xa1\x02"},
|
||||
{0x33, "\x90\x00\x1f"},
|
||||
};
|
||||
|
||||
static u8 *dat_640 = "\xd0\x02\xd1\x08\xd2\xe1\xd3\x02\xd4\x10\xd5\x81";
|
||||
static u8 *dat_800 = "\xd0\x02\xd1\x10\xd2\x57\xd3\x02\xd4\x18\xd5\x21";
|
||||
static u8 *dat_1280 = "\xd0\x02\xd1\x20\xd2\x01\xd3\x02\xd4\x28\xd5\x01";
|
||||
static u8 *dat_1600 = "\xd0\x02\xd1\x20\xd2\xaf\xd3\x02\xd4\x30\xd5\x41";
|
||||
|
||||
static int mi2020_init_at_startup(struct gspca_dev *gspca_dev);
|
||||
static int mi2020_configure_alt(struct gspca_dev *gspca_dev);
|
||||
static int mi2020_init_pre_alt(struct gspca_dev *gspca_dev);
|
||||
static int mi2020_init_post_alt(struct gspca_dev *gspca_dev);
|
||||
static void mi2020_post_unset_alt(struct gspca_dev *gspca_dev);
|
||||
static int mi2020_camera_settings(struct gspca_dev *gspca_dev);
|
||||
/*==========================================================================*/
|
||||
|
||||
void mi2020_init_settings(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
sd->vcur.backlight = 0;
|
||||
sd->vcur.brightness = 70;
|
||||
sd->vcur.sharpness = 20;
|
||||
sd->vcur.contrast = 0;
|
||||
sd->vcur.gamma = 0;
|
||||
sd->vcur.hue = 0;
|
||||
sd->vcur.saturation = 60;
|
||||
sd->vcur.whitebal = 50;
|
||||
sd->vcur.mirror = 0;
|
||||
sd->vcur.flip = 0;
|
||||
sd->vcur.AC50Hz = 1;
|
||||
|
||||
sd->vmax.backlight = 64;
|
||||
sd->vmax.brightness = 128;
|
||||
sd->vmax.sharpness = 40;
|
||||
sd->vmax.contrast = 3;
|
||||
sd->vmax.gamma = 2;
|
||||
sd->vmax.hue = 0 + 1; /* 200 */
|
||||
sd->vmax.saturation = 0; /* 100 */
|
||||
sd->vmax.whitebal = 0; /* 100 */
|
||||
sd->vmax.mirror = 1;
|
||||
sd->vmax.flip = 1;
|
||||
sd->vmax.AC50Hz = 1;
|
||||
if (_MI2020b_) {
|
||||
sd->vmax.contrast = 0;
|
||||
sd->vmax.gamma = 0;
|
||||
sd->vmax.backlight = 0;
|
||||
}
|
||||
|
||||
sd->dev_camera_settings = mi2020_camera_settings;
|
||||
sd->dev_init_at_startup = mi2020_init_at_startup;
|
||||
sd->dev_configure_alt = mi2020_configure_alt;
|
||||
sd->dev_init_pre_alt = mi2020_init_pre_alt;
|
||||
sd->dev_post_unset_alt = mi2020_post_unset_alt;
|
||||
}
|
||||
|
||||
/*==========================================================================*/
|
||||
|
||||
static void common(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
|
||||
|
||||
if (_MI2020b_) {
|
||||
fetch_validx(gspca_dev, tbl_common_a, ARRAY_SIZE(tbl_common_a));
|
||||
} else {
|
||||
if (_MI2020_)
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0008, 0x0004, 0, NULL);
|
||||
else
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0002, 0x0004, 0, NULL);
|
||||
msleep(35);
|
||||
fetch_validx(gspca_dev, tbl_common_b, ARRAY_SIZE(tbl_common_b));
|
||||
}
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x86\x25\x01");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x86\x25\x00");
|
||||
msleep(2); /* - * */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0030, 3, "\x1a\x0a\xcc");
|
||||
if (reso == IMAGE_1600)
|
||||
msleep(2); /* 1600 */
|
||||
fetch_idxdata(gspca_dev, tbl_common_c, ARRAY_SIZE(tbl_common_c));
|
||||
|
||||
if (_MI2020b_ || _MI2020_)
|
||||
fetch_idxdata(gspca_dev, tbl_common_d,
|
||||
ARRAY_SIZE(tbl_common_d));
|
||||
|
||||
fetch_idxdata(gspca_dev, tbl_common_e, ARRAY_SIZE(tbl_common_e));
|
||||
if (_MI2020b_ || _MI2020_) {
|
||||
/* Different from fret */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x78");
|
||||
/* Same as fret */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x24\x17");
|
||||
/* Different from fret */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x90");
|
||||
} else {
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x6a");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x24\x17");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x80");
|
||||
}
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x05");
|
||||
msleep(2);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
|
||||
if (reso == IMAGE_1600)
|
||||
msleep(14); /* 1600 */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x06");
|
||||
msleep(2);
|
||||
}
|
||||
|
||||
static int mi2020_init_at_startup(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
u8 c;
|
||||
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &c);
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &c);
|
||||
|
||||
fetch_validx(gspca_dev, tbl_init_at_startup,
|
||||
ARRAY_SIZE(tbl_init_at_startup));
|
||||
|
||||
common(gspca_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mi2020_init_pre_alt(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
sd->mirrorMask = 0;
|
||||
|
||||
sd->vold.backlight = -1;
|
||||
sd->vold.brightness = -1;
|
||||
sd->vold.sharpness = -1;
|
||||
sd->vold.contrast = -1;
|
||||
sd->vold.gamma = -1;
|
||||
sd->vold.hue = -1;
|
||||
sd->vold.mirror = -1;
|
||||
sd->vold.flip = -1;
|
||||
sd->vold.AC50Hz = -1;
|
||||
|
||||
mi2020_init_post_alt(gspca_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
|
||||
|
||||
s32 backlight = sd->vcur.backlight;
|
||||
s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0);
|
||||
s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0);
|
||||
s32 freq = (sd->vcur.AC50Hz > 0);
|
||||
|
||||
u8 dat_freq2[] = {0x90, 0x00, 0x80};
|
||||
u8 dat_multi1[] = {0x8c, 0xa7, 0x00};
|
||||
u8 dat_multi2[] = {0x90, 0x00, 0x00};
|
||||
u8 dat_multi3[] = {0x8c, 0xa7, 0x00};
|
||||
u8 dat_multi4[] = {0x90, 0x00, 0x00};
|
||||
u8 dat_hvflip2[] = {0x90, 0x04, 0x6c};
|
||||
u8 dat_hvflip4[] = {0x90, 0x00, 0x24};
|
||||
u8 c;
|
||||
|
||||
sd->nbIm = -1;
|
||||
|
||||
dat_freq2[2] = freq ? 0xc0 : 0x80;
|
||||
dat_multi1[2] = 0x9d;
|
||||
dat_multi3[2] = dat_multi1[2] + 1;
|
||||
dat_multi4[2] = dat_multi2[2] = backlight;
|
||||
dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror);
|
||||
dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror);
|
||||
|
||||
msleep(200);
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
|
||||
msleep(3); /* 35 * */
|
||||
|
||||
common(gspca_dev);
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL);
|
||||
msleep(70);
|
||||
|
||||
if (_MI2020b_)
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0003, 0x00c1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0042, 0x00c2, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x006a, 0x000d, 0, NULL);
|
||||
|
||||
switch (reso) {
|
||||
case IMAGE_640:
|
||||
case IMAGE_800:
|
||||
if (reso != IMAGE_800)
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
|
||||
12, dat_640);
|
||||
else
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
|
||||
12, dat_800);
|
||||
|
||||
if (_MI2020c_)
|
||||
fetch_idxdata(gspca_dev, tbl_init_post_alt_low_a,
|
||||
ARRAY_SIZE(tbl_init_post_alt_low_a));
|
||||
|
||||
if (reso == IMAGE_800)
|
||||
fetch_idxdata(gspca_dev, tbl_init_post_alt_low_b,
|
||||
ARRAY_SIZE(tbl_init_post_alt_low_b));
|
||||
|
||||
fetch_idxdata(gspca_dev, tbl_init_post_alt_low_c,
|
||||
ARRAY_SIZE(tbl_init_post_alt_low_c));
|
||||
|
||||
if (_MI2020b_) {
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
|
||||
msleep(150);
|
||||
} else if (_MI2020c_) {
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
|
||||
msleep(120);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
|
||||
msleep(30);
|
||||
} else if (_MI2020_) {
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
|
||||
msleep(120);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
|
||||
msleep(30);
|
||||
}
|
||||
|
||||
/* AC power frequency */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2);
|
||||
msleep(20);
|
||||
/* backlight */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
|
||||
/* at init time but not after */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa2\x0c");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x17");
|
||||
/* finish the backlight */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
|
||||
msleep(5);/* " */
|
||||
|
||||
if (_MI2020c_) {
|
||||
fetch_idxdata(gspca_dev, tbl_init_post_alt_low_d,
|
||||
ARRAY_SIZE(tbl_init_post_alt_low_d));
|
||||
} else {
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c);
|
||||
msleep(14); /* 0xd8 */
|
||||
|
||||
/* flip/mirror */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, dat_hvflip1);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, dat_hvflip2);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, dat_hvflip3);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, dat_hvflip4);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, dat_hvflip5);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, dat_hvflip6);
|
||||
msleep(21);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, dat_dummy1);
|
||||
msleep(5);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, dat_dummy1);
|
||||
msleep(5);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, dat_dummy1);
|
||||
msleep(5);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, dat_dummy1);
|
||||
msleep(5);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, dat_dummy1);
|
||||
msleep(5);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, dat_dummy1);
|
||||
/* end of flip/mirror main part */
|
||||
msleep(246); /* 146 */
|
||||
|
||||
sd->nbIm = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case IMAGE_1280:
|
||||
case IMAGE_1600:
|
||||
if (reso == IMAGE_1280) {
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
|
||||
12, dat_1280);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, "\x8c\x27\x07");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, "\x90\x05\x04");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, "\x8c\x27\x09");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, "\x90\x04\x02");
|
||||
} else {
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
|
||||
12, dat_1600);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, "\x8c\x27\x07");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, "\x90\x06\x40");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, "\x8c\x27\x09");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
|
||||
3, "\x90\x04\xb0");
|
||||
}
|
||||
|
||||
fetch_idxdata(gspca_dev, tbl_init_post_alt_big_a,
|
||||
ARRAY_SIZE(tbl_init_post_alt_big_a));
|
||||
|
||||
if (reso == IMAGE_1600)
|
||||
msleep(13); /* 1600 */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x27\x97");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x01\x00");
|
||||
msleep(53);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
|
||||
if (reso == IMAGE_1600)
|
||||
msleep(13); /* 1600 */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
|
||||
msleep(53);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x72");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x02");
|
||||
if (reso == IMAGE_1600)
|
||||
msleep(13); /* 1600 */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
|
||||
msleep(53);
|
||||
|
||||
if (_MI2020b_) {
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
|
||||
if (reso == IMAGE_1600)
|
||||
msleep(500); /* 1600 */
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
|
||||
msleep(1850);
|
||||
} else if (_MI2020c_ || _MI2020_) {
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
|
||||
msleep(1850);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
|
||||
msleep(30);
|
||||
}
|
||||
|
||||
/* AC power frequency */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2);
|
||||
msleep(20);
|
||||
/* backlight */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
|
||||
/* at init time but not after */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa2\x0c");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x17");
|
||||
/* finish the backlight */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
|
||||
msleep(6); /* " */
|
||||
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c);
|
||||
msleep(14);
|
||||
|
||||
if (_MI2020c_)
|
||||
fetch_idxdata(gspca_dev, tbl_init_post_alt_big_b,
|
||||
ARRAY_SIZE(tbl_init_post_alt_big_b));
|
||||
|
||||
/* flip/mirror */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6);
|
||||
/* end of flip/mirror main part */
|
||||
msleep(16);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
|
||||
if (reso == IMAGE_1600)
|
||||
msleep(25); /* 1600 */
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
|
||||
msleep(103);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x02");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x72");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
|
||||
sd->nbIm = 0;
|
||||
|
||||
if (_MI2020c_)
|
||||
fetch_idxdata(gspca_dev, tbl_init_post_alt_big_c,
|
||||
ARRAY_SIZE(tbl_init_post_alt_big_c));
|
||||
}
|
||||
|
||||
sd->vold.mirror = mirror;
|
||||
sd->vold.flip = flip;
|
||||
sd->vold.AC50Hz = freq;
|
||||
sd->vold.backlight = backlight;
|
||||
|
||||
mi2020_camera_settings(gspca_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mi2020_configure_alt(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
|
||||
|
||||
switch (reso) {
|
||||
case IMAGE_640:
|
||||
gspca_dev->alt = 3 + 1;
|
||||
break;
|
||||
|
||||
case IMAGE_800:
|
||||
case IMAGE_1280:
|
||||
case IMAGE_1600:
|
||||
gspca_dev->alt = 1 + 1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mi2020_camera_settings(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
s32 backlight = sd->vcur.backlight;
|
||||
s32 bright = sd->vcur.brightness;
|
||||
s32 sharp = sd->vcur.sharpness;
|
||||
s32 cntr = sd->vcur.contrast;
|
||||
s32 gam = sd->vcur.gamma;
|
||||
s32 hue = (sd->vcur.hue > 0);
|
||||
s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0);
|
||||
s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0);
|
||||
s32 freq = (sd->vcur.AC50Hz > 0);
|
||||
|
||||
u8 dat_sharp[] = {0x6c, 0x00, 0x08};
|
||||
u8 dat_bright2[] = {0x90, 0x00, 0x00};
|
||||
u8 dat_freq2[] = {0x90, 0x00, 0x80};
|
||||
u8 dat_multi1[] = {0x8c, 0xa7, 0x00};
|
||||
u8 dat_multi2[] = {0x90, 0x00, 0x00};
|
||||
u8 dat_multi3[] = {0x8c, 0xa7, 0x00};
|
||||
u8 dat_multi4[] = {0x90, 0x00, 0x00};
|
||||
u8 dat_hvflip2[] = {0x90, 0x04, 0x6c};
|
||||
u8 dat_hvflip4[] = {0x90, 0x00, 0x24};
|
||||
|
||||
/* Less than 4 images received -> too early to set the settings */
|
||||
if (sd->nbIm < 4) {
|
||||
sd->waitSet = 1;
|
||||
return 0;
|
||||
}
|
||||
sd->waitSet = 0;
|
||||
|
||||
if (freq != sd->vold.AC50Hz) {
|
||||
sd->vold.AC50Hz = freq;
|
||||
|
||||
dat_freq2[2] = freq ? 0xc0 : 0x80;
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2);
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
if (mirror != sd->vold.mirror || flip != sd->vold.flip) {
|
||||
sd->vold.mirror = mirror;
|
||||
sd->vold.flip = flip;
|
||||
|
||||
dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror);
|
||||
dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6);
|
||||
msleep(130);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
|
||||
msleep(6);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
|
||||
msleep(6);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
|
||||
msleep(6);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
|
||||
msleep(6);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
|
||||
msleep(6);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
|
||||
msleep(6);
|
||||
|
||||
/* Sometimes present, sometimes not, useful? */
|
||||
/* ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
|
||||
* ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);
|
||||
* ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
|
||||
* ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);
|
||||
* ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
|
||||
* ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);
|
||||
* ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
|
||||
* ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);*/
|
||||
}
|
||||
|
||||
if (backlight != sd->vold.backlight) {
|
||||
sd->vold.backlight = backlight;
|
||||
if (backlight < 0 || backlight > sd->vmax.backlight)
|
||||
backlight = 0;
|
||||
|
||||
dat_multi1[2] = 0x9d;
|
||||
dat_multi3[2] = dat_multi1[2] + 1;
|
||||
dat_multi4[2] = dat_multi2[2] = backlight;
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
|
||||
}
|
||||
|
||||
if (gam != sd->vold.gamma) {
|
||||
sd->vold.gamma = gam;
|
||||
if (gam < 0 || gam > sd->vmax.gamma)
|
||||
gam = 0;
|
||||
|
||||
dat_multi1[2] = 0x6d;
|
||||
dat_multi3[2] = dat_multi1[2] + 1;
|
||||
dat_multi4[2] = dat_multi2[2] = 0x40 + gam;
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
|
||||
}
|
||||
|
||||
if (cntr != sd->vold.contrast) {
|
||||
sd->vold.contrast = cntr;
|
||||
if (cntr < 0 || cntr > sd->vmax.contrast)
|
||||
cntr = 0;
|
||||
|
||||
dat_multi1[2] = 0x6d;
|
||||
dat_multi3[2] = dat_multi1[2] + 1;
|
||||
dat_multi4[2] = dat_multi2[2] = 0x12 + 16 * cntr;
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
|
||||
}
|
||||
|
||||
if (bright != sd->vold.brightness) {
|
||||
sd->vold.brightness = bright;
|
||||
if (bright < 0 || bright > sd->vmax.brightness)
|
||||
bright = 0;
|
||||
|
||||
dat_bright2[2] = bright;
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright1);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright2);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright3);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright4);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright5);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright6);
|
||||
}
|
||||
|
||||
if (sharp != sd->vold.sharpness) {
|
||||
sd->vold.sharpness = sharp;
|
||||
if (sharp < 0 || sharp > sd->vmax.sharpness)
|
||||
sharp = 0;
|
||||
|
||||
dat_sharp[1] = sharp;
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0032, 3, dat_sharp);
|
||||
}
|
||||
|
||||
if (hue != sd->vold.hue) {
|
||||
sd->swapRB = hue;
|
||||
sd->vold.hue = hue;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mi2020_post_unset_alt(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL);
|
||||
msleep(20);
|
||||
if (_MI2020c_ || _MI2020_)
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL);
|
||||
else
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL);
|
||||
}
|
||||
505
drivers/media/video/gspca/gl860/gl860-ov2640.c
Normal file
505
drivers/media/video/gspca/gl860/gl860-ov2640.c
Normal file
|
|
@ -0,0 +1,505 @@
|
|||
/* @file gl860-ov2640.c
|
||||
* @author Olivier LORIN, from Malmostoso's logs
|
||||
* @date 2009-08-27
|
||||
*
|
||||
* 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
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Sensor : OV2640 */
|
||||
|
||||
#include "gl860.h"
|
||||
|
||||
static u8 dat_init1[] = "\x00\x41\x07\x6a\x06\x61\x0d\x6a" "\x10\x10\xc1\x01";
|
||||
static u8 dat_init2[] = {0x61}; /* expected */
|
||||
static u8 dat_init3[] = {0x51}; /* expected */
|
||||
|
||||
static u8 dat_post[] =
|
||||
"\x00\x41\x07\x6a\x06\xef\x0d\x6a" "\x10\x10\xc1\x01";
|
||||
|
||||
static u8 dat_640[] = "\xd0\x01\xd1\x08\xd2\xe0\xd3\x02\xd4\x10\xd5\x81";
|
||||
static u8 dat_800[] = "\xd0\x01\xd1\x10\xd2\x58\xd3\x02\xd4\x18\xd5\x21";
|
||||
static u8 dat_1280[] = "\xd0\x01\xd1\x18\xd2\xc0\xd3\x02\xd4\x28\xd5\x01";
|
||||
static u8 dat_1600[] = "\xd0\x01\xd1\x20\xd2\xb0\xd3\x02\xd4\x30\xd5\x41";
|
||||
|
||||
static u8 c50[] = {0x50}; /* expected */
|
||||
static u8 c28[] = {0x28}; /* expected */
|
||||
static u8 ca8[] = {0xa8}; /* expected */
|
||||
|
||||
static struct validx tbl_init_at_startup[] = {
|
||||
{0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1},
|
||||
{0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d},
|
||||
{0x0050, 0x0000}, {0x0041, 0x0000}, {0x006a, 0x0007}, {0x0061, 0x0006},
|
||||
{0x006a, 0x000d}, {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1},
|
||||
{0x0041, 0x00c2}, {0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058},
|
||||
{0x0041, 0x0000}, {0x0061, 0x0000},
|
||||
};
|
||||
|
||||
static struct validx tbl_common[] = {
|
||||
{0x6000, 0x00ff}, {0x60ff, 0x002c}, {0x60df, 0x002e}, {0x6001, 0x00ff},
|
||||
{0x6080, 0x0012}, {0x6000, 0x0000}, {0x6000, 0x0045}, {0x6000, 0x0010},
|
||||
{0x6035, 0x003c}, {0x6000, 0x0011}, {0x6028, 0x0004}, {0x60e5, 0x0013},
|
||||
{0x6088, 0x0014}, {0x600c, 0x002c}, {0x6078, 0x0033}, {0x60f7, 0x003b},
|
||||
{0x6000, 0x003e}, {0x6011, 0x0043}, {0x6010, 0x0016}, {0x6082, 0x0039},
|
||||
{0x6088, 0x0035}, {0x600a, 0x0022}, {0x6040, 0x0037}, {0x6000, 0x0023},
|
||||
{0x60a0, 0x0034}, {0x601a, 0x0036}, {0x6002, 0x0006}, {0x60c0, 0x0007},
|
||||
{0x60b7, 0x000d}, {0x6001, 0x000e}, {0x6000, 0x004c}, {0x6081, 0x004a},
|
||||
{0x6099, 0x0021}, {0x6002, 0x0009}, {0x603e, 0x0024}, {0x6034, 0x0025},
|
||||
{0x6081, 0x0026}, {0x6000, 0x0000}, {0x6000, 0x0045}, {0x6000, 0x0010},
|
||||
{0x6000, 0x005c}, {0x6000, 0x0063}, {0x6000, 0x007c}, {0x6070, 0x0061},
|
||||
{0x6080, 0x0062}, {0x6080, 0x0020}, {0x6030, 0x0028}, {0x6000, 0x006c},
|
||||
{0x6000, 0x006e}, {0x6002, 0x0070}, {0x6094, 0x0071}, {0x60c1, 0x0073},
|
||||
{0x6034, 0x003d}, {0x6057, 0x005a}, {0x60bb, 0x004f}, {0x609c, 0x0050},
|
||||
{0x6080, 0x006d}, {0x6002, 0x0039}, {0x6033, 0x003a}, {0x60f1, 0x003b},
|
||||
{0x6031, 0x003c}, {0x6000, 0x00ff}, {0x6014, 0x00e0}, {0x60ff, 0x0076},
|
||||
{0x60a0, 0x0033}, {0x6020, 0x0042}, {0x6018, 0x0043}, {0x6000, 0x004c},
|
||||
{0x60d0, 0x0087}, {0x600f, 0x0088}, {0x6003, 0x00d7}, {0x6010, 0x00d9},
|
||||
{0x6005, 0x00da}, {0x6082, 0x00d3}, {0x60c0, 0x00f9}, {0x6006, 0x0044},
|
||||
{0x6007, 0x00d1}, {0x6002, 0x00d2}, {0x6000, 0x00d2}, {0x6011, 0x00d8},
|
||||
{0x6008, 0x00c8}, {0x6080, 0x00c9}, {0x6008, 0x007c}, {0x6020, 0x007d},
|
||||
{0x6020, 0x007d}, {0x6000, 0x0090}, {0x600e, 0x0091}, {0x601a, 0x0091},
|
||||
{0x6031, 0x0091}, {0x605a, 0x0091}, {0x6069, 0x0091}, {0x6075, 0x0091},
|
||||
{0x607e, 0x0091}, {0x6088, 0x0091}, {0x608f, 0x0091}, {0x6096, 0x0091},
|
||||
{0x60a3, 0x0091}, {0x60af, 0x0091}, {0x60c4, 0x0091}, {0x60d7, 0x0091},
|
||||
{0x60e8, 0x0091}, {0x6020, 0x0091}, {0x6000, 0x0092}, {0x6006, 0x0093},
|
||||
{0x60e3, 0x0093}, {0x6005, 0x0093}, {0x6005, 0x0093}, {0x6000, 0x0093},
|
||||
{0x6004, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093},
|
||||
{0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093},
|
||||
{0x6000, 0x0096}, {0x6008, 0x0097}, {0x6019, 0x0097}, {0x6002, 0x0097},
|
||||
{0x600c, 0x0097}, {0x6024, 0x0097}, {0x6030, 0x0097}, {0x6028, 0x0097},
|
||||
{0x6026, 0x0097}, {0x6002, 0x0097}, {0x6098, 0x0097}, {0x6080, 0x0097},
|
||||
{0x6000, 0x0097}, {0x6000, 0x0097}, {0x60ed, 0x00c3}, {0x609a, 0x00c4},
|
||||
{0x6000, 0x00a4}, {0x6011, 0x00c5}, {0x6051, 0x00c6}, {0x6010, 0x00c7},
|
||||
{0x6066, 0x00b6}, {0x60a5, 0x00b8}, {0x6064, 0x00b7}, {0x607c, 0x00b9},
|
||||
{0x60af, 0x00b3}, {0x6097, 0x00b4}, {0x60ff, 0x00b5}, {0x60c5, 0x00b0},
|
||||
{0x6094, 0x00b1}, {0x600f, 0x00b2}, {0x605c, 0x00c4}, {0x6000, 0x00a8},
|
||||
{0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x601d, 0x0086}, {0x6000, 0x0050},
|
||||
{0x6090, 0x0051}, {0x6018, 0x0052}, {0x6000, 0x0053}, {0x6000, 0x0054},
|
||||
{0x6088, 0x0055}, {0x6000, 0x0057}, {0x6090, 0x005a}, {0x6018, 0x005b},
|
||||
{0x6005, 0x005c}, {0x60ed, 0x00c3}, {0x6000, 0x007f}, {0x6005, 0x00da},
|
||||
{0x601f, 0x00e5}, {0x6067, 0x00e1}, {0x6000, 0x00e0}, {0x60ff, 0x00dd},
|
||||
{0x6000, 0x0005}, {0x6001, 0x00ff}, {0x6000, 0x0000}, {0x6000, 0x0045},
|
||||
{0x6000, 0x0010},
|
||||
};
|
||||
|
||||
static struct validx tbl_sensor_settings_common_a[] = {
|
||||
{0x0041, 0x0000}, {0x006a, 0x0007}, {0x00ef, 0x0006}, {0x006a, 0x000d},
|
||||
{0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1}, {0x0041, 0x00c2},
|
||||
{0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058}, {0x0041, 0x0000},
|
||||
{50, 0xffff},
|
||||
{0x0061, 0x0000},
|
||||
{0xffff, 0xffff},
|
||||
{0x6000, 0x00ff}, {0x6000, 0x007c}, {0x6007, 0x007d},
|
||||
{30, 0xffff},
|
||||
{0x0040, 0x0000},
|
||||
};
|
||||
|
||||
static struct validx tbl_sensor_settings_common_b[] = {
|
||||
{0x6001, 0x00ff}, {0x6038, 0x000c},
|
||||
{10, 0xffff},
|
||||
{0x6000, 0x0011},
|
||||
/* backlight=31/64 */
|
||||
{0x6001, 0x00ff}, {0x603e, 0x0024}, {0x6034, 0x0025},
|
||||
/* bright=0/256 */
|
||||
{0x6000, 0x00ff}, {0x6009, 0x007c}, {0x6000, 0x007d},
|
||||
/* wbal=64/128 */
|
||||
{0x6000, 0x00ff}, {0x6003, 0x007c}, {0x6040, 0x007d},
|
||||
/* cntr=0/256 */
|
||||
{0x6000, 0x00ff}, {0x6007, 0x007c}, {0x6000, 0x007d},
|
||||
/* sat=128/256 */
|
||||
{0x6000, 0x00ff}, {0x6001, 0x007c}, {0x6080, 0x007d},
|
||||
/* sharpness=0/32 */
|
||||
{0x6000, 0x00ff}, {0x6001, 0x0092}, {0x60c0, 0x0093},
|
||||
/* hue=0/256 */
|
||||
{0x6000, 0x00ff}, {0x6002, 0x007c}, {0x6000, 0x007d},
|
||||
/* gam=32/64 */
|
||||
{0x6000, 0x00ff}, {0x6008, 0x007c}, {0x6020, 0x007d},
|
||||
/* image right up */
|
||||
{0xffff, 0xffff},
|
||||
{15, 0xffff},
|
||||
{0x6001, 0x00ff}, {0x6000, 0x8004},
|
||||
{0xffff, 0xffff},
|
||||
{0x60a8, 0x0004},
|
||||
{15, 0xffff},
|
||||
{0x6001, 0x00ff}, {0x6000, 0x8004},
|
||||
{0xffff, 0xffff},
|
||||
{0x60f8, 0x0004},
|
||||
/* image right up */
|
||||
{0xffff, 0xffff},
|
||||
/* backlight=31/64 */
|
||||
{0x6001, 0x00ff}, {0x603e, 0x0024}, {0x6034, 0x0025},
|
||||
};
|
||||
|
||||
static struct validx tbl_640[] = {
|
||||
{0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, {0x6067, 0x00e1},
|
||||
{0x6004, 0x00da}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0},
|
||||
{0x6001, 0x00ff}, {0x6000, 0x0012}, {0x6000, 0x0011}, {0x6011, 0x0017},
|
||||
{0x6075, 0x0018}, {0x6001, 0x0019}, {0x6097, 0x001a}, {0x6036, 0x0032},
|
||||
{0x60bb, 0x004f}, {0x6057, 0x005a}, {0x609c, 0x0050}, {0x6080, 0x006d},
|
||||
{0x6092, 0x0026}, {0x60ff, 0x0020}, {0x6000, 0x0027}, {0x6000, 0x00ff},
|
||||
{0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x6000, 0x008c}, {0x603d, 0x0086},
|
||||
{0x6089, 0x0050}, {0x6090, 0x0051}, {0x602c, 0x0052}, {0x6000, 0x0053},
|
||||
{0x6000, 0x0054}, {0x6088, 0x0055}, {0x6000, 0x0057}, {0x60a0, 0x005a},
|
||||
{0x6078, 0x005b}, {0x6000, 0x005c}, {0x6004, 0x00d3}, {0x6000, 0x00e0},
|
||||
{0x60ff, 0x00dd}, {0x60a1, 0x005a},
|
||||
};
|
||||
|
||||
static struct validx tbl_800[] = {
|
||||
{0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, {0x6067, 0x00e1},
|
||||
{0x6004, 0x00da}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0},
|
||||
{0x6001, 0x00ff}, {0x6040, 0x0012}, {0x6000, 0x0011}, {0x6011, 0x0017},
|
||||
{0x6043, 0x0018}, {0x6000, 0x0019}, {0x604b, 0x001a}, {0x6009, 0x0032},
|
||||
{0x60ca, 0x004f}, {0x60a8, 0x0050}, {0x6000, 0x006d}, {0x6038, 0x003d},
|
||||
{0x60c8, 0x0035}, {0x6000, 0x0022}, {0x6092, 0x0026}, {0x60ff, 0x0020},
|
||||
{0x6000, 0x0027}, {0x6000, 0x00ff}, {0x6064, 0x00c0}, {0x604b, 0x00c1},
|
||||
{0x6000, 0x008c}, {0x601d, 0x0086}, {0x6082, 0x00d3}, {0x6000, 0x00e0},
|
||||
{0x60ff, 0x00dd}, {0x6020, 0x008c}, {0x6001, 0x00ff}, {0x6044, 0x0018},
|
||||
};
|
||||
|
||||
static struct validx tbl_big_a[] = {
|
||||
{0x0002, 0x00c1}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0},
|
||||
{0x6001, 0x00ff}, {0x6000, 0x0012}, {0x6000, 0x0000}, {0x6000, 0x0045},
|
||||
{0x6000, 0x0010}, {0x6000, 0x0011}, {0x6011, 0x0017}, {0x6075, 0x0018},
|
||||
{0x6001, 0x0019}, {0x6097, 0x001a}, {0x6036, 0x0032}, {0x60bb, 0x004f},
|
||||
{0x609c, 0x0050}, {0x6057, 0x005a}, {0x6080, 0x006d}, {0x6043, 0x000f},
|
||||
{0x608f, 0x0003}, {0x6005, 0x007c}, {0x6081, 0x0026}, {0x6000, 0x00ff},
|
||||
{0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x6000, 0x008c},
|
||||
};
|
||||
|
||||
static struct validx tbl_big_b[] = {
|
||||
{0x603d, 0x0086}, {0x6000, 0x0050}, {0x6090, 0x0051}, {0x602c, 0x0052},
|
||||
{0x6000, 0x0053}, {0x6000, 0x0054}, {0x6088, 0x0055}, {0x6000, 0x0057},
|
||||
{0x6040, 0x005a}, {0x60f0, 0x005b}, {0x6001, 0x005c}, {0x6082, 0x00d3},
|
||||
{0x6000, 0x008e},
|
||||
};
|
||||
|
||||
static struct validx tbl_big_c[] = {
|
||||
{0x6004, 0x00da}, {0x6000, 0x00e0}, {0x6067, 0x00e1}, {0x60ff, 0x00dd},
|
||||
{0x6001, 0x00ff}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0},
|
||||
{0x6001, 0x00ff}, {0x6000, 0x0011}, {0x6000, 0x00ff}, {0x6010, 0x00c7},
|
||||
{0x6000, 0x0092}, {0x6006, 0x0093}, {0x60e3, 0x0093}, {0x6005, 0x0093},
|
||||
{0x6005, 0x0093}, {0x60ed, 0x00c3}, {0x6000, 0x00a4}, {0x60d0, 0x0087},
|
||||
{0x6003, 0x0096}, {0x600c, 0x0097}, {0x6024, 0x0097}, {0x6030, 0x0097},
|
||||
{0x6028, 0x0097}, {0x6026, 0x0097}, {0x6002, 0x0097}, {0x6001, 0x00ff},
|
||||
{0x6043, 0x000f}, {0x608f, 0x0003}, {0x6000, 0x002d}, {0x6000, 0x002e},
|
||||
{0x600a, 0x0022}, {0x6002, 0x0070}, {0x6008, 0x0014}, {0x6048, 0x0014},
|
||||
{0x6000, 0x00ff}, {0x6000, 0x00e0}, {0x60ff, 0x00dd},
|
||||
};
|
||||
|
||||
static struct validx tbl_post_unset_alt[] = {
|
||||
{0x006a, 0x000d}, {0x6001, 0x00ff}, {0x6081, 0x0026}, {0x6000, 0x0000},
|
||||
{0x6000, 0x0045}, {0x6000, 0x0010}, {0x6068, 0x000d},
|
||||
{50, 0xffff},
|
||||
{0x0021, 0x0000},
|
||||
};
|
||||
|
||||
static int ov2640_init_at_startup(struct gspca_dev *gspca_dev);
|
||||
static int ov2640_configure_alt(struct gspca_dev *gspca_dev);
|
||||
static int ov2640_init_pre_alt(struct gspca_dev *gspca_dev);
|
||||
static int ov2640_init_post_alt(struct gspca_dev *gspca_dev);
|
||||
static void ov2640_post_unset_alt(struct gspca_dev *gspca_dev);
|
||||
static int ov2640_camera_settings(struct gspca_dev *gspca_dev);
|
||||
/*==========================================================================*/
|
||||
|
||||
void ov2640_init_settings(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
sd->vcur.backlight = 32;
|
||||
sd->vcur.brightness = 0;
|
||||
sd->vcur.sharpness = 6;
|
||||
sd->vcur.contrast = 0;
|
||||
sd->vcur.gamma = 32;
|
||||
sd->vcur.hue = 0;
|
||||
sd->vcur.saturation = 128;
|
||||
sd->vcur.whitebal = 64;
|
||||
|
||||
sd->vmax.backlight = 64;
|
||||
sd->vmax.brightness = 255;
|
||||
sd->vmax.sharpness = 31;
|
||||
sd->vmax.contrast = 255;
|
||||
sd->vmax.gamma = 64;
|
||||
sd->vmax.hue = 255 + 1;
|
||||
sd->vmax.saturation = 255;
|
||||
sd->vmax.whitebal = 128;
|
||||
sd->vmax.mirror = 0;
|
||||
sd->vmax.flip = 0;
|
||||
sd->vmax.AC50Hz = 0;
|
||||
|
||||
sd->dev_camera_settings = ov2640_camera_settings;
|
||||
sd->dev_init_at_startup = ov2640_init_at_startup;
|
||||
sd->dev_configure_alt = ov2640_configure_alt;
|
||||
sd->dev_init_pre_alt = ov2640_init_pre_alt;
|
||||
sd->dev_post_unset_alt = ov2640_post_unset_alt;
|
||||
}
|
||||
|
||||
/*==========================================================================*/
|
||||
|
||||
static void common(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
fetch_validx(gspca_dev, tbl_common, ARRAY_SIZE(tbl_common));
|
||||
}
|
||||
|
||||
static int ov2640_init_at_startup(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
fetch_validx(gspca_dev, tbl_init_at_startup,
|
||||
ARRAY_SIZE(tbl_init_at_startup));
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_init1);
|
||||
|
||||
common(gspca_dev);
|
||||
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0006, 1, dat_init2);
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x00ef, 0x0006, 0, NULL);
|
||||
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, dat_init3);
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0051, 0x0000, 0, NULL);
|
||||
/* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov2640_init_pre_alt(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
sd->vold.backlight = -1;
|
||||
sd->vold.brightness = -1;
|
||||
sd->vold.sharpness = -1;
|
||||
sd->vold.contrast = -1;
|
||||
sd->vold.saturation = -1;
|
||||
sd->vold.gamma = -1;
|
||||
sd->vold.hue = -1;
|
||||
sd->vold.whitebal = -1;
|
||||
|
||||
ov2640_init_post_alt(gspca_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov2640_init_post_alt(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
|
||||
s32 n; /* reserved for FETCH macros */
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
|
||||
|
||||
n = fetch_validx(gspca_dev, tbl_sensor_settings_common_a,
|
||||
ARRAY_SIZE(tbl_sensor_settings_common_a));
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_post);
|
||||
common(gspca_dev);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common_a,
|
||||
ARRAY_SIZE(tbl_sensor_settings_common_a), n);
|
||||
|
||||
switch (reso) {
|
||||
case IMAGE_640:
|
||||
n = fetch_validx(gspca_dev, tbl_640, ARRAY_SIZE(tbl_640));
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_640);
|
||||
break;
|
||||
|
||||
case IMAGE_800:
|
||||
n = fetch_validx(gspca_dev, tbl_800, ARRAY_SIZE(tbl_800));
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_800);
|
||||
break;
|
||||
|
||||
case IMAGE_1600:
|
||||
case IMAGE_1280:
|
||||
n = fetch_validx(gspca_dev, tbl_big_a, ARRAY_SIZE(tbl_big_a));
|
||||
|
||||
if (reso == IMAGE_1280) {
|
||||
n = fetch_validx(gspca_dev, tbl_big_b,
|
||||
ARRAY_SIZE(tbl_big_b));
|
||||
} else {
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x601d, 0x0086, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00d7, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6082, 0x00d3, 0, NULL);
|
||||
}
|
||||
|
||||
n = fetch_validx(gspca_dev, tbl_big_c, ARRAY_SIZE(tbl_big_c));
|
||||
|
||||
if (reso == IMAGE_1280) {
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
|
||||
12, dat_1280);
|
||||
} else {
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6020, 0x008c, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6076, 0x0018, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
|
||||
12, dat_1600);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
n = fetch_validx(gspca_dev, tbl_sensor_settings_common_b,
|
||||
ARRAY_SIZE(tbl_sensor_settings_common_b));
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, c50);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common_b,
|
||||
ARRAY_SIZE(tbl_sensor_settings_common_b), n);
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x8004, 1, c28);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common_b,
|
||||
ARRAY_SIZE(tbl_sensor_settings_common_b), n);
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x8004, 1, ca8);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common_b,
|
||||
ARRAY_SIZE(tbl_sensor_settings_common_b), n);
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, c50);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common_b,
|
||||
ARRAY_SIZE(tbl_sensor_settings_common_b), n);
|
||||
|
||||
ov2640_camera_settings(gspca_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov2640_configure_alt(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
|
||||
|
||||
switch (reso) {
|
||||
case IMAGE_640:
|
||||
gspca_dev->alt = 3 + 1;
|
||||
break;
|
||||
|
||||
case IMAGE_800:
|
||||
case IMAGE_1280:
|
||||
case IMAGE_1600:
|
||||
gspca_dev->alt = 1 + 1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov2640_camera_settings(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
s32 backlight = sd->vcur.backlight;
|
||||
s32 bright = sd->vcur.brightness;
|
||||
s32 sharp = sd->vcur.sharpness;
|
||||
s32 gam = sd->vcur.gamma;
|
||||
s32 cntr = sd->vcur.contrast;
|
||||
s32 sat = sd->vcur.saturation;
|
||||
s32 hue = sd->vcur.hue;
|
||||
s32 wbal = sd->vcur.whitebal;
|
||||
|
||||
if (backlight != sd->vold.backlight) {
|
||||
if (backlight < 0 || backlight > sd->vmax.backlight)
|
||||
backlight = 0;
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6001 , 0x00ff,
|
||||
0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x601f + backlight , 0x0024,
|
||||
0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x601f + backlight - 10, 0x0025,
|
||||
0, NULL);
|
||||
/* No sd->vold.backlight=backlight; (to be done again later) */
|
||||
}
|
||||
|
||||
if (bright != sd->vold.brightness) {
|
||||
sd->vold.brightness = bright;
|
||||
if (bright < 0 || bright > sd->vmax.brightness)
|
||||
bright = 0;
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6009 , 0x007c, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6000 + bright, 0x007d, 0, NULL);
|
||||
}
|
||||
|
||||
if (wbal != sd->vold.whitebal) {
|
||||
sd->vold.whitebal = wbal;
|
||||
if (wbal < 0 || wbal > sd->vmax.whitebal)
|
||||
wbal = 0;
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6003 , 0x007c, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6000 + wbal, 0x007d, 0, NULL);
|
||||
}
|
||||
|
||||
if (cntr != sd->vold.contrast) {
|
||||
sd->vold.contrast = cntr;
|
||||
if (cntr < 0 || cntr > sd->vmax.contrast)
|
||||
cntr = 0;
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6007 , 0x007c, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6000 + cntr, 0x007d, 0, NULL);
|
||||
}
|
||||
|
||||
if (sat != sd->vold.saturation) {
|
||||
sd->vold.saturation = sat;
|
||||
if (sat < 0 || sat > sd->vmax.saturation)
|
||||
sat = 0;
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6001 , 0x007c, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6000 + sat, 0x007d, 0, NULL);
|
||||
}
|
||||
|
||||
if (sharp != sd->vold.sharpness) {
|
||||
sd->vold.sharpness = sharp;
|
||||
if (sharp < 0 || sharp > sd->vmax.sharpness)
|
||||
sharp = 0;
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6001 , 0x0092, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x60c0 + sharp, 0x0093, 0, NULL);
|
||||
}
|
||||
|
||||
if (hue != sd->vold.hue) {
|
||||
sd->vold.hue = hue;
|
||||
if (hue < 0 || hue > sd->vmax.hue)
|
||||
hue = 0;
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6002 , 0x007c, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6000 + hue * (hue < 255), 0x007d,
|
||||
0, NULL);
|
||||
if (hue >= sd->vmax.hue)
|
||||
sd->swapRB = 1;
|
||||
else
|
||||
sd->swapRB = 0;
|
||||
}
|
||||
|
||||
if (gam != sd->vold.gamma) {
|
||||
sd->vold.gamma = gam;
|
||||
if (gam < 0 || gam > sd->vmax.gamma)
|
||||
gam = 0;
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6008 , 0x007c, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6000 + gam, 0x007d, 0, NULL);
|
||||
}
|
||||
|
||||
if (backlight != sd->vold.backlight) {
|
||||
sd->vold.backlight = backlight;
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6001 , 0x00ff,
|
||||
0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x601f + backlight , 0x0024,
|
||||
0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x601f + backlight - 10, 0x0025,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ov2640_post_unset_alt(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL);
|
||||
msleep(20);
|
||||
fetch_validx(gspca_dev, tbl_post_unset_alt,
|
||||
ARRAY_SIZE(tbl_post_unset_alt));
|
||||
}
|
||||
337
drivers/media/video/gspca/gl860/gl860-ov9655.c
Normal file
337
drivers/media/video/gspca/gl860/gl860-ov9655.c
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
/* @file gl860-ov9655.c
|
||||
* @author Olivier LORIN, from logs done by Simon (Sur3) and Almighurt
|
||||
* on dsd's weblog
|
||||
* @date 2009-08-27
|
||||
*
|
||||
* 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
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Sensor : OV9655 */
|
||||
|
||||
#include "gl860.h"
|
||||
|
||||
static struct validx tbl_init_at_startup[] = {
|
||||
{0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1},
|
||||
{0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d},
|
||||
|
||||
{0x0040, 0x0000},
|
||||
};
|
||||
|
||||
static struct validx tbl_commmon[] = {
|
||||
{0x0041, 0x0000}, {0x006a, 0x0007}, {0x0063, 0x0006}, {0x006a, 0x000d},
|
||||
{0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1}, {0x0041, 0x00c2},
|
||||
{0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058}, {0x0040, 0x0000},
|
||||
{0x00f3, 0x0006}, {0x0058, 0x0000}, {0x0048, 0x0000}, {0x0061, 0x0000},
|
||||
};
|
||||
|
||||
static s32 tbl_length[] = {12, 56, 52, 54, 56, 42, 32, 12};
|
||||
|
||||
static u8 *tbl_640[] = {
|
||||
"\x00\x40\x07\x6a\x06\xf3\x0d\x6a" "\x10\x10\xc1\x01"
|
||||
,
|
||||
"\x12\x80\x00\x00\x01\x98\x02\x80" "\x03\x12\x04\x03\x0b\x57\x0e\x61"
|
||||
"\x0f\x42\x11\x01\x12\x60\x13\x00" "\x14\x3a\x16\x24\x17\x14\x18\x00"
|
||||
"\x19\x01\x1a\x3d\x1e\x04\x24\x3c" "\x25\x36\x26\x72\x27\x08\x28\x08"
|
||||
"\x29\x15\x2a\x00\x2b\x00\x2c\x08"
|
||||
,
|
||||
"\x32\xff\x33\x00\x34\x3d\x35\x00" "\x36\xfa\x38\x72\x39\x57\x3a\x00"
|
||||
"\x3b\x0c\x3d\x99\x3e\x0c\x3f\xc1" "\x40\xc0\x41\x00\x42\xc0\x43\x0a"
|
||||
"\x44\xf0\x45\x46\x46\x62\x47\x2a" "\x48\x3c\x4a\xee\x4b\xe7\x4c\xe7"
|
||||
"\x4d\xe7\x4e\xe7"
|
||||
,
|
||||
"\x4f\x98\x50\x98\x51\x00\x52\x28" "\x53\x70\x54\x98\x58\x1a\x59\x85"
|
||||
"\x5a\xa9\x5b\x64\x5c\x84\x5d\x53" "\x5e\x0e\x5f\xf0\x60\xf0\x61\xf0"
|
||||
"\x62\x00\x63\x00\x64\x02\x65\x20" "\x66\x00\x69\x0a\x6b\x5a\x6c\x04"
|
||||
"\x6d\x55\x6e\x00\x6f\x9d"
|
||||
,
|
||||
"\x70\x15\x71\x78\x72\x00\x73\x00" "\x74\x3a\x75\x35\x76\x01\x77\x02"
|
||||
"\x7a\x24\x7b\x04\x7c\x07\x7d\x10" "\x7e\x28\x7f\x36\x80\x44\x81\x52"
|
||||
"\x82\x60\x83\x6c\x84\x78\x85\x8c" "\x86\x9e\x87\xbb\x88\xd2\x89\xe5"
|
||||
"\x8a\x23\x8c\x8d\x90\x7c\x91\x7b"
|
||||
,
|
||||
"\x9d\x02\x9e\x02\x9f\x74\xa0\x73" "\xa1\x40\xa4\x50\xa5\x68\xa6\x70"
|
||||
"\xa8\xc1\xa9\xef\xaa\x92\xab\x04" "\xac\x80\xad\x80\xae\x80\xaf\x80"
|
||||
"\xb2\xf2\xb3\x20\xb4\x20\xb5\x00" "\xb6\xaf"
|
||||
,
|
||||
"\xbb\xae\xbc\x4f\xbd\x4e\xbe\x6a" "\xbf\x68\xc0\xaa\xc1\xc0\xc2\x01"
|
||||
"\xc3\x4e\xc6\x85\xc7\x81\xc9\xe0" "\xca\xe8\xcb\xf0\xcc\xd8\xcd\x93"
|
||||
,
|
||||
"\xd0\x01\xd1\x08\xd2\xe0\xd3\x01" "\xd4\x10\xd5\x80"
|
||||
};
|
||||
|
||||
static u8 *tbl_800[] = {
|
||||
"\x00\x40\x07\x6a\x06\xf3\x0d\x6a" "\x10\x10\xc1\x01"
|
||||
,
|
||||
"\x12\x80\x00\x00\x01\x98\x02\x80" "\x03\x12\x04\x01\x0b\x57\x0e\x61"
|
||||
"\x0f\x42\x11\x00\x12\x00\x13\x00" "\x14\x3a\x16\x24\x17\x1b\x18\xbb"
|
||||
"\x19\x01\x1a\x81\x1e\x04\x24\x3c" "\x25\x36\x26\x72\x27\x08\x28\x08"
|
||||
"\x29\x15\x2a\x00\x2b\x00\x2c\x08"
|
||||
,
|
||||
"\x32\xa4\x33\x00\x34\x3d\x35\x00" "\x36\xf8\x38\x72\x39\x57\x3a\x00"
|
||||
"\x3b\x0c\x3d\x99\x3e\x0c\x3f\xc2" "\x40\xc0\x41\x00\x42\xc0\x43\x0a"
|
||||
"\x44\xf0\x45\x46\x46\x62\x47\x2a" "\x48\x3c\x4a\xec\x4b\xe8\x4c\xe8"
|
||||
"\x4d\xe8\x4e\xe8"
|
||||
,
|
||||
"\x4f\x98\x50\x98\x51\x00\x52\x28" "\x53\x70\x54\x98\x58\x1a\x59\x85"
|
||||
"\x5a\xa9\x5b\x64\x5c\x84\x5d\x53" "\x5e\x0e\x5f\xf0\x60\xf0\x61\xf0"
|
||||
"\x62\x00\x63\x00\x64\x02\x65\x20" "\x66\x00\x69\x02\x6b\x5a\x6c\x04"
|
||||
"\x6d\x55\x6e\x00\x6f\x9d"
|
||||
,
|
||||
"\x70\x08\x71\x78\x72\x00\x73\x01" "\x74\x3a\x75\x35\x76\x01\x77\x02"
|
||||
"\x7a\x24\x7b\x04\x7c\x07\x7d\x10" "\x7e\x28\x7f\x36\x80\x44\x81\x52"
|
||||
"\x82\x60\x83\x6c\x84\x78\x85\x8c" "\x86\x9e\x87\xbb\x88\xd2\x89\xe5"
|
||||
"\x8a\x23\x8c\x0d\x90\x90\x91\x90"
|
||||
,
|
||||
"\x9d\x02\x9e\x02\x9f\x94\xa0\x94" "\xa1\x01\xa4\x50\xa5\x68\xa6\x70"
|
||||
"\xa8\xc1\xa9\xef\xaa\x92\xab\x04" "\xac\x80\xad\x80\xae\x80\xaf\x80"
|
||||
"\xb2\xf2\xb3\x20\xb4\x20\xb5\x00" "\xb6\xaf"
|
||||
,
|
||||
"\xbb\xae\xbc\x38\xbd\x39\xbe\x01" "\xbf\x01\xc0\xe2\xc1\xc0\xc2\x01"
|
||||
"\xc3\x4e\xc6\x85\xc7\x81\xc9\xe0" "\xca\xe8\xcb\xf0\xcc\xd8\xcd\x93"
|
||||
,
|
||||
"\xd0\x21\xd1\x18\xd2\xe0\xd3\x01" "\xd4\x28\xd5\x00"
|
||||
};
|
||||
|
||||
static u8 c04[] = {0x04};
|
||||
static u8 dat_post_1[] = "\x04\x00\x10\x20\xa1\x00\x00\x02";
|
||||
static u8 dat_post_2[] = "\x10\x10\xc1\x02";
|
||||
static u8 dat_post_3[] = "\x04\x00\x10\x7c\xa1\x00\x00\x04";
|
||||
static u8 dat_post_4[] = "\x10\x02\xc1\x06";
|
||||
static u8 dat_post_5[] = "\x04\x00\x10\x7b\xa1\x00\x00\x08";
|
||||
static u8 dat_post_6[] = "\x10\x10\xc1\x05";
|
||||
static u8 dat_post_7[] = "\x04\x00\x10\x7c\xa1\x00\x00\x08";
|
||||
static u8 dat_post_8[] = "\x04\x00\x10\x7c\xa1\x00\x00\x09";
|
||||
|
||||
static struct validx tbl_init_post_alt[] = {
|
||||
{0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x603c, 0x00ff},
|
||||
{0x6003, 0x00ff}, {0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x6001, 0x00ff},
|
||||
{0x6000, 0x801e},
|
||||
{0xffff, 0xffff},
|
||||
{0x6004, 0x001e}, {0x6000, 0x801e},
|
||||
{0xffff, 0xffff},
|
||||
{0x6004, 0x001e}, {0x6012, 0x0003}, {0x6000, 0x801e},
|
||||
{0xffff, 0xffff},
|
||||
{0x6004, 0x001e}, {0x6000, 0x801e},
|
||||
{0xffff, 0xffff},
|
||||
{0x6004, 0x001e}, {0x6012, 0x0003},
|
||||
{0xffff, 0xffff},
|
||||
{0x6000, 0x801e},
|
||||
{0xffff, 0xffff},
|
||||
{0x6004, 0x001e}, {0x6000, 0x801e},
|
||||
{0xffff, 0xffff},
|
||||
{0x6004, 0x001e}, {0x6012, 0x0003}, {0x6000, 0x801e},
|
||||
{0xffff, 0xffff},
|
||||
{0x6004, 0x001e}, {0x6000, 0x801e},
|
||||
{0xffff, 0xffff},
|
||||
{0x6004, 0x001e}, {0x6012, 0x0003},
|
||||
{0xffff, 0xffff},
|
||||
{0x6000, 0x801e},
|
||||
{0xffff, 0xffff},
|
||||
{0x6004, 0x001e}, {0x6000, 0x801e},
|
||||
{0xffff, 0xffff},
|
||||
{0x6004, 0x001e}, {0x6012, 0x0003},
|
||||
};
|
||||
|
||||
static int ov9655_init_at_startup(struct gspca_dev *gspca_dev);
|
||||
static int ov9655_configure_alt(struct gspca_dev *gspca_dev);
|
||||
static int ov9655_init_pre_alt(struct gspca_dev *gspca_dev);
|
||||
static int ov9655_init_post_alt(struct gspca_dev *gspca_dev);
|
||||
static void ov9655_post_unset_alt(struct gspca_dev *gspca_dev);
|
||||
static int ov9655_camera_settings(struct gspca_dev *gspca_dev);
|
||||
/*==========================================================================*/
|
||||
|
||||
void ov9655_init_settings(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
sd->vcur.backlight = 0;
|
||||
sd->vcur.brightness = 128;
|
||||
sd->vcur.sharpness = 0;
|
||||
sd->vcur.contrast = 0;
|
||||
sd->vcur.gamma = 0;
|
||||
sd->vcur.hue = 0;
|
||||
sd->vcur.saturation = 0;
|
||||
sd->vcur.whitebal = 0;
|
||||
|
||||
sd->vmax.backlight = 0;
|
||||
sd->vmax.brightness = 255;
|
||||
sd->vmax.sharpness = 0;
|
||||
sd->vmax.contrast = 0;
|
||||
sd->vmax.gamma = 0;
|
||||
sd->vmax.hue = 0 + 1;
|
||||
sd->vmax.saturation = 0;
|
||||
sd->vmax.whitebal = 0;
|
||||
sd->vmax.mirror = 0;
|
||||
sd->vmax.flip = 0;
|
||||
sd->vmax.AC50Hz = 0;
|
||||
|
||||
sd->dev_camera_settings = ov9655_camera_settings;
|
||||
sd->dev_init_at_startup = ov9655_init_at_startup;
|
||||
sd->dev_configure_alt = ov9655_configure_alt;
|
||||
sd->dev_init_pre_alt = ov9655_init_pre_alt;
|
||||
sd->dev_post_unset_alt = ov9655_post_unset_alt;
|
||||
}
|
||||
|
||||
/*==========================================================================*/
|
||||
|
||||
static int ov9655_init_at_startup(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
fetch_validx(gspca_dev, tbl_init_at_startup,
|
||||
ARRAY_SIZE(tbl_init_at_startup));
|
||||
fetch_validx(gspca_dev, tbl_commmon, ARRAY_SIZE(tbl_commmon));
|
||||
/* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL);*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov9655_init_pre_alt(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
sd->vold.brightness = -1;
|
||||
sd->vold.hue = -1;
|
||||
|
||||
fetch_validx(gspca_dev, tbl_commmon, ARRAY_SIZE(tbl_commmon));
|
||||
|
||||
ov9655_init_post_alt(gspca_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov9655_init_post_alt(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
|
||||
s32 n; /* reserved for FETCH macros */
|
||||
s32 i;
|
||||
u8 **tbl;
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
|
||||
|
||||
tbl = (reso == IMAGE_640) ? tbl_640 : tbl_800;
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
|
||||
tbl_length[0], tbl[0]);
|
||||
for (i = 1; i < 7; i++)
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200,
|
||||
tbl_length[i], tbl[i]);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
|
||||
tbl_length[7], tbl[7]);
|
||||
|
||||
n = fetch_validx(gspca_dev, tbl_init_post_alt,
|
||||
ARRAY_SIZE(tbl_init_post_alt));
|
||||
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
|
||||
ARRAY_SIZE(tbl_init_post_alt), n);
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
|
||||
ARRAY_SIZE(tbl_init_post_alt), n);
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
|
||||
ARRAY_SIZE(tbl_init_post_alt), n);
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
|
||||
ARRAY_SIZE(tbl_init_post_alt), n);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_1);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
|
||||
ARRAY_SIZE(tbl_init_post_alt), n);
|
||||
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
|
||||
ARRAY_SIZE(tbl_init_post_alt), n);
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
|
||||
ARRAY_SIZE(tbl_init_post_alt), n);
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
|
||||
ARRAY_SIZE(tbl_init_post_alt), n);
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
|
||||
ARRAY_SIZE(tbl_init_post_alt), n);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_1);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
|
||||
ARRAY_SIZE(tbl_init_post_alt), n);
|
||||
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
|
||||
ARRAY_SIZE(tbl_init_post_alt), n);
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
|
||||
keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
|
||||
ARRAY_SIZE(tbl_init_post_alt), n);
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_1);
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post_2);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_3);
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post_4);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_5);
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post_6);
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_7);
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_8);
|
||||
|
||||
ov9655_camera_settings(gspca_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov9655_configure_alt(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
|
||||
|
||||
switch (reso) {
|
||||
case IMAGE_640:
|
||||
gspca_dev->alt = 1 + 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
gspca_dev->alt = 1 + 1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov9655_camera_settings(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
u8 dat_bright[] = "\x04\x00\x10\x7c\xa1\x00\x00\x70";
|
||||
|
||||
s32 bright = sd->vcur.brightness;
|
||||
s32 hue = sd->vcur.hue;
|
||||
|
||||
if (bright != sd->vold.brightness) {
|
||||
sd->vold.brightness = bright;
|
||||
if (bright < 0 || bright > sd->vmax.brightness)
|
||||
bright = 0;
|
||||
|
||||
dat_bright[3] = bright;
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_bright);
|
||||
}
|
||||
|
||||
if (hue != sd->vold.hue) {
|
||||
sd->vold.hue = hue;
|
||||
sd->swapRB = (hue != 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ov9655_post_unset_alt(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0061, 0x0000, 0, NULL);
|
||||
}
|
||||
785
drivers/media/video/gspca/gl860/gl860.c
Normal file
785
drivers/media/video/gspca/gl860/gl860.c
Normal file
|
|
@ -0,0 +1,785 @@
|
|||
/* @file gl860.c
|
||||
* @date 2009-08-27
|
||||
*
|
||||
* Genesys Logic webcam with gl860 subdrivers
|
||||
*
|
||||
* Driver by Olivier Lorin <o.lorin@laposte.net>
|
||||
* GSPCA by Jean-Francois Moine <http://moinejf.free.fr>
|
||||
* Thanks BUGabundo and Malmostoso for your amazing help!
|
||||
*
|
||||
* 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
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "gspca.h"
|
||||
#include "gl860.h"
|
||||
|
||||
MODULE_AUTHOR("Olivier Lorin <[email protected]>");
|
||||
MODULE_DESCRIPTION("GSPCA/Genesys Logic GL860 USB Camera Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*======================== static function declarations ====================*/
|
||||
|
||||
static void (*dev_init_settings)(struct gspca_dev *gspca_dev);
|
||||
|
||||
static int sd_config(struct gspca_dev *gspca_dev,
|
||||
const struct usb_device_id *id);
|
||||
static int sd_init(struct gspca_dev *gspca_dev);
|
||||
static int sd_isoc_init(struct gspca_dev *gspca_dev);
|
||||
static int sd_start(struct gspca_dev *gspca_dev);
|
||||
static void sd_stop0(struct gspca_dev *gspca_dev);
|
||||
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
|
||||
struct gspca_frame *frame, u8 *data, s32 len);
|
||||
static void sd_callback(struct gspca_dev *gspca_dev);
|
||||
|
||||
static int gl860_guess_sensor(struct gspca_dev *gspca_dev,
|
||||
s32 vendor_id, s32 product_id);
|
||||
|
||||
/*============================ driver options ==============================*/
|
||||
|
||||
static s32 AC50Hz = 0xff;
|
||||
module_param(AC50Hz, int, 0644);
|
||||
MODULE_PARM_DESC(AC50Hz, " Does AC power frequency is 50Hz? (0/1)");
|
||||
|
||||
static char sensor[7];
|
||||
module_param_string(sensor, sensor, sizeof(sensor), 0644);
|
||||
MODULE_PARM_DESC(sensor,
|
||||
" Driver sensor ('MI1320'/'MI2020'/'OV9655'/'OV2640'/'')");
|
||||
|
||||
/*============================ webcam controls =============================*/
|
||||
|
||||
/* Functions to get and set a control value */
|
||||
#define SD_SETGET(thename) \
|
||||
static int sd_set_##thename(struct gspca_dev *gspca_dev, s32 val)\
|
||||
{\
|
||||
struct sd *sd = (struct sd *) gspca_dev;\
|
||||
\
|
||||
sd->vcur.thename = val;\
|
||||
if (gspca_dev->streaming)\
|
||||
sd->dev_camera_settings(gspca_dev);\
|
||||
return 0;\
|
||||
} \
|
||||
static int sd_get_##thename(struct gspca_dev *gspca_dev, s32 *val)\
|
||||
{\
|
||||
struct sd *sd = (struct sd *) gspca_dev;\
|
||||
\
|
||||
*val = sd->vcur.thename;\
|
||||
return 0;\
|
||||
}
|
||||
|
||||
SD_SETGET(mirror)
|
||||
SD_SETGET(flip)
|
||||
SD_SETGET(AC50Hz)
|
||||
SD_SETGET(backlight)
|
||||
SD_SETGET(brightness)
|
||||
SD_SETGET(gamma)
|
||||
SD_SETGET(hue)
|
||||
SD_SETGET(saturation)
|
||||
SD_SETGET(sharpness)
|
||||
SD_SETGET(whitebal)
|
||||
SD_SETGET(contrast)
|
||||
|
||||
#define GL860_NCTRLS 11
|
||||
|
||||
/* control table */
|
||||
static struct ctrl sd_ctrls_mi1320[GL860_NCTRLS];
|
||||
static struct ctrl sd_ctrls_mi2020[GL860_NCTRLS];
|
||||
static struct ctrl sd_ctrls_mi2020b[GL860_NCTRLS];
|
||||
static struct ctrl sd_ctrls_ov2640[GL860_NCTRLS];
|
||||
static struct ctrl sd_ctrls_ov9655[GL860_NCTRLS];
|
||||
|
||||
#define SET_MY_CTRL(theid, \
|
||||
thetype, thelabel, thename) \
|
||||
if (sd->vmax.thename != 0) {\
|
||||
sd_ctrls[nCtrls].qctrl.id = theid;\
|
||||
sd_ctrls[nCtrls].qctrl.type = thetype;\
|
||||
strcpy(sd_ctrls[nCtrls].qctrl.name, thelabel);\
|
||||
sd_ctrls[nCtrls].qctrl.minimum = 0;\
|
||||
sd_ctrls[nCtrls].qctrl.maximum = sd->vmax.thename;\
|
||||
sd_ctrls[nCtrls].qctrl.default_value = sd->vcur.thename;\
|
||||
sd_ctrls[nCtrls].qctrl.step = \
|
||||
(sd->vmax.thename < 16) ? 1 : sd->vmax.thename/16;\
|
||||
sd_ctrls[nCtrls].set = sd_set_##thename;\
|
||||
sd_ctrls[nCtrls].get = sd_get_##thename;\
|
||||
nCtrls++;\
|
||||
}
|
||||
|
||||
static int gl860_build_control_table(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
struct ctrl *sd_ctrls;
|
||||
int nCtrls = 0;
|
||||
|
||||
if (_MI1320_)
|
||||
sd_ctrls = sd_ctrls_mi1320;
|
||||
else if (_MI2020_)
|
||||
sd_ctrls = sd_ctrls_mi2020;
|
||||
else if (_MI2020b_)
|
||||
sd_ctrls = sd_ctrls_mi2020b;
|
||||
else if (_OV2640_)
|
||||
sd_ctrls = sd_ctrls_ov2640;
|
||||
else if (_OV9655_)
|
||||
sd_ctrls = sd_ctrls_ov9655;
|
||||
else
|
||||
return 0;
|
||||
|
||||
memset(sd_ctrls, 0, GL860_NCTRLS * sizeof(struct ctrl));
|
||||
|
||||
SET_MY_CTRL(V4L2_CID_BRIGHTNESS,
|
||||
V4L2_CTRL_TYPE_INTEGER, "Brightness", brightness)
|
||||
SET_MY_CTRL(V4L2_CID_SHARPNESS,
|
||||
V4L2_CTRL_TYPE_INTEGER, "Sharpness", sharpness)
|
||||
SET_MY_CTRL(V4L2_CID_CONTRAST,
|
||||
V4L2_CTRL_TYPE_INTEGER, "Contrast", contrast)
|
||||
SET_MY_CTRL(V4L2_CID_GAMMA,
|
||||
V4L2_CTRL_TYPE_INTEGER, "Gamma", gamma)
|
||||
SET_MY_CTRL(V4L2_CID_HUE,
|
||||
V4L2_CTRL_TYPE_INTEGER, "Palette", hue)
|
||||
SET_MY_CTRL(V4L2_CID_SATURATION,
|
||||
V4L2_CTRL_TYPE_INTEGER, "Saturation", saturation)
|
||||
SET_MY_CTRL(V4L2_CID_WHITE_BALANCE_TEMPERATURE,
|
||||
V4L2_CTRL_TYPE_INTEGER, "White Bal.", whitebal)
|
||||
SET_MY_CTRL(V4L2_CID_BACKLIGHT_COMPENSATION,
|
||||
V4L2_CTRL_TYPE_INTEGER, "Backlight" , backlight)
|
||||
|
||||
SET_MY_CTRL(V4L2_CID_HFLIP,
|
||||
V4L2_CTRL_TYPE_BOOLEAN, "Mirror", mirror)
|
||||
SET_MY_CTRL(V4L2_CID_VFLIP,
|
||||
V4L2_CTRL_TYPE_BOOLEAN, "Flip", flip)
|
||||
SET_MY_CTRL(V4L2_CID_POWER_LINE_FREQUENCY,
|
||||
V4L2_CTRL_TYPE_BOOLEAN, "50Hz", AC50Hz)
|
||||
|
||||
return nCtrls;
|
||||
}
|
||||
|
||||
/*==================== sud-driver structure initialisation =================*/
|
||||
|
||||
static struct sd_desc sd_desc_mi1320 = {
|
||||
.name = MODULE_NAME,
|
||||
.ctrls = sd_ctrls_mi1320,
|
||||
.nctrls = GL860_NCTRLS,
|
||||
.config = sd_config,
|
||||
.init = sd_init,
|
||||
.isoc_init = sd_isoc_init,
|
||||
.start = sd_start,
|
||||
.stop0 = sd_stop0,
|
||||
.pkt_scan = sd_pkt_scan,
|
||||
.dq_callback = sd_callback,
|
||||
};
|
||||
|
||||
static struct sd_desc sd_desc_mi2020 = {
|
||||
.name = MODULE_NAME,
|
||||
.ctrls = sd_ctrls_mi2020,
|
||||
.nctrls = GL860_NCTRLS,
|
||||
.config = sd_config,
|
||||
.init = sd_init,
|
||||
.isoc_init = sd_isoc_init,
|
||||
.start = sd_start,
|
||||
.stop0 = sd_stop0,
|
||||
.pkt_scan = sd_pkt_scan,
|
||||
.dq_callback = sd_callback,
|
||||
};
|
||||
|
||||
static struct sd_desc sd_desc_mi2020b = {
|
||||
.name = MODULE_NAME,
|
||||
.ctrls = sd_ctrls_mi2020b,
|
||||
.nctrls = GL860_NCTRLS,
|
||||
.config = sd_config,
|
||||
.init = sd_init,
|
||||
.isoc_init = sd_isoc_init,
|
||||
.start = sd_start,
|
||||
.stop0 = sd_stop0,
|
||||
.pkt_scan = sd_pkt_scan,
|
||||
.dq_callback = sd_callback,
|
||||
};
|
||||
|
||||
static struct sd_desc sd_desc_ov2640 = {
|
||||
.name = MODULE_NAME,
|
||||
.ctrls = sd_ctrls_ov2640,
|
||||
.nctrls = GL860_NCTRLS,
|
||||
.config = sd_config,
|
||||
.init = sd_init,
|
||||
.isoc_init = sd_isoc_init,
|
||||
.start = sd_start,
|
||||
.stop0 = sd_stop0,
|
||||
.pkt_scan = sd_pkt_scan,
|
||||
.dq_callback = sd_callback,
|
||||
};
|
||||
|
||||
static struct sd_desc sd_desc_ov9655 = {
|
||||
.name = MODULE_NAME,
|
||||
.ctrls = sd_ctrls_ov9655,
|
||||
.nctrls = GL860_NCTRLS,
|
||||
.config = sd_config,
|
||||
.init = sd_init,
|
||||
.isoc_init = sd_isoc_init,
|
||||
.start = sd_start,
|
||||
.stop0 = sd_stop0,
|
||||
.pkt_scan = sd_pkt_scan,
|
||||
.dq_callback = sd_callback,
|
||||
};
|
||||
|
||||
/*=========================== sub-driver image sizes =======================*/
|
||||
|
||||
static struct v4l2_pix_format mi2020_mode[] = {
|
||||
{ 640, 480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
|
||||
.bytesperline = 640,
|
||||
.sizeimage = 640 * 480,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.priv = 0
|
||||
},
|
||||
{ 800, 600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
|
||||
.bytesperline = 800,
|
||||
.sizeimage = 800 * 600,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.priv = 1
|
||||
},
|
||||
{1280, 1024, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
|
||||
.bytesperline = 1280,
|
||||
.sizeimage = 1280 * 1024,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.priv = 2
|
||||
},
|
||||
{1600, 1200, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
|
||||
.bytesperline = 1600,
|
||||
.sizeimage = 1600 * 1200,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.priv = 3
|
||||
},
|
||||
};
|
||||
|
||||
static struct v4l2_pix_format ov2640_mode[] = {
|
||||
{ 640, 480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
|
||||
.bytesperline = 640,
|
||||
.sizeimage = 640 * 480,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.priv = 0
|
||||
},
|
||||
{ 800, 600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
|
||||
.bytesperline = 800,
|
||||
.sizeimage = 800 * 600,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.priv = 1
|
||||
},
|
||||
{1280, 960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
|
||||
.bytesperline = 1280,
|
||||
.sizeimage = 1280 * 960,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.priv = 2
|
||||
},
|
||||
{1600, 1200, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
|
||||
.bytesperline = 1600,
|
||||
.sizeimage = 1600 * 1200,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.priv = 3
|
||||
},
|
||||
};
|
||||
|
||||
static struct v4l2_pix_format mi1320_mode[] = {
|
||||
{ 640, 480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
|
||||
.bytesperline = 640,
|
||||
.sizeimage = 640 * 480,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.priv = 0
|
||||
},
|
||||
{ 800, 600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
|
||||
.bytesperline = 800,
|
||||
.sizeimage = 800 * 600,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.priv = 1
|
||||
},
|
||||
{1280, 960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
|
||||
.bytesperline = 1280,
|
||||
.sizeimage = 1280 * 960,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.priv = 2
|
||||
},
|
||||
};
|
||||
|
||||
static struct v4l2_pix_format ov9655_mode[] = {
|
||||
{ 640, 480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
|
||||
.bytesperline = 640,
|
||||
.sizeimage = 640 * 480,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.priv = 0
|
||||
},
|
||||
{1280, 960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
|
||||
.bytesperline = 1280,
|
||||
.sizeimage = 1280 * 960,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.priv = 1
|
||||
},
|
||||
};
|
||||
|
||||
/*========================= sud-driver functions ===========================*/
|
||||
|
||||
/* This function is called at probe time */
|
||||
static int sd_config(struct gspca_dev *gspca_dev,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
struct cam *cam;
|
||||
s32 vendor_id, product_id;
|
||||
|
||||
/* Get USB VendorID and ProductID */
|
||||
vendor_id = le16_to_cpu(id->idVendor);
|
||||
product_id = le16_to_cpu(id->idProduct);
|
||||
|
||||
sd->nbRightUp = 1;
|
||||
sd->nbIm = -1;
|
||||
|
||||
sd->sensor = 0xff;
|
||||
if (strcmp(sensor, "MI1320") == 0)
|
||||
sd->sensor = ID_MI1320;
|
||||
else if (strcmp(sensor, "OV2640") == 0)
|
||||
sd->sensor = ID_OV2640;
|
||||
else if (strcmp(sensor, "OV9655") == 0)
|
||||
sd->sensor = ID_OV9655;
|
||||
else if (strcmp(sensor, "MI2020") == 0)
|
||||
sd->sensor = ID_MI2020;
|
||||
else if (strcmp(sensor, "MI2020b") == 0)
|
||||
sd->sensor = ID_MI2020b;
|
||||
|
||||
/* Get sensor and set the suitable init/start/../stop functions */
|
||||
if (gl860_guess_sensor(gspca_dev, vendor_id, product_id) == -1)
|
||||
return -1;
|
||||
|
||||
cam = &gspca_dev->cam;
|
||||
gspca_dev->nbalt = 4;
|
||||
|
||||
switch (sd->sensor) {
|
||||
case ID_MI1320:
|
||||
gspca_dev->sd_desc = &sd_desc_mi1320;
|
||||
cam->cam_mode = mi1320_mode;
|
||||
cam->nmodes = ARRAY_SIZE(mi1320_mode);
|
||||
dev_init_settings = mi1320_init_settings;
|
||||
break;
|
||||
|
||||
case ID_MI2020:
|
||||
gspca_dev->sd_desc = &sd_desc_mi2020;
|
||||
cam->cam_mode = mi2020_mode;
|
||||
cam->nmodes = ARRAY_SIZE(mi2020_mode);
|
||||
dev_init_settings = mi2020_init_settings;
|
||||
break;
|
||||
|
||||
case ID_MI2020b:
|
||||
gspca_dev->sd_desc = &sd_desc_mi2020b;
|
||||
cam->cam_mode = mi2020_mode;
|
||||
cam->nmodes = ARRAY_SIZE(mi2020_mode);
|
||||
dev_init_settings = mi2020_init_settings;
|
||||
break;
|
||||
|
||||
case ID_OV2640:
|
||||
gspca_dev->sd_desc = &sd_desc_ov2640;
|
||||
cam->cam_mode = ov2640_mode;
|
||||
cam->nmodes = ARRAY_SIZE(ov2640_mode);
|
||||
dev_init_settings = ov2640_init_settings;
|
||||
break;
|
||||
|
||||
case ID_OV9655:
|
||||
gspca_dev->sd_desc = &sd_desc_ov9655;
|
||||
cam->cam_mode = ov9655_mode;
|
||||
cam->nmodes = ARRAY_SIZE(ov9655_mode);
|
||||
dev_init_settings = ov9655_init_settings;
|
||||
break;
|
||||
}
|
||||
|
||||
dev_init_settings(gspca_dev);
|
||||
if (AC50Hz != 0xff)
|
||||
((struct sd *) gspca_dev)->vcur.AC50Hz = AC50Hz;
|
||||
gl860_build_control_table(gspca_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function is called at probe time after sd_config */
|
||||
static int sd_init(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
return sd->dev_init_at_startup(gspca_dev);
|
||||
}
|
||||
|
||||
/* This function is called before to choose the alt setting */
|
||||
static int sd_isoc_init(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
return sd->dev_configure_alt(gspca_dev);
|
||||
}
|
||||
|
||||
/* This function is called to start the webcam */
|
||||
static int sd_start(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
return sd->dev_init_pre_alt(gspca_dev);
|
||||
}
|
||||
|
||||
/* This function is called to stop the webcam */
|
||||
static void sd_stop0(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
return sd->dev_post_unset_alt(gspca_dev);
|
||||
}
|
||||
|
||||
/* This function is called when an image is being received */
|
||||
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
|
||||
struct gspca_frame *frame, u8 *data, s32 len)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
static s32 nSkipped;
|
||||
|
||||
s32 mode = (s32) gspca_dev->curr_mode;
|
||||
s32 nToSkip =
|
||||
sd->swapRB * (gspca_dev->cam.cam_mode[mode].bytesperline + 1);
|
||||
|
||||
/* Test only against 0202h, so endianess does not matter */
|
||||
switch (*(s16 *) data) {
|
||||
case 0x0202: /* End of frame, start a new one */
|
||||
frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0);
|
||||
nSkipped = 0;
|
||||
if (sd->nbIm >= 0 && sd->nbIm < 10)
|
||||
sd->nbIm++;
|
||||
gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
data += 2;
|
||||
len -= 2;
|
||||
if (nSkipped + len <= nToSkip)
|
||||
nSkipped += len;
|
||||
else {
|
||||
if (nSkipped < nToSkip && nSkipped + len > nToSkip) {
|
||||
data += nToSkip - nSkipped;
|
||||
len -= nToSkip - nSkipped;
|
||||
nSkipped = nToSkip + 1;
|
||||
}
|
||||
gspca_frame_add(gspca_dev,
|
||||
INTER_PACKET, frame, data, len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function is called when an image has been read */
|
||||
/* This function is used to monitor webcam orientation */
|
||||
static void sd_callback(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
if (!_OV9655_) {
|
||||
u8 state;
|
||||
u8 upsideDown;
|
||||
|
||||
/* Probe sensor orientation */
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, (void *)&state);
|
||||
|
||||
/* C8/40 means upside-down (looking backwards) */
|
||||
/* D8/50 means right-up (looking onwards) */
|
||||
upsideDown = (state == 0xc8 || state == 0x40);
|
||||
|
||||
if (upsideDown && sd->nbRightUp > -4) {
|
||||
if (sd->nbRightUp > 0)
|
||||
sd->nbRightUp = 0;
|
||||
if (sd->nbRightUp == -3) {
|
||||
sd->mirrorMask = 1;
|
||||
sd->waitSet = 1;
|
||||
}
|
||||
sd->nbRightUp--;
|
||||
}
|
||||
if (!upsideDown && sd->nbRightUp < 4) {
|
||||
if (sd->nbRightUp < 0)
|
||||
sd->nbRightUp = 0;
|
||||
if (sd->nbRightUp == 3) {
|
||||
sd->mirrorMask = 0;
|
||||
sd->waitSet = 1;
|
||||
}
|
||||
sd->nbRightUp++;
|
||||
}
|
||||
}
|
||||
|
||||
if (sd->waitSet)
|
||||
sd->dev_camera_settings(gspca_dev);
|
||||
}
|
||||
|
||||
/*=================== USB driver structure initialisation ==================*/
|
||||
|
||||
static const __devinitdata struct usb_device_id device_table[] = {
|
||||
{USB_DEVICE(0x05e3, 0x0503)},
|
||||
{USB_DEVICE(0x05e3, 0xf191)},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, device_table);
|
||||
|
||||
static int sd_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct gspca_dev *gspca_dev;
|
||||
s32 ret;
|
||||
|
||||
ret = gspca_dev_probe(intf, id,
|
||||
&sd_desc_mi1320, sizeof(struct sd), THIS_MODULE);
|
||||
|
||||
if (ret >= 0) {
|
||||
gspca_dev = usb_get_intfdata(intf);
|
||||
|
||||
PDEBUG(D_PROBE,
|
||||
"Camera is now controlling video device /dev/video%d",
|
||||
gspca_dev->vdev.minor);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sd_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
gspca_disconnect(intf);
|
||||
}
|
||||
|
||||
static struct usb_driver sd_driver = {
|
||||
.name = MODULE_NAME,
|
||||
.id_table = device_table,
|
||||
.probe = sd_probe,
|
||||
.disconnect = sd_disconnect,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = gspca_suspend,
|
||||
.resume = gspca_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
/*====================== Init and Exit module functions ====================*/
|
||||
|
||||
static int __init sd_mod_init(void)
|
||||
{
|
||||
PDEBUG(D_PROBE, "driver startup - version %s", DRIVER_VERSION);
|
||||
|
||||
if (usb_register(&sd_driver) < 0)
|
||||
return -1;
|
||||
PDEBUG(D_PROBE, "driver registered");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit sd_mod_exit(void)
|
||||
{
|
||||
usb_deregister(&sd_driver);
|
||||
PDEBUG(D_PROBE, "driver deregistered");
|
||||
}
|
||||
|
||||
module_init(sd_mod_init);
|
||||
module_exit(sd_mod_exit);
|
||||
|
||||
/*==========================================================================*/
|
||||
|
||||
int gl860_RTx(struct gspca_dev *gspca_dev,
|
||||
unsigned char pref, u32 req, u16 val, u16 index,
|
||||
s32 len, void *pdata)
|
||||
{
|
||||
struct usb_device *udev = gspca_dev->dev;
|
||||
s32 r = 0;
|
||||
|
||||
if (pref == 0x40) { /* Send */
|
||||
if (len > 0) {
|
||||
memcpy(gspca_dev->usb_buf, pdata, len);
|
||||
r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
|
||||
req, pref, val, index,
|
||||
gspca_dev->usb_buf,
|
||||
len, 400 + 200 * (len > 1));
|
||||
} else {
|
||||
r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
|
||||
req, pref, val, index, NULL, len, 400);
|
||||
}
|
||||
} else { /* Receive */
|
||||
if (len > 0) {
|
||||
r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
|
||||
req, pref, val, index,
|
||||
gspca_dev->usb_buf,
|
||||
len, 400 + 200 * (len > 1));
|
||||
memcpy(pdata, gspca_dev->usb_buf, len);
|
||||
} else {
|
||||
r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
|
||||
req, pref, val, index, NULL, len, 400);
|
||||
}
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
PDEBUG(D_ERR,
|
||||
"ctrl transfer failed %4d "
|
||||
"[p%02x r%d v%04x i%04x len%d]",
|
||||
r, pref, req, val, index, len);
|
||||
else if (len > 1 && r < len)
|
||||
PDEBUG(D_ERR, "short ctrl transfer %d/%d", r, len);
|
||||
|
||||
if ((_MI2020_ || _MI2020b_ || _MI2020c_) && (val || index))
|
||||
msleep(1);
|
||||
if (_OV2640_)
|
||||
msleep(1);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int fetch_validx(struct gspca_dev *gspca_dev, struct validx *tbl, int len)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; n < len; n++) {
|
||||
if (tbl[n].idx != 0xffff)
|
||||
ctrl_out(gspca_dev, 0x40, 1, tbl[n].val,
|
||||
tbl[n].idx, 0, NULL);
|
||||
else if (tbl[n].val == 0xffff)
|
||||
break;
|
||||
else
|
||||
msleep(tbl[n].val);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int keep_on_fetching_validx(struct gspca_dev *gspca_dev, struct validx *tbl,
|
||||
int len, int n)
|
||||
{
|
||||
while (++n < len) {
|
||||
if (tbl[n].idx != 0xffff)
|
||||
ctrl_out(gspca_dev, 0x40, 1, tbl[n].val, tbl[n].idx,
|
||||
0, NULL);
|
||||
else if (tbl[n].val == 0xffff)
|
||||
break;
|
||||
else
|
||||
msleep(tbl[n].val);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void fetch_idxdata(struct gspca_dev *gspca_dev, struct idxdata *tbl, int len)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; n < len; n++) {
|
||||
if (memcmp(tbl[n].data, "\xff\xff\xff", 3) != 0)
|
||||
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, tbl[n].idx,
|
||||
3, tbl[n].data);
|
||||
else
|
||||
msleep(tbl[n].idx);
|
||||
}
|
||||
}
|
||||
|
||||
static int gl860_guess_sensor(struct gspca_dev *gspca_dev,
|
||||
s32 vendor_id, s32 product_id)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
u8 probe, nb26, nb96, nOV, ntry;
|
||||
|
||||
if (product_id == 0xf191)
|
||||
sd->sensor = ID_MI1320;
|
||||
|
||||
if (sd->sensor == 0xff) {
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &probe);
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &probe);
|
||||
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x0000, 0, NULL);
|
||||
msleep(3);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL);
|
||||
msleep(3);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0008, 0x00c0, 0, NULL);
|
||||
msleep(3);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x00c1, 0, NULL);
|
||||
msleep(3);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x00c2, 0, NULL);
|
||||
msleep(3);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0020, 0x0006, 0, NULL);
|
||||
msleep(3);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x006a, 0x000d, 0, NULL);
|
||||
msleep(56);
|
||||
|
||||
nOV = 0;
|
||||
for (ntry = 0; ntry < 4; ntry++) {
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
|
||||
msleep(3);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0063, 0x0006, 0, NULL);
|
||||
msleep(3);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x7a00, 0x8030, 0, NULL);
|
||||
msleep(10);
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x7a00, 0x8030, 1, &probe);
|
||||
PDEBUG(D_PROBE, "1st probe=%02x", probe);
|
||||
if (probe == 0xff)
|
||||
nOV++;
|
||||
}
|
||||
|
||||
if (nOV) {
|
||||
PDEBUG(D_PROBE, "0xff -> sensor OVXXXX");
|
||||
PDEBUG(D_PROBE, "Probing for sensor OV2640 or OV9655");
|
||||
|
||||
nb26 = nb96 = 0;
|
||||
for (ntry = 0; ntry < 4; ntry++) {
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000,
|
||||
0, NULL);
|
||||
msleep(3);
|
||||
ctrl_out(gspca_dev, 0x40, 1, 0x6000, 0x800a,
|
||||
0, NULL);
|
||||
msleep(10);
|
||||
/* Wait for 26(OV2640) or 96(OV9655) */
|
||||
ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x800a,
|
||||
1, &probe);
|
||||
|
||||
PDEBUG(D_PROBE, "2nd probe=%02x", probe);
|
||||
if (probe == 0x00)
|
||||
nb26++;
|
||||
if (probe == 0x26 || probe == 0x40) {
|
||||
sd->sensor = ID_OV2640;
|
||||
nb26 += 4;
|
||||
break;
|
||||
}
|
||||
if (probe == 0x96 || probe == 0x55) {
|
||||
sd->sensor = ID_OV9655;
|
||||
nb96 += 4;
|
||||
break;
|
||||
}
|
||||
if (probe == 0xff)
|
||||
nb96++;
|
||||
msleep(3);
|
||||
}
|
||||
if (nb26 < 4 && nb96 < 4) {
|
||||
PDEBUG(D_PROBE, "No relevant answer ");
|
||||
PDEBUG(D_PROBE, "* 1.3Mpixels -> use OV9655");
|
||||
PDEBUG(D_PROBE, "* 2.0Mpixels -> use OV2640");
|
||||
PDEBUG(D_PROBE,
|
||||
"To force a sensor, add that line to "
|
||||
"/etc/modprobe.d/options.conf:");
|
||||
PDEBUG(D_PROBE, "options gspca_gl860 "
|
||||
"sensor=\"OV2640\" or \"OV9655\"");
|
||||
return -1;
|
||||
}
|
||||
} else { /* probe = 0 */
|
||||
PDEBUG(D_PROBE, "No 0xff -> sensor MI2020");
|
||||
sd->sensor = ID_MI2020;
|
||||
}
|
||||
}
|
||||
|
||||
if (_MI1320_) {
|
||||
PDEBUG(D_PROBE, "05e3:f191 sensor MI1320 (1.3M)");
|
||||
} else if (_MI2020_) {
|
||||
PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 (2.0M)");
|
||||
} else if (_MI2020b_) {
|
||||
PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 alt. driver (2.0M)");
|
||||
} else if (_OV9655_) {
|
||||
PDEBUG(D_PROBE, "05e3:0503 sensor OV9655 (1.3M)");
|
||||
} else if (_OV2640_) {
|
||||
PDEBUG(D_PROBE, "05e3:0503 sensor OV2640 (2.0M)");
|
||||
} else {
|
||||
PDEBUG(D_PROBE, "***** Unknown sensor *****");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
108
drivers/media/video/gspca/gl860/gl860.h
Normal file
108
drivers/media/video/gspca/gl860/gl860.h
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/* @file gl860.h
|
||||
* @author Olivier LORIN, tiré du pilote Syntek par Nicolas VIVIEN
|
||||
* @date 2009-08-27
|
||||
*
|
||||
* 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
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef GL860_DEV_H
|
||||
#define GL860_DEV_H
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "gspca.h"
|
||||
|
||||
#define MODULE_NAME "gspca_gl860"
|
||||
#define DRIVER_VERSION "0.9d10"
|
||||
|
||||
#define ctrl_in gl860_RTx
|
||||
#define ctrl_out gl860_RTx
|
||||
|
||||
#define ID_MI1320 1
|
||||
#define ID_OV2640 2
|
||||
#define ID_OV9655 4
|
||||
#define ID_MI2020 8
|
||||
#define ID_MI2020b 16
|
||||
|
||||
#define _MI1320_ (((struct sd *) gspca_dev)->sensor == ID_MI1320)
|
||||
#define _MI2020_ (((struct sd *) gspca_dev)->sensor == ID_MI2020)
|
||||
#define _MI2020b_ (((struct sd *) gspca_dev)->sensor == ID_MI2020b)
|
||||
#define _MI2020c_ 0
|
||||
#define _OV2640_ (((struct sd *) gspca_dev)->sensor == ID_OV2640)
|
||||
#define _OV9655_ (((struct sd *) gspca_dev)->sensor == ID_OV9655)
|
||||
|
||||
#define IMAGE_640 0
|
||||
#define IMAGE_800 1
|
||||
#define IMAGE_1280 2
|
||||
#define IMAGE_1600 3
|
||||
|
||||
struct sd_gl860 {
|
||||
u16 backlight;
|
||||
u16 brightness;
|
||||
u16 sharpness;
|
||||
u16 contrast;
|
||||
u16 gamma;
|
||||
u16 hue;
|
||||
u16 saturation;
|
||||
u16 whitebal;
|
||||
u8 mirror;
|
||||
u8 flip;
|
||||
u8 AC50Hz;
|
||||
};
|
||||
|
||||
/* Specific webcam descriptor */
|
||||
struct sd {
|
||||
struct gspca_dev gspca_dev; /* !! must be the first item */
|
||||
|
||||
struct sd_gl860 vcur;
|
||||
struct sd_gl860 vold;
|
||||
struct sd_gl860 vmax;
|
||||
|
||||
int (*dev_configure_alt) (struct gspca_dev *);
|
||||
int (*dev_init_at_startup)(struct gspca_dev *);
|
||||
int (*dev_init_pre_alt) (struct gspca_dev *);
|
||||
void (*dev_post_unset_alt) (struct gspca_dev *);
|
||||
int (*dev_camera_settings)(struct gspca_dev *);
|
||||
|
||||
u8 swapRB;
|
||||
u8 mirrorMask;
|
||||
u8 sensor;
|
||||
s32 nbIm;
|
||||
s32 nbRightUp;
|
||||
u8 waitSet;
|
||||
};
|
||||
|
||||
struct validx {
|
||||
u16 val;
|
||||
u16 idx;
|
||||
};
|
||||
|
||||
struct idxdata {
|
||||
u8 idx;
|
||||
u8 data[3];
|
||||
};
|
||||
|
||||
int fetch_validx(struct gspca_dev *gspca_dev, struct validx *tbl, int len);
|
||||
int keep_on_fetching_validx(struct gspca_dev *gspca_dev, struct validx *tbl,
|
||||
int len, int n);
|
||||
void fetch_idxdata(struct gspca_dev *gspca_dev, struct idxdata *tbl, int len);
|
||||
|
||||
int gl860_RTx(struct gspca_dev *gspca_dev,
|
||||
unsigned char pref, u32 req, u16 val, u16 index,
|
||||
s32 len, void *pdata);
|
||||
|
||||
void mi1320_init_settings(struct gspca_dev *);
|
||||
void ov2640_init_settings(struct gspca_dev *);
|
||||
void ov9655_init_settings(struct gspca_dev *);
|
||||
void mi2020_init_settings(struct gspca_dev *);
|
||||
|
||||
#endif
|
||||
|
|
@ -312,6 +312,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
|
|||
|
||||
/* create the JPEG header */
|
||||
dev->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
|
||||
if (dev->jpeg_hdr == NULL)
|
||||
return -ENOMEM;
|
||||
jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width,
|
||||
0x21); /* JPEG 422 */
|
||||
jpeg_set_qual(dev->jpeg_hdr, dev->quality);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,18 @@
|
|||
|
||||
static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val);
|
||||
static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
|
||||
__s32 *val);
|
||||
static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
|
||||
__s32 val);
|
||||
static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
|
||||
static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
|
||||
static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
|
||||
static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
|
||||
|
||||
const static struct ctrl ov7660_ctrls[] = {
|
||||
#define GAIN_IDX 1
|
||||
|
|
@ -37,6 +49,79 @@ const static struct ctrl ov7660_ctrls[] = {
|
|||
.set = ov7660_set_gain,
|
||||
.get = ov7660_get_gain
|
||||
},
|
||||
#define BLUE_BALANCE_IDX 2
|
||||
#define RED_BALANCE_IDX 3
|
||||
#define AUTO_WHITE_BALANCE_IDX 4
|
||||
{
|
||||
{
|
||||
.id = V4L2_CID_AUTO_WHITE_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
.name = "auto white balance",
|
||||
.minimum = 0,
|
||||
.maximum = 1,
|
||||
.step = 1,
|
||||
.default_value = 1
|
||||
},
|
||||
.set = ov7660_set_auto_white_balance,
|
||||
.get = ov7660_get_auto_white_balance
|
||||
},
|
||||
#define AUTO_GAIN_CTRL_IDX 5
|
||||
{
|
||||
{
|
||||
.id = V4L2_CID_AUTOGAIN,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
.name = "auto gain control",
|
||||
.minimum = 0,
|
||||
.maximum = 1,
|
||||
.step = 1,
|
||||
.default_value = 1
|
||||
},
|
||||
.set = ov7660_set_auto_gain,
|
||||
.get = ov7660_get_auto_gain
|
||||
},
|
||||
#define AUTO_EXPOSURE_IDX 6
|
||||
{
|
||||
{
|
||||
.id = V4L2_CID_EXPOSURE_AUTO,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
.name = "auto exposure",
|
||||
.minimum = 0,
|
||||
.maximum = 1,
|
||||
.step = 1,
|
||||
.default_value = 1
|
||||
},
|
||||
.set = ov7660_set_auto_exposure,
|
||||
.get = ov7660_get_auto_exposure
|
||||
},
|
||||
#define HFLIP_IDX 7
|
||||
{
|
||||
{
|
||||
.id = V4L2_CID_HFLIP,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
.name = "horizontal flip",
|
||||
.minimum = 0,
|
||||
.maximum = 1,
|
||||
.step = 1,
|
||||
.default_value = 0
|
||||
},
|
||||
.set = ov7660_set_hflip,
|
||||
.get = ov7660_get_hflip
|
||||
},
|
||||
#define VFLIP_IDX 8
|
||||
{
|
||||
{
|
||||
.id = V4L2_CID_VFLIP,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
.name = "vertical flip",
|
||||
.minimum = 0,
|
||||
.maximum = 1,
|
||||
.step = 1,
|
||||
.default_value = 0
|
||||
},
|
||||
.set = ov7660_set_vflip,
|
||||
.get = ov7660_get_vflip
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
static struct v4l2_pix_format ov7660_modes[] = {
|
||||
|
|
@ -137,7 +222,7 @@ int ov7660_init(struct sd *sd)
|
|||
} else {
|
||||
data[0] = init_ov7660[i][2];
|
||||
err = m5602_write_sensor(sd,
|
||||
init_ov7660[i][1], data, 1);
|
||||
init_ov7660[i][1], data, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -148,6 +233,28 @@ int ov7660_init(struct sd *sd)
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = ov7660_set_auto_white_balance(&sd->gspca_dev,
|
||||
sensor_settings[AUTO_WHITE_BALANCE_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = ov7660_set_auto_gain(&sd->gspca_dev,
|
||||
sensor_settings[AUTO_GAIN_CTRL_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = ov7660_set_auto_exposure(&sd->gspca_dev,
|
||||
sensor_settings[AUTO_EXPOSURE_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = ov7660_set_hflip(&sd->gspca_dev,
|
||||
sensor_settings[HFLIP_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = ov7660_set_vflip(&sd->gspca_dev,
|
||||
sensor_settings[VFLIP_IDX]);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -194,6 +301,159 @@ static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val)
|
|||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
|
||||
__s32 *val)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
*val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
|
||||
__s32 val)
|
||||
{
|
||||
int err;
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
PDEBUG(D_V4L2, "Set auto white balance to %d", val);
|
||||
|
||||
sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
|
||||
err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
|
||||
err = m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
*val = sensor_settings[AUTO_GAIN_CTRL_IDX];
|
||||
PDEBUG(D_V4L2, "Read auto gain control %d", *val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
|
||||
{
|
||||
int err;
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
PDEBUG(D_V4L2, "Set auto gain control to %d", val);
|
||||
|
||||
sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
|
||||
err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
|
||||
|
||||
return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
|
||||
}
|
||||
|
||||
static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
*val = sensor_settings[AUTO_EXPOSURE_IDX];
|
||||
PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev,
|
||||
__s32 val)
|
||||
{
|
||||
int err;
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
|
||||
|
||||
sensor_settings[AUTO_EXPOSURE_IDX] = val;
|
||||
err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
|
||||
|
||||
return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
|
||||
}
|
||||
|
||||
static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
*val = sensor_settings[HFLIP_IDX];
|
||||
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
{
|
||||
int err;
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
|
||||
|
||||
sensor_settings[HFLIP_IDX] = val;
|
||||
|
||||
i2c_data = ((val & 0x01) << 5) |
|
||||
(sensor_settings[VFLIP_IDX] << 4);
|
||||
|
||||
err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
*val = sensor_settings[VFLIP_IDX];
|
||||
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
{
|
||||
int err;
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
PDEBUG(D_V4L2, "Set vertical flip to %d", val);
|
||||
sensor_settings[VFLIP_IDX] = val;
|
||||
|
||||
i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
|
||||
err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* When vflip is toggled we need to readjust the bridge hsync/vsync */
|
||||
if (gspca_dev->streaming)
|
||||
err = ov7660_start(sd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void ov7660_dump_registers(struct sd *sd)
|
||||
{
|
||||
int address;
|
||||
|
|
|
|||
|
|
@ -66,23 +66,23 @@
|
|||
#define OV7660_RBIAS 0x2c
|
||||
#define OV7660_HREF 0x32
|
||||
#define OV7660_ADC 0x37
|
||||
#define OV7660_OFON 0x39
|
||||
#define OV7660_TSLB 0x3a
|
||||
#define OV7660_COM12 0x3c
|
||||
#define OV7660_COM13 0x3d
|
||||
#define OV7660_OFON 0x39
|
||||
#define OV7660_TSLB 0x3a
|
||||
#define OV7660_COM12 0x3c
|
||||
#define OV7660_COM13 0x3d
|
||||
#define OV7660_LCC1 0x62
|
||||
#define OV7660_LCC2 0x63
|
||||
#define OV7660_LCC3 0x64
|
||||
#define OV7660_LCC4 0x65
|
||||
#define OV7660_LCC5 0x66
|
||||
#define OV7660_HV 0x69
|
||||
#define OV7660_RSVDA1 0xa1
|
||||
#define OV7660_HV 0x69
|
||||
#define OV7660_RSVDA1 0xa1
|
||||
|
||||
#define OV7660_DEFAULT_GAIN 0x0e
|
||||
#define OV7660_DEFAULT_RED_GAIN 0x80
|
||||
#define OV7660_DEFAULT_RED_GAIN 0x80
|
||||
#define OV7660_DEFAULT_BLUE_GAIN 0x80
|
||||
#define OV7660_DEFAULT_SATURATION 0x00
|
||||
#define OV7660_DEFAULT_EXPOSURE 0x20
|
||||
#define OV7660_DEFAULT_EXPOSURE 0x20
|
||||
|
||||
/* Kernel module parameters */
|
||||
extern int force_sensor;
|
||||
|
|
@ -149,22 +149,8 @@ static const unsigned char init_ov7660[][4] =
|
|||
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
|
||||
{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
|
||||
{BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
|
||||
{BRIDGE, M5602_XB_GPIO_DIR, 0x03},
|
||||
{BRIDGE, M5602_XB_GPIO_DIR, 0x03},
|
||||
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
|
||||
{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
|
||||
|
||||
{SENSOR, OV7660_OFON, 0x0c},
|
||||
{SENSOR, OV7660_COM2, 0x11},
|
||||
{SENSOR, OV7660_COM7, 0x05},
|
||||
|
||||
{BRIDGE, M5602_XB_GPIO_DIR, 0x01},
|
||||
{BRIDGE, M5602_XB_GPIO_DAT, 0x04},
|
||||
{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
|
||||
{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
|
||||
{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
|
||||
{BRIDGE, M5602_XB_GPIO_DIR, 0x01},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
|
||||
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
|
||||
|
|
@ -173,34 +159,8 @@ static const unsigned char init_ov7660[][4] =
|
|||
{BRIDGE, M5602_XB_GPIO_DAT, 0x00},
|
||||
{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
|
||||
{BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
|
||||
|
||||
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x02},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
|
||||
|
||||
{SENSOR, OV7660_AECH, OV7660_DEFAULT_EXPOSURE},
|
||||
{SENSOR, OV7660_COM1, 0x00},
|
||||
|
||||
{BRIDGE, M5602_XB_GPIO_DIR, 0x01},
|
||||
{BRIDGE, M5602_XB_GPIO_DAT, 0x04},
|
||||
{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
|
||||
{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
|
||||
{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
|
||||
|
||||
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
|
||||
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
|
||||
{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
|
||||
{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
|
||||
{BRIDGE, M5602_XB_GPIO_DAT, 0x00},
|
||||
{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
|
||||
{BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
|
||||
|
||||
{SENSOR, OV7660_COM7, 0x80},
|
||||
{SENSOR, OV7660_CLKRC, 0x80},
|
||||
{SENSOR, OV7660_BLUE_GAIN, 0x80},
|
||||
{SENSOR, OV7660_RED_GAIN, 0x80},
|
||||
{SENSOR, OV7660_COM9, 0x4c},
|
||||
{SENSOR, OV7660_OFON, 0x43},
|
||||
{SENSOR, OV7660_COM12, 0x28},
|
||||
|
|
@ -212,17 +172,17 @@ static const unsigned char init_ov7660[][4] =
|
|||
{SENSOR, OV7660_PSHFT, 0x0b},
|
||||
{SENSOR, OV7660_VSTART, 0x01},
|
||||
{SENSOR, OV7660_VSTOP, 0x7a},
|
||||
{SENSOR, OV7660_VREF, 0x00},
|
||||
{SENSOR, OV7660_VSTOP, 0x00},
|
||||
{SENSOR, OV7660_COM7, 0x05},
|
||||
{SENSOR, OV7660_COM6, 0x4b},
|
||||
{SENSOR, OV7660_BBIAS, 0x98},
|
||||
{SENSOR, OV7660_GbBIAS, 0x98},
|
||||
{SENSOR, OV7660_RSVD29, 0x98},
|
||||
{SENSOR, OV7660_RBIAS, 0x98},
|
||||
{SENSOR, OV7660_COM6, 0x42},
|
||||
{SENSOR, OV7660_BBIAS, 0x94},
|
||||
{SENSOR, OV7660_GbBIAS, 0x94},
|
||||
{SENSOR, OV7660_RSVD29, 0x94},
|
||||
{SENSOR, OV7660_RBIAS, 0x94},
|
||||
{SENSOR, OV7660_COM1, 0x00},
|
||||
{SENSOR, OV7660_AECH, 0x00},
|
||||
{SENSOR, OV7660_AECHH, 0x00},
|
||||
{SENSOR, OV7660_ADC, 0x04},
|
||||
{SENSOR, OV7660_ADC, 0x05},
|
||||
{SENSOR, OV7660_COM13, 0x00},
|
||||
{SENSOR, OV7660_RSVDA1, 0x23},
|
||||
{SENSOR, OV7660_TSLB, 0x0d},
|
||||
|
|
@ -233,6 +193,47 @@ static const unsigned char init_ov7660[][4] =
|
|||
{SENSOR, OV7660_LCC4, 0x40},
|
||||
{SENSOR, OV7660_LCC5, 0x01},
|
||||
|
||||
{SENSOR, OV7660_AECH, 0x20},
|
||||
{SENSOR, OV7660_COM1, 0x00},
|
||||
{SENSOR, OV7660_OFON, 0x0c},
|
||||
{SENSOR, OV7660_COM2, 0x11},
|
||||
{SENSOR, OV7660_COM7, 0x05},
|
||||
{BRIDGE, M5602_XB_GPIO_DIR, 0x01},
|
||||
{BRIDGE, M5602_XB_GPIO_DAT, 0x04},
|
||||
{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
|
||||
{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
|
||||
{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
|
||||
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
|
||||
{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
|
||||
{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
|
||||
{BRIDGE, M5602_XB_GPIO_DAT, 0x00},
|
||||
{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
|
||||
{BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
|
||||
{SENSOR, OV7660_AECH, 0x5f},
|
||||
{SENSOR, OV7660_COM1, 0x03},
|
||||
{SENSOR, OV7660_OFON, 0x0c},
|
||||
{SENSOR, OV7660_COM2, 0x11},
|
||||
{SENSOR, OV7660_COM7, 0x05},
|
||||
{BRIDGE, M5602_XB_GPIO_DIR, 0x01},
|
||||
{BRIDGE, M5602_XB_GPIO_DAT, 0x04},
|
||||
{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
|
||||
{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
|
||||
{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
|
||||
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
|
||||
{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
|
||||
{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
|
||||
{BRIDGE, M5602_XB_GPIO_DAT, 0x00},
|
||||
{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
|
||||
{BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
|
||||
|
||||
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
|
||||
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
|
||||
|
|
@ -245,35 +246,18 @@ static const unsigned char init_ov7660[][4] =
|
|||
{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
|
||||
{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
|
||||
{BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
|
||||
{BRIDGE, M5602_XB_VSYNC_PARA, 0xe0}, /* 480 */
|
||||
{BRIDGE, M5602_XB_VSYNC_PARA, 0xec},
|
||||
{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
|
||||
{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
|
||||
{BRIDGE, M5602_XB_SIG_INI, 0x00},
|
||||
{BRIDGE, M5602_XB_SIG_INI, 0x02},
|
||||
{BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
|
||||
{BRIDGE, M5602_XB_VSYNC_PARA, 0x27}, /* 39 */
|
||||
{BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
|
||||
{BRIDGE, M5602_XB_VSYNC_PARA, 0xa7}, /* 679 */
|
||||
{BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
|
||||
{BRIDGE, M5602_XB_HSYNC_PARA, 0x27},
|
||||
{BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
|
||||
{BRIDGE, M5602_XB_HSYNC_PARA, 0xa7},
|
||||
{BRIDGE, M5602_XB_SIG_INI, 0x00},
|
||||
|
||||
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
|
||||
|
||||
{SENSOR, OV7660_AECH, 0x20},
|
||||
{SENSOR, OV7660_COM1, 0x00},
|
||||
{SENSOR, OV7660_OFON, 0x0c},
|
||||
{SENSOR, OV7660_COM2, 0x11},
|
||||
{SENSOR, OV7660_COM7, 0x05},
|
||||
{SENSOR, OV7660_BLUE_GAIN, 0x80},
|
||||
{SENSOR, OV7660_RED_GAIN, 0x80},
|
||||
|
||||
{BRIDGE, M5602_XB_GPIO_DIR, 0x01},
|
||||
{BRIDGE, M5602_XB_GPIO_DAT, 0x04},
|
||||
{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
|
||||
{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
|
||||
{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
|
||||
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -46,6 +46,12 @@ static
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
|
||||
}
|
||||
}, {
|
||||
.ident = "Fujitsu-Siemens Amilo Pa 2548",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
|
||||
}
|
||||
}, {
|
||||
.ident = "MSI GX700",
|
||||
.matches = {
|
||||
|
|
@ -53,6 +59,13 @@ static
|
|||
DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
|
||||
DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
|
||||
}
|
||||
}, {
|
||||
.ident = "MSI GX700",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
|
||||
DMI_MATCH(DMI_BIOS_DATE, "07/19/2007")
|
||||
}
|
||||
}, {
|
||||
.ident = "MSI GX700/GX705/EX700",
|
||||
.matches = {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue