diff options
Diffstat (limited to 'drivers/media')
473 files changed, 23455 insertions, 6623 deletions
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 1570992..3ef3d6c 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -95,7 +95,7 @@ config MEDIA_CONTROLLER This API is mostly used by camera interfaces in embedded platforms. config MEDIA_CONTROLLER_DVB - bool "Enable Media controller for DVB" + bool "Enable Media controller for DVB (EXPERIMENTAL)" depends on MEDIA_CONTROLLER depends on BROKEN ---help--- diff --git a/drivers/media/common/b2c2/Kconfig b/drivers/media/common/b2c2/Kconfig index a8c6cdf..e593638 100644 --- a/drivers/media/common/b2c2/Kconfig +++ b/drivers/media/common/b2c2/Kconfig @@ -14,6 +14,7 @@ config DVB_B2C2_FLEXCOP select DVB_S5H1420 if MEDIA_SUBDRV_AUTOSELECT select DVB_TUNER_ITD1000 if MEDIA_SUBDRV_AUTOSELECT select DVB_ISL6421 if MEDIA_SUBDRV_AUTOSELECT + select DVB_CX24120 if MEDIA_SUBDRV_AUTOSELECT select DVB_CX24123 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT select DVB_TUNER_CX24113 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/common/b2c2/flexcop-common.h b/drivers/media/common/b2c2/flexcop-common.h index 437912e..2b2460e 100644 --- a/drivers/media/common/b2c2/flexcop-common.h +++ b/drivers/media/common/b2c2/flexcop-common.h @@ -91,6 +91,7 @@ struct flexcop_device { int feedcount; int pid_filtering; int fullts_streaming_state; + int skip_6_hw_pid_filter; /* bus specific callbacks */ flexcop_ibi_value(*read_ibi_reg) (struct flexcop_device *, diff --git a/drivers/media/common/b2c2/flexcop-fe-tuner.c b/drivers/media/common/b2c2/flexcop-fe-tuner.c index 7e14e90..9c59f43 100644 --- a/drivers/media/common/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/common/b2c2/flexcop-fe-tuner.c @@ -12,6 +12,7 @@ #include "cx24113.h" #include "cx24123.h" #include "isl6421.h" +#include "cx24120.h" #include "mt352.h" #include "bcm3510.h" #include "nxt200x.h" @@ -26,9 +27,20 @@ #define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \ (defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE))) +#if FE_SUPPORTED(BCM3510) || (FE_SUPPORTED(CX24120) && FE_SUPPORTED(ISL6421)) +static int flexcop_fe_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char *name) +{ + struct flexcop_device *fc = fe->dvb->priv; + + return request_firmware(fw, name, fc->dev); +} +#endif + /* lnb control */ #if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299) -static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int flexcop_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct flexcop_device *fc = fe->dvb->priv; flexcop_ibi_value v; @@ -67,7 +79,7 @@ static int flexcop_sleep(struct dvb_frontend* fe) /* SkyStar2 DVB-S rev 2.3 */ #if FE_SUPPORTED(MT312) && FE_SUPPORTED(PLL) -static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +static int flexcop_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) { /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */ struct flexcop_device *fc = fe->dvb->priv; @@ -146,7 +158,7 @@ static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe, } static int flexcop_diseqc_send_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t minicmd) + enum fe_sec_mini_cmd minicmd) { return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd); } @@ -445,13 +457,6 @@ static int airstar_dvbt_attach(struct flexcop_device *fc, /* AirStar ATSC 1st generation */ #if FE_SUPPORTED(BCM3510) -static int flexcop_fe_request_firmware(struct dvb_frontend *fe, - const struct firmware **fw, char* name) -{ - struct flexcop_device *fc = fe->dvb->priv; - return request_firmware(fw, name, fc->dev); -} - static struct bcm3510_config air2pc_atsc_first_gen_config = { .demod_address = 0x0f, .request_firmware = flexcop_fe_request_firmware, @@ -619,6 +624,43 @@ fail: #define cablestar2_attach NULL #endif +/* SkyStar S2 PCI DVB-S/S2 card based on Conexant cx24120/cx24118 */ +#if FE_SUPPORTED(CX24120) && FE_SUPPORTED(ISL6421) +static const struct cx24120_config skystar2_rev3_3_cx24120_config = { + .i2c_addr = 0x55, + .xtal_khz = 10111, + .initial_mpeg_config = { 0xa1, 0x76, 0x07 }, + .request_firmware = flexcop_fe_request_firmware, + .i2c_wr_max = 4, +}; + +static int skystarS2_rev33_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(cx24120_attach, + &skystar2_rev3_3_cx24120_config, i2c); + if (!fc->fe) + return 0; + + fc->dev_type = FC_SKYS2_REV33; + fc->fc_i2c_adap[2].no_base_addr = 1; + if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, + 0x08, 0, 0, false)) { + err("ISL6421 could NOT be attached!"); + fc->fc_i2c_adap[2].no_base_addr = 0; + return 0; + } + info("ISL6421 successfully attached."); + + if (fc->has_32_hw_pid_filter) + fc->skip_6_hw_pid_filter = 1; + + return 1; +} +#else +#define skystarS2_rev33_attach NULL +#endif + static struct { flexcop_device_type_t type; int (*attach)(struct flexcop_device *, struct i2c_adapter *); @@ -632,6 +674,7 @@ static struct { { FC_AIR_ATSC1, airstar_atsc1_attach }, { FC_CABLE, cablestar2_attach }, { FC_SKY_REV23, skystar2_rev23_attach }, + { FC_SKYS2_REV33, skystarS2_rev33_attach }, }; /* try to figure out the frontend */ diff --git a/drivers/media/common/b2c2/flexcop-hw-filter.c b/drivers/media/common/b2c2/flexcop-hw-filter.c index 77e4547..8220257 100644 --- a/drivers/media/common/b2c2/flexcop-hw-filter.c +++ b/drivers/media/common/b2c2/flexcop-hw-filter.c @@ -117,6 +117,10 @@ static void flexcop_pid_control(struct flexcop_device *fc, deb_ts("setting pid: %5d %04x at index %d '%s'\n", pid, pid, index, onoff ? "on" : "off"); + /* First 6 can be buggy - skip over them if option set */ + if (fc->skip_6_hw_pid_filter) + index += 6; + /* We could use bit magic here to reduce source code size. * I decided against it, but to use the real register names */ switch (index) { @@ -170,7 +174,10 @@ static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc, int onoff) int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff) { - int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32; + int max_pid_filter = 6; + + max_pid_filter -= 6 * fc->skip_6_hw_pid_filter; + max_pid_filter += 32 * fc->has_32_hw_pid_filter; fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */ if (dvbdmxfeed->index >= max_pid_filter) @@ -217,7 +224,12 @@ void flexcop_hw_filter_init(struct flexcop_device *fc) { int i; flexcop_ibi_value v; - for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++) + int max_pid_filter = 6; + + max_pid_filter -= 6 * fc->skip_6_hw_pid_filter; + max_pid_filter += 32 * fc->has_32_hw_pid_filter; + + for (i = 0; i < max_pid_filter; i++) flexcop_pid_control(fc, i, 0x1fff, 0); flexcop_pid_group_filter(fc, 0, 0x1fe0); diff --git a/drivers/media/common/b2c2/flexcop-misc.c b/drivers/media/common/b2c2/flexcop-misc.c index f06f3a9..b8eff23 100644 --- a/drivers/media/common/b2c2/flexcop-misc.c +++ b/drivers/media/common/b2c2/flexcop-misc.c @@ -56,6 +56,7 @@ static const char *flexcop_device_names[] = { [FC_SKY_REV26] = "Sky2PC/SkyStar 2 DVB-S rev 2.6", [FC_SKY_REV27] = "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u", [FC_SKY_REV28] = "Sky2PC/SkyStar 2 DVB-S rev 2.8", + [FC_SKYS2_REV33] = "Sky2PC/SkyStar S2 DVB-S/S2 rev 3.3", }; static const char *flexcop_bus_names[] = { diff --git a/drivers/media/common/b2c2/flexcop-reg.h b/drivers/media/common/b2c2/flexcop-reg.h index dc4528d..835c54d 100644 --- a/drivers/media/common/b2c2/flexcop-reg.h +++ b/drivers/media/common/b2c2/flexcop-reg.h @@ -24,6 +24,7 @@ typedef enum { FC_SKY_REV26, FC_SKY_REV27, FC_SKY_REV28, + FC_SKYS2_REV33, } flexcop_device_type_t; typedef enum { diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index eb8bd68..4cc39e4 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -1010,6 +1010,7 @@ struct sms_rx_stats_ex { s32 mrc_in_band_pwr; /* In band power in dBM */ }; +#define SRVM_MAX_PID_FILTERS 8 /* statistics information returned as response for * SmsHostApiGetstatisticsEx_Req for DVB applications, SMS1100 and up */ @@ -1021,7 +1022,6 @@ struct sms_stats_dvb { struct sms_tx_stats transmission_data; /* Burst parameters, valid only for DVB-H */ -#define SRVM_MAX_PID_FILTERS 8 struct sms_pid_data pid_data[SRVM_MAX_PID_FILTERS]; }; @@ -1035,7 +1035,6 @@ struct sms_stats_dvb_ex { struct sms_tx_stats transmission_data; /* Burst parameters, valid only for DVB-H */ -#define SRVM_MAX_PID_FILTERS 8 struct sms_pid_data pid_data[SRVM_MAX_PID_FILTERS]; }; diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index 367b8e7..f4305ae 100644 --- a/drivers/media/common/siano/smsdvb-main.c +++ b/drivers/media/common/siano/smsdvb-main.c @@ -753,7 +753,7 @@ static inline int led_feedback(struct smsdvb_client_t *client) SMS_LED_HI : SMS_LED_LO); } -static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat) +static int smsdvb_read_status(struct dvb_frontend *fe, enum fe_status *stat) { int rc; struct smsdvb_client_t *client; @@ -900,7 +900,7 @@ static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe) /* Disable LNA, if any. An error is returned if no LNA is present */ ret = sms_board_lna_control(client->coredev, 0); if (ret == 0) { - fe_status_t status; + enum fe_status status; /* tune with LNA off at first */ ret = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg), @@ -971,7 +971,7 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) /* Disable LNA, if any. An error is returned if no LNA is present */ ret = sms_board_lna_control(client->coredev, 0); if (ret == 0) { - fe_status_t status; + enum fe_status status; /* tune with LNA off at first */ ret = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg), diff --git a/drivers/media/common/siano/smsdvb.h b/drivers/media/common/siano/smsdvb.h index ae36d0a..b15754d 100644 --- a/drivers/media/common/siano/smsdvb.h +++ b/drivers/media/common/siano/smsdvb.h @@ -40,7 +40,7 @@ struct smsdvb_client_t { struct dmxdev dmxdev; struct dvb_frontend frontend; - fe_status_t fe_status; + enum fe_status fe_status; struct completion tune_done; struct completion stats_done; diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c index 1d60d20..41f2a39 100644 --- a/drivers/media/common/siano/smsir.c +++ b/drivers/media/common/siano/smsir.c @@ -78,7 +78,7 @@ int sms_ir_init(struct smscore_device_t *coredev) dev->dev.parent = coredev->device; #if 0 - /* TODO: properly initialize the parameters bellow */ + /* TODO: properly initialize the parameters below */ dev->input_id.bustype = BUS_USB; dev->input_id.version = 1; dev->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 882ca41..842b9c8 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -40,6 +40,7 @@ #include <linux/freezer.h> #include <linux/jiffies.h> #include <linux/kthread.h> +#include <linux/ktime.h> #include <asm/processor.h> #include "dvb_frontend.h" @@ -110,7 +111,7 @@ struct dvb_frontend_private { struct task_struct *thread; unsigned long release_jiffies; unsigned int wakeup; - fe_status_t status; + enum fe_status status; unsigned long tune_mode_flags; unsigned int delay; unsigned int reinitialise; @@ -198,7 +199,8 @@ static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system) } } -static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) +static void dvb_frontend_add_event(struct dvb_frontend *fe, + enum fe_status status) { struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_fe_events *events = &fepriv->events; @@ -429,7 +431,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra static void dvb_frontend_swzigzag(struct dvb_frontend *fe) { - fe_status_t s = 0; + enum fe_status s = 0; int retval = 0; struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp; @@ -690,7 +692,7 @@ static int dvb_frontend_thread(void *data) { struct dvb_frontend *fe = data; struct dvb_frontend_private *fepriv = fe->frontend_priv; - fe_status_t s; + enum fe_status s; enum dvbfe_algo algo; #ifdef CONFIG_MEDIA_CONTROLLER_DVB int ret; @@ -889,42 +891,21 @@ static void dvb_frontend_stop(struct dvb_frontend *fe) fepriv->thread); } -s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime) -{ - return ((curtime.tv_usec < lasttime.tv_usec) ? - 1000000 - lasttime.tv_usec + curtime.tv_usec : - curtime.tv_usec - lasttime.tv_usec); -} -EXPORT_SYMBOL(timeval_usec_diff); - -static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec) -{ - curtime->tv_usec += add_usec; - if (curtime->tv_usec >= 1000000) { - curtime->tv_usec -= 1000000; - curtime->tv_sec++; - } -} - /* * Sleep until gettimeofday() > waketime + add_usec * This needs to be as precise as possible, but as the delay is * usually between 2ms and 32ms, it is done using a scheduled msleep * followed by usleep (normally a busy-wait loop) for the remainder */ -void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec) +void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec) { - struct timeval lasttime; s32 delta, newdelta; - timeval_usec_add(waketime, add_usec); - - do_gettimeofday(&lasttime); - delta = timeval_usec_diff(lasttime, *waketime); + ktime_add_us(*waketime, add_usec); + delta = ktime_us_delta(ktime_get_real(), *waketime); if (delta > 2500) { msleep((delta - 1500) / 1000); - do_gettimeofday(&lasttime); - newdelta = timeval_usec_diff(lasttime, *waketime); + newdelta = ktime_us_delta(ktime_get_real(), *waketime); delta = (newdelta > delta) ? 0 : newdelta; } if (delta > 0) @@ -2216,7 +2197,7 @@ static int dtv_set_frontend(struct dvb_frontend *fe) break; } if (rolloff) - c->bandwidth_hz = (c->symbol_rate * rolloff) / 100; + c->bandwidth_hz = mult_frac(c->symbol_rate, rolloff, 100); /* force auto frequency inversion if requested */ if (dvb_force_auto_inversion) @@ -2341,7 +2322,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file, } case FE_READ_STATUS: { - fe_status_t* status = parg; + enum fe_status *status = parg; /* if retune was requested but hasn't occurred yet, prevent * that user get signal state from previous tuning */ @@ -2403,7 +2384,13 @@ static int dvb_frontend_ioctl_legacy(struct file *file, case FE_DISEQC_SEND_MASTER_CMD: if (fe->ops.diseqc_send_master_cmd) { - err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg); + struct dvb_diseqc_master_cmd *cmd = parg; + + if (cmd->msg_len > sizeof(cmd->msg)) { + err = -EINVAL; + break; + } + err = fe->ops.diseqc_send_master_cmd(fe, cmd); fepriv->state = FESTATE_DISEQC; fepriv->status = 0; } @@ -2411,7 +2398,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file, case FE_DISEQC_SEND_BURST: if (fe->ops.diseqc_send_burst) { - err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg); + err = fe->ops.diseqc_send_burst(fe, + (enum fe_sec_mini_cmd)parg); fepriv->state = FESTATE_DISEQC; fepriv->status = 0; } @@ -2419,8 +2407,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file, case FE_SET_TONE: if (fe->ops.set_tone) { - err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg); - fepriv->tone = (fe_sec_tone_mode_t) parg; + err = fe->ops.set_tone(fe, + (enum fe_sec_tone_mode)parg); + fepriv->tone = (enum fe_sec_tone_mode)parg; fepriv->state = FESTATE_DISEQC; fepriv->status = 0; } @@ -2428,8 +2417,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file, case FE_SET_VOLTAGE: if (fe->ops.set_voltage) { - err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg); - fepriv->voltage = (fe_sec_voltage_t) parg; + err = fe->ops.set_voltage(fe, + (enum fe_sec_voltage)parg); + fepriv->voltage = (enum fe_sec_voltage)parg; fepriv->state = FESTATE_DISEQC; fepriv->status = 0; } @@ -2437,7 +2427,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file, case FE_DISHNETWORK_SEND_LEGACY_CMD: if (fe->ops.dishnetwork_send_legacy_command) { - err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg); + err = fe->ops.dishnetwork_send_legacy_command(fe, + (unsigned long)parg); fepriv->state = FESTATE_DISEQC; fepriv->status = 0; } else if (fe->ops.set_voltage) { @@ -2458,13 +2449,13 @@ static int dvb_frontend_ioctl_legacy(struct file *file, * include the initialization or start bit */ unsigned long swcmd = ((unsigned long) parg) << 1; - struct timeval nexttime; - struct timeval tv[10]; + ktime_t nexttime; + ktime_t tv[10]; int i; u8 last = 1; if (dvb_frontend_debug) printk("%s switch command: 0x%04lx\n", __func__, swcmd); - do_gettimeofday(&nexttime); + nexttime = ktime_get_real(); if (dvb_frontend_debug) tv[0] = nexttime; /* before sending a command, initialize by sending @@ -2475,7 +2466,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file, for (i = 0; i < 9; i++) { if (dvb_frontend_debug) - do_gettimeofday(&tv[i + 1]); + tv[i+1] = ktime_get_real(); if ((swcmd & 0x01) != last) { /* set voltage to (last ? 13V : 18V) */ fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); @@ -2489,7 +2480,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file, printk("%s(%d): switch delay (should be 32k followed by all 8k\n", __func__, fe->dvb->num); for (i = 1; i < 10; i++) - printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i])); + printk("%d: %d\n", i, + (int) ktime_us_delta(tv[i], tv[i-1])); } err = 0; fepriv->state = FESTATE_DISEQC; diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index 816269e..4816947 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -279,7 +279,7 @@ struct dvb_frontend_ops { bool re_tune, unsigned int mode_flags, unsigned int *delay, - fe_status_t *status); + enum fe_status *status); /* get frontend tuning algorithm from the module */ enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe); @@ -289,7 +289,7 @@ struct dvb_frontend_ops { int (*get_frontend)(struct dvb_frontend *fe); - int (*read_status)(struct dvb_frontend* fe, fe_status_t* status); + int (*read_status)(struct dvb_frontend *fe, enum fe_status *status); int (*read_ber)(struct dvb_frontend* fe, u32* ber); int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength); int (*read_snr)(struct dvb_frontend* fe, u16* snr); @@ -298,9 +298,11 @@ struct dvb_frontend_ops { int (*diseqc_reset_overload)(struct dvb_frontend* fe); int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd); int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply); - int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); - int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); - int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); + int (*diseqc_send_burst)(struct dvb_frontend *fe, + enum fe_sec_mini_cmd minicmd); + int (*set_tone)(struct dvb_frontend *fe, enum fe_sec_tone_mode tone); + int (*set_voltage)(struct dvb_frontend *fe, + enum fe_sec_voltage voltage); int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg); int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable); @@ -338,24 +340,24 @@ struct dtv_frontend_properties { u32 state; u32 frequency; - fe_modulation_t modulation; + enum fe_modulation modulation; - fe_sec_voltage_t voltage; - fe_sec_tone_mode_t sectone; - fe_spectral_inversion_t inversion; - fe_code_rate_t fec_inner; - fe_transmit_mode_t transmission_mode; + enum fe_sec_voltage voltage; + enum fe_sec_tone_mode sectone; + enum fe_spectral_inversion inversion; + enum fe_code_rate fec_inner; + enum fe_transmit_mode transmission_mode; u32 bandwidth_hz; /* 0 = AUTO */ - fe_guard_interval_t guard_interval; - fe_hierarchy_t hierarchy; + enum fe_guard_interval guard_interval; + enum fe_hierarchy hierarchy; u32 symbol_rate; - fe_code_rate_t code_rate_HP; - fe_code_rate_t code_rate_LP; + enum fe_code_rate code_rate_HP; + enum fe_code_rate code_rate_LP; - fe_pilot_t pilot; - fe_rolloff_t rolloff; + enum fe_pilot pilot; + enum fe_rolloff rolloff; - fe_delivery_system_t delivery_system; + enum fe_delivery_system delivery_system; enum fe_interleaving interleaving; @@ -368,8 +370,8 @@ struct dtv_frontend_properties { u8 isdbt_layer_enabled; struct { u8 segment_count; - fe_code_rate_t fec; - fe_modulation_t modulation; + enum fe_code_rate fec; + enum fe_modulation modulation; u8 interleaving; } layer[3]; @@ -439,7 +441,6 @@ extern void dvb_frontend_reinitialise(struct dvb_frontend *fe); extern int dvb_frontend_suspend(struct dvb_frontend *fe); extern int dvb_frontend_resume(struct dvb_frontend *fe); -extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec); -extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime); +extern void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec); #endif diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 97c151d..0d35f58 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -36,8 +36,9 @@ config DVB_STV6110x A Silicon tuner that supports DVB-S and DVB-S2 modes config DVB_M88DS3103 - tristate "Montage M88DS3103" + tristate "Montage Technology M88DS3103" depends on DVB_CORE && I2C && I2C_MUX + select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y when you want to support this frontend. @@ -223,6 +224,13 @@ config DVB_CX24117 help A Dual DVB-S/S2 tuner module. Say Y when you want to support this frontend. +config DVB_CX24120 + tristate "Conexant CX24120 based" + depends on DVB_CORE && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + A DVB-S/S2 tuner module. Say Y when you want to support this frontend. + config DVB_SI21XX tristate "Silicon Labs SI21XX based" depends on DVB_CORE && I2C @@ -232,7 +240,8 @@ config DVB_SI21XX config DVB_TS2020 tristate "Montage Tehnology TS2020 based tuners" - depends on DVB_CORE && I2C + depends on DVB_CORE + select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S/S2 silicon tuner. Say Y when you want to support this tuner. diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index 23d399b..ebab1b8 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile @@ -83,6 +83,7 @@ obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o obj-$(CONFIG_DVB_AF9013) += af9013.o obj-$(CONFIG_DVB_CX24116) += cx24116.o obj-$(CONFIG_DVB_CX24117) += cx24117.o +obj-$(CONFIG_DVB_CX24120) += cx24120.o obj-$(CONFIG_DVB_SI21XX) += si21xx.o obj-$(CONFIG_DVB_SI2168) += si2168.o obj-$(CONFIG_DVB_STV0288) += stv0288.o diff --git a/drivers/media/dvb-frontends/a8293.c b/drivers/media/dvb-frontends/a8293.c index 780da58..97ecbe0 100644 --- a/drivers/media/dvb-frontends/a8293.c +++ b/drivers/media/dvb-frontends/a8293.c @@ -22,8 +22,9 @@ #include "a8293.h" struct a8293_priv { + u8 i2c_addr; struct i2c_adapter *i2c; - const struct a8293_config *cfg; + struct i2c_client *client; u8 reg[2]; }; @@ -32,7 +33,7 @@ static int a8293_i2c(struct a8293_priv *priv, u8 *val, int len, bool rd) int ret; struct i2c_msg msg[1] = { { - .addr = priv->cfg->i2c_addr, + .addr = priv->i2c_addr, .len = len, .buf = val, } @@ -66,7 +67,7 @@ static int a8293_rd(struct a8293_priv *priv, u8 *val, int len) } static int a8293_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t fe_sec_voltage) + enum fe_sec_voltage fe_sec_voltage) { struct a8293_priv *priv = fe->sec_priv; int ret; @@ -128,7 +129,7 @@ struct dvb_frontend *a8293_attach(struct dvb_frontend *fe, /* setup the priv */ priv->i2c = i2c; - priv->cfg = cfg; + priv->i2c_addr = cfg->i2c_addr; fe->sec_priv = priv; /* check if the SEC is there */ @@ -164,6 +165,86 @@ err: } EXPORT_SYMBOL(a8293_attach); +static int a8293_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct a8293_priv *dev; + struct a8293_platform_data *pdata = client->dev.platform_data; + struct dvb_frontend *fe = pdata->dvb_frontend; + int ret; + u8 buf[2]; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + ret = -ENOMEM; + goto err; + } + + dev->client = client; + dev->i2c = client->adapter; + dev->i2c_addr = client->addr; + + /* check if the SEC is there */ + ret = a8293_rd(dev, buf, 2); + if (ret) + goto err_kfree; + + /* ENB=0 */ + dev->reg[0] = 0x10; + ret = a8293_wr(dev, &dev->reg[0], 1); + if (ret) + goto err_kfree; + + /* TMODE=0, TGATE=1 */ + dev->reg[1] = 0x82; + ret = a8293_wr(dev, &dev->reg[1], 1); + if (ret) + goto err_kfree; + + /* override frontend ops */ + fe->ops.set_voltage = a8293_set_voltage; + + fe->sec_priv = dev; + i2c_set_clientdata(client, dev); + + dev_info(&client->dev, "Allegro A8293 SEC successfully attached\n"); + return 0; +err_kfree: + kfree(dev); +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + +static int a8293_remove(struct i2c_client *client) +{ + struct a8293_dev *dev = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + + kfree(dev); + return 0; +} + +static const struct i2c_device_id a8293_id_table[] = { + {"a8293", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, a8293_id_table); + +static struct i2c_driver a8293_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "a8293", + .suppress_bind_attrs = true, + }, + .probe = a8293_probe, + .remove = a8293_remove, + .id_table = a8293_id_table, +}; + +module_i2c_driver(a8293_driver); + MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); MODULE_DESCRIPTION("Allegro A8293 SEC driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/a8293.h b/drivers/media/dvb-frontends/a8293.h index 5f04119..aff3653 100644 --- a/drivers/media/dvb-frontends/a8293.h +++ b/drivers/media/dvb-frontends/a8293.h @@ -21,8 +21,23 @@ #ifndef A8293_H #define A8293_H +#include "dvb_frontend.h" #include <linux/kconfig.h> +/* + * I2C address + * 0x08, 0x09, 0x0a, 0x0b + */ + +/** + * struct a8293_platform_data - Platform data for the a8293 driver + * @dvb_frontend: DVB frontend. + */ +struct a8293_platform_data { + struct dvb_frontend *dvb_frontend; +}; + + struct a8293_config { u8 i2c_addr; }; diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 8001690..e23197d 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -39,7 +39,7 @@ struct af9013_state { u32 ucblocks; u16 snr; u32 bandwidth_hz; - fe_status_t fe_status; + enum fe_status fe_status; unsigned long set_frontend_jiffies; unsigned long read_status_jiffies; bool first_tune; @@ -605,6 +605,10 @@ static int af9013_set_frontend(struct dvb_frontend *fe) } } + /* Return an error if can't find bandwidth or the right clock */ + if (i == ARRAY_SIZE(coeff_lut)) + return -EINVAL; + ret = af9013_wr_regs(state, 0xae00, coeff_lut[i].val, sizeof(coeff_lut[i].val)); } @@ -979,7 +983,7 @@ err: return ret; } -static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct af9013_state *state = fe->demodulator_priv; int ret; diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 82ce47b..59018af 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -35,7 +35,7 @@ struct af9033_dev { bool ts_mode_parallel; bool ts_mode_serial; - fe_status_t fe_status; + enum fe_status fe_status; u64 post_bit_error_prev; /* for old read_ber we return (curr - prev) */ u64 post_bit_error; u64 post_bit_count; @@ -818,7 +818,7 @@ err: return ret; } -static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int af9033_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct af9033_dev *dev = fe->demodulator_priv; int ret; diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c index 4936658..544c5f6 100644 --- a/drivers/media/dvb-frontends/as102_fe.c +++ b/drivers/media/dvb-frontends/as102_fe.c @@ -32,7 +32,7 @@ struct as102_state { uint32_t ber; }; -static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg) +static uint8_t as102_fe_get_code_rate(enum fe_code_rate arg) { uint8_t c; @@ -306,7 +306,7 @@ static int as102_fe_get_tune_settings(struct dvb_frontend *fe, return 0; } -static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int as102_fe_read_status(struct dvb_frontend *fe, enum fe_status *status) { int ret = 0; struct as102_state *state = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/atbm8830.c b/drivers/media/dvb-frontends/atbm8830.c index 4e11dc4..8fe552e 100644 --- a/drivers/media/dvb-frontends/atbm8830.c +++ b/drivers/media/dvb-frontends/atbm8830.c @@ -335,7 +335,8 @@ static int atbm8830_get_tune_settings(struct dvb_frontend *fe, return 0; } -static int atbm8830_read_status(struct dvb_frontend *fe, fe_status_t *fe_status) +static int atbm8830_read_status(struct dvb_frontend *fe, + enum fe_status *fe_status) { struct atbm_state *priv = fe->demodulator_priv; u8 locked = 0; diff --git a/drivers/media/dvb-frontends/au8522_dig.c b/drivers/media/dvb-frontends/au8522_dig.c index 5d06c99..b744a3f 100644 --- a/drivers/media/dvb-frontends/au8522_dig.c +++ b/drivers/media/dvb-frontends/au8522_dig.c @@ -552,7 +552,7 @@ static struct { }; static int au8522_enable_modulation(struct dvb_frontend *fe, - fe_modulation_t m) + enum fe_modulation m) { struct au8522_state *state = fe->demodulator_priv; int i; @@ -644,7 +644,7 @@ static int au8522_set_frontend(struct dvb_frontend *fe) return 0; } -static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int au8522_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct au8522_state *state = fe->demodulator_priv; u8 reg; diff --git a/drivers/media/dvb-frontends/au8522_priv.h b/drivers/media/dvb-frontends/au8522_priv.h index b8aca1c..951b384 100644 --- a/drivers/media/dvb-frontends/au8522_priv.h +++ b/drivers/media/dvb-frontends/au8522_priv.h @@ -55,7 +55,7 @@ struct au8522_state { struct dvb_frontend frontend; u32 current_frequency; - fe_modulation_t current_modulation; + enum fe_modulation current_modulation; u32 fe_status; unsigned int led_state; diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c index 638c7aa..d30275f 100644 --- a/drivers/media/dvb-frontends/bcm3510.c +++ b/drivers/media/dvb-frontends/bcm3510.c @@ -289,7 +289,7 @@ static int bcm3510_refresh_state(struct bcm3510_state *st) return 0; } -static int bcm3510_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int bcm3510_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct bcm3510_state* st = fe->demodulator_priv; bcm3510_refresh_state(st); @@ -685,7 +685,7 @@ static int bcm3510_reset(struct bcm3510_state *st) if ((ret = bcm3510_writeB(st,0xa0,v)) < 0) return ret; - t = jiffies + 3*HZ; + t = jiffies + 3*HZ; while (time_before(jiffies, t)) { msleep(10); if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) @@ -708,7 +708,7 @@ static int bcm3510_clear_reset(struct bcm3510_state *st) if ((ret = bcm3510_writeB(st,0xa0,v)) < 0) return ret; - t = jiffies + 3*HZ; + t = jiffies + 3*HZ; while (time_before(jiffies, t)) { msleep(10); if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) diff --git a/drivers/media/dvb-frontends/cx22700.c b/drivers/media/dvb-frontends/cx22700.c index 8656326..fd033cc 100644 --- a/drivers/media/dvb-frontends/cx22700.c +++ b/drivers/media/dvb-frontends/cx22700.c @@ -191,9 +191,10 @@ static int cx22700_set_tps(struct cx22700_state *state, static int cx22700_get_tps(struct cx22700_state *state, struct dtv_frontend_properties *p) { - static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 }; - static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4, - FEC_5_6, FEC_7_8 }; + static const enum fe_modulation qam_tab[3] = { QPSK, QAM_16, QAM_64 }; + static const enum fe_code_rate fec_tab[5] = { + FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8 + }; u8 val; dprintk ("%s\n", __func__); @@ -253,7 +254,7 @@ static int cx22700_init (struct dvb_frontend* fe) return 0; } -static int cx22700_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int cx22700_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct cx22700_state* state = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/cx22702.c b/drivers/media/dvb-frontends/cx22702.c index edc8eaf..d2d06dc 100644 --- a/drivers/media/dvb-frontends/cx22702.c +++ b/drivers/media/dvb-frontends/cx22702.c @@ -452,7 +452,7 @@ static int cx22702_init(struct dvb_frontend *fe) return 0; } -static int cx22702_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int cx22702_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct cx22702_state *state = fe->demodulator_priv; u8 reg0A; diff --git a/drivers/media/dvb-frontends/cx24110.c b/drivers/media/dvb-frontends/cx24110.c index 7b510f2..cb36475 100644 --- a/drivers/media/dvb-frontends/cx24110.c +++ b/drivers/media/dvb-frontends/cx24110.c @@ -143,7 +143,8 @@ static int cx24110_readreg (struct cx24110_state* state, u8 reg) return b1[0]; } -static int cx24110_set_inversion (struct cx24110_state* state, fe_spectral_inversion_t inversion) +static int cx24110_set_inversion(struct cx24110_state *state, + enum fe_spectral_inversion inversion) { /* fixme (low): error handling */ @@ -177,7 +178,7 @@ static int cx24110_set_inversion (struct cx24110_state* state, fe_spectral_inver return 0; } -static int cx24110_set_fec(struct cx24110_state* state, fe_code_rate_t fec) +static int cx24110_set_fec(struct cx24110_state *state, enum fe_code_rate fec) { static const int rate[FEC_AUTO] = {-1, 1, 2, 3, 5, 7, -1}; static const int g1[FEC_AUTO] = {-1, 0x01, 0x02, 0x05, 0x15, 0x45, -1}; @@ -220,7 +221,7 @@ static int cx24110_set_fec(struct cx24110_state* state, fe_code_rate_t fec) return 0; } -static fe_code_rate_t cx24110_get_fec (struct cx24110_state* state) +static enum fe_code_rate cx24110_get_fec(struct cx24110_state *state) { int i; @@ -365,7 +366,8 @@ static int cx24110_initfe(struct dvb_frontend* fe) return 0; } -static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int cx24110_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct cx24110_state *state = fe->demodulator_priv; @@ -379,7 +381,8 @@ static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag } } -static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) +static int cx24110_diseqc_send_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd burst) { int rv, bit; struct cx24110_state *state = fe->demodulator_priv; @@ -434,7 +437,8 @@ static int cx24110_send_diseqc_msg(struct dvb_frontend* fe, return 0; } -static int cx24110_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int cx24110_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct cx24110_state *state = fe->demodulator_priv; @@ -574,7 +578,8 @@ static int cx24110_get_frontend(struct dvb_frontend *fe) return 0; } -static int cx24110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int cx24110_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct cx24110_state *state = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c index 2916d7c..8814f36 100644 --- a/drivers/media/dvb-frontends/cx24116.c +++ b/drivers/media/dvb-frontends/cx24116.c @@ -160,13 +160,13 @@ enum cmds { struct cx24116_tuning { u32 frequency; u32 symbol_rate; - fe_spectral_inversion_t inversion; - fe_code_rate_t fec; + enum fe_spectral_inversion inversion; + enum fe_code_rate fec; - fe_delivery_system_t delsys; - fe_modulation_t modulation; - fe_pilot_t pilot; - fe_rolloff_t rolloff; + enum fe_delivery_system delsys; + enum fe_modulation modulation; + enum fe_pilot pilot; + enum fe_rolloff rolloff; /* Demod values */ u8 fec_val; @@ -285,7 +285,7 @@ static int cx24116_readreg(struct cx24116_state *state, u8 reg) } static int cx24116_set_inversion(struct cx24116_state *state, - fe_spectral_inversion_t inversion) + enum fe_spectral_inversion inversion) { dprintk("%s(%d)\n", __func__, inversion); @@ -373,9 +373,9 @@ static int cx24116_set_inversion(struct cx24116_state *state, * a scheme are support. Especially, no auto detect when in S2 mode. */ static struct cx24116_modfec { - fe_delivery_system_t delivery_system; - fe_modulation_t modulation; - fe_code_rate_t fec; + enum fe_delivery_system delivery_system; + enum fe_modulation modulation; + enum fe_code_rate fec; u8 mask; /* In DVBS mode this is used to autodetect */ u8 val; /* Passed to the firmware to indicate mode selection */ } CX24116_MODFEC_MODES[] = { @@ -415,7 +415,7 @@ static struct cx24116_modfec { }; static int cx24116_lookup_fecmod(struct cx24116_state *state, - fe_delivery_system_t d, fe_modulation_t m, fe_code_rate_t f) + enum fe_delivery_system d, enum fe_modulation m, enum fe_code_rate f) { int i, ret = -EOPNOTSUPP; @@ -434,7 +434,9 @@ static int cx24116_lookup_fecmod(struct cx24116_state *state, } static int cx24116_set_fec(struct cx24116_state *state, - fe_delivery_system_t delsys, fe_modulation_t mod, fe_code_rate_t fec) + enum fe_delivery_system delsys, + enum fe_modulation mod, + enum fe_code_rate fec) { int ret = 0; @@ -683,7 +685,7 @@ static int cx24116_load_firmware(struct dvb_frontend *fe, return 0; } -static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int cx24116_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct cx24116_state *state = fe->demodulator_priv; @@ -844,7 +846,7 @@ static int cx24116_wait_for_lnb(struct dvb_frontend *fe) } static int cx24116_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct cx24116_cmd cmd; int ret; @@ -872,7 +874,7 @@ static int cx24116_set_voltage(struct dvb_frontend *fe, } static int cx24116_set_tone(struct dvb_frontend *fe, - fe_sec_tone_mode_t tone) + enum fe_sec_tone_mode tone) { struct cx24116_cmd cmd; int ret; @@ -963,6 +965,10 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend *fe, struct cx24116_state *state = fe->demodulator_priv; int i, ret; + /* Validate length */ + if (d->msg_len > sizeof(d->msg)) + return -EINVAL; + /* Dump DiSEqC message */ if (debug) { printk(KERN_INFO "cx24116: %s(", __func__); @@ -974,10 +980,6 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend *fe, printk(") toneburst=%d\n", toneburst); } - /* Validate length */ - if (d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS)) - return -EINVAL; - /* DiSEqC message */ for (i = 0; i < d->msg_len; i++) state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i]; @@ -1055,7 +1057,7 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend *fe, /* Send DiSEqC burst */ static int cx24116_diseqc_send_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t burst) + enum fe_sec_mini_cmd burst) { struct cx24116_state *state = fe->demodulator_priv; int ret; @@ -1220,7 +1222,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe) struct cx24116_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx24116_cmd cmd; - fe_status_t tunerstat; + enum fe_status tunerstat; int i, status, ret, retune = 1; dprintk("%s()\n", __func__); @@ -1441,7 +1443,7 @@ tuned: /* Set/Reset B/W */ } static int cx24116_tune(struct dvb_frontend *fe, bool re_tune, - unsigned int mode_flags, unsigned int *delay, fe_status_t *status) + unsigned int mode_flags, unsigned int *delay, enum fe_status *status) { /* * It is safe to discard "params" here, as the DVB core will sync diff --git a/drivers/media/dvb-frontends/cx24117.c b/drivers/media/dvb-frontends/cx24117.c index acb965c..5f77bc8 100644 --- a/drivers/media/dvb-frontends/cx24117.c +++ b/drivers/media/dvb-frontends/cx24117.c @@ -171,13 +171,13 @@ static DEFINE_MUTEX(cx24117_list_mutex); struct cx24117_tuning { u32 frequency; u32 symbol_rate; - fe_spectral_inversion_t inversion; - fe_code_rate_t fec; + enum fe_spectral_inversion inversion; + enum fe_code_rate fec; - fe_delivery_system_t delsys; - fe_modulation_t modulation; - fe_pilot_t pilot; - fe_rolloff_t rolloff; + enum fe_delivery_system delsys; + enum fe_modulation modulation; + enum fe_pilot pilot; + enum fe_rolloff rolloff; /* Demod values */ u8 fec_val; @@ -220,9 +220,9 @@ struct cx24117_state { /* modfec (modulation and FEC) lookup table */ /* Check cx24116.c for a detailed description of each field */ static struct cx24117_modfec { - fe_delivery_system_t delivery_system; - fe_modulation_t modulation; - fe_code_rate_t fec; + enum fe_delivery_system delivery_system; + enum fe_modulation modulation; + enum fe_code_rate fec; u8 mask; /* In DVBS mode this is used to autodetect */ u8 val; /* Passed to the firmware to indicate mode selection */ } cx24117_modfec_modes[] = { @@ -362,7 +362,7 @@ static int cx24117_readregN(struct cx24117_state *state, } static int cx24117_set_inversion(struct cx24117_state *state, - fe_spectral_inversion_t inversion) + enum fe_spectral_inversion inversion) { dev_dbg(&state->priv->i2c->dev, "%s(%d) demod%d\n", __func__, inversion, state->demod); @@ -387,7 +387,7 @@ static int cx24117_set_inversion(struct cx24117_state *state, } static int cx24117_lookup_fecmod(struct cx24117_state *state, - fe_delivery_system_t d, fe_modulation_t m, fe_code_rate_t f) + enum fe_delivery_system d, enum fe_modulation m, enum fe_code_rate f) { int i, ret = -EINVAL; @@ -408,7 +408,9 @@ static int cx24117_lookup_fecmod(struct cx24117_state *state, } static int cx24117_set_fec(struct cx24117_state *state, - fe_delivery_system_t delsys, fe_modulation_t mod, fe_code_rate_t fec) + enum fe_delivery_system delsys, + enum fe_modulation mod, + enum fe_code_rate fec) { int ret; @@ -737,7 +739,7 @@ error: return ret; } -static int cx24117_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int cx24117_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct cx24117_state *state = fe->demodulator_priv; int lock; @@ -843,7 +845,7 @@ static int cx24117_read_snr(struct dvb_frontend *fe, u16 *snr) static int cx24117_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { struct cx24117_state *state = fe->demodulator_priv; - fe_delivery_system_t delsys = fe->dtv_property_cache.delivery_system; + enum fe_delivery_system delsys = fe->dtv_property_cache.delivery_system; int ret; u8 buf[2]; u8 reg = (state->demod == 0) ? @@ -904,7 +906,7 @@ static int cx24117_wait_for_lnb(struct dvb_frontend *fe) } static int cx24117_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct cx24117_state *state = fe->demodulator_priv; struct cx24117_cmd cmd; @@ -956,7 +958,7 @@ static int cx24117_set_voltage(struct dvb_frontend *fe, } static int cx24117_set_tone(struct dvb_frontend *fe, - fe_sec_tone_mode_t tone) + enum fe_sec_tone_mode tone) { struct cx24117_state *state = fe->demodulator_priv; struct cx24117_cmd cmd; @@ -1043,7 +1045,7 @@ static int cx24117_send_diseqc_msg(struct dvb_frontend *fe, dev_dbg(&state->priv->i2c->dev, ")\n"); /* Validate length */ - if (d->msg_len > 15) + if (d->msg_len > sizeof(d->msg)) return -EINVAL; /* DiSEqC message */ @@ -1112,7 +1114,7 @@ static int cx24117_send_diseqc_msg(struct dvb_frontend *fe, /* Send DiSEqC burst */ static int cx24117_diseqc_send_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t burst) + enum fe_sec_mini_cmd burst) { struct cx24117_state *state = fe->demodulator_priv; @@ -1306,7 +1308,7 @@ static int cx24117_set_frontend(struct dvb_frontend *fe) struct cx24117_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx24117_cmd cmd; - fe_status_t tunerstat; + enum fe_status tunerstat; int i, status, ret, retune = 1; u8 reg_clkdiv, reg_ratediv; @@ -1537,7 +1539,7 @@ static int cx24117_set_frontend(struct dvb_frontend *fe) } static int cx24117_tune(struct dvb_frontend *fe, bool re_tune, - unsigned int mode_flags, unsigned int *delay, fe_status_t *status) + unsigned int mode_flags, unsigned int *delay, enum fe_status *status) { struct cx24117_state *state = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/cx24120.c b/drivers/media/dvb-frontends/cx24120.c new file mode 100644 index 0000000..3b0ef52 --- /dev/null +++ b/drivers/media/dvb-frontends/cx24120.c @@ -0,0 +1,1595 @@ +/* + Conexant cx24120/cx24118 - DVBS/S2 Satellite demod/tuner driver + + Copyright (C) 2008 Patrick Boettcher <pb@linuxtv.org> + Copyright (C) 2009 Sergey Tyurin <forum.free-x.de> + Updated 2012 by Jannis Achstetter <jannis_achstetter@web.de> + Copyright (C) 2015 Jemma Denson <jdenson@gmail.com> + April 2015 + Refactored & simplified driver + Updated to work with delivery system supplied by DVBv5 + Add frequency, fec & pilot to get_frontend + + Cards supported: Technisat Skystar S2 + + 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. +*/ + +#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/firmware.h> +#include "dvb_frontend.h" +#include "cx24120.h" + +#define CX24120_SEARCH_RANGE_KHZ 5000 +#define CX24120_FIRMWARE "dvb-fe-cx24120-1.20.58.2.fw" + +/* cx24120 i2c registers */ +#define CX24120_REG_CMD_START 0x00 /* write cmd_id */ +#define CX24120_REG_CMD_ARGS 0x01 /* write command arguments */ +#define CX24120_REG_CMD_END 0x1f /* write 0x01 for end */ + +#define CX24120_REG_MAILBOX 0x33 +#define CX24120_REG_FREQ3 0x34 /* frequency */ +#define CX24120_REG_FREQ2 0x35 +#define CX24120_REG_FREQ1 0x36 + +#define CX24120_REG_FECMODE 0x39 /* FEC status */ +#define CX24120_REG_STATUS 0x3a /* Tuner status */ +#define CX24120_REG_SIGSTR_H 0x3a /* Signal strength high */ +#define CX24120_REG_SIGSTR_L 0x3b /* Signal strength low byte */ +#define CX24120_REG_QUALITY_H 0x40 /* SNR high byte */ +#define CX24120_REG_QUALITY_L 0x41 /* SNR low byte */ + +#define CX24120_REG_BER_HH 0x47 /* BER high byte of high word */ +#define CX24120_REG_BER_HL 0x48 /* BER low byte of high word */ +#define CX24120_REG_BER_LH 0x49 /* BER high byte of low word */ +#define CX24120_REG_BER_LL 0x4a /* BER low byte of low word */ + +#define CX24120_REG_UCB_H 0x50 /* UCB high byte */ +#define CX24120_REG_UCB_L 0x51 /* UCB low byte */ + +#define CX24120_REG_CLKDIV 0xe6 +#define CX24120_REG_RATEDIV 0xf0 + +#define CX24120_REG_REVISION 0xff /* Chip revision (ro) */ + +/* Command messages */ +enum command_message_id { + CMD_VCO_SET = 0x10, /* cmd.len = 12; */ + CMD_TUNEREQUEST = 0x11, /* cmd.len = 15; */ + + CMD_MPEG_ONOFF = 0x13, /* cmd.len = 4; */ + CMD_MPEG_INIT = 0x14, /* cmd.len = 7; */ + CMD_BANDWIDTH = 0x15, /* cmd.len = 12; */ + CMD_CLOCK_READ = 0x16, /* read clock */ + CMD_CLOCK_SET = 0x17, /* cmd.len = 10; */ + + CMD_DISEQC_MSG1 = 0x20, /* cmd.len = 11; */ + CMD_DISEQC_MSG2 = 0x21, /* cmd.len = d->msg_len + 6; */ + CMD_SETVOLTAGE = 0x22, /* cmd.len = 2; */ + CMD_SETTONE = 0x23, /* cmd.len = 4; */ + CMD_DISEQC_BURST = 0x24, /* cmd.len not used !!! */ + + CMD_READ_SNR = 0x1a, /* Read signal strength */ + CMD_START_TUNER = 0x1b, /* ??? */ + + CMD_FWVERSION = 0x35, + + CMD_BER_CTRL = 0x3c, /* cmd.len = 0x03; */ +}; + +#define CX24120_MAX_CMD_LEN 30 + +/* pilot mask */ +#define CX24120_PILOT_OFF 0x00 +#define CX24120_PILOT_ON 0x40 +#define CX24120_PILOT_AUTO 0x80 + +/* signal status */ +#define CX24120_HAS_SIGNAL 0x01 +#define CX24120_HAS_CARRIER 0x02 +#define CX24120_HAS_VITERBI 0x04 +#define CX24120_HAS_LOCK 0x08 +#define CX24120_HAS_UNK1 0x10 +#define CX24120_HAS_UNK2 0x20 +#define CX24120_STATUS_MASK 0x0f +#define CX24120_SIGNAL_MASK 0xc0 + +/* ber window */ +#define CX24120_BER_WINDOW 16 +#define CX24120_BER_WSIZE ((1 << CX24120_BER_WINDOW) * 208 * 8) + +#define info(args...) pr_info("cx24120: " args) +#define err(args...) pr_err("cx24120: ### ERROR: " args) + +/* The Demod/Tuner can't easily provide these, we cache them */ +struct cx24120_tuning { + u32 frequency; + u32 symbol_rate; + enum fe_spectral_inversion inversion; + enum fe_code_rate fec; + + enum fe_delivery_system delsys; + enum fe_modulation modulation; + enum fe_pilot pilot; + + /* Demod values */ + u8 fec_val; + u8 fec_mask; + u8 clkdiv; + u8 ratediv; + u8 inversion_val; + u8 pilot_val; +}; + +/* Private state */ +struct cx24120_state { + struct i2c_adapter *i2c; + const struct cx24120_config *config; + struct dvb_frontend frontend; + + u8 cold_init; + u8 mpeg_enabled; + u8 need_clock_set; + + /* current and next tuning parameters */ + struct cx24120_tuning dcur; + struct cx24120_tuning dnxt; + + enum fe_status fe_status; + + /* dvbv5 stats calculations */ + u32 bitrate; + u32 berw_usecs; + u32 ber_prev; + u32 ucb_offset; + unsigned long ber_jiffies_stats; + unsigned long per_jiffies_stats; +}; + +/* Command message to firmware */ +struct cx24120_cmd { + u8 id; + u8 len; + u8 arg[CX24120_MAX_CMD_LEN]; +}; + +/* Read single register */ +static int cx24120_readreg(struct cx24120_state *state, u8 reg) +{ + int ret; + u8 buf = 0; + struct i2c_msg msg[] = { + { + .addr = state->config->i2c_addr, + .flags = 0, + .len = 1, + .buf = ® + }, { + .addr = state->config->i2c_addr, + .flags = I2C_M_RD, + .len = 1, + .buf = &buf + } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) { + err("Read error: reg=0x%02x, ret=%i)\n", reg, ret); + return ret; + } + + dev_dbg(&state->i2c->dev, "reg=0x%02x; data=0x%02x\n", reg, buf); + + return buf; +} + +/* Write single register */ +static int cx24120_writereg(struct cx24120_state *state, u8 reg, u8 data) +{ + u8 buf[] = { reg, data }; + struct i2c_msg msg = { + .addr = state->config->i2c_addr, + .flags = 0, + .buf = buf, + .len = 2 + }; + int ret; + + ret = i2c_transfer(state->i2c, &msg, 1); + if (ret != 1) { + err("Write error: i2c_write error(err == %i, 0x%02x: 0x%02x)\n", + ret, reg, data); + return ret; + } + + dev_dbg(&state->i2c->dev, "reg=0x%02x; data=0x%02x\n", reg, data); + + return 0; +} + +/* Write multiple registers in chunks of i2c_wr_max-sized buffers */ +static int cx24120_writeregs(struct cx24120_state *state, + u8 reg, const u8 *values, u16 len, u8 incr) +{ + int ret; + u16 max = state->config->i2c_wr_max > 0 ? + state->config->i2c_wr_max : + len; + + struct i2c_msg msg = { + .addr = state->config->i2c_addr, + .flags = 0, + }; + + msg.buf = kmalloc(max + 1, GFP_KERNEL); + if (!msg.buf) + return -ENOMEM; + + while (len) { + msg.buf[0] = reg; + msg.len = len > max ? max : len; + memcpy(&msg.buf[1], values, msg.len); + + len -= msg.len; /* data length revers counter */ + values += msg.len; /* incr data pointer */ + + if (incr) + reg += msg.len; + msg.len++; /* don't forget the addr byte */ + + ret = i2c_transfer(state->i2c, &msg, 1); + if (ret != 1) { + err("i2c_write error(err == %i, 0x%02x)\n", ret, reg); + goto out; + } + + dev_dbg(&state->i2c->dev, "reg=0x%02x; data=%*ph\n", + reg, msg.len - 1, msg.buf + 1); + } + + ret = 0; + +out: + kfree(msg.buf); + return ret; +} + +static struct dvb_frontend_ops cx24120_ops; + +struct dvb_frontend *cx24120_attach(const struct cx24120_config *config, + struct i2c_adapter *i2c) +{ + struct cx24120_state *state; + int demod_rev; + + info("Conexant cx24120/cx24118 - DVBS/S2 Satellite demod/tuner\n"); + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) { + err("Unable to allocate memory for cx24120_state\n"); + goto error; + } + + /* setup the state */ + state->config = config; + state->i2c = i2c; + + /* check if the demod is present and has proper type */ + demod_rev = cx24120_readreg(state, CX24120_REG_REVISION); + switch (demod_rev) { + case 0x07: + info("Demod cx24120 rev. 0x07 detected.\n"); + break; + case 0x05: + info("Demod cx24120 rev. 0x05 detected.\n"); + break; + default: + err("Unsupported demod revision: 0x%x detected.\n", demod_rev); + goto error; + } + + /* create dvb_frontend */ + state->cold_init = 0; + memcpy(&state->frontend.ops, &cx24120_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + info("Conexant cx24120/cx24118 attached.\n"); + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(cx24120_attach); + +static int cx24120_test_rom(struct cx24120_state *state) +{ + int err, ret; + + err = cx24120_readreg(state, 0xfd); + if (err & 4) { + ret = cx24120_readreg(state, 0xdf) & 0xfe; + err = cx24120_writereg(state, 0xdf, ret); + } + return err; +} + +static int cx24120_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + if (c->cnr.stat[0].scale != FE_SCALE_DECIBEL) + *snr = 0; + else + *snr = div_s64(c->cnr.stat[0].svalue, 100); + + return 0; +} + +static int cx24120_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct cx24120_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + if (c->post_bit_error.stat[0].scale != FE_SCALE_COUNTER) { + *ber = 0; + return 0; + } + + *ber = c->post_bit_error.stat[0].uvalue - state->ber_prev; + state->ber_prev = c->post_bit_error.stat[0].uvalue; + + return 0; +} + +static int cx24120_msg_mpeg_output_global_config(struct cx24120_state *state, + u8 flag); + +/* Check if we're running a command that needs to disable mpeg out */ +static void cx24120_check_cmd(struct cx24120_state *state, u8 id) +{ + switch (id) { + case CMD_TUNEREQUEST: + case CMD_CLOCK_READ: + case CMD_DISEQC_MSG1: + case CMD_DISEQC_MSG2: + case CMD_SETVOLTAGE: + case CMD_SETTONE: + case CMD_DISEQC_BURST: + cx24120_msg_mpeg_output_global_config(state, 0); + /* Old driver would do a msleep(100) here */ + default: + return; + } +} + +/* Send a message to the firmware */ +static int cx24120_message_send(struct cx24120_state *state, + struct cx24120_cmd *cmd) +{ + int ficus; + + if (state->mpeg_enabled) { + /* Disable mpeg out on certain commands */ + cx24120_check_cmd(state, cmd->id); + } + + cx24120_writereg(state, CX24120_REG_CMD_START, cmd->id); + cx24120_writeregs(state, CX24120_REG_CMD_ARGS, &cmd->arg[0], + cmd->len, 1); + cx24120_writereg(state, CX24120_REG_CMD_END, 0x01); + + ficus = 1000; + while (cx24120_readreg(state, CX24120_REG_CMD_END)) { + msleep(20); + ficus -= 20; + if (ficus == 0) { + err("Error sending message to firmware\n"); + return -EREMOTEIO; + } + } + dev_dbg(&state->i2c->dev, "sent message 0x%02x\n", cmd->id); + + return 0; +} + +/* Send a message and fill arg[] with the results */ +static int cx24120_message_sendrcv(struct cx24120_state *state, + struct cx24120_cmd *cmd, u8 numreg) +{ + int ret, i; + + if (numreg > CX24120_MAX_CMD_LEN) { + err("Too many registers to read. cmd->reg = %d", numreg); + return -EREMOTEIO; + } + + ret = cx24120_message_send(state, cmd); + if (ret != 0) + return ret; + + if (!numreg) + return 0; + + /* Read numreg registers starting from register cmd->len */ + for (i = 0; i < numreg; i++) + cmd->arg[i] = cx24120_readreg(state, (cmd->len + i + 1)); + + return 0; +} + +static int cx24120_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + if (c->strength.stat[0].scale != FE_SCALE_RELATIVE) + *signal_strength = 0; + else + *signal_strength = c->strength.stat[0].uvalue; + + return 0; +} + +static int cx24120_msg_mpeg_output_global_config(struct cx24120_state *state, + u8 enable) +{ + struct cx24120_cmd cmd; + int ret; + + cmd.id = CMD_MPEG_ONOFF; + cmd.len = 4; + cmd.arg[0] = 0x01; + cmd.arg[1] = 0x00; + cmd.arg[2] = enable ? 0 : (u8)(-1); + cmd.arg[3] = 0x01; + + ret = cx24120_message_send(state, &cmd); + if (ret != 0) { + dev_dbg(&state->i2c->dev, "failed to %s MPEG output\n", + enable ? "enable" : "disable"); + return ret; + } + + state->mpeg_enabled = enable; + dev_dbg(&state->i2c->dev, "MPEG output %s\n", + enable ? "enabled" : "disabled"); + + return 0; +} + +static int cx24120_msg_mpeg_output_config(struct cx24120_state *state, u8 seq) +{ + struct cx24120_cmd cmd; + struct cx24120_initial_mpeg_config i = + state->config->initial_mpeg_config; + + cmd.id = CMD_MPEG_INIT; + cmd.len = 7; + cmd.arg[0] = seq; /* sequental number - can be 0,1,2 */ + cmd.arg[1] = ((i.x1 & 0x01) << 1) | ((i.x1 >> 1) & 0x01); + cmd.arg[2] = 0x05; + cmd.arg[3] = 0x02; + cmd.arg[4] = ((i.x2 >> 1) & 0x01); + cmd.arg[5] = (i.x2 & 0xf0) | (i.x3 & 0x0f); + cmd.arg[6] = 0x10; + + return cx24120_message_send(state, &cmd); +} + +static int cx24120_diseqc_send_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd burst) +{ + struct cx24120_state *state = fe->demodulator_priv; + struct cx24120_cmd cmd; + + dev_dbg(&state->i2c->dev, "\n"); + + /* + * Yes, cmd.len is set to zero. The old driver + * didn't specify any len, but also had a + * memset 0 before every use of the cmd struct + * which would have set it to zero. + * This quite probably needs looking into. + */ + cmd.id = CMD_DISEQC_BURST; + cmd.len = 0; + cmd.arg[0] = 0x00; + cmd.arg[1] = (burst == SEC_MINI_B) ? 0x01 : 0x00; + + return cx24120_message_send(state, &cmd); +} + +static int cx24120_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) +{ + struct cx24120_state *state = fe->demodulator_priv; + struct cx24120_cmd cmd; + + dev_dbg(&state->i2c->dev, "(%d)\n", tone); + + if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) { + err("Invalid tone=%d\n", tone); + return -EINVAL; + } + + cmd.id = CMD_SETTONE; + cmd.len = 4; + cmd.arg[0] = 0x00; + cmd.arg[1] = 0x00; + cmd.arg[2] = 0x00; + cmd.arg[3] = (tone == SEC_TONE_ON) ? 0x01 : 0x00; + + return cx24120_message_send(state, &cmd); +} + +static int cx24120_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) +{ + struct cx24120_state *state = fe->demodulator_priv; + struct cx24120_cmd cmd; + + dev_dbg(&state->i2c->dev, "(%d)\n", voltage); + + cmd.id = CMD_SETVOLTAGE; + cmd.len = 2; + cmd.arg[0] = 0x00; + cmd.arg[1] = (voltage == SEC_VOLTAGE_18) ? 0x01 : 0x00; + + return cx24120_message_send(state, &cmd); +} + +static int cx24120_send_diseqc_msg(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *d) +{ + struct cx24120_state *state = fe->demodulator_priv; + struct cx24120_cmd cmd; + int back_count; + + dev_dbg(&state->i2c->dev, "\n"); + + cmd.id = CMD_DISEQC_MSG1; + cmd.len = 11; + cmd.arg[0] = 0x00; + cmd.arg[1] = 0x00; + cmd.arg[2] = 0x03; + cmd.arg[3] = 0x16; + cmd.arg[4] = 0x28; + cmd.arg[5] = 0x01; + cmd.arg[6] = 0x01; + cmd.arg[7] = 0x14; + cmd.arg[8] = 0x19; + cmd.arg[9] = 0x14; + cmd.arg[10] = 0x1e; + + if (cx24120_message_send(state, &cmd)) { + err("send 1st message(0x%x) failed\n", cmd.id); + return -EREMOTEIO; + } + + cmd.id = CMD_DISEQC_MSG2; + cmd.len = d->msg_len + 6; + cmd.arg[0] = 0x00; + cmd.arg[1] = 0x01; + cmd.arg[2] = 0x02; + cmd.arg[3] = 0x00; + cmd.arg[4] = 0x00; + cmd.arg[5] = d->msg_len; + + memcpy(&cmd.arg[6], &d->msg, d->msg_len); + + if (cx24120_message_send(state, &cmd)) { + err("send 2nd message(0x%x) failed\n", cmd.id); + return -EREMOTEIO; + } + + back_count = 500; + do { + if (!(cx24120_readreg(state, 0x93) & 0x01)) { + dev_dbg(&state->i2c->dev, "diseqc sequence sent\n"); + return 0; + } + msleep(20); + back_count -= 20; + } while (back_count); + + err("Too long waiting for diseqc.\n"); + return -ETIMEDOUT; +} + +static void cx24120_get_stats(struct cx24120_state *state) +{ + struct dvb_frontend *fe = &state->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct cx24120_cmd cmd; + int ret, cnr, msecs; + u16 sig, ucb; + u32 ber; + + dev_dbg(&state->i2c->dev, "\n"); + + /* signal strength */ + if (state->fe_status & FE_HAS_SIGNAL) { + cmd.id = CMD_READ_SNR; + cmd.len = 1; + cmd.arg[0] = 0x00; + + ret = cx24120_message_send(state, &cmd); + if (ret != 0) { + err("error reading signal strength\n"); + return; + } + + /* raw */ + sig = cx24120_readreg(state, CX24120_REG_SIGSTR_H) >> 6; + sig = sig << 8; + sig |= cx24120_readreg(state, CX24120_REG_SIGSTR_L); + dev_dbg(&state->i2c->dev, + "signal strength from firmware = 0x%x\n", sig); + + /* cooked */ + sig = -100 * sig + 94324; + + c->strength.stat[0].scale = FE_SCALE_RELATIVE; + c->strength.stat[0].uvalue = sig; + } else { + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + /* CNR */ + if (state->fe_status & FE_HAS_VITERBI) { + cnr = cx24120_readreg(state, CX24120_REG_QUALITY_H) << 8; + cnr |= cx24120_readreg(state, CX24120_REG_QUALITY_L); + dev_dbg(&state->i2c->dev, "read SNR index = %d\n", cnr); + + /* guessed - seems about right */ + cnr = cnr * 100; + + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = cnr; + } else { + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + /* BER & UCB require lock */ + if (!(state->fe_status & FE_HAS_LOCK)) { + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return; + } + + /* BER */ + if (time_after(jiffies, state->ber_jiffies_stats)) { + msecs = (state->berw_usecs + 500) / 1000; + state->ber_jiffies_stats = jiffies + msecs_to_jiffies(msecs); + + ber = cx24120_readreg(state, CX24120_REG_BER_HH) << 24; + ber |= cx24120_readreg(state, CX24120_REG_BER_HL) << 16; + ber |= cx24120_readreg(state, CX24120_REG_BER_LH) << 8; + ber |= cx24120_readreg(state, CX24120_REG_BER_LL); + dev_dbg(&state->i2c->dev, "read BER index = %d\n", ber); + + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += ber; + + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].uvalue += CX24120_BER_WSIZE; + } + + /* UCB */ + if (time_after(jiffies, state->per_jiffies_stats)) { + state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000); + + ucb = cx24120_readreg(state, CX24120_REG_UCB_H) << 8; + ucb |= cx24120_readreg(state, CX24120_REG_UCB_L); + dev_dbg(&state->i2c->dev, "ucblocks = %d\n", ucb); + + /* handle reset */ + if (ucb < state->ucb_offset) + state->ucb_offset = c->block_error.stat[0].uvalue; + + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue = ucb + state->ucb_offset; + + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].uvalue += state->bitrate / 8 / 208; + } +} + +static void cx24120_set_clock_ratios(struct dvb_frontend *fe); + +/* Read current tuning status */ +static int cx24120_read_status(struct dvb_frontend *fe, enum fe_status *status) +{ + struct cx24120_state *state = fe->demodulator_priv; + int lock; + + lock = cx24120_readreg(state, CX24120_REG_STATUS); + + dev_dbg(&state->i2c->dev, "status = 0x%02x\n", lock); + + *status = 0; + + if (lock & CX24120_HAS_SIGNAL) + *status = FE_HAS_SIGNAL; + if (lock & CX24120_HAS_CARRIER) + *status |= FE_HAS_CARRIER; + if (lock & CX24120_HAS_VITERBI) + *status |= FE_HAS_VITERBI | FE_HAS_SYNC; + if (lock & CX24120_HAS_LOCK) + *status |= FE_HAS_LOCK; + + /* + * TODO: is FE_HAS_SYNC in the right place? + * Other cx241xx drivers have this slightly + * different + */ + + state->fe_status = *status; + cx24120_get_stats(state); + + /* Set the clock once tuned in */ + if (state->need_clock_set && *status & FE_HAS_LOCK) { + /* Set clock ratios */ + cx24120_set_clock_ratios(fe); + + /* Old driver would do a msleep(200) here */ + + /* Renable mpeg output */ + if (!state->mpeg_enabled) + cx24120_msg_mpeg_output_global_config(state, 1); + + state->need_clock_set = 0; + } + + return 0; +} + +/* + * FEC & modulation lookup table + * Used for decoding the REG_FECMODE register + * once tuned in. + */ +struct cx24120_modfec { + enum fe_delivery_system delsys; + enum fe_modulation mod; + enum fe_code_rate fec; + u8 val; +}; + +static const struct cx24120_modfec modfec_lookup_table[] = { + /*delsys mod fec val */ + { SYS_DVBS, QPSK, FEC_1_2, 0x01 }, + { SYS_DVBS, QPSK, FEC_2_3, 0x02 }, + { SYS_DVBS, QPSK, FEC_3_4, 0x03 }, + { SYS_DVBS, QPSK, FEC_4_5, 0x04 }, + { SYS_DVBS, QPSK, FEC_5_6, 0x05 }, + { SYS_DVBS, QPSK, FEC_6_7, 0x06 }, + { SYS_DVBS, QPSK, FEC_7_8, 0x07 }, + + { SYS_DVBS2, QPSK, FEC_1_2, 0x04 }, + { SYS_DVBS2, QPSK, FEC_3_5, 0x05 }, + { SYS_DVBS2, QPSK, FEC_2_3, 0x06 }, + { SYS_DVBS2, QPSK, FEC_3_4, 0x07 }, + { SYS_DVBS2, QPSK, FEC_4_5, 0x08 }, + { SYS_DVBS2, QPSK, FEC_5_6, 0x09 }, + { SYS_DVBS2, QPSK, FEC_8_9, 0x0a }, + { SYS_DVBS2, QPSK, FEC_9_10, 0x0b }, + + { SYS_DVBS2, PSK_8, FEC_3_5, 0x0c }, + { SYS_DVBS2, PSK_8, FEC_2_3, 0x0d }, + { SYS_DVBS2, PSK_8, FEC_3_4, 0x0e }, + { SYS_DVBS2, PSK_8, FEC_5_6, 0x0f }, + { SYS_DVBS2, PSK_8, FEC_8_9, 0x10 }, + { SYS_DVBS2, PSK_8, FEC_9_10, 0x11 }, +}; + +/* Retrieve current fec, modulation & pilot values */ +static int cx24120_get_fec(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct cx24120_state *state = fe->demodulator_priv; + int idx; + int ret; + int fec; + + ret = cx24120_readreg(state, CX24120_REG_FECMODE); + fec = ret & 0x3f; /* Lower 6 bits */ + + dev_dbg(&state->i2c->dev, "raw fec = %d\n", fec); + + for (idx = 0; idx < ARRAY_SIZE(modfec_lookup_table); idx++) { + if (modfec_lookup_table[idx].delsys != state->dcur.delsys) + continue; + if (modfec_lookup_table[idx].val != fec) + continue; + + break; /* found */ + } + + if (idx >= ARRAY_SIZE(modfec_lookup_table)) { + dev_dbg(&state->i2c->dev, "couldn't find fec!\n"); + return -EINVAL; + } + + /* save values back to cache */ + c->modulation = modfec_lookup_table[idx].mod; + c->fec_inner = modfec_lookup_table[idx].fec; + c->pilot = (ret & 0x80) ? PILOT_ON : PILOT_OFF; + + dev_dbg(&state->i2c->dev, "mod(%d), fec(%d), pilot(%d)\n", + c->modulation, c->fec_inner, c->pilot); + + return 0; +} + +/* Calculate ber window time */ +static void cx24120_calculate_ber_window(struct cx24120_state *state, u32 rate) +{ + struct dvb_frontend *fe = &state->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u64 tmp; + + /* + * Calculate bitrate from rate in the clock ratios table. + * This isn't *exactly* right but close enough. + */ + tmp = (u64)c->symbol_rate * rate; + do_div(tmp, 256); + state->bitrate = tmp; + + /* usecs per ber window */ + tmp = 1000000ULL * CX24120_BER_WSIZE; + do_div(tmp, state->bitrate); + state->berw_usecs = tmp; + + dev_dbg(&state->i2c->dev, "bitrate: %u, berw_usecs: %u\n", + state->bitrate, state->berw_usecs); +} + +/* + * Clock ratios lookup table + * + * Values obtained from much larger table in old driver + * which had numerous entries which would never match. + * + * There's probably some way of calculating these but I + * can't determine the pattern + */ +struct cx24120_clock_ratios_table { + enum fe_delivery_system delsys; + enum fe_pilot pilot; + enum fe_modulation mod; + enum fe_code_rate fec; + u32 m_rat; + u32 n_rat; + u32 rate; +}; + +static const struct cx24120_clock_ratios_table clock_ratios_table[] = { + /*delsys pilot mod fec m_rat n_rat rate */ + { SYS_DVBS2, PILOT_OFF, QPSK, FEC_1_2, 273088, 254505, 274 }, + { SYS_DVBS2, PILOT_OFF, QPSK, FEC_3_5, 17272, 13395, 330 }, + { SYS_DVBS2, PILOT_OFF, QPSK, FEC_2_3, 24344, 16967, 367 }, + { SYS_DVBS2, PILOT_OFF, QPSK, FEC_3_4, 410788, 254505, 413 }, + { SYS_DVBS2, PILOT_OFF, QPSK, FEC_4_5, 438328, 254505, 440 }, + { SYS_DVBS2, PILOT_OFF, QPSK, FEC_5_6, 30464, 16967, 459 }, + { SYS_DVBS2, PILOT_OFF, QPSK, FEC_8_9, 487832, 254505, 490 }, + { SYS_DVBS2, PILOT_OFF, QPSK, FEC_9_10, 493952, 254505, 496 }, + { SYS_DVBS2, PILOT_OFF, PSK_8, FEC_3_5, 328168, 169905, 494 }, + { SYS_DVBS2, PILOT_OFF, PSK_8, FEC_2_3, 24344, 11327, 550 }, + { SYS_DVBS2, PILOT_OFF, PSK_8, FEC_3_4, 410788, 169905, 618 }, + { SYS_DVBS2, PILOT_OFF, PSK_8, FEC_5_6, 30464, 11327, 688 }, + { SYS_DVBS2, PILOT_OFF, PSK_8, FEC_8_9, 487832, 169905, 735 }, + { SYS_DVBS2, PILOT_OFF, PSK_8, FEC_9_10, 493952, 169905, 744 }, + { SYS_DVBS2, PILOT_ON, QPSK, FEC_1_2, 273088, 260709, 268 }, + { SYS_DVBS2, PILOT_ON, QPSK, FEC_3_5, 328168, 260709, 322 }, + { SYS_DVBS2, PILOT_ON, QPSK, FEC_2_3, 121720, 86903, 358 }, + { SYS_DVBS2, PILOT_ON, QPSK, FEC_3_4, 410788, 260709, 403 }, + { SYS_DVBS2, PILOT_ON, QPSK, FEC_4_5, 438328, 260709, 430 }, + { SYS_DVBS2, PILOT_ON, QPSK, FEC_5_6, 152320, 86903, 448 }, + { SYS_DVBS2, PILOT_ON, QPSK, FEC_8_9, 487832, 260709, 479 }, + { SYS_DVBS2, PILOT_ON, QPSK, FEC_9_10, 493952, 260709, 485 }, + { SYS_DVBS2, PILOT_ON, PSK_8, FEC_3_5, 328168, 173853, 483 }, + { SYS_DVBS2, PILOT_ON, PSK_8, FEC_2_3, 121720, 57951, 537 }, + { SYS_DVBS2, PILOT_ON, PSK_8, FEC_3_4, 410788, 173853, 604 }, + { SYS_DVBS2, PILOT_ON, PSK_8, FEC_5_6, 152320, 57951, 672 }, + { SYS_DVBS2, PILOT_ON, PSK_8, FEC_8_9, 487832, 173853, 718 }, + { SYS_DVBS2, PILOT_ON, PSK_8, FEC_9_10, 493952, 173853, 727 }, + { SYS_DVBS, PILOT_OFF, QPSK, FEC_1_2, 152592, 152592, 256 }, + { SYS_DVBS, PILOT_OFF, QPSK, FEC_2_3, 305184, 228888, 341 }, + { SYS_DVBS, PILOT_OFF, QPSK, FEC_3_4, 457776, 305184, 384 }, + { SYS_DVBS, PILOT_OFF, QPSK, FEC_5_6, 762960, 457776, 427 }, + { SYS_DVBS, PILOT_OFF, QPSK, FEC_7_8, 1068144, 610368, 448 }, +}; + +/* Set clock ratio from lookup table */ +static void cx24120_set_clock_ratios(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct cx24120_state *state = fe->demodulator_priv; + struct cx24120_cmd cmd; + int ret, idx; + + /* Find fec, modulation, pilot */ + ret = cx24120_get_fec(fe); + if (ret != 0) + return; + + /* Find the clock ratios in the lookup table */ + for (idx = 0; idx < ARRAY_SIZE(clock_ratios_table); idx++) { + if (clock_ratios_table[idx].delsys != state->dcur.delsys) + continue; + if (clock_ratios_table[idx].mod != c->modulation) + continue; + if (clock_ratios_table[idx].fec != c->fec_inner) + continue; + if (clock_ratios_table[idx].pilot != c->pilot) + continue; + + break; /* found */ + } + + if (idx >= ARRAY_SIZE(clock_ratios_table)) { + info("Clock ratio not found - data reception in danger\n"); + return; + } + + /* Read current values? */ + cmd.id = CMD_CLOCK_READ; + cmd.len = 1; + cmd.arg[0] = 0x00; + ret = cx24120_message_sendrcv(state, &cmd, 6); + if (ret != 0) + return; + /* in cmd[0]-[5] - result */ + + dev_dbg(&state->i2c->dev, "m=%d, n=%d; idx: %d m=%d, n=%d, rate=%d\n", + cmd.arg[2] | (cmd.arg[1] << 8) | (cmd.arg[0] << 16), + cmd.arg[5] | (cmd.arg[4] << 8) | (cmd.arg[3] << 16), + idx, + clock_ratios_table[idx].m_rat, + clock_ratios_table[idx].n_rat, + clock_ratios_table[idx].rate); + + /* Set the clock */ + cmd.id = CMD_CLOCK_SET; + cmd.len = 10; + cmd.arg[0] = 0; + cmd.arg[1] = 0x10; + cmd.arg[2] = (clock_ratios_table[idx].m_rat >> 16) & 0xff; + cmd.arg[3] = (clock_ratios_table[idx].m_rat >> 8) & 0xff; + cmd.arg[4] = (clock_ratios_table[idx].m_rat >> 0) & 0xff; + cmd.arg[5] = (clock_ratios_table[idx].n_rat >> 16) & 0xff; + cmd.arg[6] = (clock_ratios_table[idx].n_rat >> 8) & 0xff; + cmd.arg[7] = (clock_ratios_table[idx].n_rat >> 0) & 0xff; + cmd.arg[8] = (clock_ratios_table[idx].rate >> 8) & 0xff; + cmd.arg[9] = (clock_ratios_table[idx].rate >> 0) & 0xff; + + cx24120_message_send(state, &cmd); + + /* Calculate ber window rates for stat work */ + cx24120_calculate_ber_window(state, clock_ratios_table[idx].rate); +} + +/* Set inversion value */ +static int cx24120_set_inversion(struct cx24120_state *state, + enum fe_spectral_inversion inversion) +{ + dev_dbg(&state->i2c->dev, "(%d)\n", inversion); + + switch (inversion) { + case INVERSION_OFF: + state->dnxt.inversion_val = 0x00; + break; + case INVERSION_ON: + state->dnxt.inversion_val = 0x04; + break; + case INVERSION_AUTO: + state->dnxt.inversion_val = 0x0c; + break; + default: + return -EINVAL; + } + + state->dnxt.inversion = inversion; + + return 0; +} + +/* FEC lookup table for tuning */ +struct cx24120_modfec_table { + enum fe_delivery_system delsys; + enum fe_modulation mod; + enum fe_code_rate fec; + u8 val; +}; + +static const struct cx24120_modfec_table modfec_table[] = { + /*delsys mod fec val */ + { SYS_DVBS, QPSK, FEC_1_2, 0x2e }, + { SYS_DVBS, QPSK, FEC_2_3, 0x2f }, + { SYS_DVBS, QPSK, FEC_3_4, 0x30 }, + { SYS_DVBS, QPSK, FEC_5_6, 0x31 }, + { SYS_DVBS, QPSK, FEC_6_7, 0x32 }, + { SYS_DVBS, QPSK, FEC_7_8, 0x33 }, + + { SYS_DVBS2, QPSK, FEC_1_2, 0x04 }, + { SYS_DVBS2, QPSK, FEC_3_5, 0x05 }, + { SYS_DVBS2, QPSK, FEC_2_3, 0x06 }, + { SYS_DVBS2, QPSK, FEC_3_4, 0x07 }, + { SYS_DVBS2, QPSK, FEC_4_5, 0x08 }, + { SYS_DVBS2, QPSK, FEC_5_6, 0x09 }, + { SYS_DVBS2, QPSK, FEC_8_9, 0x0a }, + { SYS_DVBS2, QPSK, FEC_9_10, 0x0b }, + + { SYS_DVBS2, PSK_8, FEC_3_5, 0x0c }, + { SYS_DVBS2, PSK_8, FEC_2_3, 0x0d }, + { SYS_DVBS2, PSK_8, FEC_3_4, 0x0e }, + { SYS_DVBS2, PSK_8, FEC_5_6, 0x0f }, + { SYS_DVBS2, PSK_8, FEC_8_9, 0x10 }, + { SYS_DVBS2, PSK_8, FEC_9_10, 0x11 }, +}; + +/* Set fec_val & fec_mask values from delsys, modulation & fec */ +static int cx24120_set_fec(struct cx24120_state *state, enum fe_modulation mod, + enum fe_code_rate fec) +{ + int idx; + + dev_dbg(&state->i2c->dev, "(0x%02x,0x%02x)\n", mod, fec); + + state->dnxt.fec = fec; + + /* Lookup fec_val from modfec table */ + for (idx = 0; idx < ARRAY_SIZE(modfec_table); idx++) { + if (modfec_table[idx].delsys != state->dnxt.delsys) + continue; + if (modfec_table[idx].mod != mod) + continue; + if (modfec_table[idx].fec != fec) + continue; + + /* found */ + state->dnxt.fec_mask = 0x00; + state->dnxt.fec_val = modfec_table[idx].val; + return 0; + } + + if (state->dnxt.delsys == SYS_DVBS2) { + /* DVBS2 auto is 0x00/0x00 */ + state->dnxt.fec_mask = 0x00; + state->dnxt.fec_val = 0x00; + } else { + /* Set DVB-S to auto */ + state->dnxt.fec_val = 0x2e; + state->dnxt.fec_mask = 0xac; + } + + return 0; +} + +/* Set pilot */ +static int cx24120_set_pilot(struct cx24120_state *state, enum fe_pilot pilot) +{ + dev_dbg(&state->i2c->dev, "(%d)\n", pilot); + + /* Pilot only valid in DVBS2 */ + if (state->dnxt.delsys != SYS_DVBS2) { + state->dnxt.pilot_val = CX24120_PILOT_OFF; + return 0; + } + + switch (pilot) { + case PILOT_OFF: + state->dnxt.pilot_val = CX24120_PILOT_OFF; + break; + case PILOT_ON: + state->dnxt.pilot_val = CX24120_PILOT_ON; + break; + case PILOT_AUTO: + default: + state->dnxt.pilot_val = CX24120_PILOT_AUTO; + } + + return 0; +} + +/* Set symbol rate */ +static int cx24120_set_symbolrate(struct cx24120_state *state, u32 rate) +{ + dev_dbg(&state->i2c->dev, "(%d)\n", rate); + + state->dnxt.symbol_rate = rate; + + /* Check symbol rate */ + if (rate > 31000000) { + state->dnxt.clkdiv = (-(rate < 31000001) & 3) + 2; + state->dnxt.ratediv = (-(rate < 31000001) & 6) + 4; + } else { + state->dnxt.clkdiv = 3; + state->dnxt.ratediv = 6; + } + + return 0; +} + +/* Overwrite the current tuning params, we are about to tune */ +static void cx24120_clone_params(struct dvb_frontend *fe) +{ + struct cx24120_state *state = fe->demodulator_priv; + + state->dcur = state->dnxt; +} + +static int cx24120_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct cx24120_state *state = fe->demodulator_priv; + struct cx24120_cmd cmd; + int ret; + + switch (c->delivery_system) { + case SYS_DVBS2: + dev_dbg(&state->i2c->dev, "DVB-S2\n"); + break; + case SYS_DVBS: + dev_dbg(&state->i2c->dev, "DVB-S\n"); + break; + default: + dev_dbg(&state->i2c->dev, + "delivery system(%d) not supported\n", + c->delivery_system); + ret = -EINVAL; + break; + } + + state->dnxt.delsys = c->delivery_system; + state->dnxt.modulation = c->modulation; + state->dnxt.frequency = c->frequency; + state->dnxt.pilot = c->pilot; + + ret = cx24120_set_inversion(state, c->inversion); + if (ret != 0) + return ret; + + ret = cx24120_set_fec(state, c->modulation, c->fec_inner); + if (ret != 0) + return ret; + + ret = cx24120_set_pilot(state, c->pilot); + if (ret != 0) + return ret; + + ret = cx24120_set_symbolrate(state, c->symbol_rate); + if (ret != 0) + return ret; + + /* discard the 'current' tuning parameters and prepare to tune */ + cx24120_clone_params(fe); + + dev_dbg(&state->i2c->dev, + "delsys = %d\n", state->dcur.delsys); + dev_dbg(&state->i2c->dev, + "modulation = %d\n", state->dcur.modulation); + dev_dbg(&state->i2c->dev, + "frequency = %d\n", state->dcur.frequency); + dev_dbg(&state->i2c->dev, + "pilot = %d (val = 0x%02x)\n", + state->dcur.pilot, state->dcur.pilot_val); + dev_dbg(&state->i2c->dev, + "symbol_rate = %d (clkdiv/ratediv = 0x%02x/0x%02x)\n", + state->dcur.symbol_rate, + state->dcur.clkdiv, state->dcur.ratediv); + dev_dbg(&state->i2c->dev, + "FEC = %d (mask/val = 0x%02x/0x%02x)\n", + state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val); + dev_dbg(&state->i2c->dev, + "Inversion = %d (val = 0x%02x)\n", + state->dcur.inversion, state->dcur.inversion_val); + + /* Flag that clock needs to be set after tune */ + state->need_clock_set = 1; + + /* Tune in */ + cmd.id = CMD_TUNEREQUEST; + cmd.len = 15; + cmd.arg[0] = 0; + cmd.arg[1] = (state->dcur.frequency & 0xff0000) >> 16; + cmd.arg[2] = (state->dcur.frequency & 0x00ff00) >> 8; + cmd.arg[3] = (state->dcur.frequency & 0x0000ff); + cmd.arg[4] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8; + cmd.arg[5] = ((state->dcur.symbol_rate / 1000) & 0x00ff); + cmd.arg[6] = state->dcur.inversion; + cmd.arg[7] = state->dcur.fec_val | state->dcur.pilot_val; + cmd.arg[8] = CX24120_SEARCH_RANGE_KHZ >> 8; + cmd.arg[9] = CX24120_SEARCH_RANGE_KHZ & 0xff; + cmd.arg[10] = 0; /* maybe rolloff? */ + cmd.arg[11] = state->dcur.fec_mask; + cmd.arg[12] = state->dcur.ratediv; + cmd.arg[13] = state->dcur.clkdiv; + cmd.arg[14] = 0; + + /* Send tune command */ + ret = cx24120_message_send(state, &cmd); + if (ret != 0) + return ret; + + /* Write symbol rate values */ + ret = cx24120_writereg(state, CX24120_REG_CLKDIV, state->dcur.clkdiv); + ret = cx24120_readreg(state, CX24120_REG_RATEDIV); + ret &= 0xfffffff0; + ret |= state->dcur.ratediv; + ret = cx24120_writereg(state, CX24120_REG_RATEDIV, ret); + + return 0; +} + +/* Set vco from config */ +static int cx24120_set_vco(struct cx24120_state *state) +{ + struct cx24120_cmd cmd; + u32 nxtal_khz, vco; + u64 inv_vco; + u32 xtal_khz = state->config->xtal_khz; + + nxtal_khz = xtal_khz * 4; + vco = nxtal_khz * 10; + inv_vco = DIV_ROUND_CLOSEST_ULL(0x400000000ULL, vco); + + dev_dbg(&state->i2c->dev, "xtal=%d, vco=%d, inv_vco=%lld\n", + xtal_khz, vco, inv_vco); + + cmd.id = CMD_VCO_SET; + cmd.len = 12; + cmd.arg[0] = (vco >> 16) & 0xff; + cmd.arg[1] = (vco >> 8) & 0xff; + cmd.arg[2] = vco & 0xff; + cmd.arg[3] = (inv_vco >> 8) & 0xff; + cmd.arg[4] = (inv_vco) & 0xff; + cmd.arg[5] = 0x03; + cmd.arg[6] = (nxtal_khz >> 8) & 0xff; + cmd.arg[7] = nxtal_khz & 0xff; + cmd.arg[8] = 0x06; + cmd.arg[9] = 0x03; + cmd.arg[10] = (xtal_khz >> 16) & 0xff; + cmd.arg[11] = xtal_khz & 0xff; + + return cx24120_message_send(state, &cmd); +} + +static int cx24120_init(struct dvb_frontend *fe) +{ + const struct firmware *fw; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct cx24120_state *state = fe->demodulator_priv; + struct cx24120_cmd cmd; + u8 reg; + int ret, i; + unsigned char vers[4]; + + if (state->cold_init) + return 0; + + /* ???? */ + cx24120_writereg(state, 0xea, 0x00); + cx24120_test_rom(state); + reg = cx24120_readreg(state, 0xfb) & 0xfe; + cx24120_writereg(state, 0xfb, reg); + reg = cx24120_readreg(state, 0xfc) & 0xfe; + cx24120_writereg(state, 0xfc, reg); + cx24120_writereg(state, 0xc3, 0x04); + cx24120_writereg(state, 0xc4, 0x04); + cx24120_writereg(state, 0xce, 0x00); + cx24120_writereg(state, 0xcf, 0x00); + reg = cx24120_readreg(state, 0xea) & 0xfe; + cx24120_writereg(state, 0xea, reg); + cx24120_writereg(state, 0xeb, 0x0c); + cx24120_writereg(state, 0xec, 0x06); + cx24120_writereg(state, 0xed, 0x05); + cx24120_writereg(state, 0xee, 0x03); + cx24120_writereg(state, 0xef, 0x05); + cx24120_writereg(state, 0xf3, 0x03); + cx24120_writereg(state, 0xf4, 0x44); + + for (i = 0; i < 3; i++) { + cx24120_writereg(state, 0xf0 + i, 0x04); + cx24120_writereg(state, 0xe6 + i, 0x02); + } + + cx24120_writereg(state, 0xea, (reg | 0x01)); + for (i = 0; i < 6; i += 2) { + cx24120_writereg(state, 0xc5 + i, 0x00); + cx24120_writereg(state, 0xc6 + i, 0x00); + } + + cx24120_writereg(state, 0xe4, 0x03); + cx24120_writereg(state, 0xeb, 0x0a); + + dev_dbg(&state->i2c->dev, "requesting firmware (%s) to download...\n", + CX24120_FIRMWARE); + + ret = state->config->request_firmware(fe, &fw, CX24120_FIRMWARE); + if (ret) { + err("Could not load firmware (%s): %d\n", CX24120_FIRMWARE, + ret); + return ret; + } + + dev_dbg(&state->i2c->dev, + "Firmware found, size %d bytes (%02x %02x .. %02x %02x)\n", + (int)fw->size, /* firmware_size in bytes */ + fw->data[0], /* fw 1st byte */ + fw->data[1], /* fw 2d byte */ + fw->data[fw->size - 2], /* fw before last byte */ + fw->data[fw->size - 1]); /* fw last byte */ + + cx24120_test_rom(state); + reg = cx24120_readreg(state, 0xfb) & 0xfe; + cx24120_writereg(state, 0xfb, reg); + cx24120_writereg(state, 0xe0, 0x76); + cx24120_writereg(state, 0xf7, 0x81); + cx24120_writereg(state, 0xf8, 0x00); + cx24120_writereg(state, 0xf9, 0x00); + cx24120_writeregs(state, 0xfa, fw->data, (fw->size - 1), 0x00); + cx24120_writereg(state, 0xf7, 0xc0); + cx24120_writereg(state, 0xe0, 0x00); + reg = (fw->size - 2) & 0x00ff; + cx24120_writereg(state, 0xf8, reg); + reg = ((fw->size - 2) >> 8) & 0x00ff; + cx24120_writereg(state, 0xf9, reg); + cx24120_writereg(state, 0xf7, 0x00); + cx24120_writereg(state, 0xdc, 0x00); + cx24120_writereg(state, 0xdc, 0x07); + msleep(500); + + /* Check final byte matches final byte of firmware */ + reg = cx24120_readreg(state, 0xe1); + if (reg == fw->data[fw->size - 1]) { + dev_dbg(&state->i2c->dev, "Firmware uploaded successfully\n"); + ret = 0; + } else { + err("Firmware upload failed. Last byte returned=0x%x\n", ret); + ret = -EREMOTEIO; + } + cx24120_writereg(state, 0xdc, 0x00); + release_firmware(fw); + if (ret != 0) + return ret; + + /* Start tuner */ + cmd.id = CMD_START_TUNER; + cmd.len = 3; + cmd.arg[0] = 0x00; + cmd.arg[1] = 0x00; + cmd.arg[2] = 0x00; + + if (cx24120_message_send(state, &cmd) != 0) { + err("Error tuner start! :(\n"); + return -EREMOTEIO; + } + + /* Set VCO */ + ret = cx24120_set_vco(state); + if (ret != 0) { + err("Error set VCO! :(\n"); + return ret; + } + + /* set bandwidth */ + cmd.id = CMD_BANDWIDTH; + cmd.len = 12; + cmd.arg[0] = 0x00; + cmd.arg[1] = 0x00; + cmd.arg[2] = 0x00; + cmd.arg[3] = 0x00; + cmd.arg[4] = 0x05; + cmd.arg[5] = 0x02; + cmd.arg[6] = 0x02; + cmd.arg[7] = 0x00; + cmd.arg[8] = 0x05; + cmd.arg[9] = 0x02; + cmd.arg[10] = 0x02; + cmd.arg[11] = 0x00; + + if (cx24120_message_send(state, &cmd)) { + err("Error set bandwidth!\n"); + return -EREMOTEIO; + } + + reg = cx24120_readreg(state, 0xba); + if (reg > 3) { + dev_dbg(&state->i2c->dev, "Reset-readreg 0xba: %x\n", ret); + err("Error initialising tuner!\n"); + return -EREMOTEIO; + } + + dev_dbg(&state->i2c->dev, "Tuner initialised correctly.\n"); + + /* Initialise mpeg outputs */ + cx24120_writereg(state, 0xeb, 0x0a); + if (cx24120_msg_mpeg_output_global_config(state, 0) || + cx24120_msg_mpeg_output_config(state, 0) || + cx24120_msg_mpeg_output_config(state, 1) || + cx24120_msg_mpeg_output_config(state, 2)) { + err("Error initialising mpeg output. :(\n"); + return -EREMOTEIO; + } + + /* Set size of BER window */ + cmd.id = CMD_BER_CTRL; + cmd.len = 3; + cmd.arg[0] = 0x00; + cmd.arg[1] = CX24120_BER_WINDOW; + cmd.arg[2] = CX24120_BER_WINDOW; + if (cx24120_message_send(state, &cmd)) { + err("Error setting ber window\n"); + return -EREMOTEIO; + } + + /* Firmware CMD 35: Get firmware version */ + cmd.id = CMD_FWVERSION; + cmd.len = 1; + for (i = 0; i < 4; i++) { + cmd.arg[0] = i; + ret = cx24120_message_send(state, &cmd); + if (ret != 0) + return ret; + vers[i] = cx24120_readreg(state, CX24120_REG_MAILBOX); + } + info("FW version %i.%i.%i.%i\n", vers[0], vers[1], vers[2], vers[3]); + + /* init stats here in order signal app which stats are supported */ + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.len = 1; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.len = 1; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + + state->cold_init = 1; + + return 0; +} + +static int cx24120_tune(struct dvb_frontend *fe, bool re_tune, + unsigned int mode_flags, unsigned int *delay, + enum fe_status *status) +{ + struct cx24120_state *state = fe->demodulator_priv; + int ret; + + dev_dbg(&state->i2c->dev, "(%d)\n", re_tune); + + /* TODO: Do we need to set delay? */ + + if (re_tune) { + ret = cx24120_set_frontend(fe); + if (ret) + return ret; + } + + return cx24120_read_status(fe, status); +} + +static int cx24120_get_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_HW; +} + +static int cx24120_sleep(struct dvb_frontend *fe) +{ + return 0; +} + +static int cx24120_get_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct cx24120_state *state = fe->demodulator_priv; + u8 freq1, freq2, freq3; + + dev_dbg(&state->i2c->dev, "\n"); + + /* don't return empty data if we're not tuned in */ + if ((state->fe_status & FE_HAS_LOCK) == 0) + return 0; + + /* Get frequency */ + freq1 = cx24120_readreg(state, CX24120_REG_FREQ1); + freq2 = cx24120_readreg(state, CX24120_REG_FREQ2); + freq3 = cx24120_readreg(state, CX24120_REG_FREQ3); + c->frequency = (freq3 << 16) | (freq2 << 8) | freq1; + dev_dbg(&state->i2c->dev, "frequency = %d\n", c->frequency); + + /* Get modulation, fec, pilot */ + cx24120_get_fec(fe); + + return 0; +} + +static void cx24120_release(struct dvb_frontend *fe) +{ + struct cx24120_state *state = fe->demodulator_priv; + + dev_dbg(&state->i2c->dev, "Clear state structure\n"); + kfree(state); +} + +static int cx24120_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct cx24120_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + if (c->block_error.stat[0].scale != FE_SCALE_COUNTER) { + *ucblocks = 0; + return 0; + } + + *ucblocks = c->block_error.stat[0].uvalue - state->ucb_offset; + + return 0; +} + +static struct dvb_frontend_ops cx24120_ops = { + .delsys = { SYS_DVBS, SYS_DVBS2 }, + .info = { + .name = "Conexant CX24120/CX24118", + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1011, /* kHz for QPSK frontends */ + .frequency_tolerance = 5000, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .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_AUTO | + FE_CAN_2G_MODULATION | + FE_CAN_QPSK | FE_CAN_RECOVER + }, + .release = cx24120_release, + + .init = cx24120_init, + .sleep = cx24120_sleep, + + .tune = cx24120_tune, + .get_frontend_algo = cx24120_get_algo, + .set_frontend = cx24120_set_frontend, + + .get_frontend = cx24120_get_frontend, + .read_status = cx24120_read_status, + .read_ber = cx24120_read_ber, + .read_signal_strength = cx24120_read_signal_strength, + .read_snr = cx24120_read_snr, + .read_ucblocks = cx24120_read_ucblocks, + + .diseqc_send_master_cmd = cx24120_send_diseqc_msg, + + .diseqc_send_burst = cx24120_diseqc_send_burst, + .set_tone = cx24120_set_tone, + .set_voltage = cx24120_set_voltage, +}; + +MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24120/CX24118 hardware"); +MODULE_AUTHOR("Jemma Denson"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/cx24120.h b/drivers/media/dvb-frontends/cx24120.h new file mode 100644 index 0000000..f097042 --- /dev/null +++ b/drivers/media/dvb-frontends/cx24120.h @@ -0,0 +1,58 @@ +/* + * Conexant CX24120/CX24118 - DVB-S/S2 demod/tuner driver + * + * Copyright (C) 2008 Patrick Boettcher <pb@linuxtv.org> + * Copyright (C) 2009 Sergey Tyurin <forum.free-x.de> + * Updated 2012 by Jannis Achstetter <jannis_achstetter@web.de> + * Copyright (C) 2015 Jemma Denson <jdenson@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef CX24120_H +#define CX24120_H + +#include <linux/kconfig.h> +#include <linux/dvb/frontend.h> +#include <linux/firmware.h> + +struct cx24120_initial_mpeg_config { + u8 x1; + u8 x2; + u8 x3; +}; + +struct cx24120_config { + u8 i2c_addr; + u32 xtal_khz; + struct cx24120_initial_mpeg_config initial_mpeg_config; + + int (*request_firmware)(struct dvb_frontend *fe, + const struct firmware **fw, char *name); + + /* max bytes I2C provider can write at once */ + u16 i2c_wr_max; +}; + +#if IS_REACHABLE(CONFIG_DVB_CX24120) +struct dvb_frontend *cx24120_attach(const struct cx24120_config *config, + struct i2c_adapter *i2c); +#else +static inline +struct dvb_frontend *cx24120_attach(const struct cx24120_config *config, + struct i2c_adapter *i2c) +{ + pr_warn("%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* CX24120_H */ diff --git a/drivers/media/dvb-frontends/cx24123.c b/drivers/media/dvb-frontends/cx24123.c index 7975c660..e18cf9e 100644 --- a/drivers/media/dvb-frontends/cx24123.c +++ b/drivers/media/dvb-frontends/cx24123.c @@ -290,7 +290,7 @@ static int cx24123_i2c_readreg(struct cx24123_state *state, u8 i2c_addr, u8 reg) cx24123_i2c_writereg(state, state->config->demod_address, reg, val) static int cx24123_set_inversion(struct cx24123_state *state, - fe_spectral_inversion_t inversion) + enum fe_spectral_inversion inversion) { u8 nom_reg = cx24123_readreg(state, 0x0e); u8 auto_reg = cx24123_readreg(state, 0x10); @@ -318,7 +318,7 @@ static int cx24123_set_inversion(struct cx24123_state *state, } static int cx24123_get_inversion(struct cx24123_state *state, - fe_spectral_inversion_t *inversion) + enum fe_spectral_inversion *inversion) { u8 val; @@ -335,7 +335,7 @@ static int cx24123_get_inversion(struct cx24123_state *state, return 0; } -static int cx24123_set_fec(struct cx24123_state *state, fe_code_rate_t fec) +static int cx24123_set_fec(struct cx24123_state *state, enum fe_code_rate fec) { u8 nom_reg = cx24123_readreg(state, 0x0e) & ~0x07; @@ -397,7 +397,7 @@ static int cx24123_set_fec(struct cx24123_state *state, fe_code_rate_t fec) return 0; } -static int cx24123_get_fec(struct cx24123_state *state, fe_code_rate_t *fec) +static int cx24123_get_fec(struct cx24123_state *state, enum fe_code_rate *fec) { int ret; @@ -720,7 +720,7 @@ static int cx24123_initfe(struct dvb_frontend *fe) } static int cx24123_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct cx24123_state *state = fe->demodulator_priv; u8 val; @@ -795,7 +795,7 @@ static int cx24123_send_diseqc_msg(struct dvb_frontend *fe, } static int cx24123_diseqc_send_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t burst) + enum fe_sec_mini_cmd burst) { struct cx24123_state *state = fe->demodulator_priv; int val, tone; @@ -831,7 +831,7 @@ static int cx24123_diseqc_send_burst(struct dvb_frontend *fe, return 0; } -static int cx24123_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int cx24123_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct cx24123_state *state = fe->demodulator_priv; int sync = cx24123_readreg(state, 0x14); @@ -966,7 +966,7 @@ static int cx24123_get_frontend(struct dvb_frontend *fe) return 0; } -static int cx24123_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +static int cx24123_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) { struct cx24123_state *state = fe->demodulator_priv; u8 val; @@ -995,7 +995,7 @@ static int cx24123_tune(struct dvb_frontend *fe, bool re_tune, unsigned int mode_flags, unsigned int *delay, - fe_status_t *status) + enum fe_status *status) { int retval = 0; diff --git a/drivers/media/dvb-frontends/cx24123.h b/drivers/media/dvb-frontends/cx24123.h index 758aee5..975f3c9 100644 --- a/drivers/media/dvb-frontends/cx24123.h +++ b/drivers/media/dvb-frontends/cx24123.h @@ -50,7 +50,7 @@ static inline struct dvb_frontend *cx24123_attach( printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -static struct i2c_adapter * +static inline struct i2c_adapter * cx24123_get_tuner_i2c_adapter(struct dvb_frontend *fe) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c index 72b0e2db..42fad6a 100644 --- a/drivers/media/dvb-frontends/cxd2820r_c.c +++ b/drivers/media/dvb-frontends/cxd2820r_c.c @@ -259,7 +259,7 @@ int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks) return 0; } -int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status) +int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status) { struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index 490e090..def6d21 100644 --- a/drivers/media/dvb-frontends/cxd2820r_core.c +++ b/drivers/media/dvb-frontends/cxd2820r_core.c @@ -287,7 +287,8 @@ static int cxd2820r_set_frontend(struct dvb_frontend *fe) err: return ret; } -static int cxd2820r_read_status(struct dvb_frontend *fe, fe_status_t *status) + +static int cxd2820r_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; @@ -501,7 +502,7 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe) struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i; - fe_status_t status = 0; + enum fe_status status = 0; dev_dbg(&priv->i2c->dev, "%s: delsys=%d\n", __func__, fe->dtv_property_cache.delivery_system); diff --git a/drivers/media/dvb-frontends/cxd2820r_priv.h b/drivers/media/dvb-frontends/cxd2820r_priv.h index 4b42895..a0d53f0 100644 --- a/drivers/media/dvb-frontends/cxd2820r_priv.h +++ b/drivers/media/dvb-frontends/cxd2820r_priv.h @@ -48,7 +48,7 @@ struct cxd2820r_priv { struct gpio_chip gpio_chip; #endif - fe_delivery_system_t delivery_system; + enum fe_delivery_system delivery_system; bool last_tune_failed; /* for switch between T and T2 tune */ }; @@ -80,7 +80,7 @@ int cxd2820r_get_frontend_c(struct dvb_frontend *fe); int cxd2820r_set_frontend_c(struct dvb_frontend *fe); -int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status); +int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status); int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber); @@ -103,7 +103,7 @@ int cxd2820r_get_frontend_t(struct dvb_frontend *fe); int cxd2820r_set_frontend_t(struct dvb_frontend *fe); -int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status); +int cxd2820r_read_status_t(struct dvb_frontend *fe, enum fe_status *status); int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber); @@ -126,7 +126,7 @@ int cxd2820r_get_frontend_t2(struct dvb_frontend *fe); int cxd2820r_set_frontend_t2(struct dvb_frontend *fe); -int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status); +int cxd2820r_read_status_t2(struct dvb_frontend *fe, enum fe_status *status); int cxd2820r_read_ber_t2(struct dvb_frontend *fe, u32 *ber); diff --git a/drivers/media/dvb-frontends/cxd2820r_t.c b/drivers/media/dvb-frontends/cxd2820r_t.c index 008cb2a..21abf1b 100644 --- a/drivers/media/dvb-frontends/cxd2820r_t.c +++ b/drivers/media/dvb-frontends/cxd2820r_t.c @@ -349,7 +349,7 @@ int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks) return 0; } -int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status) +int cxd2820r_read_status_t(struct dvb_frontend *fe, enum fe_status *status) { struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; diff --git a/drivers/media/dvb-frontends/cxd2820r_t2.c b/drivers/media/dvb-frontends/cxd2820r_t2.c index 35fe364..4e028b4 100644 --- a/drivers/media/dvb-frontends/cxd2820r_t2.c +++ b/drivers/media/dvb-frontends/cxd2820r_t2.c @@ -284,7 +284,7 @@ error: return ret; } -int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status) +int cxd2820r_read_status_t2(struct dvb_frontend *fe, enum fe_status *status) { struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; diff --git a/drivers/media/dvb-frontends/dib0070.c b/drivers/media/dvb-frontends/dib0070.c index 3b024bf..0b8fb5d 100644 --- a/drivers/media/dvb-frontends/dib0070.c +++ b/drivers/media/dvb-frontends/dib0070.c @@ -58,10 +58,10 @@ struct dib0070_state { u16 wbd_ff_offset; u8 revision; - enum frontend_tune_state tune_state; - u32 current_rf; + enum frontend_tune_state tune_state; + u32 current_rf; - /* for the captrim binary search */ + /* for the captrim binary search */ s8 step; u16 adc_diff; @@ -72,7 +72,7 @@ struct dib0070_state { const struct dib0070_tuning *current_tune_table_index; const struct dib0070_lna_match *lna_match; - u8 wbd_gain_current; + u8 wbd_gain_current; u16 wbd_offset_3_3[2]; /* for the I2C transfer */ @@ -151,31 +151,31 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) } while (0) static int dib0070_set_bandwidth(struct dvb_frontend *fe) -{ - struct dib0070_state *state = fe->tuner_priv; - u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff; - - if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 7000) - tmp |= (0 << 14); - else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 6000) - tmp |= (1 << 14); - else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 5000) - tmp |= (2 << 14); - else - tmp |= (3 << 14); - - dib0070_write_reg(state, 0x02, tmp); - - /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */ - if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) { - u16 value = dib0070_read_reg(state, 0x17); - - dib0070_write_reg(state, 0x17, value & 0xfffc); - tmp = dib0070_read_reg(state, 0x01) & 0x01ff; - dib0070_write_reg(state, 0x01, tmp | (60 << 9)); - - dib0070_write_reg(state, 0x17, value); - } + { + struct dib0070_state *state = fe->tuner_priv; + u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff; + + if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 7000) + tmp |= (0 << 14); + else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 6000) + tmp |= (1 << 14); + else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 5000) + tmp |= (2 << 14); + else + tmp |= (3 << 14); + + dib0070_write_reg(state, 0x02, tmp); + + /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */ + if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) { + u16 value = dib0070_read_reg(state, 0x17); + + dib0070_write_reg(state, 0x17, value & 0xfffc); + tmp = dib0070_read_reg(state, 0x01) & 0x01ff; + dib0070_write_reg(state, 0x01, tmp | (60 << 9)); + + dib0070_write_reg(state, 0x17, value); + } return 0; } @@ -186,7 +186,6 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state int ret = 0; if (*tune_state == CT_TUNER_STEP_0) { - dib0070_write_reg(state, 0x0f, 0xed10); dib0070_write_reg(state, 0x17, 0x0034); @@ -195,7 +194,7 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state state->adc_diff = 3000; ret = 20; - *tune_state = CT_TUNER_STEP_1; + *tune_state = CT_TUNER_STEP_1; } else if (*tune_state == CT_TUNER_STEP_1) { state->step /= 2; dib0070_write_reg(state, 0x14, state->lo4 | state->captrim); @@ -220,9 +219,6 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state dprintk("CAPTRIM=%hd is closer to target (%hd/%hd)", state->captrim, adc, state->adc_diff); state->adc_diff = adc; state->fcaptrim = state->captrim; - - - } state->captrim += (step_sign * state->step); @@ -243,7 +239,8 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt) { struct dib0070_state *state = fe->tuner_priv; - u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); + u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); + dprintk("CTRL_LO5: 0x%x", lo5); return dib0070_write_reg(state, 0x15, lo5); } @@ -257,281 +254,282 @@ void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open) dib0070_write_reg(state, 0x1a, 0x0000); } else { dib0070_write_reg(state, 0x1b, 0x4112); - if (state->cfg->vga_filter != 0) { - dib0070_write_reg(state, 0x1a, state->cfg->vga_filter); - dprintk("vga filter register is set to %x", state->cfg->vga_filter); - } else - dib0070_write_reg(state, 0x1a, 0x0009); + if (state->cfg->vga_filter != 0) { + dib0070_write_reg(state, 0x1a, state->cfg->vga_filter); + dprintk("vga filter register is set to %x", state->cfg->vga_filter); + } else + dib0070_write_reg(state, 0x1a, 0x0009); } } EXPORT_SYMBOL(dib0070_ctrl_agc_filter); struct dib0070_tuning { - u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ - u8 switch_trim; - u8 vco_band; - u8 hfdiv; - u8 vco_multi; - u8 presc; - u8 wbdmux; - u16 tuner_enable; + u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ + u8 switch_trim; + u8 vco_band; + u8 hfdiv; + u8 vco_multi; + u8 presc; + u8 wbdmux; + u16 tuner_enable; }; struct dib0070_lna_match { - u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ - u8 lna_band; + u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ + u8 lna_band; }; static const struct dib0070_tuning dib0070s_tuning_table[] = { - { 570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */ - { 700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 }, - { 863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 }, - { 1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */ - { 1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, - { 2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, - { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */ + { 570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */ + { 700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 }, + { 863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 }, + { 1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */ + { 1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, + { 2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, + { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */ }; static const struct dib0070_tuning dib0070_tuning_table[] = { - { 115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */ - { 179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */ - { 189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 }, - { 250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 }, - { 569999, 2, 1, 5, 6, 2, 2, 0x4000 | 0x0800 }, /* UHF */ - { 699999, 2, 0, 1, 4, 2, 2, 0x4000 | 0x0800 }, - { 863999, 2, 1, 1, 4, 2, 2, 0x4000 | 0x0800 }, - { 0xffffffff, 0, 1, 0, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */ + { 115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */ + { 179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */ + { 189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 }, + { 250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 }, + { 569999, 2, 1, 5, 6, 2, 2, 0x4000 | 0x0800 }, /* UHF */ + { 699999, 2, 0, 1, 4, 2, 2, 0x4000 | 0x0800 }, + { 863999, 2, 1, 1, 4, 2, 2, 0x4000 | 0x0800 }, + { 0xffffffff, 0, 1, 0, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */ }; static const struct dib0070_lna_match dib0070_lna_flip_chip[] = { - { 180000, 0 }, /* VHF */ - { 188000, 1 }, - { 196400, 2 }, - { 250000, 3 }, - { 550000, 0 }, /* UHF */ - { 590000, 1 }, - { 666000, 3 }, - { 864000, 5 }, - { 1500000, 0 }, /* LBAND or everything higher than UHF */ - { 1600000, 1 }, - { 2000000, 3 }, - { 0xffffffff, 7 }, + { 180000, 0 }, /* VHF */ + { 188000, 1 }, + { 196400, 2 }, + { 250000, 3 }, + { 550000, 0 }, /* UHF */ + { 590000, 1 }, + { 666000, 3 }, + { 864000, 5 }, + { 1500000, 0 }, /* LBAND or everything higher than UHF */ + { 1600000, 1 }, + { 2000000, 3 }, + { 0xffffffff, 7 }, }; static const struct dib0070_lna_match dib0070_lna[] = { - { 180000, 0 }, /* VHF */ - { 188000, 1 }, - { 196400, 2 }, - { 250000, 3 }, - { 550000, 2 }, /* UHF */ - { 650000, 3 }, - { 750000, 5 }, - { 850000, 6 }, - { 864000, 7 }, - { 1500000, 0 }, /* LBAND or everything higher than UHF */ - { 1600000, 1 }, - { 2000000, 3 }, - { 0xffffffff, 7 }, + { 180000, 0 }, /* VHF */ + { 188000, 1 }, + { 196400, 2 }, + { 250000, 3 }, + { 550000, 2 }, /* UHF */ + { 650000, 3 }, + { 750000, 5 }, + { 850000, 6 }, + { 864000, 7 }, + { 1500000, 0 }, /* LBAND or everything higher than UHF */ + { 1600000, 1 }, + { 2000000, 3 }, + { 0xffffffff, 7 }, }; #define LPF 100 static int dib0070_tune_digital(struct dvb_frontend *fe) { - struct dib0070_state *state = fe->tuner_priv; + struct dib0070_state *state = fe->tuner_priv; - const struct dib0070_tuning *tune; - const struct dib0070_lna_match *lna_match; + const struct dib0070_tuning *tune; + const struct dib0070_lna_match *lna_match; - enum frontend_tune_state *tune_state = &state->tune_state; - int ret = 10; /* 1ms is the default delay most of the time */ + enum frontend_tune_state *tune_state = &state->tune_state; + int ret = 10; /* 1ms is the default delay most of the time */ - u8 band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000); - u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf); + u8 band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000); + u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf); #ifdef CONFIG_SYS_ISDBT - if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1) - if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) - && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) - || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) - && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2))) - || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) - && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))) - freq += 850; + if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1) + if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) + && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) + || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) + && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2))) + || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) + && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))) + freq += 850; #endif - if (state->current_rf != freq) { - - switch (state->revision) { - case DIB0070S_P1A: - tune = dib0070s_tuning_table; - lna_match = dib0070_lna; - break; - default: - tune = dib0070_tuning_table; - if (state->cfg->flip_chip) - lna_match = dib0070_lna_flip_chip; - else - lna_match = dib0070_lna; - break; - } - while (freq > tune->max_freq) /* find the right one */ - tune++; - while (freq > lna_match->max_freq) /* find the right one */ - lna_match++; - - state->current_tune_table_index = tune; - state->lna_match = lna_match; - } - - if (*tune_state == CT_TUNER_START) { - dprintk("Tuning for Band: %hd (%d kHz)", band, freq); if (state->current_rf != freq) { - u8 REFDIV; - u32 FBDiv, Rest, FREF, VCOF_kHz; - u8 Den; - - state->current_rf = freq; - state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7); - - - dib0070_write_reg(state, 0x17, 0x30); - - - VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2; - - switch (band) { - case BAND_VHF: - REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000); - break; - case BAND_FM: - REFDIV = (u8) ((state->cfg->clock_khz) / 1000); - break; - default: - REFDIV = (u8) (state->cfg->clock_khz / 10000); - break; - } - FREF = state->cfg->clock_khz / REFDIV; - - switch (state->revision) { case DIB0070S_P1A: - FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF); - Rest = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF; - break; - - case DIB0070_P1G: - case DIB0070_P1F: + tune = dib0070s_tuning_table; + lna_match = dib0070_lna; + break; default: - FBDiv = (freq / (FREF / 2)); - Rest = 2 * freq - FBDiv * FREF; - break; - } - - if (Rest < LPF) - Rest = 0; - else if (Rest < 2 * LPF) - Rest = 2 * LPF; - else if (Rest > (FREF - LPF)) { - Rest = 0; - FBDiv += 1; - } else if (Rest > (FREF - 2 * LPF)) - Rest = FREF - 2 * LPF; - Rest = (Rest * 6528) / (FREF / 10); - - Den = 1; - if (Rest > 0) { - state->lo4 |= (1 << 14) | (1 << 12); - Den = 255; + tune = dib0070_tuning_table; + if (state->cfg->flip_chip) + lna_match = dib0070_lna_flip_chip; + else + lna_match = dib0070_lna; + break; } + while (freq > tune->max_freq) /* find the right one */ + tune++; + while (freq > lna_match->max_freq) /* find the right one */ + lna_match++; + state->current_tune_table_index = tune; + state->lna_match = lna_match; + } - dib0070_write_reg(state, 0x11, (u16)FBDiv); - dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV); - dib0070_write_reg(state, 0x13, (u16) Rest); - - if (state->revision == DIB0070S_P1A) { - - if (band == BAND_SBAND) { - dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); - dib0070_write_reg(state, 0x1d, 0xFFFF); - } else - dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1); + if (*tune_state == CT_TUNER_START) { + dprintk("Tuning for Band: %hd (%d kHz)", band, freq); + if (state->current_rf != freq) { + u8 REFDIV; + u32 FBDiv, Rest, FREF, VCOF_kHz; + u8 Den; + + state->current_rf = freq; + state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7); + + + dib0070_write_reg(state, 0x17, 0x30); + + + VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2; + + switch (band) { + case BAND_VHF: + REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000); + break; + case BAND_FM: + REFDIV = (u8) ((state->cfg->clock_khz) / 1000); + break; + default: + REFDIV = (u8) (state->cfg->clock_khz / 10000); + break; + } + FREF = state->cfg->clock_khz / REFDIV; + + + + switch (state->revision) { + case DIB0070S_P1A: + FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF); + Rest = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF; + break; + + case DIB0070_P1G: + case DIB0070_P1F: + default: + FBDiv = (freq / (FREF / 2)); + Rest = 2 * freq - FBDiv * FREF; + break; + } + + if (Rest < LPF) + Rest = 0; + else if (Rest < 2 * LPF) + Rest = 2 * LPF; + else if (Rest > (FREF - LPF)) { + Rest = 0; + FBDiv += 1; + } else if (Rest > (FREF - 2 * LPF)) + Rest = FREF - 2 * LPF; + Rest = (Rest * 6528) / (FREF / 10); + + Den = 1; + if (Rest > 0) { + state->lo4 |= (1 << 14) | (1 << 12); + Den = 255; + } + + + dib0070_write_reg(state, 0x11, (u16)FBDiv); + dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV); + dib0070_write_reg(state, 0x13, (u16) Rest); + + if (state->revision == DIB0070S_P1A) { + + if (band == BAND_SBAND) { + dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); + dib0070_write_reg(state, 0x1d, 0xFFFF); + } else + dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1); + } + + dib0070_write_reg(state, 0x20, + 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable); + + dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF); + dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest); + dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1); + dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv); + dprintk("VCO = %hd", state->current_tune_table_index->vco_band); + dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq); + + *tune_state = CT_TUNER_STEP_0; + } else { /* we are already tuned to this frequency - the configuration is correct */ + ret = 50; /* wakeup time */ + *tune_state = CT_TUNER_STEP_5; } + } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) { - dib0070_write_reg(state, 0x20, - 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable); - - dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF); - dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest); - dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1); - dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv); - dprintk("VCO = %hd", state->current_tune_table_index->vco_band); - dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq); - - *tune_state = CT_TUNER_STEP_0; - } else { /* we are already tuned to this frequency - the configuration is correct */ - ret = 50; /* wakeup time */ - *tune_state = CT_TUNER_STEP_5; - } - } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) { - - ret = dib0070_captrim(state, tune_state); + ret = dib0070_captrim(state, tune_state); - } else if (*tune_state == CT_TUNER_STEP_4) { - const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; - if (tmp != NULL) { - while (freq/1000 > tmp->freq) /* find the right one */ - tmp++; - dib0070_write_reg(state, 0x0f, - (0 << 15) | (1 << 14) | (3 << 12) - | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7) - | (state->current_tune_table_index->wbdmux << 0)); - state->wbd_gain_current = tmp->wbd_gain_val; - } else { + } else if (*tune_state == CT_TUNER_STEP_4) { + const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; + if (tmp != NULL) { + while (freq/1000 > tmp->freq) /* find the right one */ + tmp++; dib0070_write_reg(state, 0x0f, - (0 << 15) | (1 << 14) | (3 << 12) | (6 << 9) | (0 << 8) | (1 << 7) | (state->current_tune_table_index-> - wbdmux << 0)); - state->wbd_gain_current = 6; - } + (0 << 15) | (1 << 14) | (3 << 12) + | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7) + | (state->current_tune_table_index->wbdmux << 0)); + state->wbd_gain_current = tmp->wbd_gain_val; + } else { + dib0070_write_reg(state, 0x0f, + (0 << 15) | (1 << 14) | (3 << 12) + | (6 << 9) | (0 << 8) | (1 << 7) + | (state->current_tune_table_index->wbdmux << 0)); + state->wbd_gain_current = 6; + } - dib0070_write_reg(state, 0x06, 0x3fff); + dib0070_write_reg(state, 0x06, 0x3fff); dib0070_write_reg(state, 0x07, (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0)); - dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127)); - dib0070_write_reg(state, 0x0d, 0x0d80); + dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127)); + dib0070_write_reg(state, 0x0d, 0x0d80); - dib0070_write_reg(state, 0x18, 0x07ff); - dib0070_write_reg(state, 0x17, 0x0033); + dib0070_write_reg(state, 0x18, 0x07ff); + dib0070_write_reg(state, 0x17, 0x0033); - *tune_state = CT_TUNER_STEP_5; - } else if (*tune_state == CT_TUNER_STEP_5) { - dib0070_set_bandwidth(fe); - *tune_state = CT_TUNER_STOP; - } else { - ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */ - } - return ret; + *tune_state = CT_TUNER_STEP_5; + } else if (*tune_state == CT_TUNER_STEP_5) { + dib0070_set_bandwidth(fe); + *tune_state = CT_TUNER_STOP; + } else { + ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */ + } + return ret; } static int dib0070_tune(struct dvb_frontend *fe) { - struct dib0070_state *state = fe->tuner_priv; - uint32_t ret; + struct dib0070_state *state = fe->tuner_priv; + uint32_t ret; - state->tune_state = CT_TUNER_START; + state->tune_state = CT_TUNER_START; - do { - ret = dib0070_tune_digital(fe); - if (ret != FE_CALLBACK_TIME_NEVER) - msleep(ret/10); - else - break; - } while (state->tune_state != CT_TUNER_STOP); + do { + ret = dib0070_tune_digital(fe); + if (ret != FE_CALLBACK_TIME_NEVER) + msleep(ret/10); + else + break; + } while (state->tune_state != CT_TUNER_STOP); - return 0; + return 0; } static int dib0070_wakeup(struct dvb_frontend *fe) @@ -610,48 +608,48 @@ static const u16 dib0070_p1f_defaults[] = static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain) { - u16 tuner_en = dib0070_read_reg(state, 0x20); - u16 offset; - - dib0070_write_reg(state, 0x18, 0x07ff); - dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); - dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0)); - msleep(9); - offset = dib0070_read_reg(state, 0x19); - dib0070_write_reg(state, 0x20, tuner_en); - return offset; + u16 tuner_en = dib0070_read_reg(state, 0x20); + u16 offset; + + dib0070_write_reg(state, 0x18, 0x07ff); + dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); + dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0)); + msleep(9); + offset = dib0070_read_reg(state, 0x19); + dib0070_write_reg(state, 0x20, tuner_en); + return offset; } static void dib0070_wbd_offset_calibration(struct dib0070_state *state) { - u8 gain; - for (gain = 6; gain < 8; gain++) { - state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2); - dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain-6]); - } + u8 gain; + for (gain = 6; gain < 8; gain++) { + state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2); + dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain-6]); + } } u16 dib0070_wbd_offset(struct dvb_frontend *fe) { - struct dib0070_state *state = fe->tuner_priv; - const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; - u32 freq = fe->dtv_property_cache.frequency/1000; - - if (tmp != NULL) { - while (freq/1000 > tmp->freq) /* find the right one */ - tmp++; - state->wbd_gain_current = tmp->wbd_gain_val; + struct dib0070_state *state = fe->tuner_priv; + const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; + u32 freq = fe->dtv_property_cache.frequency/1000; + + if (tmp != NULL) { + while (freq/1000 > tmp->freq) /* find the right one */ + tmp++; + state->wbd_gain_current = tmp->wbd_gain_val; } else - state->wbd_gain_current = 6; + state->wbd_gain_current = 6; - return state->wbd_offset_3_3[state->wbd_gain_current - 6]; + return state->wbd_offset_3_3[state->wbd_gain_current - 6]; } EXPORT_SYMBOL(dib0070_wbd_offset); #define pgm_read_word(w) (*w) static int dib0070_reset(struct dvb_frontend *fe) { - struct dib0070_state *state = fe->tuner_priv; + struct dib0070_state *state = fe->tuner_priv; u16 l, r, *n; HARD_RESET(state); @@ -664,7 +662,7 @@ static int dib0070_reset(struct dvb_frontend *fe) #else #warning forcing SBAND #endif - state->revision = DIB0070S_P1A; + state->revision = DIB0070S_P1A; /* P1F or not */ dprintk("Revision: %x", state->revision); @@ -703,24 +701,25 @@ static int dib0070_reset(struct dvb_frontend *fe) dib0070_write_reg(state, 0x02, r | (1 << 5)); } - if (state->revision == DIB0070S_P1A) - dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); - else - dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, state->cfg->enable_third_order_filter); + if (state->revision == DIB0070S_P1A) + dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); + else + dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, + state->cfg->enable_third_order_filter); dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8); - dib0070_wbd_offset_calibration(state); + dib0070_wbd_offset_calibration(state); - return 0; + return 0; } static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency) { - struct dib0070_state *state = fe->tuner_priv; + struct dib0070_state *state = fe->tuner_priv; - *frequency = 1000 * state->current_rf; - return 0; + *frequency = 1000 * state->current_rf; + return 0; } static int dib0070_release(struct dvb_frontend *fe) diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c index 68e2af2..47cb722 100644 --- a/drivers/media/dvb-frontends/dib0090.c +++ b/drivers/media/dvb-frontends/dib0090.c @@ -1696,12 +1696,10 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front if (state->identity.p1g) state->dc = dc_p1g_table; - *tune_state = CT_TUNER_STEP_0; /* fall through */ - case CT_TUNER_STEP_0: - dprintk("Sart/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q"); + dprintk("Start/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q"); dib0090_write_reg(state, 0x01, state->dc->bb1); dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7)); diff --git a/drivers/media/dvb-frontends/dib3000mb.c b/drivers/media/dvb-frontends/dib3000mb.c index af91e0c..7a61172 100644 --- a/drivers/media/dvb-frontends/dib3000mb.c +++ b/drivers/media/dvb-frontends/dib3000mb.c @@ -118,7 +118,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend *fe, int tuner) { struct dib3000_state* state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - fe_code_rate_t fe_cr = FEC_NONE; + enum fe_code_rate fe_cr = FEC_NONE; int search_state, seq; if (tuner && fe->ops.tuner_ops.set_params) { @@ -454,7 +454,7 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dib3000_state* state = fe->demodulator_priv; - fe_code_rate_t *cr; + enum fe_code_rate *cr; u16 tps_val; int inv_test1,inv_test2; u32 dds_val, threshold = 0x800000; @@ -611,7 +611,8 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe) return 0; } -static int dib3000mb_read_status(struct dvb_frontend* fe, fe_status_t *stat) +static int dib3000mb_read_status(struct dvb_frontend *fe, + enum fe_status *stat) { struct dib3000_state* state = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/dib3000mc.c b/drivers/media/dvb-frontends/dib3000mc.c index ffad181..583d6b7 100644 --- a/drivers/media/dvb-frontends/dib3000mc.c +++ b/drivers/media/dvb-frontends/dib3000mc.c @@ -131,7 +131,7 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, static int dib3000mc_setup_pwm_state(struct dib3000mc_state *state) { u16 reg_51, reg_52 = state->cfg->agc->setup & 0xfefb; - if (state->cfg->pwm3_inversion) { + if (state->cfg->pwm3_inversion) { reg_51 = (2 << 14) | (0 << 10) | (7 << 6) | (2 << 2) | (2 << 0); reg_52 |= (1 << 2); } else { @@ -141,12 +141,12 @@ static int dib3000mc_setup_pwm_state(struct dib3000mc_state *state) dib3000mc_write_word(state, 51, reg_51); dib3000mc_write_word(state, 52, reg_52); - if (state->cfg->use_pwm3) + if (state->cfg->use_pwm3) dib3000mc_write_word(state, 245, (1 << 3) | (1 << 0)); else dib3000mc_write_word(state, 245, 0); - dib3000mc_write_word(state, 1040, 0x3); + dib3000mc_write_word(state, 1040, 0x3); return 0; } @@ -417,7 +417,7 @@ static int dib3000mc_sleep(struct dvb_frontend *demod) dib3000mc_write_word(state, 1032, 0xFFFF); dib3000mc_write_word(state, 1033, 0xFFF0); - return 0; + return 0; } static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam) @@ -447,10 +447,14 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, dib3000mc_set_bandwidth(state, bw); dib3000mc_set_timing(state, ch->transmission_mode, bw, 0); -// if (boost) -// dib3000mc_write_word(state, 100, (11 << 6) + 6); -// else +#if 1 + dib3000mc_write_word(state, 100, (16 << 6) + 9); +#else + if (boost) + dib3000mc_write_word(state, 100, (11 << 6) + 6); + else dib3000mc_write_word(state, 100, (16 << 6) + 9); +#endif dib3000mc_write_word(state, 1027, 0x0800); dib3000mc_write_word(state, 1027, 0x0000); @@ -732,7 +736,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend *fe) return ret; } -static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat) +static int dib3000mc_read_status(struct dvb_frontend *fe, enum fe_status *stat) { struct dib3000mc_state *state = fe->demodulator_priv; u16 lock = dib3000mc_read_word(state, 509); diff --git a/drivers/media/dvb-frontends/dib7000m.c b/drivers/media/dvb-frontends/dib7000m.c index dcb9a15..35eb71f 100644 --- a/drivers/media/dvb-frontends/dib7000m.c +++ b/drivers/media/dvb-frontends/dib7000m.c @@ -1256,7 +1256,7 @@ static int dib7000m_set_frontend(struct dvb_frontend *fe) return ret; } -static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat) +static int dib7000m_read_status(struct dvb_frontend *fe, enum fe_status *stat) { struct dib7000m_state *state = fe->demodulator_priv; u16 lock = dib7000m_read_word(state, 535); diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index c505d69..33be5d6 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -1558,9 +1558,9 @@ static int dib7000p_set_frontend(struct dvb_frontend *fe) return ret; } -static int dib7000p_get_stats(struct dvb_frontend *fe, fe_status_t stat); +static int dib7000p_get_stats(struct dvb_frontend *fe, enum fe_status stat); -static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat) +static int dib7000p_read_status(struct dvb_frontend *fe, enum fe_status *stat) { struct dib7000p_state *state = fe->demodulator_priv; u16 lock = dib7000p_read_word(state, 509); @@ -1877,7 +1877,7 @@ static u32 dib7000p_get_time_us(struct dvb_frontend *demod) return time_us; } -static int dib7000p_get_stats(struct dvb_frontend *demod, fe_status_t stat) +static int dib7000p_get_stats(struct dvb_frontend *demod, enum fe_status stat) { struct dib7000p_state *state = demod->demodulator_priv; struct dtv_frontend_properties *c = &demod->dtv_property_cache; diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index 8c6663b..94c2627 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -3380,13 +3380,13 @@ static int dib8000_sleep(struct dvb_frontend *fe) return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF); } -static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat); +static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat); static int dib8000_get_frontend(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; u16 i, val = 0; - fe_status_t stat = 0; + enum fe_status stat = 0; u8 index_frontend, sub_index_frontend; fe->dtv_property_cache.bandwidth_hz = 6000000; @@ -3733,9 +3733,9 @@ static int dib8000_set_frontend(struct dvb_frontend *fe) return 0; } -static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat); +static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat); -static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) +static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat) { struct dib8000_state *state = fe->demodulator_priv; u16 lock_slave = 0, lock; @@ -4089,7 +4089,7 @@ static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer) return time_us; } -static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat) +static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat) { struct dib8000_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; diff --git a/drivers/media/dvb-frontends/dib8000.h b/drivers/media/dvb-frontends/dib8000.h index 780c37b..2b8b4b1 100644 --- a/drivers/media/dvb-frontends/dib8000.h +++ b/drivers/media/dvb-frontends/dib8000.h @@ -66,7 +66,7 @@ struct dib8000_ops { #if IS_REACHABLE(CONFIG_DVB_DIB8000) void *dib8000_attach(struct dib8000_ops *ops); #else -static inline int dib8000_attach(struct dib8000_ops *ops) +static inline void *dib8000_attach(struct dib8000_ops *ops) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; diff --git a/drivers/media/dvb-frontends/dib9000.c b/drivers/media/dvb-frontends/dib9000.c index f75dec4..8f92aca 100644 --- a/drivers/media/dvb-frontends/dib9000.c +++ b/drivers/media/dvb-frontends/dib9000.c @@ -1893,7 +1893,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe) { struct dib9000_state *state = fe->demodulator_priv; u8 index_frontend, sub_index_frontend; - fe_status_t stat; + enum fe_status stat; int ret = 0; if (state->get_frontend_internal == 0) { @@ -2161,7 +2161,7 @@ static u16 dib9000_read_lock(struct dvb_frontend *fe) return dib9000_read_word(state, 535); } -static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat) +static int dib9000_read_status(struct dvb_frontend *fe, enum fe_status *stat) { struct dib9000_state *state = fe->demodulator_priv; u8 index_frontend; diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 2bfa7a4..b28b578 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -210,7 +210,7 @@ DEFINES /** * \def DRXJ_DEF_I2C_ADDR -* \brief Default I2C addres of a demodulator instance. +* \brief Default I2C address of a demodulator instance. */ #define DRXJ_DEF_I2C_ADDR (0x52) @@ -336,7 +336,7 @@ DEFINES * MICROCODE RELATED DEFINES */ -/* Magic word for checking correct Endianess of microcode data */ +/* Magic word for checking correct Endianness of microcode data */ #define DRX_UCODE_MAGIC_WORD ((((u16)'H')<<8)+((u16)'L')) /* CRC flag in ucode header, flags field. */ @@ -847,9 +847,9 @@ static struct drx_common_attr drxj_default_comm_attr_g = { static clockrate is selected */ DRX_MPEG_STR_WIDTH_1 /* MPEG Start width in clock cycles */ }, - /* Initilisations below can be ommited, they require no user input and + /* Initilisations below can be omitted, they require no user input and are initialy 0, NULL or false. The compiler will initialize them to these - values when ommited. */ + values when omitted. */ false, /* is_opened */ /* SCAN */ @@ -1175,7 +1175,7 @@ static u32 log1_times100(u32 x) Now x has binary point between bit[scale] and bit[scale-1] and 1.0 <= x < 2.0 */ - /* correction for divison: log(x) = log(x/y)+log(y) */ + /* correction for division: log(x) = log(x/y)+log(y) */ y = k * ((((u32) 1) << scale) * 200); /* remove integer part */ @@ -1653,7 +1653,7 @@ static int drxdap_fasi_write_block(struct i2c_device_addr *dev_addr, sequense will be visible: (1) write address {i2c addr, 4 bytes chip address} (2) write data {i2c addr, 4 bytes data } (3) write address (4) write data etc... - Addres must be rewriten because HI is reset after data transport and + Address must be rewriten because HI is reset after data transport and expects an address. */ todo = (block_size < datasize ? block_size : datasize); @@ -2971,7 +2971,7 @@ ctrl_set_cfg_mpeg_output(struct drx_demod_instance *demod, struct drx_cfg_mpeg_o } /* ext_attr->standard */ } - if (cfg_data->enable_parallel == true) { /* MPEG data output is paralel -> clear ipr_mode[0] */ + if (cfg_data->enable_parallel == true) { /* MPEG data output is parallel -> clear ipr_mode[0] */ fec_oc_reg_ipr_mode &= (~(FEC_OC_IPR_MODE_SERIAL__M)); } else { /* MPEG data output is serial -> set ipr_mode[0] */ fec_oc_reg_ipr_mode |= FEC_OC_IPR_MODE_SERIAL__M; @@ -3157,7 +3157,7 @@ ctrl_set_cfg_mpeg_output(struct drx_demod_instance *demod, struct drx_cfg_mpeg_o pr_err("error %d\n", rc); goto rw_error; } - if (cfg_data->enable_parallel == true) { /* MPEG data output is paralel -> set MD1 to MD7 to output mode */ + if (cfg_data->enable_parallel == true) { /* MPEG data output is parallel -> set MD1 to MD7 to output mode */ sio_pdr_md_cfg = MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH << SIO_PDR_MD0_CFG_DRIVE__B | 0x03 << @@ -4320,7 +4320,7 @@ static int adc_synchronization(struct drx_demod_instance *demod) } if (count == 1) { - /* Try sampling on a diffrent edge */ + /* Try sampling on a different edge */ u16 clk_neg = 0; rc = drxj_dap_read_reg16(dev_addr, IQM_AF_CLKNEG__A, &clk_neg, 0); @@ -6461,7 +6461,7 @@ set_qam_measurement(struct drx_demod_instance *demod, enum drx_modulation constellation, u32 symbol_rate) { struct i2c_device_addr *dev_addr = NULL; /* device address for I2C writes */ - struct drxj_data *ext_attr = NULL; /* Global data container for DRXJ specif data */ + struct drxj_data *ext_attr = NULL; /* Global data container for DRXJ specific data */ int rc; u32 fec_bits_desired = 0; /* BER accounting period */ u16 fec_rs_plen = 0; /* defines RS BER measurement period */ @@ -8864,7 +8864,7 @@ qam64auto(struct drx_demod_instance *demod, u32 timeout_ofs = 0; u16 data = 0; - /* external attributes for storing aquired channel constellation */ + /* external attributes for storing acquired channel constellation */ *lock_status = DRX_NOT_LOCKED; start_time = jiffies_to_msecs(jiffies); lck_state = NO_LOCK; @@ -9011,7 +9011,7 @@ qam256auto(struct drx_demod_instance *demod, u32 d_locked_time = 0; u32 timeout_ofs = DRXJ_QAM_DEMOD_LOCK_EXT_WAITTIME; - /* external attributes for storing aquired channel constellation */ + /* external attributes for storing acquired channel constellation */ *lock_status = DRX_NOT_LOCKED; start_time = jiffies_to_msecs(jiffies); lck_state = NO_LOCK; @@ -9087,7 +9087,7 @@ set_qam_channel(struct drx_demod_instance *demod, enum drx_lock_status lock_status = DRX_NOT_LOCKED; bool auto_flag = false; - /* external attributes for storing aquired channel constellation */ + /* external attributes for storing acquired channel constellation */ ext_attr = (struct drxj_data *) demod->my_ext_attr; /* set QAM channel constellation */ @@ -9431,7 +9431,7 @@ rw_error: /** * \fn int ctrl_get_qam_sig_quality() -* \brief Retreive QAM signal quality from device. +* \brief Retrieve QAM signal quality from device. * \param devmod Pointer to demodulator instance. * \param sig_quality Pointer to signal quality data. * \return int. @@ -9541,7 +9541,7 @@ ctrl_get_qam_sig_quality(struct drx_demod_instance *demod) /* ----------------------------------------- */ /* Pre Viterbi Symbol Error Rate Calculation */ /* ----------------------------------------- */ - /* pre viterbi SER is good if it is bellow 0.025 */ + /* pre viterbi SER is good if it is below 0.025 */ /* get the register value */ /* no of quadrature symbol errors */ @@ -10647,7 +10647,7 @@ rw_error: /** * \fn int ctrl_sig_quality() -* \brief Retreive signal quality form device. +* \brief Retrieve signal quality form device. * \param devmod Pointer to demodulator instance. * \param sig_quality Pointer to signal quality data. * \return int. @@ -10763,7 +10763,7 @@ rw_error: /** * \fn int ctrl_lock_status() -* \brief Retreive lock status . +* \brief Retrieve lock status . * \param dev_addr Pointer to demodulator device address. * \param lock_stat Pointer to lock status structure. * \return int. @@ -10815,7 +10815,7 @@ ctrl_lock_status(struct drx_demod_instance *demod, enum drx_lock_status *lock_st return -EIO; } - /* define the SCU command paramters and execute the command */ + /* define the SCU command parameters and execute the command */ cmd_scu.parameter_len = 0; cmd_scu.result_len = 2; cmd_scu.parameter = NULL; @@ -11489,7 +11489,7 @@ static int drxj_open(struct drx_demod_instance *demod) } /* Stamp driver version number in SCU data RAM in BCD code - Done to enable field application engineers to retreive drxdriver version + Done to enable field application engineers to retrieve drxdriver version via I2C from SCU RAM */ driver_version = (VERSION_MAJOR / 100) % 10; @@ -11892,7 +11892,7 @@ release: return rc; } -/* caller is expeced to check if lna is supported before enabling */ +/* caller is expected to check if lna is supported before enabling */ static int drxj_set_lna_state(struct drx_demod_instance *demod, bool state) { struct drxuio_cfg uio_cfg; @@ -11946,7 +11946,7 @@ static int drx39xxj_set_powerstate(struct dvb_frontend *fe, int enable) return 0; } -static int drx39xxj_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int drx39xxj_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct drx39xxj_state *state = fe->demodulator_priv; struct drx_demod_instance *demod = state->demod; diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index 687e893..34b9441 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -2805,7 +2805,7 @@ static int drxd_read_signal_strength(struct dvb_frontend *fe, u16 * strength) return 0; } -static int drxd_read_status(struct dvb_frontend *fe, fe_status_t * status) +static int drxd_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct drxd_state *state = fe->demodulator_priv; u32 lock; diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index d46cf5f..b975da0 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -544,7 +544,7 @@ error: static int init_state(struct drxk_state *state) { /* - * FIXME: most (all?) of the values bellow should be moved into + * FIXME: most (all?) of the values below should be moved into * struct drxk_config, as they are probably board-specific */ u32 ul_vsb_if_agc_mode = DRXK_AGC_CTRL_AUTO; @@ -3262,6 +3262,7 @@ static int dvbt_sc_command(struct drxk_state *state, } /* Write needed parameters and the command */ + status = 0; switch (cmd) { /* All commands using 5 parameters */ /* All commands using 4 parameters */ @@ -3270,16 +3271,16 @@ static int dvbt_sc_command(struct drxk_state *state, case OFDM_SC_RA_RAM_CMD_PROC_START: case OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM: case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM: - status = write16(state, OFDM_SC_RA_RAM_PARAM1__A, param1); + status |= write16(state, OFDM_SC_RA_RAM_PARAM1__A, param1); /* All commands using 1 parameters */ case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING: case OFDM_SC_RA_RAM_CMD_USER_IO: - status = write16(state, OFDM_SC_RA_RAM_PARAM0__A, param0); + status |= write16(state, OFDM_SC_RA_RAM_PARAM0__A, param0); /* All commands using 0 parameters */ case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM: case OFDM_SC_RA_RAM_CMD_NULL: /* Write command */ - status = write16(state, OFDM_SC_RA_RAM_CMD__A, cmd); + status |= write16(state, OFDM_SC_RA_RAM_CMD__A, cmd); break; default: /* Unknown command */ @@ -6639,7 +6640,7 @@ error: } -static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int drxk_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct drxk_state *state = fe->demodulator_priv; int rc; diff --git a/drivers/media/dvb-frontends/drxk_hard.h b/drivers/media/dvb-frontends/drxk_hard.h index bae9c71..9ed88e0 100644 --- a/drivers/media/dvb-frontends/drxk_hard.h +++ b/drivers/media/dvb-frontends/drxk_hard.h @@ -350,7 +350,7 @@ struct drxk_state { bool antenna_dvbt; u16 antenna_gpio; - fe_status_t fe_status; + enum fe_status fe_status; /* Firmware */ const char *microcode_name; diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index 9d0d034..e8fc032 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c @@ -404,7 +404,8 @@ static int ds3000_load_firmware(struct dvb_frontend *fe, return ret; } -static int ds3000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int ds3000_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct ds3000_state *state = fe->demodulator_priv; u8 data; @@ -431,7 +432,7 @@ static int ds3000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) return 0; } -static int ds3000_read_status(struct dvb_frontend *fe, fe_status_t* status) +static int ds3000_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct ds3000_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -666,7 +667,7 @@ static int ds3000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) return 0; } -static int ds3000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +static int ds3000_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) { struct ds3000_state *state = fe->demodulator_priv; u8 data; @@ -766,7 +767,7 @@ static int ds3000_send_diseqc_msg(struct dvb_frontend *fe, /* Send DiSEqC burst */ static int ds3000_diseqc_send_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t burst) + enum fe_sec_mini_cmd burst) { struct ds3000_state *state = fe->demodulator_priv; int i; @@ -905,7 +906,7 @@ static int ds3000_set_frontend(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; int i; - fe_status_t status; + enum fe_status status; s32 offset_khz; u32 frequency; u16 value; @@ -1045,7 +1046,7 @@ static int ds3000_tune(struct dvb_frontend *fe, bool re_tune, unsigned int mode_flags, unsigned int *delay, - fe_status_t *status) + enum fe_status *status) { if (re_tune) { int ret = ds3000_set_frontend(fe); diff --git a/drivers/media/dvb-frontends/dvb_dummy_fe.c b/drivers/media/dvb-frontends/dvb_dummy_fe.c index d5acc30..14e996d 100644 --- a/drivers/media/dvb-frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb-frontends/dvb_dummy_fe.c @@ -33,7 +33,8 @@ struct dvb_dummy_fe_state { }; -static int dvb_dummy_fe_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int dvb_dummy_fe_read_status(struct dvb_frontend *fe, + enum fe_status *status) { *status = FE_HAS_SIGNAL | FE_HAS_CARRIER @@ -97,12 +98,14 @@ static int dvb_dummy_fe_init(struct dvb_frontend* fe) return 0; } -static int dvb_dummy_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int dvb_dummy_fe_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { return 0; } -static int dvb_dummy_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int dvb_dummy_fe_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { return 0; } diff --git a/drivers/media/dvb-frontends/ec100.c b/drivers/media/dvb-frontends/ec100.c index 9d42480..c9012e6 100644 --- a/drivers/media/dvb-frontends/ec100.c +++ b/drivers/media/dvb-frontends/ec100.c @@ -174,7 +174,7 @@ static int ec100_get_tune_settings(struct dvb_frontend *fe, return 0; } -static int ec100_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int ec100_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct ec100_state *state = fe->demodulator_priv; int ret; diff --git a/drivers/media/dvb-frontends/hd29l2.c b/drivers/media/dvb-frontends/hd29l2.c index 67c8e6d..40e359f 100644 --- a/drivers/media/dvb-frontends/hd29l2.c +++ b/drivers/media/dvb-frontends/hd29l2.c @@ -211,7 +211,7 @@ err: return ret; } -static int hd29l2_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int hd29l2_read_status(struct dvb_frontend *fe, enum fe_status *status) { int ret; struct hd29l2_priv *priv = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/hd29l2_priv.h b/drivers/media/dvb-frontends/hd29l2_priv.h index 4d571a2..6dc225c 100644 --- a/drivers/media/dvb-frontends/hd29l2_priv.h +++ b/drivers/media/dvb-frontends/hd29l2_priv.h @@ -67,7 +67,7 @@ struct hd29l2_priv { struct hd29l2_config cfg; u8 tuner_i2c_addr_programmed:1; - fe_status_t fe_status; + enum fe_status fe_status; }; static const struct reg_mod_vals reg_mod_vals_tab[] = { diff --git a/drivers/media/dvb-frontends/isl6405.c b/drivers/media/dvb-frontends/isl6405.c index 0c642a5..b46450a 100644 --- a/drivers/media/dvb-frontends/isl6405.c +++ b/drivers/media/dvb-frontends/isl6405.c @@ -43,7 +43,8 @@ struct isl6405 { u8 i2c_addr; }; -static int isl6405_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int isl6405_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv; struct i2c_msg msg = { .addr = isl6405->i2c_addr, .flags = 0, diff --git a/drivers/media/dvb-frontends/isl6421.c b/drivers/media/dvb-frontends/isl6421.c index c77002f..3a4d460 100644 --- a/drivers/media/dvb-frontends/isl6421.c +++ b/drivers/media/dvb-frontends/isl6421.c @@ -43,7 +43,8 @@ struct isl6421 { u8 i2c_addr; }; -static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int isl6421_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv; struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0, @@ -89,7 +90,8 @@ static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO; } -static int isl6421_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int isl6421_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv; struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0, diff --git a/drivers/media/dvb-frontends/l64781.c b/drivers/media/dvb-frontends/l64781.c index ddf866c..0977871 100644 --- a/drivers/media/dvb-frontends/l64781.c +++ b/drivers/media/dvb-frontends/l64781.c @@ -359,7 +359,7 @@ static int get_frontend(struct dvb_frontend *fe) return 0; } -static int l64781_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int l64781_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct l64781_state* state = fe->demodulator_priv; int sync = l64781_readreg (state, 0x32); diff --git a/drivers/media/dvb-frontends/lg2160.c b/drivers/media/dvb-frontends/lg2160.c index 99efeba..7880f71 100644 --- a/drivers/media/dvb-frontends/lg2160.c +++ b/drivers/media/dvb-frontends/lg2160.c @@ -1203,7 +1203,7 @@ static int lg216x_read_lock_status(struct lg216x_state *state, #endif } -static int lg216x_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int lg216x_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct lg216x_state *state = fe->demodulator_priv; int ret, acq_lock, sync_lock; diff --git a/drivers/media/dvb-frontends/lgdt3305.c b/drivers/media/dvb-frontends/lgdt3305.c index d08570a..4712186 100644 --- a/drivers/media/dvb-frontends/lgdt3305.c +++ b/drivers/media/dvb-frontends/lgdt3305.c @@ -60,7 +60,7 @@ struct lgdt3305_state { struct dvb_frontend frontend; - fe_modulation_t current_modulation; + enum fe_modulation current_modulation; u32 current_frequency; u32 snr; }; @@ -912,7 +912,7 @@ fail: return ret; } -static int lgdt3305_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int lgdt3305_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct lgdt3305_state *state = fe->demodulator_priv; u8 val; diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index d9a2b0e..721fbc0 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -62,7 +62,7 @@ struct lgdt3306a_state { struct dvb_frontend frontend; - fe_modulation_t current_modulation; + enum fe_modulation current_modulation; u32 current_frequency; u32 snr; }; @@ -1558,7 +1558,8 @@ lgdt3306a_qam_lock_poll(struct lgdt3306a_state *state) return LG3306_UNLOCK; } -static int lgdt3306a_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int lgdt3306a_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct lgdt3306a_state *state = fe->demodulator_priv; u16 strength = 0; @@ -1705,7 +1706,7 @@ static int lgdt3306a_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) static int lgdt3306a_tune(struct dvb_frontend *fe, bool re_tune, unsigned int mode_flags, unsigned int *delay, - fe_status_t *status) + enum fe_status *status) { int ret = 0; struct lgdt3306a_state *state = fe->demodulator_priv; @@ -1735,7 +1736,7 @@ static int lgdt3306a_get_tune_settings(struct dvb_frontend *fe, static int lgdt3306a_search(struct dvb_frontend *fe) { - fe_status_t status = 0; + enum fe_status status = 0; int i, ret; /* set frontend */ @@ -2101,7 +2102,7 @@ static void lgdt3306a_DumpRegs(struct lgdt3306a_state *state) lgdt3306a_read_reg(state, regtab[i], ®val1[i]); if (regval1[i] != regval2[i]) { lg_debug(" %04X = %02X\n", regtab[i], regval1[i]); - regval2[i] = regval1[i]; + regval2[i] = regval1[i]; } } debug = sav_debug; diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c index 2e1a618..cf3cc20 100644 --- a/drivers/media/dvb-frontends/lgdt330x.c +++ b/drivers/media/dvb-frontends/lgdt330x.c @@ -67,7 +67,7 @@ struct lgdt330x_state struct dvb_frontend frontend; /* Demodulator private data */ - fe_modulation_t current_modulation; + enum fe_modulation current_modulation; u32 snr; /* Result of last SNR calculation */ /* Tuner private data */ @@ -447,7 +447,8 @@ static int lgdt330x_get_frontend(struct dvb_frontend *fe) return 0; } -static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int lgdt3302_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct lgdt330x_state* state = fe->demodulator_priv; u8 buf[3]; @@ -505,7 +506,8 @@ static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) return 0; } -static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int lgdt3303_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct lgdt330x_state* state = fe->demodulator_priv; int err; diff --git a/drivers/media/dvb-frontends/lgs8gl5.c b/drivers/media/dvb-frontends/lgs8gl5.c index 416cce3..7bbb2c1 100644 --- a/drivers/media/dvb-frontends/lgs8gl5.c +++ b/drivers/media/dvb-frontends/lgs8gl5.c @@ -249,7 +249,7 @@ lgs8gl5_init(struct dvb_frontend *fe) static int -lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status) +lgs8gl5_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct lgs8gl5_state *state = fe->demodulator_priv; u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); diff --git a/drivers/media/dvb-frontends/lgs8gxx.c b/drivers/media/dvb-frontends/lgs8gxx.c index 3c92f36..e2c191c 100644 --- a/drivers/media/dvb-frontends/lgs8gxx.c +++ b/drivers/media/dvb-frontends/lgs8gxx.c @@ -732,7 +732,8 @@ int lgs8gxx_get_tune_settings(struct dvb_frontend *fe, return 0; } -static int lgs8gxx_read_status(struct dvb_frontend *fe, fe_status_t *fe_status) +static int lgs8gxx_read_status(struct dvb_frontend *fe, + enum fe_status *fe_status) { struct lgs8gxx_state *priv = fe->demodulator_priv; s8 ret; diff --git a/drivers/media/dvb-frontends/lnbp21.c b/drivers/media/dvb-frontends/lnbp21.c index f3ba7b5..4aca0fb 100644 --- a/drivers/media/dvb-frontends/lnbp21.c +++ b/drivers/media/dvb-frontends/lnbp21.c @@ -45,7 +45,7 @@ struct lnbp21 { }; static int lnbp21_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv; struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0, @@ -92,7 +92,7 @@ static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) } static int lnbp21_set_tone(struct dvb_frontend *fe, - fe_sec_tone_mode_t tone) + enum fe_sec_tone_mode tone) { struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv; struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0, diff --git a/drivers/media/dvb-frontends/lnbp22.c b/drivers/media/dvb-frontends/lnbp22.c index c463da7..d7ca0fd 100644 --- a/drivers/media/dvb-frontends/lnbp22.c +++ b/drivers/media/dvb-frontends/lnbp22.c @@ -48,7 +48,8 @@ struct lnbp22 { struct i2c_adapter *i2c; }; -static int lnbp22_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int lnbp22_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct lnbp22 *lnbp22 = (struct lnbp22 *)fe->sec_priv; struct i2c_msg msg = { diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index d3d928e..e9b2d2b 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -1,5 +1,5 @@ /* - * Montage M88DS3103/M88RS6000 demodulator driver + * Montage Technology M88DS3103/M88RS6000 demodulator driver * * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> * @@ -18,149 +18,15 @@ static struct dvb_frontend_ops m88ds3103_ops; -/* write multiple registers */ -static int m88ds3103_wr_regs(struct m88ds3103_priv *priv, - u8 reg, const u8 *val, int len) -{ -#define MAX_WR_LEN 32 -#define MAX_WR_XFER_LEN (MAX_WR_LEN + 1) - int ret; - u8 buf[MAX_WR_XFER_LEN]; - struct i2c_msg msg[1] = { - { - .addr = priv->cfg->i2c_addr, - .flags = 0, - .len = 1 + len, - .buf = buf, - } - }; - - if (WARN_ON(len > MAX_WR_LEN)) - return -EINVAL; - - buf[0] = reg; - memcpy(&buf[1], val, len); - - mutex_lock(&priv->i2c_mutex); - ret = i2c_transfer(priv->i2c, msg, 1); - mutex_unlock(&priv->i2c_mutex); - if (ret == 1) { - ret = 0; - } else { - dev_warn(&priv->i2c->dev, - "%s: i2c wr failed=%d reg=%02x len=%d\n", - KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } - - return ret; -} - -/* read multiple registers */ -static int m88ds3103_rd_regs(struct m88ds3103_priv *priv, - u8 reg, u8 *val, int len) -{ -#define MAX_RD_LEN 3 -#define MAX_RD_XFER_LEN (MAX_RD_LEN) - int ret; - u8 buf[MAX_RD_XFER_LEN]; - struct i2c_msg msg[2] = { - { - .addr = priv->cfg->i2c_addr, - .flags = 0, - .len = 1, - .buf = ®, - }, { - .addr = priv->cfg->i2c_addr, - .flags = I2C_M_RD, - .len = len, - .buf = buf, - } - }; - - if (WARN_ON(len > MAX_RD_LEN)) - return -EINVAL; - - mutex_lock(&priv->i2c_mutex); - ret = i2c_transfer(priv->i2c, msg, 2); - mutex_unlock(&priv->i2c_mutex); - if (ret == 2) { - memcpy(val, buf, len); - ret = 0; - } else { - dev_warn(&priv->i2c->dev, - "%s: i2c rd failed=%d reg=%02x len=%d\n", - KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } - - return ret; -} - -/* write single register */ -static int m88ds3103_wr_reg(struct m88ds3103_priv *priv, u8 reg, u8 val) -{ - return m88ds3103_wr_regs(priv, reg, &val, 1); -} - -/* read single register */ -static int m88ds3103_rd_reg(struct m88ds3103_priv *priv, u8 reg, u8 *val) -{ - return m88ds3103_rd_regs(priv, reg, val, 1); -} - -/* write single register with mask */ -static int m88ds3103_wr_reg_mask(struct m88ds3103_priv *priv, - u8 reg, u8 val, u8 mask) -{ - int ret; - u8 u8tmp; - - /* no need for read if whole reg is written */ - if (mask != 0xff) { - ret = m88ds3103_rd_regs(priv, reg, &u8tmp, 1); - if (ret) - return ret; - - val &= mask; - u8tmp &= ~mask; - val |= u8tmp; - } - - return m88ds3103_wr_regs(priv, reg, &val, 1); -} - -/* read single register with mask */ -static int m88ds3103_rd_reg_mask(struct m88ds3103_priv *priv, - u8 reg, u8 *val, u8 mask) -{ - int ret, i; - u8 u8tmp; - - ret = m88ds3103_rd_regs(priv, reg, &u8tmp, 1); - if (ret) - return ret; - - u8tmp &= mask; - - /* find position of the first bit */ - for (i = 0; i < 8; i++) { - if ((mask >> i) & 0x01) - break; - } - *val = u8tmp >> i; - - return 0; -} - /* write reg val table using reg addr auto increment */ -static int m88ds3103_wr_reg_val_tab(struct m88ds3103_priv *priv, +static int m88ds3103_wr_reg_val_tab(struct m88ds3103_dev *dev, const struct m88ds3103_reg_val *tab, int tab_len) { + struct i2c_client *client = dev->client; int ret, i, j; u8 buf[83]; - dev_dbg(&priv->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len); + dev_dbg(&client->dev, "tab_len=%d\n", tab_len); if (tab_len > 86) { ret = -EINVAL; @@ -171,8 +37,8 @@ static int m88ds3103_wr_reg_val_tab(struct m88ds3103_priv *priv, buf[j] = tab[i].val; if (i == tab_len - 1 || tab[i].reg != tab[i + 1].reg - 1 || - !((j + 1) % (priv->cfg->i2c_wr_max - 1))) { - ret = m88ds3103_wr_regs(priv, tab[i].reg - j, buf, j + 1); + !((j + 1) % (dev->cfg->i2c_wr_max - 1))) { + ret = regmap_bulk_write(dev->regmap, tab[i].reg - j, buf, j + 1); if (ret) goto err; @@ -182,66 +48,238 @@ static int m88ds3103_wr_reg_val_tab(struct m88ds3103_priv *priv, return 0; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + +/* + * Get the demodulator AGC PWM voltage setting supplied to the tuner. + */ +int m88ds3103_get_agc_pwm(struct dvb_frontend *fe, u8 *_agc_pwm) +{ + struct m88ds3103_dev *dev = fe->demodulator_priv; + unsigned tmp; + int ret; + + ret = regmap_read(dev->regmap, 0x3f, &tmp); + if (ret == 0) + *_agc_pwm = tmp; return ret; } +EXPORT_SYMBOL(m88ds3103_get_agc_pwm); -static int m88ds3103_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int m88ds3103_read_status(struct dvb_frontend *fe, + enum fe_status *status) { - struct m88ds3103_priv *priv = fe->demodulator_priv; + struct m88ds3103_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret; - u8 u8tmp; + int ret, i, itmp; + unsigned int utmp; + u8 buf[3]; *status = 0; - if (!priv->warm) { + if (!dev->warm) { ret = -EAGAIN; goto err; } switch (c->delivery_system) { case SYS_DVBS: - ret = m88ds3103_rd_reg_mask(priv, 0xd1, &u8tmp, 0x07); + ret = regmap_read(dev->regmap, 0xd1, &utmp); if (ret) goto err; - if (u8tmp == 0x07) + if ((utmp & 0x07) == 0x07) *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; break; case SYS_DVBS2: - ret = m88ds3103_rd_reg_mask(priv, 0x0d, &u8tmp, 0x8f); + ret = regmap_read(dev->regmap, 0x0d, &utmp); if (ret) goto err; - if (u8tmp == 0x8f) + if ((utmp & 0x8f) == 0x8f) *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; break; default: - dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n", - __func__); + dev_dbg(&client->dev, "invalid delivery_system\n"); ret = -EINVAL; goto err; } - priv->fe_status = *status; + dev->fe_status = *status; + dev_dbg(&client->dev, "lock=%02x status=%02x\n", utmp, *status); + + /* CNR */ + if (dev->fe_status & FE_HAS_VITERBI) { + unsigned int cnr, noise, signal, noise_tot, signal_tot; + + cnr = 0; + /* more iterations for more accurate estimation */ + #define M88DS3103_SNR_ITERATIONS 3 + + switch (c->delivery_system) { + case SYS_DVBS: + itmp = 0; + + for (i = 0; i < M88DS3103_SNR_ITERATIONS; i++) { + ret = regmap_read(dev->regmap, 0xff, &utmp); + if (ret) + goto err; + + itmp += utmp; + } + + /* use of single register limits max value to 15 dB */ + /* SNR(X) dB = 10 * ln(X) / ln(10) dB */ + itmp = DIV_ROUND_CLOSEST(itmp, 8 * M88DS3103_SNR_ITERATIONS); + if (itmp) + cnr = div_u64((u64) 10000 * intlog2(itmp), intlog2(10)); + break; + case SYS_DVBS2: + noise_tot = 0; + signal_tot = 0; + + for (i = 0; i < M88DS3103_SNR_ITERATIONS; i++) { + ret = regmap_bulk_read(dev->regmap, 0x8c, buf, 3); + if (ret) + goto err; + + noise = buf[1] << 6; /* [13:6] */ + noise |= buf[0] & 0x3f; /* [5:0] */ + noise >>= 2; + signal = buf[2] * buf[2]; + signal >>= 1; + + noise_tot += noise; + signal_tot += signal; + } + + noise = noise_tot / M88DS3103_SNR_ITERATIONS; + signal = signal_tot / M88DS3103_SNR_ITERATIONS; + + /* SNR(X) dB = 10 * log10(X) dB */ + if (signal > noise) { + itmp = signal / noise; + cnr = div_u64((u64) 10000 * intlog10(itmp), (1 << 24)); + } + break; + default: + dev_dbg(&client->dev, "invalid delivery_system\n"); + ret = -EINVAL; + goto err; + } + + if (cnr) { + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = cnr; + } else { + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + } else { + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + /* BER */ + if (dev->fe_status & FE_HAS_LOCK) { + unsigned int utmp, post_bit_error, post_bit_count; - dev_dbg(&priv->i2c->dev, "%s: lock=%02x status=%02x\n", - __func__, u8tmp, *status); + switch (c->delivery_system) { + case SYS_DVBS: + ret = regmap_write(dev->regmap, 0xf9, 0x04); + if (ret) + goto err; + + ret = regmap_read(dev->regmap, 0xf8, &utmp); + if (ret) + goto err; + + /* measurement ready? */ + if (!(utmp & 0x10)) { + ret = regmap_bulk_read(dev->regmap, 0xf6, buf, 2); + if (ret) + goto err; + + post_bit_error = buf[1] << 8 | buf[0] << 0; + post_bit_count = 0x800000; + dev->post_bit_error += post_bit_error; + dev->post_bit_count += post_bit_count; + dev->dvbv3_ber = post_bit_error; + + /* restart measurement */ + utmp |= 0x10; + ret = regmap_write(dev->regmap, 0xf8, utmp); + if (ret) + goto err; + } + break; + case SYS_DVBS2: + ret = regmap_bulk_read(dev->regmap, 0xd5, buf, 3); + if (ret) + goto err; + + utmp = buf[2] << 16 | buf[1] << 8 | buf[0] << 0; + + /* enough data? */ + if (utmp > 4000) { + ret = regmap_bulk_read(dev->regmap, 0xf7, buf, 2); + if (ret) + goto err; + + post_bit_error = buf[1] << 8 | buf[0] << 0; + post_bit_count = 32 * utmp; /* TODO: FEC */ + dev->post_bit_error += post_bit_error; + dev->post_bit_count += post_bit_count; + dev->dvbv3_ber = post_bit_error; + + /* restart measurement */ + ret = regmap_write(dev->regmap, 0xd1, 0x01); + if (ret) + goto err; + + ret = regmap_write(dev->regmap, 0xf9, 0x01); + if (ret) + goto err; + + ret = regmap_write(dev->regmap, 0xf9, 0x00); + if (ret) + goto err; + + ret = regmap_write(dev->regmap, 0xd1, 0x00); + if (ret) + goto err; + } + break; + default: + dev_dbg(&client->dev, "invalid delivery_system\n"); + ret = -EINVAL; + goto err; + } + + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue = dev->post_bit_error; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].uvalue = dev->post_bit_count; + } else { + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } return 0; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int m88ds3103_set_frontend(struct dvb_frontend *fe) { - struct m88ds3103_priv *priv = fe->demodulator_priv; + struct m88ds3103_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, len; const struct m88ds3103_reg_val *init; @@ -251,29 +289,28 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) u32 tuner_frequency, target_mclk; s32 s32tmp; - dev_dbg(&priv->i2c->dev, - "%s: delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n", - __func__, c->delivery_system, - c->modulation, c->frequency, c->symbol_rate, - c->inversion, c->pilot, c->rolloff); + dev_dbg(&client->dev, + "delivery_system=%d modulation=%d frequency=%u symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n", + c->delivery_system, c->modulation, c->frequency, c->symbol_rate, + c->inversion, c->pilot, c->rolloff); - if (!priv->warm) { + if (!dev->warm) { ret = -EAGAIN; goto err; } /* reset */ - ret = m88ds3103_wr_reg(priv, 0x07, 0x80); + ret = regmap_write(dev->regmap, 0x07, 0x80); if (ret) goto err; - ret = m88ds3103_wr_reg(priv, 0x07, 0x00); + ret = regmap_write(dev->regmap, 0x07, 0x00); if (ret) goto err; /* Disable demod clock path */ - if (priv->chip_id == M88RS6000_CHIP_ID) { - ret = m88ds3103_wr_reg(priv, 0x06, 0xe0); + if (dev->chip_id == M88RS6000_CHIP_ID) { + ret = regmap_write(dev->regmap, 0x06, 0xe0); if (ret) goto err; } @@ -299,11 +336,11 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) } /* select M88RS6000 demod main mclk and ts mclk from tuner die. */ - if (priv->chip_id == M88RS6000_CHIP_ID) { + if (dev->chip_id == M88RS6000_CHIP_ID) { if (c->symbol_rate > 45010000) - priv->mclk_khz = 110250; + dev->mclk_khz = 110250; else - priv->mclk_khz = 96000; + dev->mclk_khz = 96000; if (c->delivery_system == SYS_DVBS) target_mclk = 96000; @@ -311,18 +348,18 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) target_mclk = 144000; /* Enable demod clock path */ - ret = m88ds3103_wr_reg(priv, 0x06, 0x00); + ret = regmap_write(dev->regmap, 0x06, 0x00); if (ret) goto err; usleep_range(10000, 20000); } else { /* set M88DS3103 mclk and ts mclk. */ - priv->mclk_khz = 96000; + dev->mclk_khz = 96000; - switch (priv->cfg->ts_mode) { + switch (dev->cfg->ts_mode) { case M88DS3103_TS_SERIAL: case M88DS3103_TS_SERIAL_D7: - target_mclk = priv->cfg->ts_clk; + target_mclk = dev->cfg->ts_clk; break; case M88DS3103_TS_PARALLEL: case M88DS3103_TS_CI: @@ -338,8 +375,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) } break; default: - dev_dbg(&priv->i2c->dev, "%s: invalid ts_mode\n", - __func__); + dev_dbg(&client->dev, "invalid ts_mode\n"); ret = -EINVAL; goto err; } @@ -358,25 +394,25 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) u8tmp2 = 0x00; /* 0b00 */ break; } - ret = m88ds3103_wr_reg_mask(priv, 0x22, u8tmp1 << 6, 0xc0); + ret = regmap_update_bits(dev->regmap, 0x22, 0xc0, u8tmp1 << 6); if (ret) goto err; - ret = m88ds3103_wr_reg_mask(priv, 0x24, u8tmp2 << 6, 0xc0); + ret = regmap_update_bits(dev->regmap, 0x24, 0xc0, u8tmp2 << 6); if (ret) goto err; } - ret = m88ds3103_wr_reg(priv, 0xb2, 0x01); + ret = regmap_write(dev->regmap, 0xb2, 0x01); if (ret) goto err; - ret = m88ds3103_wr_reg(priv, 0x00, 0x01); + ret = regmap_write(dev->regmap, 0x00, 0x01); if (ret) goto err; switch (c->delivery_system) { case SYS_DVBS: - if (priv->chip_id == M88RS6000_CHIP_ID) { + if (dev->chip_id == M88RS6000_CHIP_ID) { len = ARRAY_SIZE(m88rs6000_dvbs_init_reg_vals); init = m88rs6000_dvbs_init_reg_vals; } else { @@ -385,7 +421,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) } break; case SYS_DVBS2: - if (priv->chip_id == M88RS6000_CHIP_ID) { + if (dev->chip_id == M88RS6000_CHIP_ID) { len = ARRAY_SIZE(m88rs6000_dvbs2_init_reg_vals); init = m88rs6000_dvbs2_init_reg_vals; } else { @@ -394,44 +430,43 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) } break; default: - dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n", - __func__); + dev_dbg(&client->dev, "invalid delivery_system\n"); ret = -EINVAL; goto err; } /* program init table */ - if (c->delivery_system != priv->delivery_system) { - ret = m88ds3103_wr_reg_val_tab(priv, init, len); + if (c->delivery_system != dev->delivery_system) { + ret = m88ds3103_wr_reg_val_tab(dev, init, len); if (ret) goto err; } - if (priv->chip_id == M88RS6000_CHIP_ID) { + if (dev->chip_id == M88RS6000_CHIP_ID) { if ((c->delivery_system == SYS_DVBS2) && ((c->symbol_rate / 1000) <= 5000)) { - ret = m88ds3103_wr_reg(priv, 0xc0, 0x04); + ret = regmap_write(dev->regmap, 0xc0, 0x04); if (ret) goto err; buf[0] = 0x09; buf[1] = 0x22; buf[2] = 0x88; - ret = m88ds3103_wr_regs(priv, 0x8a, buf, 3); + ret = regmap_bulk_write(dev->regmap, 0x8a, buf, 3); if (ret) goto err; } - ret = m88ds3103_wr_reg_mask(priv, 0x9d, 0x08, 0x08); + ret = regmap_update_bits(dev->regmap, 0x9d, 0x08, 0x08); if (ret) goto err; - ret = m88ds3103_wr_reg(priv, 0xf1, 0x01); + ret = regmap_write(dev->regmap, 0xf1, 0x01); if (ret) goto err; - ret = m88ds3103_wr_reg_mask(priv, 0x30, 0x80, 0x80); + ret = regmap_update_bits(dev->regmap, 0x30, 0x80, 0x80); if (ret) goto err; } - switch (priv->cfg->ts_mode) { + switch (dev->cfg->ts_mode) { case M88DS3103_TS_SERIAL: u8tmp1 = 0x00; u8tmp = 0x06; @@ -447,39 +482,39 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) u8tmp = 0x03; break; default: - dev_dbg(&priv->i2c->dev, "%s: invalid ts_mode\n", __func__); + dev_dbg(&client->dev, "invalid ts_mode\n"); ret = -EINVAL; goto err; } - if (priv->cfg->ts_clk_pol) + if (dev->cfg->ts_clk_pol) u8tmp |= 0x40; /* TS mode */ - ret = m88ds3103_wr_reg(priv, 0xfd, u8tmp); + ret = regmap_write(dev->regmap, 0xfd, u8tmp); if (ret) goto err; - switch (priv->cfg->ts_mode) { + switch (dev->cfg->ts_mode) { case M88DS3103_TS_SERIAL: case M88DS3103_TS_SERIAL_D7: - ret = m88ds3103_wr_reg_mask(priv, 0x29, u8tmp1, 0x20); + ret = regmap_update_bits(dev->regmap, 0x29, 0x20, u8tmp1); if (ret) goto err; u8tmp1 = 0; u8tmp2 = 0; break; default: - if (priv->cfg->ts_clk) { - divide_ratio = DIV_ROUND_UP(target_mclk, priv->cfg->ts_clk); + if (dev->cfg->ts_clk) { + divide_ratio = DIV_ROUND_UP(target_mclk, dev->cfg->ts_clk); u8tmp1 = divide_ratio / 2; u8tmp2 = DIV_ROUND_UP(divide_ratio, 2); } } - dev_dbg(&priv->i2c->dev, - "%s: target_mclk=%d ts_clk=%d divide_ratio=%d\n", - __func__, target_mclk, priv->cfg->ts_clk, divide_ratio); + dev_dbg(&client->dev, + "target_mclk=%d ts_clk=%d divide_ratio=%d\n", + target_mclk, dev->cfg->ts_clk, divide_ratio); u8tmp1--; u8tmp2--; @@ -488,17 +523,17 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) /* u8tmp2[5:0] => ea[5:0] */ u8tmp2 &= 0x3f; - ret = m88ds3103_rd_reg(priv, 0xfe, &u8tmp); + ret = regmap_bulk_read(dev->regmap, 0xfe, &u8tmp, 1); if (ret) goto err; u8tmp = ((u8tmp & 0xf0) << 0) | u8tmp1 >> 2; - ret = m88ds3103_wr_reg(priv, 0xfe, u8tmp); + ret = regmap_write(dev->regmap, 0xfe, u8tmp); if (ret) goto err; u8tmp = ((u8tmp1 & 0x03) << 6) | u8tmp2 >> 0; - ret = m88ds3103_wr_reg(priv, 0xea, u8tmp); + ret = regmap_write(dev->regmap, 0xea, u8tmp); if (ret) goto err; @@ -509,250 +544,254 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) else u8tmp = 0x06; - ret = m88ds3103_wr_reg(priv, 0xc3, 0x08); + ret = regmap_write(dev->regmap, 0xc3, 0x08); if (ret) goto err; - ret = m88ds3103_wr_reg(priv, 0xc8, u8tmp); + ret = regmap_write(dev->regmap, 0xc8, u8tmp); if (ret) goto err; - ret = m88ds3103_wr_reg(priv, 0xc4, 0x08); + ret = regmap_write(dev->regmap, 0xc4, 0x08); if (ret) goto err; - ret = m88ds3103_wr_reg(priv, 0xc7, 0x00); + ret = regmap_write(dev->regmap, 0xc7, 0x00); if (ret) goto err; - u16tmp = DIV_ROUND_CLOSEST((c->symbol_rate / 1000) << 15, priv->mclk_khz / 2); + u16tmp = DIV_ROUND_CLOSEST((c->symbol_rate / 1000) << 15, dev->mclk_khz / 2); buf[0] = (u16tmp >> 0) & 0xff; buf[1] = (u16tmp >> 8) & 0xff; - ret = m88ds3103_wr_regs(priv, 0x61, buf, 2); + ret = regmap_bulk_write(dev->regmap, 0x61, buf, 2); if (ret) goto err; - ret = m88ds3103_wr_reg_mask(priv, 0x4d, priv->cfg->spec_inv << 1, 0x02); + ret = regmap_update_bits(dev->regmap, 0x4d, 0x02, dev->cfg->spec_inv << 1); if (ret) goto err; - ret = m88ds3103_wr_reg_mask(priv, 0x30, priv->cfg->agc_inv << 4, 0x10); + ret = regmap_update_bits(dev->regmap, 0x30, 0x10, dev->cfg->agc_inv << 4); if (ret) goto err; - ret = m88ds3103_wr_reg(priv, 0x33, priv->cfg->agc); + ret = regmap_write(dev->regmap, 0x33, dev->cfg->agc); if (ret) goto err; - dev_dbg(&priv->i2c->dev, "%s: carrier offset=%d\n", __func__, - (tuner_frequency - c->frequency)); + dev_dbg(&client->dev, "carrier offset=%d\n", + (tuner_frequency - c->frequency)); s32tmp = 0x10000 * (tuner_frequency - c->frequency); - s32tmp = DIV_ROUND_CLOSEST(s32tmp, priv->mclk_khz); + s32tmp = DIV_ROUND_CLOSEST(s32tmp, dev->mclk_khz); if (s32tmp < 0) s32tmp += 0x10000; buf[0] = (s32tmp >> 0) & 0xff; buf[1] = (s32tmp >> 8) & 0xff; - ret = m88ds3103_wr_regs(priv, 0x5e, buf, 2); + ret = regmap_bulk_write(dev->regmap, 0x5e, buf, 2); if (ret) goto err; - ret = m88ds3103_wr_reg(priv, 0x00, 0x00); + ret = regmap_write(dev->regmap, 0x00, 0x00); if (ret) goto err; - ret = m88ds3103_wr_reg(priv, 0xb2, 0x00); + ret = regmap_write(dev->regmap, 0xb2, 0x00); if (ret) goto err; - priv->delivery_system = c->delivery_system; + dev->delivery_system = c->delivery_system; return 0; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int m88ds3103_init(struct dvb_frontend *fe) { - struct m88ds3103_priv *priv = fe->demodulator_priv; + struct m88ds3103_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, len, remaining; + unsigned int utmp; const struct firmware *fw = NULL; u8 *fw_file; - u8 u8tmp; - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); /* set cold state by default */ - priv->warm = false; + dev->warm = false; /* wake up device from sleep */ - ret = m88ds3103_wr_reg_mask(priv, 0x08, 0x01, 0x01); + ret = regmap_update_bits(dev->regmap, 0x08, 0x01, 0x01); if (ret) goto err; - - ret = m88ds3103_wr_reg_mask(priv, 0x04, 0x00, 0x01); + ret = regmap_update_bits(dev->regmap, 0x04, 0x01, 0x00); if (ret) goto err; - - ret = m88ds3103_wr_reg_mask(priv, 0x23, 0x00, 0x10); + ret = regmap_update_bits(dev->regmap, 0x23, 0x10, 0x00); if (ret) goto err; /* firmware status */ - ret = m88ds3103_rd_reg(priv, 0xb9, &u8tmp); + ret = regmap_read(dev->regmap, 0xb9, &utmp); if (ret) goto err; - dev_dbg(&priv->i2c->dev, "%s: firmware=%02x\n", __func__, u8tmp); + dev_dbg(&client->dev, "firmware=%02x\n", utmp); - if (u8tmp) + if (utmp) goto skip_fw_download; /* global reset, global diseqc reset, golbal fec reset */ - ret = m88ds3103_wr_reg(priv, 0x07, 0xe0); + ret = regmap_write(dev->regmap, 0x07, 0xe0); if (ret) goto err; - - ret = m88ds3103_wr_reg(priv, 0x07, 0x00); + ret = regmap_write(dev->regmap, 0x07, 0x00); if (ret) goto err; /* cold state - try to download firmware */ - dev_info(&priv->i2c->dev, "%s: found a '%s' in cold state\n", - KBUILD_MODNAME, m88ds3103_ops.info.name); + dev_info(&client->dev, "found a '%s' in cold state\n", + m88ds3103_ops.info.name); - if (priv->chip_id == M88RS6000_CHIP_ID) + if (dev->chip_id == M88RS6000_CHIP_ID) fw_file = M88RS6000_FIRMWARE; else fw_file = M88DS3103_FIRMWARE; /* request the firmware, this will block and timeout */ - ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent); + ret = request_firmware(&fw, fw_file, &client->dev); if (ret) { - dev_err(&priv->i2c->dev, "%s: firmware file '%s' not found\n", - KBUILD_MODNAME, fw_file); + dev_err(&client->dev, "firmare file '%s' not found\n", fw_file); goto err; } - dev_info(&priv->i2c->dev, "%s: downloading firmware from file '%s'\n", - KBUILD_MODNAME, fw_file); + dev_info(&client->dev, "downloading firmware from file '%s'\n", + fw_file); - ret = m88ds3103_wr_reg(priv, 0xb2, 0x01); + ret = regmap_write(dev->regmap, 0xb2, 0x01); if (ret) goto error_fw_release; for (remaining = fw->size; remaining > 0; - remaining -= (priv->cfg->i2c_wr_max - 1)) { + remaining -= (dev->cfg->i2c_wr_max - 1)) { len = remaining; - if (len > (priv->cfg->i2c_wr_max - 1)) - len = (priv->cfg->i2c_wr_max - 1); + if (len > (dev->cfg->i2c_wr_max - 1)) + len = (dev->cfg->i2c_wr_max - 1); - ret = m88ds3103_wr_regs(priv, 0xb0, + ret = regmap_bulk_write(dev->regmap, 0xb0, &fw->data[fw->size - remaining], len); if (ret) { - dev_err(&priv->i2c->dev, - "%s: firmware download failed=%d\n", - KBUILD_MODNAME, ret); + dev_err(&client->dev, "firmware download failed=%d\n", + ret); goto error_fw_release; } } - ret = m88ds3103_wr_reg(priv, 0xb2, 0x00); + ret = regmap_write(dev->regmap, 0xb2, 0x00); if (ret) goto error_fw_release; release_firmware(fw); fw = NULL; - ret = m88ds3103_rd_reg(priv, 0xb9, &u8tmp); + ret = regmap_read(dev->regmap, 0xb9, &utmp); if (ret) goto err; - if (!u8tmp) { - dev_info(&priv->i2c->dev, "%s: firmware did not run\n", - KBUILD_MODNAME); + if (!utmp) { + dev_info(&client->dev, "firmware did not run\n"); ret = -EFAULT; goto err; } - dev_info(&priv->i2c->dev, "%s: found a '%s' in warm state\n", - KBUILD_MODNAME, m88ds3103_ops.info.name); - dev_info(&priv->i2c->dev, "%s: firmware version %X.%X\n", - KBUILD_MODNAME, (u8tmp >> 4) & 0xf, (u8tmp >> 0 & 0xf)); + dev_info(&client->dev, "found a '%s' in warm state\n", + m88ds3103_ops.info.name); + dev_info(&client->dev, "firmware version: %X.%X\n", + (utmp >> 4) & 0xf, (utmp >> 0 & 0xf)); skip_fw_download: /* warm state */ - priv->warm = true; + dev->warm = true; - return 0; + /* init stats here in order signal app which stats are supported */ + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return 0; error_fw_release: release_firmware(fw); err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int m88ds3103_sleep(struct dvb_frontend *fe) { - struct m88ds3103_priv *priv = fe->demodulator_priv; + struct m88ds3103_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; int ret; - u8 u8tmp; + unsigned int utmp; - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); - priv->delivery_system = SYS_UNDEFINED; + dev->fe_status = 0; + dev->delivery_system = SYS_UNDEFINED; /* TS Hi-Z */ - if (priv->chip_id == M88RS6000_CHIP_ID) - u8tmp = 0x29; + if (dev->chip_id == M88RS6000_CHIP_ID) + utmp = 0x29; else - u8tmp = 0x27; - ret = m88ds3103_wr_reg_mask(priv, u8tmp, 0x00, 0x01); + utmp = 0x27; + ret = regmap_update_bits(dev->regmap, utmp, 0x01, 0x00); if (ret) goto err; /* sleep */ - ret = m88ds3103_wr_reg_mask(priv, 0x08, 0x00, 0x01); + ret = regmap_update_bits(dev->regmap, 0x08, 0x01, 0x00); if (ret) goto err; - - ret = m88ds3103_wr_reg_mask(priv, 0x04, 0x01, 0x01); + ret = regmap_update_bits(dev->regmap, 0x04, 0x01, 0x01); if (ret) goto err; - - ret = m88ds3103_wr_reg_mask(priv, 0x23, 0x10, 0x10); + ret = regmap_update_bits(dev->regmap, 0x23, 0x10, 0x10); if (ret) goto err; return 0; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int m88ds3103_get_frontend(struct dvb_frontend *fe) { - struct m88ds3103_priv *priv = fe->demodulator_priv; + struct m88ds3103_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; u8 buf[3]; - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); - if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) { - ret = -EAGAIN; + if (!dev->warm || !(dev->fe_status & FE_HAS_LOCK)) { + ret = 0; goto err; } switch (c->delivery_system) { case SYS_DVBS: - ret = m88ds3103_rd_reg(priv, 0xe0, &buf[0]); + ret = regmap_bulk_read(dev->regmap, 0xe0, &buf[0], 1); if (ret) goto err; - ret = m88ds3103_rd_reg(priv, 0xe6, &buf[1]); + ret = regmap_bulk_read(dev->regmap, 0xe6, &buf[1], 1); if (ret) goto err; @@ -782,23 +821,22 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe) c->fec_inner = FEC_1_2; break; default: - dev_dbg(&priv->i2c->dev, "%s: invalid fec_inner\n", - __func__); + dev_dbg(&client->dev, "invalid fec_inner\n"); } c->modulation = QPSK; break; case SYS_DVBS2: - ret = m88ds3103_rd_reg(priv, 0x7e, &buf[0]); + ret = regmap_bulk_read(dev->regmap, 0x7e, &buf[0], 1); if (ret) goto err; - ret = m88ds3103_rd_reg(priv, 0x89, &buf[1]); + ret = regmap_bulk_read(dev->regmap, 0x89, &buf[1], 1); if (ret) goto err; - ret = m88ds3103_rd_reg(priv, 0xf2, &buf[2]); + ret = regmap_bulk_read(dev->regmap, 0xf2, &buf[2], 1); if (ret) goto err; @@ -831,8 +869,7 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe) c->fec_inner = FEC_9_10; break; default: - dev_dbg(&priv->i2c->dev, "%s: invalid fec_inner\n", - __func__); + dev_dbg(&client->dev, "invalid fec_inner\n"); } switch ((buf[0] >> 5) & 0x01) { @@ -858,8 +895,7 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe) c->modulation = APSK_32; break; default: - dev_dbg(&priv->i2c->dev, "%s: invalid modulation\n", - __func__); + dev_dbg(&client->dev, "invalid modulation\n"); } switch ((buf[1] >> 7) & 0x01) { @@ -882,201 +918,60 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe) c->rolloff = ROLLOFF_20; break; default: - dev_dbg(&priv->i2c->dev, "%s: invalid rolloff\n", - __func__); + dev_dbg(&client->dev, "invalid rolloff\n"); } break; default: - dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n", - __func__); + dev_dbg(&client->dev, "invalid delivery_system\n"); ret = -EINVAL; goto err; } - ret = m88ds3103_rd_regs(priv, 0x6d, buf, 2); + ret = regmap_bulk_read(dev->regmap, 0x6d, buf, 2); if (ret) goto err; c->symbol_rate = 1ull * ((buf[1] << 8) | (buf[0] << 0)) * - priv->mclk_khz * 1000 / 0x10000; + dev->mclk_khz * 1000 / 0x10000; return 0; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *snr) { - struct m88ds3103_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret, i, tmp; - u8 buf[3]; - u16 noise, signal; - u32 noise_tot, signal_tot; - - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); - /* reports SNR in resolution of 0.1 dB */ - - /* more iterations for more accurate estimation */ - #define M88DS3103_SNR_ITERATIONS 3 - - switch (c->delivery_system) { - case SYS_DVBS: - tmp = 0; - for (i = 0; i < M88DS3103_SNR_ITERATIONS; i++) { - ret = m88ds3103_rd_reg(priv, 0xff, &buf[0]); - if (ret) - goto err; - - tmp += buf[0]; - } - - /* use of one register limits max value to 15 dB */ - /* SNR(X) dB = 10 * ln(X) / ln(10) dB */ - tmp = DIV_ROUND_CLOSEST(tmp, 8 * M88DS3103_SNR_ITERATIONS); - if (tmp) - *snr = div_u64((u64) 100 * intlog2(tmp), intlog2(10)); - else - *snr = 0; - break; - case SYS_DVBS2: - noise_tot = 0; - signal_tot = 0; - - for (i = 0; i < M88DS3103_SNR_ITERATIONS; i++) { - ret = m88ds3103_rd_regs(priv, 0x8c, buf, 3); - if (ret) - goto err; - - noise = buf[1] << 6; /* [13:6] */ - noise |= buf[0] & 0x3f; /* [5:0] */ - noise >>= 2; - signal = buf[2] * buf[2]; - signal >>= 1; - - noise_tot += noise; - signal_tot += signal; - } - - noise = noise_tot / M88DS3103_SNR_ITERATIONS; - signal = signal_tot / M88DS3103_SNR_ITERATIONS; - - /* SNR(X) dB = 10 * log10(X) dB */ - if (signal > noise) { - tmp = signal / noise; - *snr = div_u64((u64) 100 * intlog10(tmp), (1 << 24)); - } else { - *snr = 0; - } - break; - default: - dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n", - __func__); - ret = -EINVAL; - goto err; - } + if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL) + *snr = div_s64(c->cnr.stat[0].svalue, 100); + else + *snr = 0; return 0; -err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - return ret; } static int m88ds3103_read_ber(struct dvb_frontend *fe, u32 *ber) { - struct m88ds3103_priv *priv = fe->demodulator_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret; - unsigned int utmp; - u8 buf[3], u8tmp; - - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); - - switch (c->delivery_system) { - case SYS_DVBS: - ret = m88ds3103_wr_reg(priv, 0xf9, 0x04); - if (ret) - goto err; - - ret = m88ds3103_rd_reg(priv, 0xf8, &u8tmp); - if (ret) - goto err; - - if (!(u8tmp & 0x10)) { - u8tmp |= 0x10; - - ret = m88ds3103_rd_regs(priv, 0xf6, buf, 2); - if (ret) - goto err; - - priv->ber = (buf[1] << 8) | (buf[0] << 0); - - /* restart counters */ - ret = m88ds3103_wr_reg(priv, 0xf8, u8tmp); - if (ret) - goto err; - } - break; - case SYS_DVBS2: - ret = m88ds3103_rd_regs(priv, 0xd5, buf, 3); - if (ret) - goto err; - - utmp = (buf[2] << 16) | (buf[1] << 8) | (buf[0] << 0); - - if (utmp > 3000) { - ret = m88ds3103_rd_regs(priv, 0xf7, buf, 2); - if (ret) - goto err; - - priv->ber = (buf[1] << 8) | (buf[0] << 0); - - /* restart counters */ - ret = m88ds3103_wr_reg(priv, 0xd1, 0x01); - if (ret) - goto err; - - ret = m88ds3103_wr_reg(priv, 0xf9, 0x01); - if (ret) - goto err; - - ret = m88ds3103_wr_reg(priv, 0xf9, 0x00); - if (ret) - goto err; - - ret = m88ds3103_wr_reg(priv, 0xd1, 0x00); - if (ret) - goto err; - } - break; - default: - dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n", - __func__); - ret = -EINVAL; - goto err; - } + struct m88ds3103_dev *dev = fe->demodulator_priv; - *ber = priv->ber; + *ber = dev->dvbv3_ber; return 0; -err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - return ret; } static int m88ds3103_set_tone(struct dvb_frontend *fe, - fe_sec_tone_mode_t fe_sec_tone_mode) + enum fe_sec_tone_mode fe_sec_tone_mode) { - struct m88ds3103_priv *priv = fe->demodulator_priv; + struct m88ds3103_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; int ret; - u8 u8tmp, tone, reg_a1_mask; + unsigned int utmp, tone, reg_a1_mask; - dev_dbg(&priv->i2c->dev, "%s: fe_sec_tone_mode=%d\n", __func__, - fe_sec_tone_mode); + dev_dbg(&client->dev, "fe_sec_tone_mode=%d\n", fe_sec_tone_mode); - if (!priv->warm) { + if (!dev->warm) { ret = -EAGAIN; goto err; } @@ -1091,40 +986,39 @@ static int m88ds3103_set_tone(struct dvb_frontend *fe, reg_a1_mask = 0x00; break; default: - dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_tone_mode\n", - __func__); + dev_dbg(&client->dev, "invalid fe_sec_tone_mode\n"); ret = -EINVAL; goto err; } - u8tmp = tone << 7 | priv->cfg->envelope_mode << 5; - ret = m88ds3103_wr_reg_mask(priv, 0xa2, u8tmp, 0xe0); + utmp = tone << 7 | dev->cfg->envelope_mode << 5; + ret = regmap_update_bits(dev->regmap, 0xa2, 0xe0, utmp); if (ret) goto err; - u8tmp = 1 << 2; - ret = m88ds3103_wr_reg_mask(priv, 0xa1, u8tmp, reg_a1_mask); + utmp = 1 << 2; + ret = regmap_update_bits(dev->regmap, 0xa1, reg_a1_mask, utmp); if (ret) goto err; return 0; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int m88ds3103_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t fe_sec_voltage) + enum fe_sec_voltage fe_sec_voltage) { - struct m88ds3103_priv *priv = fe->demodulator_priv; + struct m88ds3103_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; int ret; - u8 u8tmp; + unsigned int utmp; bool voltage_sel, voltage_dis; - dev_dbg(&priv->i2c->dev, "%s: fe_sec_voltage=%d\n", __func__, - fe_sec_voltage); + dev_dbg(&client->dev, "fe_sec_voltage=%d\n", fe_sec_voltage); - if (!priv->warm) { + if (!dev->warm) { ret = -EAGAIN; goto err; } @@ -1143,38 +1037,39 @@ static int m88ds3103_set_voltage(struct dvb_frontend *fe, voltage_dis = true; break; default: - dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_voltage\n", - __func__); + dev_dbg(&client->dev, "invalid fe_sec_voltage\n"); ret = -EINVAL; goto err; } /* output pin polarity */ - voltage_sel ^= priv->cfg->lnb_hv_pol; - voltage_dis ^= priv->cfg->lnb_en_pol; + voltage_sel ^= dev->cfg->lnb_hv_pol; + voltage_dis ^= dev->cfg->lnb_en_pol; - u8tmp = voltage_dis << 1 | voltage_sel << 0; - ret = m88ds3103_wr_reg_mask(priv, 0xa2, u8tmp, 0x03); + utmp = voltage_dis << 1 | voltage_sel << 0; + ret = regmap_update_bits(dev->regmap, 0xa2, 0x03, utmp); if (ret) goto err; return 0; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int m88ds3103_diseqc_send_master_cmd(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *diseqc_cmd) { - struct m88ds3103_priv *priv = fe->demodulator_priv; - int ret, i; - u8 u8tmp; + struct m88ds3103_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; + int ret; + unsigned int utmp; + unsigned long timeout; - dev_dbg(&priv->i2c->dev, "%s: msg=%*ph\n", __func__, - diseqc_cmd->msg_len, diseqc_cmd->msg); + dev_dbg(&client->dev, "msg=%*ph\n", + diseqc_cmd->msg_len, diseqc_cmd->msg); - if (!priv->warm) { + if (!dev->warm) { ret = -EAGAIN; goto err; } @@ -1184,75 +1079,80 @@ static int m88ds3103_diseqc_send_master_cmd(struct dvb_frontend *fe, goto err; } - u8tmp = priv->cfg->envelope_mode << 5; - ret = m88ds3103_wr_reg_mask(priv, 0xa2, u8tmp, 0xe0); + utmp = dev->cfg->envelope_mode << 5; + ret = regmap_update_bits(dev->regmap, 0xa2, 0xe0, utmp); if (ret) goto err; - ret = m88ds3103_wr_regs(priv, 0xa3, diseqc_cmd->msg, + ret = regmap_bulk_write(dev->regmap, 0xa3, diseqc_cmd->msg, diseqc_cmd->msg_len); if (ret) goto err; - ret = m88ds3103_wr_reg(priv, 0xa1, + ret = regmap_write(dev->regmap, 0xa1, (diseqc_cmd->msg_len - 1) << 3 | 0x07); if (ret) goto err; - /* DiSEqC message typical period is 54 ms */ - usleep_range(40000, 60000); - /* wait DiSEqC TX ready */ - for (i = 20, u8tmp = 1; i && u8tmp; i--) { - usleep_range(5000, 10000); + #define SEND_MASTER_CMD_TIMEOUT 120 + timeout = jiffies + msecs_to_jiffies(SEND_MASTER_CMD_TIMEOUT); + + /* DiSEqC message typical period is 54 ms */ + usleep_range(50000, 54000); - ret = m88ds3103_rd_reg_mask(priv, 0xa1, &u8tmp, 0x40); + for (utmp = 1; !time_after(jiffies, timeout) && utmp;) { + ret = regmap_read(dev->regmap, 0xa1, &utmp); if (ret) goto err; + utmp = (utmp >> 6) & 0x1; } - dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i); - - if (i == 0) { - dev_dbg(&priv->i2c->dev, "%s: diseqc tx timeout\n", __func__); + if (utmp == 0) { + dev_dbg(&client->dev, "diseqc tx took %u ms\n", + jiffies_to_msecs(jiffies) - + (jiffies_to_msecs(timeout) - SEND_MASTER_CMD_TIMEOUT)); + } else { + dev_dbg(&client->dev, "diseqc tx timeout\n"); - ret = m88ds3103_wr_reg_mask(priv, 0xa1, 0x40, 0xc0); + ret = regmap_update_bits(dev->regmap, 0xa1, 0xc0, 0x40); if (ret) goto err; } - ret = m88ds3103_wr_reg_mask(priv, 0xa2, 0x80, 0xc0); + ret = regmap_update_bits(dev->regmap, 0xa2, 0xc0, 0x80); if (ret) goto err; - if (i == 0) { + if (utmp == 1) { ret = -ETIMEDOUT; goto err; } return 0; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t fe_sec_mini_cmd) + enum fe_sec_mini_cmd fe_sec_mini_cmd) { - struct m88ds3103_priv *priv = fe->demodulator_priv; - int ret, i; - u8 u8tmp, burst; + struct m88ds3103_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; + int ret; + unsigned int utmp, burst; + unsigned long timeout; - dev_dbg(&priv->i2c->dev, "%s: fe_sec_mini_cmd=%d\n", __func__, - fe_sec_mini_cmd); + dev_dbg(&client->dev, "fe_sec_mini_cmd=%d\n", fe_sec_mini_cmd); - if (!priv->warm) { + if (!dev->warm) { ret = -EAGAIN; goto err; } - u8tmp = priv->cfg->envelope_mode << 5; - ret = m88ds3103_wr_reg_mask(priv, 0xa2, u8tmp, 0xe0); + utmp = dev->cfg->envelope_mode << 5; + ret = regmap_update_bits(dev->regmap, 0xa2, 0xe0, utmp); if (ret) goto err; @@ -1264,43 +1164,53 @@ static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe, burst = 0x01; break; default: - dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_mini_cmd\n", - __func__); + dev_dbg(&client->dev, "invalid fe_sec_mini_cmd\n"); ret = -EINVAL; goto err; } - ret = m88ds3103_wr_reg(priv, 0xa1, burst); + ret = regmap_write(dev->regmap, 0xa1, burst); if (ret) goto err; - /* DiSEqC ToneBurst period is 12.5 ms */ - usleep_range(11000, 20000); - /* wait DiSEqC TX ready */ - for (i = 5, u8tmp = 1; i && u8tmp; i--) { - usleep_range(800, 2000); + #define SEND_BURST_TIMEOUT 40 + timeout = jiffies + msecs_to_jiffies(SEND_BURST_TIMEOUT); - ret = m88ds3103_rd_reg_mask(priv, 0xa1, &u8tmp, 0x40); + /* DiSEqC ToneBurst period is 12.5 ms */ + usleep_range(8500, 12500); + + for (utmp = 1; !time_after(jiffies, timeout) && utmp;) { + ret = regmap_read(dev->regmap, 0xa1, &utmp); if (ret) goto err; + utmp = (utmp >> 6) & 0x1; } - dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i); + if (utmp == 0) { + dev_dbg(&client->dev, "diseqc tx took %u ms\n", + jiffies_to_msecs(jiffies) - + (jiffies_to_msecs(timeout) - SEND_BURST_TIMEOUT)); + } else { + dev_dbg(&client->dev, "diseqc tx timeout\n"); - ret = m88ds3103_wr_reg_mask(priv, 0xa2, 0x80, 0xc0); + ret = regmap_update_bits(dev->regmap, 0xa1, 0xc0, 0x40); + if (ret) + goto err; + } + + ret = regmap_update_bits(dev->regmap, 0xa2, 0xc0, 0x80); if (ret) goto err; - if (i == 0) { - dev_dbg(&priv->i2c->dev, "%s: diseqc tx timeout\n", __func__); + if (utmp == 1) { ret = -ETIMEDOUT; goto err; } return 0; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } @@ -1314,193 +1224,290 @@ static int m88ds3103_get_tune_settings(struct dvb_frontend *fe, static void m88ds3103_release(struct dvb_frontend *fe) { - struct m88ds3103_priv *priv = fe->demodulator_priv; + struct m88ds3103_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; - i2c_del_mux_adapter(priv->i2c_adapter); - kfree(priv); + i2c_unregister_device(client); } static int m88ds3103_select(struct i2c_adapter *adap, void *mux_priv, u32 chan) { - struct m88ds3103_priv *priv = mux_priv; + struct m88ds3103_dev *dev = mux_priv; + struct i2c_client *client = dev->client; int ret; - struct i2c_msg gate_open_msg[1] = { - { - .addr = priv->cfg->i2c_addr, - .flags = 0, - .len = 2, - .buf = "\x03\x11", - } + struct i2c_msg msg = { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = "\x03\x11", }; - mutex_lock(&priv->i2c_mutex); - - /* open tuner I2C repeater for 1 xfer, closes automatically */ - ret = __i2c_transfer(priv->i2c, gate_open_msg, 1); + /* Open tuner I2C repeater for 1 xfer, closes automatically */ + ret = __i2c_transfer(client->adapter, &msg, 1); if (ret != 1) { - dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d\n", - KBUILD_MODNAME, ret); + dev_warn(&client->dev, "i2c wr failed=%d\n", ret); if (ret >= 0) ret = -EREMOTEIO; - return ret; } return 0; } -static int m88ds3103_deselect(struct i2c_adapter *adap, void *mux_priv, - u32 chan) +/* + * XXX: That is wrapper to m88ds3103_probe() via driver core in order to provide + * proper I2C client for legacy media attach binding. + * New users must use I2C client binding directly! + */ +struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg, + struct i2c_adapter *i2c, struct i2c_adapter **tuner_i2c_adapter) { - struct m88ds3103_priv *priv = mux_priv; + struct i2c_client *client; + struct i2c_board_info board_info; + struct m88ds3103_platform_data pdata; + + pdata.clk = cfg->clock; + pdata.i2c_wr_max = cfg->i2c_wr_max; + pdata.ts_mode = cfg->ts_mode; + pdata.ts_clk = cfg->ts_clk; + pdata.ts_clk_pol = cfg->ts_clk_pol; + pdata.spec_inv = cfg->spec_inv; + pdata.agc = cfg->agc; + pdata.agc_inv = cfg->agc_inv; + pdata.clk_out = cfg->clock_out; + pdata.envelope_mode = cfg->envelope_mode; + pdata.lnb_hv_pol = cfg->lnb_hv_pol; + pdata.lnb_en_pol = cfg->lnb_en_pol; + pdata.attach_in_use = true; + + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "m88ds3103", I2C_NAME_SIZE); + board_info.addr = cfg->i2c_addr; + board_info.platform_data = &pdata; + client = i2c_new_device(i2c, &board_info); + if (!client || !client->dev.driver) + return NULL; + + *tuner_i2c_adapter = pdata.get_i2c_adapter(client); + return pdata.get_dvb_frontend(client); +} +EXPORT_SYMBOL(m88ds3103_attach); + +static struct dvb_frontend_ops m88ds3103_ops = { + .delsys = {SYS_DVBS, SYS_DVBS2}, + .info = { + .name = "Montage Technology M88DS3103", + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_tolerance = 5000, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .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_QPSK | + FE_CAN_RECOVER | + FE_CAN_2G_MODULATION + }, - mutex_unlock(&priv->i2c_mutex); + .release = m88ds3103_release, - return 0; + .get_tune_settings = m88ds3103_get_tune_settings, + + .init = m88ds3103_init, + .sleep = m88ds3103_sleep, + + .set_frontend = m88ds3103_set_frontend, + .get_frontend = m88ds3103_get_frontend, + + .read_status = m88ds3103_read_status, + .read_snr = m88ds3103_read_snr, + .read_ber = m88ds3103_read_ber, + + .diseqc_send_master_cmd = m88ds3103_diseqc_send_master_cmd, + .diseqc_send_burst = m88ds3103_diseqc_send_burst, + + .set_tone = m88ds3103_set_tone, + .set_voltage = m88ds3103_set_voltage, +}; + +static struct dvb_frontend *m88ds3103_get_dvb_frontend(struct i2c_client *client) +{ + struct m88ds3103_dev *dev = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + + return &dev->fe; } -struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg, - struct i2c_adapter *i2c, struct i2c_adapter **tuner_i2c_adapter) +static struct i2c_adapter *m88ds3103_get_i2c_adapter(struct i2c_client *client) +{ + struct m88ds3103_dev *dev = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + + return dev->i2c_adapter; +} + +static int m88ds3103_probe(struct i2c_client *client, + const struct i2c_device_id *id) { + struct m88ds3103_dev *dev; + struct m88ds3103_platform_data *pdata = client->dev.platform_data; int ret; - struct m88ds3103_priv *priv; - u8 chip_id, u8tmp; + unsigned int utmp; - /* allocate memory for the internal priv */ - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { ret = -ENOMEM; - dev_err(&i2c->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); goto err; } - priv->cfg = cfg; - priv->i2c = i2c; - mutex_init(&priv->i2c_mutex); + dev->client = client; + dev->config.clock = pdata->clk; + dev->config.i2c_wr_max = pdata->i2c_wr_max; + dev->config.ts_mode = pdata->ts_mode; + dev->config.ts_clk = pdata->ts_clk; + dev->config.ts_clk_pol = pdata->ts_clk_pol; + dev->config.spec_inv = pdata->spec_inv; + dev->config.agc_inv = pdata->agc_inv; + dev->config.clock_out = pdata->clk_out; + dev->config.envelope_mode = pdata->envelope_mode; + dev->config.agc = pdata->agc; + dev->config.lnb_hv_pol = pdata->lnb_hv_pol; + dev->config.lnb_en_pol = pdata->lnb_en_pol; + dev->cfg = &dev->config; + /* create regmap */ + dev->regmap_config.reg_bits = 8, + dev->regmap_config.val_bits = 8, + dev->regmap_config.lock_arg = dev, + dev->regmap = devm_regmap_init_i2c(client, &dev->regmap_config); + if (IS_ERR(dev->regmap)) { + ret = PTR_ERR(dev->regmap); + goto err_kfree; + } /* 0x00: chip id[6:0], 0x01: chip ver[7:0], 0x02: chip ver[15:8] */ - ret = m88ds3103_rd_reg(priv, 0x00, &chip_id); + ret = regmap_read(dev->regmap, 0x00, &utmp); if (ret) - goto err; + goto err_kfree; - chip_id >>= 1; - dev_info(&priv->i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id); + dev->chip_id = utmp >> 1; + dev_dbg(&client->dev, "chip_id=%02x\n", dev->chip_id); - switch (chip_id) { + switch (dev->chip_id) { case M88RS6000_CHIP_ID: case M88DS3103_CHIP_ID: break; default: - goto err; + goto err_kfree; } - priv->chip_id = chip_id; - switch (priv->cfg->clock_out) { + switch (dev->cfg->clock_out) { case M88DS3103_CLOCK_OUT_DISABLED: - u8tmp = 0x80; + utmp = 0x80; break; case M88DS3103_CLOCK_OUT_ENABLED: - u8tmp = 0x00; + utmp = 0x00; break; case M88DS3103_CLOCK_OUT_ENABLED_DIV2: - u8tmp = 0x10; + utmp = 0x10; break; default: - goto err; + ret = -EINVAL; + goto err_kfree; } /* 0x29 register is defined differently for m88rs6000. */ /* set internal tuner address to 0x21 */ - if (chip_id == M88RS6000_CHIP_ID) - u8tmp = 0x00; + if (dev->chip_id == M88RS6000_CHIP_ID) + utmp = 0x00; - ret = m88ds3103_wr_reg(priv, 0x29, u8tmp); + ret = regmap_write(dev->regmap, 0x29, utmp); if (ret) - goto err; + goto err_kfree; /* sleep */ - ret = m88ds3103_wr_reg_mask(priv, 0x08, 0x00, 0x01); + ret = regmap_update_bits(dev->regmap, 0x08, 0x01, 0x00); if (ret) - goto err; - - ret = m88ds3103_wr_reg_mask(priv, 0x04, 0x01, 0x01); + goto err_kfree; + ret = regmap_update_bits(dev->regmap, 0x04, 0x01, 0x01); if (ret) - goto err; - - ret = m88ds3103_wr_reg_mask(priv, 0x23, 0x10, 0x10); + goto err_kfree; + ret = regmap_update_bits(dev->regmap, 0x23, 0x10, 0x10); if (ret) - goto err; + goto err_kfree; /* create mux i2c adapter for tuner */ - priv->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, priv, 0, 0, 0, - m88ds3103_select, m88ds3103_deselect); - if (priv->i2c_adapter == NULL) - goto err; - - *tuner_i2c_adapter = priv->i2c_adapter; + dev->i2c_adapter = i2c_add_mux_adapter(client->adapter, &client->dev, + dev, 0, 0, 0, m88ds3103_select, + NULL); + if (dev->i2c_adapter == NULL) { + ret = -ENOMEM; + goto err_kfree; + } /* create dvb_frontend */ - memcpy(&priv->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops)); - if (priv->chip_id == M88RS6000_CHIP_ID) - strncpy(priv->fe.ops.info.name, - "Montage M88RS6000", sizeof(priv->fe.ops.info.name)); - priv->fe.demodulator_priv = priv; - - return &priv->fe; + memcpy(&dev->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops)); + if (dev->chip_id == M88RS6000_CHIP_ID) + strncpy(dev->fe.ops.info.name, "Montage Technology M88RS6000", + sizeof(dev->fe.ops.info.name)); + if (!pdata->attach_in_use) + dev->fe.ops.release = NULL; + dev->fe.demodulator_priv = dev; + i2c_set_clientdata(client, dev); + + /* setup callbacks */ + pdata->get_dvb_frontend = m88ds3103_get_dvb_frontend; + pdata->get_i2c_adapter = m88ds3103_get_i2c_adapter; + return 0; +err_kfree: + kfree(dev); err: - dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); - kfree(priv); - return NULL; + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; } -EXPORT_SYMBOL(m88ds3103_attach); - -static struct dvb_frontend_ops m88ds3103_ops = { - .delsys = { SYS_DVBS, SYS_DVBS2 }, - .info = { - .name = "Montage M88DS3103", - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_tolerance = 5000, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .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_QPSK | - FE_CAN_RECOVER | - FE_CAN_2G_MODULATION - }, - .release = m88ds3103_release, +static int m88ds3103_remove(struct i2c_client *client) +{ + struct m88ds3103_dev *dev = i2c_get_clientdata(client); - .get_tune_settings = m88ds3103_get_tune_settings, + dev_dbg(&client->dev, "\n"); - .init = m88ds3103_init, - .sleep = m88ds3103_sleep, + i2c_del_mux_adapter(dev->i2c_adapter); - .set_frontend = m88ds3103_set_frontend, - .get_frontend = m88ds3103_get_frontend, - - .read_status = m88ds3103_read_status, - .read_snr = m88ds3103_read_snr, - .read_ber = m88ds3103_read_ber, + kfree(dev); + return 0; +} - .diseqc_send_master_cmd = m88ds3103_diseqc_send_master_cmd, - .diseqc_send_burst = m88ds3103_diseqc_send_burst, +static const struct i2c_device_id m88ds3103_id_table[] = { + {"m88ds3103", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, m88ds3103_id_table); - .set_tone = m88ds3103_set_tone, - .set_voltage = m88ds3103_set_voltage, +static struct i2c_driver m88ds3103_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "m88ds3103", + .suppress_bind_attrs = true, + }, + .probe = m88ds3103_probe, + .remove = m88ds3103_remove, + .id_table = m88ds3103_id_table, }; +module_i2c_driver(m88ds3103_driver); + MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); -MODULE_DESCRIPTION("Montage M88DS3103 DVB-S/S2 demodulator driver"); +MODULE_DESCRIPTION("Montage Technology M88DS3103 DVB-S/S2 demodulator driver"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(M88DS3103_FIRMWARE); MODULE_FIRMWARE(M88RS6000_FIRMWARE); diff --git a/drivers/media/dvb-frontends/m88ds3103.h b/drivers/media/dvb-frontends/m88ds3103.h index 9b3b496..04b355a 100644 --- a/drivers/media/dvb-frontends/m88ds3103.h +++ b/drivers/media/dvb-frontends/m88ds3103.h @@ -1,5 +1,5 @@ /* - * Montage M88DS3103 demodulator driver + * Montage Technology M88DS3103/M88RS6000 demodulator driver * * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> * @@ -19,6 +19,63 @@ #include <linux/dvb/frontend.h> +/* + * I2C address + * 0x68, + */ + +/** + * struct m88ds3103_platform_data - Platform data for the m88ds3103 driver + * @clk: Clock frequency. + * @i2c_wr_max: Max bytes I2C adapter can write at once. + * @ts_mode: TS mode. + * @ts_clk: TS clock (KHz). + * @ts_clk_pol: TS clk polarity. 1-active at falling edge; 0-active at rising + * edge. + * @spec_inv: Input spectrum inversion. + * @agc: AGC configuration. + * @agc_inv: AGC polarity. + * @clk_out: Clock output. + * @envelope_mode: DiSEqC envelope mode. + * @lnb_hv_pol: LNB H/V pin polarity. 0: pin high set to VOLTAGE_18, pin low to + * set VOLTAGE_13. 1: pin high set to VOLTAGE_13, pin low to set VOLTAGE_18. + * @lnb_en_pol: LNB enable pin polarity. 0: pin high to disable, pin low to + * enable. 1: pin high to enable, pin low to disable. + * @get_dvb_frontend: Get DVB frontend. + * @get_i2c_adapter: Get I2C adapter. + */ + +struct m88ds3103_platform_data { + u32 clk; + u16 i2c_wr_max; +#define M88DS3103_TS_SERIAL 0 /* TS output pin D0, normal */ +#define M88DS3103_TS_SERIAL_D7 1 /* TS output pin D7 */ +#define M88DS3103_TS_PARALLEL 2 /* TS Parallel mode */ +#define M88DS3103_TS_CI 3 /* TS CI Mode */ + u8 ts_mode:2; + u32 ts_clk; + u8 ts_clk_pol:1; + u8 spec_inv:1; + u8 agc; + u8 agc_inv:1; +#define M88DS3103_CLOCK_OUT_DISABLED 0 +#define M88DS3103_CLOCK_OUT_ENABLED 1 +#define M88DS3103_CLOCK_OUT_ENABLED_DIV2 2 + u8 clk_out:2; + u8 envelope_mode:1; + u8 lnb_hv_pol:1; + u8 lnb_en_pol:1; + + struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); + struct i2c_adapter* (*get_i2c_adapter)(struct i2c_client *); + +/* private: For legacy media attach wrapper. Do not set value. */ + u8 attach_in_use:1; +}; + +/* + * Do not add new m88ds3103_attach() users! Use I2C bindings instead. + */ struct m88ds3103_config { /* * I2C address @@ -113,18 +170,13 @@ struct m88ds3103_config { u8 lnb_en_pol:1; }; -/* - * Driver implements own I2C-adapter for tuner I2C access. That's since chip - * has I2C-gate control which closes gate automatically after I2C transfer. - * Using own I2C adapter we can workaround that. - */ - #if defined(CONFIG_DVB_M88DS3103) || \ (defined(CONFIG_DVB_M88DS3103_MODULE) && defined(MODULE)) extern struct dvb_frontend *m88ds3103_attach( const struct m88ds3103_config *config, struct i2c_adapter *i2c, struct i2c_adapter **tuner_i2c); +extern int m88ds3103_get_agc_pwm(struct dvb_frontend *fe, u8 *_agc_pwm); #else static inline struct dvb_frontend *m88ds3103_attach( const struct m88ds3103_config *config, @@ -134,6 +186,7 @@ static inline struct dvb_frontend *m88ds3103_attach( pr_warn("%s: driver disabled by Kconfig\n", __func__); return NULL; } +#define m88ds3103_get_agc_pwm NULL #endif #endif diff --git a/drivers/media/dvb-frontends/m88ds3103_priv.h b/drivers/media/dvb-frontends/m88ds3103_priv.h index a2c0958..eee8c22 100644 --- a/drivers/media/dvb-frontends/m88ds3103_priv.h +++ b/drivers/media/dvb-frontends/m88ds3103_priv.h @@ -1,5 +1,5 @@ /* - * Montage M88DS3103 demodulator driver + * Montage Technology M88DS3103/M88RS6000 demodulator driver * * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> * @@ -22,6 +22,7 @@ #include "dvb_math.h" #include <linux/firmware.h> #include <linux/i2c-mux.h> +#include <linux/regmap.h> #include <linux/math64.h> #define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw" @@ -30,21 +31,24 @@ #define M88RS6000_CHIP_ID 0x74 #define M88DS3103_CHIP_ID 0x70 -struct m88ds3103_priv { - struct i2c_adapter *i2c; - /* mutex needed due to own tuner I2C adapter */ - struct mutex i2c_mutex; +struct m88ds3103_dev { + struct i2c_client *client; + struct regmap_config regmap_config; + struct regmap *regmap; + struct m88ds3103_config config; const struct m88ds3103_config *cfg; struct dvb_frontend fe; - fe_delivery_system_t delivery_system; - fe_status_t fe_status; - u32 ber; + enum fe_delivery_system delivery_system; + enum fe_status fe_status; + u32 dvbv3_ber; /* for old DVBv3 API read_ber */ bool warm; /* FW running */ struct i2c_adapter *i2c_adapter; /* auto detect chip id to do different config */ u8 chip_id; /* main mclk is calculated for M88RS6000 dynamically */ u32 mclk_khz; + u64 post_bit_error; + u64 post_bit_count; }; struct m88ds3103_reg_val { diff --git a/drivers/media/dvb-frontends/m88rs2000.c b/drivers/media/dvb-frontends/m88rs2000.c index d63bc9c..9b6f464 100644 --- a/drivers/media/dvb-frontends/m88rs2000.c +++ b/drivers/media/dvb-frontends/m88rs2000.c @@ -41,7 +41,7 @@ struct m88rs2000_state { u8 no_lock_count; u32 tuner_frequency; u32 symbol_rate; - fe_code_rate_t fec_inner; + enum fe_code_rate fec_inner; u8 tuner_level; int errmode; }; @@ -247,7 +247,7 @@ static int m88rs2000_send_diseqc_msg(struct dvb_frontend *fe, } static int m88rs2000_send_diseqc_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t burst) + enum fe_sec_mini_cmd burst) { struct m88rs2000_state *state = fe->demodulator_priv; u8 reg0, reg1; @@ -264,7 +264,8 @@ static int m88rs2000_send_diseqc_burst(struct dvb_frontend *fe, return 0; } -static int m88rs2000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +static int m88rs2000_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct m88rs2000_state *state = fe->demodulator_priv; u8 reg0, reg1; @@ -412,7 +413,8 @@ static int m88rs2000_tab_set(struct m88rs2000_state *state, return 0; } -static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) +static int m88rs2000_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage volt) { struct m88rs2000_state *state = fe->demodulator_priv; u8 data; @@ -462,7 +464,8 @@ static int m88rs2000_sleep(struct dvb_frontend *fe) return ret; } -static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int m88rs2000_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct m88rs2000_state *state = fe->demodulator_priv; u8 reg = m88rs2000_readreg(state, 0x8c); @@ -539,7 +542,7 @@ static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) } static int m88rs2000_set_fec(struct m88rs2000_state *state, - fe_code_rate_t fec) + enum fe_code_rate fec) { u8 fec_set, reg; int ret; @@ -574,7 +577,7 @@ static int m88rs2000_set_fec(struct m88rs2000_state *state, return ret; } -static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state) +static enum fe_code_rate m88rs2000_get_fec(struct m88rs2000_state *state) { u8 reg; m88rs2000_writereg(state, 0x9a, 0x30); @@ -606,7 +609,7 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe) { struct m88rs2000_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - fe_status_t status; + enum fe_status status; int i, ret = 0; u32 tuner_freq; s16 offset = 0; diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c index 3ddea44..79bc671 100644 --- a/drivers/media/dvb-frontends/mb86a16.c +++ b/drivers/media/dvb-frontends/mb86a16.c @@ -593,7 +593,7 @@ err: return -EREMOTEIO; } -static int mb86a16_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int mb86a16_read_status(struct dvb_frontend *fe, enum fe_status *status) { u8 stat, stat2; struct mb86a16_state *state = fe->demodulator_priv; @@ -1562,7 +1562,8 @@ err: return -EREMOTEIO; } -static int mb86a16_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst) +static int mb86a16_send_diseqc_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd burst) { struct mb86a16_state *state = fe->demodulator_priv; @@ -1590,7 +1591,7 @@ err: return -EREMOTEIO; } -static int mb86a16_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +static int mb86a16_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) { struct mb86a16_state *state = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/mb86a16.h b/drivers/media/dvb-frontends/mb86a16.h index e486dc0..dbd5f43 100644 --- a/drivers/media/dvb-frontends/mb86a16.h +++ b/drivers/media/dvb-frontends/mb86a16.h @@ -28,7 +28,8 @@ struct mb86a16_config { u8 demod_address; - int (*set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage); + int (*set_voltage)(struct dvb_frontend *fe, + enum fe_sec_voltage voltage); }; diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 8f54c39..cfc005e 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -294,7 +294,7 @@ static int mb86a20s_i2c_readreg(struct mb86a20s_state *state, * The functions below assume that gateway lock has already obtained */ -static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int mb86a20s_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct mb86a20s_state *state = fe->demodulator_priv; int val; @@ -1951,7 +1951,7 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe) } static int mb86a20s_read_status_and_stats(struct dvb_frontend *fe, - fe_status_t *status) + enum fe_status *status) { struct mb86a20s_state *state = fe->demodulator_priv; int rc, status_nr; @@ -2042,7 +2042,7 @@ static int mb86a20s_tune(struct dvb_frontend *fe, bool re_tune, unsigned int mode_flags, unsigned int *delay, - fe_status_t *status) + enum fe_status *status) { struct mb86a20s_state *state = fe->demodulator_priv; int rc = 0; diff --git a/drivers/media/dvb-frontends/mb86a20s.h b/drivers/media/dvb-frontends/mb86a20s.h index f749c8a..a113282 100644 --- a/drivers/media/dvb-frontends/mb86a20s.h +++ b/drivers/media/dvb-frontends/mb86a20s.h @@ -45,7 +45,7 @@ static inline struct dvb_frontend *mb86a20s_attach( printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -static struct i2c_adapter * +static inline struct i2c_adapter * mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *fe) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c index 2163490..c36e676 100644 --- a/drivers/media/dvb-frontends/mt312.c +++ b/drivers/media/dvb-frontends/mt312.c @@ -156,7 +156,7 @@ static int mt312_reset(struct mt312_state *state, const u8 full) } static int mt312_get_inversion(struct mt312_state *state, - fe_spectral_inversion_t *i) + enum fe_spectral_inversion *i) { int ret; u8 vit_mode; @@ -225,9 +225,9 @@ static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr) return 0; } -static int mt312_get_code_rate(struct mt312_state *state, fe_code_rate_t *cr) +static int mt312_get_code_rate(struct mt312_state *state, enum fe_code_rate *cr) { - const fe_code_rate_t fec_tab[8] = + const enum fe_code_rate fec_tab[8] = { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8, FEC_AUTO, FEC_AUTO }; @@ -380,7 +380,8 @@ static int mt312_send_master_cmd(struct dvb_frontend *fe, return 0; } -static int mt312_send_burst(struct dvb_frontend *fe, const fe_sec_mini_cmd_t c) +static int mt312_send_burst(struct dvb_frontend *fe, + const enum fe_sec_mini_cmd c) { struct mt312_state *state = fe->demodulator_priv; const u8 mini_tab[2] = { 0x02, 0x03 }; @@ -403,7 +404,8 @@ static int mt312_send_burst(struct dvb_frontend *fe, const fe_sec_mini_cmd_t c) return 0; } -static int mt312_set_tone(struct dvb_frontend *fe, const fe_sec_tone_mode_t t) +static int mt312_set_tone(struct dvb_frontend *fe, + const enum fe_sec_tone_mode t) { struct mt312_state *state = fe->demodulator_priv; const u8 tone_tab[2] = { 0x01, 0x00 }; @@ -426,7 +428,8 @@ static int mt312_set_tone(struct dvb_frontend *fe, const fe_sec_tone_mode_t t) return 0; } -static int mt312_set_voltage(struct dvb_frontend *fe, const fe_sec_voltage_t v) +static int mt312_set_voltage(struct dvb_frontend *fe, + const enum fe_sec_voltage v) { struct mt312_state *state = fe->demodulator_priv; const u8 volt_tab[3] = { 0x00, 0x40, 0x00 }; @@ -442,7 +445,7 @@ static int mt312_set_voltage(struct dvb_frontend *fe, const fe_sec_voltage_t v) return mt312_writereg(state, DISEQC_MODE, val); } -static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s) +static int mt312_read_status(struct dvb_frontend *fe, enum fe_status *s) { struct mt312_state *state = fe->demodulator_priv; int ret; diff --git a/drivers/media/dvb-frontends/mt352.c b/drivers/media/dvb-frontends/mt352.c index 2c3b50e..123bb2f 100644 --- a/drivers/media/dvb-frontends/mt352.c +++ b/drivers/media/dvb-frontends/mt352.c @@ -417,7 +417,7 @@ static int mt352_get_parameters(struct dvb_frontend* fe) return 0; } -static int mt352_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int mt352_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct mt352_state* state = fe->demodulator_priv; int s0, s1, s3; diff --git a/drivers/media/dvb-frontends/nxt200x.c b/drivers/media/dvb-frontends/nxt200x.c index 8a8e1ec..79c3040 100644 --- a/drivers/media/dvb-frontends/nxt200x.c +++ b/drivers/media/dvb-frontends/nxt200x.c @@ -781,7 +781,7 @@ static int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe) return 0; } -static int nxt200x_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int nxt200x_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct nxt200x_state* state = fe->demodulator_priv; u8 lock; diff --git a/drivers/media/dvb-frontends/nxt6000.c b/drivers/media/dvb-frontends/nxt6000.c index 90ae6c7..73f9505 100644 --- a/drivers/media/dvb-frontends/nxt6000.c +++ b/drivers/media/dvb-frontends/nxt6000.c @@ -109,7 +109,8 @@ static int nxt6000_set_bandwidth(struct nxt6000_state *state, u32 bandwidth) return nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, (nominal_rate >> 8) & 0xFF); } -static int nxt6000_set_guard_interval(struct nxt6000_state* state, fe_guard_interval_t guard_interval) +static int nxt6000_set_guard_interval(struct nxt6000_state *state, + enum fe_guard_interval guard_interval) { switch (guard_interval) { @@ -131,7 +132,8 @@ static int nxt6000_set_guard_interval(struct nxt6000_state* state, fe_guard_inte } } -static int nxt6000_set_inversion(struct nxt6000_state* state, fe_spectral_inversion_t inversion) +static int nxt6000_set_inversion(struct nxt6000_state *state, + enum fe_spectral_inversion inversion) { switch (inversion) { @@ -147,7 +149,9 @@ static int nxt6000_set_inversion(struct nxt6000_state* state, fe_spectral_invers } } -static int nxt6000_set_transmission_mode(struct nxt6000_state* state, fe_transmit_mode_t transmission_mode) +static int +nxt6000_set_transmission_mode(struct nxt6000_state *state, + enum fe_transmit_mode transmission_mode) { int result; @@ -416,7 +420,7 @@ static void nxt6000_dump_status(struct nxt6000_state *state) printk("\n"); } -static int nxt6000_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int nxt6000_read_status(struct dvb_frontend *fe, enum fe_status *status) { u8 core_status; struct nxt6000_state* state = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/or51132.c b/drivers/media/dvb-frontends/or51132.c index cbbd259..35b1053 100644 --- a/drivers/media/dvb-frontends/or51132.c +++ b/drivers/media/dvb-frontends/or51132.c @@ -63,7 +63,7 @@ struct or51132_state struct dvb_frontend frontend; /* Demodulator private data */ - fe_modulation_t current_modulation; + enum fe_modulation current_modulation; u32 snr; /* Result of last SNR calculation */ /* Tuner private data */ @@ -292,7 +292,7 @@ static int or51132_setmode(struct dvb_frontend* fe) #define MOD_FWCLASS_UNKNOWN 0 #define MOD_FWCLASS_VSB 1 #define MOD_FWCLASS_QAM 2 -static int modulation_fw_class(fe_modulation_t modulation) +static int modulation_fw_class(enum fe_modulation modulation) { switch(modulation) { case VSB_8: @@ -415,7 +415,7 @@ start: return 0; } -static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int or51132_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct or51132_state* state = fe->demodulator_priv; int reg; diff --git a/drivers/media/dvb-frontends/or51211.c b/drivers/media/dvb-frontends/or51211.c index 873ea1d..e82413b 100644 --- a/drivers/media/dvb-frontends/or51211.c +++ b/drivers/media/dvb-frontends/or51211.c @@ -237,7 +237,7 @@ static int or51211_set_parameters(struct dvb_frontend *fe) return 0; } -static int or51211_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int or51211_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct or51211_state* state = fe->demodulator_priv; unsigned char rec_buf[2]; diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c index e1b8df6..3d01f4f 100644 --- a/drivers/media/dvb-frontends/rtl2830.c +++ b/drivers/media/dvb-frontends/rtl2830.c @@ -392,7 +392,7 @@ err: return ret; } -static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int rtl2830_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct i2c_client *client = fe->demodulator_priv; struct rtl2830_dev *dev = i2c_get_clientdata(client); diff --git a/drivers/media/dvb-frontends/rtl2830_priv.h b/drivers/media/dvb-frontends/rtl2830_priv.h index d50d537..cf793f3 100644 --- a/drivers/media/dvb-frontends/rtl2830_priv.h +++ b/drivers/media/dvb-frontends/rtl2830_priv.h @@ -34,7 +34,7 @@ struct rtl2830_dev { bool sleeping; unsigned long filters; struct delayed_work stat_work; - fe_status_t fe_status; + enum fe_status fe_status; u64 post_bit_error_prev; /* for old DVBv3 read_ber() calculation */ u64 post_bit_error; u64 post_bit_count; diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index b400f7b..822ea4b 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -358,6 +358,10 @@ static int rtl2832_init(struct dvb_frontend *fe) dev_dbg(&client->dev, "load settings for tuner=%02x\n", dev->pdata->tuner); switch (dev->pdata->tuner) { + case RTL2832_TUNER_FC2580: + len = ARRAY_SIZE(rtl2832_tuner_init_fc2580); + init = rtl2832_tuner_init_fc2580; + break; case RTL2832_TUNER_FC0012: case RTL2832_TUNER_FC0013: len = ARRAY_SIZE(rtl2832_tuner_init_fc0012); @@ -376,6 +380,10 @@ static int rtl2832_init(struct dvb_frontend *fe) len = ARRAY_SIZE(rtl2832_tuner_init_r820t); init = rtl2832_tuner_init_r820t; break; + case RTL2832_TUNER_SI2157: + len = ARRAY_SIZE(rtl2832_tuner_init_si2157); + init = rtl2832_tuner_init_si2157; + break; default: ret = -EINVAL; goto err; @@ -680,7 +688,7 @@ err: return ret; } -static int rtl2832_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int rtl2832_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct rtl2832_dev *dev = fe->demodulator_priv; struct i2c_client *client = dev->client; diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h index a8e912e..c29a4c2 100644 --- a/drivers/media/dvb-frontends/rtl2832.h +++ b/drivers/media/dvb-frontends/rtl2832.h @@ -41,12 +41,14 @@ struct rtl2832_platform_data { /* * XXX: This list must be kept sync with dvb_usb_rtl28xxu USB IF driver. */ +#define RTL2832_TUNER_FC2580 0x21 #define RTL2832_TUNER_TUA9001 0x24 #define RTL2832_TUNER_FC0012 0x26 #define RTL2832_TUNER_E4000 0x27 #define RTL2832_TUNER_FC0013 0x29 #define RTL2832_TUNER_R820T 0x2a #define RTL2832_TUNER_R828D 0x2b +#define RTL2832_TUNER_SI2157 0x2c u8 tuner; struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h index c3a922c..5dcd3a4 100644 --- a/drivers/media/dvb-frontends/rtl2832_priv.h +++ b/drivers/media/dvb-frontends/rtl2832_priv.h @@ -39,7 +39,7 @@ struct rtl2832_dev { struct i2c_adapter *i2c_adapter_tuner; struct dvb_frontend fe; struct delayed_work stat_work; - fe_status_t fe_status; + enum fe_status fe_status; u64 post_bit_error_prev; /* for old DVBv3 read_ber() calculation */ u64 post_bit_error; u64 post_bit_count; @@ -252,6 +252,30 @@ enum DVBT_REG_BIT_NAME { DVBT_REG_BIT_NAME_ITEM_TERMINATOR, }; +static const struct rtl2832_reg_value rtl2832_tuner_init_fc2580[] = { + {DVBT_DAGC_TRG_VAL, 0x39}, + {DVBT_AGC_TARG_VAL_0, 0x0}, + {DVBT_AGC_TARG_VAL_8_1, 0x5a}, + {DVBT_AAGC_LOOP_GAIN, 0x16}, + {DVBT_LOOP_GAIN2_3_0, 0x6}, + {DVBT_LOOP_GAIN2_4, 0x1}, + {DVBT_LOOP_GAIN3, 0x16}, + {DVBT_VTOP1, 0x35}, + {DVBT_VTOP2, 0x21}, + {DVBT_VTOP3, 0x21}, + {DVBT_KRF1, 0x0}, + {DVBT_KRF2, 0x40}, + {DVBT_KRF3, 0x10}, + {DVBT_KRF4, 0x10}, + {DVBT_IF_AGC_MIN, 0x80}, + {DVBT_IF_AGC_MAX, 0x7f}, + {DVBT_RF_AGC_MIN, 0x9c}, + {DVBT_RF_AGC_MAX, 0x7f}, + {DVBT_POLAR_RF_AGC, 0x0}, + {DVBT_POLAR_IF_AGC, 0x0}, + {DVBT_AD7_SETTING, 0xe9f4}, +}; + static const struct rtl2832_reg_value rtl2832_tuner_init_tua9001[] = { {DVBT_DAGC_TRG_VAL, 0x39}, {DVBT_AGC_TARG_VAL_0, 0x0}, @@ -377,4 +401,29 @@ static const struct rtl2832_reg_value rtl2832_tuner_init_r820t[] = { {DVBT_SPEC_INV, 0x1}, }; +static const struct rtl2832_reg_value rtl2832_tuner_init_si2157[] = { + {DVBT_DAGC_TRG_VAL, 0x39}, + {DVBT_AGC_TARG_VAL_0, 0x0}, + {DVBT_AGC_TARG_VAL_8_1, 0x40}, + {DVBT_AAGC_LOOP_GAIN, 0x16}, + {DVBT_LOOP_GAIN2_3_0, 0x8}, + {DVBT_LOOP_GAIN2_4, 0x1}, + {DVBT_LOOP_GAIN3, 0x18}, + {DVBT_VTOP1, 0x35}, + {DVBT_VTOP2, 0x21}, + {DVBT_VTOP3, 0x21}, + {DVBT_KRF1, 0x0}, + {DVBT_KRF2, 0x40}, + {DVBT_KRF3, 0x10}, + {DVBT_KRF4, 0x10}, + {DVBT_IF_AGC_MIN, 0x80}, + {DVBT_IF_AGC_MAX, 0x7f}, + {DVBT_RF_AGC_MIN, 0x80}, + {DVBT_RF_AGC_MAX, 0x7f}, + {DVBT_POLAR_RF_AGC, 0x0}, + {DVBT_POLAR_IF_AGC, 0x0}, + {DVBT_AD7_SETTING, 0xe9f4}, + {DVBT_SPEC_INV, 0x0}, +}; + #endif /* RTL2832_PRIV_H */ diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index 3ff8806..7edb885 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -39,6 +39,10 @@ static bool rtl2832_sdr_emulated_fmt; module_param_named(emulated_formats, rtl2832_sdr_emulated_fmt, bool, 0644); MODULE_PARM_DESC(emulated_formats, "enable emulated formats (disappears in future)"); +/* Original macro does not contain enough null pointer checks for our need */ +#define V4L2_SUBDEV_HAS_OP(sd, o, f) \ + ((sd) && (sd)->ops && (sd)->ops->o && (sd)->ops->o->f) + #define MAX_BULK_BUFS (10) #define BULK_BUFFER_SIZE (128 * 512) @@ -108,14 +112,15 @@ struct rtl2832_sdr_frame_buf { }; struct rtl2832_sdr_dev { -#define POWER_ON (1 << 1) -#define URB_BUF (1 << 2) +#define POWER_ON 0 /* BIT(0) */ +#define URB_BUF 1 /* BIT(1) */ unsigned long flags; struct platform_device *pdev; struct video_device vdev; struct v4l2_device v4l2_dev; + struct v4l2_subdev *v4l2_subdev; /* videobuf2 queue and queued buffers list */ struct vb2_queue vb_queue; @@ -351,7 +356,7 @@ static int rtl2832_sdr_free_stream_bufs(struct rtl2832_sdr_dev *dev) { struct platform_device *pdev = dev->pdev; - if (dev->flags & USB_STATE_URB_BUF) { + if (test_bit(URB_BUF, &dev->flags)) { while (dev->buf_num) { dev->buf_num--; dev_dbg(&pdev->dev, "free buf=%d\n", dev->buf_num); @@ -360,7 +365,7 @@ static int rtl2832_sdr_free_stream_bufs(struct rtl2832_sdr_dev *dev) dev->dma_addr[dev->buf_num]); } } - dev->flags &= ~USB_STATE_URB_BUF; + clear_bit(URB_BUF, &dev->flags); return 0; } @@ -389,7 +394,7 @@ static int rtl2832_sdr_alloc_stream_bufs(struct rtl2832_sdr_dev *dev) dev_dbg(&pdev->dev, "alloc buf=%d %p (dma %llu)\n", dev->buf_num, dev->buf_list[dev->buf_num], (long long)dev->dma_addr[dev->buf_num]); - dev->flags |= USB_STATE_URB_BUF; + set_bit(URB_BUF, &dev->flags); } return 0; @@ -742,6 +747,29 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_dev *dev) ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1); ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xf4", 1); break; + case RTL2832_SDR_TUNER_FC2580: + ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x39", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x103, "\x5a", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1c7, "\x2c", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x104, "\xcc", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x105, "\xbe", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1c8, "\x16", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x106, "\x35", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1c9, "\x21", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1ca, "\x21", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1cb, "\x00", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x107, "\x40", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1cd, "\x10", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1ce, "\x10", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x108, "\x80", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x109, "\x7f", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x10a, "\x9c", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x10b, "\x7f", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xe9\xf4", 2); + break; default: dev_notice(&pdev->dev, "Unsupported tuner\n"); } @@ -832,8 +860,10 @@ static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_dev *dev) if (!test_bit(POWER_ON, &dev->flags)) return 0; - if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe); + if (!V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, tuner, s_frequency)) { + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe); + } return 0; }; @@ -891,7 +921,11 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count) set_bit(POWER_ON, &dev->flags); - ret = rtl2832_sdr_set_tuner(dev); + /* wake-up tuner */ + if (V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, core, s_power)) + ret = v4l2_subdev_call(dev->v4l2_subdev, core, s_power, 1); + else + ret = rtl2832_sdr_set_tuner(dev); if (ret) goto err; @@ -939,7 +973,12 @@ static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq) rtl2832_sdr_free_stream_bufs(dev); rtl2832_sdr_cleanup_queued_bufs(dev); rtl2832_sdr_unset_adc(dev); - rtl2832_sdr_unset_tuner(dev); + + /* sleep tuner */ + if (V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, core, s_power)) + v4l2_subdev_call(dev->v4l2_subdev, core, s_power, 0); + else + rtl2832_sdr_unset_tuner(dev); clear_bit(POWER_ON, &dev->flags); @@ -968,6 +1007,7 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv, { struct rtl2832_sdr_dev *dev = video_drvdata(file); struct platform_device *pdev = dev->pdev; + int ret; dev_dbg(&pdev->dev, "index=%d type=%d\n", v->index, v->type); @@ -977,17 +1017,21 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv, v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; v->rangelow = 300000; v->rangehigh = 3200000; + ret = 0; + } else if (v->index == 1 && + V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, tuner, g_tuner)) { + ret = v4l2_subdev_call(dev->v4l2_subdev, tuner, g_tuner, v); } else if (v->index == 1) { strlcpy(v->name, "RF: <unknown>", sizeof(v->name)); v->type = V4L2_TUNER_RF; v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; v->rangelow = 50000000; v->rangehigh = 2000000000; + ret = 0; } else { - return -EINVAL; + ret = -EINVAL; } - - return 0; + return ret; } static int rtl2832_sdr_s_tuner(struct file *file, void *priv, @@ -995,12 +1039,21 @@ static int rtl2832_sdr_s_tuner(struct file *file, void *priv, { struct rtl2832_sdr_dev *dev = video_drvdata(file); struct platform_device *pdev = dev->pdev; + int ret; dev_dbg(&pdev->dev, "\n"); - if (v->index > 1) - return -EINVAL; - return 0; + if (v->index == 0) { + ret = 0; + } else if (v->index == 1 && + V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, tuner, s_tuner)) { + ret = v4l2_subdev_call(dev->v4l2_subdev, tuner, s_tuner, v); + } else if (v->index == 1) { + ret = 0; + } else { + ret = -EINVAL; + } + return ret; } static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv, @@ -1008,6 +1061,7 @@ static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv, { struct rtl2832_sdr_dev *dev = video_drvdata(file); struct platform_device *pdev = dev->pdev; + int ret; dev_dbg(&pdev->dev, "tuner=%d type=%d index=%d\n", band->tuner, band->type, band->index); @@ -1017,16 +1071,20 @@ static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv, return -EINVAL; *band = bands_adc[band->index]; + ret = 0; + } else if (band->tuner == 1 && + V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, tuner, enum_freq_bands)) { + ret = v4l2_subdev_call(dev->v4l2_subdev, tuner, enum_freq_bands, band); } else if (band->tuner == 1) { if (band->index >= ARRAY_SIZE(bands_fm)) return -EINVAL; *band = bands_fm[band->index]; + ret = 0; } else { - return -EINVAL; + ret = -EINVAL; } - - return 0; + return ret; } static int rtl2832_sdr_g_frequency(struct file *file, void *priv, @@ -1034,20 +1092,25 @@ static int rtl2832_sdr_g_frequency(struct file *file, void *priv, { struct rtl2832_sdr_dev *dev = video_drvdata(file); struct platform_device *pdev = dev->pdev; - int ret = 0; + int ret; dev_dbg(&pdev->dev, "tuner=%d type=%d\n", f->tuner, f->type); if (f->tuner == 0) { f->frequency = dev->f_adc; f->type = V4L2_TUNER_ADC; + ret = 0; + } else if (f->tuner == 1 && + V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, tuner, g_frequency)) { + f->type = V4L2_TUNER_RF; + ret = v4l2_subdev_call(dev->v4l2_subdev, tuner, g_frequency, f); } else if (f->tuner == 1) { f->frequency = dev->f_tuner; f->type = V4L2_TUNER_RF; + ret = 0; } else { - return -EINVAL; + ret = -EINVAL; } - return ret; } @@ -1074,11 +1137,14 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv, band = 2; dev->f_adc = clamp_t(unsigned int, f->frequency, - bands_adc[band].rangelow, - bands_adc[band].rangehigh); + bands_adc[band].rangelow, + bands_adc[band].rangehigh); dev_dbg(&pdev->dev, "ADC frequency=%u Hz\n", dev->f_adc); ret = rtl2832_sdr_set_adc(dev); + } else if (f->tuner == 1 && + V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, tuner, s_frequency)) { + ret = v4l2_subdev_call(dev->v4l2_subdev, tuner, s_frequency, f); } else if (f->tuner == 1) { dev->f_tuner = clamp_t(unsigned int, f->frequency, bands_fm[0].rangelow, @@ -1089,7 +1155,6 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv, } else { ret = -EINVAL; } - return ret; } @@ -1329,6 +1394,7 @@ static int rtl2832_sdr_probe(struct platform_device *pdev) /* setup the state */ subdev = pdata->v4l2_subdev; + dev->v4l2_subdev = pdata->v4l2_subdev; dev->pdev = pdev; dev->udev = pdata->dvb_usb_device->udev; dev->f_adc = bands_adc[0].rangelow; @@ -1388,6 +1454,12 @@ static int rtl2832_sdr_probe(struct platform_device *pdev) 6000000); v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false); break; + case RTL2832_SDR_TUNER_FC2580: + v4l2_ctrl_handler_init(&dev->hdl, 2); + if (subdev) + v4l2_ctrl_add_handler(&dev->hdl, subdev->ctrl_handler, + NULL); + break; default: v4l2_ctrl_handler_init(&dev->hdl, 0); dev_err(&pdev->dev, "Unsupported tuner\n"); diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.h b/drivers/media/dvb-frontends/rtl2832_sdr.h index d259476..342ea84 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.h +++ b/drivers/media/dvb-frontends/rtl2832_sdr.h @@ -47,6 +47,7 @@ struct rtl2832_sdr_platform_data { /* * XXX: This list must be kept sync with dvb_usb_rtl28xxu USB IF driver. */ +#define RTL2832_SDR_TUNER_FC2580 0x21 #define RTL2832_SDR_TUNER_TUA9001 0x24 #define RTL2832_SDR_TUNER_FC0012 0x26 #define RTL2832_SDR_TUNER_E4000 0x27 diff --git a/drivers/media/dvb-frontends/s5h1409.c b/drivers/media/dvb-frontends/s5h1409.c index 5ff474a..1096484 100644 --- a/drivers/media/dvb-frontends/s5h1409.c +++ b/drivers/media/dvb-frontends/s5h1409.c @@ -38,7 +38,7 @@ struct s5h1409_state { struct dvb_frontend frontend; /* previous uncorrected block counter */ - fe_modulation_t current_modulation; + enum fe_modulation current_modulation; u32 current_frequency; int if_freq; @@ -400,7 +400,7 @@ static int s5h1409_set_spectralinversion(struct dvb_frontend *fe, int inverted) } static int s5h1409_enable_modulation(struct dvb_frontend *fe, - fe_modulation_t m) + enum fe_modulation m) { struct s5h1409_state *state = fe->demodulator_priv; @@ -755,7 +755,7 @@ static int s5h1409_init(struct dvb_frontend *fe) return 0; } -static int s5h1409_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int s5h1409_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct s5h1409_state *state = fe->demodulator_priv; u16 reg; diff --git a/drivers/media/dvb-frontends/s5h1411.c b/drivers/media/dvb-frontends/s5h1411.c index 64f35fe..9afc3f4 100644 --- a/drivers/media/dvb-frontends/s5h1411.c +++ b/drivers/media/dvb-frontends/s5h1411.c @@ -37,7 +37,7 @@ struct s5h1411_state { struct dvb_frontend frontend; - fe_modulation_t current_modulation; + enum fe_modulation current_modulation; unsigned int first_tune:1; u32 current_frequency; @@ -484,7 +484,7 @@ static int s5h1411_set_serialmode(struct dvb_frontend *fe, int serial) } static int s5h1411_enable_modulation(struct dvb_frontend *fe, - fe_modulation_t m) + enum fe_modulation m) { struct s5h1411_state *state = fe->demodulator_priv; @@ -659,7 +659,7 @@ static int s5h1411_init(struct dvb_frontend *fe) return 0; } -static int s5h1411_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int s5h1411_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct s5h1411_state *state = fe->demodulator_priv; u16 reg; diff --git a/drivers/media/dvb-frontends/s5h1420.c b/drivers/media/dvb-frontends/s5h1420.c index 93eeaf7..9c22a4c 100644 --- a/drivers/media/dvb-frontends/s5h1420.c +++ b/drivers/media/dvb-frontends/s5h1420.c @@ -52,7 +52,7 @@ struct s5h1420_state { u8 postlocked:1; u32 fclk; u32 tunedfreq; - fe_code_rate_t fec_inner; + enum fe_code_rate fec_inner; u32 symbol_rate; /* FIXME: ugly workaround for flexcop's incapable i2c-controller @@ -124,7 +124,8 @@ static int s5h1420_writereg (struct s5h1420_state* state, u8 reg, u8 data) return 0; } -static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int s5h1420_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct s5h1420_state* state = fe->demodulator_priv; @@ -149,7 +150,8 @@ static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag return 0; } -static int s5h1420_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int s5h1420_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct s5h1420_state* state = fe->demodulator_priv; @@ -180,7 +182,7 @@ static int s5h1420_send_master_cmd (struct dvb_frontend* fe, int result = 0; dprintk("enter %s\n", __func__); - if (cmd->msg_len > 8) + if (cmd->msg_len > sizeof(cmd->msg)) return -EINVAL; /* setup for DISEQC */ @@ -270,7 +272,8 @@ exit: return result; } -static int s5h1420_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +static int s5h1420_send_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd minicmd) { struct s5h1420_state* state = fe->demodulator_priv; u8 val; @@ -307,10 +310,10 @@ static int s5h1420_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicm return result; } -static fe_status_t s5h1420_get_status_bits(struct s5h1420_state* state) +static enum fe_status s5h1420_get_status_bits(struct s5h1420_state *state) { u8 val; - fe_status_t status = 0; + enum fe_status status = 0; val = s5h1420_readreg(state, 0x14); if (val & 0x02) @@ -328,7 +331,8 @@ static fe_status_t s5h1420_get_status_bits(struct s5h1420_state* state) return status; } -static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int s5h1420_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct s5h1420_state* state = fe->demodulator_priv; u8 val; @@ -561,27 +565,33 @@ static void s5h1420_setfec_inversion(struct s5h1420_state* state, } else { switch (p->fec_inner) { case FEC_1_2: - vit08 = 0x01; vit09 = 0x10; + vit08 = 0x01; + vit09 = 0x10; break; case FEC_2_3: - vit08 = 0x02; vit09 = 0x11; + vit08 = 0x02; + vit09 = 0x11; break; case FEC_3_4: - vit08 = 0x04; vit09 = 0x12; + vit08 = 0x04; + vit09 = 0x12; break; case FEC_5_6: - vit08 = 0x08; vit09 = 0x13; + vit08 = 0x08; + vit09 = 0x13; break; case FEC_6_7: - vit08 = 0x10; vit09 = 0x14; + vit08 = 0x10; + vit09 = 0x14; break; case FEC_7_8: - vit08 = 0x20; vit09 = 0x15; + vit08 = 0x20; + vit09 = 0x15; break; default: @@ -595,7 +605,7 @@ static void s5h1420_setfec_inversion(struct s5h1420_state* state, dprintk("leave %s\n", __func__); } -static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state) +static enum fe_code_rate s5h1420_getfec(struct s5h1420_state *state) { switch(s5h1420_readreg(state, 0x32) & 0x07) { case 0: @@ -620,7 +630,8 @@ static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state) return FEC_NONE; } -static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state) +static enum fe_spectral_inversion +s5h1420_getinversion(struct s5h1420_state *state) { if (s5h1420_readreg(state, 0x32) & 0x08) return INVERSION_ON; diff --git a/drivers/media/dvb-frontends/s5h1432.c b/drivers/media/dvb-frontends/s5h1432.c index 6ec16a2..4215652 100644 --- a/drivers/media/dvb-frontends/s5h1432.c +++ b/drivers/media/dvb-frontends/s5h1432.c @@ -36,7 +36,7 @@ struct s5h1432_state { struct dvb_frontend frontend; - fe_modulation_t current_modulation; + enum fe_modulation current_modulation; unsigned int first_tune:1; u32 current_frequency; @@ -302,7 +302,7 @@ static int s5h1432_init(struct dvb_frontend *fe) return 0; } -static int s5h1432_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int s5h1432_read_status(struct dvb_frontend *fe, enum fe_status *status) { return 0; } diff --git a/drivers/media/dvb-frontends/s921.c b/drivers/media/dvb-frontends/s921.c index 69862e1..b2d9fe1 100644 --- a/drivers/media/dvb-frontends/s921.c +++ b/drivers/media/dvb-frontends/s921.c @@ -348,7 +348,7 @@ static int s921_initfe(struct dvb_frontend *fe) return 0; } -static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int s921_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct s921_state *state = fe->demodulator_priv; int regstatus, rc; @@ -389,7 +389,7 @@ static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status) static int s921_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { - fe_status_t status; + enum fe_status status; struct s921_state *state = fe->demodulator_priv; int rc; @@ -449,7 +449,7 @@ static int s921_tune(struct dvb_frontend *fe, bool re_tune, unsigned int mode_flags, unsigned int *delay, - fe_status_t *status) + enum fe_status *status) { int rc = 0; diff --git a/drivers/media/dvb-frontends/s921.h b/drivers/media/dvb-frontends/s921.h index 7d3999a..f5b722d 100644 --- a/drivers/media/dvb-frontends/s921.h +++ b/drivers/media/dvb-frontends/s921.h @@ -36,7 +36,7 @@ static inline struct dvb_frontend *s921_attach( printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -static struct i2c_adapter * +static inline struct i2c_adapter * s921_get_tuner_i2c_adapter(struct dvb_frontend *fe) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c index 4cc5d10..7c2eeee 100644 --- a/drivers/media/dvb-frontends/si2165.c +++ b/drivers/media/dvb-frontends/si2165.c @@ -698,7 +698,7 @@ static int si2165_sleep(struct dvb_frontend *fe) return 0; } -static int si2165_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int si2165_read_status(struct dvb_frontend *fe, enum fe_status *status) { int ret; u8 fec_lock = 0; diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 5db588e..25e238c 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -18,23 +18,53 @@ static const struct dvb_frontend_ops si2168_ops; +/* Own I2C adapter locking is needed because of I2C gate logic. */ +static int si2168_i2c_master_send_unlocked(const struct i2c_client *client, + const char *buf, int count) +{ + int ret; + struct i2c_msg msg = { + .addr = client->addr, + .flags = 0, + .len = count, + .buf = (char *)buf, + }; + + ret = __i2c_transfer(client->adapter, &msg, 1); + return (ret == 1) ? count : ret; +} + +static int si2168_i2c_master_recv_unlocked(const struct i2c_client *client, + char *buf, int count) +{ + int ret; + struct i2c_msg msg = { + .addr = client->addr, + .flags = I2C_M_RD, + .len = count, + .buf = buf, + }; + + ret = __i2c_transfer(client->adapter, &msg, 1); + return (ret == 1) ? count : ret; +} + /* execute firmware command */ -static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) +static int si2168_cmd_execute_unlocked(struct i2c_client *client, + struct si2168_cmd *cmd) { - struct si2168_dev *dev = i2c_get_clientdata(client); int ret; unsigned long timeout; - mutex_lock(&dev->i2c_mutex); - if (cmd->wlen) { /* write cmd and args for firmware */ - ret = i2c_master_send(client, cmd->args, cmd->wlen); + ret = si2168_i2c_master_send_unlocked(client, cmd->args, + cmd->wlen); if (ret < 0) { - goto err_mutex_unlock; + goto err; } else if (ret != cmd->wlen) { ret = -EREMOTEIO; - goto err_mutex_unlock; + goto err; } } @@ -43,12 +73,13 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) #define TIMEOUT 70 timeout = jiffies + msecs_to_jiffies(TIMEOUT); while (!time_after(jiffies, timeout)) { - ret = i2c_master_recv(client, cmd->args, cmd->rlen); + ret = si2168_i2c_master_recv_unlocked(client, cmd->args, + cmd->rlen); if (ret < 0) { - goto err_mutex_unlock; + goto err; } else if (ret != cmd->rlen) { ret = -EREMOTEIO; - goto err_mutex_unlock; + goto err; } /* firmware ready? */ @@ -60,22 +91,36 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) jiffies_to_msecs(jiffies) - (jiffies_to_msecs(timeout) - TIMEOUT)); + /* error bit set? */ + if ((cmd->args[0] >> 6) & 0x01) { + ret = -EREMOTEIO; + goto err; + } + if (!((cmd->args[0] >> 7) & 0x01)) { ret = -ETIMEDOUT; - goto err_mutex_unlock; + goto err; } } - mutex_unlock(&dev->i2c_mutex); return 0; - -err_mutex_unlock: - mutex_unlock(&dev->i2c_mutex); +err: dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } -static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) +{ + int ret; + + i2c_lock_adapter(client->adapter); + ret = si2168_cmd_execute_unlocked(client, cmd); + i2c_unlock_adapter(client->adapter); + + return ret; +} + +static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct i2c_client *client = fe->demodulator_priv; struct si2168_dev *dev = i2c_get_clientdata(client); @@ -508,6 +553,8 @@ static int si2168_init(struct dvb_frontend *fe) /* set ts mode */ memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); cmd.args[4] |= dev->ts_mode; + if (dev->ts_clock_gapped) + cmd.args[4] |= 0x40; cmd.wlen = 6; cmd.rlen = 4; ret = si2168_cmd_execute(client, &cmd); @@ -561,60 +608,46 @@ static int si2168_get_tune_settings(struct dvb_frontend *fe, /* * I2C gate logic - * We must use unlocked i2c_transfer() here because I2C lock is already taken - * by tuner driver. + * We must use unlocked I2C I/O because I2C adapter lock is already taken + * by the caller (usually tuner driver). */ static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan) { struct i2c_client *client = mux_priv; - struct si2168_dev *dev = i2c_get_clientdata(client); int ret; - struct i2c_msg gate_open_msg = { - .addr = client->addr, - .flags = 0, - .len = 3, - .buf = "\xc0\x0d\x01", - }; - - mutex_lock(&dev->i2c_mutex); + struct si2168_cmd cmd; - /* open tuner I2C gate */ - ret = __i2c_transfer(client->adapter, &gate_open_msg, 1); - if (ret != 1) { - dev_warn(&client->dev, "i2c write failed=%d\n", ret); - if (ret >= 0) - ret = -EREMOTEIO; - } else { - ret = 0; - } + /* open I2C gate */ + memcpy(cmd.args, "\xc0\x0d\x01", 3); + cmd.wlen = 3; + cmd.rlen = 0; + ret = si2168_cmd_execute_unlocked(client, &cmd); + if (ret) + goto err; + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan) { struct i2c_client *client = mux_priv; - struct si2168_dev *dev = i2c_get_clientdata(client); int ret; - struct i2c_msg gate_close_msg = { - .addr = client->addr, - .flags = 0, - .len = 3, - .buf = "\xc0\x0d\x00", - }; - - /* close tuner I2C gate */ - ret = __i2c_transfer(client->adapter, &gate_close_msg, 1); - if (ret != 1) { - dev_warn(&client->dev, "i2c write failed=%d\n", ret); - if (ret >= 0) - ret = -EREMOTEIO; - } else { - ret = 0; - } + struct si2168_cmd cmd; - mutex_unlock(&dev->i2c_mutex); + /* close I2C gate */ + memcpy(cmd.args, "\xc0\x0d\x00", 3); + cmd.wlen = 3; + cmd.rlen = 0; + ret = si2168_cmd_execute_unlocked(client, &cmd); + if (ret) + goto err; + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } @@ -671,8 +704,6 @@ static int si2168_probe(struct i2c_client *client, goto err; } - mutex_init(&dev->i2c_mutex); - /* create mux i2c adapter for tuner */ dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev, client, 0, 0, 0, si2168_select, si2168_deselect); @@ -688,6 +719,7 @@ static int si2168_probe(struct i2c_client *client, *config->fe = &dev->fe; dev->ts_mode = config->ts_mode; dev->ts_clock_inv = config->ts_clock_inv; + dev->ts_clock_gapped = config->ts_clock_gapped; dev->fw_loaded = false; i2c_set_clientdata(client, dev); diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h index 70d702a..3225d0c 100644 --- a/drivers/media/dvb-frontends/si2168.h +++ b/drivers/media/dvb-frontends/si2168.h @@ -42,6 +42,9 @@ struct si2168_config { /* TS clock inverted */ bool ts_clock_inv; + + /* TS clock gapped */ + bool ts_clock_gapped; }; #endif diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h index d7efce8..c07e6fe 100644 --- a/drivers/media/dvb-frontends/si2168_priv.h +++ b/drivers/media/dvb-frontends/si2168_priv.h @@ -30,14 +30,14 @@ /* state struct */ struct si2168_dev { struct i2c_adapter *adapter; - struct mutex i2c_mutex; struct dvb_frontend fe; - fe_delivery_system_t delivery_system; - fe_status_t fe_status; + enum fe_delivery_system delivery_system; + enum fe_status fe_status; bool active; bool fw_loaded; u8 ts_mode; bool ts_clock_inv; + bool ts_clock_gapped; }; /* firmware command struct */ diff --git a/drivers/media/dvb-frontends/si21xx.c b/drivers/media/dvb-frontends/si21xx.c index 16850e2..62ad7a7 100644 --- a/drivers/media/dvb-frontends/si21xx.c +++ b/drivers/media/dvb-frontends/si21xx.c @@ -410,7 +410,7 @@ static int si21xx_send_diseqc_msg(struct dvb_frontend *fe, } static int si21xx_send_diseqc_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t burst) + enum fe_sec_mini_cmd burst) { struct si21xx_state *state = fe->demodulator_priv; u8 val; @@ -434,7 +434,7 @@ static int si21xx_send_diseqc_burst(struct dvb_frontend *fe, return 0; } /* 30.06.2008 */ -static int si21xx_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +static int si21xx_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) { struct si21xx_state *state = fe->demodulator_priv; u8 val; @@ -454,7 +454,7 @@ static int si21xx_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) } } -static int si21xx_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) +static int si21xx_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage volt) { struct si21xx_state *state = fe->demodulator_priv; @@ -536,7 +536,7 @@ static int si21xx_init(struct dvb_frontend *fe) } -static int si21_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int si21_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct si21xx_state *state = fe->demodulator_priv; u8 regs_read[2]; @@ -641,7 +641,7 @@ static int si21_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) /* initiates a channel acquisition sequence using the specified symbol rate and code rate */ static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate, - fe_code_rate_t crate) + enum fe_code_rate crate) { struct si21xx_state *state = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/sp8870.c b/drivers/media/dvb-frontends/sp8870.c index 57dc2aba..e87ac30 100644 --- a/drivers/media/dvb-frontends/sp8870.c +++ b/drivers/media/dvb-frontends/sp8870.c @@ -350,7 +350,8 @@ static int sp8870_init (struct dvb_frontend* fe) return 0; } -static int sp8870_read_status (struct dvb_frontend* fe, fe_status_t * fe_status) +static int sp8870_read_status(struct dvb_frontend *fe, + enum fe_status *fe_status) { struct sp8870_state* state = fe->demodulator_priv; int status; diff --git a/drivers/media/dvb-frontends/sp887x.c b/drivers/media/dvb-frontends/sp887x.c index 1bb81b5..4378fe1 100644 --- a/drivers/media/dvb-frontends/sp887x.c +++ b/drivers/media/dvb-frontends/sp887x.c @@ -416,7 +416,7 @@ static int sp887x_setup_frontend_parameters(struct dvb_frontend *fe) return 0; } -static int sp887x_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int sp887x_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct sp887x_state* state = fe->demodulator_priv; u16 snr12 = sp887x_readreg(state, 0xf16); diff --git a/drivers/media/dvb-frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c index c73899d..756650f 100644 --- a/drivers/media/dvb-frontends/stb0899_drv.c +++ b/drivers/media/dvb-frontends/stb0899_drv.c @@ -792,7 +792,8 @@ static int stb0899_wait_diseqc_txidle(struct stb0899_state *state, int timeout) return 0; } -static int stb0899_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst) +static int stb0899_send_diseqc_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd burst) { struct stb0899_state *state = fe->demodulator_priv; u8 reg, old_state; @@ -1178,7 +1179,8 @@ static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber) return 0; } -static int stb0899_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int stb0899_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct stb0899_state *state = fe->demodulator_priv; @@ -1205,7 +1207,7 @@ static int stb0899_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage return 0; } -static int stb0899_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +static int stb0899_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) { struct stb0899_state *state = fe->demodulator_priv; struct stb0899_internal *internal = &state->internal; diff --git a/drivers/media/dvb-frontends/stv0288.c b/drivers/media/dvb-frontends/stv0288.c index 632b251..c93d9a4 100644 --- a/drivers/media/dvb-frontends/stv0288.c +++ b/drivers/media/dvb-frontends/stv0288.c @@ -44,7 +44,7 @@ struct stv0288_state { u8 initialised:1; u32 tuner_frequency; u32 symbol_rate; - fe_code_rate_t fec_inner; + enum fe_code_rate fec_inner; int errmode; }; @@ -134,20 +134,20 @@ static int stv0288_set_symbolrate(struct dvb_frontend *fe, u32 srate) temp = (unsigned int)srate / 1000; - temp = temp * 32768; - temp = temp / 25; - temp = temp / 125; - b[0] = (unsigned char)((temp >> 12) & 0xff); - b[1] = (unsigned char)((temp >> 4) & 0xff); - b[2] = (unsigned char)((temp << 4) & 0xf0); - stv0288_writeregI(state, 0x28, 0x80); /* SFRH */ - stv0288_writeregI(state, 0x29, 0); /* SFRM */ - stv0288_writeregI(state, 0x2a, 0); /* SFRL */ - - stv0288_writeregI(state, 0x28, b[0]); - stv0288_writeregI(state, 0x29, b[1]); - stv0288_writeregI(state, 0x2a, b[2]); - dprintk("stv0288: stv0288_set_symbolrate\n"); + temp = temp * 32768; + temp = temp / 25; + temp = temp / 125; + b[0] = (unsigned char)((temp >> 12) & 0xff); + b[1] = (unsigned char)((temp >> 4) & 0xff); + b[2] = (unsigned char)((temp << 4) & 0xf0); + stv0288_writeregI(state, 0x28, 0x80); /* SFRH */ + stv0288_writeregI(state, 0x29, 0); /* SFRM */ + stv0288_writeregI(state, 0x2a, 0); /* SFRL */ + + stv0288_writeregI(state, 0x28, b[0]); + stv0288_writeregI(state, 0x29, b[1]); + stv0288_writeregI(state, 0x2a, b[2]); + dprintk("stv0288: stv0288_set_symbolrate\n"); return 0; } @@ -174,7 +174,7 @@ static int stv0288_send_diseqc_msg(struct dvb_frontend *fe, } static int stv0288_send_diseqc_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t burst) + enum fe_sec_mini_cmd burst) { struct stv0288_state *state = fe->demodulator_priv; @@ -193,7 +193,7 @@ static int stv0288_send_diseqc_burst(struct dvb_frontend *fe, return 0; } -static int stv0288_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +static int stv0288_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) { struct stv0288_state *state = fe->demodulator_priv; @@ -323,7 +323,8 @@ static u8 stv0288_inittab[] = { 0xff, 0xff, }; -static int stv0288_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) +static int stv0288_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage volt) { dprintk("%s: %s\n", __func__, volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : @@ -361,7 +362,7 @@ static int stv0288_init(struct dvb_frontend *fe) return 0; } -static int stv0288_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int stv0288_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct stv0288_state *state = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/stv0297.c b/drivers/media/dvb-frontends/stv0297.c index d40f226..75b4d8b 100644 --- a/drivers/media/dvb-frontends/stv0297.c +++ b/drivers/media/dvb-frontends/stv0297.c @@ -136,10 +136,10 @@ static u32 stv0297_get_symbolrate(struct stv0297_state *state) { u64 tmp; - tmp = stv0297_readreg(state, 0x55); - tmp |= stv0297_readreg(state, 0x56) << 8; - tmp |= stv0297_readreg(state, 0x57) << 16; - tmp |= stv0297_readreg(state, 0x58) << 24; + tmp = (u64)(stv0297_readreg(state, 0x55) + | (stv0297_readreg(state, 0x56) << 8) + | (stv0297_readreg(state, 0x57) << 16) + | (stv0297_readreg(state, 0x58) << 24)); tmp *= STV0297_CLOCK_KHZ; tmp >>= 32; @@ -233,7 +233,8 @@ static void stv0297_set_initialdemodfreq(struct stv0297_state *state, long freq) stv0297_writereg(state, 0x20, tmp); } -static int stv0297_set_qam(struct stv0297_state *state, fe_modulation_t modulation) +static int stv0297_set_qam(struct stv0297_state *state, + enum fe_modulation modulation) { int val = 0; @@ -267,7 +268,8 @@ static int stv0297_set_qam(struct stv0297_state *state, fe_modulation_t modulati return 0; } -static int stv0297_set_inversion(struct stv0297_state *state, fe_spectral_inversion_t inversion) +static int stv0297_set_inversion(struct stv0297_state *state, + enum fe_spectral_inversion inversion) { int val = 0; @@ -325,7 +327,8 @@ static int stv0297_sleep(struct dvb_frontend *fe) return 0; } -static int stv0297_read_status(struct dvb_frontend *fe, fe_status_t * status) +static int stv0297_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct stv0297_state *state = fe->demodulator_priv; @@ -415,7 +418,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe) int sweeprate; int carrieroffset; unsigned long timeout; - fe_spectral_inversion_t inversion; + enum fe_spectral_inversion inversion; switch (p->modulation) { case QAM_16: diff --git a/drivers/media/dvb-frontends/stv0299.c b/drivers/media/dvb-frontends/stv0299.c index b57ecf4..a817780 100644 --- a/drivers/media/dvb-frontends/stv0299.c +++ b/drivers/media/dvb-frontends/stv0299.c @@ -44,6 +44,7 @@ #include <linux/init.h> #include <linux/kernel.h> +#include <linux/ktime.h> #include <linux/module.h> #include <linux/string.h> #include <linux/slab.h> @@ -61,7 +62,7 @@ struct stv0299_state { u8 initialised:1; u32 tuner_frequency; u32 symbol_rate; - fe_code_rate_t fec_inner; + enum fe_code_rate fec_inner; int errmode; u32 ucblocks; u8 mcr_reg; @@ -134,7 +135,7 @@ static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len return ret == 2 ? 0 : ret; } -static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec) +static int stv0299_set_FEC(struct stv0299_state *state, enum fe_code_rate fec) { dprintk ("%s\n", __func__); @@ -170,10 +171,10 @@ static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec) } } -static fe_code_rate_t stv0299_get_fec (struct stv0299_state* state) +static enum fe_code_rate stv0299_get_fec(struct stv0299_state *state) { - static fe_code_rate_t fec_tab [] = { FEC_2_3, FEC_3_4, FEC_5_6, - FEC_7_8, FEC_1_2 }; + static enum fe_code_rate fec_tab[] = { FEC_2_3, FEC_3_4, FEC_5_6, + FEC_7_8, FEC_1_2 }; u8 index; dprintk ("%s\n", __func__); @@ -302,7 +303,8 @@ static int stv0299_send_diseqc_msg (struct dvb_frontend* fe, return 0; } -static int stv0299_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) +static int stv0299_send_diseqc_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd burst) { struct stv0299_state* state = fe->demodulator_priv; u8 val; @@ -329,7 +331,8 @@ static int stv0299_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t return 0; } -static int stv0299_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int stv0299_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct stv0299_state* state = fe->demodulator_priv; u8 val; @@ -351,7 +354,8 @@ static int stv0299_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) } } -static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int stv0299_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct stv0299_state* state = fe->demodulator_priv; u8 reg0x08; @@ -404,8 +408,8 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long u8 lv_mask = 0x40; u8 last = 1; int i; - struct timeval nexttime; - struct timeval tv[10]; + ktime_t nexttime; + ktime_t tv[10]; reg0x08 = stv0299_readreg (state, 0x08); reg0x0c = stv0299_readreg (state, 0x0c); @@ -418,7 +422,7 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long if (debug_legacy_dish_switch) printk ("%s switch command: 0x%04lx\n",__func__, cmd); - do_gettimeofday (&nexttime); + nexttime = ktime_get_real(); if (debug_legacy_dish_switch) tv[0] = nexttime; stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */ @@ -427,7 +431,7 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long for (i=0; i<9; i++) { if (debug_legacy_dish_switch) - do_gettimeofday (&tv[i+1]); + tv[i+1] = ktime_get_real(); if((cmd & 0x01) != last) { /* set voltage to (last ? 13V : 18V) */ stv0299_writeregI (state, 0x0c, reg0x0c | (last ? lv_mask : 0x50)); @@ -443,7 +447,8 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long printk ("%s(%d): switch delay (should be 32k followed by all 8k\n", __func__, fe->dvb->num); for (i = 1; i < 10; i++) - printk ("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i])); + printk("%d: %d\n", i, + (int) ktime_us_delta(tv[i], tv[i-1])); } return 0; @@ -476,7 +481,8 @@ static int stv0299_init (struct dvb_frontend* fe) return 0; } -static int stv0299_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int stv0299_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct stv0299_state* state = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index b31ff26..ec3e18e 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -59,7 +59,7 @@ struct stv0367cab_state { int locked; /* channel found */ u32 freq_khz; /* found frequency (in kHz) */ u32 symbol_rate; /* found symbol rate (in Bds) */ - fe_spectral_inversion_t spect_inv; /* Spectrum Inversion */ + enum fe_spectral_inversion spect_inv; /* Spectrum Inversion */ }; struct stv0367ter_state { @@ -67,10 +67,10 @@ struct stv0367ter_state { enum stv0367_ter_signal_type state; enum stv0367_ter_if_iq_mode if_iq_mode; enum stv0367_ter_mode mode;/* mode 2K or 8K */ - fe_guard_interval_t guard; + enum fe_guard_interval guard; enum stv0367_ter_hierarchy hierarchy; u32 frequency; - fe_spectral_inversion_t sense; /* current search spectrum */ + enum fe_spectral_inversion sense; /* current search spectrum */ u8 force; /* force mode/guard */ u8 bw; /* channel width 6, 7 or 8 in MHz */ u8 pBW; /* channel width used during previous lock */ @@ -2074,7 +2074,8 @@ static int stv0367ter_status(struct dvb_frontend *fe) return locked; } #endif -static int stv0367ter_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int stv0367ter_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct stv0367_state *state = fe->demodulator_priv; @@ -2716,7 +2717,8 @@ static u32 stv0367cab_GetSymbolRate(struct stv0367_state *state, u32 mclk_hz) return regsym; } -static int stv0367cab_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int stv0367cab_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct stv0367_state *state = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/stv0367_priv.h b/drivers/media/dvb-frontends/stv0367_priv.h index 995db06..89bf6f6 100644 --- a/drivers/media/dvb-frontends/stv0367_priv.h +++ b/drivers/media/dvb-frontends/stv0367_priv.h @@ -188,7 +188,7 @@ struct stv0367_cab_signal_info { u32 frequency; /* kHz */ u32 symbol_rate; /* Mbds */ enum stv0367cab_mod modulation; - fe_spectral_inversion_t spect_inv; + enum fe_spectral_inversion spect_inv; s32 Power_dBmx10; /* Power of the RF signal (dBm x 10) */ u32 CN_dBx10; /* Carrier to noise ratio (dB x 10) */ u32 BER; /* Bit error rate (x 10000000) */ diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c index 2c88abf..fe31dd5 100644 --- a/drivers/media/dvb-frontends/stv0900_core.c +++ b/drivers/media/dvb-frontends/stv0900_core.c @@ -1744,7 +1744,8 @@ static int stv0900_send_master_cmd(struct dvb_frontend *fe, state->demod); } -static int stv0900_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst) +static int stv0900_send_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd burst) { struct stv0900_state *state = fe->demodulator_priv; struct stv0900_internal *intp = state->internal; @@ -1793,7 +1794,8 @@ static int stv0900_recv_slave_reply(struct dvb_frontend *fe, return 0; } -static int stv0900_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t toneoff) +static int stv0900_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode toneoff) { struct stv0900_state *state = fe->demodulator_priv; struct stv0900_internal *intp = state->internal; diff --git a/drivers/media/dvb-frontends/stv0900_sw.c b/drivers/media/dvb-frontends/stv0900_sw.c index a0a7b16..fa63a9e 100644 --- a/drivers/media/dvb-frontends/stv0900_sw.c +++ b/drivers/media/dvb-frontends/stv0900_sw.c @@ -1556,8 +1556,8 @@ static u32 stv0900_search_srate_fine(struct dvb_frontend *fe) } symbcomp = 13 * (coarse_srate / 10); - coarse_freq = (stv0900_read_reg(intp, CFR2) << 8) - | stv0900_read_reg(intp, CFR1); + coarse_freq = (stv0900_read_reg(intp, CFR2) << 8) + | stv0900_read_reg(intp, CFR1); if (symbcomp < intp->symbol_rate[demod]) coarse_srate = 0; @@ -2009,7 +2009,7 @@ enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe) signal_type = STV0900_NODATA; no_signal = stv0900_check_signal_presence(intp, demod); - intp->result[demod].locked = FALSE; + intp->result[demod].locked = FALSE; } } diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c index 0b2a934..25bdf6e 100644 --- a/drivers/media/dvb-frontends/stv090x.c +++ b/drivers/media/dvb-frontends/stv090x.c @@ -3732,7 +3732,7 @@ static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr) return 0; } -static int stv090x_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +static int stv090x_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) { struct stv090x_state *state = fe->demodulator_priv; u32 reg; @@ -3822,7 +3822,8 @@ err: return -1; } -static int stv090x_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst) +static int stv090x_send_diseqc_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd burst) { struct stv090x_state *state = fe->demodulator_priv; u32 reg, idle = 0, fifo_full = 1; diff --git a/drivers/media/dvb-frontends/stv6110.c b/drivers/media/dvb-frontends/stv6110.c index b142583..91c6dcf 100644 --- a/drivers/media/dvb-frontends/stv6110.c +++ b/drivers/media/dvb-frontends/stv6110.c @@ -158,7 +158,7 @@ static int stv6110_sleep(struct dvb_frontend *fe) return 0; } -static u32 carrier_width(u32 symbol_rate, fe_rolloff_t rolloff) +static u32 carrier_width(u32 symbol_rate, enum fe_rolloff rolloff) { u32 rlf; diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c index dce22ce..456cdc7 100644 --- a/drivers/media/dvb-frontends/tc90522.c +++ b/drivers/media/dvb-frontends/tc90522.c @@ -130,7 +130,7 @@ static int tc90522t_set_layers(struct dvb_frontend *fe) /* frontend ops */ -static int tc90522s_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int tc90522s_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct tc90522_state *state; int ret; @@ -158,7 +158,7 @@ static int tc90522s_read_status(struct dvb_frontend *fe, fe_status_t *status) return 0; } -static int tc90522t_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int tc90522t_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct tc90522_state *state; int ret; @@ -194,7 +194,7 @@ static int tc90522t_read_status(struct dvb_frontend *fe, fe_status_t *status) return 0; } -static const fe_code_rate_t fec_conv_sat[] = { +static const enum fe_code_rate fec_conv_sat[] = { FEC_NONE, /* unused */ FEC_1_2, /* for BPSK */ FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, /* for QPSK */ @@ -238,7 +238,10 @@ static int tc90522s_get_frontend(struct dvb_frontend *fe) c->layer[1].segment_count = 0; else c->layer[1].segment_count = val[4] & 0x3f; /* slots */ - /* actually, BPSK if v==1, but not defined in fe_modulation_t */ + /* + * actually, BPSK if v==1, but not defined in + * enum fe_modulation + */ c->layer[1].modulation = QPSK; layers = (v > 0) ? 2 : 1; } @@ -319,18 +322,18 @@ static int tc90522s_get_frontend(struct dvb_frontend *fe) } -static const fe_transmit_mode_t tm_conv[] = { +static const enum fe_transmit_mode tm_conv[] = { TRANSMISSION_MODE_2K, TRANSMISSION_MODE_4K, TRANSMISSION_MODE_8K, 0 }; -static const fe_code_rate_t fec_conv_ter[] = { +static const enum fe_code_rate fec_conv_ter[] = { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, 0, 0, 0 }; -static const fe_modulation_t mod_conv[] = { +static const enum fe_modulation mod_conv[] = { DQPSK, QPSK, QAM_16, QAM_64, 0, 0, 0, 0 }; diff --git a/drivers/media/dvb-frontends/tda10021.c b/drivers/media/dvb-frontends/tda10021.c index 1bff7f4..a684424 100644 --- a/drivers/media/dvb-frontends/tda10021.c +++ b/drivers/media/dvb-frontends/tda10021.c @@ -129,8 +129,8 @@ static int unlock_tuner(struct tda10021_state* state) return 0; } -static int tda10021_setup_reg0 (struct tda10021_state* state, u8 reg0, - fe_spectral_inversion_t inversion) +static int tda10021_setup_reg0(struct tda10021_state *state, u8 reg0, + enum fe_spectral_inversion inversion) { reg0 |= state->reg0 & 0x63; @@ -258,7 +258,7 @@ static int tda10021_set_parameters(struct dvb_frontend *fe) } /* - * gcc optimizes the code bellow the same way as it would code: + * gcc optimizes the code below the same way as it would code: * "if (qam > 5) return -EINVAL;" * Yet, the code is clearer, as it shows what QAM standards are * supported by the driver, and avoids the usage of magic numbers on @@ -308,7 +308,8 @@ static int tda10021_set_parameters(struct dvb_frontend *fe) return 0; } -static int tda10021_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int tda10021_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct tda10021_state* state = fe->demodulator_priv; int sync; diff --git a/drivers/media/dvb-frontends/tda10023.c b/drivers/media/dvb-frontends/tda10023.c index ca1e0d5..44a5565 100644 --- a/drivers/media/dvb-frontends/tda10023.c +++ b/drivers/media/dvb-frontends/tda10023.c @@ -331,7 +331,7 @@ static int tda10023_set_parameters(struct dvb_frontend *fe) } /* - * gcc optimizes the code bellow the same way as it would code: + * gcc optimizes the code below the same way as it would code: * "if (qam > 5) return -EINVAL;" * Yet, the code is clearer, as it shows what QAM standards are * supported by the driver, and avoids the usage of magic numbers on @@ -376,7 +376,8 @@ static int tda10023_set_parameters(struct dvb_frontend *fe) return 0; } -static int tda10023_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int tda10023_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct tda10023_state* state = fe->demodulator_priv; int sync; diff --git a/drivers/media/dvb-frontends/tda10048.c b/drivers/media/dvb-frontends/tda10048.c index 71fb632..8451086 100644 --- a/drivers/media/dvb-frontends/tda10048.c +++ b/drivers/media/dvb-frontends/tda10048.c @@ -792,7 +792,7 @@ static int tda10048_init(struct dvb_frontend *fe) return ret; } -static int tda10048_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int tda10048_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct tda10048_state *state = fe->demodulator_priv; u8 reg; diff --git a/drivers/media/dvb-frontends/tda1004x.c b/drivers/media/dvb-frontends/tda1004x.c index a2631be..0e209b5 100644 --- a/drivers/media/dvb-frontends/tda1004x.c +++ b/drivers/media/dvb-frontends/tda1004x.c @@ -650,7 +650,7 @@ static int tda10046_init(struct dvb_frontend* fe) if (tda10046_fwupload(fe)) { printk("tda1004x: firmware upload failed\n"); - return -EIO; + return -EIO; } // tda setup @@ -1005,7 +1005,8 @@ static int tda1004x_get_fe(struct dvb_frontend *fe) return 0; } -static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status) +static int tda1004x_read_status(struct dvb_frontend *fe, + enum fe_status *fe_status) { struct tda1004x_state* state = fe->demodulator_priv; int status; diff --git a/drivers/media/dvb-frontends/tda10071.c b/drivers/media/dvb-frontends/tda10071.c index 4a19b85..f6dc630 100644 --- a/drivers/media/dvb-frontends/tda10071.c +++ b/drivers/media/dvb-frontends/tda10071.c @@ -203,7 +203,7 @@ error: } static int tda10071_set_tone(struct dvb_frontend *fe, - fe_sec_tone_mode_t fe_sec_tone_mode) + enum fe_sec_tone_mode fe_sec_tone_mode) { struct tda10071_priv *priv = fe->demodulator_priv; struct tda10071_cmd cmd; @@ -249,7 +249,7 @@ error: } static int tda10071_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t fe_sec_voltage) + enum fe_sec_voltage fe_sec_voltage) { struct tda10071_priv *priv = fe->demodulator_priv; struct tda10071_cmd cmd; @@ -413,7 +413,7 @@ error: } static int tda10071_diseqc_send_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t fe_sec_mini_cmd) + enum fe_sec_mini_cmd fe_sec_mini_cmd) { struct tda10071_priv *priv = fe->demodulator_priv; struct tda10071_cmd cmd; @@ -476,7 +476,7 @@ error: return ret; } -static int tda10071_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int tda10071_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct tda10071_priv *priv = fe->demodulator_priv; int ret; @@ -668,7 +668,7 @@ static int tda10071_set_frontend(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i; u8 mode, rolloff, pilot, inversion, div; - fe_modulation_t modulation; + enum fe_modulation modulation; dev_dbg(&priv->i2c->dev, "%s: delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n", @@ -1313,6 +1313,113 @@ static struct dvb_frontend_ops tda10071_ops = { .set_voltage = tda10071_set_voltage, }; +static struct dvb_frontend *tda10071_get_dvb_frontend(struct i2c_client *client) +{ + struct tda10071_priv *dev = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + + return &dev->fe; +} + +static int tda10071_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tda10071_priv *dev; + struct tda10071_platform_data *pdata = client->dev.platform_data; + int ret; + u8 u8tmp; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + ret = -ENOMEM; + goto err; + } + + dev->client = client; + dev->i2c = client->adapter; + dev->cfg.demod_i2c_addr = client->addr; + dev->cfg.i2c_wr_max = pdata->i2c_wr_max; + dev->cfg.ts_mode = pdata->ts_mode; + dev->cfg.spec_inv = pdata->spec_inv; + dev->cfg.xtal = pdata->clk; + dev->cfg.pll_multiplier = pdata->pll_multiplier; + dev->cfg.tuner_i2c_addr = pdata->tuner_i2c_addr; + + /* chip ID */ + ret = tda10071_rd_reg(dev, 0xff, &u8tmp); + if (ret) + goto err_kfree; + if (u8tmp != 0x0f) { + ret = -ENODEV; + goto err_kfree; + } + + /* chip type */ + ret = tda10071_rd_reg(dev, 0xdd, &u8tmp); + if (ret) + goto err_kfree; + if (u8tmp != 0x00) { + ret = -ENODEV; + goto err_kfree; + } + + /* chip version */ + ret = tda10071_rd_reg(dev, 0xfe, &u8tmp); + if (ret) + goto err_kfree; + if (u8tmp != 0x01) { + ret = -ENODEV; + goto err_kfree; + } + + /* create dvb_frontend */ + memcpy(&dev->fe.ops, &tda10071_ops, sizeof(struct dvb_frontend_ops)); + dev->fe.ops.release = NULL; + dev->fe.demodulator_priv = dev; + i2c_set_clientdata(client, dev); + + /* setup callbacks */ + pdata->get_dvb_frontend = tda10071_get_dvb_frontend; + + dev_info(&client->dev, "NXP TDA10071 successfully identified\n"); + return 0; +err_kfree: + kfree(dev); +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + +static int tda10071_remove(struct i2c_client *client) +{ + struct tda10071_dev *dev = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + + kfree(dev); + return 0; +} + +static const struct i2c_device_id tda10071_id_table[] = { + {"tda10071_cx24118", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, tda10071_id_table); + +static struct i2c_driver tda10071_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "tda10071", + .suppress_bind_attrs = true, + }, + .probe = tda10071_probe, + .remove = tda10071_remove, + .id_table = tda10071_id_table, +}; + +module_i2c_driver(tda10071_driver); + MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); MODULE_DESCRIPTION("NXP TDA10071 DVB-S/S2 demodulator driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/tda10071.h b/drivers/media/dvb-frontends/tda10071.h index da89f42..0ffbfa5 100644 --- a/drivers/media/dvb-frontends/tda10071.h +++ b/drivers/media/dvb-frontends/tda10071.h @@ -24,6 +24,35 @@ #include <linux/kconfig.h> #include <linux/dvb/frontend.h> +/* + * I2C address + * 0x55, + */ + +/** + * struct tda10071_platform_data - Platform data for the tda10071 driver + * @clk: Clock frequency. + * @i2c_wr_max: Max bytes I2C adapter can write at once. + * @ts_mode: TS mode. + * @spec_inv: Input spectrum inversion. + * @pll_multiplier: PLL multiplier. + * @tuner_i2c_addr: CX24118A tuner I2C address (0x14, 0x54, ...). + * @get_dvb_frontend: Get DVB frontend. + */ + +struct tda10071_platform_data { + u32 clk; + u16 i2c_wr_max; +#define TDA10071_TS_SERIAL 0 +#define TDA10071_TS_PARALLEL 1 + u8 ts_mode; + bool spec_inv; + u8 pll_multiplier; + u8 tuner_i2c_addr; + + struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); +}; + struct tda10071_config { /* Demodulator I2C address. * Default: none, must set diff --git a/drivers/media/dvb-frontends/tda10071_priv.h b/drivers/media/dvb-frontends/tda10071_priv.h index 03f839c..54d7c71 100644 --- a/drivers/media/dvb-frontends/tda10071_priv.h +++ b/drivers/media/dvb-frontends/tda10071_priv.h @@ -28,20 +28,21 @@ struct tda10071_priv { struct i2c_adapter *i2c; struct dvb_frontend fe; + struct i2c_client *client; struct tda10071_config cfg; u8 meas_count[2]; u32 ber; u32 ucb; - fe_status_t fe_status; - fe_delivery_system_t delivery_system; + enum fe_status fe_status; + enum fe_delivery_system delivery_system; bool warm; /* FW running */ }; static struct tda10071_modcod { - fe_delivery_system_t delivery_system; - fe_modulation_t modulation; - fe_code_rate_t fec; + enum fe_delivery_system delivery_system; + enum fe_modulation modulation; + enum fe_code_rate fec; u8 val; } TDA10071_MODCOD[] = { /* NBC-QPSK */ diff --git a/drivers/media/dvb-frontends/tda10086.c b/drivers/media/dvb-frontends/tda10086.c index fcfe2e0..95a33e1 100644 --- a/drivers/media/dvb-frontends/tda10086.c +++ b/drivers/media/dvb-frontends/tda10086.c @@ -185,7 +185,8 @@ static void tda10086_diseqc_wait(struct tda10086_state *state) } } -static int tda10086_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int tda10086_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct tda10086_state* state = fe->demodulator_priv; u8 t22k_off = 0x80; @@ -238,7 +239,8 @@ static int tda10086_send_master_cmd (struct dvb_frontend* fe, return 0; } -static int tda10086_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +static int tda10086_send_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd minicmd) { struct tda10086_state* state = fe->demodulator_priv; u8 oldval = tda10086_read_byte(state, 0x36); @@ -472,8 +474,8 @@ static int tda10086_get_frontend(struct dvb_frontend *fe) return -EINVAL; /* calculate the updated frequency (note: we convert from Hz->kHz) */ - tmp64 = tda10086_read_byte(state, 0x52); - tmp64 |= (tda10086_read_byte(state, 0x51) << 8); + tmp64 = ((u64)tda10086_read_byte(state, 0x52) + | (tda10086_read_byte(state, 0x51) << 8)); if (tmp64 & 0x8000) tmp64 |= 0xffffffffffff0000ULL; tmp64 = (tmp64 * (SACLK/1000ULL)); @@ -551,7 +553,8 @@ static int tda10086_get_frontend(struct dvb_frontend *fe) return 0; } -static int tda10086_read_status(struct dvb_frontend* fe, fe_status_t *fe_status) +static int tda10086_read_status(struct dvb_frontend *fe, + enum fe_status *fe_status) { struct tda10086_state* state = fe->demodulator_priv; u8 val; diff --git a/drivers/media/dvb-frontends/tda8083.c b/drivers/media/dvb-frontends/tda8083.c index 69e62f4..796543f 100644 --- a/drivers/media/dvb-frontends/tda8083.c +++ b/drivers/media/dvb-frontends/tda8083.c @@ -97,7 +97,8 @@ static inline u8 tda8083_readreg (struct tda8083_state* state, u8 reg) return val; } -static int tda8083_set_inversion (struct tda8083_state* state, fe_spectral_inversion_t inversion) +static int tda8083_set_inversion(struct tda8083_state *state, + enum fe_spectral_inversion inversion) { /* XXX FIXME: implement other modes than FEC_AUTO */ if (inversion == INVERSION_AUTO) @@ -106,7 +107,7 @@ static int tda8083_set_inversion (struct tda8083_state* state, fe_spectral_inver return -EINVAL; } -static int tda8083_set_fec (struct tda8083_state* state, fe_code_rate_t fec) +static int tda8083_set_fec(struct tda8083_state *state, enum fe_code_rate fec) { if (fec == FEC_AUTO) return tda8083_writereg (state, 0x07, 0xff); @@ -117,11 +118,13 @@ static int tda8083_set_fec (struct tda8083_state* state, fe_code_rate_t fec) return -EINVAL; } -static fe_code_rate_t tda8083_get_fec (struct tda8083_state* state) +static enum fe_code_rate tda8083_get_fec(struct tda8083_state *state) { u8 index; - static fe_code_rate_t fec_tab [] = { FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4, - FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8 }; + static enum fe_code_rate fec_tab[] = { + FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4, + FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8 + }; index = tda8083_readreg(state, 0x0e) & 0x07; @@ -178,7 +181,8 @@ static void tda8083_wait_diseqc_fifo (struct tda8083_state* state, int timeout) } } -static int tda8083_set_tone (struct tda8083_state* state, fe_sec_tone_mode_t tone) +static int tda8083_set_tone(struct tda8083_state *state, + enum fe_sec_tone_mode tone) { tda8083_writereg (state, 0x26, 0xf1); @@ -192,7 +196,8 @@ static int tda8083_set_tone (struct tda8083_state* state, fe_sec_tone_mode_t ton } } -static int tda8083_set_voltage (struct tda8083_state* state, fe_sec_voltage_t voltage) +static int tda8083_set_voltage(struct tda8083_state *state, + enum fe_sec_voltage voltage) { switch (voltage) { case SEC_VOLTAGE_13: @@ -204,7 +209,8 @@ static int tda8083_set_voltage (struct tda8083_state* state, fe_sec_voltage_t vo } } -static int tda8083_send_diseqc_burst (struct tda8083_state* state, fe_sec_mini_cmd_t burst) +static int tda8083_send_diseqc_burst(struct tda8083_state *state, + enum fe_sec_mini_cmd burst) { switch (burst) { case SEC_MINI_A: @@ -222,8 +228,8 @@ static int tda8083_send_diseqc_burst (struct tda8083_state* state, fe_sec_mini_c return 0; } -static int tda8083_send_diseqc_msg (struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd *m) +static int tda8083_send_diseqc_msg(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *m) { struct tda8083_state* state = fe->demodulator_priv; int i; @@ -240,7 +246,8 @@ static int tda8083_send_diseqc_msg (struct dvb_frontend* fe, return 0; } -static int tda8083_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int tda8083_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct tda8083_state* state = fe->demodulator_priv; @@ -372,7 +379,8 @@ static int tda8083_init(struct dvb_frontend* fe) return 0; } -static int tda8083_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) +static int tda8083_diseqc_send_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd burst) { struct tda8083_state* state = fe->demodulator_priv; @@ -383,7 +391,8 @@ static int tda8083_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t return 0; } -static int tda8083_diseqc_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int tda8083_diseqc_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct tda8083_state* state = fe->demodulator_priv; @@ -394,7 +403,8 @@ static int tda8083_diseqc_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t t return 0; } -static int tda8083_diseqc_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int tda8083_diseqc_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct tda8083_state* state = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c index 90164a3..f61b143 100644 --- a/drivers/media/dvb-frontends/ts2020.c +++ b/drivers/media/dvb-frontends/ts2020.c @@ -21,23 +21,32 @@ #include "dvb_frontend.h" #include "ts2020.h" +#include <linux/regmap.h> +#include <linux/math64.h> #define TS2020_XTAL_FREQ 27000 /* in kHz */ #define FREQ_OFFSET_LOW_SYM_RATE 3000 struct ts2020_priv { + struct i2c_client *client; + struct mutex regmap_mutex; + struct regmap_config regmap_config; + struct regmap *regmap; struct dvb_frontend *fe; + struct delayed_work stat_work; + int (*get_agc_pwm)(struct dvb_frontend *fe, u8 *_agc_pwm); /* i2c details */ - int i2c_address; struct i2c_adapter *i2c; + int i2c_address; + bool loop_through:1; u8 clk_out:2; u8 clk_out_div:5; - u32 frequency; - u32 frequency_div; + bool dont_poll:1; + u32 frequency_div; /* LO output divider switch frequency */ + u32 frequency_khz; /* actual used LO frequency */ #define TS2020_M88TS2020 0 #define TS2020_M88TS2022 1 u8 tuner; - u8 loop_through:1; }; struct ts2020_reg_val { @@ -45,84 +54,23 @@ struct ts2020_reg_val { u8 val; }; -static int ts2020_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} +static void ts2020_stat_work(struct work_struct *work); -static int ts2020_writereg(struct dvb_frontend *fe, int reg, int data) +static int ts2020_release(struct dvb_frontend *fe) { struct ts2020_priv *priv = fe->tuner_priv; - u8 buf[] = { reg, data }; - struct i2c_msg msg[] = { - { - .addr = priv->i2c_address, - .flags = 0, - .buf = buf, - .len = 2 - } - }; - int err; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - err = i2c_transfer(priv->i2c, msg, 1); - if (err != 1) { - printk(KERN_ERR - "%s: writereg error(err == %i, reg == 0x%02x, value == 0x%02x)\n", - __func__, err, reg, data); - return -EREMOTEIO; - } + struct i2c_client *client = priv->client; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); + dev_dbg(&client->dev, "\n"); + i2c_unregister_device(client); return 0; } -static int ts2020_readreg(struct dvb_frontend *fe, u8 reg) -{ - struct ts2020_priv *priv = fe->tuner_priv; - int ret; - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - struct i2c_msg msg[] = { - { - .addr = priv->i2c_address, - .flags = 0, - .buf = b0, - .len = 1 - }, { - .addr = priv->i2c_address, - .flags = I2C_M_RD, - .buf = b1, - .len = 1 - } - }; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - ret = i2c_transfer(priv->i2c, msg, 2); - - if (ret != 2) { - printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", - __func__, reg, ret); - return ret; - } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return b1[0]; -} - static int ts2020_sleep(struct dvb_frontend *fe) { struct ts2020_priv *priv = fe->tuner_priv; + int ret; u8 u8tmp; if (priv->tuner == TS2020_M88TS2020) @@ -130,24 +78,32 @@ static int ts2020_sleep(struct dvb_frontend *fe) else u8tmp = 0x00; - return ts2020_writereg(fe, u8tmp, 0x00); + ret = regmap_write(priv->regmap, u8tmp, 0x00); + if (ret < 0) + return ret; + + /* stop statistics polling */ + if (!priv->dont_poll) + cancel_delayed_work_sync(&priv->stat_work); + return 0; } static int ts2020_init(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct ts2020_priv *priv = fe->tuner_priv; int i; u8 u8tmp; if (priv->tuner == TS2020_M88TS2020) { - ts2020_writereg(fe, 0x42, 0x73); - ts2020_writereg(fe, 0x05, priv->clk_out_div); - ts2020_writereg(fe, 0x20, 0x27); - ts2020_writereg(fe, 0x07, 0x02); - ts2020_writereg(fe, 0x11, 0xff); - ts2020_writereg(fe, 0x60, 0xf9); - ts2020_writereg(fe, 0x08, 0x01); - ts2020_writereg(fe, 0x00, 0x41); + regmap_write(priv->regmap, 0x42, 0x73); + regmap_write(priv->regmap, 0x05, priv->clk_out_div); + regmap_write(priv->regmap, 0x20, 0x27); + regmap_write(priv->regmap, 0x07, 0x02); + regmap_write(priv->regmap, 0x11, 0xff); + regmap_write(priv->regmap, 0x60, 0xf9); + regmap_write(priv->regmap, 0x08, 0x01); + regmap_write(priv->regmap, 0x00, 0x41); } else { static const struct ts2020_reg_val reg_vals[] = { {0x7d, 0x9d}, @@ -163,8 +119,8 @@ static int ts2020_init(struct dvb_frontend *fe) {0x12, 0xa0}, }; - ts2020_writereg(fe, 0x00, 0x01); - ts2020_writereg(fe, 0x00, 0x03); + regmap_write(priv->regmap, 0x00, 0x01); + regmap_write(priv->regmap, 0x00, 0x03); switch (priv->clk_out) { case TS2020_CLK_OUT_DISABLED: @@ -172,7 +128,7 @@ static int ts2020_init(struct dvb_frontend *fe) break; case TS2020_CLK_OUT_ENABLED: u8tmp = 0x70; - ts2020_writereg(fe, 0x05, priv->clk_out_div); + regmap_write(priv->regmap, 0x05, priv->clk_out_div); break; case TS2020_CLK_OUT_ENABLED_XTALOUT: u8tmp = 0x6c; @@ -182,50 +138,61 @@ static int ts2020_init(struct dvb_frontend *fe) break; } - ts2020_writereg(fe, 0x42, u8tmp); + regmap_write(priv->regmap, 0x42, u8tmp); if (priv->loop_through) u8tmp = 0xec; else u8tmp = 0x6c; - ts2020_writereg(fe, 0x62, u8tmp); + regmap_write(priv->regmap, 0x62, u8tmp); for (i = 0; i < ARRAY_SIZE(reg_vals); i++) - ts2020_writereg(fe, reg_vals[i].reg, reg_vals[i].val); + regmap_write(priv->regmap, reg_vals[i].reg, + reg_vals[i].val); } + /* Initialise v5 stats here */ + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + c->strength.stat[0].uvalue = 0; + + /* Start statistics polling by invoking the work function */ + ts2020_stat_work(&priv->stat_work.work); return 0; } static int ts2020_tuner_gate_ctrl(struct dvb_frontend *fe, u8 offset) { + struct ts2020_priv *priv = fe->tuner_priv; int ret; - ret = ts2020_writereg(fe, 0x51, 0x1f - offset); - ret |= ts2020_writereg(fe, 0x51, 0x1f); - ret |= ts2020_writereg(fe, 0x50, offset); - ret |= ts2020_writereg(fe, 0x50, 0x00); + ret = regmap_write(priv->regmap, 0x51, 0x1f - offset); + ret |= regmap_write(priv->regmap, 0x51, 0x1f); + ret |= regmap_write(priv->regmap, 0x50, offset); + ret |= regmap_write(priv->regmap, 0x50, 0x00); msleep(20); return ret; } static int ts2020_set_tuner_rf(struct dvb_frontend *fe) { - int reg; - - reg = ts2020_readreg(fe, 0x3d); - reg &= 0x7f; - if (reg < 0x16) - reg = 0xa1; - else if (reg == 0x16) - reg = 0x99; + struct ts2020_priv *dev = fe->tuner_priv; + int ret; + unsigned int utmp; + + ret = regmap_read(dev->regmap, 0x3d, &utmp); + utmp &= 0x7f; + if (utmp < 0x16) + utmp = 0xa1; + else if (utmp == 0x16) + utmp = 0x99; else - reg = 0xf9; + utmp = 0xf9; - ts2020_writereg(fe, 0x60, reg); - reg = ts2020_tuner_gate_ctrl(fe, 0x08); + regmap_write(dev->regmap, 0x60, utmp); + ret = ts2020_tuner_gate_ctrl(fe, 0x08); - return reg; + return ret; } static int ts2020_set_params(struct dvb_frontend *fe) @@ -233,45 +200,62 @@ static int ts2020_set_params(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct ts2020_priv *priv = fe->tuner_priv; int ret; - u32 frequency = c->frequency; - s32 offset_khz; - u32 symbol_rate = (c->symbol_rate / 1000); + unsigned int utmp; u32 f3db, gdiv28; - u16 value, ndiv, lpf_coeff; - u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf; - u8 lo = 0x01, div4 = 0x0; - - /* Calculate frequency divider */ - if (frequency < priv->frequency_div) { - lo |= 0x10; - div4 = 0x1; - ndiv = (frequency * 14 * 4) / TS2020_XTAL_FREQ; - } else - ndiv = (frequency * 14 * 2) / TS2020_XTAL_FREQ; - ndiv = ndiv + ndiv % 2; - ndiv = ndiv - 1024; + u16 u16tmp, value, lpf_coeff; + u8 buf[3], reg10, lpf_mxdiv, mlpf_max, mlpf_min, nlpf; + unsigned int f_ref_khz, f_vco_khz, div_ref, div_out, pll_n; + unsigned int frequency_khz = c->frequency; + + /* + * Integer-N PLL synthesizer + * kHz is used for all calculations to keep calculations within 32-bit + */ + f_ref_khz = TS2020_XTAL_FREQ; + div_ref = DIV_ROUND_CLOSEST(f_ref_khz, 2000); + + /* select LO output divider */ + if (frequency_khz < priv->frequency_div) { + div_out = 4; + reg10 = 0x10; + } else { + div_out = 2; + reg10 = 0x00; + } + + f_vco_khz = frequency_khz * div_out; + pll_n = f_vco_khz * div_ref / f_ref_khz; + pll_n += pll_n % 2; + priv->frequency_khz = pll_n * f_ref_khz / div_ref / div_out; + + pr_debug("frequency=%u offset=%d f_vco_khz=%u pll_n=%u div_ref=%u div_out=%u\n", + priv->frequency_khz, priv->frequency_khz - c->frequency, + f_vco_khz, pll_n, div_ref, div_out); if (priv->tuner == TS2020_M88TS2020) { lpf_coeff = 2766; - ret = ts2020_writereg(fe, 0x10, 0x80 | lo); + reg10 |= 0x01; + ret = regmap_write(priv->regmap, 0x10, reg10); } else { lpf_coeff = 3200; - ret = ts2020_writereg(fe, 0x10, 0x0b); - ret |= ts2020_writereg(fe, 0x11, 0x40); + reg10 |= 0x0b; + ret = regmap_write(priv->regmap, 0x10, reg10); + ret |= regmap_write(priv->regmap, 0x11, 0x40); } - /* Set frequency divider */ - ret |= ts2020_writereg(fe, 0x01, (ndiv >> 8) & 0xf); - ret |= ts2020_writereg(fe, 0x02, ndiv & 0xff); + u16tmp = pll_n - 1024; + buf[0] = (u16tmp >> 8) & 0xff; + buf[1] = (u16tmp >> 0) & 0xff; + buf[2] = div_ref - 8; + + ret |= regmap_write(priv->regmap, 0x01, buf[0]); + ret |= regmap_write(priv->regmap, 0x02, buf[1]); + ret |= regmap_write(priv->regmap, 0x03, buf[2]); - ret |= ts2020_writereg(fe, 0x03, 0x06); ret |= ts2020_tuner_gate_ctrl(fe, 0x10); if (ret < 0) return -ENODEV; - /* Tuner Frequency Range */ - ret = ts2020_writereg(fe, 0x10, lo); - ret |= ts2020_tuner_gate_ctrl(fe, 0x08); /* Tuner RF */ @@ -279,28 +263,26 @@ static int ts2020_set_params(struct dvb_frontend *fe) ret |= ts2020_set_tuner_rf(fe); gdiv28 = (TS2020_XTAL_FREQ / 1000 * 1694 + 500) / 1000; - ret |= ts2020_writereg(fe, 0x04, gdiv28 & 0xff); + ret |= regmap_write(priv->regmap, 0x04, gdiv28 & 0xff); ret |= ts2020_tuner_gate_ctrl(fe, 0x04); if (ret < 0) return -ENODEV; if (priv->tuner == TS2020_M88TS2022) { - ret = ts2020_writereg(fe, 0x25, 0x00); - ret |= ts2020_writereg(fe, 0x27, 0x70); - ret |= ts2020_writereg(fe, 0x41, 0x09); - ret |= ts2020_writereg(fe, 0x08, 0x0b); + ret = regmap_write(priv->regmap, 0x25, 0x00); + ret |= regmap_write(priv->regmap, 0x27, 0x70); + ret |= regmap_write(priv->regmap, 0x41, 0x09); + ret |= regmap_write(priv->regmap, 0x08, 0x0b); if (ret < 0) return -ENODEV; } - value = ts2020_readreg(fe, 0x26); + regmap_read(priv->regmap, 0x26, &utmp); + value = utmp; - f3db = (symbol_rate * 135) / 200 + 2000; - f3db += FREQ_OFFSET_LOW_SYM_RATE; - if (f3db < 7000) - f3db = 7000; - if (f3db > 40000) - f3db = 40000; + f3db = (c->bandwidth_hz / 1000 / 2) + 2000; + f3db += FREQ_OFFSET_LOW_SYM_RATE; /* FIXME: ~always too wide filter */ + f3db = clamp(f3db, 7000U, 40000U); gdiv28 = gdiv28 * 207 / (value * 2 + 151); mlpf_max = gdiv28 * 135 / 100; @@ -327,19 +309,14 @@ static int ts2020_set_params(struct dvb_frontend *fe) if (lpf_mxdiv > mlpf_max) lpf_mxdiv = mlpf_max; - ret = ts2020_writereg(fe, 0x04, lpf_mxdiv); - ret |= ts2020_writereg(fe, 0x06, nlpf); + ret = regmap_write(priv->regmap, 0x04, lpf_mxdiv); + ret |= regmap_write(priv->regmap, 0x06, nlpf); ret |= ts2020_tuner_gate_ctrl(fe, 0x04); ret |= ts2020_tuner_gate_ctrl(fe, 0x01); msleep(80); - /* calculate offset assuming 96000kHz*/ - offset_khz = (ndiv - ndiv % 2 + 1024) * TS2020_XTAL_FREQ - / (6 + 8) / (div4 + 1) / 2; - - priv->frequency = offset_khz; return (ret < 0) ? -EINVAL : 0; } @@ -347,8 +324,8 @@ static int ts2020_set_params(struct dvb_frontend *fe) static int ts2020_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct ts2020_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; + *frequency = priv->frequency_khz; return 0; } @@ -358,28 +335,164 @@ static int ts2020_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } -/* read TS2020 signal strength */ -static int ts2020_read_signal_strength(struct dvb_frontend *fe, - u16 *signal_strength) +/* + * Get the tuner gain. + * @fe: The front end for which we're determining the gain + * @v_agc: The voltage of the AGC from the demodulator (0-2600mV) + * @_gain: Where to store the gain (in 0.001dB units) + * + * Returns 0 or a negative error code. + */ +static int ts2020_read_tuner_gain(struct dvb_frontend *fe, unsigned v_agc, + __s64 *_gain) +{ + struct ts2020_priv *priv = fe->tuner_priv; + unsigned long gain1, gain2, gain3; + unsigned utmp; + int ret; + + /* Read the RF gain */ + ret = regmap_read(priv->regmap, 0x3d, &utmp); + if (ret < 0) + return ret; + gain1 = utmp & 0x1f; + + /* Read the baseband gain */ + ret = regmap_read(priv->regmap, 0x21, &utmp); + if (ret < 0) + return ret; + gain2 = utmp & 0x1f; + + switch (priv->tuner) { + case TS2020_M88TS2020: + gain1 = clamp_t(long, gain1, 0, 15); + gain2 = clamp_t(long, gain2, 0, 13); + v_agc = clamp_t(long, v_agc, 400, 1100); + + *_gain = -(gain1 * 2330 + + gain2 * 3500 + + v_agc * 24 / 10 * 10 + + 10000); + /* gain in range -19600 to -116850 in units of 0.001dB */ + break; + + case TS2020_M88TS2022: + ret = regmap_read(priv->regmap, 0x66, &utmp); + if (ret < 0) + return ret; + gain3 = (utmp >> 3) & 0x07; + + gain1 = clamp_t(long, gain1, 0, 15); + gain2 = clamp_t(long, gain2, 2, 16); + gain3 = clamp_t(long, gain3, 0, 6); + v_agc = clamp_t(long, v_agc, 600, 1600); + + *_gain = -(gain1 * 2650 + + gain2 * 3380 + + gain3 * 2850 + + v_agc * 176 / 100 * 10 - + 30000); + /* gain in range -47320 to -158950 in units of 0.001dB */ + break; + } + + return 0; +} + +/* + * Get the AGC information from the demodulator and use that to calculate the + * tuner gain. + */ +static int ts2020_get_tuner_gain(struct dvb_frontend *fe, __s64 *_gain) { - u16 sig_reading, sig_strength; - u8 rfgain, bbgain; + struct ts2020_priv *priv = fe->tuner_priv; + int v_agc = 0, ret; + u8 agc_pwm; - rfgain = ts2020_readreg(fe, 0x3d) & 0x1f; - bbgain = ts2020_readreg(fe, 0x21) & 0x1f; + /* Read the AGC PWM rate from the demodulator */ + if (priv->get_agc_pwm) { + ret = priv->get_agc_pwm(fe, &agc_pwm); + if (ret < 0) + return ret; - if (rfgain > 15) - rfgain = 15; - if (bbgain > 13) - bbgain = 13; + switch (priv->tuner) { + case TS2020_M88TS2020: + v_agc = (int)agc_pwm * 20 - 1166; + break; + case TS2020_M88TS2022: + v_agc = (int)agc_pwm * 16 - 670; + break; + } - sig_reading = rfgain * 2 + bbgain * 3; + if (v_agc < 0) + v_agc = 0; + } - sig_strength = 40 + (64 - sig_reading) * 50 / 64 ; + return ts2020_read_tuner_gain(fe, v_agc, _gain); +} - /* cook the value to be suitable for szap-s2 human readable output */ - *signal_strength = sig_strength * 1000; +/* + * Gather statistics on a regular basis + */ +static void ts2020_stat_work(struct work_struct *work) +{ + struct ts2020_priv *priv = container_of(work, struct ts2020_priv, + stat_work.work); + struct i2c_client *client = priv->client; + struct dtv_frontend_properties *c = &priv->fe->dtv_property_cache; + int ret; + + dev_dbg(&client->dev, "\n"); + + ret = ts2020_get_tuner_gain(priv->fe, &c->strength.stat[0].svalue); + if (ret < 0) + goto err; + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + + if (!priv->dont_poll) + schedule_delayed_work(&priv->stat_work, msecs_to_jiffies(2000)); + return; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); +} + +/* + * Read TS2020 signal strength in v3 format. + */ +static int ts2020_read_signal_strength(struct dvb_frontend *fe, + u16 *_signal_strength) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct ts2020_priv *priv = fe->tuner_priv; + unsigned strength; + __s64 gain; + + if (priv->dont_poll) + ts2020_stat_work(&priv->stat_work.work); + + if (c->strength.stat[0].scale == FE_SCALE_NOT_AVAILABLE) { + *_signal_strength = 0; + return 0; + } + + gain = c->strength.stat[0].svalue; + + /* Calculate the signal strength based on the total gain of the tuner */ + if (gain < -85000) + /* 0%: no signal or weak signal */ + strength = 0; + else if (gain < -65000) + /* 0% - 60%: weak signal */ + strength = 0 + div64_s64((85000 + gain) * 3, 1000); + else if (gain < -45000) + /* 60% - 90%: normal signal */ + strength = 60 + div64_s64((65000 + gain) * 3, 2000); + else + /* 90% - 99%: strong signal */ + strength = 90 + div64_s64((45000 + gain), 5000); + + *_signal_strength = strength * 65535 / 100; return 0; } @@ -402,53 +515,50 @@ struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe, const struct ts2020_config *config, struct i2c_adapter *i2c) { - struct ts2020_priv *priv = NULL; - u8 buf; - - priv = kzalloc(sizeof(struct ts2020_priv), GFP_KERNEL); - if (priv == NULL) + struct i2c_client *client; + struct i2c_board_info board_info; + + /* This is only used by ts2020_probe() so can be on the stack */ + struct ts2020_config pdata; + + memcpy(&pdata, config, sizeof(pdata)); + pdata.fe = fe; + pdata.attach_in_use = true; + + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "ts2020", I2C_NAME_SIZE); + board_info.addr = config->tuner_address; + board_info.platform_data = &pdata; + client = i2c_new_device(i2c, &board_info); + if (!client || !client->dev.driver) return NULL; - priv->i2c_address = config->tuner_address; - priv->i2c = i2c; - priv->clk_out = config->clk_out; - priv->clk_out_div = config->clk_out_div; - priv->frequency_div = config->frequency_div; - priv->fe = fe; - fe->tuner_priv = priv; - - if (!priv->frequency_div) - priv->frequency_div = 1060000; - - /* Wake Up the tuner */ - if ((0x03 & ts2020_readreg(fe, 0x00)) == 0x00) { - ts2020_writereg(fe, 0x00, 0x01); - msleep(2); - } + return fe; +} +EXPORT_SYMBOL(ts2020_attach); - ts2020_writereg(fe, 0x00, 0x03); - msleep(2); - - /* Check the tuner version */ - buf = ts2020_readreg(fe, 0x00); - if ((buf == 0x01) || (buf == 0x41) || (buf == 0x81)) { - printk(KERN_INFO "%s: Find tuner TS2020!\n", __func__); - priv->tuner = TS2020_M88TS2020; - } else if ((buf == 0x83) || (buf == 0xc3)) { - printk(KERN_INFO "%s: Find tuner TS2022!\n", __func__); - priv->tuner = TS2020_M88TS2022; - } else { - printk(KERN_ERR "%s: Read tuner reg[0] = %d\n", __func__, buf); - kfree(priv); - return NULL; - } +/* + * We implement own regmap locking due to legacy DVB attach which uses frontend + * gate control callback to control I2C bus access. We can open / close gate and + * serialize whole open / I2C-operation / close sequence at the same. + */ +static void ts2020_regmap_lock(void *__dev) +{ + struct ts2020_priv *dev = __dev; - memcpy(&fe->ops.tuner_ops, &ts2020_tuner_ops, - sizeof(struct dvb_tuner_ops)); + mutex_lock(&dev->regmap_mutex); + if (dev->fe->ops.i2c_gate_ctrl) + dev->fe->ops.i2c_gate_ctrl(dev->fe, 1); +} - return fe; +static void ts2020_regmap_unlock(void *__dev) +{ + struct ts2020_priv *dev = __dev; + + if (dev->fe->ops.i2c_gate_ctrl) + dev->fe->ops.i2c_gate_ctrl(dev->fe, 0); + mutex_unlock(&dev->regmap_mutex); } -EXPORT_SYMBOL(ts2020_attach); static int ts2020_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -467,38 +577,54 @@ static int ts2020_probe(struct i2c_client *client, goto err; } + /* create regmap */ + mutex_init(&dev->regmap_mutex); + dev->regmap_config.reg_bits = 8, + dev->regmap_config.val_bits = 8, + dev->regmap_config.lock = ts2020_regmap_lock, + dev->regmap_config.unlock = ts2020_regmap_unlock, + dev->regmap_config.lock_arg = dev, + dev->regmap = regmap_init_i2c(client, &dev->regmap_config); + if (IS_ERR(dev->regmap)) { + ret = PTR_ERR(dev->regmap); + goto err_kfree; + } + dev->i2c = client->adapter; dev->i2c_address = client->addr; + dev->loop_through = pdata->loop_through; dev->clk_out = pdata->clk_out; dev->clk_out_div = pdata->clk_out_div; + dev->dont_poll = pdata->dont_poll; dev->frequency_div = pdata->frequency_div; dev->fe = fe; + dev->get_agc_pwm = pdata->get_agc_pwm; fe->tuner_priv = dev; + dev->client = client; + INIT_DELAYED_WORK(&dev->stat_work, ts2020_stat_work); /* check if the tuner is there */ - ret = ts2020_readreg(fe, 0x00); - if (ret < 0) - goto err; - utmp = ret; + ret = regmap_read(dev->regmap, 0x00, &utmp); + if (ret) + goto err_regmap_exit; if ((utmp & 0x03) == 0x00) { - ret = ts2020_writereg(fe, 0x00, 0x01); + ret = regmap_write(dev->regmap, 0x00, 0x01); if (ret) - goto err; + goto err_regmap_exit; usleep_range(2000, 50000); } - ret = ts2020_writereg(fe, 0x00, 0x03); + ret = regmap_write(dev->regmap, 0x00, 0x03); if (ret) - goto err; + goto err_regmap_exit; usleep_range(2000, 50000); - ret = ts2020_readreg(fe, 0x00); - if (ret < 0) - goto err; - utmp = ret; + ret = regmap_read(dev->regmap, 0x00, &utmp); + if (ret) + goto err_regmap_exit; dev_dbg(&client->dev, "chip_id=%02x\n", utmp); @@ -520,7 +646,7 @@ static int ts2020_probe(struct i2c_client *client, break; default: ret = -ENODEV; - goto err; + goto err_regmap_exit; } if (dev->tuner == TS2020_M88TS2022) { @@ -530,63 +656,64 @@ static int ts2020_probe(struct i2c_client *client, break; case TS2020_CLK_OUT_ENABLED: u8tmp = 0x70; - ret = ts2020_writereg(fe, 0x05, dev->clk_out_div); + ret = regmap_write(dev->regmap, 0x05, dev->clk_out_div); if (ret) - goto err; + goto err_regmap_exit; break; case TS2020_CLK_OUT_ENABLED_XTALOUT: u8tmp = 0x6c; break; default: ret = -EINVAL; - goto err; + goto err_regmap_exit; } - ret = ts2020_writereg(fe, 0x42, u8tmp); + ret = regmap_write(dev->regmap, 0x42, u8tmp); if (ret) - goto err; + goto err_regmap_exit; if (dev->loop_through) u8tmp = 0xec; else u8tmp = 0x6c; - ret = ts2020_writereg(fe, 0x62, u8tmp); + ret = regmap_write(dev->regmap, 0x62, u8tmp); if (ret) - goto err; + goto err_regmap_exit; } /* sleep */ - ret = ts2020_writereg(fe, 0x00, 0x00); + ret = regmap_write(dev->regmap, 0x00, 0x00); if (ret) - goto err; + goto err_regmap_exit; dev_info(&client->dev, "Montage Technology %s successfully identified\n", chip_str); memcpy(&fe->ops.tuner_ops, &ts2020_tuner_ops, sizeof(struct dvb_tuner_ops)); - fe->ops.tuner_ops.release = NULL; + if (!pdata->attach_in_use) + fe->ops.tuner_ops.release = NULL; i2c_set_clientdata(client, dev); return 0; +err_regmap_exit: + regmap_exit(dev->regmap); +err_kfree: + kfree(dev); err: dev_dbg(&client->dev, "failed=%d\n", ret); - kfree(dev); return ret; } static int ts2020_remove(struct i2c_client *client) { struct ts2020_priv *dev = i2c_get_clientdata(client); - struct dvb_frontend *fe = dev->fe; dev_dbg(&client->dev, "\n"); - memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = NULL; + regmap_exit(dev->regmap); kfree(dev); - return 0; } diff --git a/drivers/media/dvb-frontends/ts2020.h b/drivers/media/dvb-frontends/ts2020.h index 1714af9..9220e5c 100644 --- a/drivers/media/dvb-frontends/ts2020.h +++ b/drivers/media/dvb-frontends/ts2020.h @@ -32,7 +32,7 @@ struct ts2020_config { /* * RF loop-through */ - u8 loop_through:1; + bool loop_through:1; /* * clock output @@ -48,14 +48,27 @@ struct ts2020_config { */ u8 clk_out_div:5; + /* Set to true to suppress stat polling */ + bool dont_poll:1; + /* * pointer to DVB frontend */ struct dvb_frontend *fe; + + /* + * driver private, do not set value + */ + u8 attach_in_use:1; + + /* Operation to be called by the ts2020 driver to get the value of the + * AGC PWM tuner input as theoretically output by the demodulator. + */ + int (*get_agc_pwm)(struct dvb_frontend *fe, u8 *_agc_pwm); }; +/* Do not add new ts2020_attach() users! Use I2C bindings instead. */ #if IS_REACHABLE(CONFIG_DVB_TS2020) - extern struct dvb_frontend *ts2020_attach( struct dvb_frontend *fe, const struct ts2020_config *config, diff --git a/drivers/media/dvb-frontends/ves1820.c b/drivers/media/dvb-frontends/ves1820.c index bb42b56..aacfdda 100644 --- a/drivers/media/dvb-frontends/ves1820.c +++ b/drivers/media/dvb-frontends/ves1820.c @@ -90,7 +90,8 @@ static u8 ves1820_readreg(struct ves1820_state *state, u8 reg) return b1[0]; } -static int ves1820_setup_reg0(struct ves1820_state *state, u8 reg0, fe_spectral_inversion_t inversion) +static int ves1820_setup_reg0(struct ves1820_state *state, + u8 reg0, enum fe_spectral_inversion inversion) { reg0 |= state->reg0 & 0x62; @@ -237,7 +238,8 @@ static int ves1820_set_parameters(struct dvb_frontend *fe) return 0; } -static int ves1820_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int ves1820_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct ves1820_state* state = fe->demodulator_priv; int sync; diff --git a/drivers/media/dvb-frontends/ves1x93.c b/drivers/media/dvb-frontends/ves1x93.c index 9c17eac..5269523 100644 --- a/drivers/media/dvb-frontends/ves1x93.c +++ b/drivers/media/dvb-frontends/ves1x93.c @@ -41,7 +41,7 @@ struct ves1x93_state { struct dvb_frontend frontend; /* previous uncorrected block counter */ - fe_spectral_inversion_t inversion; + enum fe_spectral_inversion inversion; u8 *init_1x93_tab; u8 *init_1x93_wtab; u8 tab_size; @@ -130,7 +130,8 @@ static int ves1x93_clr_bit (struct ves1x93_state* state) return 0; } -static int ves1x93_set_inversion (struct ves1x93_state* state, fe_spectral_inversion_t inversion) +static int ves1x93_set_inversion(struct ves1x93_state *state, + enum fe_spectral_inversion inversion) { u8 val; @@ -156,7 +157,7 @@ static int ves1x93_set_inversion (struct ves1x93_state* state, fe_spectral_inver return ves1x93_writereg (state, 0x0c, (state->init_1x93_tab[0x0c] & 0x3f) | val); } -static int ves1x93_set_fec (struct ves1x93_state* state, fe_code_rate_t fec) +static int ves1x93_set_fec(struct ves1x93_state *state, enum fe_code_rate fec) { if (fec == FEC_AUTO) return ves1x93_writereg (state, 0x0d, 0x08); @@ -166,7 +167,7 @@ static int ves1x93_set_fec (struct ves1x93_state* state, fe_code_rate_t fec) return ves1x93_writereg (state, 0x0d, fec - FEC_1_2); } -static fe_code_rate_t ves1x93_get_fec (struct ves1x93_state* state) +static enum fe_code_rate ves1x93_get_fec(struct ves1x93_state *state) { return FEC_1_2 + ((ves1x93_readreg (state, 0x0d) >> 4) & 0x7); } @@ -281,7 +282,8 @@ static int ves1x93_init (struct dvb_frontend* fe) return 0; } -static int ves1x93_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int ves1x93_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct ves1x93_state* state = fe->demodulator_priv; @@ -297,7 +299,8 @@ static int ves1x93_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag } } -static int ves1x93_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int ves1x93_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct ves1x93_state* state = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/zl10353.c b/drivers/media/dvb-frontends/zl10353.c index 82946cd..ef9764a 100644 --- a/drivers/media/dvb-frontends/zl10353.c +++ b/drivers/media/dvb-frontends/zl10353.c @@ -462,7 +462,7 @@ static int zl10353_get_parameters(struct dvb_frontend *fe) return 0; } -static int zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int zl10353_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct zl10353_state *state = fe->demodulator_priv; int s6, s7, s8; @@ -533,13 +533,13 @@ static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr) static int zl10353_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { struct zl10353_state *state = fe->demodulator_priv; - u32 ubl = 0; + u32 ubl = 0; - ubl = zl10353_read_register(state, RS_UBC_1) << 8 | - zl10353_read_register(state, RS_UBC_0); + ubl = zl10353_read_register(state, RS_UBC_1) << 8 | + zl10353_read_register(state, RS_UBC_0); - state->ucblocks += ubl; - *ucblocks = state->ucblocks; + state->ucblocks += ubl; + *ucblocks = state->ucblocks; return 0; } diff --git a/drivers/media/firewire/firedtv-fe.c b/drivers/media/firewire/firedtv-fe.c index 6fe9793..17acda6 100644 --- a/drivers/media/firewire/firedtv-fe.c +++ b/drivers/media/firewire/firedtv-fe.c @@ -61,12 +61,12 @@ static int fdtv_diseqc_send_master_cmd(struct dvb_frontend *fe, } static int fdtv_diseqc_send_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t minicmd) + enum fe_sec_mini_cmd minicmd) { return 0; } -static int fdtv_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +static int fdtv_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) { struct firedtv *fdtv = fe->sec_priv; @@ -75,7 +75,7 @@ static int fdtv_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) } static int fdtv_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct firedtv *fdtv = fe->sec_priv; @@ -83,7 +83,7 @@ static int fdtv_set_voltage(struct dvb_frontend *fe, return 0; } -static int fdtv_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int fdtv_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct firedtv *fdtv = fe->sec_priv; struct firedtv_tuner_status stat; diff --git a/drivers/media/firewire/firedtv.h b/drivers/media/firewire/firedtv.h index 346a85b..345d1eda 100644 --- a/drivers/media/firewire/firedtv.h +++ b/drivers/media/firewire/firedtv.h @@ -99,8 +99,8 @@ struct firedtv { s8 isochannel; struct fdtv_ir_context *ir_context; - fe_sec_voltage_t voltage; - fe_sec_tone_mode_t tone; + enum fe_sec_voltage voltage; + enum fe_sec_tone_mode tone; struct mutex demux_mutex; unsigned long channel_active; diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 6f30ea7..71ee8f5 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -196,7 +196,8 @@ config VIDEO_ADV7183 config VIDEO_ADV7604 tristate "Analog Devices ADV7604 decoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && GPIOLIB + select HDMI ---help--- Support for the Analog Devices ADV7604 video decoder. @@ -424,6 +425,7 @@ config VIDEO_ADV7393 config VIDEO_ADV7511 tristate "Analog Devices ADV7511 encoder" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + select HDMI ---help--- Support for the Analog Devices ADV7511 video encoder. diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c index 873fe19..c70abab 100644 --- a/drivers/media/i2c/adp1653.c +++ b/drivers/media/i2c/adp1653.c @@ -8,6 +8,7 @@ * Contributors: * Sakari Ailus <sakari.ailus@iki.fi> * Tuukka Toivonen <tuukkat76@gmail.com> + * Pavel Machek <pavel@ucw.cz> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -34,6 +35,8 @@ #include <linux/module.h> #include <linux/i2c.h> #include <linux/slab.h> +#include <linux/of.h> +#include <linux/gpio/consumer.h> #include <media/adp1653.h> #include <media/v4l2-device.h> @@ -308,16 +311,28 @@ __adp1653_set_power(struct adp1653_flash *flash, int on) { int ret; - ret = flash->platform_data->power(&flash->subdev, on); - if (ret < 0) - return ret; + if (flash->platform_data->power) { + ret = flash->platform_data->power(&flash->subdev, on); + if (ret < 0) + return ret; + } else { + gpiod_set_value(flash->platform_data->enable_gpio, on); + if (on) + /* Some delay is apparently required. */ + udelay(20); + } if (!on) return 0; ret = adp1653_init_device(flash); - if (ret < 0) + if (ret >= 0) + return ret; + + if (flash->platform_data->power) flash->platform_data->power(&flash->subdev, 0); + else + gpiod_set_value(flash->platform_data->enable_gpio, 0); return ret; } @@ -407,21 +422,85 @@ static int adp1653_resume(struct device *dev) #endif /* CONFIG_PM */ +static int adp1653_of_init(struct i2c_client *client, + struct adp1653_flash *flash, + struct device_node *node) +{ + struct adp1653_platform_data *pd; + struct device_node *child; + + pd = devm_kzalloc(&client->dev, sizeof(*pd), GFP_KERNEL); + if (!pd) + return -ENOMEM; + flash->platform_data = pd; + + child = of_get_child_by_name(node, "flash"); + if (!child) + return -EINVAL; + + if (of_property_read_u32(child, "flash-timeout-us", + &pd->max_flash_timeout)) + goto err; + + if (of_property_read_u32(child, "flash-max-microamp", + &pd->max_flash_intensity)) + goto err; + + pd->max_flash_intensity /= 1000; + + if (of_property_read_u32(child, "led-max-microamp", + &pd->max_torch_intensity)) + goto err; + + pd->max_torch_intensity /= 1000; + of_node_put(child); + + child = of_get_child_by_name(node, "indicator"); + if (!child) + return -EINVAL; + + if (of_property_read_u32(child, "led-max-microamp", + &pd->max_indicator_intensity)) + goto err; + + of_node_put(child); + + pd->enable_gpio = devm_gpiod_get(&client->dev, "enable"); + if (!pd->enable_gpio) { + dev_err(&client->dev, "Error getting GPIO\n"); + return -EINVAL; + } + + return 0; +err: + dev_err(&client->dev, "Required property not found\n"); + of_node_put(child); + return -EINVAL; +} + + static int adp1653_probe(struct i2c_client *client, const struct i2c_device_id *devid) { struct adp1653_flash *flash; int ret; - /* we couldn't work without platform data */ - if (client->dev.platform_data == NULL) - return -ENODEV; - flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL); if (flash == NULL) return -ENOMEM; - flash->platform_data = client->dev.platform_data; + if (client->dev.of_node) { + ret = adp1653_of_init(client, flash, client->dev.of_node); + if (ret) + return ret; + } else { + if (!client->dev.platform_data) { + dev_err(&client->dev, + "Neither DT not platform data provided\n"); + return EINVAL; + } + flash->platform_data = client->dev.platform_data; + } mutex_init(&flash->power_lock); @@ -442,6 +521,7 @@ static int adp1653_probe(struct i2c_client *client, return 0; free_and_quit: + dev_err(&client->dev, "adp1653: failed to register device\n"); v4l2_ctrl_handler_free(&flash->ctrls); return ret; } @@ -464,7 +544,7 @@ static const struct i2c_device_id adp1653_id_table[] = { }; MODULE_DEVICE_TABLE(i2c, adp1653_id_table); -static struct dev_pm_ops adp1653_pm_ops = { +static const struct dev_pm_ops adp1653_pm_ops = { .suspend = adp1653_suspend, .resume = adp1653_resume, }; diff --git a/drivers/media/i2c/adv7170.c b/drivers/media/i2c/adv7170.c index 40a1a95..f0d3f5a 100644 --- a/drivers/media/i2c/adv7170.c +++ b/drivers/media/i2c/adv7170.c @@ -262,21 +262,27 @@ static int adv7170_s_routing(struct v4l2_subdev *sd, return 0; } -static int adv7170_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int adv7170_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(adv7170_codes)) + if (code->pad || code->index >= ARRAY_SIZE(adv7170_codes)) return -EINVAL; - *code = adv7170_codes[index]; + code->code = adv7170_codes[code->index]; return 0; } -static int adv7170_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int adv7170_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; u8 val = adv7170_read(sd, 0x7); + if (format->pad) + return -EINVAL; + if ((val & 0x40) == (1 << 6)) mf->code = MEDIA_BUS_FMT_UYVY8_1X16; else @@ -290,11 +296,16 @@ static int adv7170_g_fmt(struct v4l2_subdev *sd, return 0; } -static int adv7170_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int adv7170_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; u8 val = adv7170_read(sd, 0x7); - int ret; + int ret = 0; + + if (format->pad) + return -EINVAL; switch (mf->code) { case MEDIA_BUS_FMT_UYVY8_2X8: @@ -311,7 +322,8 @@ static int adv7170_s_fmt(struct v4l2_subdev *sd, return -EINVAL; } - ret = adv7170_write(sd, 0x7, val); + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + ret = adv7170_write(sd, 0x7, val); return ret; } @@ -321,13 +333,17 @@ static int adv7170_s_fmt(struct v4l2_subdev *sd, static const struct v4l2_subdev_video_ops adv7170_video_ops = { .s_std_output = adv7170_s_std_output, .s_routing = adv7170_s_routing, - .s_mbus_fmt = adv7170_s_fmt, - .g_mbus_fmt = adv7170_g_fmt, - .enum_mbus_fmt = adv7170_enum_fmt, +}; + +static const struct v4l2_subdev_pad_ops adv7170_pad_ops = { + .enum_mbus_code = adv7170_enum_mbus_code, + .get_fmt = adv7170_get_fmt, + .set_fmt = adv7170_set_fmt, }; static const struct v4l2_subdev_ops adv7170_ops = { .video = &adv7170_video_ops, + .pad = &adv7170_pad_ops, }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/i2c/adv7175.c b/drivers/media/i2c/adv7175.c index d220af5..321834b 100644 --- a/drivers/media/i2c/adv7175.c +++ b/drivers/media/i2c/adv7175.c @@ -300,21 +300,27 @@ static int adv7175_s_routing(struct v4l2_subdev *sd, return 0; } -static int adv7175_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int adv7175_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(adv7175_codes)) + if (code->pad || code->index >= ARRAY_SIZE(adv7175_codes)) return -EINVAL; - *code = adv7175_codes[index]; + code->code = adv7175_codes[code->index]; return 0; } -static int adv7175_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int adv7175_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; u8 val = adv7175_read(sd, 0x7); + if (format->pad) + return -EINVAL; + if ((val & 0x40) == (1 << 6)) mf->code = MEDIA_BUS_FMT_UYVY8_1X16; else @@ -328,11 +334,16 @@ static int adv7175_g_fmt(struct v4l2_subdev *sd, return 0; } -static int adv7175_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int adv7175_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; u8 val = adv7175_read(sd, 0x7); - int ret; + int ret = 0; + + if (format->pad) + return -EINVAL; switch (mf->code) { case MEDIA_BUS_FMT_UYVY8_2X8: @@ -349,7 +360,8 @@ static int adv7175_s_fmt(struct v4l2_subdev *sd, return -EINVAL; } - ret = adv7175_write(sd, 0x7, val); + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + ret = adv7175_write(sd, 0x7, val); return ret; } @@ -374,14 +386,18 @@ static const struct v4l2_subdev_core_ops adv7175_core_ops = { static const struct v4l2_subdev_video_ops adv7175_video_ops = { .s_std_output = adv7175_s_std_output, .s_routing = adv7175_s_routing, - .s_mbus_fmt = adv7175_s_fmt, - .g_mbus_fmt = adv7175_g_fmt, - .enum_mbus_fmt = adv7175_enum_fmt, +}; + +static const struct v4l2_subdev_pad_ops adv7175_pad_ops = { + .enum_mbus_code = adv7175_enum_mbus_code, + .get_fmt = adv7175_get_fmt, + .set_fmt = adv7175_set_fmt, }; static const struct v4l2_subdev_ops adv7175_ops = { .core = &adv7175_core_ops, .video = &adv7175_video_ops, + .pad = &adv7175_pad_ops, }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c index 28940cc..e2dd161 100644 --- a/drivers/media/i2c/adv7183.c +++ b/drivers/media/i2c/adv7183.c @@ -420,20 +420,26 @@ static int adv7183_g_input_status(struct v4l2_subdev *sd, u32 *status) return 0; } -static int adv7183_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - u32 *code) +static int adv7183_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index > 0) + if (code->pad || code->index > 0) return -EINVAL; - *code = MEDIA_BUS_FMT_UYVY8_2X8; + code->code = MEDIA_BUS_FMT_UYVY8_2X8; return 0; } -static int adv7183_try_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int adv7183_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct adv7183 *decoder = to_adv7183(sd); + struct v4l2_mbus_framefmt *fmt = &format->format; + + if (format->pad) + return -EINVAL; fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; @@ -446,25 +452,23 @@ static int adv7183_try_mbus_fmt(struct v4l2_subdev *sd, fmt->width = 720; fmt->height = 576; } + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + decoder->fmt = *fmt; + else + cfg->try_fmt = *fmt; return 0; } -static int adv7183_s_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int adv7183_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct adv7183 *decoder = to_adv7183(sd); - adv7183_try_mbus_fmt(sd, fmt); - decoder->fmt = *fmt; - return 0; -} - -static int adv7183_g_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) -{ - struct adv7183 *decoder = to_adv7183(sd); + if (format->pad) + return -EINVAL; - *fmt = decoder->fmt; + format->format = decoder->fmt; return 0; } @@ -514,16 +518,19 @@ static const struct v4l2_subdev_video_ops adv7183_video_ops = { .s_routing = adv7183_s_routing, .querystd = adv7183_querystd, .g_input_status = adv7183_g_input_status, - .enum_mbus_fmt = adv7183_enum_mbus_fmt, - .try_mbus_fmt = adv7183_try_mbus_fmt, - .s_mbus_fmt = adv7183_s_mbus_fmt, - .g_mbus_fmt = adv7183_g_mbus_fmt, .s_stream = adv7183_s_stream, }; +static const struct v4l2_subdev_pad_ops adv7183_pad_ops = { + .enum_mbus_code = adv7183_enum_mbus_code, + .get_fmt = adv7183_get_fmt, + .set_fmt = adv7183_set_fmt, +}; + static const struct v4l2_subdev_ops adv7183_ops = { .core = &adv7183_core_ops, .video = &adv7183_video_ops, + .pad = &adv7183_pad_ops, }; static int adv7183_probe(struct i2c_client *client, @@ -533,7 +540,9 @@ static int adv7183_probe(struct i2c_client *client, struct v4l2_subdev *sd; struct v4l2_ctrl_handler *hdl; int ret; - struct v4l2_mbus_framefmt fmt; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; const unsigned *pin_array; /* Check if the adapter supports the needed features */ @@ -603,9 +612,9 @@ static int adv7183_probe(struct i2c_client *client, adv7183_writeregs(sd, adv7183_init_regs, ARRAY_SIZE(adv7183_init_regs)); adv7183_s_std(sd, decoder->std); - fmt.width = 720; - fmt.height = 576; - adv7183_s_mbus_fmt(sd, &fmt); + fmt.format.width = 720; + fmt.format.height = 576; + adv7183_set_fmt(sd, NULL, &fmt); /* initialize the hardware to the default control values */ ret = v4l2_ctrl_handler_setup(hdl); diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c index 12d9320..95bcd40 100644 --- a/drivers/media/i2c/adv7511.c +++ b/drivers/media/i2c/adv7511.c @@ -77,7 +77,7 @@ struct adv7511_state_edid { u32 blocks; /* Number of segments read */ u32 segments; - uint8_t data[EDID_MAX_SEGM * 256]; + u8 data[EDID_MAX_SEGM * 256]; /* Number of EDID read retries left */ unsigned read_retries; bool complete; @@ -89,8 +89,9 @@ struct adv7511_state { struct media_pad pad; struct v4l2_ctrl_handler hdl; int chip_revision; - uint8_t i2c_edid_addr; - uint8_t i2c_cec_addr; + u8 i2c_edid_addr; + u8 i2c_cec_addr; + u8 i2c_pktmem_addr; /* Is the adv7511 powered on? */ bool power_on; /* Did we receive hotplug and rx-sense signals? */ @@ -101,6 +102,7 @@ struct adv7511_state { u32 colorspace; u32 ycbcr_enc; u32 quantization; + u32 xfer_func; /* controls */ struct v4l2_ctrl *hdmi_mode_ctrl; struct v4l2_ctrl *hotplug_ctrl; @@ -108,6 +110,7 @@ struct adv7511_state { struct v4l2_ctrl *have_edid0_ctrl; struct v4l2_ctrl *rgb_quantization_range_ctrl; struct i2c_client *i2c_edid; + struct i2c_client *i2c_pktmem; struct adv7511_state_edid edid; /* Running counter of the number of detected EDIDs (for debugging) */ unsigned edid_detect_counter; @@ -200,7 +203,7 @@ static int adv7511_wr(struct v4l2_subdev *sd, u8 reg, u8 val) /* To set specific bits in the register, a clear-mask is given (to be AND-ed), and then the value-mask (to be OR-ed). */ -static inline void adv7511_wr_and_or(struct v4l2_subdev *sd, u8 reg, uint8_t clr_mask, uint8_t val_mask) +static inline void adv7511_wr_and_or(struct v4l2_subdev *sd, u8 reg, u8 clr_mask, u8 val_mask) { adv7511_wr(sd, reg, (adv7511_rd(sd, reg) & clr_mask) | val_mask); } @@ -222,7 +225,7 @@ static int adv_smbus_read_i2c_block_data(struct i2c_client *client, return ret; } -static inline void adv7511_edid_rd(struct v4l2_subdev *sd, uint16_t len, uint8_t *buf) +static inline void adv7511_edid_rd(struct v4l2_subdev *sd, u16 len, u8 *buf) { struct adv7511_state *state = get_adv7511_state(sd); int i; @@ -237,6 +240,35 @@ static inline void adv7511_edid_rd(struct v4l2_subdev *sd, uint16_t len, uint8_t v4l2_err(sd, "%s: i2c read error\n", __func__); } +static int adv7511_pktmem_rd(struct v4l2_subdev *sd, u8 reg) +{ + struct adv7511_state *state = get_adv7511_state(sd); + + return adv_smbus_read_byte_data(state->i2c_pktmem, reg); +} + +static int adv7511_pktmem_wr(struct v4l2_subdev *sd, u8 reg, u8 val) +{ + struct adv7511_state *state = get_adv7511_state(sd); + int ret; + int i; + + for (i = 0; i < 3; i++) { + ret = i2c_smbus_write_byte_data(state->i2c_pktmem, reg, val); + if (ret == 0) + return 0; + } + v4l2_err(sd, "%s: i2c write error\n", __func__); + return ret; +} + +/* To set specific bits in the register, a clear-mask is given (to be AND-ed), + and then the value-mask (to be OR-ed). */ +static inline void adv7511_pktmem_wr_and_or(struct v4l2_subdev *sd, u8 reg, u8 clr_mask, u8 val_mask) +{ + adv7511_pktmem_wr(sd, reg, (adv7511_pktmem_rd(sd, reg) & clr_mask) | val_mask); +} + static inline bool adv7511_have_hotplug(struct v4l2_subdev *sd) { return adv7511_rd(sd, 0x42) & MASK_ADV7511_HPD_DETECT; @@ -247,7 +279,7 @@ static inline bool adv7511_have_rx_sense(struct v4l2_subdev *sd) return adv7511_rd(sd, 0x42) & MASK_ADV7511_MSEN_DETECT; } -static void adv7511_csc_conversion_mode(struct v4l2_subdev *sd, uint8_t mode) +static void adv7511_csc_conversion_mode(struct v4l2_subdev *sd, u8 mode) { adv7511_wr_and_or(sd, 0x18, 0x9f, (mode & 0x3)<<5); } @@ -291,7 +323,7 @@ static void adv7511_csc_coeff(struct v4l2_subdev *sd, static void adv7511_csc_rgb_full2limit(struct v4l2_subdev *sd, bool enable) { if (enable) { - uint8_t csc_mode = 0; + u8 csc_mode = 0; adv7511_csc_conversion_mode(sd, csc_mode); adv7511_csc_coeff(sd, 4096-564, 0, 0, 256, @@ -414,6 +446,80 @@ static int adv7511_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_regi } #endif +struct adv7511_cfg_read_infoframe { + const char *desc; + u8 present_reg; + u8 present_mask; + u8 header[3]; + u16 payload_addr; +}; + +static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size) +{ + u8 csum = 0; + size_t i; + + /* compute checksum */ + for (i = 0; i < size; i++) + csum += ptr[i]; + + return 256 - csum; +} + +static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_infoframe *cri) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct device *dev = &client->dev; + union hdmi_infoframe frame; + u8 buffer[32]; + u8 len; + int i; + + if (!(adv7511_rd(sd, cri->present_reg) & cri->present_mask)) { + v4l2_info(sd, "%s infoframe not transmitted\n", cri->desc); + return; + } + + memcpy(buffer, cri->header, sizeof(cri->header)); + + len = buffer[2]; + + if (len + 4 > sizeof(buffer)) { + v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, cri->desc, len); + return; + } + + if (cri->payload_addr >= 0x100) { + for (i = 0; i < len; i++) + buffer[i + 4] = adv7511_pktmem_rd(sd, cri->payload_addr + i - 0x100); + } else { + for (i = 0; i < len; i++) + buffer[i + 4] = adv7511_rd(sd, cri->payload_addr + i); + } + buffer[3] = 0; + buffer[3] = hdmi_infoframe_checksum(buffer, len + 4); + + if (hdmi_infoframe_unpack(&frame, buffer) < 0) { + v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc); + return; + } + + hdmi_infoframe_log(KERN_INFO, dev, &frame); +} + +static void adv7511_log_infoframes(struct v4l2_subdev *sd) +{ + static const struct adv7511_cfg_read_infoframe cri[] = { + { "AVI", 0x44, 0x10, { 0x82, 2, 13 }, 0x55 }, + { "Audio", 0x44, 0x08, { 0x84, 1, 10 }, 0x73 }, + { "SDP", 0x40, 0x40, { 0x83, 1, 25 }, 0x103 }, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(cri); i++) + log_infoframe(sd, &cri[i]); +} + static int adv7511_log_status(struct v4l2_subdev *sd) { struct adv7511_state *state = get_adv7511_state(sd); @@ -479,6 +585,7 @@ static int adv7511_log_status(struct v4l2_subdev *sd) manual_cts ? "manual" : "automatic", N, CTS); v4l2_info(sd, "VIC: detected %d, sent %d\n", vic_detect, vic_sent); + adv7511_log_infoframes(sd); } if (state->dv_timings.type == V4L2_DV_BT_656_1120) v4l2_print_dv_timings(sd->name, "timings: ", @@ -487,6 +594,7 @@ static int adv7511_log_status(struct v4l2_subdev *sd) v4l2_info(sd, "no timings set\n"); v4l2_info(sd, "i2c edid addr: 0x%x\n", state->i2c_edid_addr); v4l2_info(sd, "i2c cec addr: 0x%x\n", state->i2c_cec_addr); + v4l2_info(sd, "i2c pktmem addr: 0x%x\n", state->i2c_pktmem_addr); return 0; } @@ -536,6 +644,7 @@ static int adv7511_s_power(struct v4l2_subdev *sd, int on) adv7511_wr(sd, 0xf9, 0x00); adv7511_wr(sd, 0x43, state->i2c_edid_addr); + adv7511_wr(sd, 0x45, state->i2c_pktmem_addr); /* Set number of attempts to read the EDID */ adv7511_wr(sd, 0xc9, 0xf); @@ -545,8 +654,8 @@ static int adv7511_s_power(struct v4l2_subdev *sd, int on) /* Enable interrupts */ static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable) { - uint8_t irqs = MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT; - uint8_t irqs_rd; + u8 irqs = MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT; + u8 irqs_rd; int retries = 100; v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ? "enable" : "disable"); @@ -579,7 +688,7 @@ static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable) /* Interrupt handler */ static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled) { - uint8_t irq_status; + u8 irq_status; /* disable interrupts to prevent a race condition */ adv7511_set_isr(sd, false); @@ -861,11 +970,13 @@ static int adv7511_get_fmt(struct v4l2_subdev *sd, format->format.colorspace = fmt->colorspace; format->format.ycbcr_enc = fmt->ycbcr_enc; format->format.quantization = fmt->quantization; + format->format.xfer_func = fmt->xfer_func; } else { format->format.code = state->fmt_code; format->format.colorspace = state->colorspace; format->format.ycbcr_enc = state->ycbcr_enc; format->format.quantization = state->quantization; + format->format.xfer_func = state->xfer_func; } return 0; @@ -912,6 +1023,7 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd, fmt->colorspace = format->format.colorspace; fmt->ycbcr_enc = format->format.ycbcr_enc; fmt->quantization = format->format.quantization; + fmt->xfer_func = format->format.xfer_func; return 0; } @@ -936,6 +1048,7 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd, state->colorspace = format->format.colorspace; state->ycbcr_enc = format->format.ycbcr_enc; state->quantization = format->format.quantization; + state->xfer_func = format->format.xfer_func; switch (format->format.colorspace) { case V4L2_COLORSPACE_ADOBERGB: @@ -1028,7 +1141,7 @@ static const struct v4l2_subdev_ops adv7511_ops = { }; /* ----------------------------------------------------------------------- */ -static void adv7511_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd, int segment, uint8_t *buf) +static void adv7511_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd, int segment, u8 *buf) { if (debug >= lvl) { int i, j; @@ -1140,7 +1253,7 @@ static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd) { struct adv7511_state *state = get_adv7511_state(sd); /* read hotplug and rx-sense state */ - uint8_t status = adv7511_rd(sd, 0x42); + u8 status = adv7511_rd(sd, 0x42); v4l2_dbg(1, debug, sd, "%s: status: 0x%x%s%s\n", __func__, @@ -1184,9 +1297,9 @@ static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd) } } -static bool edid_block_verify_crc(uint8_t *edid_block) +static bool edid_block_verify_crc(u8 *edid_block) { - uint8_t sum = 0; + u8 sum = 0; int i; for (i = 0; i < 128; i++) @@ -1198,7 +1311,7 @@ static bool edid_verify_crc(struct v4l2_subdev *sd, u32 segment) { struct adv7511_state *state = get_adv7511_state(sd); u32 blocks = state->edid.blocks; - uint8_t *data = state->edid.data; + u8 *data = state->edid.data; if (!edid_block_verify_crc(&data[segment * 256])) return false; @@ -1223,7 +1336,7 @@ static bool edid_verify_header(struct v4l2_subdev *sd, u32 segment) static bool adv7511_check_edid_status(struct v4l2_subdev *sd) { struct adv7511_state *state = get_adv7511_state(sd); - uint8_t edidRdy = adv7511_rd(sd, 0xc5); + u8 edidRdy = adv7511_rd(sd, 0xc5); v4l2_dbg(1, debug, sd, "%s: edid ready (retries: %d)\n", __func__, EDID_MAX_RETRIES - state->edid.read_retries); @@ -1376,6 +1489,7 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * /* EDID and CEC i2c addr */ state->i2c_edid_addr = state->pdata.i2c_edid << 1; state->i2c_cec_addr = state->pdata.i2c_cec << 1; + state->i2c_pktmem_addr = state->pdata.i2c_pktmem << 1; state->chip_revision = adv7511_rd(sd, 0x0); chip_id[0] = adv7511_rd(sd, 0xf5); @@ -1393,12 +1507,19 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * goto err_entity; } + state->i2c_pktmem = i2c_new_dummy(client->adapter, state->i2c_pktmem_addr >> 1); + if (state->i2c_pktmem == NULL) { + v4l2_err(sd, "failed to register pktmem i2c client\n"); + err = -ENOMEM; + goto err_unreg_edid; + } + adv7511_wr(sd, 0xe2, 0x01); /* power down cec section */ state->work_queue = create_singlethread_workqueue(sd->name); if (state->work_queue == NULL) { v4l2_err(sd, "could not create workqueue\n"); err = -ENOMEM; - goto err_unreg_cec; + goto err_unreg_pktmem; } INIT_DELAYED_WORK(&state->edid_handler, adv7511_edid_handler); @@ -1411,7 +1532,9 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * client->addr << 1, client->adapter->name); return 0; -err_unreg_cec: +err_unreg_pktmem: + i2c_unregister_device(state->i2c_pktmem); +err_unreg_edid: i2c_unregister_device(state->i2c_edid); err_entity: media_entity_cleanup(&sd->entity); @@ -1435,6 +1558,7 @@ static int adv7511_remove(struct i2c_client *client) adv7511_init_setup(sd); cancel_delayed_work(&state->edid_handler); i2c_unregister_device(state->i2c_edid); + i2c_unregister_device(state->i2c_pktmem); destroy_workqueue(state->work_queue); v4l2_device_unregister_subdev(sd); media_entity_cleanup(&sd->entity); diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 60ffcf0..808360f 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -29,6 +29,7 @@ #include <linux/delay.h> #include <linux/gpio/consumer.h> +#include <linux/hdmi.h> #include <linux/i2c.h> #include <linux/kernel.h> #include <linux/module.h> @@ -95,6 +96,13 @@ struct adv76xx_format_info { u8 op_format_sel; }; +struct adv76xx_cfg_read_infoframe { + const char *desc; + u8 present_mask; + u8 head_addr; + u8 payload_addr; +}; + struct adv76xx_chip_info { enum adv76xx_type type; @@ -124,6 +132,20 @@ struct adv76xx_chip_info { unsigned int num_recommended_settings[2]; unsigned long page_mask; + + /* Masks for timings */ + unsigned int linewidth_mask; + unsigned int field0_height_mask; + unsigned int field1_height_mask; + unsigned int hfrontporch_mask; + unsigned int hsync_mask; + unsigned int hbackporch_mask; + unsigned int field0_vfrontporch_mask; + unsigned int field1_vfrontporch_mask; + unsigned int field0_vsync_mask; + unsigned int field1_vsync_mask; + unsigned int field0_vbackporch_mask; + unsigned int field1_vbackporch_mask; }; /* @@ -327,6 +349,11 @@ static const struct adv76xx_video_standards adv76xx_prim_mode_hdmi_gr[] = { { }, }; +static const struct v4l2_event adv76xx_ev_fmt = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, +}; + /* ----------------------------------------------------------------------- */ static inline struct adv76xx_state *to_state(struct v4l2_subdev *sd) @@ -1304,12 +1331,12 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), - timings)) + false, timings)) return 0; if (v4l2_detect_gtf(stdi->lcf + 1, hfreq, stdi->lcvs, (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), - state->aspect_ratio, timings)) + false, state->aspect_ratio, timings)) return 0; v4l2_dbg(2, debug, sd, @@ -1504,23 +1531,28 @@ static int adv76xx_query_dv_timings(struct v4l2_subdev *sd, if (is_digital_input(sd)) { timings->type = V4L2_DV_BT_656_1120; - /* FIXME: All masks are incorrect for ADV7611 */ - bt->width = hdmi_read16(sd, 0x07, 0xfff); - bt->height = hdmi_read16(sd, 0x09, 0xfff); + bt->width = hdmi_read16(sd, 0x07, info->linewidth_mask); + bt->height = hdmi_read16(sd, 0x09, info->field0_height_mask); bt->pixelclock = info->read_hdmi_pixelclock(sd); - bt->hfrontporch = hdmi_read16(sd, 0x20, 0x3ff); - bt->hsync = hdmi_read16(sd, 0x22, 0x3ff); - bt->hbackporch = hdmi_read16(sd, 0x24, 0x3ff); - bt->vfrontporch = hdmi_read16(sd, 0x2a, 0x1fff) / 2; - bt->vsync = hdmi_read16(sd, 0x2e, 0x1fff) / 2; - bt->vbackporch = hdmi_read16(sd, 0x32, 0x1fff) / 2; + bt->hfrontporch = hdmi_read16(sd, 0x20, info->hfrontporch_mask); + bt->hsync = hdmi_read16(sd, 0x22, info->hsync_mask); + bt->hbackporch = hdmi_read16(sd, 0x24, info->hbackporch_mask); + bt->vfrontporch = hdmi_read16(sd, 0x2a, + info->field0_vfrontporch_mask) / 2; + bt->vsync = hdmi_read16(sd, 0x2e, info->field0_vsync_mask) / 2; + bt->vbackporch = hdmi_read16(sd, 0x32, + info->field0_vbackporch_mask) / 2; bt->polarities = ((hdmi_read(sd, 0x05) & 0x10) ? V4L2_DV_VSYNC_POS_POL : 0) | ((hdmi_read(sd, 0x05) & 0x20) ? V4L2_DV_HSYNC_POS_POL : 0); if (bt->interlaced == V4L2_DV_INTERLACED) { - bt->height += hdmi_read16(sd, 0x0b, 0xfff); - bt->il_vfrontporch = hdmi_read16(sd, 0x2c, 0x1fff) / 2; - bt->il_vsync = hdmi_read16(sd, 0x30, 0x1fff) / 2; - bt->il_vbackporch = hdmi_read16(sd, 0x34, 0x1fff) / 2; + bt->height += hdmi_read16(sd, 0x0b, + info->field1_height_mask); + bt->il_vfrontporch = hdmi_read16(sd, 0x2c, + info->field1_vfrontporch_mask) / 2; + bt->il_vsync = hdmi_read16(sd, 0x30, + info->field1_vsync_mask) / 2; + bt->il_vbackporch = hdmi_read16(sd, 0x34, + info->field1_vbackporch_mask) / 2; } adv76xx_fill_optional_dv_timings_fields(sd, timings); } else { @@ -1725,11 +1757,11 @@ static int adv76xx_s_routing(struct v4l2_subdev *sd, state->selected_input = input; disable_input(sd); - select_input(sd); - enable_input(sd); + v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, + (void *)&adv76xx_ev_fmt); return 0; } @@ -1896,7 +1928,8 @@ static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled) "%s: fmt_change = 0x%x, fmt_change_digital = 0x%x\n", __func__, fmt_change, fmt_change_digital); - v4l2_subdev_notify(sd, ADV76XX_FMT_CHANGE, NULL); + v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, + (void *)&adv76xx_ev_fmt); if (handled) *handled = true; @@ -2102,46 +2135,67 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) /*********** avi info frame CEA-861-E **************/ -static void print_avi_infoframe(struct v4l2_subdev *sd) +static const struct adv76xx_cfg_read_infoframe adv76xx_cri[] = { + { "AVI", 0x01, 0xe0, 0x00 }, + { "Audio", 0x02, 0xe3, 0x1c }, + { "SDP", 0x04, 0xe6, 0x2a }, + { "Vendor", 0x10, 0xec, 0x54 } +}; + +static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index, + union hdmi_infoframe *frame) { + uint8_t buffer[32]; + u8 len; int i; - u8 buf[14]; - u8 avi_len; - u8 avi_ver; - if (!is_hdmi(sd)) { - v4l2_info(sd, "receive DVI-D signal (AVI infoframe not supported)\n"); - return; + if (!(io_read(sd, 0x60) & adv76xx_cri[index].present_mask)) { + v4l2_info(sd, "%s infoframe not received\n", + adv76xx_cri[index].desc); + return -ENOENT; } - if (!(io_read(sd, 0x60) & 0x01)) { - v4l2_info(sd, "AVI infoframe not received\n"); - return; + + for (i = 0; i < 3; i++) + buffer[i] = infoframe_read(sd, + adv76xx_cri[index].head_addr + i); + + len = buffer[2] + 1; + + if (len + 3 > sizeof(buffer)) { + v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, + adv76xx_cri[index].desc, len); + return -ENOENT; } - if (io_read(sd, 0x83) & 0x01) { - v4l2_info(sd, "AVI infoframe checksum error has occurred earlier\n"); - io_write(sd, 0x85, 0x01); /* clear AVI_INF_CKS_ERR_RAW */ - if (io_read(sd, 0x83) & 0x01) { - v4l2_info(sd, "AVI infoframe checksum error still present\n"); - io_write(sd, 0x85, 0x01); /* clear AVI_INF_CKS_ERR_RAW */ - } + for (i = 0; i < len; i++) + buffer[i + 3] = infoframe_read(sd, + adv76xx_cri[index].payload_addr + i); + + if (hdmi_infoframe_unpack(frame, buffer) < 0) { + v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, + adv76xx_cri[index].desc); + return -ENOENT; } + return 0; +} - avi_len = infoframe_read(sd, 0xe2); - avi_ver = infoframe_read(sd, 0xe1); - v4l2_info(sd, "AVI infoframe version %d (%d byte)\n", - avi_ver, avi_len); +static void adv76xx_log_infoframes(struct v4l2_subdev *sd) +{ + int i; - if (avi_ver != 0x02) + if (!is_hdmi(sd)) { + v4l2_info(sd, "receive DVI-D signal, no infoframes\n"); return; + } - for (i = 0; i < 14; i++) - buf[i] = infoframe_read(sd, i); + for (i = 0; i < ARRAY_SIZE(adv76xx_cri); i++) { + union hdmi_infoframe frame; + struct i2c_client *client = v4l2_get_subdevdata(sd); - v4l2_info(sd, - "\t%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], - buf[8], buf[9], buf[10], buf[11], buf[12], buf[13]); + if (adv76xx_read_infoframe(sd, i, &frame)) + return; + hdmi_infoframe_log(KERN_INFO, &client->dev, &frame); + } } static int adv76xx_log_status(struct v4l2_subdev *sd) @@ -2168,6 +2222,14 @@ static int adv76xx_log_status(struct v4l2_subdev *sd) "invalid", "invalid", "invalid", "invalid", "invalid", "invalid", "invalid", "automatic" }; + static const char * const hdmi_color_space_txt[16] = { + "RGB limited range (16-235)", "RGB full range (0-255)", + "YCbCr Bt.601 (16-235)", "YCbCr Bt.709 (16-235)", + "xvYCC Bt.601", "xvYCC Bt.709", + "YCbCr Bt.601 (0-255)", "YCbCr Bt.709 (0-255)", + "sYCC", "Adobe YCC 601", "AdobeRGB", "invalid", "invalid", + "invalid", "invalid", "invalid" + }; static const char * const rgb_quantization_range_txt[] = { "Automatic", "RGB limited range (16-235)", @@ -2235,11 +2297,12 @@ static int adv76xx_log_status(struct v4l2_subdev *sd) rgb_quantization_range_txt[state->rgb_quantization_range]); v4l2_info(sd, "Input color space: %s\n", input_color_space_txt[reg_io_0x02 >> 4]); - v4l2_info(sd, "Output color space: %s %s, saturator %s\n", + v4l2_info(sd, "Output color space: %s %s, saturator %s, alt-gamma %s\n", (reg_io_0x02 & 0x02) ? "RGB" : "YCbCr", (reg_io_0x02 & 0x04) ? "(16-235)" : "(0-255)", - ((reg_io_0x02 & 0x04) ^ (reg_io_0x02 & 0x01)) ? - "enabled" : "disabled"); + (((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ? + "enabled" : "disabled", + (reg_io_0x02 & 0x08) ? "enabled" : "disabled"); v4l2_info(sd, "Color space conversion: %s\n", csc_coeff_sel_rb[cp_read(sd, info->cp_csc) >> 4]); @@ -2276,8 +2339,9 @@ static int adv76xx_log_status(struct v4l2_subdev *sd) v4l2_info(sd, "AV Mute: %s\n", (hdmi_read(sd, 0x04) & 0x40) ? "on" : "off"); v4l2_info(sd, "Deep color mode: %s\n", deep_color_mode_txt[(hdmi_read(sd, 0x0b) & 0x60) >> 5]); + v4l2_info(sd, "HDMI colorspace: %s\n", hdmi_color_space_txt[hdmi_read(sd, 0x53) & 0xf]); - print_avi_infoframe(sd); + adv76xx_log_infoframes(sd); } return 0; @@ -2567,6 +2631,18 @@ static const struct adv76xx_chip_info adv76xx_chip_info[] = { BIT(ADV76XX_PAGE_EDID) | BIT(ADV76XX_PAGE_HDMI) | BIT(ADV76XX_PAGE_TEST) | BIT(ADV76XX_PAGE_CP) | BIT(ADV7604_PAGE_VDP), + .linewidth_mask = 0xfff, + .field0_height_mask = 0xfff, + .field1_height_mask = 0xfff, + .hfrontporch_mask = 0x3ff, + .hsync_mask = 0x3ff, + .hbackporch_mask = 0x3ff, + .field0_vfrontporch_mask = 0x1fff, + .field0_vsync_mask = 0x1fff, + .field0_vbackporch_mask = 0x1fff, + .field1_vfrontporch_mask = 0x1fff, + .field1_vsync_mask = 0x1fff, + .field1_vbackporch_mask = 0x1fff, }, [ADV7611] = { .type = ADV7611, @@ -2596,17 +2672,29 @@ static const struct adv76xx_chip_info adv76xx_chip_info[] = { BIT(ADV76XX_PAGE_INFOFRAME) | BIT(ADV76XX_PAGE_AFE) | BIT(ADV76XX_PAGE_REP) | BIT(ADV76XX_PAGE_EDID) | BIT(ADV76XX_PAGE_HDMI) | BIT(ADV76XX_PAGE_CP), + .linewidth_mask = 0x1fff, + .field0_height_mask = 0x1fff, + .field1_height_mask = 0x1fff, + .hfrontporch_mask = 0x1fff, + .hsync_mask = 0x1fff, + .hbackporch_mask = 0x1fff, + .field0_vfrontporch_mask = 0x3fff, + .field0_vsync_mask = 0x3fff, + .field0_vbackporch_mask = 0x3fff, + .field1_vfrontporch_mask = 0x3fff, + .field1_vsync_mask = 0x3fff, + .field1_vbackporch_mask = 0x3fff, }, }; -static struct i2c_device_id adv76xx_i2c_id[] = { +static const struct i2c_device_id adv76xx_i2c_id[] = { { "adv7604", (kernel_ulong_t)&adv76xx_chip_info[ADV7604] }, { "adv7611", (kernel_ulong_t)&adv76xx_chip_info[ADV7611] }, { } }; MODULE_DEVICE_TABLE(i2c, adv76xx_i2c_id); -static struct of_device_id adv76xx_of_id[] __maybe_unused = { +static const struct of_device_id adv76xx_of_id[] __maybe_unused = { { .compatible = "adi,adv7611", .data = &adv76xx_chip_info[ADV7611] }, { } }; diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index b5a37fe..4cf79b24 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -56,6 +56,28 @@ MODULE_LICENSE("GPL"); /* ADV7842 system clock frequency */ #define ADV7842_fsc (28636360) +#define ADV7842_RGB_OUT (1 << 1) + +#define ADV7842_OP_FORMAT_SEL_8BIT (0 << 0) +#define ADV7842_OP_FORMAT_SEL_10BIT (1 << 0) +#define ADV7842_OP_FORMAT_SEL_12BIT (2 << 0) + +#define ADV7842_OP_MODE_SEL_SDR_422 (0 << 5) +#define ADV7842_OP_MODE_SEL_DDR_422 (1 << 5) +#define ADV7842_OP_MODE_SEL_SDR_444 (2 << 5) +#define ADV7842_OP_MODE_SEL_DDR_444 (3 << 5) +#define ADV7842_OP_MODE_SEL_SDR_422_2X (4 << 5) +#define ADV7842_OP_MODE_SEL_ADI_CM (5 << 5) + +#define ADV7842_OP_CH_SEL_GBR (0 << 5) +#define ADV7842_OP_CH_SEL_GRB (1 << 5) +#define ADV7842_OP_CH_SEL_BGR (2 << 5) +#define ADV7842_OP_CH_SEL_RGB (3 << 5) +#define ADV7842_OP_CH_SEL_BRG (4 << 5) +#define ADV7842_OP_CH_SEL_RBG (5 << 5) + +#define ADV7842_OP_SWAP_CB_CR (1 << 0) + /* ********************************************************************** * @@ -64,6 +86,14 @@ MODULE_LICENSE("GPL"); ********************************************************************** */ +struct adv7842_format_info { + u32 code; + u8 op_ch_sel; + bool rgb_out; + bool swap_cb_cr; + u8 op_format_sel; +}; + struct adv7842_state { struct adv7842_platform_data pdata; struct v4l2_subdev sd; @@ -72,6 +102,9 @@ struct adv7842_state { enum adv7842_mode mode; struct v4l2_dv_timings timings; enum adv7842_vid_std_select vid_std_select; + + const struct adv7842_format_info *format; + v4l2_std_id norm; struct { u8 edid[256]; @@ -209,6 +242,11 @@ static const struct adv7842_video_standards adv7842_prim_mode_hdmi_gr[] = { { }, }; +static const struct v4l2_event adv7842_ev_fmt = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, +}; + /* ----------------------------------------------------------------------- */ static inline struct adv7842_state *to_state(struct v4l2_subdev *sd) @@ -221,11 +259,21 @@ static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) return &container_of(ctrl->handler, struct adv7842_state, hdl)->sd; } +static inline unsigned hblanking(const struct v4l2_bt_timings *t) +{ + return V4L2_DV_BT_BLANKING_WIDTH(t); +} + static inline unsigned htotal(const struct v4l2_bt_timings *t) { return V4L2_DV_BT_FRAME_WIDTH(t); } +static inline unsigned vblanking(const struct v4l2_bt_timings *t) +{ + return V4L2_DV_BT_BLANKING_HEIGHT(t); +} + static inline unsigned vtotal(const struct v4l2_bt_timings *t) { return V4L2_DV_BT_FRAME_HEIGHT(t); @@ -335,6 +383,12 @@ static inline int io_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 va return io_write(sd, reg, (io_read(sd, reg) & mask) | val); } +static inline int io_write_clr_set(struct v4l2_subdev *sd, + u8 reg, u8 mask, u8 val) +{ + return io_write(sd, reg, (io_read(sd, reg) & ~mask) | val); +} + static inline int avlink_read(struct v4l2_subdev *sd, u8 reg) { struct adv7842_state *state = to_state(sd); @@ -535,6 +589,64 @@ static void main_reset(struct v4l2_subdev *sd) mdelay(5); } +/* ----------------------------------------------------------------------------- + * Format helpers + */ + +static const struct adv7842_format_info adv7842_formats[] = { + { MEDIA_BUS_FMT_RGB888_1X24, ADV7842_OP_CH_SEL_RGB, true, false, + ADV7842_OP_MODE_SEL_SDR_444 | ADV7842_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV8_2X8, ADV7842_OP_CH_SEL_RGB, false, false, + ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YVYU8_2X8, ADV7842_OP_CH_SEL_RGB, false, true, + ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV10_2X10, ADV7842_OP_CH_SEL_RGB, false, false, + ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_YVYU10_2X10, ADV7842_OP_CH_SEL_RGB, false, true, + ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_YUYV12_2X12, ADV7842_OP_CH_SEL_RGB, false, false, + ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_YVYU12_2X12, ADV7842_OP_CH_SEL_RGB, false, true, + ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_UYVY8_1X16, ADV7842_OP_CH_SEL_RBG, false, false, + ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_VYUY8_1X16, ADV7842_OP_CH_SEL_RBG, false, true, + ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV8_1X16, ADV7842_OP_CH_SEL_RGB, false, false, + ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YVYU8_1X16, ADV7842_OP_CH_SEL_RGB, false, true, + ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_UYVY10_1X20, ADV7842_OP_CH_SEL_RBG, false, false, + ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_VYUY10_1X20, ADV7842_OP_CH_SEL_RBG, false, true, + ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_YUYV10_1X20, ADV7842_OP_CH_SEL_RGB, false, false, + ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_YVYU10_1X20, ADV7842_OP_CH_SEL_RGB, false, true, + ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_UYVY12_1X24, ADV7842_OP_CH_SEL_RBG, false, false, + ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_VYUY12_1X24, ADV7842_OP_CH_SEL_RBG, false, true, + ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_YUYV12_1X24, ADV7842_OP_CH_SEL_RGB, false, false, + ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_YVYU12_1X24, ADV7842_OP_CH_SEL_RGB, false, true, + ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_12BIT }, +}; + +static const struct adv7842_format_info * +adv7842_format_info(struct adv7842_state *state, u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(adv7842_formats); ++i) { + if (adv7842_formats[i].code == code) + return &adv7842_formats[i]; + } + + return NULL; +} + /* ----------------------------------------------------------------------- */ static inline bool is_analog_input(struct v4l2_subdev *sd) @@ -1333,12 +1445,12 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), - timings)) + false, timings)) return 0; if (v4l2_detect_gtf(stdi->lcf + 1, hfreq, stdi->lcvs, (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), - state->aspect_ratio, timings)) + false, state->aspect_ratio, timings)) return 0; v4l2_dbg(2, debug, sd, @@ -1440,9 +1552,11 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd, } bt->interlaced = stdi.interlaced ? V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; + bt->standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | + V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT; if (is_digital_input(sd)) { - uint32_t freq; + u32 freq; timings->type = V4L2_DV_BT_656_1120; @@ -1478,6 +1592,10 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd, hdmi_read(sd, 0x31)) / 2; bt->il_vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 + hdmi_read(sd, 0x35)) / 2; + } else { + bt->il_vfrontporch = 0; + bt->il_vsync = 0; + bt->il_vbackporch = 0; } adv7842_fill_optional_dv_timings_fields(sd, timings); } else { @@ -1862,50 +1980,155 @@ static int adv7842_s_routing(struct v4l2_subdev *sd, select_input(sd, state->vid_std_select); enable_input(sd); - v4l2_subdev_notify(sd, ADV7842_FMT_CHANGE, NULL); + v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, + (void *)&adv7842_ev_fmt); return 0; } -static int adv7842_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int adv7842_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index) + if (code->index >= ARRAY_SIZE(adv7842_formats)) return -EINVAL; - /* Good enough for now */ - *code = MEDIA_BUS_FMT_FIXED; + code->code = adv7842_formats[code->index].code; return 0; } -static int adv7842_g_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static void adv7842_fill_format(struct adv7842_state *state, + struct v4l2_mbus_framefmt *format) +{ + memset(format, 0, sizeof(*format)); + + format->width = state->timings.bt.width; + format->height = state->timings.bt.height; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_SRGB; + + if (state->timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) + format->colorspace = (state->timings.bt.height <= 576) ? + V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709; +} + +/* + * Compute the op_ch_sel value required to obtain on the bus the component order + * corresponding to the selected format taking into account bus reordering + * applied by the board at the output of the device. + * + * The following table gives the op_ch_value from the format component order + * (expressed as op_ch_sel value in column) and the bus reordering (expressed as + * adv7842_bus_order value in row). + * + * | GBR(0) GRB(1) BGR(2) RGB(3) BRG(4) RBG(5) + * ----------+------------------------------------------------- + * RGB (NOP) | GBR GRB BGR RGB BRG RBG + * GRB (1-2) | BGR RGB GBR GRB RBG BRG + * RBG (2-3) | GRB GBR BRG RBG BGR RGB + * BGR (1-3) | RBG BRG RGB BGR GRB GBR + * BRG (ROR) | BRG RBG GRB GBR RGB BGR + * GBR (ROL) | RGB BGR RBG BRG GBR GRB + */ +static unsigned int adv7842_op_ch_sel(struct adv7842_state *state) +{ +#define _SEL(a, b, c, d, e, f) { \ + ADV7842_OP_CH_SEL_##a, ADV7842_OP_CH_SEL_##b, ADV7842_OP_CH_SEL_##c, \ + ADV7842_OP_CH_SEL_##d, ADV7842_OP_CH_SEL_##e, ADV7842_OP_CH_SEL_##f } +#define _BUS(x) [ADV7842_BUS_ORDER_##x] + + static const unsigned int op_ch_sel[6][6] = { + _BUS(RGB) /* NOP */ = _SEL(GBR, GRB, BGR, RGB, BRG, RBG), + _BUS(GRB) /* 1-2 */ = _SEL(BGR, RGB, GBR, GRB, RBG, BRG), + _BUS(RBG) /* 2-3 */ = _SEL(GRB, GBR, BRG, RBG, BGR, RGB), + _BUS(BGR) /* 1-3 */ = _SEL(RBG, BRG, RGB, BGR, GRB, GBR), + _BUS(BRG) /* ROR */ = _SEL(BRG, RBG, GRB, GBR, RGB, BGR), + _BUS(GBR) /* ROL */ = _SEL(RGB, BGR, RBG, BRG, GBR, GRB), + }; + + return op_ch_sel[state->pdata.bus_order][state->format->op_ch_sel >> 5]; +} + +static void adv7842_setup_format(struct adv7842_state *state) +{ + struct v4l2_subdev *sd = &state->sd; + + io_write_clr_set(sd, 0x02, 0x02, + state->format->rgb_out ? ADV7842_RGB_OUT : 0); + io_write(sd, 0x03, state->format->op_format_sel | + state->pdata.op_format_mode_sel); + io_write_clr_set(sd, 0x04, 0xe0, adv7842_op_ch_sel(state)); + io_write_clr_set(sd, 0x05, 0x01, + state->format->swap_cb_cr ? ADV7842_OP_SWAP_CB_CR : 0); +} + +static int adv7842_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct adv7842_state *state = to_state(sd); - fmt->width = state->timings.bt.width; - fmt->height = state->timings.bt.height; - fmt->code = MEDIA_BUS_FMT_FIXED; - fmt->field = V4L2_FIELD_NONE; + if (format->pad != ADV7842_PAD_SOURCE) + return -EINVAL; if (state->mode == ADV7842_MODE_SDP) { /* SPD block */ - if (!(sdp_read(sd, 0x5A) & 0x01)) + if (!(sdp_read(sd, 0x5a) & 0x01)) return -EINVAL; - fmt->width = 720; + format->format.code = MEDIA_BUS_FMT_YUYV8_2X8; + format->format.width = 720; /* valid signal */ if (state->norm & V4L2_STD_525_60) - fmt->height = 480; + format->format.height = 480; else - fmt->height = 576; - fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + format->format.height = 576; + format->format.colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; } - fmt->colorspace = V4L2_COLORSPACE_SRGB; - if (state->timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { - fmt->colorspace = (state->timings.bt.height <= 576) ? - V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709; + adv7842_fill_format(state, &format->format); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); + format->format.code = fmt->code; + } else { + format->format.code = state->format->code; + } + + return 0; +} + +static int adv7842_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct adv7842_state *state = to_state(sd); + const struct adv7842_format_info *info; + + if (format->pad != ADV7842_PAD_SOURCE) + return -EINVAL; + + if (state->mode == ADV7842_MODE_SDP) + return adv7842_get_format(sd, cfg, format); + + info = adv7842_format_info(state, format->format.code); + if (info == NULL) + info = adv7842_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); + + adv7842_fill_format(state, &format->format); + format->format.code = info->code; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); + fmt->code = format->format.code; + } else { + state->format = info; + adv7842_setup_format(state); } + return 0; } @@ -1991,7 +2214,8 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled) "%s: fmt_change_cp = 0x%x, fmt_change_digital = 0x%x, fmt_change_sdp = 0x%x\n", __func__, fmt_change_cp, fmt_change_digital, fmt_change_sdp); - v4l2_subdev_notify(sd, ADV7842_FMT_CHANGE, NULL); + v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, + (void *)&adv7842_ev_fmt); if (handled) *handled = true; } @@ -2110,7 +2334,7 @@ struct adv7842_cfg_read_infoframe { static void log_infoframe(struct v4l2_subdev *sd, struct adv7842_cfg_read_infoframe *cri) { int i; - uint8_t buffer[32]; + u8 buffer[32]; union hdmi_infoframe frame; u8 len; struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -2183,7 +2407,7 @@ static const char * const prim_mode_txt[] = { static int adv7842_sdp_log_status(struct v4l2_subdev *sd) { /* SDP (Standard definition processor) block */ - uint8_t sdp_signal_detected = sdp_read(sd, 0x5A) & 0x01; + u8 sdp_signal_detected = sdp_read(sd, 0x5A) & 0x01; v4l2_info(sd, "Chip powered %s\n", no_power(sd) ? "off" : "on"); v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x\n", @@ -2227,10 +2451,10 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd) /* CP block */ struct adv7842_state *state = to_state(sd); struct v4l2_dv_timings timings; - uint8_t reg_io_0x02 = io_read(sd, 0x02); - uint8_t reg_io_0x21 = io_read(sd, 0x21); - uint8_t reg_rep_0x77 = rep_read(sd, 0x77); - uint8_t reg_rep_0x7d = rep_read(sd, 0x7d); + u8 reg_io_0x02 = io_read(sd, 0x02); + u8 reg_io_0x21 = io_read(sd, 0x21); + u8 reg_rep_0x77 = rep_read(sd, 0x77); + u8 reg_rep_0x7d = rep_read(sd, 0x7d); bool audio_pll_locked = hdmi_read(sd, 0x04) & 0x01; bool audio_sample_packet_detect = hdmi_read(sd, 0x18) & 0x01; bool audio_mute = io_read(sd, 0x65) & 0x40; @@ -2302,10 +2526,10 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd) if (no_cp_signal(sd)) { v4l2_info(sd, "STDI: not locked\n"); } else { - uint32_t bl = ((cp_read(sd, 0xb1) & 0x3f) << 8) | cp_read(sd, 0xb2); - uint32_t lcf = ((cp_read(sd, 0xb3) & 0x7) << 8) | cp_read(sd, 0xb4); - uint32_t lcvs = cp_read(sd, 0xb3) >> 3; - uint32_t fcl = ((cp_read(sd, 0xb8) & 0x1f) << 8) | cp_read(sd, 0xb9); + u32 bl = ((cp_read(sd, 0xb1) & 0x3f) << 8) | cp_read(sd, 0xb2); + u32 lcf = ((cp_read(sd, 0xb3) & 0x7) << 8) | cp_read(sd, 0xb4); + u32 lcvs = cp_read(sd, 0xb3) >> 3; + u32 fcl = ((cp_read(sd, 0xb8) & 0x1f) << 8) | cp_read(sd, 0xb9); char hs_pol = ((cp_read(sd, 0xb5) & 0x10) ? ((cp_read(sd, 0xb5) & 0x08) ? '+' : '-') : 'x'); char vs_pol = ((cp_read(sd, 0xb5) & 0x40) ? @@ -2545,14 +2769,11 @@ static int adv7842_core_init(struct v4l2_subdev *sd) 0xf0 | pdata->alt_gamma << 3 | pdata->op_656_range << 2 | - pdata->rgb_out << 1 | pdata->alt_data_sat << 0); - io_write(sd, 0x03, pdata->op_format_sel); - io_write_and_or(sd, 0x04, 0x1f, pdata->op_ch_sel << 5); io_write_and_or(sd, 0x05, 0xf0, pdata->blank_data << 3 | pdata->insert_av_codes << 2 | - pdata->replicate_av_codes << 1 | - pdata->invert_cbcr << 0); + pdata->replicate_av_codes << 1); + adv7842_setup_format(state); /* HDMI audio */ hdmi_write_and_or(sd, 0x1a, 0xf1, 0x08); /* Wait 1 s before unmute */ @@ -2809,13 +3030,12 @@ static const struct v4l2_subdev_video_ops adv7842_video_ops = { .s_dv_timings = adv7842_s_dv_timings, .g_dv_timings = adv7842_g_dv_timings, .query_dv_timings = adv7842_query_dv_timings, - .enum_mbus_fmt = adv7842_enum_mbus_fmt, - .g_mbus_fmt = adv7842_g_mbus_fmt, - .try_mbus_fmt = adv7842_g_mbus_fmt, - .s_mbus_fmt = adv7842_g_mbus_fmt, }; static const struct v4l2_subdev_pad_ops adv7842_pad_ops = { + .enum_mbus_code = adv7842_enum_mbus_code, + .get_fmt = adv7842_get_format, + .set_fmt = adv7842_set_format, .get_edid = adv7842_get_edid, .set_edid = adv7842_set_edid, .enum_dv_timings = adv7842_enum_dv_timings, @@ -2986,6 +3206,7 @@ static int adv7842_probe(struct i2c_client *client, /* platform data */ state->pdata = *pdata; state->timings = cea640x480; + state->format = adv7842_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &adv7842_ops); diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c index 69aeaf3..2984624 100644 --- a/drivers/media/i2c/ak881x.c +++ b/drivers/media/i2c/ak881x.c @@ -93,12 +93,17 @@ static int ak881x_s_register(struct v4l2_subdev *sd, } #endif -static int ak881x_try_g_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ak881x_fill_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct ak881x *ak881x = to_ak881x(client); + if (format->pad) + return -EINVAL; + v4l_bound_align_image(&mf->width, 0, 720, 2, &mf->height, 0, ak881x->lines, 1, 0); mf->field = V4L2_FIELD_INTERLACED; @@ -108,23 +113,14 @@ static int ak881x_try_g_mbus_fmt(struct v4l2_subdev *sd, return 0; } -static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ak881x_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (mf->field != V4L2_FIELD_INTERLACED || - mf->code != MEDIA_BUS_FMT_YUYV8_2X8) + if (code->pad || code->index) return -EINVAL; - return ak881x_try_g_mbus_fmt(sd, mf); -} - -static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) -{ - if (index) - return -EINVAL; - - *code = MEDIA_BUS_FMT_YUYV8_2X8; + code->code = MEDIA_BUS_FMT_YUYV8_2X8; return 0; } @@ -211,18 +207,21 @@ static struct v4l2_subdev_core_ops ak881x_subdev_core_ops = { }; static struct v4l2_subdev_video_ops ak881x_subdev_video_ops = { - .s_mbus_fmt = ak881x_s_mbus_fmt, - .g_mbus_fmt = ak881x_try_g_mbus_fmt, - .try_mbus_fmt = ak881x_try_g_mbus_fmt, .cropcap = ak881x_cropcap, - .enum_mbus_fmt = ak881x_enum_mbus_fmt, .s_std_output = ak881x_s_std_output, .s_stream = ak881x_s_stream, }; +static const struct v4l2_subdev_pad_ops ak881x_subdev_pad_ops = { + .enum_mbus_code = ak881x_enum_mbus_code, + .set_fmt = ak881x_fill_fmt, + .get_fmt = ak881x_fill_fmt, +}; + static struct v4l2_subdev_ops ak881x_subdev_ops = { .core = &ak881x_subdev_core_ops, .video = &ak881x_subdev_video_ops, + .pad = &ak881x_subdev_pad_ops, }; static int ak881x_probe(struct i2c_client *client, diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index bd49644..e15a789 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -971,7 +971,7 @@ static void input_change(struct i2c_client *client) not used by any public broadcast network, force 6.5 MHz carrier to be interpreted as System DK, this avoids DK audio detection instability */ - cx25840_write(client, 0x80b, 0x00); + cx25840_write(client, 0x80b, 0x00); } else if (std & V4L2_STD_SECAM) { /* Autodetect audio standard and audio system */ cx25840_write(client, 0x808, 0xff); @@ -1366,14 +1366,17 @@ static int cx25840_s_ctrl(struct v4l2_ctrl *ctrl) /* ----------------------------------------------------------------------- */ -static int cx25840_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +static int cx25840_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *fmt = &format->format; struct cx25840_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); int HSC, VSC, Vsrc, Hsrc, filter, Vlines; int is_50Hz = !(state->std & V4L2_STD_525_60); - if (fmt->code != MEDIA_BUS_FMT_FIXED) + if (format->pad || fmt->code != MEDIA_BUS_FMT_FIXED) return -EINVAL; fmt->field = V4L2_FIELD_INTERLACED; @@ -1403,6 +1406,8 @@ static int cx25840_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt fmt->width, fmt->height); return -ERANGE; } + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + return 0; HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20); VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); @@ -5068,7 +5073,6 @@ static const struct v4l2_subdev_video_ops cx25840_video_ops = { .s_std = cx25840_s_std, .g_std = cx25840_g_std, .s_routing = cx25840_s_video_routing, - .s_mbus_fmt = cx25840_s_mbus_fmt, .s_stream = cx25840_s_stream, .g_input_status = cx25840_g_input_status, }; @@ -5080,12 +5084,17 @@ static const struct v4l2_subdev_vbi_ops cx25840_vbi_ops = { .g_sliced_fmt = cx25840_g_sliced_fmt, }; +static const struct v4l2_subdev_pad_ops cx25840_pad_ops = { + .set_fmt = cx25840_set_fmt, +}; + static const struct v4l2_subdev_ops cx25840_ops = { .core = &cx25840_core_ops, .tuner = &cx25840_tuner_ops, .audio = &cx25840_audio_ops, .video = &cx25840_video_ops, .vbi = &cx25840_vbi_ops, + .pad = &cx25840_pad_ops, .ir = &cx25840_ir_ops, }; diff --git a/drivers/media/i2c/ml86v7667.c b/drivers/media/i2c/ml86v7667.c index d730786..af5eaf2 100644 --- a/drivers/media/i2c/ml86v7667.c +++ b/drivers/media/i2c/ml86v7667.c @@ -191,21 +191,27 @@ static int ml86v7667_g_input_status(struct v4l2_subdev *sd, u32 *status) return 0; } -static int ml86v7667_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int ml86v7667_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index > 0) + if (code->pad || code->index > 0) return -EINVAL; - *code = MEDIA_BUS_FMT_YUYV8_2X8; + code->code = MEDIA_BUS_FMT_YUYV8_2X8; return 0; } -static int ml86v7667_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int ml86v7667_fill_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct ml86v7667_priv *priv = to_ml86v7667(sd); + struct v4l2_mbus_framefmt *fmt = &format->format; + + if (format->pad) + return -EINVAL; fmt->code = MEDIA_BUS_FMT_YUYV8_2X8; fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; @@ -279,13 +285,15 @@ static struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = { .s_std = ml86v7667_s_std, .querystd = ml86v7667_querystd, .g_input_status = ml86v7667_g_input_status, - .enum_mbus_fmt = ml86v7667_enum_mbus_fmt, - .try_mbus_fmt = ml86v7667_mbus_fmt, - .g_mbus_fmt = ml86v7667_mbus_fmt, - .s_mbus_fmt = ml86v7667_mbus_fmt, .g_mbus_config = ml86v7667_g_mbus_config, }; +static const struct v4l2_subdev_pad_ops ml86v7667_subdev_pad_ops = { + .enum_mbus_code = ml86v7667_enum_mbus_code, + .get_fmt = ml86v7667_fill_fmt, + .set_fmt = ml86v7667_fill_fmt, +}; + static struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = { #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = ml86v7667_g_register, @@ -296,6 +304,7 @@ static struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = { static struct v4l2_subdev_ops ml86v7667_subdev_ops = { .core = &ml86v7667_subdev_core_ops, .video = &ml86v7667_subdev_video_ops, + .pad = &ml86v7667_subdev_pad_ops, }; static int ml86v7667_init(struct ml86v7667_priv *priv) diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c index a10f7f8..57132cd 100644 --- a/drivers/media/i2c/mt9v011.c +++ b/drivers/media/i2c/mt9v011.c @@ -324,19 +324,25 @@ static int mt9v011_reset(struct v4l2_subdev *sd, u32 val) return 0; } -static int mt9v011_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - u32 *code) +static int mt9v011_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index > 0) + if (code->pad || code->index > 0) return -EINVAL; - *code = MEDIA_BUS_FMT_SGRBG8_1X8; + code->code = MEDIA_BUS_FMT_SGRBG8_1X8; return 0; } -static int mt9v011_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +static int mt9v011_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { - if (fmt->code != MEDIA_BUS_FMT_SGRBG8_1X8) + struct v4l2_mbus_framefmt *fmt = &format->format; + struct mt9v011 *core = to_mt9v011(sd); + + if (format->pad || fmt->code != MEDIA_BUS_FMT_SGRBG8_1X8) return -EINVAL; v4l_bound_align_image(&fmt->width, 48, 639, 1, @@ -344,6 +350,15 @@ static int mt9v011_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefm fmt->field = V4L2_FIELD_NONE; fmt->colorspace = V4L2_COLORSPACE_SRGB; + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + core->width = fmt->width; + core->height = fmt->height; + + set_res(sd); + } else { + cfg->try_fmt = *fmt; + } + return 0; } @@ -385,23 +400,6 @@ static int mt9v011_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) return 0; } -static int mt9v011_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) -{ - struct mt9v011 *core = to_mt9v011(sd); - int rc; - - rc = mt9v011_try_mbus_fmt(sd, fmt); - if (rc < 0) - return -EINVAL; - - core->width = fmt->width; - core->height = fmt->height; - - set_res(sd); - - return 0; -} - #ifdef CONFIG_VIDEO_ADV_DEBUG static int mt9v011_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) @@ -469,16 +467,19 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = { }; static const struct v4l2_subdev_video_ops mt9v011_video_ops = { - .enum_mbus_fmt = mt9v011_enum_mbus_fmt, - .try_mbus_fmt = mt9v011_try_mbus_fmt, - .s_mbus_fmt = mt9v011_s_mbus_fmt, .g_parm = mt9v011_g_parm, .s_parm = mt9v011_s_parm, }; +static const struct v4l2_subdev_pad_ops mt9v011_pad_ops = { + .enum_mbus_code = mt9v011_enum_mbus_code, + .set_fmt = mt9v011_set_fmt, +}; + static const struct v4l2_subdev_ops mt9v011_ops = { .core = &mt9v011_core_ops, .video = &mt9v011_video_ops, + .pad = &mt9v011_pad_ops, }; diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c index edebd11..6edffc7 100644 --- a/drivers/media/i2c/ov2659.c +++ b/drivers/media/i2c/ov2659.c @@ -1046,16 +1046,21 @@ static int ov2659_get_fmt(struct v4l2_subdev *sd, { struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov2659 *ov2659 = to_ov2659(sd); - struct v4l2_mbus_framefmt *mf; dev_dbg(&client->dev, "ov2659_get_fmt\n"); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + struct v4l2_mbus_framefmt *mf; + mf = v4l2_subdev_get_try_format(sd, cfg, 0); mutex_lock(&ov2659->lock); fmt->format = *mf; mutex_unlock(&ov2659->lock); return 0; +#else + return -ENOTTY; +#endif } mutex_lock(&ov2659->lock); @@ -1102,7 +1107,7 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_format *fmt) { struct i2c_client *client = v4l2_get_subdevdata(sd); - unsigned int index = ARRAY_SIZE(ov2659_formats); + int index = ARRAY_SIZE(ov2659_formats); struct v4l2_mbus_framefmt *mf = &fmt->format; const struct ov2659_framesize *size = NULL; struct ov2659 *ov2659 = to_ov2659(sd); @@ -1126,8 +1131,12 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd, mutex_lock(&ov2659->lock); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; +#else + return -ENOTTY; +#endif } else { s64 val; @@ -1257,6 +1266,7 @@ static const char * const ov2659_test_pattern_menu[] = { * V4L2 subdev internal operations */ +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static int ov2659_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -1269,6 +1279,7 @@ static int ov2659_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return 0; } +#endif static const struct v4l2_subdev_core_ops ov2659_subdev_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, @@ -1287,6 +1298,7 @@ static const struct v4l2_subdev_pad_ops ov2659_subdev_pad_ops = { .set_fmt = ov2659_set_fmt, }; +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static const struct v4l2_subdev_ops ov2659_subdev_ops = { .core = &ov2659_subdev_core_ops, .video = &ov2659_subdev_video_ops, @@ -1296,6 +1308,7 @@ static const struct v4l2_subdev_ops ov2659_subdev_ops = { static const struct v4l2_subdev_internal_ops ov2659_subdev_internal_ops = { .open = ov2659_open, }; +#endif static int ov2659_detect(struct v4l2_subdev *sd) { @@ -1340,8 +1353,8 @@ static struct ov2659_platform_data * ov2659_get_pdata(struct i2c_client *client) { struct ov2659_platform_data *pdata; + struct v4l2_of_endpoint *bus_cfg; struct device_node *endpoint; - int ret; if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return client->dev.platform_data; @@ -1350,18 +1363,27 @@ ov2659_get_pdata(struct i2c_client *client) if (!endpoint) return NULL; + bus_cfg = v4l2_of_alloc_parse_endpoint(endpoint); + if (IS_ERR(bus_cfg)) { + pdata = NULL; + goto done; + } + pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) goto done; - ret = of_property_read_u64(endpoint, "link-frequencies", - &pdata->link_frequency); - if (ret) { - dev_err(&client->dev, "link-frequencies property not found\n"); + if (!bus_cfg->nr_of_link_frequencies) { + dev_err(&client->dev, + "link-frequencies property not found or too many\n"); pdata = NULL; + goto done; } + pdata->link_frequency = bus_cfg->link_frequencies[0]; + done: + v4l2_of_free_endpoint(bus_cfg); of_node_put(endpoint); return pdata; } @@ -1417,11 +1439,13 @@ static int ov2659_probe(struct i2c_client *client, sd = &ov2659->sd; client->flags |= I2C_CLIENT_SCCB; +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API v4l2_i2c_subdev_init(sd, client, &ov2659_subdev_ops); sd->internal_ops = &ov2659_subdev_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; +#endif #if defined(CONFIG_MEDIA_CONTROLLER) ov2659->pad.flags = MEDIA_PAD_FL_SOURCE; diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index b984752..2d1e25f 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -639,7 +639,7 @@ static struct ov7670_format_struct { } ov7670_formats[] = { { .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, + .colorspace = V4L2_COLORSPACE_SRGB, .regs = ov7670_fmt_yuv422, .cmatrix = { 128, -128, 0, -34, -94, 128 }, }, @@ -899,13 +899,14 @@ static int ov7670_set_hw(struct v4l2_subdev *sd, int hstart, int hstop, } -static int ov7670_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - u32 *code) +static int ov7670_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= N_OV7670_FMTS) + if (code->pad || code->index >= N_OV7670_FMTS) return -EINVAL; - *code = ov7670_formats[index].mbus_code; + code->code = ov7670_formats[code->index].mbus_code; return 0; } @@ -970,17 +971,12 @@ static int ov7670_try_fmt_internal(struct v4l2_subdev *sd, return 0; } -static int ov7670_try_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) -{ - return ov7670_try_fmt_internal(sd, fmt, NULL, NULL); -} - /* * Set a format. */ -static int ov7670_s_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int ov7670_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct ov7670_format_struct *ovfmt; struct ov7670_win_size *wsize; @@ -988,7 +984,18 @@ static int ov7670_s_mbus_fmt(struct v4l2_subdev *sd, unsigned char com7; int ret; - ret = ov7670_try_fmt_internal(sd, fmt, &ovfmt, &wsize); + if (format->pad) + return -EINVAL; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + ret = ov7670_try_fmt_internal(sd, &format->format, NULL, NULL); + if (ret) + return ret; + cfg->try_fmt = format->format; + return 0; + } + + ret = ov7670_try_fmt_internal(sd, &format->format, &ovfmt, &wsize); if (ret) return ret; @@ -1073,10 +1080,33 @@ static int ov7670_enum_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_interval_enum *fie) { + struct ov7670_info *info = to_state(sd); + unsigned int n_win_sizes = info->devtype->n_win_sizes; + int i; + if (fie->pad) return -EINVAL; if (fie->index >= ARRAY_SIZE(ov7670_frame_rates)) return -EINVAL; + + /* + * Check if the width/height is valid. + * + * If a minimum width/height was requested, filter out the capture + * windows that fall outside that. + */ + for (i = 0; i < n_win_sizes; i++) { + struct ov7670_win_size *win = &info->devtype->win_sizes[i]; + + if (info->min_width && win->width < info->min_width) + continue; + if (info->min_height && win->height < info->min_height) + continue; + if (fie->width == win->width && fie->height == win->height) + break; + } + if (i == n_win_sizes) + return -EINVAL; fie->interval.numerator = 1; fie->interval.denominator = ov7670_frame_rates[fie->index]; return 0; @@ -1362,7 +1392,7 @@ static int ov7670_s_exp(struct v4l2_subdev *sd, int value) unsigned char com1, com8, aech, aechh; ret = ov7670_read(sd, REG_COM1, &com1) + - ov7670_read(sd, REG_COM8, &com8); + ov7670_read(sd, REG_COM8, &com8) + ov7670_read(sd, REG_AECHH, &aechh); if (ret) return ret; @@ -1485,9 +1515,6 @@ static const struct v4l2_subdev_core_ops ov7670_core_ops = { }; static const struct v4l2_subdev_video_ops ov7670_video_ops = { - .enum_mbus_fmt = ov7670_enum_mbus_fmt, - .try_mbus_fmt = ov7670_try_mbus_fmt, - .s_mbus_fmt = ov7670_s_mbus_fmt, .s_parm = ov7670_s_parm, .g_parm = ov7670_g_parm, }; @@ -1495,6 +1522,8 @@ static const struct v4l2_subdev_video_ops ov7670_video_ops = { static const struct v4l2_subdev_pad_ops ov7670_pad_ops = { .enum_frame_interval = ov7670_enum_frame_interval, .enum_frame_size = ov7670_enum_frame_size, + .enum_mbus_code = ov7670_enum_mbus_code, + .set_fmt = ov7670_set_fmt, }; static const struct v4l2_subdev_ops ov7670_ops = { diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index 08b234b..53c5ea8 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -1453,7 +1453,7 @@ static int s5c73m3_oif_set_power(struct v4l2_subdev *sd, int on) state->apply_fiv = 1; state->apply_fmt = 1; } - } else if (!on == state->power) { + } else if (state->power == !on) { ret = s5c73m3_set_af_softlanding(state); if (!ret) ret = __s5c73m3_power_off(state); diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index 297ef04..774e0d0 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -491,7 +491,7 @@ static void s5k5baf_write_arr_seq(struct s5k5baf *state, u16 addr, v4l2_dbg(3, debug, c, "i2c_write_seq(count=%d): %*ph\n", count, min(2 * count, 64), seq); - buf[0] = __constant_cpu_to_be16(REG_CMD_BUF); + buf[0] = cpu_to_be16(REG_CMD_BUF); while (count > 0) { int n = min_t(int, count, ARRAY_SIZE(buf) - 1); @@ -1054,7 +1054,7 @@ static int s5k5baf_set_power(struct v4l2_subdev *sd, int on) mutex_lock(&state->lock); - if (!on != state->power) + if (state->power != !on) goto out; if (on) { diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c index de803a1..d0ad6a2 100644 --- a/drivers/media/i2c/s5k6aa.c +++ b/drivers/media/i2c/s5k6aa.c @@ -875,7 +875,7 @@ static int s5k6aa_set_power(struct v4l2_subdev *sd, int on) mutex_lock(&s5k6aa->lock); - if (!on == s5k6aa->power) { + if (s5k6aa->power == !on) { if (on) { ret = __s5k6aa_power_on(s5k6aa); if (!ret) diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c index f14c0e6..ba3c415 100644 --- a/drivers/media/i2c/saa6752hs.c +++ b/drivers/media/i2c/saa6752hs.c @@ -554,10 +554,16 @@ static int saa6752hs_init(struct v4l2_subdev *sd, u32 leading_null_bytes) return 0; } -static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) +static int saa6752hs_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *f = &format->format; struct saa6752hs_state *h = to_state(sd); + if (format->pad) + return -EINVAL; + if (h->video_format == SAA6752HS_VF_UNKNOWN) h->video_format = SAA6752HS_VF_D1; f->width = v4l2_format_table[h->video_format].fmt.pix.width; @@ -568,10 +574,17 @@ static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefm return 0; } -static int saa6752hs_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) +static int saa6752hs_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *f = &format->format; + struct saa6752hs_state *h = to_state(sd); int dist_352, dist_480, dist_720; + if (format->pad) + return -EINVAL; + f->code = MEDIA_BUS_FMT_FIXED; dist_352 = abs(f->width - 352); @@ -592,15 +605,11 @@ static int saa6752hs_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_frame } f->field = V4L2_FIELD_INTERLACED; f->colorspace = V4L2_COLORSPACE_SMPTE170M; - return 0; -} - -static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) -{ - struct saa6752hs_state *h = to_state(sd); - if (f->code != MEDIA_BUS_FMT_FIXED) - return -EINVAL; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *f; + return 0; + } /* FIXME: translate and round width/height into EMPRESS @@ -614,7 +623,9 @@ static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefm D1 | 720x576 | 720x480 */ - saa6752hs_try_mbus_fmt(sd, f); + if (f->code != MEDIA_BUS_FMT_FIXED) + return -EINVAL; + if (f->width == 720) h->video_format = SAA6752HS_VF_D1; else if (f->width == 480) @@ -647,14 +658,17 @@ static const struct v4l2_subdev_core_ops saa6752hs_core_ops = { static const struct v4l2_subdev_video_ops saa6752hs_video_ops = { .s_std = saa6752hs_s_std, - .s_mbus_fmt = saa6752hs_s_mbus_fmt, - .try_mbus_fmt = saa6752hs_try_mbus_fmt, - .g_mbus_fmt = saa6752hs_g_mbus_fmt, +}; + +static const struct v4l2_subdev_pad_ops saa6752hs_pad_ops = { + .get_fmt = saa6752hs_get_fmt, + .set_fmt = saa6752hs_set_fmt, }; static const struct v4l2_subdev_ops saa6752hs_ops = { .core = &saa6752hs_core_ops, .video = &saa6752hs_video_ops, + .pad = &saa6752hs_pad_ops, }; static int saa6752hs_probe(struct i2c_client *client, diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index 7147c8b..0eae5f4 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c @@ -1170,12 +1170,18 @@ static int saa711x_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f return 0; } -static int saa711x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +static int saa711x_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { - if (fmt->code != MEDIA_BUS_FMT_FIXED) + struct v4l2_mbus_framefmt *fmt = &format->format; + + if (format->pad || fmt->code != MEDIA_BUS_FMT_FIXED) return -EINVAL; fmt->field = V4L2_FIELD_INTERLACED; fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + return 0; return saa711x_set_size(sd, fmt->width, fmt->height); } @@ -1603,7 +1609,6 @@ static const struct v4l2_subdev_video_ops saa711x_video_ops = { .s_std = saa711x_s_std, .s_routing = saa711x_s_routing, .s_crystal_freq = saa711x_s_crystal_freq, - .s_mbus_fmt = saa711x_s_mbus_fmt, .s_stream = saa711x_s_stream, .querystd = saa711x_querystd, .g_input_status = saa711x_g_input_status, @@ -1617,12 +1622,17 @@ static const struct v4l2_subdev_vbi_ops saa711x_vbi_ops = { .s_raw_fmt = saa711x_s_raw_fmt, }; +static const struct v4l2_subdev_pad_ops saa711x_pad_ops = { + .set_fmt = saa711x_set_fmt, +}; + static const struct v4l2_subdev_ops saa711x_ops = { .core = &saa711x_core_ops, .tuner = &saa711x_tuner_ops, .audio = &saa711x_audio_ops, .video = &saa711x_video_ops, .vbi = &saa711x_vbi_ops, + .pad = &saa711x_pad_ops, }; #define CHIP_VER_SIZE 16 diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c index 0d0f9a9..7d51736 100644 --- a/drivers/media/i2c/saa717x.c +++ b/drivers/media/i2c/saa717x.c @@ -152,9 +152,9 @@ static u32 saa717x_read(struct v4l2_subdev *sd, u32 reg) i2c_transfer(adap, msgs, 2); if (fw_addr) - value = (mm2[2] & 0xff) | ((mm2[1] & 0xff) >> 8) | ((mm2[0] & 0xff) >> 16); + value = (mm2[2] << 16) | (mm2[1] << 8) | mm2[0]; else - value = mm2[0] & 0xff; + value = mm2[0]; v4l2_dbg(2, debug, sd, "read: reg 0x%03x=0x%08x\n", reg, value); return value; @@ -992,13 +992,16 @@ static int saa717x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_regi } #endif -static int saa717x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +static int saa717x_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *fmt = &format->format; int prescale, h_scale, v_scale; v4l2_dbg(1, debug, sd, "decoder set size\n"); - if (fmt->code != MEDIA_BUS_FMT_FIXED) + if (format->pad || fmt->code != MEDIA_BUS_FMT_FIXED) return -EINVAL; /* FIXME need better bounds checking here */ @@ -1010,6 +1013,9 @@ static int saa717x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt fmt->field = V4L2_FIELD_INTERLACED; fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + return 0; + /* scaling setting */ /* NTSC and interlace only */ prescale = SAA717X_NTSC_WIDTH / fmt->width; @@ -1217,7 +1223,6 @@ static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = { static const struct v4l2_subdev_video_ops saa717x_video_ops = { .s_std = saa717x_s_std, .s_routing = saa717x_s_video_routing, - .s_mbus_fmt = saa717x_s_mbus_fmt, .s_stream = saa717x_s_stream, }; @@ -1225,11 +1230,16 @@ static const struct v4l2_subdev_audio_ops saa717x_audio_ops = { .s_routing = saa717x_s_audio_routing, }; +static const struct v4l2_subdev_pad_ops saa717x_pad_ops = { + .set_fmt = saa717x_set_fmt, +}; + static const struct v4l2_subdev_ops saa717x_ops = { .core = &saa717x_core_ops, .tuner = &saa717x_tuner_ops, .audio = &saa717x_audio_ops, .video = &saa717x_video_ops, + .pad = &saa717x_pad_ops, }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 557f25d..636ebd6 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2975,9 +2975,9 @@ static int smiapp_resume(struct device *dev) static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev) { struct smiapp_platform_data *pdata; - struct v4l2_of_endpoint bus_cfg; + struct v4l2_of_endpoint *bus_cfg; struct device_node *ep; - uint32_t asize; + int i; int rval; if (!dev->of_node) @@ -2987,13 +2987,15 @@ static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev) if (!ep) return NULL; + bus_cfg = v4l2_of_alloc_parse_endpoint(ep); + if (IS_ERR(bus_cfg)) + goto out_err; + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) goto out_err; - v4l2_of_parse_endpoint(ep, &bus_cfg); - - switch (bus_cfg.bus_type) { + switch (bus_cfg->bus_type) { case V4L2_MBUS_CSI2: pdata->csi_signalling_mode = SMIAPP_CSI_SIGNALLING_MODE_CSI2; break; @@ -3002,7 +3004,7 @@ static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev) goto out_err; } - pdata->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; + pdata->lanes = bus_cfg->bus.mipi_csi2.num_data_lanes; dev_dbg(dev, "lanes %u\n", pdata->lanes); /* xshutdown GPIO is optional */ @@ -3022,34 +3024,30 @@ static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev) dev_dbg(dev, "reset %d, nvm %d, clk %d, csi %d\n", pdata->xshutdown, pdata->nvm_size, pdata->ext_clk, pdata->csi_signalling_mode); - rval = of_get_property(ep, "link-frequencies", &asize) ? 0 : -ENOENT; - if (rval) { - dev_warn(dev, "can't get link-frequencies array size\n"); + if (!bus_cfg->nr_of_link_frequencies) { + dev_warn(dev, "no link frequencies defined\n"); goto out_err; } - pdata->op_sys_clock = devm_kzalloc(dev, asize, GFP_KERNEL); + pdata->op_sys_clock = devm_kcalloc( + dev, bus_cfg->nr_of_link_frequencies + 1 /* guardian */, + sizeof(*pdata->op_sys_clock), GFP_KERNEL); if (!pdata->op_sys_clock) { rval = -ENOMEM; goto out_err; } - asize /= sizeof(*pdata->op_sys_clock); - rval = of_property_read_u64_array( - ep, "link-frequencies", pdata->op_sys_clock, asize); - if (rval) { - dev_warn(dev, "can't get link-frequencies\n"); - goto out_err; + for (i = 0; i < bus_cfg->nr_of_link_frequencies; i++) { + pdata->op_sys_clock[i] = bus_cfg->link_frequencies[i]; + dev_dbg(dev, "freq %d: %lld\n", i, pdata->op_sys_clock[i]); } - for (; asize > 0; asize--) - dev_dbg(dev, "freq %d: %lld\n", asize - 1, - pdata->op_sys_clock[asize - 1]); - + v4l2_of_free_endpoint(bus_cfg); of_node_put(ep); return pdata; out_err: + v4l2_of_free_endpoint(bus_cfg); of_node_put(ep); return NULL; } diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/media/i2c/soc_camera/imx074.c index ec89cfa..f68c235 100644 --- a/drivers/media/i2c/soc_camera/imx074.c +++ b/drivers/media/i2c/soc_camera/imx074.c @@ -153,14 +153,24 @@ static int reg_read(struct i2c_client *client, const u16 addr) return buf[0] & 0xff; /* no sign-extension */ } -static int imx074_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int imx074_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; const struct imx074_datafmt *fmt = imx074_find_datafmt(mf->code); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct imx074 *priv = to_imx074(client); + + if (format->pad) + return -EINVAL; dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); if (!fmt) { + /* MIPI CSI could have changed the format, double-check */ + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; mf->code = imx074_colour_fmts[0].code; mf->colorspace = imx074_colour_fmts[0].colorspace; } @@ -169,36 +179,27 @@ static int imx074_try_fmt(struct v4l2_subdev *sd, mf->height = IMX074_HEIGHT; mf->field = V4L2_FIELD_NONE; - return 0; -} - -static int imx074_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct imx074 *priv = to_imx074(client); - - dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); - - /* MIPI CSI could have changed the format, double-check */ - if (!imx074_find_datafmt(mf->code)) - return -EINVAL; - - imx074_try_fmt(sd, mf); - - priv->fmt = imx074_find_datafmt(mf->code); + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + priv->fmt = imx074_find_datafmt(mf->code); + else + cfg->try_fmt = *mf; return 0; } -static int imx074_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int imx074_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct imx074 *priv = to_imx074(client); const struct imx074_datafmt *fmt = priv->fmt; + if (format->pad) + return -EINVAL; + mf->code = fmt->code; mf->colorspace = fmt->colorspace; mf->width = IMX074_WIDTH; @@ -235,13 +236,15 @@ static int imx074_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int imx074_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int imx074_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if ((unsigned int)index >= ARRAY_SIZE(imx074_colour_fmts)) + if (code->pad || + (unsigned int)code->index >= ARRAY_SIZE(imx074_colour_fmts)) return -EINVAL; - *code = imx074_colour_fmts[index].code; + code->code = imx074_colour_fmts[code->index].code; return 0; } @@ -275,10 +278,6 @@ static int imx074_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { .s_stream = imx074_s_stream, - .s_mbus_fmt = imx074_s_fmt, - .g_mbus_fmt = imx074_g_fmt, - .try_mbus_fmt = imx074_try_fmt, - .enum_mbus_fmt = imx074_enum_fmt, .g_crop = imx074_g_crop, .cropcap = imx074_cropcap, .g_mbus_config = imx074_g_mbus_config, @@ -288,9 +287,16 @@ static struct v4l2_subdev_core_ops imx074_subdev_core_ops = { .s_power = imx074_s_power, }; +static const struct v4l2_subdev_pad_ops imx074_subdev_pad_ops = { + .enum_mbus_code = imx074_enum_mbus_code, + .get_fmt = imx074_get_fmt, + .set_fmt = imx074_set_fmt, +}; + static struct v4l2_subdev_ops imx074_subdev_ops = { .core = &imx074_subdev_core_ops, .video = &imx074_subdev_video_ops, + .pad = &imx074_subdev_pad_ops, }; static int imx074_video_probe(struct i2c_client *client) diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c index 2e9a535..4fbdd1e 100644 --- a/drivers/media/i2c/soc_camera/mt9m001.c +++ b/drivers/media/i2c/soc_camera/mt9m001.c @@ -205,7 +205,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) /* * The caller provides a supported format, as verified per - * call to .try_mbus_fmt() + * call to .set_fmt(FORMAT_TRY). */ if (!ret) ret = reg_write(client, MT9M001_COLUMN_START, rect.left); @@ -250,11 +250,16 @@ static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int mt9m001_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9m001_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9m001 *mt9m001 = to_mt9m001(client); + struct v4l2_mbus_framefmt *mf = &format->format; + + if (format->pad) + return -EINVAL; mf->width = mt9m001->rect.width; mf->height = mt9m001->rect.height; @@ -293,13 +298,18 @@ static int mt9m001_s_fmt(struct v4l2_subdev *sd, return ret; } -static int mt9m001_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9m001_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9m001 *mt9m001 = to_mt9m001(client); const struct mt9m001_datafmt *fmt; + if (format->pad) + return -EINVAL; + v4l_bound_align_image(&mf->width, MT9M001_MIN_WIDTH, MT9M001_MAX_WIDTH, 1, &mf->height, MT9M001_MIN_HEIGHT + mt9m001->y_skip_top, @@ -317,6 +327,9 @@ static int mt9m001_try_fmt(struct v4l2_subdev *sd, mf->colorspace = fmt->colorspace; + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return mt9m001_s_fmt(sd, mf); + cfg->try_fmt = *mf; return 0; } @@ -562,16 +575,17 @@ static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { .s_power = mt9m001_s_power, }; -static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int mt9m001_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9m001 *mt9m001 = to_mt9m001(client); - if (index >= mt9m001->num_fmts) + if (code->pad || code->index >= mt9m001->num_fmts) return -EINVAL; - *code = mt9m001->fmts[index].code; + code->code = mt9m001->fmts[code->index].code; return 0; } @@ -611,13 +625,9 @@ static int mt9m001_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { .s_stream = mt9m001_s_stream, - .s_mbus_fmt = mt9m001_s_fmt, - .g_mbus_fmt = mt9m001_g_fmt, - .try_mbus_fmt = mt9m001_try_fmt, .s_crop = mt9m001_s_crop, .g_crop = mt9m001_g_crop, .cropcap = mt9m001_cropcap, - .enum_mbus_fmt = mt9m001_enum_fmt, .g_mbus_config = mt9m001_g_mbus_config, .s_mbus_config = mt9m001_s_mbus_config, }; @@ -626,10 +636,17 @@ static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { .g_skip_top_lines = mt9m001_g_skip_top_lines, }; +static const struct v4l2_subdev_pad_ops mt9m001_subdev_pad_ops = { + .enum_mbus_code = mt9m001_enum_mbus_code, + .get_fmt = mt9m001_get_fmt, + .set_fmt = mt9m001_set_fmt, +}; + static struct v4l2_subdev_ops mt9m001_subdev_ops = { .core = &mt9m001_subdev_core_ops, .video = &mt9m001_subdev_video_ops, .sensor = &mt9m001_subdev_sensor_ops, + .pad = &mt9m001_subdev_pad_ops, }; static int mt9m001_probe(struct i2c_client *client, diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c index 441e0fd..6dfaead 100644 --- a/drivers/media/i2c/soc_camera/mt9m111.c +++ b/drivers/media/i2c/soc_camera/mt9m111.c @@ -447,11 +447,16 @@ static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int mt9m111_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9m111_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); + if (format->pad) + return -EINVAL; + mf->width = mt9m111->width; mf->height = mt9m111->height; mf->code = mt9m111->fmt->code; @@ -531,14 +536,20 @@ static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111, return ret; } -static int mt9m111_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9m111_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); const struct mt9m111_datafmt *fmt; struct v4l2_rect *rect = &mt9m111->rect; bool bayer; + int ret; + + if (format->pad) + return -EINVAL; fmt = mt9m111_find_datafmt(mt9m111, mf->code); @@ -572,20 +583,10 @@ static int mt9m111_try_fmt(struct v4l2_subdev *sd, mf->code = fmt->code; mf->colorspace = fmt->colorspace; - return 0; -} - -static int mt9m111_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - const struct mt9m111_datafmt *fmt; - struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); - struct v4l2_rect *rect = &mt9m111->rect; - int ret; - - mt9m111_try_fmt(sd, mf); - fmt = mt9m111_find_datafmt(mt9m111, mf->code); - /* try_fmt() guarantees fmt != NULL && fmt->code == mf->code */ + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *mf; + return 0; + } ret = mt9m111_setup_geometry(mt9m111, rect, mf->width, mf->height, mf->code); if (!ret) @@ -839,13 +840,14 @@ static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { #endif }; -static int mt9m111_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int mt9m111_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(mt9m111_colour_fmts)) + if (code->pad || code->index >= ARRAY_SIZE(mt9m111_colour_fmts)) return -EINVAL; - *code = mt9m111_colour_fmts[index].code; + code->code = mt9m111_colour_fmts[code->index].code; return 0; } @@ -865,19 +867,22 @@ static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, } static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { - .s_mbus_fmt = mt9m111_s_fmt, - .g_mbus_fmt = mt9m111_g_fmt, - .try_mbus_fmt = mt9m111_try_fmt, .s_crop = mt9m111_s_crop, .g_crop = mt9m111_g_crop, .cropcap = mt9m111_cropcap, - .enum_mbus_fmt = mt9m111_enum_fmt, .g_mbus_config = mt9m111_g_mbus_config, }; +static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = { + .enum_mbus_code = mt9m111_enum_mbus_code, + .get_fmt = mt9m111_get_fmt, + .set_fmt = mt9m111_set_fmt, +}; + static struct v4l2_subdev_ops mt9m111_subdev_ops = { .core = &mt9m111_subdev_core_ops, .video = &mt9m111_subdev_video_ops, + .pad = &mt9m111_subdev_pad_ops, }; /* diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c index 35d9c8d..3b6eeed 100644 --- a/drivers/media/i2c/soc_camera/mt9t031.c +++ b/drivers/media/i2c/soc_camera/mt9t031.c @@ -264,7 +264,7 @@ static int mt9t031_set_params(struct i2c_client *client, /* * The caller provides a supported format, as guaranteed by - * .try_mbus_fmt(), soc_camera_s_crop() and soc_camera_cropcap() + * .set_fmt(FORMAT_TRY), soc_camera_s_crop() and soc_camera_cropcap() */ if (ret >= 0) ret = reg_write(client, MT9T031_COLUMN_START, rect->left); @@ -337,12 +337,17 @@ static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int mt9t031_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9t031_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9t031 *mt9t031 = to_mt9t031(client); + if (format->pad) + return -EINVAL; + mf->width = mt9t031->rect.width / mt9t031->xskip; mf->height = mt9t031->rect.height / mt9t031->yskip; mf->code = MEDIA_BUS_FMT_SBGGR10_1X10; @@ -352,16 +357,36 @@ static int mt9t031_g_fmt(struct v4l2_subdev *sd, return 0; } -static int mt9t031_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +/* + * If a user window larger than sensor window is requested, we'll increase the + * sensor window. + */ +static int mt9t031_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9t031 *mt9t031 = to_mt9t031(client); u16 xskip, yskip; struct v4l2_rect rect = mt9t031->rect; + if (format->pad) + return -EINVAL; + + mf->code = MEDIA_BUS_FMT_SBGGR10_1X10; + mf->colorspace = V4L2_COLORSPACE_SRGB; + v4l_bound_align_image( + &mf->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1, + &mf->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *mf; + return 0; + } + /* - * try_fmt has put width and height within limits. + * Width and height are within limits. * S_FMT: use binning and skipping for scaling */ xskip = mt9t031_skip(&rect.width, mf->width, MT9T031_MAX_WIDTH); @@ -374,23 +399,6 @@ static int mt9t031_s_fmt(struct v4l2_subdev *sd, return mt9t031_set_params(client, &rect, xskip, yskip); } -/* - * If a user window larger than sensor window is requested, we'll increase the - * sensor window. - */ -static int mt9t031_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - v4l_bound_align_image( - &mf->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1, - &mf->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0); - - mf->code = MEDIA_BUS_FMT_SBGGR10_1X10; - mf->colorspace = V4L2_COLORSPACE_SRGB; - - return 0; -} - #ifdef CONFIG_VIDEO_ADV_DEBUG static int mt9t031_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) @@ -672,13 +680,14 @@ static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { #endif }; -static int mt9t031_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int mt9t031_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index) + if (code->pad || code->index) return -EINVAL; - *code = MEDIA_BUS_FMT_SBGGR10_1X10; + code->code = MEDIA_BUS_FMT_SBGGR10_1X10; return 0; } @@ -712,13 +721,9 @@ static int mt9t031_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { .s_stream = mt9t031_s_stream, - .s_mbus_fmt = mt9t031_s_fmt, - .g_mbus_fmt = mt9t031_g_fmt, - .try_mbus_fmt = mt9t031_try_fmt, .s_crop = mt9t031_s_crop, .g_crop = mt9t031_g_crop, .cropcap = mt9t031_cropcap, - .enum_mbus_fmt = mt9t031_enum_fmt, .g_mbus_config = mt9t031_g_mbus_config, .s_mbus_config = mt9t031_s_mbus_config, }; @@ -727,10 +732,17 @@ static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = { .g_skip_top_lines = mt9t031_g_skip_top_lines, }; +static const struct v4l2_subdev_pad_ops mt9t031_subdev_pad_ops = { + .enum_mbus_code = mt9t031_enum_mbus_code, + .get_fmt = mt9t031_get_fmt, + .set_fmt = mt9t031_set_fmt, +}; + static struct v4l2_subdev_ops mt9t031_subdev_ops = { .core = &mt9t031_subdev_core_ops, .video = &mt9t031_subdev_video_ops, .sensor = &mt9t031_subdev_sensor_ops, + .pad = &mt9t031_subdev_pad_ops, }; static int mt9t031_probe(struct i2c_client *client, diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index 64f0836..de10a76 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c @@ -904,12 +904,17 @@ static int mt9t112_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) return mt9t112_set_params(priv, rect, priv->format->code); } -static int mt9t112_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9t112_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9t112_priv *priv = to_mt9t112(client); + if (format->pad) + return -EINVAL; + mf->width = priv->frame.width; mf->height = priv->frame.height; mf->colorspace = priv->format->colorspace; @@ -940,14 +945,19 @@ static int mt9t112_s_fmt(struct v4l2_subdev *sd, return ret; } -static int mt9t112_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9t112_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9t112_priv *priv = to_mt9t112(client); unsigned int top, left; int i; + if (format->pad) + return -EINVAL; + for (i = 0; i < priv->num_formats; i++) if (mt9t112_cfmts[i].code == mf->code) break; @@ -963,19 +973,23 @@ static int mt9t112_try_fmt(struct v4l2_subdev *sd, mf->field = V4L2_FIELD_NONE; + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return mt9t112_s_fmt(sd, mf); + cfg->try_fmt = *mf; return 0; } -static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int mt9t112_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9t112_priv *priv = to_mt9t112(client); - if (index >= priv->num_formats) + if (code->pad || code->index >= priv->num_formats) return -EINVAL; - *code = mt9t112_cfmts[index].code; + code->code = mt9t112_cfmts[code->index].code; return 0; } @@ -1010,23 +1024,26 @@ static int mt9t112_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { .s_stream = mt9t112_s_stream, - .g_mbus_fmt = mt9t112_g_fmt, - .s_mbus_fmt = mt9t112_s_fmt, - .try_mbus_fmt = mt9t112_try_fmt, .cropcap = mt9t112_cropcap, .g_crop = mt9t112_g_crop, .s_crop = mt9t112_s_crop, - .enum_mbus_fmt = mt9t112_enum_fmt, .g_mbus_config = mt9t112_g_mbus_config, .s_mbus_config = mt9t112_s_mbus_config, }; +static const struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = { + .enum_mbus_code = mt9t112_enum_mbus_code, + .get_fmt = mt9t112_get_fmt, + .set_fmt = mt9t112_set_fmt, +}; + /************************************************************************ i2c driver ************************************************************************/ static struct v4l2_subdev_ops mt9t112_subdev_ops = { .core = &mt9t112_subdev_core_ops, .video = &mt9t112_subdev_video_ops, + .pad = &mt9t112_subdev_pad_ops, }; static int mt9t112_camera_probe(struct i2c_client *client) diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index a246d4d..f313774 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c @@ -375,12 +375,17 @@ static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int mt9v022_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9v022_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9v022 *mt9v022 = to_mt9v022(client); + if (format->pad) + return -EINVAL; + mf->width = mt9v022->rect.width; mf->height = mt9v022->rect.height; mf->code = mt9v022->fmt->code; @@ -407,7 +412,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, /* * The caller provides a supported format, as verified per call to - * .try_mbus_fmt(), datawidth is from our supported format list + * .set_fmt(FORMAT_TRY), datawidth is from our supported format list */ switch (mf->code) { case MEDIA_BUS_FMT_Y8_1X8: @@ -437,15 +442,20 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, return ret; } -static int mt9v022_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9v022_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9v022 *mt9v022 = to_mt9v022(client); const struct mt9v022_datafmt *fmt; int align = mf->code == MEDIA_BUS_FMT_SBGGR8_1X8 || mf->code == MEDIA_BUS_FMT_SBGGR10_1X10; + if (format->pad) + return -EINVAL; + v4l_bound_align_image(&mf->width, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH, align, &mf->height, MT9V022_MIN_HEIGHT + mt9v022->y_skip_top, @@ -460,6 +470,9 @@ static int mt9v022_try_fmt(struct v4l2_subdev *sd, mf->colorspace = fmt->colorspace; + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return mt9v022_s_fmt(sd, mf); + cfg->try_fmt = *mf; return 0; } @@ -758,16 +771,17 @@ static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { .s_power = mt9v022_s_power, }; -static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int mt9v022_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9v022 *mt9v022 = to_mt9v022(client); - if (index >= mt9v022->num_fmts) + if (code->pad || code->index >= mt9v022->num_fmts) return -EINVAL; - *code = mt9v022->fmts[index].code; + code->code = mt9v022->fmts[code->index].code; return 0; } @@ -839,13 +853,9 @@ static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { .s_stream = mt9v022_s_stream, - .s_mbus_fmt = mt9v022_s_fmt, - .g_mbus_fmt = mt9v022_g_fmt, - .try_mbus_fmt = mt9v022_try_fmt, .s_crop = mt9v022_s_crop, .g_crop = mt9v022_g_crop, .cropcap = mt9v022_cropcap, - .enum_mbus_fmt = mt9v022_enum_fmt, .g_mbus_config = mt9v022_g_mbus_config, .s_mbus_config = mt9v022_s_mbus_config, }; @@ -854,10 +864,17 @@ static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { .g_skip_top_lines = mt9v022_g_skip_top_lines, }; +static const struct v4l2_subdev_pad_ops mt9v022_subdev_pad_ops = { + .enum_mbus_code = mt9v022_enum_mbus_code, + .get_fmt = mt9v022_get_fmt, + .set_fmt = mt9v022_set_fmt, +}; + static struct v4l2_subdev_ops mt9v022_subdev_ops = { .core = &mt9v022_subdev_core_ops, .video = &mt9v022_subdev_video_ops, .sensor = &mt9v022_subdev_sensor_ops, + .pad = &mt9v022_subdev_pad_ops, }; static int mt9v022_probe(struct i2c_client *client, diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index e3c907a..9b4f5de 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -845,12 +845,17 @@ err: return ret; } -static int ov2640_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov2640_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov2640_priv *priv = to_ov2640(client); + if (format->pad) + return -EINVAL; + if (!priv->win) { u32 width = SVGA_WIDTH, height = SVGA_HEIGHT; priv->win = ov2640_select_win(&width, &height); @@ -876,33 +881,16 @@ static int ov2640_g_fmt(struct v4l2_subdev *sd, return 0; } -static int ov2640_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov2640_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; + if (format->pad) + return -EINVAL; - switch (mf->code) { - case MEDIA_BUS_FMT_RGB565_2X8_BE: - case MEDIA_BUS_FMT_RGB565_2X8_LE: - mf->colorspace = V4L2_COLORSPACE_SRGB; - break; - default: - mf->code = MEDIA_BUS_FMT_UYVY8_2X8; - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - mf->colorspace = V4L2_COLORSPACE_JPEG; - } - - ret = ov2640_set_params(client, &mf->width, &mf->height, mf->code); - - return ret; -} - -static int ov2640_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ /* * select suitable win, but don't store it */ @@ -922,16 +910,21 @@ static int ov2640_try_fmt(struct v4l2_subdev *sd, mf->colorspace = V4L2_COLORSPACE_JPEG; } + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return ov2640_set_params(client, &mf->width, + &mf->height, mf->code); + cfg->try_fmt = *mf; return 0; } -static int ov2640_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int ov2640_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(ov2640_codes)) + if (code->pad || code->index >= ARRAY_SIZE(ov2640_codes)) return -EINVAL; - *code = ov2640_codes[index]; + code->code = ov2640_codes[code->index]; return 0; } @@ -1031,18 +1024,21 @@ static int ov2640_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { .s_stream = ov2640_s_stream, - .g_mbus_fmt = ov2640_g_fmt, - .s_mbus_fmt = ov2640_s_fmt, - .try_mbus_fmt = ov2640_try_fmt, .cropcap = ov2640_cropcap, .g_crop = ov2640_g_crop, - .enum_mbus_fmt = ov2640_enum_fmt, .g_mbus_config = ov2640_g_mbus_config, }; +static const struct v4l2_subdev_pad_ops ov2640_subdev_pad_ops = { + .enum_mbus_code = ov2640_enum_mbus_code, + .get_fmt = ov2640_get_fmt, + .set_fmt = ov2640_set_fmt, +}; + static struct v4l2_subdev_ops ov2640_subdev_ops = { .core = &ov2640_subdev_core_ops, .video = &ov2640_subdev_video_ops, + .pad = &ov2640_subdev_pad_ops, }; /* OF probe functions */ diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c index 93ae031..bab9ac0 100644 --- a/drivers/media/i2c/soc_camera/ov5642.c +++ b/drivers/media/i2c/soc_camera/ov5642.c @@ -786,50 +786,50 @@ static int ov5642_set_resolution(struct v4l2_subdev *sd) return ret; } -static int ov5642_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov5642_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov5642 *priv = to_ov5642(client); const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code); + if (format->pad) + return -EINVAL; + mf->width = priv->crop_rect.width; mf->height = priv->crop_rect.height; if (!fmt) { + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; mf->code = ov5642_colour_fmts[0].code; mf->colorspace = ov5642_colour_fmts[0].colorspace; } mf->field = V4L2_FIELD_NONE; + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + priv->fmt = ov5642_find_datafmt(mf->code); + else + cfg->try_fmt = *mf; return 0; } -static int ov5642_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov5642 *priv = to_ov5642(client); - - /* MIPI CSI could have changed the format, double-check */ - if (!ov5642_find_datafmt(mf->code)) - return -EINVAL; - - ov5642_try_fmt(sd, mf); - priv->fmt = ov5642_find_datafmt(mf->code); - - return 0; -} - -static int ov5642_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov5642_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov5642 *priv = to_ov5642(client); const struct ov5642_datafmt *fmt = priv->fmt; + if (format->pad) + return -EINVAL; + mf->code = fmt->code; mf->colorspace = fmt->colorspace; mf->width = priv->crop_rect.width; @@ -839,13 +839,14 @@ static int ov5642_g_fmt(struct v4l2_subdev *sd, return 0; } -static int ov5642_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int ov5642_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(ov5642_colour_fmts)) + if (code->pad || code->index >= ARRAY_SIZE(ov5642_colour_fmts)) return -EINVAL; - *code = ov5642_colour_fmts[index].code; + code->code = ov5642_colour_fmts[code->index].code; return 0; } @@ -939,16 +940,18 @@ static int ov5642_s_power(struct v4l2_subdev *sd, int on) } static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { - .s_mbus_fmt = ov5642_s_fmt, - .g_mbus_fmt = ov5642_g_fmt, - .try_mbus_fmt = ov5642_try_fmt, - .enum_mbus_fmt = ov5642_enum_fmt, .s_crop = ov5642_s_crop, .g_crop = ov5642_g_crop, .cropcap = ov5642_cropcap, .g_mbus_config = ov5642_g_mbus_config, }; +static const struct v4l2_subdev_pad_ops ov5642_subdev_pad_ops = { + .enum_mbus_code = ov5642_enum_mbus_code, + .get_fmt = ov5642_get_fmt, + .set_fmt = ov5642_set_fmt, +}; + static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { .s_power = ov5642_s_power, #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -960,6 +963,7 @@ static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { static struct v4l2_subdev_ops ov5642_subdev_ops = { .core = &ov5642_subdev_core_ops, .video = &ov5642_subdev_video_ops, + .pad = &ov5642_subdev_pad_ops, }; static int ov5642_video_probe(struct i2c_client *client) diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c index f4eef2f..1f8af1e 100644 --- a/drivers/media/i2c/soc_camera/ov6650.c +++ b/drivers/media/i2c/soc_camera/ov6650.c @@ -499,12 +499,17 @@ static int ov6650_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int ov6650_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov6650_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov6650 *priv = to_ov6650(client); + if (format->pad) + return -EINVAL; + mf->width = priv->rect.width >> priv->half_scale; mf->height = priv->rect.height >> priv->half_scale; mf->code = priv->code; @@ -680,16 +685,20 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) mf->width = priv->rect.width >> half_scale; mf->height = priv->rect.height >> half_scale; } - return ret; } -static int ov6650_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov6650_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov6650 *priv = to_ov6650(client); + if (format->pad) + return -EINVAL; + if (is_unscaled_ok(mf->width, mf->height, &priv->rect)) v4l_bound_align_image(&mf->width, 2, W_CIF, 1, &mf->height, 2, H_CIF, 1, 0); @@ -713,16 +722,21 @@ static int ov6650_try_fmt(struct v4l2_subdev *sd, break; } + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return ov6650_s_fmt(sd, mf); + cfg->try_fmt = *mf; + return 0; } -static int ov6650_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int ov6650_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(ov6650_codes)) + if (code->pad || code->index >= ARRAY_SIZE(ov6650_codes)) return -EINVAL; - *code = ov6650_codes[index]; + code->code = ov6650_codes[code->index]; return 0; } @@ -929,10 +943,6 @@ static int ov6650_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops ov6650_video_ops = { .s_stream = ov6650_s_stream, - .g_mbus_fmt = ov6650_g_fmt, - .s_mbus_fmt = ov6650_s_fmt, - .try_mbus_fmt = ov6650_try_fmt, - .enum_mbus_fmt = ov6650_enum_fmt, .cropcap = ov6650_cropcap, .g_crop = ov6650_g_crop, .s_crop = ov6650_s_crop, @@ -942,9 +952,16 @@ static struct v4l2_subdev_video_ops ov6650_video_ops = { .s_mbus_config = ov6650_s_mbus_config, }; +static const struct v4l2_subdev_pad_ops ov6650_pad_ops = { + .enum_mbus_code = ov6650_enum_mbus_code, + .get_fmt = ov6650_get_fmt, + .set_fmt = ov6650_set_fmt, +}; + static struct v4l2_subdev_ops ov6650_subdev_ops = { .core = &ov6650_core_ops, .video = &ov6650_video_ops, + .pad = &ov6650_pad_ops, }; /* diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index 8daac88..f150a8b 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c @@ -876,11 +876,16 @@ static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int ov772x_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov772x_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct ov772x_priv *priv = to_ov772x(sd); + if (format->pad) + return -EINVAL; + mf->width = priv->win->rect.width; mf->height = priv->win->rect.height; mf->code = priv->cfmt->code; @@ -915,12 +920,17 @@ static int ov772x_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) return 0; } -static int ov772x_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov772x_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; const struct ov772x_color_format *cfmt; const struct ov772x_win_size *win; + if (format->pad) + return -EINVAL; + ov772x_select_params(mf, &cfmt, &win); mf->code = cfmt->code; @@ -929,6 +939,9 @@ static int ov772x_try_fmt(struct v4l2_subdev *sd, mf->field = V4L2_FIELD_NONE; mf->colorspace = cfmt->colorspace; + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return ov772x_s_fmt(sd, mf); + cfg->try_fmt = *mf; return 0; } @@ -989,13 +1002,14 @@ static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { .s_power = ov772x_s_power, }; -static int ov772x_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int ov772x_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(ov772x_cfmts)) + if (code->pad || code->index >= ARRAY_SIZE(ov772x_cfmts)) return -EINVAL; - *code = ov772x_cfmts[index].code; + code->code = ov772x_cfmts[code->index].code; return 0; } @@ -1016,18 +1030,21 @@ static int ov772x_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { .s_stream = ov772x_s_stream, - .g_mbus_fmt = ov772x_g_fmt, - .s_mbus_fmt = ov772x_s_fmt, - .try_mbus_fmt = ov772x_try_fmt, .cropcap = ov772x_cropcap, .g_crop = ov772x_g_crop, - .enum_mbus_fmt = ov772x_enum_fmt, .g_mbus_config = ov772x_g_mbus_config, }; +static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = { + .enum_mbus_code = ov772x_enum_mbus_code, + .get_fmt = ov772x_get_fmt, + .set_fmt = ov772x_set_fmt, +}; + static struct v4l2_subdev_ops ov772x_subdev_ops = { .core = &ov772x_subdev_core_ops, .video = &ov772x_subdev_video_ops, + .pad = &ov772x_subdev_pad_ops, }; /* diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c index aa93d2e..8caae1c 100644 --- a/drivers/media/i2c/soc_camera/ov9640.c +++ b/drivers/media/i2c/soc_camera/ov9640.c @@ -519,9 +519,15 @@ static int ov9640_s_fmt(struct v4l2_subdev *sd, return ret; } -static int ov9640_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov9640_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; + + if (format->pad) + return -EINVAL; + ov9640_res_roundup(&mf->width, &mf->height); mf->field = V4L2_FIELD_NONE; @@ -537,16 +543,21 @@ static int ov9640_try_fmt(struct v4l2_subdev *sd, mf->colorspace = V4L2_COLORSPACE_JPEG; } + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return ov9640_s_fmt(sd, mf); + + cfg->try_fmt = *mf; return 0; } -static int ov9640_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int ov9640_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(ov9640_codes)) + if (code->pad || code->index >= ARRAY_SIZE(ov9640_codes)) return -EINVAL; - *code = ov9640_codes[index]; + code->code = ov9640_codes[code->index]; return 0; } @@ -656,17 +667,20 @@ static int ov9640_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops ov9640_video_ops = { .s_stream = ov9640_s_stream, - .s_mbus_fmt = ov9640_s_fmt, - .try_mbus_fmt = ov9640_try_fmt, - .enum_mbus_fmt = ov9640_enum_fmt, .cropcap = ov9640_cropcap, .g_crop = ov9640_g_crop, .g_mbus_config = ov9640_g_mbus_config, }; +static const struct v4l2_subdev_pad_ops ov9640_pad_ops = { + .enum_mbus_code = ov9640_enum_mbus_code, + .set_fmt = ov9640_set_fmt, +}; + static struct v4l2_subdev_ops ov9640_subdev_ops = { .core = &ov9640_core_ops, .video = &ov9640_video_ops, + .pad = &ov9640_pad_ops, }; /* diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c index 841dc55..03a7fc7 100644 --- a/drivers/media/i2c/soc_camera/ov9740.c +++ b/drivers/media/i2c/soc_camera/ov9740.c @@ -704,25 +704,35 @@ static int ov9740_s_fmt(struct v4l2_subdev *sd, return ret; } -static int ov9740_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov9740_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; + + if (format->pad) + return -EINVAL; + ov9740_res_roundup(&mf->width, &mf->height); mf->field = V4L2_FIELD_NONE; mf->code = MEDIA_BUS_FMT_YUYV8_2X8; mf->colorspace = V4L2_COLORSPACE_SRGB; + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return ov9740_s_fmt(sd, mf); + cfg->try_fmt = *mf; return 0; } -static int ov9740_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int ov9740_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(ov9740_codes)) + if (code->pad || code->index >= ARRAY_SIZE(ov9740_codes)) return -EINVAL; - *code = ov9740_codes[index]; + code->code = ov9740_codes[code->index]; return 0; } @@ -904,9 +914,6 @@ static int ov9740_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops ov9740_video_ops = { .s_stream = ov9740_s_stream, - .s_mbus_fmt = ov9740_s_fmt, - .try_mbus_fmt = ov9740_try_fmt, - .enum_mbus_fmt = ov9740_enum_fmt, .cropcap = ov9740_cropcap, .g_crop = ov9740_g_crop, .g_mbus_config = ov9740_g_mbus_config, @@ -920,9 +927,15 @@ static struct v4l2_subdev_core_ops ov9740_core_ops = { #endif }; +static const struct v4l2_subdev_pad_ops ov9740_pad_ops = { + .enum_mbus_code = ov9740_enum_mbus_code, + .set_fmt = ov9740_set_fmt, +}; + static struct v4l2_subdev_ops ov9740_subdev_ops = { - .core = &ov9740_core_ops, - .video = &ov9740_video_ops, + .core = &ov9740_core_ops, + .video = &ov9740_video_ops, + .pad = &ov9740_pad_ops, }; static const struct v4l2_ctrl_ops ov9740_ctrl_ops = { diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c index 1752428..c769cf6 100644 --- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c +++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c @@ -485,13 +485,14 @@ static int reg_write_multiple(struct i2c_client *client, return 0; } -static int rj54n1_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int rj54n1_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(rj54n1_colour_fmts)) + if (code->pad || code->index >= ARRAY_SIZE(rj54n1_colour_fmts)) return -EINVAL; - *code = rj54n1_colour_fmts[index].code; + code->code = rj54n1_colour_fmts[code->index].code; return 0; } @@ -597,12 +598,17 @@ static int rj54n1_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int rj54n1_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int rj54n1_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct rj54n1 *rj54n1 = to_rj54n1(client); + if (format->pad) + return -EINVAL; + mf->code = rj54n1->fmt->code; mf->colorspace = rj54n1->fmt->colorspace; mf->field = V4L2_FIELD_NONE; @@ -959,17 +965,25 @@ static int rj54n1_reg_init(struct i2c_client *client) return ret; } -static int rj54n1_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int rj54n1_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct rj54n1 *rj54n1 = to_rj54n1(client); const struct rj54n1_datafmt *fmt; + int output_w, output_h, max_w, max_h, + input_w = rj54n1->rect.width, input_h = rj54n1->rect.height; int align = mf->code == MEDIA_BUS_FMT_SBGGR10_1X10 || mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE || mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE || mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE || mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE; + int ret; + + if (format->pad) + return -EINVAL; dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n", __func__, mf->code, mf->width, mf->height); @@ -987,24 +1001,10 @@ static int rj54n1_try_fmt(struct v4l2_subdev *sd, v4l_bound_align_image(&mf->width, 112, RJ54N1_MAX_WIDTH, align, &mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0); - return 0; -} - -static int rj54n1_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); - const struct rj54n1_datafmt *fmt; - int output_w, output_h, max_w, max_h, - input_w = rj54n1->rect.width, input_h = rj54n1->rect.height; - int ret; - - /* - * The host driver can call us without .try_fmt(), so, we have to take - * care ourseleves - */ - rj54n1_try_fmt(sd, mf); + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *mf; + return 0; + } /* * Verify if the sensor has just been powered on. TODO: replace this @@ -1020,9 +1020,6 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd, return ret; } - dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n", - __func__, mf->code, mf->width, mf->height); - /* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */ switch (mf->code) { case MEDIA_BUS_FMT_YUYV8_2X8: @@ -1249,10 +1246,6 @@ static int rj54n1_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { .s_stream = rj54n1_s_stream, - .s_mbus_fmt = rj54n1_s_fmt, - .g_mbus_fmt = rj54n1_g_fmt, - .try_mbus_fmt = rj54n1_try_fmt, - .enum_mbus_fmt = rj54n1_enum_fmt, .g_crop = rj54n1_g_crop, .s_crop = rj54n1_s_crop, .cropcap = rj54n1_cropcap, @@ -1260,9 +1253,16 @@ static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { .s_mbus_config = rj54n1_s_mbus_config, }; +static const struct v4l2_subdev_pad_ops rj54n1_subdev_pad_ops = { + .enum_mbus_code = rj54n1_enum_mbus_code, + .get_fmt = rj54n1_get_fmt, + .set_fmt = rj54n1_set_fmt, +}; + static struct v4l2_subdev_ops rj54n1_subdev_ops = { .core = &rj54n1_subdev_core_ops, .video = &rj54n1_subdev_video_ops, + .pad = &rj54n1_subdev_pad_ops, }; /* diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c index 9b85321..42bec9b 100644 --- a/drivers/media/i2c/soc_camera/tw9910.c +++ b/drivers/media/i2c/soc_camera/tw9910.c @@ -691,12 +691,17 @@ static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int tw9910_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int tw9910_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct tw9910_priv *priv = to_tw9910(client); + if (format->pad) + return -EINVAL; + if (!priv->scale) { priv->scale = tw9910_select_norm(priv->norm, 640, 480); if (!priv->scale) @@ -737,13 +742,18 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd, return ret; } -static int tw9910_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int tw9910_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct tw9910_priv *priv = to_tw9910(client); const struct tw9910_scale_ctrl *scale; + if (format->pad) + return -EINVAL; + if (V4L2_FIELD_ANY == mf->field) { mf->field = V4L2_FIELD_INTERLACED_BT; } else if (V4L2_FIELD_INTERLACED_BT != mf->field) { @@ -764,6 +774,9 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd, mf->width = scale->width; mf->height = scale->height; + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return tw9910_s_fmt(sd, mf); + cfg->try_fmt = *mf; return 0; } @@ -821,13 +834,14 @@ static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { .s_power = tw9910_s_power, }; -static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int tw9910_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index) + if (code->pad || code->index) return -EINVAL; - *code = MEDIA_BUS_FMT_UYVY8_2X8; + code->code = MEDIA_BUS_FMT_UYVY8_2X8; return 0; } @@ -880,20 +894,23 @@ static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { .s_std = tw9910_s_std, .g_std = tw9910_g_std, .s_stream = tw9910_s_stream, - .g_mbus_fmt = tw9910_g_fmt, - .s_mbus_fmt = tw9910_s_fmt, - .try_mbus_fmt = tw9910_try_fmt, .cropcap = tw9910_cropcap, .g_crop = tw9910_g_crop, - .enum_mbus_fmt = tw9910_enum_fmt, .g_mbus_config = tw9910_g_mbus_config, .s_mbus_config = tw9910_s_mbus_config, .g_tvnorms = tw9910_g_tvnorms, }; +static const struct v4l2_subdev_pad_ops tw9910_subdev_pad_ops = { + .enum_mbus_code = tw9910_enum_mbus_code, + .get_fmt = tw9910_get_fmt, + .set_fmt = tw9910_set_fmt, +}; + static struct v4l2_subdev_ops tw9910_subdev_ops = { .core = &tw9910_subdev_core_ops, .video = &tw9910_subdev_video_ops, + .pad = &tw9910_subdev_pad_ops, }; /* diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c index 10c735c..b62b6dd 100644 --- a/drivers/media/i2c/sr030pc30.c +++ b/drivers/media/i2c/sr030pc30.c @@ -471,25 +471,31 @@ static int sr030pc30_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static int sr030pc30_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int sr030pc30_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (!code || index >= ARRAY_SIZE(sr030pc30_formats)) + if (!code || code->pad || + code->index >= ARRAY_SIZE(sr030pc30_formats)) return -EINVAL; - *code = sr030pc30_formats[index].code; + code->code = sr030pc30_formats[code->index].code; return 0; } -static int sr030pc30_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int sr030pc30_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf; struct sr030pc30_info *info = to_sr030pc30(sd); int ret; - if (!mf) + if (!format || format->pad) return -EINVAL; + mf = &format->format; + if (!info->curr_win || !info->curr_fmt) { ret = sr030pc30_set_params(sd); if (ret) @@ -523,25 +529,28 @@ static const struct sr030pc30_format *try_fmt(struct v4l2_subdev *sd, } /* Return nearest media bus frame format. */ -static int sr030pc30_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int sr030pc30_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { - if (!sd || !mf) - return -EINVAL; - - try_fmt(sd, mf); - return 0; -} + struct sr030pc30_info *info = sd ? to_sr030pc30(sd) : NULL; + const struct sr030pc30_format *fmt; + struct v4l2_mbus_framefmt *mf; -static int sr030pc30_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct sr030pc30_info *info = to_sr030pc30(sd); + if (!sd || !format) + return -EINVAL; - if (!sd || !mf) + mf = &format->format; + if (format->pad) return -EINVAL; - info->curr_fmt = try_fmt(sd, mf); + fmt = try_fmt(sd, mf); + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *mf; + return 0; + } + + info->curr_fmt = fmt; return sr030pc30_set_params(sd); } @@ -636,16 +645,15 @@ static const struct v4l2_subdev_core_ops sr030pc30_core_ops = { .querymenu = v4l2_subdev_querymenu, }; -static const struct v4l2_subdev_video_ops sr030pc30_video_ops = { - .g_mbus_fmt = sr030pc30_g_fmt, - .s_mbus_fmt = sr030pc30_s_fmt, - .try_mbus_fmt = sr030pc30_try_fmt, - .enum_mbus_fmt = sr030pc30_enum_fmt, +static const struct v4l2_subdev_pad_ops sr030pc30_pad_ops = { + .enum_mbus_code = sr030pc30_enum_mbus_code, + .get_fmt = sr030pc30_get_fmt, + .set_fmt = sr030pc30_set_fmt, }; static const struct v4l2_subdev_ops sr030pc30_ops = { .core = &sr030pc30_core_ops, - .video = &sr030pc30_video_ops, + .pad = &sr030pc30_pad_ops, }; /* diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index 070c152..0c50e52 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c @@ -272,7 +272,7 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) return -EINVAL; } - /* FIXME: it seems that the shadow bytes are wrong bellow !*/ + /* FIXME: it seems that the shadow bytes are wrong below !*/ /* update our shadow register set; print bytes if (debug > 0) */ v4l2_dbg(1, debug, sd, "chip_cmd(%s): reg=%d, data:", diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 1c6bc30..24e4727 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -747,54 +747,6 @@ static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl) } /** - * tvp514x_enum_mbus_fmt() - V4L2 decoder interface handler for enum_mbus_fmt - * @sd: pointer to standard V4L2 sub-device structure - * @index: index of pixelcode to retrieve - * @code: receives the pixelcode - * - * Enumerates supported mediabus formats - */ -static int -tvp514x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - u32 *code) -{ - if (index) - return -EINVAL; - - *code = MEDIA_BUS_FMT_YUYV10_2X10; - return 0; -} - -/** - * tvp514x_mbus_fmt() - V4L2 decoder interface handler for try/s/g_mbus_fmt - * @sd: pointer to standard V4L2 sub-device structure - * @f: pointer to the mediabus format structure - * - * Negotiates the image capture size and mediabus format. - */ -static int -tvp514x_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) -{ - struct tvp514x_decoder *decoder = to_decoder(sd); - enum tvp514x_std current_std; - - if (f == NULL) - return -EINVAL; - - /* Calculate height and width based on current standard */ - current_std = decoder->current_std; - - f->code = MEDIA_BUS_FMT_YUYV8_2X8; - f->width = decoder->std_list[current_std].width; - f->height = decoder->std_list[current_std].height; - f->field = V4L2_FIELD_INTERLACED; - f->colorspace = V4L2_COLORSPACE_SMPTE170M; - v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d\n", - f->width, f->height); - return 0; -} - -/** * tvp514x_g_parm() - V4L2 decoder interface handler for g_parm * @sd: pointer to standard V4L2 sub-device structure * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure @@ -962,6 +914,9 @@ static int tvp514x_get_pad_format(struct v4l2_subdev *sd, struct tvp514x_decoder *decoder = to_decoder(sd); __u32 which = format->which; + if (format->pad) + return -EINVAL; + if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { format->format = decoder->format; return 0; @@ -1016,10 +971,6 @@ static const struct v4l2_subdev_video_ops tvp514x_video_ops = { .s_std = tvp514x_s_std, .s_routing = tvp514x_s_routing, .querystd = tvp514x_querystd, - .enum_mbus_fmt = tvp514x_enum_mbus_fmt, - .g_mbus_fmt = tvp514x_mbus_fmt, - .try_mbus_fmt = tvp514x_mbus_fmt, - .s_mbus_fmt = tvp514x_mbus_fmt, .g_parm = tvp514x_g_parm, .s_parm = tvp514x_s_parm, .s_stream = tvp514x_s_stream, diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 68cdab9..e4fa074 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -817,24 +817,29 @@ static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd) } } -static int tvp5150_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - u32 *code) +static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index) + if (code->pad || code->index) return -EINVAL; - *code = MEDIA_BUS_FMT_UYVY8_2X8; + code->code = MEDIA_BUS_FMT_UYVY8_2X8; return 0; } -static int tvp5150_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *f) +static int tvp5150_fill_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *f; struct tvp5150 *decoder = to_tvp5150(sd); - if (f == NULL) + if (!format || format->pad) return -EINVAL; + f = &format->format; + tvp5150_reset(sd, 0); f->width = decoder->rect.width; @@ -1068,10 +1073,6 @@ static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = { static const struct v4l2_subdev_video_ops tvp5150_video_ops = { .s_std = tvp5150_s_std, .s_routing = tvp5150_s_routing, - .enum_mbus_fmt = tvp5150_enum_mbus_fmt, - .s_mbus_fmt = tvp5150_mbus_fmt, - .try_mbus_fmt = tvp5150_mbus_fmt, - .g_mbus_fmt = tvp5150_mbus_fmt, .s_crop = tvp5150_s_crop, .g_crop = tvp5150_g_crop, .cropcap = tvp5150_cropcap, @@ -1084,11 +1085,18 @@ static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { .s_raw_fmt = tvp5150_s_raw_fmt, }; +static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = { + .enum_mbus_code = tvp5150_enum_mbus_code, + .set_fmt = tvp5150_fill_fmt, + .get_fmt = tvp5150_fill_fmt, +}; + static const struct v4l2_subdev_ops tvp5150_ops = { .core = &tvp5150_core_ops, .tuner = &tvp5150_tuner_ops, .video = &tvp5150_video_ops, .vbi = &tvp5150_vbi_ops, + .pad = &tvp5150_pad_ops, }; diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 787cdfb..05077cf 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -611,31 +611,6 @@ static int tvp7002_s_ctrl(struct v4l2_ctrl *ctrl) } /* - * tvp7002_mbus_fmt() - V4L2 decoder interface handler for try/s/g_mbus_fmt - * @sd: pointer to standard V4L2 sub-device structure - * @f: pointer to mediabus format structure - * - * Negotiate the image capture size and mediabus format. - * There is only one possible format, so this single function works for - * get, set and try. - */ -static int tvp7002_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) -{ - struct tvp7002 *device = to_tvp7002(sd); - const struct v4l2_bt_timings *bt = &device->current_timings->timings.bt; - - f->width = bt->width; - f->height = bt->height; - f->code = MEDIA_BUS_FMT_YUYV10_1X20; - f->field = device->current_timings->scanmode; - f->colorspace = device->current_timings->color_space; - - v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d", - f->width, f->height); - return 0; -} - -/* * tvp7002_query_dv() - query DV timings * @sd: pointer to standard V4L2 sub-device structure * @index: index into the tvp7002_timings array @@ -747,25 +722,6 @@ static int tvp7002_s_register(struct v4l2_subdev *sd, #endif /* - * tvp7002_enum_mbus_fmt() - Enum supported mediabus formats - * @sd: pointer to standard V4L2 sub-device structure - * @index: format index - * @code: pointer to mediabus format - * - * Enumerate supported mediabus formats. - */ - -static int tvp7002_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - u32 *code) -{ - /* Check requested format index is within range */ - if (index) - return -EINVAL; - *code = MEDIA_BUS_FMT_YUYV10_1X20; - return 0; -} - -/* * tvp7002_s_stream() - V4L2 decoder i/f handler for s_stream * @sd: pointer to standard V4L2 sub-device structure * @enable: streaming enable or disable @@ -924,10 +880,6 @@ static const struct v4l2_subdev_video_ops tvp7002_video_ops = { .s_dv_timings = tvp7002_s_dv_timings, .query_dv_timings = tvp7002_query_dv_timings, .s_stream = tvp7002_s_stream, - .g_mbus_fmt = tvp7002_mbus_fmt, - .try_mbus_fmt = tvp7002_mbus_fmt, - .s_mbus_fmt = tvp7002_mbus_fmt, - .enum_mbus_fmt = tvp7002_enum_mbus_fmt, }; /* media pad related operation handlers */ diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c index 00e7f04..4c72a18 100644 --- a/drivers/media/i2c/vs6624.c +++ b/drivers/media/i2c/vs6624.c @@ -557,21 +557,28 @@ static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static int vs6624_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - u32 *code) +static int vs6624_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(vs6624_formats)) + if (code->pad || code->index >= ARRAY_SIZE(vs6624_formats)) return -EINVAL; - *code = vs6624_formats[index].mbus_code; + code->code = vs6624_formats[code->index].mbus_code; return 0; } -static int vs6624_try_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int vs6624_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *fmt = &format->format; + struct vs6624 *sensor = to_vs6624(sd); int index; + if (format->pad) + return -EINVAL; + for (index = 0; index < ARRAY_SIZE(vs6624_formats); index++) if (vs6624_formats[index].mbus_code == fmt->code) break; @@ -590,18 +597,11 @@ static int vs6624_try_mbus_fmt(struct v4l2_subdev *sd, fmt->height = fmt->height & (~3); fmt->field = V4L2_FIELD_NONE; fmt->colorspace = vs6624_formats[index].colorspace; - return 0; -} - -static int vs6624_s_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) -{ - struct vs6624 *sensor = to_vs6624(sd); - int ret; - ret = vs6624_try_mbus_fmt(sd, fmt); - if (ret) - return ret; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *fmt; + return 0; + } /* set image format */ switch (fmt->code) { @@ -648,12 +648,16 @@ static int vs6624_s_mbus_fmt(struct v4l2_subdev *sd, return 0; } -static int vs6624_g_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int vs6624_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct vs6624 *sensor = to_vs6624(sd); - *fmt = sensor->fmt; + if (format->pad) + return -EINVAL; + + format->format = sensor->fmt; return 0; } @@ -738,18 +742,21 @@ static const struct v4l2_subdev_core_ops vs6624_core_ops = { }; static const struct v4l2_subdev_video_ops vs6624_video_ops = { - .enum_mbus_fmt = vs6624_enum_mbus_fmt, - .try_mbus_fmt = vs6624_try_mbus_fmt, - .s_mbus_fmt = vs6624_s_mbus_fmt, - .g_mbus_fmt = vs6624_g_mbus_fmt, .s_parm = vs6624_s_parm, .g_parm = vs6624_g_parm, .s_stream = vs6624_s_stream, }; +static const struct v4l2_subdev_pad_ops vs6624_pad_ops = { + .enum_mbus_code = vs6624_enum_mbus_code, + .get_fmt = vs6624_get_fmt, + .set_fmt = vs6624_set_fmt, +}; + static const struct v4l2_subdev_ops vs6624_ops = { .core = &vs6624_core_ops, .video = &vs6624_video_ops, + .pad = &vs6624_pad_ops, }; static int vs6624_probe(struct i2c_client *client, diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index 218144a..f318ae9 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -21,6 +21,7 @@ source "drivers/media/pci/zoran/Kconfig" source "drivers/media/pci/saa7146/Kconfig" source "drivers/media/pci/solo6x10/Kconfig" source "drivers/media/pci/tw68/Kconfig" +source "drivers/media/pci/dt3155/Kconfig" endif if MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT @@ -32,6 +33,7 @@ source "drivers/media/pci/cx88/Kconfig" source "drivers/media/pci/bt8xx/Kconfig" source "drivers/media/pci/saa7134/Kconfig" source "drivers/media/pci/saa7164/Kconfig" +source "drivers/media/pci/cobalt/Kconfig" endif diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index 0baf0d29..23ce53b 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile @@ -24,6 +24,8 @@ obj-$(CONFIG_VIDEO_BT848) += bt8xx/ obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ obj-$(CONFIG_VIDEO_TW68) += tw68/ +obj-$(CONFIG_VIDEO_DT3155) += dt3155/ obj-$(CONFIG_VIDEO_MEYE) += meye/ obj-$(CONFIG_STA2X11_VIP) += sta2x11/ obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/ +obj-$(CONFIG_VIDEO_COBALT) += cobalt/ diff --git a/drivers/media/pci/bt8xx/bttv-audio-hook.c b/drivers/media/pci/bt8xx/bttv-audio-hook.c index 2364d16..9f1f9169 100644 --- a/drivers/media/pci/bt8xx/bttv-audio-hook.c +++ b/drivers/media/pci/bt8xx/bttv-audio-hook.c @@ -54,23 +54,33 @@ void winview_volume(struct bttv *btv, __u16 volume) void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { - unsigned int con = 0; + unsigned int con; - if (set) { - gpio_inout(0x300, 0x300); - if (t->audmode & V4L2_TUNER_MODE_LANG1) - con = 0x000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) - con = 0x300; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - con = 0x200; -/* if (t->audmode & V4L2_TUNER_MODE_MONO) - * con = 0x100; */ - gpio_bits(0x300, con); - } else { - t->audmode = V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + + return; + } + + gpio_inout(0x300, 0x300); + switch (t->audmode) { + case V4L2_TUNER_MODE_LANG1: + default: + con = 0x000; + break; + case V4L2_TUNER_MODE_LANG2: + con = 0x300; + break; + case V4L2_TUNER_MODE_STEREO: + con = 0x200; + break; } + gpio_bits(0x300, con); } void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) @@ -82,47 +92,51 @@ void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) val = gpio_read(); if (set) { - con = 0x000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) { - if (t->audmode & V4L2_TUNER_MODE_LANG1) { - /* LANG1 + LANG2 */ - con = 0x100; - } - else { - /* LANG2 */ - con = 0x300; - } + switch (t->audmode) { + case V4L2_TUNER_MODE_LANG2: + con = 0x300; + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + con = 0x100; + break; + default: + con = 0x000; + break; } if (con != (val & 0x300)) { gpio_bits(0x300, con); if (bttv_gpio) - bttv_gpio_tracking(btv,"gvbctv5pci"); + bttv_gpio_tracking(btv, "gvbctv5pci"); } } else { switch (val & 0x70) { case 0x10: t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + t->audmode = V4L2_TUNER_MODE_LANG1_LANG2; break; case 0x30: t->rxsubchans = V4L2_TUNER_SUB_LANG2; + t->audmode = V4L2_TUNER_MODE_LANG1_LANG2; break; case 0x50: t->rxsubchans = V4L2_TUNER_SUB_LANG1; + t->audmode = V4L2_TUNER_MODE_LANG1_LANG2; break; case 0x60: t->rxsubchans = V4L2_TUNER_SUB_STEREO; + t->audmode = V4L2_TUNER_MODE_STEREO; break; case 0x70: t->rxsubchans = V4L2_TUNER_SUB_MONO; + t->audmode = V4L2_TUNER_MODE_MONO; break; default: t->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + t->audmode = V4L2_TUNER_MODE_LANG1; } - t->audmode = V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } } @@ -142,23 +156,32 @@ void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { - int val = 0; + int val; - if (set) { - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ - val = 0x02; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - val = 0x01; - if (val) { - gpio_bits(0x03,val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"avermedia"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + + return; + } + + switch (t->audmode) { + case V4L2_TUNER_MODE_LANG2: /* SAP */ + val = 0x02; + break; + case V4L2_TUNER_MODE_STEREO: + val = 0x01; + break; + default: return; } + gpio_bits(0x03, val); + if (bttv_gpio) + bttv_gpio_tracking(btv, "avermedia"); } @@ -166,19 +189,31 @@ void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { int val = 0; - if (set) { - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ - val = 0x01; - if (t->audmode & V4L2_TUNER_MODE_STEREO) /* STEREO */ - val = 0x02; - btaor(val, ~0x03, BT848_GPIO_DATA); - if (bttv_gpio) - bttv_gpio_tracking(btv,"avermedia"); - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + return; } + + switch (t->audmode) { + case V4L2_TUNER_MODE_LANG2: /* SAP */ + val = 0x01; + break; + case V4L2_TUNER_MODE_STEREO: + val = 0x02; + break; + default: + val = 0; + break; + } + btaor(val, ~0x03, BT848_GPIO_DATA); + if (bttv_gpio) + bttv_gpio_tracking(btv, "avermedia"); } /* Lifetec 9415 handling */ @@ -192,23 +227,32 @@ void lt9415_audio(struct bttv *btv, struct v4l2_tuner *t, int set) return; } - if (set) { - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* A2 SAP */ - val = 0x0080; - if (t->audmode & V4L2_TUNER_MODE_STEREO) /* A2 stereo */ - val = 0x0880; - if ((t->audmode & V4L2_TUNER_MODE_LANG1) || - (t->audmode & V4L2_TUNER_MODE_MONO)) - val = 0; - gpio_bits(0x0880, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"lt9415"); - } else { - /* autodetect doesn't work with this card :-( */ - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + return; } + + switch (t->audmode) { + case V4L2_TUNER_MODE_LANG2: /* A2 SAP */ + val = 0x0080; + break; + case V4L2_TUNER_MODE_STEREO: /* A2 stereo */ + val = 0x0880; + break; + default: + val = 0; + break; + } + + gpio_bits(0x0880, val); + if (bttv_gpio) + bttv_gpio_tracking(btv, "lt9415"); } /* TDA9821 on TerraTV+ Bt848, Bt878 */ @@ -216,45 +260,69 @@ void terratv_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { unsigned int con = 0; - if (set) { - gpio_inout(0x180000,0x180000); - if (t->audmode & V4L2_TUNER_MODE_LANG2) - con = 0x080000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - con = 0x180000; - gpio_bits(0x180000, con); - if (bttv_gpio) - bttv_gpio_tracking(btv,"terratv"); - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + + return; + } + + gpio_inout(0x180000, 0x180000); + switch (t->audmode) { + case V4L2_TUNER_MODE_LANG2: + con = 0x080000; + break; + case V4L2_TUNER_MODE_STEREO: + con = 0x180000; + break; + default: + con = 0; + break; } + gpio_bits(0x180000, con); + if (bttv_gpio) + bttv_gpio_tracking(btv, "terratv"); } void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { - unsigned long val = 0; + unsigned long val; - if (set) { - /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ - if (t->audmode & V4L2_TUNER_MODE_MONO) /* Mono */ - val = 0x420000; - if (t->audmode & V4L2_TUNER_MODE_LANG1) /* Mono */ - val = 0x420000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ - val = 0x410000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) /* Stereo */ - val = 0x020000; - if (val) { - gpio_bits(0x430000, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"winfast2000"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + + return; } + + /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ + switch (t->audmode) { + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_LANG1: + val = 0x420000; + break; + case V4L2_TUNER_MODE_LANG2: /* SAP */ + val = 0x410000; + break; + case V4L2_TUNER_MODE_STEREO: + val = 0x020000; + break; + default: + return; + } + + gpio_bits(0x430000, val); + if (bttv_gpio) + bttv_gpio_tracking(btv, "winfast2000"); } /* @@ -272,23 +340,33 @@ void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set) if (btv->radio_user) return; - if (set) { - if (t->audmode & V4L2_TUNER_MODE_MONO) { - val = 0x01; - } - if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) - || (t->audmode & V4L2_TUNER_MODE_STEREO)) { - val = 0x02; - } - if (val) { - gpio_bits(0x03,val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"pvbt878p9b"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + + return; } + + switch (t->audmode) { + case V4L2_TUNER_MODE_MONO: + val = 0x01; + break; + case V4L2_TUNER_MODE_LANG1: + case V4L2_TUNER_MODE_LANG2: + case V4L2_TUNER_MODE_STEREO: + val = 0x02; + break; + default: + return; + } + + gpio_bits(0x03, val); + if (bttv_gpio) + bttv_gpio_tracking(btv, "pvbt878p9b"); } /* @@ -298,28 +376,37 @@ void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set) */ void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { - unsigned int val = 0xffff; + unsigned int val; if (btv->radio_user) return; - if (set) { - if (t->audmode & V4L2_TUNER_MODE_MONO) { - val = 0x0000; - } - if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) - || (t->audmode & V4L2_TUNER_MODE_STEREO)) { - val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ - } - if (val != 0xffff) { - gpio_bits(0x1800, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"fv2000s"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + + return; } + + switch (t->audmode) { + case V4L2_TUNER_MODE_MONO: + val = 0x0000; + break; + case V4L2_TUNER_MODE_LANG1: + case V4L2_TUNER_MODE_LANG2: + case V4L2_TUNER_MODE_STEREO: + val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ + break; + default: + return; + } + gpio_bits(0x1800, val); + if (bttv_gpio) + bttv_gpio_tracking(btv, "fv2000s"); } /* @@ -328,26 +415,33 @@ void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set) */ void windvr_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { - unsigned long val = 0; + unsigned long val; - if (set) { - if (t->audmode & V4L2_TUNER_MODE_MONO) - val = 0x040000; - if (t->audmode & V4L2_TUNER_MODE_LANG1) - val = 0; - if (t->audmode & V4L2_TUNER_MODE_LANG2) - val = 0x100000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - val = 0; - if (val) { - gpio_bits(0x140000, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"windvr"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + + return; + } + + switch (t->audmode) { + case V4L2_TUNER_MODE_MONO: + val = 0x040000; + break; + case V4L2_TUNER_MODE_LANG2: + val = 0x100000; + break; + default: + return; } + + gpio_bits(0x140000, val); + if (bttv_gpio) + bttv_gpio_tracking(btv, "windvr"); } /* @@ -360,23 +454,36 @@ void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *t, int set) /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */ - if (set) { - /* btor(***, BT848_GPIO_OUT_EN); */ - if (t->audmode & V4L2_TUNER_MODE_LANG1) - con = 0x00000000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) - con = 0x00180000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - con = 0x00000000; - if (t->audmode & V4L2_TUNER_MODE_MONO) - con = 0x00060000; - if (con != 0xffffff) { - gpio_bits(0x1e0000,con); - if (bttv_gpio) - bttv_gpio_tracking(btv, "adtvk503"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + + return; } + + /* btor(***, BT848_GPIO_OUT_EN); */ + switch (t->audmode) { + case V4L2_TUNER_MODE_LANG1: + con = 0x00000000; + break; + case V4L2_TUNER_MODE_LANG2: + con = 0x00180000; + break; + case V4L2_TUNER_MODE_STEREO: + con = 0x00000000; + break; + case V4L2_TUNER_MODE_MONO: + con = 0x00060000; + break; + default: + return; + } + + gpio_bits(0x1e0000, con); + if (bttv_gpio) + bttv_gpio_tracking(btv, "adtvk503"); } diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index bc12060..3632958 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2676,7 +2676,8 @@ static int bttv_s_fbuf(struct file *file, void *f, fh->ov.w.height = fb->fmt.height; btv->init.ov.w.width = fb->fmt.width; btv->init.ov.w.height = fb->fmt.height; - kfree(fh->ov.clips); + + kfree(fh->ov.clips); fh->ov.clips = NULL; fh->ov.nclips = 0; @@ -4238,6 +4239,7 @@ fail0: iounmap(btv->bt848_mmio); release_mem_region(pci_resource_start(btv->c.pci,0), pci_resource_len(btv->c.pci,0)); + pci_disable_device(btv->c.pci); return result; } @@ -4281,6 +4283,7 @@ static void bttv_remove(struct pci_dev *pci_dev) iounmap(btv->bt848_mmio); release_mem_region(pci_resource_start(btv->c.pci,0), pci_resource_len(btv->c.pci,0)); + pci_disable_device(btv->c.pci); v4l2_device_unregister(&btv->c.v4l2_dev); bttvs[btv->c.nr] = NULL; diff --git a/drivers/media/pci/bt8xx/dst.c b/drivers/media/pci/bt8xx/dst.c index f2261df..4a90eee 100644 --- a/drivers/media/pci/bt8xx/dst.c +++ b/drivers/media/pci/bt8xx/dst.c @@ -425,7 +425,8 @@ static int dst_set_bandwidth(struct dst_state *state, u32 bandwidth) return 0; } -static int dst_set_inversion(struct dst_state *state, fe_spectral_inversion_t inversion) +static int dst_set_inversion(struct dst_state *state, + enum fe_spectral_inversion inversion) { state->inversion = inversion; switch (inversion) { @@ -442,13 +443,13 @@ static int dst_set_inversion(struct dst_state *state, fe_spectral_inversion_t in return 0; } -static int dst_set_fec(struct dst_state *state, fe_code_rate_t fec) +static int dst_set_fec(struct dst_state *state, enum fe_code_rate fec) { state->fec = fec; return 0; } -static fe_code_rate_t dst_get_fec(struct dst_state *state) +static enum fe_code_rate dst_get_fec(struct dst_state *state) { return state->fec; } @@ -499,7 +500,8 @@ static int dst_set_symbolrate(struct dst_state *state, u32 srate) return 0; } -static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation) +static int dst_set_modulation(struct dst_state *state, + enum fe_modulation modulation) { if (state->dst_type != DST_TYPE_IS_CABLE) return -EOPNOTSUPP; @@ -536,7 +538,7 @@ static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulatio return 0; } -static fe_modulation_t dst_get_modulation(struct dst_state *state) +static enum fe_modulation dst_get_modulation(struct dst_state *state) { return state->modulation; } @@ -1376,7 +1378,8 @@ static int dst_get_tuna(struct dst_state *state) return 1; } -static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); +static int dst_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage); static int dst_write_tuna(struct dvb_frontend *fe) { @@ -1466,7 +1469,7 @@ static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd return dst_command(state, paket, 8); } -static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int dst_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) { int need_cmd, retval = 0; struct dst_state *state = fe->demodulator_priv; @@ -1500,7 +1503,7 @@ static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) return retval; } -static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +static int dst_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) { struct dst_state *state = fe->demodulator_priv; @@ -1525,7 +1528,7 @@ static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) return dst_tone_power_cmd(state); } -static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) +static int dst_send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd minicmd) { struct dst_state *state = fe->demodulator_priv; @@ -1575,7 +1578,7 @@ static int bt8xx_dst_init(struct dvb_frontend *fe) return 0; } -static int dst_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int dst_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct dst_state *state = fe->demodulator_priv; @@ -1646,7 +1649,7 @@ static int dst_tune_frontend(struct dvb_frontend* fe, bool re_tune, unsigned int mode_flags, unsigned int *delay, - fe_status_t *status) + enum fe_status *status) { struct dst_state *state = fe->demodulator_priv; struct dtv_frontend_properties *p = &fe->dtv_property_cache; diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c index c22c4ae..c5cc14e 100644 --- a/drivers/media/pci/bt8xx/dst_ca.c +++ b/drivers/media/pci/bt8xx/dst_ca.c @@ -320,29 +320,27 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) return -EFAULT; - if (p_ca_message->msg) { - dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%*ph]", - 3, p_ca_message->msg); - - for (i = 0; i < 3; i++) { - command = command | p_ca_message->msg[i]; - if (i < 2) - command = command << 8; - } - dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command); + dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%*ph]", + 3, p_ca_message->msg); - switch (command) { - case CA_APP_INFO: - memcpy(p_ca_message->msg, state->messages, 128); - if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) - return -EFAULT; - break; - case CA_INFO: - memcpy(p_ca_message->msg, state->messages, 128); - if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) - return -EFAULT; - break; - } + for (i = 0; i < 3; i++) { + command = command | p_ca_message->msg[i]; + if (i < 2) + command = command << 8; + } + dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command); + + switch (command) { + case CA_APP_INFO: + memcpy(p_ca_message->msg, state->messages, 128); + if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) + return -EFAULT; + break; + case CA_INFO: + memcpy(p_ca_message->msg, state->messages, 128); + if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) + return -EFAULT; + break; } return 0; @@ -494,60 +492,58 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, goto free_mem_and_exit; } + /* EN50221 tag */ + command = 0; - if (p_ca_message->msg) { - /* EN50221 tag */ - command = 0; + for (i = 0; i < 3; i++) { + command = command | p_ca_message->msg[i]; + if (i < 2) + command = command << 8; + } + dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command); - for (i = 0; i < 3; i++) { - command = command | p_ca_message->msg[i]; - if (i < 2) - command = command << 8; + switch (command) { + case CA_PMT: + dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT"); + if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !"); + result = -1; + goto free_mem_and_exit; } - dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command); - - switch (command) { - case CA_PMT: - dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT"); - if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !"); - break; - case CA_PMT_REPLY: - dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY"); - /* Have to handle the 2 basic types of cards here */ - if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !"); - break; - case CA_APP_INFO_ENQUIRY: // only for debugging - dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information"); - - if ((ca_get_app_info(state)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !"); - break; - case CA_INFO_ENQUIRY: - dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information"); - - if ((ca_get_ca_info(state)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !"); - break; + dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !"); + break; + case CA_PMT_REPLY: + dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY"); + /* Have to handle the 2 basic types of cards here */ + if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !"); + break; + case CA_APP_INFO_ENQUIRY: // only for debugging + dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information"); + + if ((ca_get_app_info(state)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !"); + result = -1; + goto free_mem_and_exit; } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !"); + break; + case CA_INFO_ENQUIRY: + dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information"); + + if ((ca_get_ca_info(state)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !"); + break; } + free_mem_and_exit: kfree (hw_buffer); diff --git a/drivers/media/pci/bt8xx/dst_common.h b/drivers/media/pci/bt8xx/dst_common.h index d70d98f..6a2cfdd 100644 --- a/drivers/media/pci/bt8xx/dst_common.h +++ b/drivers/media/pci/bt8xx/dst_common.h @@ -113,11 +113,11 @@ struct dst_state { u8 dst_type; u32 type_flags; u32 frequency; /* intermediate frequency in kHz for QPSK */ - fe_spectral_inversion_t inversion; + enum fe_spectral_inversion inversion; u32 symbol_rate; /* symbol rate in Symbols per second */ - fe_code_rate_t fec; - fe_sec_voltage_t voltage; - fe_sec_tone_mode_t tone; + enum fe_code_rate fec; + enum fe_sec_voltage voltage; + enum fe_sec_tone_mode tone; u32 decode_freq; u8 decode_lock; u16 decode_strength; @@ -127,8 +127,8 @@ struct dst_state { u32 bandwidth; u32 dst_hw_cap; u8 dst_fw_version; - fe_sec_mini_cmd_t minicmd; - fe_modulation_t modulation; + enum fe_sec_mini_cmd minicmd; + enum fe_modulation modulation; u8 messages[256]; u8 mac_address[8]; u8 fw_version[8]; diff --git a/drivers/media/pci/cobalt/Kconfig b/drivers/media/pci/cobalt/Kconfig new file mode 100644 index 0000000..3be1b2c --- /dev/null +++ b/drivers/media/pci/cobalt/Kconfig @@ -0,0 +1,18 @@ +config VIDEO_COBALT + tristate "Cisco Cobalt support" + depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER + depends on PCI_MSI && MTD_COMPLEX_MAPPINGS && GPIOLIB + select I2C_ALGOBIT + select VIDEO_ADV7604 + select VIDEO_ADV7511 + select VIDEO_ADV7842 + select VIDEOBUF2_DMA_SG + ---help--- + This is a video4linux driver for the Cisco PCIe Cobalt card. + + This board is sadly not available outside of Cisco, but it is + very useful as an example of a real driver that uses all the + latest frameworks and APIs. + + To compile this driver as a module, choose M here: the + module will be called cobalt. diff --git a/drivers/media/pci/cobalt/Makefile b/drivers/media/pci/cobalt/Makefile new file mode 100644 index 0000000..b328955 --- /dev/null +++ b/drivers/media/pci/cobalt/Makefile @@ -0,0 +1,5 @@ +cobalt-objs := cobalt-driver.o cobalt-irq.o cobalt-v4l2.o \ + cobalt-i2c.o cobalt-omnitek.o cobalt-flash.o cobalt-cpld.o \ + cobalt-alsa-main.o cobalt-alsa-pcm.o + +obj-$(CONFIG_VIDEO_COBALT) += cobalt.o diff --git a/drivers/media/pci/cobalt/cobalt-alsa-main.c b/drivers/media/pci/cobalt/cobalt-alsa-main.c new file mode 100644 index 0000000..720e3ad --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-alsa-main.c @@ -0,0 +1,162 @@ +/* + * ALSA interface to cobalt PCM capture streams + * + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/spinlock.h> + +#include <media/v4l2-device.h> + +#include <sound/core.h> +#include <sound/initval.h> + +#include "cobalt-driver.h" +#include "cobalt-alsa.h" +#include "cobalt-alsa-pcm.h" + +static void snd_cobalt_card_free(struct snd_cobalt_card *cobsc) +{ + if (cobsc == NULL) + return; + + cobsc->s->alsa = NULL; + + kfree(cobsc); +} + +static void snd_cobalt_card_private_free(struct snd_card *sc) +{ + if (sc == NULL) + return; + snd_cobalt_card_free(sc->private_data); + sc->private_data = NULL; + sc->private_free = NULL; +} + +static int snd_cobalt_card_create(struct cobalt_stream *s, + struct snd_card *sc, + struct snd_cobalt_card **cobsc) +{ + *cobsc = kzalloc(sizeof(struct snd_cobalt_card), GFP_KERNEL); + if (*cobsc == NULL) + return -ENOMEM; + + (*cobsc)->s = s; + (*cobsc)->sc = sc; + + sc->private_data = *cobsc; + sc->private_free = snd_cobalt_card_private_free; + + return 0; +} + +static int snd_cobalt_card_set_names(struct snd_cobalt_card *cobsc) +{ + struct cobalt_stream *s = cobsc->s; + struct cobalt *cobalt = s->cobalt; + struct snd_card *sc = cobsc->sc; + + /* sc->driver is used by alsa-lib's configurator: simple, unique */ + strlcpy(sc->driver, "cobalt", sizeof(sc->driver)); + + /* sc->shortname is a symlink in /proc/asound: COBALT-M -> cardN */ + snprintf(sc->shortname, sizeof(sc->shortname), "cobalt-%d-%d", + cobalt->instance, s->video_channel); + + /* sc->longname is read from /proc/asound/cards */ + snprintf(sc->longname, sizeof(sc->longname), + "Cobalt %d HDMI %d", + cobalt->instance, s->video_channel); + + return 0; +} + +int cobalt_alsa_init(struct cobalt_stream *s) +{ + struct cobalt *cobalt = s->cobalt; + struct snd_card *sc = NULL; + struct snd_cobalt_card *cobsc; + int ret; + + /* Numbrs steps from "Writing an ALSA Driver" by Takashi Iwai */ + + /* (1) Check and increment the device index */ + /* This is a no-op for us. We'll use the cobalt->instance */ + + /* (2) Create a card instance */ + ret = snd_card_new(&cobalt->pci_dev->dev, SNDRV_DEFAULT_IDX1, + SNDRV_DEFAULT_STR1, THIS_MODULE, 0, &sc); + if (ret) { + cobalt_err("snd_card_new() failed with err %d\n", ret); + goto err_exit; + } + + /* (3) Create a main component */ + ret = snd_cobalt_card_create(s, sc, &cobsc); + if (ret) { + cobalt_err("snd_cobalt_card_create() failed with err %d\n", + ret); + goto err_exit_free; + } + + /* (4) Set the driver ID and name strings */ + snd_cobalt_card_set_names(cobsc); + + ret = snd_cobalt_pcm_create(cobsc); + if (ret) { + cobalt_err("snd_cobalt_pcm_create() failed with err %d\n", + ret); + goto err_exit_free; + } + /* FIXME - proc files */ + + /* (7) Set the driver data and return 0 */ + /* We do this out of normal order for PCI drivers to avoid races */ + s->alsa = cobsc; + + /* (6) Register the card instance */ + ret = snd_card_register(sc); + if (ret) { + s->alsa = NULL; + cobalt_err("snd_card_register() failed with err %d\n", ret); + goto err_exit_free; + } + + return 0; + +err_exit_free: + if (sc != NULL) + snd_card_free(sc); + kfree(cobsc); +err_exit: + return ret; +} + +void cobalt_alsa_exit(struct cobalt_stream *s) +{ + struct snd_cobalt_card *cobsc = s->alsa; + + if (cobsc) + snd_card_free(cobsc->sc); + s->alsa = NULL; +} diff --git a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c new file mode 100644 index 0000000..f0bdf10 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c @@ -0,0 +1,603 @@ +/* + * ALSA PCM device for the + * ALSA interface to cobalt PCM capture streams + * + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> + +#include <media/v4l2-device.h> + +#include <sound/core.h> +#include <sound/pcm.h> + +#include "cobalt-driver.h" +#include "cobalt-alsa.h" +#include "cobalt-alsa-pcm.h" + +static unsigned int pcm_debug; +module_param(pcm_debug, int, 0644); +MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm"); + +#define dprintk(fmt, arg...) \ + do { \ + if (pcm_debug) \ + pr_info("cobalt-alsa-pcm %s: " fmt, __func__, ##arg); \ + } while (0) + +static struct snd_pcm_hardware snd_cobalt_hdmi_capture = { + .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID, + + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + + .rates = SNDRV_PCM_RATE_48000, + + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 8, + .buffer_bytes_max = 4 * 240 * 8 * 4, /* 5 ms of data */ + .period_bytes_min = 1920, /* 1 sample = 8 * 4 bytes */ + .period_bytes_max = 240 * 8 * 4, /* 5 ms of 8 channel data */ + .periods_min = 1, + .periods_max = 4, +}; + +static struct snd_pcm_hardware snd_cobalt_playback = { + .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID, + + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + + .rates = SNDRV_PCM_RATE_48000, + + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 8, + .buffer_bytes_max = 4 * 240 * 8 * 4, /* 5 ms of data */ + .period_bytes_min = 1920, /* 1 sample = 8 * 4 bytes */ + .period_bytes_max = 240 * 8 * 4, /* 5 ms of 8 channel data */ + .periods_min = 1, + .periods_max = 4, +}; + +static void sample_cpy(u8 *dst, const u8 *src, u32 len, bool is_s32) +{ + static const unsigned map[8] = { 0, 1, 5, 4, 2, 3, 6, 7 }; + unsigned idx = 0; + + while (len >= (is_s32 ? 4 : 2)) { + unsigned offset = map[idx] * 4; + u32 val = src[offset + 1] + (src[offset + 2] << 8) + + (src[offset + 3] << 16); + + if (is_s32) { + *dst++ = 0; + *dst++ = val & 0xff; + } + *dst++ = (val >> 8) & 0xff; + *dst++ = (val >> 16) & 0xff; + len -= is_s32 ? 4 : 2; + idx++; + } +} + +static void cobalt_alsa_announce_pcm_data(struct snd_cobalt_card *cobsc, + u8 *pcm_data, + size_t skip, + size_t samples) +{ + struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; + unsigned long flags; + unsigned int oldptr; + unsigned int stride; + int length = samples; + int period_elapsed = 0; + bool is_s32; + + dprintk("cobalt alsa announce ptr=%p data=%p num_bytes=%zd\n", cobsc, + pcm_data, samples); + + substream = cobsc->capture_pcm_substream; + if (substream == NULL) { + dprintk("substream was NULL\n"); + return; + } + + runtime = substream->runtime; + if (runtime == NULL) { + dprintk("runtime was NULL\n"); + return; + } + is_s32 = runtime->format == SNDRV_PCM_FORMAT_S32_LE; + + stride = runtime->frame_bits >> 3; + if (stride == 0) { + dprintk("stride is zero\n"); + return; + } + + if (length == 0) { + dprintk("%s: length was zero\n", __func__); + return; + } + + if (runtime->dma_area == NULL) { + dprintk("dma area was NULL - ignoring\n"); + return; + } + + oldptr = cobsc->hwptr_done_capture; + if (oldptr + length >= runtime->buffer_size) { + unsigned int cnt = runtime->buffer_size - oldptr; + unsigned i; + + for (i = 0; i < cnt; i++) + sample_cpy(runtime->dma_area + (oldptr + i) * stride, + pcm_data + i * skip, + stride, is_s32); + for (i = cnt; i < length; i++) + sample_cpy(runtime->dma_area + (i - cnt) * stride, + pcm_data + i * skip, stride, is_s32); + } else { + unsigned i; + + for (i = 0; i < length; i++) + sample_cpy(runtime->dma_area + (oldptr + i) * stride, + pcm_data + i * skip, + stride, is_s32); + } + snd_pcm_stream_lock_irqsave(substream, flags); + + cobsc->hwptr_done_capture += length; + if (cobsc->hwptr_done_capture >= + runtime->buffer_size) + cobsc->hwptr_done_capture -= + runtime->buffer_size; + + cobsc->capture_transfer_done += length; + if (cobsc->capture_transfer_done >= + runtime->period_size) { + cobsc->capture_transfer_done -= + runtime->period_size; + period_elapsed = 1; + } + + snd_pcm_stream_unlock_irqrestore(substream, flags); + + if (period_elapsed) + snd_pcm_period_elapsed(substream); +} + +static int alsa_fnc(struct vb2_buffer *vb, void *priv) +{ + struct cobalt_stream *s = priv; + unsigned char *p = vb2_plane_vaddr(vb, 0); + int i; + + if (pcm_debug) { + pr_info("alsa: "); + for (i = 0; i < 8 * 4; i++) { + if (!(i & 3)) + pr_cont(" "); + pr_cont("%02x", p[i]); + } + pr_cont("\n"); + } + cobalt_alsa_announce_pcm_data(s->alsa, + vb2_plane_vaddr(vb, 0), + 8 * 4, + vb2_get_plane_payload(vb, 0) / (8 * 4)); + return 0; +} + +static int snd_cobalt_pcm_capture_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + struct cobalt_stream *s = cobsc->s; + + runtime->hw = snd_cobalt_hdmi_capture; + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + cobsc->capture_pcm_substream = substream; + runtime->private_data = s; + cobsc->alsa_record_cnt++; + if (cobsc->alsa_record_cnt == 1) { + int rc; + + rc = vb2_thread_start(&s->q, alsa_fnc, s, s->vdev.name); + if (rc) { + cobsc->alsa_record_cnt--; + return rc; + } + } + return 0; +} + +static int snd_cobalt_pcm_capture_close(struct snd_pcm_substream *substream) +{ + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + struct cobalt_stream *s = cobsc->s; + + cobsc->alsa_record_cnt--; + if (cobsc->alsa_record_cnt == 0) + vb2_thread_stop(&s->q); + return 0; +} + +static int snd_cobalt_pcm_ioctl(struct snd_pcm_substream *substream, + unsigned int cmd, void *arg) +{ + return snd_pcm_lib_ioctl(substream, cmd, arg); +} + + +static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, + size_t size) +{ + struct snd_pcm_runtime *runtime = subs->runtime; + + dprintk("Allocating vbuffer\n"); + if (runtime->dma_area) { + if (runtime->dma_bytes > size) + return 0; + + vfree(runtime->dma_area); + } + runtime->dma_area = vmalloc(size); + if (!runtime->dma_area) + return -ENOMEM; + + runtime->dma_bytes = size; + + return 0; +} + +static int snd_cobalt_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + dprintk("%s called\n", __func__); + + return snd_pcm_alloc_vmalloc_buffer(substream, + params_buffer_bytes(params)); +} + +static int snd_cobalt_pcm_hw_free(struct snd_pcm_substream *substream) +{ + if (substream->runtime->dma_area) { + dprintk("freeing pcm capture region\n"); + vfree(substream->runtime->dma_area); + substream->runtime->dma_area = NULL; + } + + return 0; +} + +static int snd_cobalt_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + + cobsc->hwptr_done_capture = 0; + cobsc->capture_transfer_done = 0; + + return 0; +} + +static int snd_cobalt_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_STOP: + return 0; + default: + return -EINVAL; + } + return 0; +} + +static +snd_pcm_uframes_t snd_cobalt_pcm_pointer(struct snd_pcm_substream *substream) +{ + snd_pcm_uframes_t hwptr_done; + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + + hwptr_done = cobsc->hwptr_done_capture; + + return hwptr_done; +} + +static void pb_sample_cpy(u8 *dst, const u8 *src, u32 len, bool is_s32) +{ + static const unsigned map[8] = { 0, 1, 5, 4, 2, 3, 6, 7 }; + unsigned idx = 0; + + while (len >= (is_s32 ? 4 : 2)) { + unsigned offset = map[idx] * 4; + u8 *out = dst + offset; + + *out++ = 0; + if (is_s32) { + src++; + *out++ = *src++; + } else { + *out++ = 0; + } + *out++ = *src++; + *out = *src++; + len -= is_s32 ? 4 : 2; + idx++; + } +} + +static void cobalt_alsa_pb_pcm_data(struct snd_cobalt_card *cobsc, + u8 *pcm_data, + size_t skip, + size_t samples) +{ + struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; + unsigned long flags; + unsigned int pos; + unsigned int stride; + bool is_s32; + unsigned i; + + dprintk("cobalt alsa pb ptr=%p data=%p samples=%zd\n", cobsc, + pcm_data, samples); + + substream = cobsc->playback_pcm_substream; + if (substream == NULL) { + dprintk("substream was NULL\n"); + return; + } + + runtime = substream->runtime; + if (runtime == NULL) { + dprintk("runtime was NULL\n"); + return; + } + + is_s32 = runtime->format == SNDRV_PCM_FORMAT_S32_LE; + stride = runtime->frame_bits >> 3; + if (stride == 0) { + dprintk("stride is zero\n"); + return; + } + + if (samples == 0) { + dprintk("%s: samples was zero\n", __func__); + return; + } + + if (runtime->dma_area == NULL) { + dprintk("dma area was NULL - ignoring\n"); + return; + } + + pos = cobsc->pb_pos % cobsc->pb_size; + for (i = 0; i < cobsc->pb_count / (8 * 4); i++) + pb_sample_cpy(pcm_data + i * skip, + runtime->dma_area + pos + i * stride, + stride, is_s32); + snd_pcm_stream_lock_irqsave(substream, flags); + + cobsc->pb_pos += i * stride; + + snd_pcm_stream_unlock_irqrestore(substream, flags); + if (cobsc->pb_pos % cobsc->pb_count == 0) + snd_pcm_period_elapsed(substream); +} + +static int alsa_pb_fnc(struct vb2_buffer *vb, void *priv) +{ + struct cobalt_stream *s = priv; + + if (s->alsa->alsa_pb_channel) + cobalt_alsa_pb_pcm_data(s->alsa, + vb2_plane_vaddr(vb, 0), + 8 * 4, + vb2_get_plane_payload(vb, 0) / (8 * 4)); + return 0; +} + +static int snd_cobalt_pcm_playback_open(struct snd_pcm_substream *substream) +{ + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + struct cobalt_stream *s = cobsc->s; + + runtime->hw = snd_cobalt_playback; + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + cobsc->playback_pcm_substream = substream; + runtime->private_data = s; + cobsc->alsa_playback_cnt++; + if (cobsc->alsa_playback_cnt == 1) { + int rc; + + rc = vb2_thread_start(&s->q, alsa_pb_fnc, s, s->vdev.name); + if (rc) { + cobsc->alsa_playback_cnt--; + return rc; + } + } + + return 0; +} + +static int snd_cobalt_pcm_playback_close(struct snd_pcm_substream *substream) +{ + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + struct cobalt_stream *s = cobsc->s; + + cobsc->alsa_playback_cnt--; + if (cobsc->alsa_playback_cnt == 0) + vb2_thread_stop(&s->q); + return 0; +} + +static int snd_cobalt_pcm_pb_prepare(struct snd_pcm_substream *substream) +{ + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + + cobsc->pb_size = snd_pcm_lib_buffer_bytes(substream); + cobsc->pb_count = snd_pcm_lib_period_bytes(substream); + cobsc->pb_pos = 0; + + return 0; +} + +static int snd_cobalt_pcm_pb_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (cobsc->alsa_pb_channel) + return -EBUSY; + cobsc->alsa_pb_channel = true; + return 0; + case SNDRV_PCM_TRIGGER_STOP: + cobsc->alsa_pb_channel = false; + return 0; + default: + return -EINVAL; + } +} + +static +snd_pcm_uframes_t snd_cobalt_pcm_pb_pointer(struct snd_pcm_substream *substream) +{ + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + size_t ptr; + + ptr = cobsc->pb_pos; + + return bytes_to_frames(substream->runtime, ptr) % + substream->runtime->buffer_size; +} + +static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, + unsigned long offset) +{ + void *pageptr = subs->runtime->dma_area + offset; + + return vmalloc_to_page(pageptr); +} + +static struct snd_pcm_ops snd_cobalt_pcm_capture_ops = { + .open = snd_cobalt_pcm_capture_open, + .close = snd_cobalt_pcm_capture_close, + .ioctl = snd_cobalt_pcm_ioctl, + .hw_params = snd_cobalt_pcm_hw_params, + .hw_free = snd_cobalt_pcm_hw_free, + .prepare = snd_cobalt_pcm_prepare, + .trigger = snd_cobalt_pcm_trigger, + .pointer = snd_cobalt_pcm_pointer, + .page = snd_pcm_get_vmalloc_page, +}; + +static struct snd_pcm_ops snd_cobalt_pcm_playback_ops = { + .open = snd_cobalt_pcm_playback_open, + .close = snd_cobalt_pcm_playback_close, + .ioctl = snd_cobalt_pcm_ioctl, + .hw_params = snd_cobalt_pcm_hw_params, + .hw_free = snd_cobalt_pcm_hw_free, + .prepare = snd_cobalt_pcm_pb_prepare, + .trigger = snd_cobalt_pcm_pb_trigger, + .pointer = snd_cobalt_pcm_pb_pointer, + .page = snd_pcm_get_vmalloc_page, +}; + +int snd_cobalt_pcm_create(struct snd_cobalt_card *cobsc) +{ + struct snd_pcm *sp; + struct snd_card *sc = cobsc->sc; + struct cobalt_stream *s = cobsc->s; + struct cobalt *cobalt = s->cobalt; + int ret; + + s->q.gfp_flags |= __GFP_ZERO; + + if (!s->is_output) { + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_AUDIO_IPP_RESETN_BIT(s->video_channel), + 0); + mdelay(2); + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_AUDIO_IPP_RESETN_BIT(s->video_channel), + 1); + mdelay(1); + + ret = snd_pcm_new(sc, "Cobalt PCM-In HDMI", + 0, /* PCM device 0, the only one for this card */ + 0, /* 0 playback substreams */ + 1, /* 1 capture substream */ + &sp); + if (ret) { + cobalt_err("snd_cobalt_pcm_create() failed for input with err %d\n", + ret); + goto err_exit; + } + + snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_CAPTURE, + &snd_cobalt_pcm_capture_ops); + sp->info_flags = 0; + sp->private_data = cobsc; + strlcpy(sp->name, "cobalt", sizeof(sp->name)); + } else { + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_AUDIO_OPP_RESETN_BIT, 0); + mdelay(2); + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_AUDIO_OPP_RESETN_BIT, 1); + mdelay(1); + + ret = snd_pcm_new(sc, "Cobalt PCM-Out HDMI", + 0, /* PCM device 0, the only one for this card */ + 1, /* 0 playback substreams */ + 0, /* 1 capture substream */ + &sp); + if (ret) { + cobalt_err("snd_cobalt_pcm_create() failed for output with err %d\n", + ret); + goto err_exit; + } + + snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_PLAYBACK, + &snd_cobalt_pcm_playback_ops); + sp->info_flags = 0; + sp->private_data = cobsc; + strlcpy(sp->name, "cobalt", sizeof(sp->name)); + } + + return 0; + +err_exit: + return ret; +} diff --git a/drivers/media/pci/cobalt/cobalt-alsa-pcm.h b/drivers/media/pci/cobalt/cobalt-alsa-pcm.h new file mode 100644 index 0000000..513fb1f --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-alsa-pcm.h @@ -0,0 +1,22 @@ +/* + * ALSA PCM device for the + * ALSA interface to cobalt PCM capture streams + * + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +int snd_cobalt_pcm_create(struct snd_cobalt_card *cobsc); diff --git a/drivers/media/pci/cobalt/cobalt-alsa.h b/drivers/media/pci/cobalt/cobalt-alsa.h new file mode 100644 index 0000000..08db699 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-alsa.h @@ -0,0 +1,41 @@ +/* + * ALSA interface to cobalt PCM capture streams + * + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +struct snd_card; + +struct snd_cobalt_card { + struct cobalt_stream *s; + struct snd_card *sc; + unsigned int capture_transfer_done; + unsigned int hwptr_done_capture; + unsigned alsa_record_cnt; + struct snd_pcm_substream *capture_pcm_substream; + + unsigned int pb_size; + unsigned int pb_count; + unsigned int pb_pos; + unsigned pb_filled; + bool alsa_pb_channel; + unsigned alsa_playback_cnt; + struct snd_pcm_substream *playback_pcm_substream; +}; + +int cobalt_alsa_init(struct cobalt_stream *s); +void cobalt_alsa_exit(struct cobalt_stream *s); diff --git a/drivers/media/pci/cobalt/cobalt-cpld.c b/drivers/media/pci/cobalt/cobalt-cpld.c new file mode 100644 index 0000000..e83f5c9 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-cpld.c @@ -0,0 +1,341 @@ +/* + * Cobalt CPLD functions + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/delay.h> + +#include "cobalt-cpld.h" + +#define ADRS(offset) (COBALT_BUS_CPLD_BASE + offset) + +static u16 cpld_read(struct cobalt *cobalt, u32 offset) +{ + return cobalt_bus_read32(cobalt->bar1, ADRS(offset)); +} + +static void cpld_write(struct cobalt *cobalt, u32 offset, u16 val) +{ + return cobalt_bus_write32(cobalt->bar1, ADRS(offset), val); +} + +static void cpld_info_ver3(struct cobalt *cobalt) +{ + u32 rd; + u32 tmp; + + cobalt_info("CPLD System control register (read/write)\n"); + cobalt_info("\t\tSystem control: 0x%04x (0x0f00)\n", + cpld_read(cobalt, 0)); + cobalt_info("CPLD Clock control register (read/write)\n"); + cobalt_info("\t\tClock control: 0x%04x (0x0000)\n", + cpld_read(cobalt, 0x04)); + cobalt_info("CPLD HSMA Clk Osc register (read/write) - Must set wr trigger to load default values\n"); + cobalt_info("\t\tRegister #7:\t0x%04x (0x0022)\n", + cpld_read(cobalt, 0x08)); + cobalt_info("\t\tRegister #8:\t0x%04x (0x0047)\n", + cpld_read(cobalt, 0x0c)); + cobalt_info("\t\tRegister #9:\t0x%04x (0x00fa)\n", + cpld_read(cobalt, 0x10)); + cobalt_info("\t\tRegister #10:\t0x%04x (0x0061)\n", + cpld_read(cobalt, 0x14)); + cobalt_info("\t\tRegister #11:\t0x%04x (0x001e)\n", + cpld_read(cobalt, 0x18)); + cobalt_info("\t\tRegister #12:\t0x%04x (0x0045)\n", + cpld_read(cobalt, 0x1c)); + cobalt_info("\t\tRegister #135:\t0x%04x\n", + cpld_read(cobalt, 0x20)); + cobalt_info("\t\tRegister #137:\t0x%04x\n", + cpld_read(cobalt, 0x24)); + cobalt_info("CPLD System status register (read only)\n"); + cobalt_info("\t\tSystem status: 0x%04x\n", + cpld_read(cobalt, 0x28)); + cobalt_info("CPLD MAXII info register (read only)\n"); + cobalt_info("\t\tBoard serial number: 0x%04x\n", + cpld_read(cobalt, 0x2c)); + cobalt_info("\t\tMAXII program revision: 0x%04x\n", + cpld_read(cobalt, 0x30)); + cobalt_info("CPLD temp and voltage ADT7411 registers (read only)\n"); + cobalt_info("\t\tBoard temperature: %u Celcius\n", + cpld_read(cobalt, 0x34) / 4); + cobalt_info("\t\tFPGA temperature: %u Celcius\n", + cpld_read(cobalt, 0x38) / 4); + rd = cpld_read(cobalt, 0x3c); + tmp = (rd * 33 * 1000) / (483 * 10); + cobalt_info("\t\tVDD 3V3: %u,%03uV\n", tmp / 1000, tmp % 1000); + rd = cpld_read(cobalt, 0x40); + tmp = (rd * 74 * 2197) / (27 * 1000); + cobalt_info("\t\tADC ch3 5V: %u,%03uV\n", tmp / 1000, tmp % 1000); + rd = cpld_read(cobalt, 0x44); + tmp = (rd * 74 * 2197) / (47 * 1000); + cobalt_info("\t\tADC ch4 3V: %u,%03uV\n", tmp / 1000, tmp % 1000); + rd = cpld_read(cobalt, 0x48); + tmp = (rd * 57 * 2197) / (47 * 1000); + cobalt_info("\t\tADC ch5 2V5: %u,%03uV\n", tmp / 1000, tmp % 1000); + rd = cpld_read(cobalt, 0x4c); + tmp = (rd * 2197) / 1000; + cobalt_info("\t\tADC ch6 1V8: %u,%03uV\n", tmp / 1000, tmp % 1000); + rd = cpld_read(cobalt, 0x50); + tmp = (rd * 2197) / 1000; + cobalt_info("\t\tADC ch7 1V5: %u,%03uV\n", tmp / 1000, tmp % 1000); + rd = cpld_read(cobalt, 0x54); + tmp = (rd * 2197) / 1000; + cobalt_info("\t\tADC ch8 0V9: %u,%03uV\n", tmp / 1000, tmp % 1000); +} + +void cobalt_cpld_status(struct cobalt *cobalt) +{ + u32 rev = cpld_read(cobalt, 0x30); + + switch (rev) { + case 3: + case 4: + case 5: + cpld_info_ver3(cobalt); + break; + default: + cobalt_info("CPLD revision %u is not supported!\n", rev); + break; + } +} + +#define DCO_MIN 4850000000ULL +#define DCO_MAX 5670000000ULL + +#define SI570_CLOCK_CTRL 0x04 +#define S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_WR_TRIGGER 0x200 +#define S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_RST_TRIGGER 0x100 +#define S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL 0x80 +#define S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN 0x40 + +#define SI570_REG7 0x08 +#define SI570_REG8 0x0c +#define SI570_REG9 0x10 +#define SI570_REG10 0x14 +#define SI570_REG11 0x18 +#define SI570_REG12 0x1c +#define SI570_REG135 0x20 +#define SI570_REG137 0x24 + +struct multiplier { + unsigned mult, hsdiv, n1; +}; + +/* List all possible multipliers (= hsdiv * n1). There are lots of duplicates, + which are all removed in this list to keep the list as short as possible. + The values for hsdiv and n1 are the actual values, not the register values. + */ +static const struct multiplier multipliers[] = { + { 4, 4, 1 }, { 5, 5, 1 }, { 6, 6, 1 }, + { 7, 7, 1 }, { 8, 4, 2 }, { 9, 9, 1 }, + { 10, 5, 2 }, { 11, 11, 1 }, { 12, 6, 2 }, + { 14, 7, 2 }, { 16, 4, 4 }, { 18, 9, 2 }, + { 20, 5, 4 }, { 22, 11, 2 }, { 24, 4, 6 }, + { 28, 7, 4 }, { 30, 5, 6 }, { 32, 4, 8 }, + { 36, 6, 6 }, { 40, 4, 10 }, { 42, 7, 6 }, + { 44, 11, 4 }, { 48, 4, 12 }, { 50, 5, 10 }, + { 54, 9, 6 }, { 56, 4, 14 }, { 60, 5, 12 }, + { 64, 4, 16 }, { 66, 11, 6 }, { 70, 5, 14 }, + { 72, 4, 18 }, { 80, 4, 20 }, { 84, 6, 14 }, + { 88, 11, 8 }, { 90, 5, 18 }, { 96, 4, 24 }, + { 98, 7, 14 }, { 100, 5, 20 }, { 104, 4, 26 }, + { 108, 6, 18 }, { 110, 11, 10 }, { 112, 4, 28 }, + { 120, 4, 30 }, { 126, 7, 18 }, { 128, 4, 32 }, + { 130, 5, 26 }, { 132, 11, 12 }, { 136, 4, 34 }, + { 140, 5, 28 }, { 144, 4, 36 }, { 150, 5, 30 }, + { 152, 4, 38 }, { 154, 11, 14 }, { 156, 6, 26 }, + { 160, 4, 40 }, { 162, 9, 18 }, { 168, 4, 42 }, + { 170, 5, 34 }, { 176, 11, 16 }, { 180, 5, 36 }, + { 182, 7, 26 }, { 184, 4, 46 }, { 190, 5, 38 }, + { 192, 4, 48 }, { 196, 7, 28 }, { 198, 11, 18 }, + { 198, 9, 22 }, { 200, 4, 50 }, { 204, 6, 34 }, + { 208, 4, 52 }, { 210, 5, 42 }, { 216, 4, 54 }, + { 220, 11, 20 }, { 224, 4, 56 }, { 228, 6, 38 }, + { 230, 5, 46 }, { 232, 4, 58 }, { 234, 9, 26 }, + { 238, 7, 34 }, { 240, 4, 60 }, { 242, 11, 22 }, + { 248, 4, 62 }, { 250, 5, 50 }, { 252, 6, 42 }, + { 256, 4, 64 }, { 260, 5, 52 }, { 264, 11, 24 }, + { 266, 7, 38 }, { 270, 5, 54 }, { 272, 4, 68 }, + { 276, 6, 46 }, { 280, 4, 70 }, { 286, 11, 26 }, + { 288, 4, 72 }, { 290, 5, 58 }, { 294, 7, 42 }, + { 296, 4, 74 }, { 300, 5, 60 }, { 304, 4, 76 }, + { 306, 9, 34 }, { 308, 11, 28 }, { 310, 5, 62 }, + { 312, 4, 78 }, { 320, 4, 80 }, { 322, 7, 46 }, + { 324, 6, 54 }, { 328, 4, 82 }, { 330, 11, 30 }, + { 336, 4, 84 }, { 340, 5, 68 }, { 342, 9, 38 }, + { 344, 4, 86 }, { 348, 6, 58 }, { 350, 5, 70 }, + { 352, 11, 32 }, { 360, 4, 90 }, { 364, 7, 52 }, + { 368, 4, 92 }, { 370, 5, 74 }, { 372, 6, 62 }, + { 374, 11, 34 }, { 376, 4, 94 }, { 378, 7, 54 }, + { 380, 5, 76 }, { 384, 4, 96 }, { 390, 5, 78 }, + { 392, 4, 98 }, { 396, 11, 36 }, { 400, 4, 100 }, + { 406, 7, 58 }, { 408, 4, 102 }, { 410, 5, 82 }, + { 414, 9, 46 }, { 416, 4, 104 }, { 418, 11, 38 }, + { 420, 5, 84 }, { 424, 4, 106 }, { 430, 5, 86 }, + { 432, 4, 108 }, { 434, 7, 62 }, { 440, 11, 40 }, + { 444, 6, 74 }, { 448, 4, 112 }, { 450, 5, 90 }, + { 456, 4, 114 }, { 460, 5, 92 }, { 462, 11, 42 }, + { 464, 4, 116 }, { 468, 6, 78 }, { 470, 5, 94 }, + { 472, 4, 118 }, { 476, 7, 68 }, { 480, 4, 120 }, + { 484, 11, 44 }, { 486, 9, 54 }, { 488, 4, 122 }, + { 490, 5, 98 }, { 492, 6, 82 }, { 496, 4, 124 }, + { 500, 5, 100 }, { 504, 4, 126 }, { 506, 11, 46 }, + { 510, 5, 102 }, { 512, 4, 128 }, { 516, 6, 86 }, + { 518, 7, 74 }, { 520, 5, 104 }, { 522, 9, 58 }, + { 528, 11, 48 }, { 530, 5, 106 }, { 532, 7, 76 }, + { 540, 5, 108 }, { 546, 7, 78 }, { 550, 11, 50 }, + { 552, 6, 92 }, { 558, 9, 62 }, { 560, 5, 112 }, + { 564, 6, 94 }, { 570, 5, 114 }, { 572, 11, 52 }, + { 574, 7, 82 }, { 576, 6, 96 }, { 580, 5, 116 }, + { 588, 6, 98 }, { 590, 5, 118 }, { 594, 11, 54 }, + { 600, 5, 120 }, { 602, 7, 86 }, { 610, 5, 122 }, + { 612, 6, 102 }, { 616, 11, 56 }, { 620, 5, 124 }, + { 624, 6, 104 }, { 630, 5, 126 }, { 636, 6, 106 }, + { 638, 11, 58 }, { 640, 5, 128 }, { 644, 7, 92 }, + { 648, 6, 108 }, { 658, 7, 94 }, { 660, 11, 60 }, + { 666, 9, 74 }, { 672, 6, 112 }, { 682, 11, 62 }, + { 684, 6, 114 }, { 686, 7, 98 }, { 696, 6, 116 }, + { 700, 7, 100 }, { 702, 9, 78 }, { 704, 11, 64 }, + { 708, 6, 118 }, { 714, 7, 102 }, { 720, 6, 120 }, + { 726, 11, 66 }, { 728, 7, 104 }, { 732, 6, 122 }, + { 738, 9, 82 }, { 742, 7, 106 }, { 744, 6, 124 }, + { 748, 11, 68 }, { 756, 6, 126 }, { 768, 6, 128 }, + { 770, 11, 70 }, { 774, 9, 86 }, { 784, 7, 112 }, + { 792, 11, 72 }, { 798, 7, 114 }, { 810, 9, 90 }, + { 812, 7, 116 }, { 814, 11, 74 }, { 826, 7, 118 }, + { 828, 9, 92 }, { 836, 11, 76 }, { 840, 7, 120 }, + { 846, 9, 94 }, { 854, 7, 122 }, { 858, 11, 78 }, + { 864, 9, 96 }, { 868, 7, 124 }, { 880, 11, 80 }, + { 882, 7, 126 }, { 896, 7, 128 }, { 900, 9, 100 }, + { 902, 11, 82 }, { 918, 9, 102 }, { 924, 11, 84 }, + { 936, 9, 104 }, { 946, 11, 86 }, { 954, 9, 106 }, + { 968, 11, 88 }, { 972, 9, 108 }, { 990, 11, 90 }, + { 1008, 9, 112 }, { 1012, 11, 92 }, { 1026, 9, 114 }, + { 1034, 11, 94 }, { 1044, 9, 116 }, { 1056, 11, 96 }, + { 1062, 9, 118 }, { 1078, 11, 98 }, { 1080, 9, 120 }, + { 1098, 9, 122 }, { 1100, 11, 100 }, { 1116, 9, 124 }, + { 1122, 11, 102 }, { 1134, 9, 126 }, { 1144, 11, 104 }, + { 1152, 9, 128 }, { 1166, 11, 106 }, { 1188, 11, 108 }, + { 1210, 11, 110 }, { 1232, 11, 112 }, { 1254, 11, 114 }, + { 1276, 11, 116 }, { 1298, 11, 118 }, { 1320, 11, 120 }, + { 1342, 11, 122 }, { 1364, 11, 124 }, { 1386, 11, 126 }, + { 1408, 11, 128 }, +}; + +bool cobalt_cpld_set_freq(struct cobalt *cobalt, unsigned f_out) +{ + const unsigned f_xtal = 39170000; /* xtal for si598 */ + u64 dco; + u64 rfreq; + unsigned delta = 0xffffffff; + unsigned i_best = 0; + unsigned i; + u8 n1, hsdiv; + u8 regs[6]; + int found = 0; + u16 clock_ctrl; + int retries = 3; + + for (i = 0; i < ARRAY_SIZE(multipliers); i++) { + unsigned mult = multipliers[i].mult; + u32 d; + + dco = (u64)f_out * mult; + if (dco < DCO_MIN || dco > DCO_MAX) + continue; + div_u64_rem((dco << 28) + f_xtal / 2, f_xtal, &d); + if (d < delta) { + found = 1; + i_best = i; + delta = d; + } + } + if (!found) + return false; + dco = (u64)f_out * multipliers[i_best].mult; + n1 = multipliers[i_best].n1 - 1; + hsdiv = multipliers[i_best].hsdiv - 4; + rfreq = div_u64(dco << 28, f_xtal); + + clock_ctrl = cpld_read(cobalt, SI570_CLOCK_CTRL); + clock_ctrl |= S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL; + clock_ctrl |= S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN; + + regs[0] = (hsdiv << 5) | (n1 >> 2); + regs[1] = ((n1 & 0x3) << 6) | (rfreq >> 32); + regs[2] = (rfreq >> 24) & 0xff; + regs[3] = (rfreq >> 16) & 0xff; + regs[4] = (rfreq >> 8) & 0xff; + regs[5] = rfreq & 0xff; + + /* The sequence of clock_ctrl flags to set is very weird. It looks + like I have to reset it, then set the new frequency and reset it + again. It shouldn't be necessary to do a reset, but if I don't, + then a strange frequency is set (156.412034 MHz, or register values + 0x01, 0xc7, 0xfc, 0x7f, 0x53, 0x62). + */ + + cobalt_dbg(1, "%u: %02x %02x %02x %02x %02x %02x\n", f_out, + regs[0], regs[1], regs[2], regs[3], regs[4], regs[5]); + while (retries--) { + u8 read_regs[6]; + + cpld_write(cobalt, SI570_CLOCK_CTRL, + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN | + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL); + usleep_range(10000, 15000); + cpld_write(cobalt, SI570_REG7, regs[0]); + cpld_write(cobalt, SI570_REG8, regs[1]); + cpld_write(cobalt, SI570_REG9, regs[2]); + cpld_write(cobalt, SI570_REG10, regs[3]); + cpld_write(cobalt, SI570_REG11, regs[4]); + cpld_write(cobalt, SI570_REG12, regs[5]); + cpld_write(cobalt, SI570_CLOCK_CTRL, + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN | + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_WR_TRIGGER); + usleep_range(10000, 15000); + cpld_write(cobalt, SI570_CLOCK_CTRL, + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN | + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL); + usleep_range(10000, 15000); + read_regs[0] = cpld_read(cobalt, SI570_REG7); + read_regs[1] = cpld_read(cobalt, SI570_REG8); + read_regs[2] = cpld_read(cobalt, SI570_REG9); + read_regs[3] = cpld_read(cobalt, SI570_REG10); + read_regs[4] = cpld_read(cobalt, SI570_REG11); + read_regs[5] = cpld_read(cobalt, SI570_REG12); + cpld_write(cobalt, SI570_CLOCK_CTRL, + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN | + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL | + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_RST_TRIGGER); + usleep_range(10000, 15000); + cpld_write(cobalt, SI570_CLOCK_CTRL, + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN); + usleep_range(10000, 15000); + + if (!memcmp(read_regs, regs, sizeof(read_regs))) + break; + cobalt_dbg(1, "retry: %02x %02x %02x %02x %02x %02x\n", + read_regs[0], read_regs[1], read_regs[2], + read_regs[3], read_regs[4], read_regs[5]); + } + if (2 - retries) + cobalt_info("Needed %d retries\n", 2 - retries); + + return true; +} diff --git a/drivers/media/pci/cobalt/cobalt-cpld.h b/drivers/media/pci/cobalt/cobalt-cpld.h new file mode 100644 index 0000000..0fc88fd --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-cpld.h @@ -0,0 +1,29 @@ +/* + * Cobalt CPLD functions + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef COBALT_CPLD_H +#define COBALT_CPLD_H + +#include "cobalt-driver.h" + +void cobalt_cpld_status(struct cobalt *cobalt); +bool cobalt_cpld_set_freq(struct cobalt *cobalt, unsigned freq); + +#endif diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c new file mode 100644 index 0000000..b994b8e --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -0,0 +1,832 @@ +/* + * cobalt driver initialization and card probing + * + * Derived from cx18-driver.c + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/delay.h> +#include <media/adv7604.h> +#include <media/adv7842.h> +#include <media/adv7511.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ctrls.h> + +#include "cobalt-driver.h" +#include "cobalt-irq.h" +#include "cobalt-i2c.h" +#include "cobalt-v4l2.h" +#include "cobalt-flash.h" +#include "cobalt-alsa.h" +#include "cobalt-omnitek.h" + +/* add your revision and whatnot here */ +static struct pci_device_id cobalt_pci_tbl[] = { + {PCI_VENDOR_ID_CISCO, PCI_DEVICE_ID_COBALT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, cobalt_pci_tbl); + +static atomic_t cobalt_instance = ATOMIC_INIT(0); + +int cobalt_debug; +module_param_named(debug, cobalt_debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level. Default: 0\n"); + +int cobalt_ignore_err; +module_param_named(ignore_err, cobalt_ignore_err, int, 0644); +MODULE_PARM_DESC(ignore_err, + "If set then ignore missing i2c adapters/receivers. Default: 0\n"); + +MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com> & Morten Hestnes"); +MODULE_DESCRIPTION("cobalt driver"); +MODULE_LICENSE("GPL"); + +static u8 edid[256] = { + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x50, 0x21, 0x9C, 0x27, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x12, 0x01, 0x03, 0x80, 0x00, 0x00, 0x78, + 0x0E, 0x00, 0xB2, 0xA0, 0x57, 0x49, 0x9B, 0x26, + 0x10, 0x48, 0x4F, 0x2F, 0xCF, 0x00, 0x31, 0x59, + 0x45, 0x59, 0x61, 0x59, 0x81, 0x99, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3A, + 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C, + 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, + 0x00, 0x00, 0x00, 0xFD, 0x00, 0x31, 0x55, 0x18, + 0x5E, 0x11, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x43, + 0x20, 0x39, 0x30, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, + 0x02, 0x03, 0x1a, 0xc0, 0x48, 0xa2, 0x10, 0x04, + 0x02, 0x01, 0x21, 0x14, 0x13, 0x23, 0x09, 0x07, + 0x07, 0x65, 0x03, 0x0c, 0x00, 0x10, 0x00, 0xe2, + 0x00, 0x2a, 0x01, 0x1d, 0x00, 0x80, 0x51, 0xd0, + 0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1e, 0x8c, 0x0a, 0xd0, 0x8a, + 0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd7 +}; + +static void cobalt_set_interrupt(struct cobalt *cobalt, bool enable) +{ + if (enable) { + unsigned irqs = COBALT_SYSSTAT_VI0_INT1_MSK | + COBALT_SYSSTAT_VI1_INT1_MSK | + COBALT_SYSSTAT_VI2_INT1_MSK | + COBALT_SYSSTAT_VI3_INT1_MSK | + COBALT_SYSSTAT_VI0_INT2_MSK | + COBALT_SYSSTAT_VI1_INT2_MSK | + COBALT_SYSSTAT_VI2_INT2_MSK | + COBALT_SYSSTAT_VI3_INT2_MSK | + COBALT_SYSSTAT_VI0_LOST_DATA_MSK | + COBALT_SYSSTAT_VI1_LOST_DATA_MSK | + COBALT_SYSSTAT_VI2_LOST_DATA_MSK | + COBALT_SYSSTAT_VI3_LOST_DATA_MSK | + COBALT_SYSSTAT_AUD_IN_LOST_DATA_MSK; + + if (cobalt->have_hsma_rx) + irqs |= COBALT_SYSSTAT_VIHSMA_INT1_MSK | + COBALT_SYSSTAT_VIHSMA_INT2_MSK | + COBALT_SYSSTAT_VIHSMA_LOST_DATA_MSK; + + if (cobalt->have_hsma_tx) + irqs |= COBALT_SYSSTAT_VOHSMA_INT1_MSK | + COBALT_SYSSTAT_VOHSMA_LOST_DATA_MSK | + COBALT_SYSSTAT_AUD_OUT_LOST_DATA_MSK; + /* Clear any existing interrupts */ + cobalt_write_bar1(cobalt, COBALT_SYS_STAT_EDGE, 0xffffffff); + /* PIO Core interrupt mask register. + Enable ADV7604 INT1 interrupts */ + cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, irqs); + } else { + /* Disable all ADV7604 interrupts */ + cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, 0); + } +} + +static unsigned cobalt_get_sd_nr(struct v4l2_subdev *sd) +{ + struct cobalt *cobalt = to_cobalt(sd->v4l2_dev); + unsigned i; + + for (i = 0; i < COBALT_NUM_NODES; i++) + if (sd == cobalt->streams[i].sd) + return i; + cobalt_err("Invalid adv7604 subdev pointer!\n"); + return 0; +} + +static void cobalt_notify(struct v4l2_subdev *sd, + unsigned int notification, void *arg) +{ + struct cobalt *cobalt = to_cobalt(sd->v4l2_dev); + unsigned sd_nr = cobalt_get_sd_nr(sd); + struct cobalt_stream *s = &cobalt->streams[sd_nr]; + bool hotplug = arg ? *((int *)arg) : false; + + if (s->is_output) + return; + + switch (notification) { + case ADV76XX_HOTPLUG: + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_HPD_TO_CONNECTOR_BIT(sd_nr), hotplug); + cobalt_dbg(1, "Set hotplug for adv %d to %d\n", sd_nr, hotplug); + break; + case V4L2_DEVICE_NOTIFY_EVENT: + cobalt_dbg(1, "Format changed for adv %d\n", sd_nr); + v4l2_event_queue(&s->vdev, arg); + break; + default: + break; + } +} + +static int get_payload_size(u16 code) +{ + switch (code) { + case 0: return 128; + case 1: return 256; + case 2: return 512; + case 3: return 1024; + case 4: return 2048; + case 5: return 4096; + default: return 0; + } + return 0; +} + +static const char *get_link_speed(u16 stat) +{ + switch (stat & PCI_EXP_LNKSTA_CLS) { + case 1: return "2.5 Gbit/s"; + case 2: return "5 Gbit/s"; + case 3: return "10 Gbit/s"; + } + return "Unknown speed"; +} + +void cobalt_pcie_status_show(struct cobalt *cobalt) +{ + struct pci_dev *pci_dev = cobalt->pci_dev; + struct pci_dev *pci_bus_dev = cobalt->pci_dev->bus->self; + int offset; + int bus_offset; + u32 capa; + u16 stat, ctrl; + + offset = pci_find_capability(pci_dev, PCI_CAP_ID_EXP); + bus_offset = pci_find_capability(pci_bus_dev, PCI_CAP_ID_EXP); + + /* Device */ + pci_read_config_dword(pci_dev, offset + PCI_EXP_DEVCAP, &capa); + pci_read_config_word(pci_dev, offset + PCI_EXP_DEVCTL, &ctrl); + pci_read_config_word(pci_dev, offset + PCI_EXP_DEVSTA, &stat); + cobalt_info("PCIe device capability 0x%08x: Max payload %d\n", + capa, get_payload_size(capa & PCI_EXP_DEVCAP_PAYLOAD)); + cobalt_info("PCIe device control 0x%04x: Max payload %d. Max read request %d\n", + ctrl, + get_payload_size((ctrl & PCI_EXP_DEVCTL_PAYLOAD) >> 5), + get_payload_size((ctrl & PCI_EXP_DEVCTL_READRQ) >> 12)); + cobalt_info("PCIe device status 0x%04x\n", stat); + + /* Link */ + pci_read_config_dword(pci_dev, offset + PCI_EXP_LNKCAP, &capa); + pci_read_config_word(pci_dev, offset + PCI_EXP_LNKCTL, &ctrl); + pci_read_config_word(pci_dev, offset + PCI_EXP_LNKSTA, &stat); + cobalt_info("PCIe link capability 0x%08x: %s per lane and %u lanes\n", + capa, get_link_speed(capa), + (capa & PCI_EXP_LNKCAP_MLW) >> 4); + cobalt_info("PCIe link control 0x%04x\n", ctrl); + cobalt_info("PCIe link status 0x%04x: %s per lane and %u lanes\n", + stat, get_link_speed(stat), + (stat & PCI_EXP_LNKSTA_NLW) >> 4); + + /* Bus */ + pci_read_config_dword(pci_bus_dev, bus_offset + PCI_EXP_LNKCAP, &capa); + cobalt_info("PCIe bus link capability 0x%08x: %s per lane and %u lanes\n", + capa, get_link_speed(capa), + (capa & PCI_EXP_LNKCAP_MLW) >> 4); + + /* Slot */ + pci_read_config_dword(pci_dev, offset + PCI_EXP_SLTCAP, &capa); + pci_read_config_word(pci_dev, offset + PCI_EXP_SLTCTL, &ctrl); + pci_read_config_word(pci_dev, offset + PCI_EXP_SLTSTA, &stat); + cobalt_info("PCIe slot capability 0x%08x\n", capa); + cobalt_info("PCIe slot control 0x%04x\n", ctrl); + cobalt_info("PCIe slot status 0x%04x\n", stat); +} + +static unsigned pcie_link_get_lanes(struct cobalt *cobalt) +{ + struct pci_dev *pci_dev = cobalt->pci_dev; + unsigned offset; + u16 link; + + offset = pci_find_capability(pci_dev, PCI_CAP_ID_EXP); + if (!offset) + return 0; + pci_read_config_word(pci_dev, offset + PCI_EXP_LNKSTA, &link); + return (link & PCI_EXP_LNKSTA_NLW) >> 4; +} + +static unsigned pcie_bus_link_get_lanes(struct cobalt *cobalt) +{ + struct pci_dev *pci_dev = cobalt->pci_dev->bus->self; + unsigned offset; + u32 link; + + offset = pci_find_capability(pci_dev, PCI_CAP_ID_EXP); + if (!offset) + return 0; + pci_read_config_dword(pci_dev, offset + PCI_EXP_LNKCAP, &link); + return (link & PCI_EXP_LNKCAP_MLW) >> 4; +} + +static void msi_config_show(struct cobalt *cobalt, struct pci_dev *pci_dev) +{ + u16 ctrl, data; + u32 adrs_l, adrs_h; + + pci_read_config_word(pci_dev, 0x52, &ctrl); + cobalt_info("MSI %s\n", ctrl & 1 ? "enable" : "disable"); + cobalt_info("MSI multiple message: Capable %u. Enable %u\n", + (1 << ((ctrl >> 1) & 7)), (1 << ((ctrl >> 4) & 7))); + if (ctrl & 0x80) + cobalt_info("MSI: 64-bit address capable\n"); + pci_read_config_dword(pci_dev, 0x54, &adrs_l); + pci_read_config_dword(pci_dev, 0x58, &adrs_h); + pci_read_config_word(pci_dev, 0x5c, &data); + if (ctrl & 0x80) + cobalt_info("MSI: Address 0x%08x%08x. Data 0x%04x\n", + adrs_h, adrs_l, data); + else + cobalt_info("MSI: Address 0x%08x. Data 0x%04x\n", + adrs_l, data); +} + +static void cobalt_pci_iounmap(struct cobalt *cobalt, struct pci_dev *pci_dev) +{ + if (cobalt->bar0) { + pci_iounmap(pci_dev, cobalt->bar0); + cobalt->bar0 = NULL; + } + if (cobalt->bar1) { + pci_iounmap(pci_dev, cobalt->bar1); + cobalt->bar1 = NULL; + } +} + +static void cobalt_free_msi(struct cobalt *cobalt, struct pci_dev *pci_dev) +{ + free_irq(pci_dev->irq, (void *)cobalt); + + if (cobalt->msi_enabled) + pci_disable_msi(pci_dev); +} + +static int cobalt_setup_pci(struct cobalt *cobalt, struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + u32 ctrl; + int ret; + + cobalt_dbg(1, "enabling pci device\n"); + + ret = pci_enable_device(pci_dev); + if (ret) { + cobalt_err("can't enable device\n"); + return ret; + } + pci_set_master(pci_dev); + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &cobalt->card_rev); + pci_read_config_word(pci_dev, PCI_DEVICE_ID, &cobalt->device_id); + + switch (cobalt->device_id) { + case PCI_DEVICE_ID_COBALT: + cobalt_info("PCI Express interface from Omnitek\n"); + break; + default: + cobalt_info("PCI Express interface provider is unknown!\n"); + break; + } + + if (pcie_link_get_lanes(cobalt) != 8) { + cobalt_err("PCI Express link width is not 8 lanes (%d)\n", + pcie_link_get_lanes(cobalt)); + if (pcie_bus_link_get_lanes(cobalt) < 8) + cobalt_err("The current slot only supports %d lanes, at least 8 are needed\n", + pcie_bus_link_get_lanes(cobalt)); + else + cobalt_err("The card is most likely not seated correctly in the PCIe slot\n"); + ret = -EIO; + goto err_disable; + } + + if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(64))) { + ret = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); + if (ret) { + cobalt_err("no suitable DMA available\n"); + goto err_disable; + } + } + + ret = pci_request_regions(pci_dev, "cobalt"); + if (ret) { + cobalt_err("error requesting regions\n"); + goto err_disable; + } + + cobalt_pcie_status_show(cobalt); + + cobalt->bar0 = pci_iomap(pci_dev, 0, 0); + cobalt->bar1 = pci_iomap(pci_dev, 1, 0); + if (cobalt->bar1 == NULL) { + cobalt->bar1 = pci_iomap(pci_dev, 2, 0); + cobalt_info("64-bit BAR\n"); + } + if (!cobalt->bar0 || !cobalt->bar1) { + ret = -EIO; + goto err_release; + } + + /* Reset the video inputs before enabling any interrupts */ + ctrl = cobalt_read_bar1(cobalt, COBALT_SYS_CTRL_BASE); + cobalt_write_bar1(cobalt, COBALT_SYS_CTRL_BASE, ctrl & ~0xf00); + + /* Disable interrupts to prevent any spurious interrupts + from being generated. */ + cobalt_set_interrupt(cobalt, false); + + if (pci_enable_msi_range(pci_dev, 1, 1) < 1) { + cobalt_err("Could not enable MSI\n"); + cobalt->msi_enabled = false; + ret = -EIO; + goto err_release; + } + msi_config_show(cobalt, pci_dev); + cobalt->msi_enabled = true; + + /* Register IRQ */ + if (request_irq(pci_dev->irq, cobalt_irq_handler, IRQF_SHARED, + cobalt->v4l2_dev.name, (void *)cobalt)) { + cobalt_err("Failed to register irq %d\n", pci_dev->irq); + ret = -EIO; + goto err_msi; + } + + omni_sg_dma_init(cobalt); + return 0; + +err_msi: + pci_disable_msi(pci_dev); + +err_release: + cobalt_pci_iounmap(cobalt, pci_dev); + pci_release_regions(pci_dev); + +err_disable: + pci_disable_device(cobalt->pci_dev); + return ret; +} + +static int cobalt_hdl_info_get(struct cobalt *cobalt) +{ + int i; + + for (i = 0; i < COBALT_HDL_INFO_SIZE; i++) + cobalt->hdl_info[i] = + ioread8(cobalt->bar1 + COBALT_HDL_INFO_BASE + i); + cobalt->hdl_info[COBALT_HDL_INFO_SIZE - 1] = '\0'; + if (strstr(cobalt->hdl_info, COBALT_HDL_SEARCH_STR)) + return 0; + + return 1; +} + +static void cobalt_stream_struct_init(struct cobalt *cobalt) +{ + int i; + + for (i = 0; i < COBALT_NUM_STREAMS; i++) { + struct cobalt_stream *s = &cobalt->streams[i]; + + s->cobalt = cobalt; + s->flags = 0; + s->is_audio = false; + s->is_output = false; + s->is_dummy = true; + + /* The Memory DMA channels will always get a lower channel + * number than the FIFO DMA. Video input should map to the + * stream 0-3. The other can use stream struct from 4 and + * higher */ + if (i <= COBALT_HSMA_IN_NODE) { + s->dma_channel = i + cobalt->first_fifo_channel; + s->video_channel = i; + s->dma_fifo_mask = + COBALT_SYSSTAT_VI0_LOST_DATA_MSK << (4 * i); + s->adv_irq_mask = + COBALT_SYSSTAT_VI0_INT1_MSK << (4 * i); + } else if (i >= COBALT_AUDIO_IN_STREAM && + i <= COBALT_AUDIO_IN_STREAM + 4) { + unsigned idx = i - COBALT_AUDIO_IN_STREAM; + + s->dma_channel = 6 + idx; + s->is_audio = true; + s->video_channel = idx; + s->dma_fifo_mask = COBALT_SYSSTAT_AUD_IN_LOST_DATA_MSK; + } else if (i == COBALT_HSMA_OUT_NODE) { + s->dma_channel = 11; + s->is_output = true; + s->video_channel = 5; + s->dma_fifo_mask = COBALT_SYSSTAT_VOHSMA_LOST_DATA_MSK; + s->adv_irq_mask = COBALT_SYSSTAT_VOHSMA_INT1_MSK; + } else if (i == COBALT_AUDIO_OUT_STREAM) { + s->dma_channel = 12; + s->is_audio = true; + s->is_output = true; + s->video_channel = 5; + s->dma_fifo_mask = COBALT_SYSSTAT_AUD_OUT_LOST_DATA_MSK; + } else { + /* FIXME: Memory DMA for debug purpose */ + s->dma_channel = i - COBALT_NUM_NODES; + } + cobalt_info("stream #%d -> dma channel #%d <- video channel %d\n", + i, s->dma_channel, s->video_channel); + } +} + +static int cobalt_subdevs_init(struct cobalt *cobalt) +{ + static struct adv76xx_platform_data adv7604_pdata = { + .disable_pwrdnb = 1, + .ain_sel = ADV7604_AIN7_8_9_NC_SYNC_3_1, + .bus_order = ADV7604_BUS_ORDER_BRG, + .blank_data = 1, + .op_656_range = 1, + .op_format_mode_sel = ADV7604_OP_FORMAT_MODE0, + .int1_config = ADV76XX_INT1_CONFIG_ACTIVE_HIGH, + .dr_str_data = ADV76XX_DR_STR_HIGH, + .dr_str_clk = ADV76XX_DR_STR_HIGH, + .dr_str_sync = ADV76XX_DR_STR_HIGH, + .hdmi_free_run_mode = 1, + .inv_vs_pol = 1, + .inv_hs_pol = 1, + }; + static struct i2c_board_info adv7604_info = { + .type = "adv7604", + .addr = 0x20, + .platform_data = &adv7604_pdata, + }; + + struct cobalt_stream *s = cobalt->streams; + int i; + + for (i = 0; i < COBALT_NUM_INPUTS; i++) { + struct v4l2_subdev_format sd_fmt = { + .pad = ADV7604_PAD_SOURCE, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .format.code = MEDIA_BUS_FMT_YUYV8_1X16, + }; + struct v4l2_subdev_edid cobalt_edid = { + .pad = ADV76XX_PAD_HDMI_PORT_A, + .start_block = 0, + .blocks = 2, + .edid = edid, + }; + int err; + + s[i].pad_source = ADV7604_PAD_SOURCE; + s[i].i2c_adap = &cobalt->i2c_adap[i]; + if (s[i].i2c_adap->dev.parent == NULL) + continue; + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_NRESET_TO_HDMI_BIT(i), 1); + s[i].sd = v4l2_i2c_new_subdev_board(&cobalt->v4l2_dev, + s[i].i2c_adap, &adv7604_info, NULL); + if (!s[i].sd) { + if (cobalt_ignore_err) + continue; + return -ENODEV; + } + err = v4l2_subdev_call(s[i].sd, video, s_routing, + ADV76XX_PAD_HDMI_PORT_A, 0, 0); + if (err) + return err; + err = v4l2_subdev_call(s[i].sd, pad, set_edid, + &cobalt_edid); + if (err) + return err; + err = v4l2_subdev_call(s[i].sd, pad, set_fmt, NULL, + &sd_fmt); + if (err) + return err; + /* Reset channel video module */ + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(i), 0); + mdelay(2); + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(i), 1); + mdelay(1); + s[i].is_dummy = false; + cobalt->streams[i + COBALT_AUDIO_IN_STREAM].is_dummy = false; + } + return 0; +} + +static int cobalt_subdevs_hsma_init(struct cobalt *cobalt) +{ + static struct adv7842_platform_data adv7842_pdata = { + .disable_pwrdnb = 1, + .ain_sel = ADV7842_AIN1_2_3_NC_SYNC_1_2, + .bus_order = ADV7842_BUS_ORDER_RBG, + .op_format_mode_sel = ADV7842_OP_FORMAT_MODE0, + .blank_data = 1, + .op_656_range = 1, + .dr_str_data = 3, + .dr_str_clk = 3, + .dr_str_sync = 3, + .mode = ADV7842_MODE_HDMI, + .hdmi_free_run_enable = 1, + .vid_std_select = ADV7842_HDMI_COMP_VID_STD_HD_1250P, + .i2c_sdp_io = 0x4a, + .i2c_sdp = 0x48, + .i2c_cp = 0x22, + .i2c_vdp = 0x24, + .i2c_afe = 0x26, + .i2c_hdmi = 0x34, + .i2c_repeater = 0x32, + .i2c_edid = 0x36, + .i2c_infoframe = 0x3e, + .i2c_cec = 0x40, + .i2c_avlink = 0x42, + }; + static struct i2c_board_info adv7842_info = { + .type = "adv7842", + .addr = 0x20, + .platform_data = &adv7842_pdata, + }; + static struct v4l2_subdev_format sd_fmt = { + .pad = ADV7842_PAD_SOURCE, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .format.code = MEDIA_BUS_FMT_YUYV8_1X16, + }; + static struct adv7511_platform_data adv7511_pdata = { + .i2c_edid = 0x7e >> 1, + .i2c_cec = 0x7c >> 1, + .i2c_pktmem = 0x70 >> 1, + .cec_clk = 12000000, + }; + static struct i2c_board_info adv7511_info = { + .type = "adv7511", + .addr = 0x39, /* 0x39 or 0x3d */ + .platform_data = &adv7511_pdata, + }; + struct v4l2_subdev_edid cobalt_edid = { + .pad = ADV7842_EDID_PORT_A, + .start_block = 0, + .blocks = 2, + .edid = edid, + }; + struct cobalt_stream *s = &cobalt->streams[COBALT_HSMA_IN_NODE]; + + s->i2c_adap = &cobalt->i2c_adap[COBALT_NUM_ADAPTERS - 1]; + if (s->i2c_adap->dev.parent == NULL) + return 0; + cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_NRESET_TO_HDMI_BIT(4), 1); + + s->sd = v4l2_i2c_new_subdev_board(&cobalt->v4l2_dev, + s->i2c_adap, &adv7842_info, NULL); + if (s->sd) { + int err = v4l2_subdev_call(s->sd, pad, set_edid, &cobalt_edid); + + if (err) + return err; + err = v4l2_subdev_call(s->sd, pad, set_fmt, NULL, + &sd_fmt); + if (err) + return err; + cobalt->have_hsma_rx = true; + s->pad_source = ADV7842_PAD_SOURCE; + s->is_dummy = false; + cobalt->streams[4 + COBALT_AUDIO_IN_STREAM].is_dummy = false; + /* Reset channel video module */ + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(4), 0); + mdelay(2); + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(4), 1); + mdelay(1); + return err; + } + cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_NRESET_TO_HDMI_BIT(4), 0); + cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_PWRDN0_TO_HSMA_TX_BIT, 0); + s++; + s->i2c_adap = &cobalt->i2c_adap[COBALT_NUM_ADAPTERS - 1]; + s->sd = v4l2_i2c_new_subdev_board(&cobalt->v4l2_dev, + s->i2c_adap, &adv7511_info, NULL); + if (s->sd) { + /* A transmitter is hooked up, so we can set this bit */ + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_HSMA_TX_ENABLE_BIT, 1); + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(4), 0); + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_VIDEO_TX_RESETN_BIT, 1); + cobalt->have_hsma_tx = true; + v4l2_subdev_call(s->sd, core, s_power, 1); + v4l2_subdev_call(s->sd, video, s_stream, 1); + v4l2_subdev_call(s->sd, audio, s_stream, 1); + v4l2_ctrl_s_ctrl(v4l2_ctrl_find(s->sd->ctrl_handler, + V4L2_CID_DV_TX_MODE), V4L2_DV_TX_MODE_HDMI); + s->is_dummy = false; + cobalt->streams[COBALT_AUDIO_OUT_STREAM].is_dummy = false; + return 0; + } + return -ENODEV; +} + +static int cobalt_probe(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + struct cobalt *cobalt; + int retval = 0; + int i; + + /* FIXME - module parameter arrays constrain max instances */ + i = atomic_inc_return(&cobalt_instance) - 1; + + cobalt = kzalloc(sizeof(struct cobalt), GFP_ATOMIC); + if (cobalt == NULL) + return -ENOMEM; + cobalt->pci_dev = pci_dev; + cobalt->instance = i; + + cobalt->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev); + if (IS_ERR(cobalt->alloc_ctx)) { + kfree(cobalt); + return -ENOMEM; + } + + retval = v4l2_device_register(&pci_dev->dev, &cobalt->v4l2_dev); + if (retval) { + pr_err("cobalt: v4l2_device_register of card %d failed\n", + cobalt->instance); + vb2_dma_sg_cleanup_ctx(cobalt->alloc_ctx); + kfree(cobalt); + return retval; + } + snprintf(cobalt->v4l2_dev.name, sizeof(cobalt->v4l2_dev.name), + "cobalt-%d", cobalt->instance); + cobalt->v4l2_dev.notify = cobalt_notify; + cobalt_info("Initializing card %d\n", cobalt->instance); + + cobalt->irq_work_queues = + create_singlethread_workqueue(cobalt->v4l2_dev.name); + if (cobalt->irq_work_queues == NULL) { + cobalt_err("Could not create workqueue\n"); + retval = -ENOMEM; + goto err; + } + + INIT_WORK(&cobalt->irq_work_queue, cobalt_irq_work_handler); + + /* PCI Device Setup */ + retval = cobalt_setup_pci(cobalt, pci_dev, pci_id); + if (retval != 0) + goto err_wq; + + /* Show HDL version info */ + if (cobalt_hdl_info_get(cobalt)) + cobalt_info("Not able to read the HDL info\n"); + else + cobalt_info("%s", cobalt->hdl_info); + + retval = cobalt_i2c_init(cobalt); + if (retval) + goto err_pci; + + cobalt_stream_struct_init(cobalt); + + retval = cobalt_subdevs_init(cobalt); + if (retval) + goto err_i2c; + + if (!(cobalt_read_bar1(cobalt, COBALT_SYS_STAT_BASE) & + COBALT_SYSSTAT_HSMA_PRSNTN_MSK)) { + retval = cobalt_subdevs_hsma_init(cobalt); + if (retval) + goto err_i2c; + } + + retval = v4l2_device_register_subdev_nodes(&cobalt->v4l2_dev); + if (retval) + goto err_i2c; + retval = cobalt_nodes_register(cobalt); + if (retval) { + cobalt_err("Error %d registering device nodes\n", retval); + goto err_i2c; + } + cobalt_set_interrupt(cobalt, true); + v4l2_device_call_all(&cobalt->v4l2_dev, 0, core, + interrupt_service_routine, 0, NULL); + + cobalt_info("Initialized cobalt card\n"); + + cobalt_flash_probe(cobalt); + + return 0; + +err_i2c: + cobalt_i2c_exit(cobalt); + cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_HSMA_TX_ENABLE_BIT, 0); +err_pci: + cobalt_free_msi(cobalt, pci_dev); + cobalt_pci_iounmap(cobalt, pci_dev); + pci_release_regions(cobalt->pci_dev); + pci_disable_device(cobalt->pci_dev); +err_wq: + destroy_workqueue(cobalt->irq_work_queues); +err: + if (retval == 0) + retval = -ENODEV; + cobalt_err("error %d on initialization\n", retval); + + v4l2_device_unregister(&cobalt->v4l2_dev); + vb2_dma_sg_cleanup_ctx(cobalt->alloc_ctx); + kfree(cobalt); + return retval; +} + +static void cobalt_remove(struct pci_dev *pci_dev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct cobalt *cobalt = to_cobalt(v4l2_dev); + int i; + + cobalt_flash_remove(cobalt); + cobalt_set_interrupt(cobalt, false); + flush_workqueue(cobalt->irq_work_queues); + cobalt_nodes_unregister(cobalt); + for (i = 0; i < COBALT_NUM_ADAPTERS; i++) { + struct v4l2_subdev *sd = cobalt->streams[i].sd; + struct i2c_client *client; + + if (sd == NULL) + continue; + client = v4l2_get_subdevdata(sd); + v4l2_device_unregister_subdev(sd); + i2c_unregister_device(client); + } + cobalt_i2c_exit(cobalt); + cobalt_free_msi(cobalt, pci_dev); + cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_HSMA_TX_ENABLE_BIT, 0); + cobalt_pci_iounmap(cobalt, pci_dev); + pci_release_regions(cobalt->pci_dev); + pci_disable_device(cobalt->pci_dev); + destroy_workqueue(cobalt->irq_work_queues); + + cobalt_info("removed cobalt card\n"); + + v4l2_device_unregister(v4l2_dev); + vb2_dma_sg_cleanup_ctx(cobalt->alloc_ctx); + kfree(cobalt); +} + +/* define a pci_driver for card detection */ +static struct pci_driver cobalt_pci_driver = { + .name = "cobalt", + .id_table = cobalt_pci_tbl, + .probe = cobalt_probe, + .remove = cobalt_remove, +}; + +module_pci_driver(cobalt_pci_driver); diff --git a/drivers/media/pci/cobalt/cobalt-driver.h b/drivers/media/pci/cobalt/cobalt-driver.h new file mode 100644 index 0000000..c206df9 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-driver.h @@ -0,0 +1,380 @@ +/* + * cobalt driver internal defines and structures + * + * Derived from cx18-driver.h + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef COBALT_DRIVER_H +#define COBALT_DRIVER_H + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/i2c.h> +#include <linux/list.h> +#include <linux/workqueue.h> +#include <linux/mutex.h> + +#include <media/v4l2-common.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fh.h> +#include <media/videobuf2-dma-sg.h> + +#include "m00233_video_measure_memmap_package.h" +#include "m00235_fdma_packer_memmap_package.h" +#include "m00389_cvi_memmap_package.h" +#include "m00460_evcnt_memmap_package.h" +#include "m00473_freewheel_memmap_package.h" +#include "m00479_clk_loss_detector_memmap_package.h" +#include "m00514_syncgen_flow_evcnt_memmap_package.h" + +/* System device ID */ +#define PCI_DEVICE_ID_COBALT 0x2732 + +/* Number of cobalt device nodes. */ +#define COBALT_NUM_INPUTS 4 +#define COBALT_NUM_NODES 6 + +/* Number of cobalt device streams. */ +#define COBALT_NUM_STREAMS 12 + +#define COBALT_HSMA_IN_NODE 4 +#define COBALT_HSMA_OUT_NODE 5 + +/* Cobalt audio streams */ +#define COBALT_AUDIO_IN_STREAM 6 +#define COBALT_AUDIO_OUT_STREAM 11 + +/* DMA stuff */ +#define DMA_CHANNELS_MAX 16 + +/* i2c stuff */ +#define I2C_CLIENTS_MAX 16 +#define COBALT_NUM_ADAPTERS 5 + +#define COBALT_CLK 50000000 + +/* System status register */ +#define COBALT_SYSSTAT_DIP0_MSK (1 << 0) +#define COBALT_SYSSTAT_DIP1_MSK (1 << 1) +#define COBALT_SYSSTAT_HSMA_PRSNTN_MSK (1 << 2) +#define COBALT_SYSSTAT_FLASH_RDYBSYN_MSK (1 << 3) +#define COBALT_SYSSTAT_VI0_5V_MSK (1 << 4) +#define COBALT_SYSSTAT_VI0_INT1_MSK (1 << 5) +#define COBALT_SYSSTAT_VI0_INT2_MSK (1 << 6) +#define COBALT_SYSSTAT_VI0_LOST_DATA_MSK (1 << 7) +#define COBALT_SYSSTAT_VI1_5V_MSK (1 << 8) +#define COBALT_SYSSTAT_VI1_INT1_MSK (1 << 9) +#define COBALT_SYSSTAT_VI1_INT2_MSK (1 << 10) +#define COBALT_SYSSTAT_VI1_LOST_DATA_MSK (1 << 11) +#define COBALT_SYSSTAT_VI2_5V_MSK (1 << 12) +#define COBALT_SYSSTAT_VI2_INT1_MSK (1 << 13) +#define COBALT_SYSSTAT_VI2_INT2_MSK (1 << 14) +#define COBALT_SYSSTAT_VI2_LOST_DATA_MSK (1 << 15) +#define COBALT_SYSSTAT_VI3_5V_MSK (1 << 16) +#define COBALT_SYSSTAT_VI3_INT1_MSK (1 << 17) +#define COBALT_SYSSTAT_VI3_INT2_MSK (1 << 18) +#define COBALT_SYSSTAT_VI3_LOST_DATA_MSK (1 << 19) +#define COBALT_SYSSTAT_VIHSMA_5V_MSK (1 << 20) +#define COBALT_SYSSTAT_VIHSMA_INT1_MSK (1 << 21) +#define COBALT_SYSSTAT_VIHSMA_INT2_MSK (1 << 22) +#define COBALT_SYSSTAT_VIHSMA_LOST_DATA_MSK (1 << 23) +#define COBALT_SYSSTAT_VOHSMA_INT1_MSK (1 << 24) +#define COBALT_SYSSTAT_VOHSMA_PLL_LOCKED_MSK (1 << 25) +#define COBALT_SYSSTAT_VOHSMA_LOST_DATA_MSK (1 << 26) +#define COBALT_SYSSTAT_AUD_PLL_LOCKED_MSK (1 << 28) +#define COBALT_SYSSTAT_AUD_IN_LOST_DATA_MSK (1 << 29) +#define COBALT_SYSSTAT_AUD_OUT_LOST_DATA_MSK (1 << 30) +#define COBALT_SYSSTAT_PCIE_SMBCLK_MSK (1 << 31) + +/* Cobalt memory map */ +#define COBALT_I2C_0_BASE 0x0 +#define COBALT_I2C_1_BASE 0x080 +#define COBALT_I2C_2_BASE 0x100 +#define COBALT_I2C_3_BASE 0x180 +#define COBALT_I2C_HSMA_BASE 0x200 + +#define COBALT_SYS_CTRL_BASE 0x400 +#define COBALT_SYS_CTRL_HSMA_TX_ENABLE_BIT 1 +#define COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(n) (4 + 4 * (n)) +#define COBALT_SYS_CTRL_NRESET_TO_HDMI_BIT(n) (5 + 4 * (n)) +#define COBALT_SYS_CTRL_HPD_TO_CONNECTOR_BIT(n) (6 + 4 * (n)) +#define COBALT_SYS_CTRL_AUDIO_IPP_RESETN_BIT(n) (7 + 4 * (n)) +#define COBALT_SYS_CTRL_PWRDN0_TO_HSMA_TX_BIT 24 +#define COBALT_SYS_CTRL_VIDEO_TX_RESETN_BIT 25 +#define COBALT_SYS_CTRL_AUDIO_OPP_RESETN_BIT 27 + +#define COBALT_SYS_STAT_BASE 0x500 +#define COBALT_SYS_STAT_MASK (COBALT_SYS_STAT_BASE + 0x08) +#define COBALT_SYS_STAT_EDGE (COBALT_SYS_STAT_BASE + 0x0c) + +#define COBALT_HDL_INFO_BASE 0x4800 +#define COBALT_HDL_INFO_SIZE 0x200 + +#define COBALT_VID_BASE 0x10000 +#define COBALT_VID_SIZE 0x1000 + +#define COBALT_CVI(cobalt, c) \ + (cobalt->bar1 + COBALT_VID_BASE + (c) * COBALT_VID_SIZE) +#define COBALT_CVI_VMR(cobalt, c) \ + (cobalt->bar1 + COBALT_VID_BASE + (c) * COBALT_VID_SIZE + 0x100) +#define COBALT_CVI_EVCNT(cobalt, c) \ + (cobalt->bar1 + COBALT_VID_BASE + (c) * COBALT_VID_SIZE + 0x200) +#define COBALT_CVI_FREEWHEEL(cobalt, c) \ + (cobalt->bar1 + COBALT_VID_BASE + (c) * COBALT_VID_SIZE + 0x300) +#define COBALT_CVI_CLK_LOSS(cobalt, c) \ + (cobalt->bar1 + COBALT_VID_BASE + (c) * COBALT_VID_SIZE + 0x400) +#define COBALT_CVI_PACKER(cobalt, c) \ + (cobalt->bar1 + COBALT_VID_BASE + (c) * COBALT_VID_SIZE + 0x500) + +#define COBALT_TX_BASE(cobalt) (cobalt->bar1 + COBALT_VID_BASE + 0x5000) + +#define DMA_INTERRUPT_STATUS_REG 0x08 + +#define COBALT_HDL_SEARCH_STR "** HDL version info **" + +/* Cobalt CPU bus interface */ +#define COBALT_BUS_BAR1_BASE 0x600 +#define COBALT_BUS_SRAM_BASE 0x0 +#define COBALT_BUS_CPLD_BASE 0x00600000 +#define COBALT_BUS_FLASH_BASE 0x08000000 + +/* FDMA to PCIe packing */ +#define COBALT_BYTES_PER_PIXEL_YUYV 2 +#define COBALT_BYTES_PER_PIXEL_RGB24 3 +#define COBALT_BYTES_PER_PIXEL_RGB32 4 + +/* debugging */ +extern int cobalt_debug; +extern int cobalt_ignore_err; + +#define cobalt_err(fmt, arg...) v4l2_err(&cobalt->v4l2_dev, fmt, ## arg) +#define cobalt_warn(fmt, arg...) v4l2_warn(&cobalt->v4l2_dev, fmt, ## arg) +#define cobalt_info(fmt, arg...) v4l2_info(&cobalt->v4l2_dev, fmt, ## arg) +#define cobalt_dbg(level, fmt, arg...) \ + v4l2_dbg(level, cobalt_debug, &cobalt->v4l2_dev, fmt, ## arg) + +struct cobalt; +struct cobalt_i2c_regs; + +/* Per I2C bus private algo callback data */ +struct cobalt_i2c_data { + struct cobalt *cobalt; + struct cobalt_i2c_regs __iomem *regs; +}; + +struct pci_consistent_buffer { + void *virt; + dma_addr_t bus; + size_t bytes; +}; + +struct sg_dma_desc_info { + void *virt; + dma_addr_t bus; + unsigned size; + void *last_desc_virt; + struct device *dev; +}; + +#define COBALT_MAX_WIDTH 1920 +#define COBALT_MAX_HEIGHT 1200 +#define COBALT_MAX_BPP 3 +#define COBALT_MAX_FRAMESZ \ + (COBALT_MAX_WIDTH * COBALT_MAX_HEIGHT * COBALT_MAX_BPP) + +#define NR_BUFS VIDEO_MAX_FRAME + +#define COBALT_STREAM_FL_DMA_IRQ 0 +#define COBALT_STREAM_FL_ADV_IRQ 1 + +struct cobalt_buffer { + struct vb2_buffer vb; + struct list_head list; +}; + +static inline struct cobalt_buffer *to_cobalt_buffer(struct vb2_buffer *vb2) +{ + return container_of(vb2, struct cobalt_buffer, vb); +} + +struct cobalt_stream { + struct video_device vdev; + struct vb2_queue q; + struct list_head bufs; + struct i2c_adapter *i2c_adap; + struct v4l2_subdev *sd; + struct mutex lock; + spinlock_t irqlock; + struct v4l2_dv_timings timings; + u32 input; + u32 pad_source; + u32 width, height, bpp; + u32 stride; + u32 pixfmt; + u32 sequence; + u32 colorspace; + u32 xfer_func; + u32 ycbcr_enc; + u32 quantization; + + u8 dma_channel; + int video_channel; + unsigned dma_fifo_mask; + unsigned adv_irq_mask; + struct sg_dma_desc_info dma_desc_info[NR_BUFS]; + unsigned long flags; + bool unstable_frame; + bool enable_cvi; + bool enable_freewheel; + unsigned skip_first_frames; + bool is_output; + bool is_audio; + bool is_dummy; + + struct cobalt *cobalt; + struct snd_cobalt_card *alsa; +}; + +struct snd_cobalt_card; + +/* Struct to hold info about cobalt cards */ +struct cobalt { + int instance; + struct pci_dev *pci_dev; + struct v4l2_device v4l2_dev; + void *alloc_ctx; + + void __iomem *bar0, *bar1; + + u8 card_rev; + u16 device_id; + + /* device nodes */ + struct cobalt_stream streams[DMA_CHANNELS_MAX]; + struct i2c_adapter i2c_adap[COBALT_NUM_ADAPTERS]; + struct cobalt_i2c_data i2c_data[COBALT_NUM_ADAPTERS]; + bool have_hsma_rx; + bool have_hsma_tx; + + /* irq */ + struct workqueue_struct *irq_work_queues; + struct work_struct irq_work_queue; /* work entry */ + /* irq counters */ + u32 irq_adv1; + u32 irq_adv2; + u32 irq_advout; + u32 irq_dma_tot; + u32 irq_dma[COBALT_NUM_STREAMS]; + u32 irq_none; + u32 irq_full_fifo; + + bool msi_enabled; + + /* omnitek dma */ + int dma_channels; + int first_fifo_channel; + bool pci_32_bit; + + char hdl_info[COBALT_HDL_INFO_SIZE]; + + /* NOR flash */ + struct mtd_info *mtd; +}; + +static inline struct cobalt *to_cobalt(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct cobalt, v4l2_dev); +} + +static inline void cobalt_write_bar0(struct cobalt *cobalt, u32 reg, u32 val) +{ + iowrite32(val, cobalt->bar0 + reg); +} + +static inline u32 cobalt_read_bar0(struct cobalt *cobalt, u32 reg) +{ + return ioread32(cobalt->bar0 + reg); +} + +static inline void cobalt_write_bar1(struct cobalt *cobalt, u32 reg, u32 val) +{ + iowrite32(val, cobalt->bar1 + reg); +} + +static inline u32 cobalt_read_bar1(struct cobalt *cobalt, u32 reg) +{ + return ioread32(cobalt->bar1 + reg); +} + +static inline u32 cobalt_g_sysctrl(struct cobalt *cobalt) +{ + return cobalt_read_bar1(cobalt, COBALT_SYS_CTRL_BASE); +} + +static inline void cobalt_s_bit_sysctrl(struct cobalt *cobalt, + int bit, int val) +{ + u32 ctrl = cobalt_read_bar1(cobalt, COBALT_SYS_CTRL_BASE); + + cobalt_write_bar1(cobalt, COBALT_SYS_CTRL_BASE, + (ctrl & ~(1UL << bit)) | (val << bit)); +} + +static inline u32 cobalt_g_sysstat(struct cobalt *cobalt) +{ + return cobalt_read_bar1(cobalt, COBALT_SYS_STAT_BASE); +} + +#define ADRS_REG (bar1 + COBALT_BUS_BAR1_BASE + 0) +#define LOWER_DATA (bar1 + COBALT_BUS_BAR1_BASE + 4) +#define UPPER_DATA (bar1 + COBALT_BUS_BAR1_BASE + 6) + +static inline u32 cobalt_bus_read32(void __iomem *bar1, u32 bus_adrs) +{ + iowrite32(bus_adrs, ADRS_REG); + return ioread32(LOWER_DATA); +} + +static inline void cobalt_bus_write16(void __iomem *bar1, + u32 bus_adrs, u16 data) +{ + iowrite32(bus_adrs, ADRS_REG); + if (bus_adrs & 2) + iowrite16(data, UPPER_DATA); + else + iowrite16(data, LOWER_DATA); +} + +static inline void cobalt_bus_write32(void __iomem *bar1, + u32 bus_adrs, u16 data) +{ + iowrite32(bus_adrs, ADRS_REG); + if (bus_adrs & 2) + iowrite32(data, UPPER_DATA); + else + iowrite32(data, LOWER_DATA); +} + +/*==============Prototypes==================*/ + +void cobalt_pcie_status_show(struct cobalt *cobalt); + +#endif diff --git a/drivers/media/pci/cobalt/cobalt-flash.c b/drivers/media/pci/cobalt/cobalt-flash.c new file mode 100644 index 0000000..04dcaf9 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-flash.c @@ -0,0 +1,128 @@ +/* + * Cobalt NOR flash functions + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/cfi.h> +#include <linux/time.h> + +#include "cobalt-flash.h" + +#define ADRS(offset) (COBALT_BUS_FLASH_BASE + offset) + +static struct map_info cobalt_flash_map = { + .name = "cobalt-flash", + .bankwidth = 2, /* 16 bits */ + .size = 0x4000000, /* 64MB */ + .phys = 0, /* offset */ +}; + +static map_word flash_read16(struct map_info *map, unsigned long offset) +{ + map_word r; + + r.x[0] = cobalt_bus_read32(map->virt, ADRS(offset)); + if (offset & 0x2) + r.x[0] >>= 16; + else + r.x[0] &= 0x0000ffff; + + return r; +} + +static void flash_write16(struct map_info *map, const map_word datum, + unsigned long offset) +{ + u16 data = (u16)datum.x[0]; + + cobalt_bus_write16(map->virt, ADRS(offset), data); +} + +static void flash_copy_from(struct map_info *map, void *to, + unsigned long from, ssize_t len) +{ + u32 src = from; + u8 *dest = to; + u32 data; + + while (len) { + data = cobalt_bus_read32(map->virt, ADRS(src)); + do { + *dest = data >> (8 * (src & 3)); + src++; + dest++; + len--; + } while (len && (src % 4)); + } +} + +static void flash_copy_to(struct map_info *map, unsigned long to, + const void *from, ssize_t len) +{ + const u8 *src = from; + u32 dest = to; + + pr_info("%s: offset 0x%x: length %zu\n", __func__, dest, len); + while (len) { + u16 data = 0xffff; + + do { + data = *src << (8 * (dest & 1)); + src++; + dest++; + len--; + } while (len && (dest % 2)); + + cobalt_bus_write16(map->virt, ADRS(dest - 2), data); + } +} + +int cobalt_flash_probe(struct cobalt *cobalt) +{ + struct map_info *map = &cobalt_flash_map; + struct mtd_info *mtd; + + BUG_ON(!map_bankwidth_supported(map->bankwidth)); + map->virt = cobalt->bar1; + map->read = flash_read16; + map->write = flash_write16; + map->copy_from = flash_copy_from; + map->copy_to = flash_copy_to; + + mtd = do_map_probe("cfi_probe", map); + cobalt->mtd = mtd; + if (!mtd) { + cobalt_err("Probe CFI flash failed!\n"); + return -1; + } + + mtd->owner = THIS_MODULE; + mtd->dev.parent = &cobalt->pci_dev->dev; + mtd_device_register(mtd, NULL, 0); + return 0; +} + +void cobalt_flash_remove(struct cobalt *cobalt) +{ + if (cobalt->mtd) { + mtd_device_unregister(cobalt->mtd); + map_destroy(cobalt->mtd); + } +} diff --git a/drivers/media/pci/cobalt/cobalt-flash.h b/drivers/media/pci/cobalt/cobalt-flash.h new file mode 100644 index 0000000..8077dae --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-flash.h @@ -0,0 +1,29 @@ +/* + * Cobalt NOR flash functions + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef COBALT_FLASH_H +#define COBALT_FLASH_H + +#include "cobalt-driver.h" + +int cobalt_flash_probe(struct cobalt *cobalt); +void cobalt_flash_remove(struct cobalt *cobalt); + +#endif diff --git a/drivers/media/pci/cobalt/cobalt-i2c.c b/drivers/media/pci/cobalt/cobalt-i2c.c new file mode 100644 index 0000000..ad16b89 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-i2c.c @@ -0,0 +1,396 @@ +/* + * cobalt I2C functions + * + * Derived from cx18-i2c.c + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "cobalt-driver.h" +#include "cobalt-i2c.h" + +struct cobalt_i2c_regs { + /* Clock prescaler register lo-byte */ + u8 prerlo; + u8 dummy0[3]; + /* Clock prescaler register high-byte */ + u8 prerhi; + u8 dummy1[3]; + /* Control register */ + u8 ctr; + u8 dummy2[3]; + /* Transmit/Receive register */ + u8 txr_rxr; + u8 dummy3[3]; + /* Command and Status register */ + u8 cr_sr; + u8 dummy4[3]; +}; + +/* CTR[7:0] - Control register */ + +/* I2C Core enable bit */ +#define M00018_CTR_BITMAP_EN_MSK (1 << 7) + +/* I2C Core interrupt enable bit */ +#define M00018_CTR_BITMAP_IEN_MSK (1 << 6) + +/* CR[7:0] - Command register */ + +/* I2C start condition */ +#define M00018_CR_BITMAP_STA_MSK (1 << 7) + +/* I2C stop condition */ +#define M00018_CR_BITMAP_STO_MSK (1 << 6) + +/* I2C read from slave */ +#define M00018_CR_BITMAP_RD_MSK (1 << 5) + +/* I2C write to slave */ +#define M00018_CR_BITMAP_WR_MSK (1 << 4) + +/* I2C ack */ +#define M00018_CR_BITMAP_ACK_MSK (1 << 3) + +/* I2C Interrupt ack */ +#define M00018_CR_BITMAP_IACK_MSK (1 << 0) + +/* SR[7:0] - Status register */ + +/* Receive acknowledge from slave */ +#define M00018_SR_BITMAP_RXACK_MSK (1 << 7) + +/* Busy, I2C bus busy (as defined by start / stop bits) */ +#define M00018_SR_BITMAP_BUSY_MSK (1 << 6) + +/* Arbitration lost - core lost arbitration */ +#define M00018_SR_BITMAP_AL_MSK (1 << 5) + +/* Transfer in progress */ +#define M00018_SR_BITMAP_TIP_MSK (1 << 1) + +/* Interrupt flag */ +#define M00018_SR_BITMAP_IF_MSK (1 << 0) + +/* Frequency, in Hz */ +#define I2C_FREQUENCY 400000 +#define ALT_CPU_FREQ 83333333 + +static struct cobalt_i2c_regs __iomem * +cobalt_i2c_regs(struct cobalt *cobalt, unsigned idx) +{ + switch (idx) { + case 0: + default: + return (struct cobalt_i2c_regs __iomem *) + (cobalt->bar1 + COBALT_I2C_0_BASE); + case 1: + return (struct cobalt_i2c_regs __iomem *) + (cobalt->bar1 + COBALT_I2C_1_BASE); + case 2: + return (struct cobalt_i2c_regs __iomem *) + (cobalt->bar1 + COBALT_I2C_2_BASE); + case 3: + return (struct cobalt_i2c_regs __iomem *) + (cobalt->bar1 + COBALT_I2C_3_BASE); + case 4: + return (struct cobalt_i2c_regs __iomem *) + (cobalt->bar1 + COBALT_I2C_HSMA_BASE); + } +} + +/* Do low-level i2c byte transfer. + * Returns -1 in case of an error or 0 otherwise. + */ +static int cobalt_tx_bytes(struct cobalt_i2c_regs __iomem *regs, + struct i2c_adapter *adap, bool start, bool stop, + u8 *data, u16 len) +{ + unsigned long start_time; + int status; + int cmd; + int i; + + for (i = 0; i < len; i++) { + /* Setup data */ + iowrite8(data[i], ®s->txr_rxr); + + /* Setup command */ + if (i == 0 && start != 0) { + /* Write + Start */ + cmd = M00018_CR_BITMAP_WR_MSK | + M00018_CR_BITMAP_STA_MSK; + } else if (i == len - 1 && stop != 0) { + /* Write + Stop */ + cmd = M00018_CR_BITMAP_WR_MSK | + M00018_CR_BITMAP_STO_MSK; + } else { + /* Write only */ + cmd = M00018_CR_BITMAP_WR_MSK; + } + + /* Execute command */ + iowrite8(cmd, ®s->cr_sr); + + /* Wait for transfer to complete (TIP = 0) */ + start_time = jiffies; + status = ioread8(®s->cr_sr); + while (status & M00018_SR_BITMAP_TIP_MSK) { + if (time_after(jiffies, start_time + adap->timeout)) + return -ETIMEDOUT; + cond_resched(); + status = ioread8(®s->cr_sr); + } + + /* Verify ACK */ + if (status & M00018_SR_BITMAP_RXACK_MSK) { + /* NO ACK! */ + return -EIO; + } + + /* Verify arbitration */ + if (status & M00018_SR_BITMAP_AL_MSK) { + /* Arbitration lost! */ + return -EIO; + } + } + return 0; +} + +/* Do low-level i2c byte read. + * Returns -1 in case of an error or 0 otherwise. + */ +static int cobalt_rx_bytes(struct cobalt_i2c_regs __iomem *regs, + struct i2c_adapter *adap, bool start, bool stop, + u8 *data, u16 len) +{ + unsigned long start_time; + int status; + int cmd; + int i; + + for (i = 0; i < len; i++) { + /* Setup command */ + if (i == 0 && start != 0) { + /* Read + Start */ + cmd = M00018_CR_BITMAP_RD_MSK | + M00018_CR_BITMAP_STA_MSK; + } else if (i == len - 1 && stop != 0) { + /* Read + Stop */ + cmd = M00018_CR_BITMAP_RD_MSK | + M00018_CR_BITMAP_STO_MSK; + } else { + /* Read only */ + cmd = M00018_CR_BITMAP_RD_MSK; + } + + /* Last byte to read, no ACK */ + if (i == len - 1) + cmd |= M00018_CR_BITMAP_ACK_MSK; + + /* Execute command */ + iowrite8(cmd, ®s->cr_sr); + + /* Wait for transfer to complete (TIP = 0) */ + start_time = jiffies; + status = ioread8(®s->cr_sr); + while (status & M00018_SR_BITMAP_TIP_MSK) { + if (time_after(jiffies, start_time + adap->timeout)) + return -ETIMEDOUT; + cond_resched(); + status = ioread8(®s->cr_sr); + } + + /* Verify arbitration */ + if (status & M00018_SR_BITMAP_AL_MSK) { + /* Arbitration lost! */ + return -EIO; + } + + /* Store data */ + data[i] = ioread8(®s->txr_rxr); + } + return 0; +} + +/* Generate stop condition on i2c bus. + * The m00018 stop isn't doing the right thing (wrong timing). + * So instead send a start condition, 8 zeroes and a stop condition. + */ +static int cobalt_stop(struct cobalt_i2c_regs __iomem *regs, + struct i2c_adapter *adap) +{ + u8 data = 0; + + return cobalt_tx_bytes(regs, adap, true, true, &data, 1); +} + +static int cobalt_xfer(struct i2c_adapter *adap, + struct i2c_msg msgs[], int num) +{ + struct cobalt_i2c_data *data = adap->algo_data; + struct cobalt_i2c_regs __iomem *regs = data->regs; + struct i2c_msg *pmsg; + unsigned short flags; + int ret = 0; + int i, j; + + for (i = 0; i < num; i++) { + int stop = (i == num - 1); + + pmsg = &msgs[i]; + flags = pmsg->flags; + + if (!(pmsg->flags & I2C_M_NOSTART)) { + u8 addr = pmsg->addr << 1; + + if (flags & I2C_M_RD) + addr |= 1; + if (flags & I2C_M_REV_DIR_ADDR) + addr ^= 1; + for (j = 0; j < adap->retries; j++) { + ret = cobalt_tx_bytes(regs, adap, true, false, + &addr, 1); + if (!ret) + break; + cobalt_stop(regs, adap); + } + if (ret < 0) + return ret; + ret = 0; + } + if (pmsg->flags & I2C_M_RD) { + /* read bytes into buffer */ + ret = cobalt_rx_bytes(regs, adap, false, stop, + pmsg->buf, pmsg->len); + if (ret < 0) + goto bailout; + } else { + /* write bytes from buffer */ + ret = cobalt_tx_bytes(regs, adap, false, stop, + pmsg->buf, pmsg->len); + if (ret < 0) + goto bailout; + } + } + ret = i; + +bailout: + if (ret < 0) + cobalt_stop(regs, adap); + return ret; +} + +static u32 cobalt_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +/* template for i2c-bit-algo */ +static struct i2c_adapter cobalt_i2c_adap_template = { + .name = "cobalt i2c driver", + .algo = NULL, /* set by i2c-algo-bit */ + .algo_data = NULL, /* filled from template */ + .owner = THIS_MODULE, +}; + +static const struct i2c_algorithm cobalt_algo = { + .master_xfer = cobalt_xfer, + .functionality = cobalt_func, +}; + +/* init + register i2c algo-bit adapter */ +int cobalt_i2c_init(struct cobalt *cobalt) +{ + int i, err; + int status; + int prescale; + unsigned long start_time; + + cobalt_dbg(1, "i2c init\n"); + + /* Define I2C clock prescaler */ + prescale = ((ALT_CPU_FREQ) / (5 * I2C_FREQUENCY)) - 1; + + for (i = 0; i < COBALT_NUM_ADAPTERS; i++) { + struct cobalt_i2c_regs __iomem *regs = + cobalt_i2c_regs(cobalt, i); + struct i2c_adapter *adap = &cobalt->i2c_adap[i]; + + /* Disable I2C */ + iowrite8(M00018_CTR_BITMAP_EN_MSK, ®s->cr_sr); + iowrite8(0, ®s->ctr); + iowrite8(0, ®s->cr_sr); + + start_time = jiffies; + do { + if (time_after(jiffies, start_time + HZ)) { + if (cobalt_ignore_err) { + adap->dev.parent = NULL; + return 0; + } + return -ETIMEDOUT; + } + status = ioread8(®s->cr_sr); + } while (status & M00018_SR_BITMAP_TIP_MSK); + + /* Disable I2C */ + iowrite8(0, ®s->ctr); + iowrite8(0, ®s->cr_sr); + + /* Calculate i2c prescaler */ + iowrite8(prescale & 0xff, ®s->prerlo); + iowrite8((prescale >> 8) & 0xff, ®s->prerhi); + /* Enable I2C, interrupts disabled */ + iowrite8(M00018_CTR_BITMAP_EN_MSK, ®s->ctr); + /* Setup algorithm for adapter */ + cobalt->i2c_data[i].cobalt = cobalt; + cobalt->i2c_data[i].regs = regs; + *adap = cobalt_i2c_adap_template; + adap->algo = &cobalt_algo; + adap->algo_data = &cobalt->i2c_data[i]; + adap->retries = 3; + sprintf(adap->name + strlen(adap->name), + " #%d-%d", cobalt->instance, i); + i2c_set_adapdata(adap, &cobalt->v4l2_dev); + adap->dev.parent = &cobalt->pci_dev->dev; + err = i2c_add_adapter(adap); + if (err) { + if (cobalt_ignore_err) { + adap->dev.parent = NULL; + return 0; + } + while (i--) + i2c_del_adapter(&cobalt->i2c_adap[i]); + return err; + } + cobalt_info("registered bus %s\n", adap->name); + } + return 0; +} + +void cobalt_i2c_exit(struct cobalt *cobalt) +{ + int i; + + cobalt_dbg(1, "i2c exit\n"); + + for (i = 0; i < COBALT_NUM_ADAPTERS; i++) { + cobalt_err("unregistered bus %s\n", cobalt->i2c_adap[i].name); + i2c_del_adapter(&cobalt->i2c_adap[i]); + } +} diff --git a/drivers/media/pci/cobalt/cobalt-i2c.h b/drivers/media/pci/cobalt/cobalt-i2c.h new file mode 100644 index 0000000..a4c1cfa --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-i2c.h @@ -0,0 +1,25 @@ +/* + * cobalt I2C functions + * + * Derived from cx18-i2c.h + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* init + register i2c algo-bit adapter */ +int cobalt_i2c_init(struct cobalt *cobalt); +void cobalt_i2c_exit(struct cobalt *cobalt); diff --git a/drivers/media/pci/cobalt/cobalt-irq.c b/drivers/media/pci/cobalt/cobalt-irq.c new file mode 100644 index 0000000..dd4bff9 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-irq.c @@ -0,0 +1,258 @@ +/* + * cobalt interrupt handling + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <media/adv7604.h> + +#include "cobalt-driver.h" +#include "cobalt-irq.h" +#include "cobalt-omnitek.h" + +static void cobalt_dma_stream_queue_handler(struct cobalt_stream *s) +{ + struct cobalt *cobalt = s->cobalt; + int rx = s->video_channel; + struct m00473_freewheel_regmap __iomem *fw = + COBALT_CVI_FREEWHEEL(s->cobalt, rx); + struct m00233_video_measure_regmap __iomem *vmr = + COBALT_CVI_VMR(s->cobalt, rx); + struct m00389_cvi_regmap __iomem *cvi = + COBALT_CVI(s->cobalt, rx); + struct m00479_clk_loss_detector_regmap __iomem *clkloss = + COBALT_CVI_CLK_LOSS(s->cobalt, rx); + struct cobalt_buffer *cb; + bool skip = false; + + spin_lock(&s->irqlock); + + if (list_empty(&s->bufs)) { + pr_err("no buffers!\n"); + spin_unlock(&s->irqlock); + return; + } + + /* Give the fresh filled up buffer to the user. + * Note that the interrupt is only sent if the DMA can continue + * with a new buffer, so it is always safe to return this buffer + * to userspace. */ + cb = list_first_entry(&s->bufs, struct cobalt_buffer, list); + list_del(&cb->list); + spin_unlock(&s->irqlock); + + if (s->is_audio || s->is_output) + goto done; + + if (s->unstable_frame) { + uint32_t stat = ioread32(&vmr->irq_status); + + iowrite32(stat, &vmr->irq_status); + if (!(ioread32(&vmr->status) & + M00233_STATUS_BITMAP_INIT_DONE_MSK)) { + cobalt_dbg(1, "!init_done\n"); + if (s->enable_freewheel) + goto restart_fw; + goto done; + } + + if (ioread32(&clkloss->status) & + M00479_STATUS_BITMAP_CLOCK_MISSING_MSK) { + iowrite32(0, &clkloss->ctrl); + iowrite32(M00479_CTRL_BITMAP_ENABLE_MSK, &clkloss->ctrl); + cobalt_dbg(1, "no clock\n"); + if (s->enable_freewheel) + goto restart_fw; + goto done; + } + if ((stat & (M00233_IRQ_STATUS_BITMAP_VACTIVE_AREA_MSK | + M00233_IRQ_STATUS_BITMAP_HACTIVE_AREA_MSK)) || + ioread32(&vmr->vactive_area) != s->timings.bt.height || + ioread32(&vmr->hactive_area) != s->timings.bt.width) { + cobalt_dbg(1, "unstable\n"); + if (s->enable_freewheel) + goto restart_fw; + goto done; + } + if (!s->enable_cvi) { + s->enable_cvi = true; + iowrite32(M00389_CONTROL_BITMAP_ENABLE_MSK, &cvi->control); + goto done; + } + if (!(ioread32(&cvi->status) & M00389_STATUS_BITMAP_LOCK_MSK)) { + cobalt_dbg(1, "cvi no lock\n"); + if (s->enable_freewheel) + goto restart_fw; + goto done; + } + if (!s->enable_freewheel) { + cobalt_dbg(1, "stable\n"); + s->enable_freewheel = true; + iowrite32(0, &fw->ctrl); + goto done; + } + cobalt_dbg(1, "enabled fw\n"); + iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK | + M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_MSK, + &vmr->control); + iowrite32(M00473_CTRL_BITMAP_ENABLE_MSK, &fw->ctrl); + s->enable_freewheel = false; + s->unstable_frame = false; + s->skip_first_frames = 2; + skip = true; + goto done; + } + if (ioread32(&fw->status) & M00473_STATUS_BITMAP_FREEWHEEL_MODE_MSK) { +restart_fw: + cobalt_dbg(1, "lost lock\n"); + iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, + &vmr->control); + iowrite32(M00473_CTRL_BITMAP_ENABLE_MSK | + M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK, + &fw->ctrl); + iowrite32(0, &cvi->control); + s->unstable_frame = true; + s->enable_freewheel = false; + s->enable_cvi = false; + } +done: + if (s->skip_first_frames) { + skip = true; + s->skip_first_frames--; + } + v4l2_get_timestamp(&cb->vb.v4l2_buf.timestamp); + /* TODO: the sequence number should be read from the FPGA so we + also know about dropped frames. */ + cb->vb.v4l2_buf.sequence = s->sequence++; + vb2_buffer_done(&cb->vb, (skip || s->unstable_frame) ? + VB2_BUF_STATE_QUEUED : VB2_BUF_STATE_DONE); +} + +irqreturn_t cobalt_irq_handler(int irq, void *dev_id) +{ + struct cobalt *cobalt = (struct cobalt *)dev_id; + u32 dma_interrupt = + cobalt_read_bar0(cobalt, DMA_INTERRUPT_STATUS_REG) & 0xffff; + u32 mask = cobalt_read_bar1(cobalt, COBALT_SYS_STAT_MASK); + u32 edge = cobalt_read_bar1(cobalt, COBALT_SYS_STAT_EDGE); + int i; + + /* Clear DMA interrupt */ + cobalt_write_bar0(cobalt, DMA_INTERRUPT_STATUS_REG, dma_interrupt); + cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, mask & ~edge); + cobalt_write_bar1(cobalt, COBALT_SYS_STAT_EDGE, edge); + + for (i = 0; i < COBALT_NUM_STREAMS; i++) { + struct cobalt_stream *s = &cobalt->streams[i]; + unsigned dma_fifo_mask = s->dma_fifo_mask; + + if (dma_interrupt & (1 << s->dma_channel)) { + cobalt->irq_dma[i]++; + /* Give fresh buffer to user and chain newly + * queued buffers */ + cobalt_dma_stream_queue_handler(s); + if (!s->is_audio) { + edge &= ~dma_fifo_mask; + cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, + mask & ~edge); + } + } + if (s->is_audio) + continue; + if (edge & s->adv_irq_mask) + set_bit(COBALT_STREAM_FL_ADV_IRQ, &s->flags); + if ((edge & mask & dma_fifo_mask) && vb2_is_streaming(&s->q)) { + cobalt_info("full rx FIFO %d\n", i); + cobalt->irq_full_fifo++; + } + } + + queue_work(cobalt->irq_work_queues, &cobalt->irq_work_queue); + + if (edge & mask & (COBALT_SYSSTAT_VI0_INT1_MSK | + COBALT_SYSSTAT_VI1_INT1_MSK | + COBALT_SYSSTAT_VI2_INT1_MSK | + COBALT_SYSSTAT_VI3_INT1_MSK | + COBALT_SYSSTAT_VIHSMA_INT1_MSK | + COBALT_SYSSTAT_VOHSMA_INT1_MSK)) + cobalt->irq_adv1++; + if (edge & mask & (COBALT_SYSSTAT_VI0_INT2_MSK | + COBALT_SYSSTAT_VI1_INT2_MSK | + COBALT_SYSSTAT_VI2_INT2_MSK | + COBALT_SYSSTAT_VI3_INT2_MSK | + COBALT_SYSSTAT_VIHSMA_INT2_MSK)) + cobalt->irq_adv2++; + if (edge & mask & COBALT_SYSSTAT_VOHSMA_INT1_MSK) + cobalt->irq_advout++; + if (dma_interrupt) + cobalt->irq_dma_tot++; + if (!(edge & mask) && !dma_interrupt) + cobalt->irq_none++; + dma_interrupt = cobalt_read_bar0(cobalt, DMA_INTERRUPT_STATUS_REG); + + return IRQ_HANDLED; +} + +void cobalt_irq_work_handler(struct work_struct *work) +{ + struct cobalt *cobalt = + container_of(work, struct cobalt, irq_work_queue); + int i; + + for (i = 0; i < COBALT_NUM_NODES; i++) { + struct cobalt_stream *s = &cobalt->streams[i]; + + if (test_and_clear_bit(COBALT_STREAM_FL_ADV_IRQ, &s->flags)) { + u32 mask; + + v4l2_subdev_call(cobalt->streams[i].sd, core, + interrupt_service_routine, 0, NULL); + mask = cobalt_read_bar1(cobalt, COBALT_SYS_STAT_MASK); + cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, + mask | s->adv_irq_mask); + } + } +} + +void cobalt_irq_log_status(struct cobalt *cobalt) +{ + u32 mask; + int i; + + cobalt_info("irq: adv1=%u adv2=%u advout=%u none=%u full=%u\n", + cobalt->irq_adv1, cobalt->irq_adv2, cobalt->irq_advout, + cobalt->irq_none, cobalt->irq_full_fifo); + cobalt_info("irq: dma_tot=%u (", cobalt->irq_dma_tot); + for (i = 0; i < COBALT_NUM_STREAMS; i++) + pr_cont("%s%u", i ? "/" : "", cobalt->irq_dma[i]); + pr_cont(")\n"); + cobalt->irq_dma_tot = cobalt->irq_adv1 = cobalt->irq_adv2 = 0; + cobalt->irq_advout = cobalt->irq_none = cobalt->irq_full_fifo = 0; + memset(cobalt->irq_dma, 0, sizeof(cobalt->irq_dma)); + + mask = cobalt_read_bar1(cobalt, COBALT_SYS_STAT_MASK); + cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, + mask | + COBALT_SYSSTAT_VI0_LOST_DATA_MSK | + COBALT_SYSSTAT_VI1_LOST_DATA_MSK | + COBALT_SYSSTAT_VI2_LOST_DATA_MSK | + COBALT_SYSSTAT_VI3_LOST_DATA_MSK | + COBALT_SYSSTAT_VIHSMA_LOST_DATA_MSK | + COBALT_SYSSTAT_VOHSMA_LOST_DATA_MSK | + COBALT_SYSSTAT_AUD_IN_LOST_DATA_MSK | + COBALT_SYSSTAT_AUD_OUT_LOST_DATA_MSK); +} diff --git a/drivers/media/pci/cobalt/cobalt-irq.h b/drivers/media/pci/cobalt/cobalt-irq.h new file mode 100644 index 0000000..5119484 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-irq.h @@ -0,0 +1,25 @@ +/* + * cobalt interrupt handling + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/interrupt.h> + +irqreturn_t cobalt_irq_handler(int irq, void *dev_id); +void cobalt_irq_work_handler(struct work_struct *work); +void cobalt_irq_log_status(struct cobalt *cobalt); diff --git a/drivers/media/pci/cobalt/cobalt-omnitek.c b/drivers/media/pci/cobalt/cobalt-omnitek.c new file mode 100644 index 0000000..a28a848 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-omnitek.c @@ -0,0 +1,341 @@ +/* + * Omnitek Scatter-Gather DMA Controller + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/string.h> +#include <linux/io.h> +#include <linux/pci_regs.h> +#include <linux/spinlock.h> + +#include "cobalt-driver.h" +#include "cobalt-omnitek.h" + +/* descriptor */ +#define END_OF_CHAIN (1 << 1) +#define INTERRUPT_ENABLE (1 << 2) +#define WRITE_TO_PCI (1 << 3) +#define READ_FROM_PCI (0 << 3) +#define DESCRIPTOR_FLAG_MSK (END_OF_CHAIN | INTERRUPT_ENABLE | WRITE_TO_PCI) +#define NEXT_ADRS_MSK 0xffffffe0 + +/* control/status register */ +#define ENABLE (1 << 0) +#define START (1 << 1) +#define ABORT (1 << 2) +#define DONE (1 << 4) +#define SG_INTERRUPT (1 << 5) +#define EVENT_INTERRUPT (1 << 6) +#define SCATTER_GATHER_MODE (1 << 8) +#define DISABLE_VIDEO_RESYNC (1 << 9) +#define EVENT_INTERRUPT_ENABLE (1 << 10) +#define DIRECTIONAL_MSK (3 << 16) +#define INPUT_ONLY (0 << 16) +#define OUTPUT_ONLY (1 << 16) +#define BIDIRECTIONAL (2 << 16) +#define DMA_TYPE_MEMORY (0 << 18) +#define DMA_TYPE_FIFO (1 << 18) + +#define BASE (cobalt->bar0) +#define CAPABILITY_HEADER (BASE) +#define CAPABILITY_REGISTER (BASE + 0x04) +#define PCI_64BIT (1 << 8) +#define LOCAL_64BIT (1 << 9) +#define INTERRUPT_STATUS (BASE + 0x08) +#define PCI(c) (BASE + 0x40 + ((c) * 0x40)) +#define SIZE(c) (BASE + 0x58 + ((c) * 0x40)) +#define DESCRIPTOR(c) (BASE + 0x50 + ((c) * 0x40)) +#define CS_REG(c) (BASE + 0x60 + ((c) * 0x40)) +#define BYTES_TRANSFERRED(c) (BASE + 0x64 + ((c) * 0x40)) + + +static char *get_dma_direction(u32 status) +{ + switch (status & DIRECTIONAL_MSK) { + case INPUT_ONLY: return "Input"; + case OUTPUT_ONLY: return "Output"; + case BIDIRECTIONAL: return "Bidirectional"; + } + return ""; +} + +static void show_dma_capability(struct cobalt *cobalt) +{ + u32 header = ioread32(CAPABILITY_HEADER); + u32 capa = ioread32(CAPABILITY_REGISTER); + u32 i; + + cobalt_info("Omnitek DMA capability: ID 0x%02x Version 0x%02x Next 0x%x Size 0x%x\n", + header & 0xff, (header >> 8) & 0xff, + (header >> 16) & 0xffff, (capa >> 24) & 0xff); + + switch ((capa >> 8) & 0x3) { + case 0: + cobalt_info("Omnitek DMA: 32 bits PCIe and Local\n"); + break; + case 1: + cobalt_info("Omnitek DMA: 64 bits PCIe, 32 bits Local\n"); + break; + case 3: + cobalt_info("Omnitek DMA: 64 bits PCIe and Local\n"); + break; + } + + for (i = 0; i < (capa & 0xf); i++) { + u32 status = ioread32(CS_REG(i)); + + cobalt_info("Omnitek DMA channel #%d: %s %s\n", i, + status & DMA_TYPE_FIFO ? "FIFO" : "MEMORY", + get_dma_direction(status)); + } +} + +void omni_sg_dma_start(struct cobalt_stream *s, struct sg_dma_desc_info *desc) +{ + struct cobalt *cobalt = s->cobalt; + + iowrite32((u32)((u64)desc->bus >> 32), DESCRIPTOR(s->dma_channel) + 4); + iowrite32((u32)desc->bus & NEXT_ADRS_MSK, DESCRIPTOR(s->dma_channel)); + iowrite32(ENABLE | SCATTER_GATHER_MODE | START, CS_REG(s->dma_channel)); +} + +bool is_dma_done(struct cobalt_stream *s) +{ + struct cobalt *cobalt = s->cobalt; + + if (ioread32(CS_REG(s->dma_channel)) & DONE) + return true; + + return false; +} + +void omni_sg_dma_abort_channel(struct cobalt_stream *s) +{ + struct cobalt *cobalt = s->cobalt; + + if (is_dma_done(s) == false) + iowrite32(ABORT, CS_REG(s->dma_channel)); +} + +int omni_sg_dma_init(struct cobalt *cobalt) +{ + u32 capa = ioread32(CAPABILITY_REGISTER); + int i; + + cobalt->first_fifo_channel = 0; + cobalt->dma_channels = capa & 0xf; + if (capa & PCI_64BIT) + cobalt->pci_32_bit = false; + else + cobalt->pci_32_bit = true; + + for (i = 0; i < cobalt->dma_channels; i++) { + u32 status = ioread32(CS_REG(i)); + u32 ctrl = ioread32(CS_REG(i)); + + if (!(ctrl & DONE)) + iowrite32(ABORT, CS_REG(i)); + + if (!(status & DMA_TYPE_FIFO)) + cobalt->first_fifo_channel++; + } + show_dma_capability(cobalt); + return 0; +} + +int descriptor_list_create(struct cobalt *cobalt, + struct scatterlist *scatter_list, bool to_pci, unsigned sglen, + unsigned size, unsigned width, unsigned stride, + struct sg_dma_desc_info *desc) +{ + struct sg_dma_descriptor *d = (struct sg_dma_descriptor *)desc->virt; + dma_addr_t next = desc->bus; + unsigned offset = 0; + unsigned copy_bytes = width; + unsigned copied = 0; + bool first = true; + + /* Must be 4-byte aligned */ + WARN_ON(sg_dma_address(scatter_list) & 3); + WARN_ON(size & 3); + WARN_ON(next & 3); + WARN_ON(stride & 3); + WARN_ON(stride < width); + if (width >= stride) + copy_bytes = stride = size; + + while (size) { + dma_addr_t addr = sg_dma_address(scatter_list) + offset; + unsigned bytes; + + if (addr == 0) + return -EFAULT; + if (cobalt->pci_32_bit) { + WARN_ON((u64)addr >> 32); + if ((u64)addr >> 32) + return -EFAULT; + } + + /* PCIe address */ + d->pci_l = addr & 0xffffffff; + /* If dma_addr_t is 32 bits, then addr >> 32 is actually the + equivalent of addr >> 0 in gcc. So must cast to u64. */ + d->pci_h = (u64)addr >> 32; + + /* Sync to start of streaming frame */ + d->local = 0; + d->reserved0 = 0; + + /* Transfer bytes */ + bytes = min(sg_dma_len(scatter_list) - offset, + copy_bytes - copied); + + if (first) { + if (to_pci) + d->local = 0x11111111; + first = false; + if (sglen == 1) { + /* Make sure there are always at least two + * descriptors */ + d->bytes = (bytes / 2) & ~3; + d->reserved1 = 0; + size -= d->bytes; + copied += d->bytes; + offset += d->bytes; + addr += d->bytes; + next += sizeof(struct sg_dma_descriptor); + d->next_h = (u32)((u64)next >> 32); + d->next_l = (u32)next | + (to_pci ? WRITE_TO_PCI : 0); + bytes -= d->bytes; + d++; + /* PCIe address */ + d->pci_l = addr & 0xffffffff; + /* If dma_addr_t is 32 bits, then addr >> 32 + * is actually the equivalent of addr >> 0 in + * gcc. So must cast to u64. */ + d->pci_h = (u64)addr >> 32; + + /* Sync to start of streaming frame */ + d->local = 0; + d->reserved0 = 0; + } + } + + d->bytes = bytes; + d->reserved1 = 0; + size -= bytes; + copied += bytes; + offset += bytes; + + if (copied == copy_bytes) { + while (copied < stride) { + bytes = min(sg_dma_len(scatter_list) - offset, + stride - copied); + copied += bytes; + offset += bytes; + size -= bytes; + if (sg_dma_len(scatter_list) == offset) { + offset = 0; + scatter_list = sg_next(scatter_list); + } + } + copied = 0; + } else { + offset = 0; + scatter_list = sg_next(scatter_list); + } + + /* Next descriptor + control bits */ + next += sizeof(struct sg_dma_descriptor); + if (size == 0) { + /* Loopback to the first descriptor */ + d->next_h = (u32)((u64)desc->bus >> 32); + d->next_l = (u32)desc->bus | + (to_pci ? WRITE_TO_PCI : 0) | INTERRUPT_ENABLE; + if (!to_pci) + d->local = 0x22222222; + desc->last_desc_virt = d; + } else { + d->next_h = (u32)((u64)next >> 32); + d->next_l = (u32)next | (to_pci ? WRITE_TO_PCI : 0); + } + d++; + } + return 0; +} + +void descriptor_list_chain(struct sg_dma_desc_info *this, + struct sg_dma_desc_info *next) +{ + struct sg_dma_descriptor *d = this->last_desc_virt; + u32 direction = d->next_l & WRITE_TO_PCI; + + if (next == NULL) { + d->next_h = 0; + d->next_l = direction | INTERRUPT_ENABLE | END_OF_CHAIN; + } else { + d->next_h = (u32)((u64)next->bus >> 32); + d->next_l = (u32)next->bus | direction | INTERRUPT_ENABLE; + } +} + +void *descriptor_list_allocate(struct sg_dma_desc_info *desc, size_t bytes) +{ + desc->size = bytes; + desc->virt = dma_alloc_coherent(desc->dev, bytes, + &desc->bus, GFP_KERNEL); + return desc->virt; +} + +void descriptor_list_free(struct sg_dma_desc_info *desc) +{ + if (desc->virt) + dma_free_coherent(desc->dev, desc->size, + desc->virt, desc->bus); + desc->virt = NULL; +} + +void descriptor_list_interrupt_enable(struct sg_dma_desc_info *desc) +{ + struct sg_dma_descriptor *d = desc->last_desc_virt; + + d->next_l |= INTERRUPT_ENABLE; +} + +void descriptor_list_interrupt_disable(struct sg_dma_desc_info *desc) +{ + struct sg_dma_descriptor *d = desc->last_desc_virt; + + d->next_l &= ~INTERRUPT_ENABLE; +} + +void descriptor_list_loopback(struct sg_dma_desc_info *desc) +{ + struct sg_dma_descriptor *d = desc->last_desc_virt; + + d->next_h = (u32)((u64)desc->bus >> 32); + d->next_l = (u32)desc->bus | (d->next_l & DESCRIPTOR_FLAG_MSK); +} + +void descriptor_list_end_of_chain(struct sg_dma_desc_info *desc) +{ + struct sg_dma_descriptor *d = desc->last_desc_virt; + + d->next_l |= END_OF_CHAIN; +} diff --git a/drivers/media/pci/cobalt/cobalt-omnitek.h b/drivers/media/pci/cobalt/cobalt-omnitek.h new file mode 100644 index 0000000..e5c6d03 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-omnitek.h @@ -0,0 +1,62 @@ +/* + * Omnitek Scatter-Gather DMA Controller + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef COBALT_OMNITEK_H +#define COBALT_OMNITEK_H + +#include <linux/scatterlist.h> +#include "cobalt-driver.h" + +struct sg_dma_descriptor { + u32 pci_l; + u32 pci_h; + + u32 local; + u32 reserved0; + + u32 next_l; + u32 next_h; + + u32 bytes; + u32 reserved1; +}; + +int omni_sg_dma_init(struct cobalt *cobalt); +void omni_sg_dma_abort_channel(struct cobalt_stream *s); +void omni_sg_dma_start(struct cobalt_stream *s, struct sg_dma_desc_info *desc); +bool is_dma_done(struct cobalt_stream *s); + +int descriptor_list_create(struct cobalt *cobalt, + struct scatterlist *scatter_list, bool to_pci, unsigned sglen, + unsigned size, unsigned width, unsigned stride, + struct sg_dma_desc_info *desc); + +void descriptor_list_chain(struct sg_dma_desc_info *this, + struct sg_dma_desc_info *next); +void descriptor_list_loopback(struct sg_dma_desc_info *desc); +void descriptor_list_end_of_chain(struct sg_dma_desc_info *desc); + +void *descriptor_list_allocate(struct sg_dma_desc_info *desc, size_t bytes); +void descriptor_list_free(struct sg_dma_desc_info *desc); + +void descriptor_list_interrupt_enable(struct sg_dma_desc_info *desc); +void descriptor_list_interrupt_disable(struct sg_dma_desc_info *desc); + +#endif diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c new file mode 100644 index 0000000..b40c2d1 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -0,0 +1,1272 @@ +/* + * cobalt V4L2 API + * + * Derived from ivtv-ioctl.c and cx18-fileops.c + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/math64.h> +#include <linux/pci.h> +#include <linux/v4l2-dv-timings.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> +#include <media/adv7604.h> +#include <media/adv7842.h> + +#include "cobalt-alsa.h" +#include "cobalt-cpld.h" +#include "cobalt-driver.h" +#include "cobalt-v4l2.h" +#include "cobalt-irq.h" +#include "cobalt-omnitek.h" + +static const struct v4l2_dv_timings cea1080p60 = V4L2_DV_BT_CEA_1920X1080P60; + +/* vb2 DMA streaming ops */ + +static int cobalt_queue_setup(struct vb2_queue *q, + const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct cobalt_stream *s = q->drv_priv; + unsigned size = s->stride * s->height; + + if (*num_buffers < 3) + *num_buffers = 3; + if (*num_buffers > NR_BUFS) + *num_buffers = NR_BUFS; + *num_planes = 1; + if (fmt) { + if (fmt->fmt.pix.sizeimage < size) + return -EINVAL; + size = fmt->fmt.pix.sizeimage; + } + sizes[0] = size; + alloc_ctxs[0] = s->cobalt->alloc_ctx; + return 0; +} + +static int cobalt_buf_init(struct vb2_buffer *vb) +{ + struct cobalt_stream *s = vb->vb2_queue->drv_priv; + struct cobalt *cobalt = s->cobalt; + const size_t max_pages_per_line = + (COBALT_MAX_WIDTH * COBALT_MAX_BPP) / PAGE_SIZE + 2; + const size_t bytes = + COBALT_MAX_HEIGHT * max_pages_per_line * 0x20; + const size_t audio_bytes = ((1920 * 4) / PAGE_SIZE + 1) * 0x20; + struct sg_dma_desc_info *desc = &s->dma_desc_info[vb->v4l2_buf.index]; + struct sg_table *sg_desc = vb2_dma_sg_plane_desc(vb, 0); + unsigned size; + int ret; + + size = s->stride * s->height; + if (vb2_plane_size(vb, 0) < size) { + cobalt_info("data will not fit into plane (%lu < %u)\n", + vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + if (desc->virt == NULL) { + desc->dev = &cobalt->pci_dev->dev; + descriptor_list_allocate(desc, + s->is_audio ? audio_bytes : bytes); + if (desc->virt == NULL) + return -ENOMEM; + } + ret = descriptor_list_create(cobalt, sg_desc->sgl, + !s->is_output, sg_desc->nents, size, + s->width * s->bpp, s->stride, desc); + if (ret) + descriptor_list_free(desc); + return ret; +} + +static void cobalt_buf_cleanup(struct vb2_buffer *vb) +{ + struct cobalt_stream *s = vb->vb2_queue->drv_priv; + struct sg_dma_desc_info *desc = &s->dma_desc_info[vb->v4l2_buf.index]; + + descriptor_list_free(desc); +} + +static int cobalt_buf_prepare(struct vb2_buffer *vb) +{ + struct cobalt_stream *s = vb->vb2_queue->drv_priv; + + vb2_set_plane_payload(vb, 0, s->stride * s->height); + vb->v4l2_buf.field = V4L2_FIELD_NONE; + return 0; +} + +static void chain_all_buffers(struct cobalt_stream *s) +{ + struct sg_dma_desc_info *desc[NR_BUFS]; + struct cobalt_buffer *cb; + struct list_head *p; + int i = 0; + + list_for_each(p, &s->bufs) { + cb = list_entry(p, struct cobalt_buffer, list); + desc[i] = &s->dma_desc_info[cb->vb.v4l2_buf.index]; + if (i > 0) + descriptor_list_chain(desc[i-1], desc[i]); + i++; + } +} + +static void cobalt_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_queue *q = vb->vb2_queue; + struct cobalt_stream *s = q->drv_priv; + struct cobalt_buffer *cb = to_cobalt_buffer(vb); + struct sg_dma_desc_info *desc = &s->dma_desc_info[vb->v4l2_buf.index]; + unsigned long flags; + + /* Prepare new buffer */ + descriptor_list_loopback(desc); + descriptor_list_interrupt_disable(desc); + + spin_lock_irqsave(&s->irqlock, flags); + list_add_tail(&cb->list, &s->bufs); + chain_all_buffers(s); + spin_unlock_irqrestore(&s->irqlock, flags); +} + +static void cobalt_enable_output(struct cobalt_stream *s) +{ + struct cobalt *cobalt = s->cobalt; + struct v4l2_bt_timings *bt = &s->timings.bt; + struct m00514_syncgen_flow_evcnt_regmap __iomem *vo = + COBALT_TX_BASE(cobalt); + unsigned fmt = s->pixfmt != V4L2_PIX_FMT_BGR32 ? + M00514_CONTROL_BITMAP_FORMAT_16_BPP_MSK : 0; + struct v4l2_subdev_format sd_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + if (!cobalt_cpld_set_freq(cobalt, bt->pixelclock)) { + cobalt_err("pixelclock out of range\n"); + return; + } + + sd_fmt.format.colorspace = s->colorspace; + sd_fmt.format.xfer_func = s->xfer_func; + sd_fmt.format.ycbcr_enc = s->ycbcr_enc; + sd_fmt.format.quantization = s->quantization; + sd_fmt.format.width = bt->width; + sd_fmt.format.height = bt->height; + + /* Set up FDMA packer */ + switch (s->pixfmt) { + case V4L2_PIX_FMT_YUYV: + sd_fmt.format.code = MEDIA_BUS_FMT_UYVY8_1X16; + break; + case V4L2_PIX_FMT_BGR32: + sd_fmt.format.code = MEDIA_BUS_FMT_RGB888_1X24; + break; + } + v4l2_subdev_call(s->sd, pad, set_fmt, NULL, &sd_fmt); + + iowrite32(0, &vo->control); + /* 1080p60 */ + iowrite32(bt->hsync, &vo->sync_generator_h_sync_length); + iowrite32(bt->hbackporch, &vo->sync_generator_h_backporch_length); + iowrite32(bt->width, &vo->sync_generator_h_active_length); + iowrite32(bt->hfrontporch, &vo->sync_generator_h_frontporch_length); + iowrite32(bt->vsync, &vo->sync_generator_v_sync_length); + iowrite32(bt->vbackporch, &vo->sync_generator_v_backporch_length); + iowrite32(bt->height, &vo->sync_generator_v_active_length); + iowrite32(bt->vfrontporch, &vo->sync_generator_v_frontporch_length); + iowrite32(0x9900c1, &vo->error_color); + + iowrite32(M00514_CONTROL_BITMAP_SYNC_GENERATOR_LOAD_PARAM_MSK | fmt, + &vo->control); + iowrite32(M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK | fmt, &vo->control); + iowrite32(M00514_CONTROL_BITMAP_SYNC_GENERATOR_ENABLE_MSK | + M00514_CONTROL_BITMAP_FLOW_CTRL_OUTPUT_ENABLE_MSK | + fmt, &vo->control); +} + +static void cobalt_enable_input(struct cobalt_stream *s) +{ + struct cobalt *cobalt = s->cobalt; + int ch = (int)s->video_channel; + struct m00235_fdma_packer_regmap __iomem *packer; + struct v4l2_subdev_format sd_fmt_yuyv = { + .pad = s->pad_source, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .format.code = MEDIA_BUS_FMT_YUYV8_1X16, + }; + struct v4l2_subdev_format sd_fmt_rgb = { + .pad = s->pad_source, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .format.code = MEDIA_BUS_FMT_RGB888_1X24, + }; + + cobalt_dbg(1, "video_channel %d (%s, %s)\n", + s->video_channel, + s->input == 0 ? "hdmi" : "generator", + "YUYV"); + + packer = COBALT_CVI_PACKER(cobalt, ch); + + /* Set up FDMA packer */ + switch (s->pixfmt) { + case V4L2_PIX_FMT_YUYV: + iowrite32(M00235_CONTROL_BITMAP_ENABLE_MSK | + (1 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST), + &packer->control); + v4l2_subdev_call(s->sd, pad, set_fmt, NULL, + &sd_fmt_yuyv); + break; + case V4L2_PIX_FMT_RGB24: + iowrite32(M00235_CONTROL_BITMAP_ENABLE_MSK | + (2 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST), + &packer->control); + v4l2_subdev_call(s->sd, pad, set_fmt, NULL, + &sd_fmt_rgb); + break; + case V4L2_PIX_FMT_BGR32: + iowrite32(M00235_CONTROL_BITMAP_ENABLE_MSK | + M00235_CONTROL_BITMAP_ENDIAN_FORMAT_MSK | + (3 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST), + &packer->control); + v4l2_subdev_call(s->sd, pad, set_fmt, NULL, + &sd_fmt_rgb); + break; + } +} + +static void cobalt_dma_start_streaming(struct cobalt_stream *s) +{ + struct cobalt *cobalt = s->cobalt; + int rx = s->video_channel; + struct m00460_evcnt_regmap __iomem *evcnt = + COBALT_CVI_EVCNT(cobalt, rx); + struct cobalt_buffer *cb; + unsigned long flags; + + spin_lock_irqsave(&s->irqlock, flags); + if (!s->is_output) { + iowrite32(M00460_CONTROL_BITMAP_CLEAR_MSK, &evcnt->control); + iowrite32(M00460_CONTROL_BITMAP_ENABLE_MSK, &evcnt->control); + } else { + struct m00514_syncgen_flow_evcnt_regmap __iomem *vo = + COBALT_TX_BASE(cobalt); + u32 ctrl = ioread32(&vo->control); + + ctrl &= ~(M00514_CONTROL_BITMAP_EVCNT_ENABLE_MSK | + M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK); + iowrite32(ctrl | M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK, + &vo->control); + iowrite32(ctrl | M00514_CONTROL_BITMAP_EVCNT_ENABLE_MSK, + &vo->control); + } + cb = list_first_entry(&s->bufs, struct cobalt_buffer, list); + omni_sg_dma_start(s, &s->dma_desc_info[cb->vb.v4l2_buf.index]); + spin_unlock_irqrestore(&s->irqlock, flags); +} + +static int cobalt_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct cobalt_stream *s = q->drv_priv; + struct cobalt *cobalt = s->cobalt; + struct m00233_video_measure_regmap __iomem *vmr; + struct m00473_freewheel_regmap __iomem *fw; + struct m00479_clk_loss_detector_regmap __iomem *clkloss; + int rx = s->video_channel; + struct m00389_cvi_regmap __iomem *cvi = COBALT_CVI(cobalt, rx); + struct m00460_evcnt_regmap __iomem *evcnt = COBALT_CVI_EVCNT(cobalt, rx); + struct v4l2_bt_timings *bt = &s->timings.bt; + u64 tot_size; + u32 clk_freq; + + if (s->is_audio) + goto done; + if (s->is_output) { + s->unstable_frame = false; + cobalt_enable_output(s); + goto done; + } + + cobalt_enable_input(s); + + fw = COBALT_CVI_FREEWHEEL(cobalt, rx); + vmr = COBALT_CVI_VMR(cobalt, rx); + clkloss = COBALT_CVI_CLK_LOSS(cobalt, rx); + + iowrite32(M00460_CONTROL_BITMAP_CLEAR_MSK, &evcnt->control); + iowrite32(M00460_CONTROL_BITMAP_ENABLE_MSK, &evcnt->control); + iowrite32(bt->width, &cvi->frame_width); + iowrite32(bt->height, &cvi->frame_height); + tot_size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt); + iowrite32(div_u64((u64)V4L2_DV_BT_FRAME_WIDTH(bt) * COBALT_CLK * 4, + bt->pixelclock), &vmr->hsync_timeout_val); + iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, &vmr->control); + clk_freq = ioread32(&fw->clk_freq); + iowrite32(clk_freq / 1000000, &clkloss->ref_clk_cnt_val); + /* The lower bound for the clock frequency is 0.5% lower as is + * allowed by the spec */ + iowrite32(div_u64(bt->pixelclock * 995, 1000000000), + &clkloss->test_clk_cnt_val); + /* will be enabled after the first frame has been received */ + iowrite32(bt->width * bt->height, &fw->active_length); + iowrite32(div_u64((u64)clk_freq * tot_size, bt->pixelclock), + &fw->total_length); + iowrite32(M00233_IRQ_TRIGGERS_BITMAP_VACTIVE_AREA_MSK | + M00233_IRQ_TRIGGERS_BITMAP_HACTIVE_AREA_MSK, + &vmr->irq_triggers); + iowrite32(0, &cvi->control); + iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, &vmr->control); + + iowrite32(0xff, &fw->output_color); + iowrite32(M00479_CTRL_BITMAP_ENABLE_MSK, &clkloss->ctrl); + iowrite32(M00473_CTRL_BITMAP_ENABLE_MSK | + M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK, &fw->ctrl); + s->unstable_frame = true; + s->enable_freewheel = false; + s->enable_cvi = false; + s->skip_first_frames = 0; + +done: + s->sequence = 0; + cobalt_dma_start_streaming(s); + return 0; +} + +static void cobalt_dma_stop_streaming(struct cobalt_stream *s) +{ + struct cobalt *cobalt = s->cobalt; + struct sg_dma_desc_info *desc; + struct cobalt_buffer *cb; + struct list_head *p; + unsigned long flags; + int timeout_msec = 100; + int rx = s->video_channel; + struct m00460_evcnt_regmap __iomem *evcnt = + COBALT_CVI_EVCNT(cobalt, rx); + + if (!s->is_output) { + iowrite32(0, &evcnt->control); + } else if (!s->is_audio) { + struct m00514_syncgen_flow_evcnt_regmap __iomem *vo = + COBALT_TX_BASE(cobalt); + + iowrite32(M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK, &vo->control); + iowrite32(0, &vo->control); + } + + /* Try to stop the DMA engine gracefully */ + spin_lock_irqsave(&s->irqlock, flags); + list_for_each(p, &s->bufs) { + cb = list_entry(p, struct cobalt_buffer, list); + desc = &s->dma_desc_info[cb->vb.v4l2_buf.index]; + /* Stop DMA after this descriptor chain */ + descriptor_list_end_of_chain(desc); + } + spin_unlock_irqrestore(&s->irqlock, flags); + + /* Wait 100 milisecond for DMA to finish, abort on timeout. */ + if (!wait_event_timeout(s->q.done_wq, is_dma_done(s), + msecs_to_jiffies(timeout_msec))) { + omni_sg_dma_abort_channel(s); + pr_warn("aborted\n"); + } + cobalt_write_bar0(cobalt, DMA_INTERRUPT_STATUS_REG, + 1 << s->dma_channel); +} + +static void cobalt_stop_streaming(struct vb2_queue *q) +{ + struct cobalt_stream *s = q->drv_priv; + struct cobalt *cobalt = s->cobalt; + int rx = s->video_channel; + struct m00233_video_measure_regmap __iomem *vmr; + struct m00473_freewheel_regmap __iomem *fw; + struct m00479_clk_loss_detector_regmap __iomem *clkloss; + struct cobalt_buffer *cb; + struct list_head *p, *safe; + unsigned long flags; + + cobalt_dma_stop_streaming(s); + + /* Return all buffers to user space */ + spin_lock_irqsave(&s->irqlock, flags); + list_for_each_safe(p, safe, &s->bufs) { + cb = list_entry(p, struct cobalt_buffer, list); + list_del(&cb->list); + vb2_buffer_done(&cb->vb, VB2_BUF_STATE_ERROR); + } + spin_unlock_irqrestore(&s->irqlock, flags); + + if (s->is_audio || s->is_output) + return; + + fw = COBALT_CVI_FREEWHEEL(cobalt, rx); + vmr = COBALT_CVI_VMR(cobalt, rx); + clkloss = COBALT_CVI_CLK_LOSS(cobalt, rx); + iowrite32(0, &vmr->control); + iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, &vmr->control); + iowrite32(0, &fw->ctrl); + iowrite32(0, &clkloss->ctrl); +} + +static const struct vb2_ops cobalt_qops = { + .queue_setup = cobalt_queue_setup, + .buf_init = cobalt_buf_init, + .buf_cleanup = cobalt_buf_cleanup, + .buf_prepare = cobalt_buf_prepare, + .buf_queue = cobalt_buf_queue, + .start_streaming = cobalt_start_streaming, + .stop_streaming = cobalt_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +/* V4L2 ioctls */ + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int cobalt_cobaltc(struct cobalt *cobalt, unsigned int cmd, void *arg) +{ + struct v4l2_dbg_register *regs = arg; + void __iomem *adrs = cobalt->bar1 + regs->reg; + + cobalt_info("cobalt_cobaltc: adrs = %p\n", adrs); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + regs->size = 4; + if (cmd == VIDIOC_DBG_S_REGISTER) + iowrite32(regs->val, adrs); + else + regs->val = ioread32(adrs); + return 0; +} + +static int cobalt_g_register(struct file *file, void *priv_fh, + struct v4l2_dbg_register *reg) +{ + struct cobalt_stream *s = video_drvdata(file); + struct cobalt *cobalt = s->cobalt; + + return cobalt_cobaltc(cobalt, VIDIOC_DBG_G_REGISTER, reg); +} + +static int cobalt_s_register(struct file *file, void *priv_fh, + const struct v4l2_dbg_register *reg) +{ + struct cobalt_stream *s = video_drvdata(file); + struct cobalt *cobalt = s->cobalt; + + return cobalt_cobaltc(cobalt, VIDIOC_DBG_S_REGISTER, + (struct v4l2_dbg_register *)reg); +} +#endif + +static int cobalt_querycap(struct file *file, void *priv_fh, + struct v4l2_capability *vcap) +{ + struct cobalt_stream *s = video_drvdata(file); + struct cobalt *cobalt = s->cobalt; + + strlcpy(vcap->driver, "cobalt", sizeof(vcap->driver)); + strlcpy(vcap->card, "cobalt", sizeof(vcap->card)); + snprintf(vcap->bus_info, sizeof(vcap->bus_info), + "PCIe:%s", pci_name(cobalt->pci_dev)); + vcap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (s->is_output) + vcap->device_caps |= V4L2_CAP_VIDEO_OUTPUT; + else + vcap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; + vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS | + V4L2_CAP_VIDEO_CAPTURE; + if (cobalt->have_hsma_tx) + vcap->capabilities |= V4L2_CAP_VIDEO_OUTPUT; + return 0; +} + +static void cobalt_video_input_status_show(struct cobalt_stream *s) +{ + struct m00389_cvi_regmap __iomem *cvi; + struct m00233_video_measure_regmap __iomem *vmr; + struct m00473_freewheel_regmap __iomem *fw; + struct m00479_clk_loss_detector_regmap __iomem *clkloss; + struct m00235_fdma_packer_regmap __iomem *packer; + int rx = s->video_channel; + struct cobalt *cobalt = s->cobalt; + u32 cvi_ctrl, cvi_stat; + u32 vmr_ctrl, vmr_stat; + + cvi = COBALT_CVI(cobalt, rx); + vmr = COBALT_CVI_VMR(cobalt, rx); + fw = COBALT_CVI_FREEWHEEL(cobalt, rx); + clkloss = COBALT_CVI_CLK_LOSS(cobalt, rx); + packer = COBALT_CVI_PACKER(cobalt, rx); + cvi_ctrl = ioread32(&cvi->control); + cvi_stat = ioread32(&cvi->status); + vmr_ctrl = ioread32(&vmr->control); + vmr_stat = ioread32(&vmr->control); + cobalt_info("rx%d: cvi resolution: %dx%d\n", rx, + ioread32(&cvi->frame_width), ioread32(&cvi->frame_height)); + cobalt_info("rx%d: cvi control: %s%s%s\n", rx, + (cvi_ctrl & M00389_CONTROL_BITMAP_ENABLE_MSK) ? + "enable " : "disable ", + (cvi_ctrl & M00389_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK) ? + "HSync- " : "HSync+ ", + (cvi_ctrl & M00389_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK) ? + "VSync- " : "VSync+ "); + cobalt_info("rx%d: cvi status: %s%s\n", rx, + (cvi_stat & M00389_STATUS_BITMAP_LOCK_MSK) ? + "lock " : "no-lock ", + (cvi_stat & M00389_STATUS_BITMAP_ERROR_MSK) ? + "error " : "no-error "); + + cobalt_info("rx%d: Measurements: %s%s%s%s%s%s%s\n", rx, + (vmr_ctrl & M00233_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK) ? + "HSync- " : "HSync+ ", + (vmr_ctrl & M00233_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK) ? + "VSync- " : "VSync+ ", + (vmr_ctrl & M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK) ? + "enabled " : "disabled ", + (vmr_ctrl & M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_MSK) ? + "irq-enabled " : "irq-disabled ", + (vmr_ctrl & M00233_CONTROL_BITMAP_UPDATE_ON_HSYNC_MSK) ? + "update-on-hsync " : "", + (vmr_stat & M00233_STATUS_BITMAP_HSYNC_TIMEOUT_MSK) ? + "hsync-timeout " : "", + (vmr_stat & M00233_STATUS_BITMAP_INIT_DONE_MSK) ? + "init-done" : ""); + cobalt_info("rx%d: irq_status: 0x%02x irq_triggers: 0x%02x\n", rx, + ioread32(&vmr->irq_status) & 0xff, + ioread32(&vmr->irq_triggers) & 0xff); + cobalt_info("rx%d: vsync: %d\n", rx, ioread32(&vmr->vsync_time)); + cobalt_info("rx%d: vbp: %d\n", rx, ioread32(&vmr->vback_porch)); + cobalt_info("rx%d: vact: %d\n", rx, ioread32(&vmr->vactive_area)); + cobalt_info("rx%d: vfb: %d\n", rx, ioread32(&vmr->vfront_porch)); + cobalt_info("rx%d: hsync: %d\n", rx, ioread32(&vmr->hsync_time)); + cobalt_info("rx%d: hbp: %d\n", rx, ioread32(&vmr->hback_porch)); + cobalt_info("rx%d: hact: %d\n", rx, ioread32(&vmr->hactive_area)); + cobalt_info("rx%d: hfb: %d\n", rx, ioread32(&vmr->hfront_porch)); + cobalt_info("rx%d: Freewheeling: %s%s%s\n", rx, + (ioread32(&fw->ctrl) & M00473_CTRL_BITMAP_ENABLE_MSK) ? + "enabled " : "disabled ", + (ioread32(&fw->ctrl) & M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK) ? + "forced " : "", + (ioread32(&fw->status) & M00473_STATUS_BITMAP_FREEWHEEL_MODE_MSK) ? + "freewheeling " : "video-passthrough "); + iowrite32(0xff, &vmr->irq_status); + cobalt_info("rx%d: Clock Loss Detection: %s%s\n", rx, + (ioread32(&clkloss->ctrl) & M00479_CTRL_BITMAP_ENABLE_MSK) ? + "enabled " : "disabled ", + (ioread32(&clkloss->status) & M00479_STATUS_BITMAP_CLOCK_MISSING_MSK) ? + "clock-missing " : "found-clock "); + cobalt_info("rx%d: Packer: %x\n", rx, ioread32(&packer->control)); +} + +static int cobalt_log_status(struct file *file, void *priv_fh) +{ + struct cobalt_stream *s = video_drvdata(file); + struct cobalt *cobalt = s->cobalt; + struct m00514_syncgen_flow_evcnt_regmap __iomem *vo = + COBALT_TX_BASE(cobalt); + u8 stat; + + cobalt_info("%s", cobalt->hdl_info); + cobalt_info("sysctrl: %08x, sysstat: %08x\n", + cobalt_g_sysctrl(cobalt), + cobalt_g_sysstat(cobalt)); + cobalt_info("dma channel: %d, video channel: %d\n", + s->dma_channel, s->video_channel); + cobalt_pcie_status_show(cobalt); + cobalt_cpld_status(cobalt); + cobalt_irq_log_status(cobalt); + v4l2_subdev_call(s->sd, core, log_status); + if (!s->is_output) { + cobalt_video_input_status_show(s); + return 0; + } + + stat = ioread32(&vo->rd_status); + + cobalt_info("tx: status: %s%s\n", + (stat & M00514_RD_STATUS_BITMAP_FLOW_CTRL_NO_DATA_ERROR_MSK) ? + "no_data " : "", + (stat & M00514_RD_STATUS_BITMAP_READY_BUFFER_FULL_MSK) ? + "ready_buffer_full " : ""); + cobalt_info("tx: evcnt: %d\n", ioread32(&vo->rd_evcnt_count)); + return 0; +} + +static int cobalt_enum_dv_timings(struct file *file, void *priv_fh, + struct v4l2_enum_dv_timings *timings) +{ + struct cobalt_stream *s = video_drvdata(file); + + if (s->input == 1) { + if (timings->index) + return -EINVAL; + memset(timings->reserved, 0, sizeof(timings->reserved)); + timings->timings = cea1080p60; + return 0; + } + timings->pad = 0; + return v4l2_subdev_call(s->sd, + pad, enum_dv_timings, timings); +} + +static int cobalt_s_dv_timings(struct file *file, void *priv_fh, + struct v4l2_dv_timings *timings) +{ + struct cobalt_stream *s = video_drvdata(file); + int err; + + if (vb2_is_busy(&s->q)) + return -EBUSY; + + if (s->input == 1) { + *timings = cea1080p60; + return 0; + } + err = v4l2_subdev_call(s->sd, + video, s_dv_timings, timings); + if (!err) { + s->timings = *timings; + s->width = timings->bt.width; + s->height = timings->bt.height; + s->stride = timings->bt.width * s->bpp; + } + return err; +} + +static int cobalt_g_dv_timings(struct file *file, void *priv_fh, + struct v4l2_dv_timings *timings) +{ + struct cobalt_stream *s = video_drvdata(file); + + if (s->input == 1) { + *timings = cea1080p60; + return 0; + } + return v4l2_subdev_call(s->sd, + video, g_dv_timings, timings); +} + +static int cobalt_query_dv_timings(struct file *file, void *priv_fh, + struct v4l2_dv_timings *timings) +{ + struct cobalt_stream *s = video_drvdata(file); + + if (s->input == 1) { + *timings = cea1080p60; + return 0; + } + return v4l2_subdev_call(s->sd, + video, query_dv_timings, timings); +} + +static int cobalt_dv_timings_cap(struct file *file, void *priv_fh, + struct v4l2_dv_timings_cap *cap) +{ + struct cobalt_stream *s = video_drvdata(file); + + cap->pad = 0; + return v4l2_subdev_call(s->sd, + pad, dv_timings_cap, cap); +} + +static int cobalt_enum_fmt_vid_cap(struct file *file, void *priv_fh, + struct v4l2_fmtdesc *f) +{ + switch (f->index) { + case 0: + strlcpy(f->description, "YUV 4:2:2", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_YUYV; + break; + case 1: + strlcpy(f->description, "RGB24", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_RGB24; + break; + case 2: + strlcpy(f->description, "RGB32", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_BGR32; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cobalt_g_fmt_vid_cap(struct file *file, void *priv_fh, + struct v4l2_format *f) +{ + struct cobalt_stream *s = video_drvdata(file); + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_subdev_format sd_fmt; + + pix->width = s->width; + pix->height = s->height; + pix->bytesperline = s->stride; + pix->field = V4L2_FIELD_NONE; + + if (s->input == 1) { + pix->colorspace = V4L2_COLORSPACE_SRGB; + } else { + sd_fmt.pad = s->pad_source; + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + v4l2_subdev_call(s->sd, pad, get_fmt, NULL, &sd_fmt); + v4l2_fill_pix_format(pix, &sd_fmt.format); + } + + pix->pixelformat = s->pixfmt; + pix->sizeimage = pix->bytesperline * pix->height; + + return 0; +} + +static int cobalt_try_fmt_vid_cap(struct file *file, void *priv_fh, + struct v4l2_format *f) +{ + struct cobalt_stream *s = video_drvdata(file); + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_subdev_format sd_fmt; + + /* Check for min (QCIF) and max (Full HD) size */ + if ((pix->width < 176) || (pix->height < 144)) { + pix->width = 176; + pix->height = 144; + } + + if ((pix->width > 1920) || (pix->height > 1080)) { + pix->width = 1920; + pix->height = 1080; + } + + /* Make width multiple of 4 */ + pix->width &= ~0x3; + + /* Make height multiple of 2 */ + pix->height &= ~0x1; + + if (s->input == 1) { + /* Generator => fixed format only */ + pix->width = 1920; + pix->height = 1080; + pix->colorspace = V4L2_COLORSPACE_SRGB; + } else { + sd_fmt.pad = s->pad_source; + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + v4l2_subdev_call(s->sd, pad, get_fmt, NULL, &sd_fmt); + v4l2_fill_pix_format(pix, &sd_fmt.format); + } + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + default: + pix->bytesperline = max(pix->bytesperline & ~0x3, + pix->width * COBALT_BYTES_PER_PIXEL_YUYV); + pix->pixelformat = V4L2_PIX_FMT_YUYV; + break; + case V4L2_PIX_FMT_RGB24: + pix->bytesperline = max(pix->bytesperline & ~0x3, + pix->width * COBALT_BYTES_PER_PIXEL_RGB24); + break; + case V4L2_PIX_FMT_BGR32: + pix->bytesperline = max(pix->bytesperline & ~0x3, + pix->width * COBALT_BYTES_PER_PIXEL_RGB32); + break; + } + + pix->sizeimage = pix->bytesperline * pix->height; + pix->field = V4L2_FIELD_NONE; + pix->priv = 0; + + return 0; +} + +static int cobalt_s_fmt_vid_cap(struct file *file, void *priv_fh, + struct v4l2_format *f) +{ + struct cobalt_stream *s = video_drvdata(file); + struct v4l2_pix_format *pix = &f->fmt.pix; + + if (vb2_is_busy(&s->q)) + return -EBUSY; + + if (cobalt_try_fmt_vid_cap(file, priv_fh, f)) + return -EINVAL; + + s->width = pix->width; + s->height = pix->height; + s->stride = pix->bytesperline; + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + s->bpp = COBALT_BYTES_PER_PIXEL_YUYV; + break; + case V4L2_PIX_FMT_RGB24: + s->bpp = COBALT_BYTES_PER_PIXEL_RGB24; + break; + case V4L2_PIX_FMT_BGR32: + s->bpp = COBALT_BYTES_PER_PIXEL_RGB32; + break; + default: + return -EINVAL; + } + s->pixfmt = pix->pixelformat; + cobalt_enable_input(s); + + return 0; +} + +static int cobalt_try_fmt_vid_out(struct file *file, void *priv_fh, + struct v4l2_format *f) +{ + struct v4l2_pix_format *pix = &f->fmt.pix; + + /* Check for min (QCIF) and max (Full HD) size */ + if ((pix->width < 176) || (pix->height < 144)) { + pix->width = 176; + pix->height = 144; + } + + if ((pix->width > 1920) || (pix->height > 1080)) { + pix->width = 1920; + pix->height = 1080; + } + + /* Make width multiple of 4 */ + pix->width &= ~0x3; + + /* Make height multiple of 2 */ + pix->height &= ~0x1; + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + default: + pix->bytesperline = max(pix->bytesperline & ~0x3, + pix->width * COBALT_BYTES_PER_PIXEL_YUYV); + pix->pixelformat = V4L2_PIX_FMT_YUYV; + break; + case V4L2_PIX_FMT_BGR32: + pix->bytesperline = max(pix->bytesperline & ~0x3, + pix->width * COBALT_BYTES_PER_PIXEL_RGB32); + break; + } + + pix->sizeimage = pix->bytesperline * pix->height; + pix->field = V4L2_FIELD_NONE; + + return 0; +} + +static int cobalt_g_fmt_vid_out(struct file *file, void *priv_fh, + struct v4l2_format *f) +{ + struct cobalt_stream *s = video_drvdata(file); + struct v4l2_pix_format *pix = &f->fmt.pix; + + pix->width = s->width; + pix->height = s->height; + pix->bytesperline = s->stride; + pix->field = V4L2_FIELD_NONE; + pix->pixelformat = s->pixfmt; + pix->colorspace = s->colorspace; + pix->xfer_func = s->xfer_func; + pix->ycbcr_enc = s->ycbcr_enc; + pix->quantization = s->quantization; + pix->sizeimage = pix->bytesperline * pix->height; + + return 0; +} + +static int cobalt_enum_fmt_vid_out(struct file *file, void *priv_fh, + struct v4l2_fmtdesc *f) +{ + switch (f->index) { + case 0: + strlcpy(f->description, "YUV 4:2:2", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_YUYV; + break; + case 1: + strlcpy(f->description, "RGB32", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_BGR32; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cobalt_s_fmt_vid_out(struct file *file, void *priv_fh, + struct v4l2_format *f) +{ + struct cobalt_stream *s = video_drvdata(file); + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_subdev_format sd_fmt = { 0 }; + u32 code; + + if (cobalt_try_fmt_vid_out(file, priv_fh, f)) + return -EINVAL; + + if (vb2_is_busy(&s->q) && (pix->pixelformat != s->pixfmt || + pix->width != s->width || pix->height != s->height || + pix->bytesperline != s->stride)) + return -EBUSY; + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + s->bpp = COBALT_BYTES_PER_PIXEL_YUYV; + code = MEDIA_BUS_FMT_UYVY8_1X16; + break; + case V4L2_PIX_FMT_BGR32: + s->bpp = COBALT_BYTES_PER_PIXEL_RGB32; + code = MEDIA_BUS_FMT_RGB888_1X24; + break; + default: + return -EINVAL; + } + s->width = pix->width; + s->height = pix->height; + s->stride = pix->bytesperline; + s->pixfmt = pix->pixelformat; + s->colorspace = pix->colorspace; + s->xfer_func = pix->xfer_func; + s->ycbcr_enc = pix->ycbcr_enc; + s->quantization = pix->quantization; + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + v4l2_fill_mbus_format(&sd_fmt.format, pix, code); + v4l2_subdev_call(s->sd, pad, set_fmt, NULL, &sd_fmt); + return 0; +} + +static int cobalt_enum_input(struct file *file, void *priv_fh, + struct v4l2_input *inp) +{ + struct cobalt_stream *s = video_drvdata(file); + + if (inp->index > 1) + return -EINVAL; + if (inp->index == 0) + snprintf(inp->name, sizeof(inp->name), + "HDMI-%d", s->video_channel); + else + snprintf(inp->name, sizeof(inp->name), + "Generator-%d", s->video_channel); + inp->type = V4L2_INPUT_TYPE_CAMERA; + inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; + if (inp->index == 1) + return 0; + return v4l2_subdev_call(s->sd, + video, g_input_status, &inp->status); +} + +static int cobalt_g_input(struct file *file, void *priv_fh, unsigned int *i) +{ + struct cobalt_stream *s = video_drvdata(file); + + *i = s->input; + return 0; +} + +static int cobalt_s_input(struct file *file, void *priv_fh, unsigned int i) +{ + struct cobalt_stream *s = video_drvdata(file); + + if (i >= 2) + return -EINVAL; + if (vb2_is_busy(&s->q)) + return -EBUSY; + s->input = i; + + cobalt_enable_input(s); + + if (s->input == 1) /* Test Pattern Generator */ + return 0; + + return v4l2_subdev_call(s->sd, video, s_routing, + ADV76XX_PAD_HDMI_PORT_A, 0, 0); +} + +static int cobalt_enum_output(struct file *file, void *priv_fh, + struct v4l2_output *out) +{ + if (out->index) + return -EINVAL; + snprintf(out->name, sizeof(out->name), "HDMI-%d", out->index); + out->type = V4L2_OUTPUT_TYPE_ANALOG; + out->capabilities = V4L2_OUT_CAP_DV_TIMINGS; + return 0; +} + +static int cobalt_g_output(struct file *file, void *priv_fh, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int cobalt_s_output(struct file *file, void *priv_fh, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int cobalt_g_edid(struct file *file, void *fh, struct v4l2_edid *edid) +{ + struct cobalt_stream *s = video_drvdata(file); + u32 pad = edid->pad; + int ret; + + if (edid->pad >= (s->is_output ? 1 : 2)) + return -EINVAL; + edid->pad = 0; + ret = v4l2_subdev_call(s->sd, pad, get_edid, edid); + edid->pad = pad; + return ret; +} + +static int cobalt_s_edid(struct file *file, void *fh, struct v4l2_edid *edid) +{ + struct cobalt_stream *s = video_drvdata(file); + u32 pad = edid->pad; + int ret; + + if (edid->pad >= 2) + return -EINVAL; + edid->pad = 0; + ret = v4l2_subdev_call(s->sd, pad, set_edid, edid); + edid->pad = pad; + return ret; +} + +static int cobalt_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_event_subscribe(fh, sub, 4, NULL); + } + return v4l2_ctrl_subscribe_event(fh, sub); +} + +static int cobalt_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + a->parm.capture.timeperframe.numerator = 1; + a->parm.capture.timeperframe.denominator = 60; + a->parm.capture.readbuffers = 3; + return 0; +} + +static const struct v4l2_ioctl_ops cobalt_ioctl_ops = { + .vidioc_querycap = cobalt_querycap, + .vidioc_g_parm = cobalt_g_parm, + .vidioc_log_status = cobalt_log_status, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_enum_input = cobalt_enum_input, + .vidioc_g_input = cobalt_g_input, + .vidioc_s_input = cobalt_s_input, + .vidioc_enum_fmt_vid_cap = cobalt_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = cobalt_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = cobalt_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = cobalt_try_fmt_vid_cap, + .vidioc_enum_output = cobalt_enum_output, + .vidioc_g_output = cobalt_g_output, + .vidioc_s_output = cobalt_s_output, + .vidioc_enum_fmt_vid_out = cobalt_enum_fmt_vid_out, + .vidioc_g_fmt_vid_out = cobalt_g_fmt_vid_out, + .vidioc_s_fmt_vid_out = cobalt_s_fmt_vid_out, + .vidioc_try_fmt_vid_out = cobalt_try_fmt_vid_out, + .vidioc_s_dv_timings = cobalt_s_dv_timings, + .vidioc_g_dv_timings = cobalt_g_dv_timings, + .vidioc_query_dv_timings = cobalt_query_dv_timings, + .vidioc_enum_dv_timings = cobalt_enum_dv_timings, + .vidioc_dv_timings_cap = cobalt_dv_timings_cap, + .vidioc_g_edid = cobalt_g_edid, + .vidioc_s_edid = cobalt_s_edid, + .vidioc_subscribe_event = cobalt_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = cobalt_g_register, + .vidioc_s_register = cobalt_s_register, +#endif +}; + +static const struct v4l2_ioctl_ops cobalt_ioctl_empty_ops = { +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = cobalt_g_register, + .vidioc_s_register = cobalt_s_register, +#endif +}; + +/* Register device nodes */ + +static const struct v4l2_file_operations cobalt_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .unlocked_ioctl = video_ioctl2, + .release = vb2_fop_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .read = vb2_fop_read, +}; + +static const struct v4l2_file_operations cobalt_out_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .unlocked_ioctl = video_ioctl2, + .release = vb2_fop_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .write = vb2_fop_write, +}; + +static const struct v4l2_file_operations cobalt_empty_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .unlocked_ioctl = video_ioctl2, + .release = v4l2_fh_release, +}; + +static int cobalt_node_register(struct cobalt *cobalt, int node) +{ + static const struct v4l2_dv_timings dv1080p60 = + V4L2_DV_BT_CEA_1920X1080P60; + struct cobalt_stream *s = cobalt->streams + node; + struct video_device *vdev = &s->vdev; + struct vb2_queue *q = &s->q; + int ret; + + mutex_init(&s->lock); + spin_lock_init(&s->irqlock); + + snprintf(vdev->name, sizeof(vdev->name), + "%s-%d", cobalt->v4l2_dev.name, node); + s->width = 1920; + /* Audio frames are just 4 lines of 1920 bytes */ + s->height = s->is_audio ? 4 : 1080; + + if (s->is_audio) { + s->bpp = 1; + s->pixfmt = V4L2_PIX_FMT_GREY; + } else if (s->is_output) { + s->bpp = COBALT_BYTES_PER_PIXEL_RGB32; + s->pixfmt = V4L2_PIX_FMT_BGR32; + } else { + s->bpp = COBALT_BYTES_PER_PIXEL_YUYV; + s->pixfmt = V4L2_PIX_FMT_YUYV; + } + s->colorspace = V4L2_COLORSPACE_SRGB; + s->stride = s->width * s->bpp; + + if (!s->is_audio) { + if (s->is_dummy) + cobalt_warn("Setting up dummy video node %d\n", node); + vdev->v4l2_dev = &cobalt->v4l2_dev; + if (s->is_dummy) + vdev->fops = &cobalt_empty_fops; + else + vdev->fops = s->is_output ? &cobalt_out_fops : + &cobalt_fops; + vdev->release = video_device_release_empty; + vdev->vfl_dir = s->is_output ? VFL_DIR_TX : VFL_DIR_RX; + vdev->lock = &s->lock; + if (s->sd) + vdev->ctrl_handler = s->sd->ctrl_handler; + s->timings = dv1080p60; + v4l2_subdev_call(s->sd, video, s_dv_timings, &s->timings); + if (!s->is_output && s->sd) + cobalt_enable_input(s); + vdev->ioctl_ops = s->is_dummy ? &cobalt_ioctl_empty_ops : + &cobalt_ioctl_ops; + } + + INIT_LIST_HEAD(&s->bufs); + q->type = s->is_output ? V4L2_BUF_TYPE_VIDEO_OUTPUT : + V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + q->io_modes |= s->is_output ? VB2_WRITE : VB2_READ; + q->drv_priv = s; + q->buf_struct_size = sizeof(struct cobalt_buffer); + q->ops = &cobalt_qops; + q->mem_ops = &vb2_dma_sg_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 2; + q->lock = &s->lock; + vdev->queue = q; + + video_set_drvdata(vdev, s); + ret = vb2_queue_init(q); + if (!s->is_audio && ret == 0) + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + else if (!s->is_dummy) + ret = cobalt_alsa_init(s); + + if (ret < 0) { + if (!s->is_audio) + cobalt_err("couldn't register v4l2 device node %d\n", + node); + return ret; + } + cobalt_info("registered node %d\n", node); + return 0; +} + +/* Initialize v4l2 variables and register v4l2 devices */ +int cobalt_nodes_register(struct cobalt *cobalt) +{ + int node, ret; + + /* Setup V4L2 Devices */ + for (node = 0; node < COBALT_NUM_STREAMS; node++) { + ret = cobalt_node_register(cobalt, node); + if (ret) + return ret; + } + return 0; +} + +/* Unregister v4l2 devices */ +void cobalt_nodes_unregister(struct cobalt *cobalt) +{ + int node; + + /* Teardown all streams */ + for (node = 0; node < COBALT_NUM_STREAMS; node++) { + struct cobalt_stream *s = cobalt->streams + node; + struct video_device *vdev = &s->vdev; + + if (!s->is_audio) + video_unregister_device(vdev); + else if (!s->is_dummy) + cobalt_alsa_exit(s); + } +} diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.h b/drivers/media/pci/cobalt/cobalt-v4l2.h new file mode 100644 index 0000000..62be553 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-v4l2.h @@ -0,0 +1,22 @@ +/* + * cobalt V4L2 API + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +int cobalt_nodes_register(struct cobalt *cobalt); +void cobalt_nodes_unregister(struct cobalt *cobalt); diff --git a/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h b/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h new file mode 100644 index 0000000..9bc9ef1 --- /dev/null +++ b/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h @@ -0,0 +1,115 @@ +/* + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef M00233_VIDEO_MEASURE_MEMMAP_PACKAGE_H +#define M00233_VIDEO_MEASURE_MEMMAP_PACKAGE_H + +/******************************************************************* + * Register Block + * M00233_VIDEO_MEASURE_MEMMAP_PACKAGE_VHD_REGMAP + *******************************************************************/ +struct m00233_video_measure_regmap { + uint32_t irq_status; /* Reg 0x0000 */ + /* The vertical counter starts on rising edge of vsync */ + uint32_t vsync_time; /* Reg 0x0004 */ + uint32_t vback_porch; /* Reg 0x0008 */ + uint32_t vactive_area; /* Reg 0x000c */ + uint32_t vfront_porch; /* Reg 0x0010 */ + /* The horizontal counter starts on rising edge of hsync. */ + uint32_t hsync_time; /* Reg 0x0014 */ + uint32_t hback_porch; /* Reg 0x0018 */ + uint32_t hactive_area; /* Reg 0x001c */ + uint32_t hfront_porch; /* Reg 0x0020 */ + uint32_t control; /* Reg 0x0024, Default=0x0 */ + uint32_t irq_triggers; /* Reg 0x0028, Default=0xff */ + /* Value is given in number of register bus clock periods between */ + /* falling and rising edge of hsync. Must be non-zero. */ + uint32_t hsync_timeout_val; /* Reg 0x002c, Default=0x1fff */ + uint32_t status; /* Reg 0x0030 */ +}; + +#define M00233_VIDEO_MEASURE_REG_IRQ_STATUS_OFST 0 +#define M00233_VIDEO_MEASURE_REG_VSYNC_TIME_OFST 4 +#define M00233_VIDEO_MEASURE_REG_VBACK_PORCH_OFST 8 +#define M00233_VIDEO_MEASURE_REG_VACTIVE_AREA_OFST 12 +#define M00233_VIDEO_MEASURE_REG_VFRONT_PORCH_OFST 16 +#define M00233_VIDEO_MEASURE_REG_HSYNC_TIME_OFST 20 +#define M00233_VIDEO_MEASURE_REG_HBACK_PORCH_OFST 24 +#define M00233_VIDEO_MEASURE_REG_HACTIVE_AREA_OFST 28 +#define M00233_VIDEO_MEASURE_REG_HFRONT_PORCH_OFST 32 +#define M00233_VIDEO_MEASURE_REG_CONTROL_OFST 36 +#define M00233_VIDEO_MEASURE_REG_IRQ_TRIGGERS_OFST 40 +#define M00233_VIDEO_MEASURE_REG_HSYNC_TIMEOUT_VAL_OFST 44 +#define M00233_VIDEO_MEASURE_REG_STATUS_OFST 48 + +/******************************************************************* + * Bit Mask for register + * M00233_VIDEO_MEASURE_MEMMAP_PACKAGE_VHD_BITMAP + *******************************************************************/ +/* irq_status [7:0] */ +#define M00233_IRQ_STATUS_BITMAP_VSYNC_TIME_OFST (0) +#define M00233_IRQ_STATUS_BITMAP_VSYNC_TIME_MSK (0x1 << M00233_IRQ_STATUS_BITMAP_VSYNC_TIME_OFST) +#define M00233_IRQ_STATUS_BITMAP_VBACK_PORCH_OFST (1) +#define M00233_IRQ_STATUS_BITMAP_VBACK_PORCH_MSK (0x1 << M00233_IRQ_STATUS_BITMAP_VBACK_PORCH_OFST) +#define M00233_IRQ_STATUS_BITMAP_VACTIVE_AREA_OFST (2) +#define M00233_IRQ_STATUS_BITMAP_VACTIVE_AREA_MSK (0x1 << M00233_IRQ_STATUS_BITMAP_VACTIVE_AREA_OFST) +#define M00233_IRQ_STATUS_BITMAP_VFRONT_PORCH_OFST (3) +#define M00233_IRQ_STATUS_BITMAP_VFRONT_PORCH_MSK (0x1 << M00233_IRQ_STATUS_BITMAP_VFRONT_PORCH_OFST) +#define M00233_IRQ_STATUS_BITMAP_HSYNC_TIME_OFST (4) +#define M00233_IRQ_STATUS_BITMAP_HSYNC_TIME_MSK (0x1 << M00233_IRQ_STATUS_BITMAP_HSYNC_TIME_OFST) +#define M00233_IRQ_STATUS_BITMAP_HBACK_PORCH_OFST (5) +#define M00233_IRQ_STATUS_BITMAP_HBACK_PORCH_MSK (0x1 << M00233_IRQ_STATUS_BITMAP_HBACK_PORCH_OFST) +#define M00233_IRQ_STATUS_BITMAP_HACTIVE_AREA_OFST (6) +#define M00233_IRQ_STATUS_BITMAP_HACTIVE_AREA_MSK (0x1 << M00233_IRQ_STATUS_BITMAP_HACTIVE_AREA_OFST) +#define M00233_IRQ_STATUS_BITMAP_HFRONT_PORCH_OFST (7) +#define M00233_IRQ_STATUS_BITMAP_HFRONT_PORCH_MSK (0x1 << M00233_IRQ_STATUS_BITMAP_HFRONT_PORCH_OFST) +/* control [4:0] */ +#define M00233_CONTROL_BITMAP_HSYNC_POLARITY_LOW_OFST (0) +#define M00233_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK (0x1 << M00233_CONTROL_BITMAP_HSYNC_POLARITY_LOW_OFST) +#define M00233_CONTROL_BITMAP_VSYNC_POLARITY_LOW_OFST (1) +#define M00233_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK (0x1 << M00233_CONTROL_BITMAP_VSYNC_POLARITY_LOW_OFST) +#define M00233_CONTROL_BITMAP_ENABLE_MEASURE_OFST (2) +#define M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK (0x1 << M00233_CONTROL_BITMAP_ENABLE_MEASURE_OFST) +#define M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_OFST (3) +#define M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_MSK (0x1 << M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_OFST) +#define M00233_CONTROL_BITMAP_UPDATE_ON_HSYNC_OFST (4) +#define M00233_CONTROL_BITMAP_UPDATE_ON_HSYNC_MSK (0x1 << M00233_CONTROL_BITMAP_UPDATE_ON_HSYNC_OFST) +/* irq_triggers [7:0] */ +#define M00233_IRQ_TRIGGERS_BITMAP_VSYNC_TIME_OFST (0) +#define M00233_IRQ_TRIGGERS_BITMAP_VSYNC_TIME_MSK (0x1 << M00233_IRQ_TRIGGERS_BITMAP_VSYNC_TIME_OFST) +#define M00233_IRQ_TRIGGERS_BITMAP_VBACK_PORCH_OFST (1) +#define M00233_IRQ_TRIGGERS_BITMAP_VBACK_PORCH_MSK (0x1 << M00233_IRQ_TRIGGERS_BITMAP_VBACK_PORCH_OFST) +#define M00233_IRQ_TRIGGERS_BITMAP_VACTIVE_AREA_OFST (2) +#define M00233_IRQ_TRIGGERS_BITMAP_VACTIVE_AREA_MSK (0x1 << M00233_IRQ_TRIGGERS_BITMAP_VACTIVE_AREA_OFST) +#define M00233_IRQ_TRIGGERS_BITMAP_VFRONT_PORCH_OFST (3) +#define M00233_IRQ_TRIGGERS_BITMAP_VFRONT_PORCH_MSK (0x1 << M00233_IRQ_TRIGGERS_BITMAP_VFRONT_PORCH_OFST) +#define M00233_IRQ_TRIGGERS_BITMAP_HSYNC_TIME_OFST (4) +#define M00233_IRQ_TRIGGERS_BITMAP_HSYNC_TIME_MSK (0x1 << M00233_IRQ_TRIGGERS_BITMAP_HSYNC_TIME_OFST) +#define M00233_IRQ_TRIGGERS_BITMAP_HBACK_PORCH_OFST (5) +#define M00233_IRQ_TRIGGERS_BITMAP_HBACK_PORCH_MSK (0x1 << M00233_IRQ_TRIGGERS_BITMAP_HBACK_PORCH_OFST) +#define M00233_IRQ_TRIGGERS_BITMAP_HACTIVE_AREA_OFST (6) +#define M00233_IRQ_TRIGGERS_BITMAP_HACTIVE_AREA_MSK (0x1 << M00233_IRQ_TRIGGERS_BITMAP_HACTIVE_AREA_OFST) +#define M00233_IRQ_TRIGGERS_BITMAP_HFRONT_PORCH_OFST (7) +#define M00233_IRQ_TRIGGERS_BITMAP_HFRONT_PORCH_MSK (0x1 << M00233_IRQ_TRIGGERS_BITMAP_HFRONT_PORCH_OFST) +/* status [1:0] */ +#define M00233_STATUS_BITMAP_HSYNC_TIMEOUT_OFST (0) +#define M00233_STATUS_BITMAP_HSYNC_TIMEOUT_MSK (0x1 << M00233_STATUS_BITMAP_HSYNC_TIMEOUT_OFST) +#define M00233_STATUS_BITMAP_INIT_DONE_OFST (1) +#define M00233_STATUS_BITMAP_INIT_DONE_MSK (0x1 << M00233_STATUS_BITMAP_INIT_DONE_OFST) + +#endif /*M00233_VIDEO_MEASURE_MEMMAP_PACKAGE_H*/ diff --git a/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h b/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h new file mode 100644 index 0000000..a480529 --- /dev/null +++ b/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h @@ -0,0 +1,44 @@ +/* + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef M00235_FDMA_PACKER_MEMMAP_PACKAGE_H +#define M00235_FDMA_PACKER_MEMMAP_PACKAGE_H + +/******************************************************************* + * Register Block + * M00235_FDMA_PACKER_MEMMAP_PACKAGE_VHD_REGMAP + *******************************************************************/ +struct m00235_fdma_packer_regmap { + uint32_t control; /* Reg 0x0000, Default=0x0 */ +}; + +#define M00235_FDMA_PACKER_REG_CONTROL_OFST 0 + +/******************************************************************* + * Bit Mask for register + * M00235_FDMA_PACKER_MEMMAP_PACKAGE_VHD_BITMAP + *******************************************************************/ +/* control [3:0] */ +#define M00235_CONTROL_BITMAP_ENABLE_OFST (0) +#define M00235_CONTROL_BITMAP_ENABLE_MSK (0x1 << M00235_CONTROL_BITMAP_ENABLE_OFST) +#define M00235_CONTROL_BITMAP_PACK_FORMAT_OFST (1) +#define M00235_CONTROL_BITMAP_PACK_FORMAT_MSK (0x3 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST) +#define M00235_CONTROL_BITMAP_ENDIAN_FORMAT_OFST (3) +#define M00235_CONTROL_BITMAP_ENDIAN_FORMAT_MSK (0x1 << M00235_CONTROL_BITMAP_ENDIAN_FORMAT_OFST) + +#endif /*M00235_FDMA_PACKER_MEMMAP_PACKAGE_H*/ diff --git a/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h b/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h new file mode 100644 index 0000000..602419e5 --- /dev/null +++ b/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h @@ -0,0 +1,59 @@ +/* + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef M00389_CVI_MEMMAP_PACKAGE_H +#define M00389_CVI_MEMMAP_PACKAGE_H + +/******************************************************************* + * Register Block + * M00389_CVI_MEMMAP_PACKAGE_VHD_REGMAP + *******************************************************************/ +struct m00389_cvi_regmap { + uint32_t control; /* Reg 0x0000, Default=0x0 */ + uint32_t frame_width; /* Reg 0x0004, Default=0x10 */ + uint32_t frame_height; /* Reg 0x0008, Default=0xc */ + uint32_t freewheel_period; /* Reg 0x000c, Default=0x0 */ + uint32_t error_color; /* Reg 0x0010, Default=0x0 */ + uint32_t status; /* Reg 0x0014 */ +}; + +#define M00389_CVI_REG_CONTROL_OFST 0 +#define M00389_CVI_REG_FRAME_WIDTH_OFST 4 +#define M00389_CVI_REG_FRAME_HEIGHT_OFST 8 +#define M00389_CVI_REG_FREEWHEEL_PERIOD_OFST 12 +#define M00389_CVI_REG_ERROR_COLOR_OFST 16 +#define M00389_CVI_REG_STATUS_OFST 20 + +/******************************************************************* + * Bit Mask for register + * M00389_CVI_MEMMAP_PACKAGE_VHD_BITMAP + *******************************************************************/ +/* control [2:0] */ +#define M00389_CONTROL_BITMAP_ENABLE_OFST (0) +#define M00389_CONTROL_BITMAP_ENABLE_MSK (0x1 << M00389_CONTROL_BITMAP_ENABLE_OFST) +#define M00389_CONTROL_BITMAP_HSYNC_POLARITY_LOW_OFST (1) +#define M00389_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK (0x1 << M00389_CONTROL_BITMAP_HSYNC_POLARITY_LOW_OFST) +#define M00389_CONTROL_BITMAP_VSYNC_POLARITY_LOW_OFST (2) +#define M00389_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK (0x1 << M00389_CONTROL_BITMAP_VSYNC_POLARITY_LOW_OFST) +/* status [1:0] */ +#define M00389_STATUS_BITMAP_LOCK_OFST (0) +#define M00389_STATUS_BITMAP_LOCK_MSK (0x1 << M00389_STATUS_BITMAP_LOCK_OFST) +#define M00389_STATUS_BITMAP_ERROR_OFST (1) +#define M00389_STATUS_BITMAP_ERROR_MSK (0x1 << M00389_STATUS_BITMAP_ERROR_OFST) + +#endif /*M00389_CVI_MEMMAP_PACKAGE_H*/ diff --git a/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h b/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h new file mode 100644 index 0000000..95471c9 --- /dev/null +++ b/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h @@ -0,0 +1,44 @@ +/* + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef M00460_EVCNT_MEMMAP_PACKAGE_H +#define M00460_EVCNT_MEMMAP_PACKAGE_H + +/******************************************************************* + * Register Block + * M00460_EVCNT_MEMMAP_PACKAGE_VHD_REGMAP + *******************************************************************/ +struct m00460_evcnt_regmap { + uint32_t control; /* Reg 0x0000, Default=0x0 */ + uint32_t count; /* Reg 0x0004 */ +}; + +#define M00460_EVCNT_REG_CONTROL_OFST 0 +#define M00460_EVCNT_REG_COUNT_OFST 4 + +/******************************************************************* + * Bit Mask for register + * M00460_EVCNT_MEMMAP_PACKAGE_VHD_BITMAP + *******************************************************************/ +/* control [1:0] */ +#define M00460_CONTROL_BITMAP_ENABLE_OFST (0) +#define M00460_CONTROL_BITMAP_ENABLE_MSK (0x1 << M00460_CONTROL_BITMAP_ENABLE_OFST) +#define M00460_CONTROL_BITMAP_CLEAR_OFST (1) +#define M00460_CONTROL_BITMAP_CLEAR_MSK (0x1 << M00460_CONTROL_BITMAP_CLEAR_OFST) + +#endif /*M00460_EVCNT_MEMMAP_PACKAGE_H*/ diff --git a/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h b/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h new file mode 100644 index 0000000..384a3e1 --- /dev/null +++ b/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h @@ -0,0 +1,57 @@ +/* + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef M00473_FREEWHEEL_MEMMAP_PACKAGE_H +#define M00473_FREEWHEEL_MEMMAP_PACKAGE_H + +/******************************************************************* + * Register Block + * M00473_FREEWHEEL_MEMMAP_PACKAGE_VHD_REGMAP + *******************************************************************/ +struct m00473_freewheel_regmap { + uint32_t ctrl; /* Reg 0x0000, Default=0x0 */ + uint32_t status; /* Reg 0x0004 */ + uint32_t active_length; /* Reg 0x0008, Default=0x1fa400 */ + uint32_t total_length; /* Reg 0x000c, Default=0x31151b */ + uint32_t data_width; /* Reg 0x0010 */ + uint32_t output_color; /* Reg 0x0014, Default=0xffff */ + uint32_t clk_freq; /* Reg 0x0018 */ +}; + +#define M00473_FREEWHEEL_REG_CTRL_OFST 0 +#define M00473_FREEWHEEL_REG_STATUS_OFST 4 +#define M00473_FREEWHEEL_REG_ACTIVE_LENGTH_OFST 8 +#define M00473_FREEWHEEL_REG_TOTAL_LENGTH_OFST 12 +#define M00473_FREEWHEEL_REG_DATA_WIDTH_OFST 16 +#define M00473_FREEWHEEL_REG_OUTPUT_COLOR_OFST 20 +#define M00473_FREEWHEEL_REG_CLK_FREQ_OFST 24 + +/******************************************************************* + * Bit Mask for register + * M00473_FREEWHEEL_MEMMAP_PACKAGE_VHD_BITMAP + *******************************************************************/ +/* ctrl [1:0] */ +#define M00473_CTRL_BITMAP_ENABLE_OFST (0) +#define M00473_CTRL_BITMAP_ENABLE_MSK (0x1 << M00473_CTRL_BITMAP_ENABLE_OFST) +#define M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_OFST (1) +#define M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK (0x1 << M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_OFST) +/* status [0:0] */ +#define M00473_STATUS_BITMAP_FREEWHEEL_MODE_OFST (0) +#define M00473_STATUS_BITMAP_FREEWHEEL_MODE_MSK (0x1 << M00473_STATUS_BITMAP_FREEWHEEL_MODE_OFST) + +#endif /*M00473_FREEWHEEL_MEMMAP_PACKAGE_H*/ diff --git a/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h b/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h new file mode 100644 index 0000000..2a02902 --- /dev/null +++ b/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h @@ -0,0 +1,53 @@ +/* + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef M00479_CLK_LOSS_DETECTOR_MEMMAP_PACKAGE_H +#define M00479_CLK_LOSS_DETECTOR_MEMMAP_PACKAGE_H + +/******************************************************************* + * Register Block + * M00479_CLK_LOSS_DETECTOR_MEMMAP_PACKAGE_VHD_REGMAP + *******************************************************************/ +struct m00479_clk_loss_detector_regmap { + /* Control module */ + uint32_t ctrl; /* Reg 0x0000, Default=0x0 */ + uint32_t status; /* Reg 0x0004 */ + /* Number of ref clk cycles before checking the clock under test */ + uint32_t ref_clk_cnt_val; /* Reg 0x0008, Default=0xc4 */ + /* Number of test clk cycles required in the ref_clk_cnt_val period + * to ensure that the test clock is performing as expected */ + uint32_t test_clk_cnt_val; /* Reg 0x000c, Default=0xa */ +}; + +#define M00479_CLK_LOSS_DETECTOR_REG_CTRL_OFST 0 +#define M00479_CLK_LOSS_DETECTOR_REG_STATUS_OFST 4 +#define M00479_CLK_LOSS_DETECTOR_REG_REF_CLK_CNT_VAL_OFST 8 +#define M00479_CLK_LOSS_DETECTOR_REG_TEST_CLK_CNT_VAL_OFST 12 + +/******************************************************************* + * Bit Mask for register + * M00479_CLK_LOSS_DETECTOR_MEMMAP_PACKAGE_VHD_BITMAP + *******************************************************************/ +/* ctrl [0:0] */ +#define M00479_CTRL_BITMAP_ENABLE_OFST (0) +#define M00479_CTRL_BITMAP_ENABLE_MSK (0x1 << M00479_CTRL_BITMAP_ENABLE_OFST) +/* status [0:0] */ +#define M00479_STATUS_BITMAP_CLOCK_MISSING_OFST (0) +#define M00479_STATUS_BITMAP_CLOCK_MISSING_MSK (0x1 << M00479_STATUS_BITMAP_CLOCK_MISSING_OFST) + +#endif /*M00479_CLK_LOSS_DETECTOR_MEMMAP_PACKAGE_H*/ diff --git a/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h b/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h new file mode 100644 index 0000000..bdef2df --- /dev/null +++ b/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h @@ -0,0 +1,88 @@ +/* + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef M00514_SYNCGEN_FLOW_EVCNT_MEMMAP_PACKAGE_H +#define M00514_SYNCGEN_FLOW_EVCNT_MEMMAP_PACKAGE_H + +/******************************************************************* + * Register Block + * M00514_SYNCGEN_FLOW_EVCNT_MEMMAP_PACKAGE_VHD_REGMAP + *******************************************************************/ +struct m00514_syncgen_flow_evcnt_regmap { + uint32_t control; /* Reg 0x0000, Default=0x0 */ + uint32_t sync_generator_h_sync_length; /* Reg 0x0004, Default=0x0 */ + uint32_t sync_generator_h_backporch_length; /* Reg 0x0008, Default=0x0 */ + uint32_t sync_generator_h_active_length; /* Reg 0x000c, Default=0x0 */ + uint32_t sync_generator_h_frontporch_length; /* Reg 0x0010, Default=0x0 */ + uint32_t sync_generator_v_sync_length; /* Reg 0x0014, Default=0x0 */ + uint32_t sync_generator_v_backporch_length; /* Reg 0x0018, Default=0x0 */ + uint32_t sync_generator_v_active_length; /* Reg 0x001c, Default=0x0 */ + uint32_t sync_generator_v_frontporch_length; /* Reg 0x0020, Default=0x0 */ + uint32_t error_color; /* Reg 0x0024, Default=0x0 */ + uint32_t rd_status; /* Reg 0x0028 */ + uint32_t rd_evcnt_count; /* Reg 0x002c */ +}; + +#define M00514_SYNCGEN_FLOW_EVCNT_REG_CONTROL_OFST 0 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_SYNC_GENERATOR_H_SYNC_LENGTH_OFST 4 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_SYNC_GENERATOR_H_BACKPORCH_LENGTH_OFST 8 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_SYNC_GENERATOR_H_ACTIVE_LENGTH_OFST 12 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_SYNC_GENERATOR_H_FRONTPORCH_LENGTH_OFST 16 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_SYNC_GENERATOR_V_SYNC_LENGTH_OFST 20 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_SYNC_GENERATOR_V_BACKPORCH_LENGTH_OFST 24 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_SYNC_GENERATOR_V_ACTIVE_LENGTH_OFST 28 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_SYNC_GENERATOR_V_FRONTPORCH_LENGTH_OFST 32 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_ERROR_COLOR_OFST 36 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_RD_STATUS_OFST 40 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_RD_EVCNT_COUNT_OFST 44 + +/******************************************************************* + * Bit Mask for register + * M00514_SYNCGEN_FLOW_EVCNT_MEMMAP_PACKAGE_VHD_BITMAP + *******************************************************************/ +/* control [7:0] */ +#define M00514_CONTROL_BITMAP_SYNC_GENERATOR_LOAD_PARAM_OFST (0) +#define M00514_CONTROL_BITMAP_SYNC_GENERATOR_LOAD_PARAM_MSK (0x1 << M00514_CONTROL_BITMAP_SYNC_GENERATOR_LOAD_PARAM_OFST) +#define M00514_CONTROL_BITMAP_SYNC_GENERATOR_ENABLE_OFST (1) +#define M00514_CONTROL_BITMAP_SYNC_GENERATOR_ENABLE_MSK (0x1 << M00514_CONTROL_BITMAP_SYNC_GENERATOR_ENABLE_OFST) +#define M00514_CONTROL_BITMAP_FLOW_CTRL_OUTPUT_ENABLE_OFST (2) +#define M00514_CONTROL_BITMAP_FLOW_CTRL_OUTPUT_ENABLE_MSK (0x1 << M00514_CONTROL_BITMAP_FLOW_CTRL_OUTPUT_ENABLE_OFST) +#define M00514_CONTROL_BITMAP_HSYNC_POLARITY_LOW_OFST (3) +#define M00514_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK (0x1 << M00514_CONTROL_BITMAP_HSYNC_POLARITY_LOW_OFST) +#define M00514_CONTROL_BITMAP_VSYNC_POLARITY_LOW_OFST (4) +#define M00514_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK (0x1 << M00514_CONTROL_BITMAP_VSYNC_POLARITY_LOW_OFST) +#define M00514_CONTROL_BITMAP_EVCNT_ENABLE_OFST (5) +#define M00514_CONTROL_BITMAP_EVCNT_ENABLE_MSK (0x1 << M00514_CONTROL_BITMAP_EVCNT_ENABLE_OFST) +#define M00514_CONTROL_BITMAP_EVCNT_CLEAR_OFST (6) +#define M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK (0x1 << M00514_CONTROL_BITMAP_EVCNT_CLEAR_OFST) +#define M00514_CONTROL_BITMAP_FORMAT_16_BPP_OFST (7) +#define M00514_CONTROL_BITMAP_FORMAT_16_BPP_MSK (0x1 << M00514_CONTROL_BITMAP_FORMAT_16_BPP_OFST) +/* error_color [23:0] */ +#define M00514_ERROR_COLOR_BITMAP_BLUE_OFST (0) +#define M00514_ERROR_COLOR_BITMAP_BLUE_MSK (0xff << M00514_ERROR_COLOR_BITMAP_BLUE_OFST) +#define M00514_ERROR_COLOR_BITMAP_GREEN_OFST (8) +#define M00514_ERROR_COLOR_BITMAP_GREEN_MSK (0xff << M00514_ERROR_COLOR_BITMAP_GREEN_OFST) +#define M00514_ERROR_COLOR_BITMAP_RED_OFST (16) +#define M00514_ERROR_COLOR_BITMAP_RED_MSK (0xff << M00514_ERROR_COLOR_BITMAP_RED_OFST) +/* rd_status [1:0] */ +#define M00514_RD_STATUS_BITMAP_FLOW_CTRL_NO_DATA_ERROR_OFST (0) +#define M00514_RD_STATUS_BITMAP_FLOW_CTRL_NO_DATA_ERROR_MSK (0x1 << M00514_RD_STATUS_BITMAP_FLOW_CTRL_NO_DATA_ERROR_OFST) +#define M00514_RD_STATUS_BITMAP_READY_BUFFER_FULL_OFST (1) +#define M00514_RD_STATUS_BITMAP_READY_BUFFER_FULL_MSK (0x1 << M00514_RD_STATUS_BITMAP_READY_BUFFER_FULL_OFST) + +#endif /*M00514_SYNCGEN_FLOW_EVCNT_MEMMAP_PACKAGE_H*/ diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c index 5a55630..30bbe8d 100644 --- a/drivers/media/pci/cx18/cx18-av-core.c +++ b/drivers/media/pci/cx18/cx18-av-core.c @@ -945,14 +945,17 @@ static int cx18_av_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +static int cx18_av_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *fmt = &format->format; struct cx18_av_state *state = to_cx18_av_state(sd); struct cx18 *cx = v4l2_get_subdevdata(sd); int HSC, VSC, Vsrc, Hsrc, filter, Vlines; int is_50Hz = !(state->std & V4L2_STD_525_60); - if (fmt->code != MEDIA_BUS_FMT_FIXED) + if (format->pad || fmt->code != MEDIA_BUS_FMT_FIXED) return -EINVAL; fmt->field = V4L2_FIELD_INTERLACED; @@ -987,6 +990,9 @@ static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt return -ERANGE; } + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + return 0; + HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20); VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); VSC &= 0x1fff; @@ -1285,7 +1291,6 @@ static const struct v4l2_subdev_video_ops cx18_av_video_ops = { .s_std = cx18_av_s_std, .s_routing = cx18_av_s_video_routing, .s_stream = cx18_av_s_stream, - .s_mbus_fmt = cx18_av_s_mbus_fmt, }; static const struct v4l2_subdev_vbi_ops cx18_av_vbi_ops = { @@ -1295,12 +1300,17 @@ static const struct v4l2_subdev_vbi_ops cx18_av_vbi_ops = { .s_raw_fmt = cx18_av_s_raw_fmt, }; +static const struct v4l2_subdev_pad_ops cx18_av_pad_ops = { + .set_fmt = cx18_av_set_fmt, +}; + static const struct v4l2_subdev_ops cx18_av_ops = { .core = &cx18_av_general_ops, .tuner = &cx18_av_tuner_ops, .audio = &cx18_av_audio_ops, .video = &cx18_av_video_ops, .vbi = &cx18_av_vbi_ops, + .pad = &cx18_av_pad_ops, }; int cx18_av_probe(struct cx18 *cx) diff --git a/drivers/media/pci/cx18/cx18-controls.c b/drivers/media/pci/cx18/cx18-controls.c index 4aeb7c6..71227a1 100644 --- a/drivers/media/pci/cx18/cx18-controls.c +++ b/drivers/media/pci/cx18/cx18-controls.c @@ -93,13 +93,16 @@ static int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) { struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_mbus_framefmt fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *fmt = &format.format; /* fix videodecoder resolution */ - fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); - fmt.height = cxhdl->height; - fmt.code = MEDIA_BUS_FMT_FIXED; - v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt); + fmt->width = cxhdl->width / (is_mpeg1 ? 2 : 1); + fmt->height = cxhdl->height; + fmt->code = MEDIA_BUS_FMT_FIXED; + v4l2_subdev_call(cx->sd_av, pad, set_fmt, NULL, &format); return 0; } diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 83f5074..260e462 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -786,11 +786,11 @@ static void cx18_init_struct2(struct cx18 *cx) { int i; - for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS; i++) + for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS - 1; i++) if (cx->card->video_inputs[i].video_type == 0) break; cx->nof_inputs = i; - for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS; i++) + for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS - 1; i++) if (cx->card->audio_inputs[i].audio_type == 0) break; cx->nof_audio_inputs = i; diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 79aee30..55525af 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -267,7 +267,9 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, { struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; struct cx18_stream *s = &cx->streams[id->type]; int ret; int w, h; @@ -296,10 +298,10 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, s->vb_bytes_per_line = 1440; /* Packed */ } - mbus_fmt.width = cx->cxhdl.width = w; - mbus_fmt.height = cx->cxhdl.height = h; - mbus_fmt.code = MEDIA_BUS_FMT_FIXED; - v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt); + format.format.width = cx->cxhdl.width = w; + format.format.height = cx->cxhdl.height = h; + format.format.code = MEDIA_BUS_FMT_FIXED; + v4l2_subdev_call(cx->sd_av, pad, set_fmt, NULL, &format); return cx18_g_fmt_vid_cap(file, fh, fmt); } diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index c82d25d..c986084 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c @@ -90,6 +90,7 @@ static struct { "encoder PCM audio", VFL_TYPE_GRABBER, CX18_V4L2_ENC_PCM_OFFSET, PCI_DMA_FROMDEVICE, + V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, }, { /* CX18_ENC_STREAM_TYPE_IDX */ "encoder IDX", diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c index 0a91df2..aaf4e46 100644 --- a/drivers/media/pci/cx23885/altera-ci.c +++ b/drivers/media/pci/cx23885/altera-ci.c @@ -759,7 +759,7 @@ int altera_ci_init(struct altera_ci_config *config, int ci_nr) if (0 != ret) goto err; - inter->state[ci_nr - 1] = state; + inter->state[ci_nr - 1] = state; altera_hw_filt_init(config, ci_nr); diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 745caab..6e8c24c 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -572,7 +572,8 @@ static struct stb6100_config prof_8000_stb6100_config = { .refclock = 27000000, }; -static int p8000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int p8000_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct cx23885_tsport *port = fe->dvb->priv; struct cx23885_dev *dev = port->dev; @@ -587,7 +588,7 @@ static int p8000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) } static int dvbsky_t9580_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct cx23885_tsport *port = fe->dvb->priv; struct cx23885_dev *dev = port->dev; @@ -616,7 +617,7 @@ static int dvbsky_t9580_set_voltage(struct dvb_frontend *fe, } static int dvbsky_s952_portc_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct cx23885_tsport *port = fe->dvb->priv; struct cx23885_dev *dev = port->dev; @@ -856,18 +857,12 @@ static struct mt2063_config terratec_mt2063_config[] = { }, }; -static const struct tda10071_config hauppauge_tda10071_config = { - .demod_i2c_addr = 0x05, - .tuner_i2c_addr = 0x54, +static const struct tda10071_platform_data hauppauge_tda10071_pdata = { + .clk = 40444000, /* 40.444 MHz */ .i2c_wr_max = 64, .ts_mode = TDA10071_TS_SERIAL, - .spec_inv = 0, - .xtal = 40444000, /* 40.444 MHz */ .pll_multiplier = 20, -}; - -static const struct a8293_config hauppauge_a8293_config = { - .i2c_addr = 0x0b, + .tuner_i2c_addr = 0x54, }; static const struct si2165_config hauppauge_hvr4400_si2165_config = { @@ -1190,8 +1185,10 @@ static int dvb_register(struct cx23885_tsport *port) struct i2c_board_info info; struct i2c_adapter *adapter; struct i2c_client *client_demod = NULL, *client_tuner = NULL; + struct i2c_client *client_sec = NULL; const struct m88ds3103_config *p_m88ds3103_config = NULL; - int (*p_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage) = NULL; + int (*p_set_voltage)(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) = NULL; int mfe_shared = 0; /* bus not shared by default */ int ret; @@ -1797,21 +1794,46 @@ static int dvb_register(struct cx23885_tsport *port) fe0->dvb.frontend->ops.set_voltage = p8000_set_voltage; break; - case CX23885_BOARD_HAUPPAUGE_HVR4400: + case CX23885_BOARD_HAUPPAUGE_HVR4400: { + struct tda10071_platform_data tda10071_pdata = hauppauge_tda10071_pdata; + struct a8293_platform_data a8293_pdata = {}; + i2c_bus = &dev->i2c_bus[0]; i2c_bus2 = &dev->i2c_bus[1]; switch (port->nr) { /* port b */ case 1: - fe0->dvb.frontend = dvb_attach(tda10071_attach, - &hauppauge_tda10071_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend == NULL) - break; - if (!dvb_attach(a8293_attach, fe0->dvb.frontend, - &i2c_bus->i2c_adap, - &hauppauge_a8293_config)) + /* attach demod + tuner combo */ + memset(&info, 0, sizeof(info)); + strlcpy(info.type, "tda10071_cx24118", I2C_NAME_SIZE); + info.addr = 0x05; + info.platform_data = &tda10071_pdata; + request_module("tda10071"); + client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info); + if (!client_demod || !client_demod->dev.driver) + goto frontend_detach; + if (!try_module_get(client_demod->dev.driver->owner)) { + i2c_unregister_device(client_demod); + goto frontend_detach; + } + fe0->dvb.frontend = tda10071_pdata.get_dvb_frontend(client_demod); + port->i2c_client_demod = client_demod; + + /* attach SEC */ + a8293_pdata.dvb_frontend = fe0->dvb.frontend; + memset(&info, 0, sizeof(info)); + strlcpy(info.type, "a8293", I2C_NAME_SIZE); + info.addr = 0x0b; + info.platform_data = &a8293_pdata; + request_module("a8293"); + client_sec = i2c_new_device(&i2c_bus->i2c_adap, &info); + if (!client_sec || !client_sec->dev.driver) + goto frontend_detach; + if (!try_module_get(client_sec->dev.driver->owner)) { + i2c_unregister_device(client_sec); goto frontend_detach; + } + port->i2c_client_sec = client_sec; break; /* port c */ case 2: @@ -1829,17 +1851,46 @@ static int dvb_register(struct cx23885_tsport *port) break; } break; - case CX23885_BOARD_HAUPPAUGE_STARBURST: + } + case CX23885_BOARD_HAUPPAUGE_STARBURST: { + struct tda10071_platform_data tda10071_pdata = hauppauge_tda10071_pdata; + struct a8293_platform_data a8293_pdata = {}; + i2c_bus = &dev->i2c_bus[0]; - fe0->dvb.frontend = dvb_attach(tda10071_attach, - &hauppauge_tda10071_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(a8293_attach, fe0->dvb.frontend, - &i2c_bus->i2c_adap, - &hauppauge_a8293_config); + + /* attach demod + tuner combo */ + memset(&info, 0, sizeof(info)); + strlcpy(info.type, "tda10071_cx24118", I2C_NAME_SIZE); + info.addr = 0x05; + info.platform_data = &tda10071_pdata; + request_module("tda10071"); + client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info); + if (!client_demod || !client_demod->dev.driver) + goto frontend_detach; + if (!try_module_get(client_demod->dev.driver->owner)) { + i2c_unregister_device(client_demod); + goto frontend_detach; } + fe0->dvb.frontend = tda10071_pdata.get_dvb_frontend(client_demod); + port->i2c_client_demod = client_demod; + + /* attach SEC */ + a8293_pdata.dvb_frontend = fe0->dvb.frontend; + memset(&info, 0, sizeof(info)); + strlcpy(info.type, "a8293", I2C_NAME_SIZE); + info.addr = 0x0b; + info.platform_data = &a8293_pdata; + request_module("a8293"); + client_sec = i2c_new_device(&i2c_bus->i2c_adap, &info); + if (!client_sec || !client_sec->dev.driver) + goto frontend_detach; + if (!try_module_get(client_sec->dev.driver->owner)) { + i2c_unregister_device(client_sec); + goto frontend_detach; + } + port->i2c_client_sec = client_sec; break; + } case CX23885_BOARD_DVBSKY_T9580: case CX23885_BOARD_DVBSKY_S950: i2c_bus = &dev->i2c_bus[0]; @@ -1857,6 +1908,7 @@ static int dvb_register(struct cx23885_tsport *port) /* attach tuner */ memset(&ts2020_config, 0, sizeof(ts2020_config)); ts2020_config.fe = fe0->dvb.frontend; + ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "ts2020", I2C_NAME_SIZE); info.addr = 0x60; @@ -1912,6 +1964,7 @@ static int dvb_register(struct cx23885_tsport *port) /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = fe0->dvb.frontend; + si2157_config.if_port = 1; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2157", I2C_NAME_SIZE); info.addr = 0x60; @@ -1957,6 +2010,7 @@ static int dvb_register(struct cx23885_tsport *port) /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = fe0->dvb.frontend; + si2157_config.if_port = 1; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2157", I2C_NAME_SIZE); info.addr = 0x60; @@ -1986,6 +2040,7 @@ static int dvb_register(struct cx23885_tsport *port) /* attach tuner */ memset(&ts2020_config, 0, sizeof(ts2020_config)); ts2020_config.fe = fe0->dvb.frontend; + ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "ts2020", I2C_NAME_SIZE); info.addr = 0x60; @@ -2031,6 +2086,7 @@ static int dvb_register(struct cx23885_tsport *port) /* attach tuner */ memset(&ts2020_config, 0, sizeof(ts2020_config)); ts2020_config.fe = fe0->dvb.frontend; + ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "ts2020", I2C_NAME_SIZE); info.addr = 0x60; @@ -2093,6 +2149,7 @@ static int dvb_register(struct cx23885_tsport *port) /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = fe0->dvb.frontend; + si2157_config.if_port = 1; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2157", I2C_NAME_SIZE); info.addr = 0x60; @@ -2111,6 +2168,7 @@ static int dvb_register(struct cx23885_tsport *port) case CX23885_BOARD_HAUPPAUGE_HVR5525: switch (port->nr) { struct m88rs6000t_config m88rs6000t_config; + struct a8293_platform_data a8293_pdata = {}; /* port b - satellite */ case 1: @@ -2122,10 +2180,20 @@ static int dvb_register(struct cx23885_tsport *port) break; /* attach SEC */ - if (!dvb_attach(a8293_attach, fe0->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, - &hauppauge_a8293_config)) + a8293_pdata.dvb_frontend = fe0->dvb.frontend; + memset(&info, 0, sizeof(info)); + strlcpy(info.type, "a8293", I2C_NAME_SIZE); + info.addr = 0x0b; + info.platform_data = &a8293_pdata; + request_module("a8293"); + client_sec = i2c_new_device(&dev->i2c_bus[0].i2c_adap, &info); + if (!client_sec || !client_sec->dev.driver) + goto frontend_detach; + if (!try_module_get(client_sec->dev.driver->owner)) { + i2c_unregister_device(client_sec); goto frontend_detach; + } + port->i2c_client_sec = client_sec; /* attach tuner */ memset(&m88rs6000t_config, 0, sizeof(m88rs6000t_config)); @@ -2172,6 +2240,7 @@ static int dvb_register(struct cx23885_tsport *port) /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = fe0->dvb.frontend; + si2157_config.if_port = 1; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2157", I2C_NAME_SIZE); info.addr = 0x60; @@ -2238,6 +2307,14 @@ static int dvb_register(struct cx23885_tsport *port) return 0; frontend_detach: + /* remove I2C client for SEC */ + client_sec = port->i2c_client_sec; + if (client_sec) { + module_put(client_sec->dev.driver->owner); + i2c_unregister_device(client_sec); + port->i2c_client_sec = NULL; + } + /* remove I2C client for tuner */ client_tuner = port->i2c_client_tuner; if (client_tuner) { @@ -2339,6 +2416,13 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) i2c_unregister_device(client); } + /* remove I2C client for SEC */ + client = port->i2c_client_sec; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + /* remove I2C client for tuner */ client = port->i2c_client_tuner; if (client) { diff --git a/drivers/media/pci/cx23885/cx23885-f300.c b/drivers/media/pci/cx23885/cx23885-f300.c index 6f817d8..a6c45eb 100644 --- a/drivers/media/pci/cx23885/cx23885-f300.c +++ b/drivers/media/pci/cx23885/cx23885-f300.c @@ -144,7 +144,7 @@ static u8 f300_xfer(struct dvb_frontend *fe, u8 *buf) return ret; } -int f300_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +int f300_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) { u8 buf[16]; diff --git a/drivers/media/pci/cx23885/cx23885-f300.h b/drivers/media/pci/cx23885/cx23885-f300.h index e73344c..be14d7d 100644 --- a/drivers/media/pci/cx23885/cx23885-f300.h +++ b/drivers/media/pci/cx23885/cx23885-f300.h @@ -1,2 +1,2 @@ extern int f300_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage); + enum fe_sec_voltage voltage); diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 2232b38..ec76470 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -581,7 +581,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_dev *dev = video_drvdata(file); - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int err; dprintk(2, "%s()\n", __func__); @@ -600,10 +602,10 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, dev->field = f->fmt.pix.field; dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, dev->width, dev->height, dev->field); - v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); - call_all(dev, video, s_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); - /* s_mbus_fmt overwrites f->fmt.pix.field, restore it */ + v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); + call_all(dev, pad, set_fmt, NULL, &format); + v4l2_fill_pix_format(&f->fmt.pix, &format.format); + /* set_fmt overwrites f->fmt.pix.field, restore it */ f->fmt.pix.field = dev->field; return 0; } diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index aeda8d3..027ead4 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -304,11 +304,12 @@ struct cx23885_tsport { struct i2c_client *i2c_client_demod; struct i2c_client *i2c_client_tuner; + struct i2c_client *i2c_client_sec; struct i2c_client *i2c_client_ci; int (*set_frontend)(struct dvb_frontend *fe); int (*fe_set_voltage)(struct dvb_frontend *fe, - fe_sec_voltage_t voltage); + enum fe_sec_voltage voltage); }; struct cx23885_kernel_ir { diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c index 3501be9..aab7cf4 100644 --- a/drivers/media/pci/cx88/cx88-core.c +++ b/drivers/media/pci/cx88/cx88-core.c @@ -519,6 +519,8 @@ void cx88_wakeup(struct cx88_core *core, buf = list_entry(q->active.next, struct cx88_buffer, list); v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + buf->vb.v4l2_buf.field = core->field; + buf->vb.v4l2_buf.sequence = q->count++; list_del(&buf->list); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); } diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index 1b2ed23..9dfa5ee 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -449,7 +449,7 @@ static int cx24123_set_ts_param(struct dvb_frontend* fe, } static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct cx8802_dev *dev= fe->dvb->priv; struct cx88_core *core = dev->core; @@ -465,7 +465,7 @@ static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, } static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct cx8802_dev *dev= fe->dvb->priv; struct cx88_core *core = dev->core; @@ -481,7 +481,7 @@ static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe, } static int tevii_dvbs_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct cx8802_dev *dev= fe->dvb->priv; struct cx88_core *core = dev->core; @@ -505,7 +505,7 @@ static int tevii_dvbs_set_voltage(struct dvb_frontend *fe, } static int vp1027_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct cx8802_dev *dev = fe->dvb->priv; struct cx88_core *core = dev->core; @@ -897,7 +897,7 @@ static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe) } static int samsung_smt_7020_set_tone(struct dvb_frontend *fe, - fe_sec_tone_mode_t tone) + enum fe_sec_tone_mode tone) { struct cx8802_dev *dev = fe->dvb->priv; struct cx88_core *core = dev->core; @@ -919,7 +919,7 @@ static int samsung_smt_7020_set_tone(struct dvb_frontend *fe, } static int samsung_smt_7020_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct cx8802_dev *dev = fe->dvb->priv; struct cx88_core *core = dev->core; diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index 9834454..34f5057 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -173,7 +173,7 @@ int cx8802_start_dma(struct cx8802_dev *dev, /* reset counter */ cx_write(MO_TS_GPCNTRL, GP_COUNT_CONTROL_RESET); - q->count = 1; + q->count = 0; /* enable irqs */ dprintk( 1, "setting the interrupt mask\n" ); @@ -216,8 +216,6 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, dprintk(2,"restart_queue [%p/%d]: restart dma\n", buf, buf->vb.v4l2_buf.index); cx8802_start_dma(dev, q, buf); - list_for_each_entry(buf, &q->active, list) - buf->count = q->count++; return 0; } @@ -260,7 +258,6 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) if (list_empty(&cx88q->active)) { dprintk( 1, "queue is empty - first active\n" ); list_add_tail(&buf->list, &cx88q->active); - buf->count = cx88q->count++; dprintk(1,"[%p/%d] %s - first active\n", buf, buf->vb.v4l2_buf.index, __func__); @@ -269,7 +266,6 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) dprintk( 1, "queue is not empty - append to active\n" ); prev = list_entry(cx88q->active.prev, struct cx88_buffer, list); list_add_tail(&buf->list, &cx88q->active); - buf->count = cx88q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk( 1, "[%p/%d] %s - append to active\n", buf, buf->vb.v4l2_buf.index, __func__); diff --git a/drivers/media/pci/cx88/cx88-vbi.c b/drivers/media/pci/cx88/cx88-vbi.c index 32eb7fd..7510e80 100644 --- a/drivers/media/pci/cx88/cx88-vbi.c +++ b/drivers/media/pci/cx88/cx88-vbi.c @@ -59,7 +59,7 @@ static int cx8800_start_vbi_dma(struct cx8800_dev *dev, /* reset counter */ cx_write(MO_VBI_GPCNTRL, GP_COUNT_CONTROL_RESET); - q->count = 1; + q->count = 0; /* enable irqs */ cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); @@ -102,8 +102,6 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev, dprintk(2,"restart_queue [%p/%d]: restart dma\n", buf, buf->vb.v4l2_buf.index); cx8800_start_vbi_dma(dev, q, buf); - list_for_each_entry(buf, &q->active, list) - buf->count = q->count++; return 0; } @@ -175,7 +173,6 @@ static void buffer_queue(struct vb2_buffer *vb) if (list_empty(&q->active)) { list_add_tail(&buf->list, &q->active); cx8800_start_vbi_dma(dev, q, buf); - buf->count = q->count++; dprintk(2,"[%p/%d] vbi_queue - first active\n", buf, buf->vb.v4l2_buf.index); @@ -183,7 +180,6 @@ static void buffer_queue(struct vb2_buffer *vb) buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1); prev = list_entry(q->active.prev, struct cx88_buffer, list); list_add_tail(&buf->list, &q->active); - buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(2,"[%p/%d] buffer_queue - append to active\n", buf, buf->vb.v4l2_buf.index); diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index c9decd8..400e5ca 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -370,7 +370,7 @@ static int start_video_dma(struct cx8800_dev *dev, /* reset counter */ cx_write(MO_VIDY_GPCNTRL,GP_COUNT_CONTROL_RESET); - q->count = 1; + q->count = 0; /* enable irqs */ cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); @@ -410,7 +410,6 @@ static int stop_video_dma(struct cx8800_dev *dev) cx_clear(MO_VID_INTMSK, 0x0f0011); return 0; } -#endif static int restart_video_queue(struct cx8800_dev *dev, struct cx88_dmaqueue *q) @@ -423,11 +422,10 @@ static int restart_video_queue(struct cx8800_dev *dev, dprintk(2,"restart_queue [%p/%d]: restart dma\n", buf, buf->vb.v4l2_buf.index); start_video_dma(dev, q, buf); - list_for_each_entry(buf, &q->active, list) - buf->count = q->count++; } return 0; } +#endif /* ------------------------------------------------------------------ */ @@ -523,7 +521,6 @@ static void buffer_queue(struct vb2_buffer *vb) if (list_empty(&q->active)) { list_add_tail(&buf->list, &q->active); - buf->count = q->count++; dprintk(2,"[%p/%d] buffer_queue - first active\n", buf, buf->vb.v4l2_buf.index); @@ -531,7 +528,6 @@ static void buffer_queue(struct vb2_buffer *vb) buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1); prev = list_entry(q->active.prev, struct cx88_buffer, list); list_add_tail(&buf->list, &q->active); - buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(2, "[%p/%d] buffer_queue - append to active\n", buf, buf->vb.v4l2_buf.index); @@ -771,6 +767,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; } diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h index b9fe1ac..785fe2e 100644 --- a/drivers/media/pci/cx88/cx88.h +++ b/drivers/media/pci/cx88/cx88.h @@ -327,7 +327,6 @@ struct cx88_buffer { /* cx88 specific */ unsigned int bpl; struct cx88_riscmem risc; - u32 count; }; struct cx88_dmaqueue { @@ -376,9 +375,10 @@ struct cx88_core { /* config info -- dvb */ #if IS_ENABLED(CONFIG_VIDEO_CX88_DVB) - int (*prev_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage); + int (*prev_set_voltage)(struct dvb_frontend *fe, + enum fe_sec_voltage voltage); #endif - void (*gate_ctrl)(struct cx88_core *core, int open); + void (*gate_ctrl)(struct cx88_core *core, int open); /* state info */ struct task_struct *kthread; diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index 9e3492e..0ac2dd3 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -1630,7 +1630,8 @@ fail1: printk(KERN_ERR "fail1\n"); if (dev->msi) pci_disable_msi(dev->pdev); - free_irq(dev->pdev->irq, dev); + if (stat == 0) + free_irq(dev->pdev->irq, dev); fail: printk(KERN_ERR "fail\n"); ddb_unmap(dev); diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c index ed11716..88915fb 100644 --- a/drivers/media/pci/dm1105/dm1105.c +++ b/drivers/media/pci/dm1105/dm1105.c @@ -591,7 +591,8 @@ static inline struct dm1105_dev *frontend_to_dm1105_dev(struct dvb_frontend *fe) return container_of(fe->dvb, struct dm1105_dev, dvb_adapter); } -static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int dm1105_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct dm1105_dev *dev = frontend_to_dm1105_dev(fe); diff --git a/drivers/media/pci/dt3155/Kconfig b/drivers/media/pci/dt3155/Kconfig new file mode 100644 index 0000000..5145e0d --- /dev/null +++ b/drivers/media/pci/dt3155/Kconfig @@ -0,0 +1,13 @@ +config VIDEO_DT3155 + tristate "DT3155 frame grabber" + depends on PCI && VIDEO_DEV && VIDEO_V4L2 + depends on HAS_DMA + select VIDEOBUF2_DMA_CONTIG + default n + ---help--- + Enables dt3155 device driver for the DataTranslation DT3155 frame grabber. + Say Y here if you have this hardware. + In doubt, say N. + + To compile this driver as a module, choose M here: the + module will be called dt3155. diff --git a/drivers/media/pci/dt3155/Makefile b/drivers/media/pci/dt3155/Makefile new file mode 100644 index 0000000..89fa637 --- /dev/null +++ b/drivers/media/pci/dt3155/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_VIDEO_DT3155) += dt3155.o diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c new file mode 100644 index 0000000..89d0dc7 --- /dev/null +++ b/drivers/media/pci/dt3155/dt3155.c @@ -0,0 +1,632 @@ +/*************************************************************************** + * Copyright (C) 2006-2010 by Marin Mitov * + * mitov@issp.bas.bg * + * * + * 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. * + * * + ***************************************************************************/ + +#include <linux/module.h> +#include <linux/version.h> +#include <linux/stringify.h> +#include <linux/delay.h> +#include <linux/kthread.h> +#include <linux/slab.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-common.h> +#include <media/videobuf2-dma-contig.h> + +#include "dt3155.h" + +#define DT3155_DEVICE_ID 0x1223 + +/** + * read_i2c_reg - reads an internal i2c register + * + * @addr: dt3155 mmio base address + * @index: index (internal address) of register to read + * @data: pointer to byte the read data will be placed in + * + * returns: zero on success or error code + * + * This function starts reading the specified (by index) register + * and busy waits for the process to finish. The result is placed + * in a byte pointed by data. + */ +static int read_i2c_reg(void __iomem *addr, u8 index, u8 *data) +{ + u32 tmp = index; + + iowrite32((tmp << 17) | IIC_READ, addr + IIC_CSR2); + mmiowb(); + udelay(45); /* wait at least 43 usec for NEW_CYCLE to clear */ + if (ioread32(addr + IIC_CSR2) & NEW_CYCLE) + return -EIO; /* error: NEW_CYCLE not cleared */ + tmp = ioread32(addr + IIC_CSR1); + if (tmp & DIRECT_ABORT) { + /* reset DIRECT_ABORT bit */ + iowrite32(DIRECT_ABORT, addr + IIC_CSR1); + return -EIO; /* error: DIRECT_ABORT set */ + } + *data = tmp >> 24; + return 0; +} + +/** + * write_i2c_reg - writes to an internal i2c register + * + * @addr: dt3155 mmio base address + * @index: index (internal address) of register to read + * @data: data to be written + * + * returns: zero on success or error code + * + * This function starts writing the specified (by index) register + * and busy waits for the process to finish. + */ +static int write_i2c_reg(void __iomem *addr, u8 index, u8 data) +{ + u32 tmp = index; + + iowrite32((tmp << 17) | IIC_WRITE | data, addr + IIC_CSR2); + mmiowb(); + udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */ + if (ioread32(addr + IIC_CSR2) & NEW_CYCLE) + return -EIO; /* error: NEW_CYCLE not cleared */ + if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) { + /* reset DIRECT_ABORT bit */ + iowrite32(DIRECT_ABORT, addr + IIC_CSR1); + return -EIO; /* error: DIRECT_ABORT set */ + } + return 0; +} + +/** + * write_i2c_reg_nowait - writes to an internal i2c register + * + * @addr: dt3155 mmio base address + * @index: index (internal address) of register to read + * @data: data to be written + * + * This function starts writing the specified (by index) register + * and then returns. + */ +static void write_i2c_reg_nowait(void __iomem *addr, u8 index, u8 data) +{ + u32 tmp = index; + + iowrite32((tmp << 17) | IIC_WRITE | data, addr + IIC_CSR2); + mmiowb(); +} + +/** + * wait_i2c_reg - waits the read/write to finish + * + * @addr: dt3155 mmio base address + * + * returns: zero on success or error code + * + * This function waits reading/writing to finish. + */ +static int wait_i2c_reg(void __iomem *addr) +{ + if (ioread32(addr + IIC_CSR2) & NEW_CYCLE) + udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */ + if (ioread32(addr + IIC_CSR2) & NEW_CYCLE) + return -EIO; /* error: NEW_CYCLE not cleared */ + if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) { + /* reset DIRECT_ABORT bit */ + iowrite32(DIRECT_ABORT, addr + IIC_CSR1); + return -EIO; /* error: DIRECT_ABORT set */ + } + return 0; +} + +static int +dt3155_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) + +{ + struct dt3155_priv *pd = vb2_get_drv_priv(vq); + unsigned size = pd->width * pd->height; + + if (vq->num_buffers + *nbuffers < 2) + *nbuffers = 2 - vq->num_buffers; + if (fmt && fmt->fmt.pix.sizeimage < size) + return -EINVAL; + *num_planes = 1; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size; + alloc_ctxs[0] = pd->alloc_ctx; + return 0; +} + +static int dt3155_buf_prepare(struct vb2_buffer *vb) +{ + struct dt3155_priv *pd = vb2_get_drv_priv(vb->vb2_queue); + + vb2_set_plane_payload(vb, 0, pd->width * pd->height); + return 0; +} + +static int dt3155_start_streaming(struct vb2_queue *q, unsigned count) +{ + struct dt3155_priv *pd = vb2_get_drv_priv(q); + struct vb2_buffer *vb = pd->curr_buf; + dma_addr_t dma_addr; + + pd->sequence = 0; + dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + iowrite32(dma_addr, pd->regs + EVEN_DMA_START); + iowrite32(dma_addr + pd->width, pd->regs + ODD_DMA_START); + iowrite32(pd->width, pd->regs + EVEN_DMA_STRIDE); + iowrite32(pd->width, pd->regs + ODD_DMA_STRIDE); + /* enable interrupts, clear all irq flags */ + iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START | + FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR); + iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN | + FLD_DN_ODD | FLD_DN_EVEN | CAP_CONT_EVEN | CAP_CONT_ODD, + pd->regs + CSR1); + wait_i2c_reg(pd->regs); + write_i2c_reg(pd->regs, CONFIG, pd->config); + write_i2c_reg(pd->regs, EVEN_CSR, CSR_ERROR | CSR_DONE); + write_i2c_reg(pd->regs, ODD_CSR, CSR_ERROR | CSR_DONE); + + /* start the board */ + write_i2c_reg(pd->regs, CSR2, pd->csr2 | BUSY_EVEN | BUSY_ODD); + return 0; +} + +static void dt3155_stop_streaming(struct vb2_queue *q) +{ + struct dt3155_priv *pd = vb2_get_drv_priv(q); + struct vb2_buffer *vb; + + spin_lock_irq(&pd->lock); + /* stop the board */ + write_i2c_reg_nowait(pd->regs, CSR2, pd->csr2); + iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN | + FLD_DN_ODD | FLD_DN_EVEN, pd->regs + CSR1); + /* disable interrupts, clear all irq flags */ + iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR); + spin_unlock_irq(&pd->lock); + + /* + * It is not clear whether the DMA stops at once or whether it + * will finish the current frame or field first. To be on the + * safe side we wait a bit. + */ + msleep(45); + + spin_lock_irq(&pd->lock); + if (pd->curr_buf) { + vb2_buffer_done(pd->curr_buf, VB2_BUF_STATE_ERROR); + pd->curr_buf = NULL; + } + + while (!list_empty(&pd->dmaq)) { + vb = list_first_entry(&pd->dmaq, typeof(*vb), done_entry); + list_del(&vb->done_entry); + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); + } + spin_unlock_irq(&pd->lock); +} + +static void dt3155_buf_queue(struct vb2_buffer *vb) +{ + struct dt3155_priv *pd = vb2_get_drv_priv(vb->vb2_queue); + + /* pd->vidq.streaming = 1 when dt3155_buf_queue() is invoked */ + spin_lock_irq(&pd->lock); + if (pd->curr_buf) + list_add_tail(&vb->done_entry, &pd->dmaq); + else + pd->curr_buf = vb; + spin_unlock_irq(&pd->lock); +} + +static const struct vb2_ops q_ops = { + .queue_setup = dt3155_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_prepare = dt3155_buf_prepare, + .start_streaming = dt3155_start_streaming, + .stop_streaming = dt3155_stop_streaming, + .buf_queue = dt3155_buf_queue, +}; + +static irqreturn_t dt3155_irq_handler_even(int irq, void *dev_id) +{ + struct dt3155_priv *ipd = dev_id; + struct vb2_buffer *ivb; + dma_addr_t dma_addr; + u32 tmp; + + tmp = ioread32(ipd->regs + INT_CSR) & (FLD_START | FLD_END_ODD); + if (!tmp) + return IRQ_NONE; /* not our irq */ + if ((tmp & FLD_START) && !(tmp & FLD_END_ODD)) { + iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START, + ipd->regs + INT_CSR); + return IRQ_HANDLED; /* start of field irq */ + } + tmp = ioread32(ipd->regs + CSR1) & (FLD_CRPT_EVEN | FLD_CRPT_ODD); + if (tmp) { + iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN | + FLD_DN_ODD | FLD_DN_EVEN | + CAP_CONT_EVEN | CAP_CONT_ODD, + ipd->regs + CSR1); + mmiowb(); + } + + spin_lock(&ipd->lock); + if (ipd->curr_buf && !list_empty(&ipd->dmaq)) { + v4l2_get_timestamp(&ipd->curr_buf->v4l2_buf.timestamp); + ipd->curr_buf->v4l2_buf.sequence = ipd->sequence++; + ipd->curr_buf->v4l2_buf.field = V4L2_FIELD_NONE; + vb2_buffer_done(ipd->curr_buf, VB2_BUF_STATE_DONE); + + ivb = list_first_entry(&ipd->dmaq, typeof(*ivb), done_entry); + list_del(&ivb->done_entry); + ipd->curr_buf = ivb; + dma_addr = vb2_dma_contig_plane_dma_addr(ivb, 0); + iowrite32(dma_addr, ipd->regs + EVEN_DMA_START); + iowrite32(dma_addr + ipd->width, ipd->regs + ODD_DMA_START); + iowrite32(ipd->width, ipd->regs + EVEN_DMA_STRIDE); + iowrite32(ipd->width, ipd->regs + ODD_DMA_STRIDE); + mmiowb(); + } + + /* enable interrupts, clear all irq flags */ + iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START | + FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR); + spin_unlock(&ipd->lock); + return IRQ_HANDLED; +} + +static const struct v4l2_file_operations dt3155_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .unlocked_ioctl = video_ioctl2, + .read = vb2_fop_read, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll +}; + +static int dt3155_querycap(struct file *filp, void *p, + struct v4l2_capability *cap) +{ + struct dt3155_priv *pd = video_drvdata(filp); + + strcpy(cap->driver, DT3155_NAME); + strcpy(cap->card, DT3155_NAME " frame grabber"); + sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev)); + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +static int dt3155_enum_fmt_vid_cap(struct file *filp, + void *p, struct v4l2_fmtdesc *f) +{ + if (f->index) + return -EINVAL; + f->pixelformat = V4L2_PIX_FMT_GREY; + strcpy(f->description, "8-bit Greyscale"); + return 0; +} + +static int dt3155_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f) +{ + struct dt3155_priv *pd = video_drvdata(filp); + + f->fmt.pix.width = pd->width; + f->fmt.pix.height = pd->height; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_GREY; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.bytesperline = f->fmt.pix.width; + f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + return 0; +} + +static int dt3155_g_std(struct file *filp, void *p, v4l2_std_id *norm) +{ + struct dt3155_priv *pd = video_drvdata(filp); + + *norm = pd->std; + return 0; +} + +static int dt3155_s_std(struct file *filp, void *p, v4l2_std_id norm) +{ + struct dt3155_priv *pd = video_drvdata(filp); + + if (pd->std == norm) + return 0; + if (vb2_is_busy(&pd->vidq)) + return -EBUSY; + pd->std = norm; + if (pd->std & V4L2_STD_525_60) { + pd->csr2 = VT_60HZ; + pd->width = 640; + pd->height = 480; + } else { + pd->csr2 = VT_50HZ; + pd->width = 768; + pd->height = 576; + } + return 0; +} + +static int dt3155_enum_input(struct file *filp, void *p, + struct v4l2_input *input) +{ + if (input->index > 3) + return -EINVAL; + if (input->index) + snprintf(input->name, sizeof(input->name), "VID%d", + input->index); + else + strlcpy(input->name, "J2/VID0", sizeof(input->name)); + input->type = V4L2_INPUT_TYPE_CAMERA; + input->std = V4L2_STD_ALL; + input->status = 0; + return 0; +} + +static int dt3155_g_input(struct file *filp, void *p, unsigned int *i) +{ + struct dt3155_priv *pd = video_drvdata(filp); + + *i = pd->input; + return 0; +} + +static int dt3155_s_input(struct file *filp, void *p, unsigned int i) +{ + struct dt3155_priv *pd = video_drvdata(filp); + + if (i > 3) + return -EINVAL; + pd->input = i; + write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG); + write_i2c_reg(pd->regs, AD_CMD, (i << 6) | (i << 4) | SYNC_LVL_3); + return 0; +} + +static const struct v4l2_ioctl_ops dt3155_ioctl_ops = { + .vidioc_querycap = dt3155_querycap, + .vidioc_enum_fmt_vid_cap = dt3155_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = dt3155_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = dt3155_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = dt3155_fmt_vid_cap, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_g_std = dt3155_g_std, + .vidioc_s_std = dt3155_s_std, + .vidioc_enum_input = dt3155_enum_input, + .vidioc_g_input = dt3155_g_input, + .vidioc_s_input = dt3155_s_input, +}; + +static int dt3155_init_board(struct dt3155_priv *pd) +{ + struct pci_dev *pdev = pd->pdev; + int i; + u8 tmp = 0; + + pci_set_master(pdev); /* dt3155 needs it */ + + /* resetting the adapter */ + iowrite32(ADDR_ERR_ODD | ADDR_ERR_EVEN | FLD_CRPT_ODD | FLD_CRPT_EVEN | + FLD_DN_ODD | FLD_DN_EVEN, pd->regs + CSR1); + mmiowb(); + msleep(20); + + /* initializing adapter registers */ + iowrite32(FIFO_EN | SRST, pd->regs + CSR1); + mmiowb(); + iowrite32(0xEEEEEE01, pd->regs + EVEN_PIXEL_FMT); + iowrite32(0xEEEEEE01, pd->regs + ODD_PIXEL_FMT); + iowrite32(0x00000020, pd->regs + FIFO_TRIGER); + iowrite32(0x00000103, pd->regs + XFER_MODE); + iowrite32(0, pd->regs + RETRY_WAIT_CNT); + iowrite32(0, pd->regs + INT_CSR); + iowrite32(1, pd->regs + EVEN_FLD_MASK); + iowrite32(1, pd->regs + ODD_FLD_MASK); + iowrite32(0, pd->regs + MASK_LENGTH); + iowrite32(0x0005007C, pd->regs + FIFO_FLAG_CNT); + iowrite32(0x01010101, pd->regs + IIC_CLK_DUR); + mmiowb(); + + /* verifying that we have a DT3155 board (not just a SAA7116 chip) */ + read_i2c_reg(pd->regs, DT_ID, &tmp); + if (tmp != DT3155_ID) + return -ENODEV; + + /* initialize AD LUT */ + write_i2c_reg(pd->regs, AD_ADDR, 0); + for (i = 0; i < 256; i++) + write_i2c_reg(pd->regs, AD_LUT, i); + + /* initialize ADC references */ + /* FIXME: pos_ref & neg_ref depend on VT_50HZ */ + write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG); + write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3); + write_i2c_reg(pd->regs, AD_ADDR, AD_POS_REF); + write_i2c_reg(pd->regs, AD_CMD, 34); + write_i2c_reg(pd->regs, AD_ADDR, AD_NEG_REF); + write_i2c_reg(pd->regs, AD_CMD, 0); + + /* initialize PM LUT */ + write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM); + for (i = 0; i < 256; i++) { + write_i2c_reg(pd->regs, PM_LUT_ADDR, i); + write_i2c_reg(pd->regs, PM_LUT_DATA, i); + } + write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM | PM_LUT_SEL); + for (i = 0; i < 256; i++) { + write_i2c_reg(pd->regs, PM_LUT_ADDR, i); + write_i2c_reg(pd->regs, PM_LUT_DATA, i); + } + write_i2c_reg(pd->regs, CONFIG, pd->config); /* ACQ_MODE_EVEN */ + + /* select channel 1 for input and set sync level */ + write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG); + write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3); + + /* disable all irqs, clear all irq flags */ + iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, + pd->regs + INT_CSR); + + return 0; +} + +static struct video_device dt3155_vdev = { + .name = DT3155_NAME, + .fops = &dt3155_fops, + .ioctl_ops = &dt3155_ioctl_ops, + .minor = -1, + .release = video_device_release_empty, + .tvnorms = V4L2_STD_ALL, +}; + +static int dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int err; + struct dt3155_priv *pd; + + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) + return -ENODEV; + pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL); + if (!pd) + return -ENOMEM; + + err = v4l2_device_register(&pdev->dev, &pd->v4l2_dev); + if (err) + return err; + pd->vdev = dt3155_vdev; + pd->vdev.v4l2_dev = &pd->v4l2_dev; + video_set_drvdata(&pd->vdev, pd); /* for use in video_fops */ + pd->pdev = pdev; + pd->std = V4L2_STD_625_50; + pd->csr2 = VT_50HZ; + pd->width = 768; + pd->height = 576; + INIT_LIST_HEAD(&pd->dmaq); + mutex_init(&pd->mux); + pd->vdev.lock = &pd->mux; /* for locking v4l2_file_operations */ + pd->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + pd->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + pd->vidq.io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; + pd->vidq.ops = &q_ops; + pd->vidq.mem_ops = &vb2_dma_contig_memops; + pd->vidq.drv_priv = pd; + pd->vidq.min_buffers_needed = 2; + pd->vidq.gfp_flags = GFP_DMA32; + pd->vidq.lock = &pd->mux; /* for locking v4l2_file_operations */ + pd->vdev.queue = &pd->vidq; + err = vb2_queue_init(&pd->vidq); + if (err < 0) + goto err_v4l2_dev_unreg; + pd->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(pd->alloc_ctx)) { + dev_err(&pdev->dev, "Can't allocate buffer context"); + err = PTR_ERR(pd->alloc_ctx); + goto err_v4l2_dev_unreg; + } + spin_lock_init(&pd->lock); + pd->config = ACQ_MODE_EVEN; + err = pci_enable_device(pdev); + if (err) + goto err_free_ctx; + err = pci_request_region(pdev, 0, pci_name(pdev)); + if (err) + goto err_pci_disable; + pd->regs = pci_iomap(pdev, 0, pci_resource_len(pd->pdev, 0)); + if (!pd->regs) { + err = -ENOMEM; + goto err_free_reg; + } + err = dt3155_init_board(pd); + if (err) + goto err_iounmap; + err = request_irq(pd->pdev->irq, dt3155_irq_handler_even, + IRQF_SHARED, DT3155_NAME, pd); + if (err) + goto err_iounmap; + err = video_register_device(&pd->vdev, VFL_TYPE_GRABBER, -1); + if (err) + goto err_free_irq; + dev_info(&pdev->dev, "/dev/video%i is ready\n", pd->vdev.minor); + return 0; /* success */ + +err_free_irq: + free_irq(pd->pdev->irq, pd); +err_iounmap: + pci_iounmap(pdev, pd->regs); +err_free_reg: + pci_release_region(pdev, 0); +err_pci_disable: + pci_disable_device(pdev); +err_free_ctx: + vb2_dma_contig_cleanup_ctx(pd->alloc_ctx); +err_v4l2_dev_unreg: + v4l2_device_unregister(&pd->v4l2_dev); + return err; +} + +static void dt3155_remove(struct pci_dev *pdev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev); + struct dt3155_priv *pd = container_of(v4l2_dev, struct dt3155_priv, + v4l2_dev); + + video_unregister_device(&pd->vdev); + free_irq(pd->pdev->irq, pd); + vb2_queue_release(&pd->vidq); + v4l2_device_unregister(&pd->v4l2_dev); + pci_iounmap(pdev, pd->regs); + pci_release_region(pdev, 0); + pci_disable_device(pdev); + vb2_dma_contig_cleanup_ctx(pd->alloc_ctx); +} + +static const struct pci_device_id pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, DT3155_DEVICE_ID) }, + { 0, /* zero marks the end */ }, +}; +MODULE_DEVICE_TABLE(pci, pci_ids); + +static struct pci_driver pci_driver = { + .name = DT3155_NAME, + .id_table = pci_ids, + .probe = dt3155_probe, + .remove = dt3155_remove, +}; + +module_pci_driver(pci_driver); + +MODULE_DESCRIPTION("video4linux pci-driver for dt3155 frame grabber"); +MODULE_AUTHOR("Marin Mitov <mitov@issp.bas.bg>"); +MODULE_VERSION(DT3155_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/dt3155/dt3155.h b/drivers/media/pci/dt3155/dt3155.h new file mode 100644 index 0000000..4e1f4d5 --- /dev/null +++ b/drivers/media/pci/dt3155/dt3155.h @@ -0,0 +1,196 @@ +/*************************************************************************** + * Copyright (C) 2006-2010 by Marin Mitov * + * mitov@issp.bas.bg * + * * + * 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. * + * * + ***************************************************************************/ + +/* DT3155 header file */ +#ifndef _DT3155_H_ +#define _DT3155_H_ + +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <media/v4l2-device.h> +#include <media/v4l2-dev.h> + +#define DT3155_NAME "dt3155" +#define DT3155_VER_MAJ 2 +#define DT3155_VER_MIN 0 +#define DT3155_VER_EXT 0 +#define DT3155_VERSION __stringify(DT3155_VER_MAJ) "." \ + __stringify(DT3155_VER_MIN) "." \ + __stringify(DT3155_VER_EXT) + +/* DT3155 Base Register offsets (memory mapped) */ +#define EVEN_DMA_START 0x00 +#define ODD_DMA_START 0x0C +#define EVEN_DMA_STRIDE 0x18 +#define ODD_DMA_STRIDE 0x24 +#define EVEN_PIXEL_FMT 0x30 +#define ODD_PIXEL_FMT 0x34 +#define FIFO_TRIGER 0x38 +#define XFER_MODE 0x3C +#define CSR1 0x40 +#define RETRY_WAIT_CNT 0x44 +#define INT_CSR 0x48 +#define EVEN_FLD_MASK 0x4C +#define ODD_FLD_MASK 0x50 +#define MASK_LENGTH 0x54 +#define FIFO_FLAG_CNT 0x58 +#define IIC_CLK_DUR 0x5C +#define IIC_CSR1 0x60 +#define IIC_CSR2 0x64 + +/* DT3155 Internal Registers indexes (i2c/IIC mapped) */ +#define CSR2 0x10 +#define EVEN_CSR 0x11 +#define ODD_CSR 0x12 +#define CONFIG 0x13 +#define DT_ID 0x1F +#define X_CLIP_START 0x20 +#define Y_CLIP_START 0x22 +#define X_CLIP_END 0x24 +#define Y_CLIP_END 0x26 +#define AD_ADDR 0x30 +#define AD_LUT 0x31 +#define AD_CMD 0x32 +#define DIG_OUT 0x40 +#define PM_LUT_ADDR 0x50 +#define PM_LUT_DATA 0x51 + +/* AD command register values */ +#define AD_CMD_REG 0x00 +#define AD_POS_REF 0x01 +#define AD_NEG_REF 0x02 + +/* CSR1 bit masks */ +#define RANGE_EN 0x00008000 +#define CRPT_DIS 0x00004000 +#define ADDR_ERR_ODD 0x00000800 +#define ADDR_ERR_EVEN 0x00000400 +#define FLD_CRPT_ODD 0x00000200 +#define FLD_CRPT_EVEN 0x00000100 +#define FIFO_EN 0x00000080 +#define SRST 0x00000040 +#define FLD_DN_ODD 0x00000020 +#define FLD_DN_EVEN 0x00000010 +/* These should not be used. + * Use CAP_CONT_ODD/EVEN instead +#define CAP_SNGL_ODD 0x00000008 +#define CAP_SNGL_EVEN 0x00000004 +*/ +#define CAP_CONT_ODD 0x00000002 +#define CAP_CONT_EVEN 0x00000001 + +/* INT_CSR bit masks */ +#define FLD_START_EN 0x00000400 +#define FLD_END_ODD_EN 0x00000200 +#define FLD_END_EVEN_EN 0x00000100 +#define FLD_START 0x00000004 +#define FLD_END_ODD 0x00000002 +#define FLD_END_EVEN 0x00000001 + +/* IIC_CSR1 bit masks */ +#define DIRECT_ABORT 0x00000200 + +/* IIC_CSR2 bit masks */ +#define NEW_CYCLE 0x01000000 +#define DIR_RD 0x00010000 +#define IIC_READ 0x01010000 +#define IIC_WRITE 0x01000000 + +/* CSR2 bit masks */ +#define DISP_PASS 0x40 +#define BUSY_ODD 0x20 +#define BUSY_EVEN 0x10 +#define SYNC_PRESENT 0x08 +#define VT_50HZ 0x04 +#define SYNC_SNTL 0x02 +#define CHROM_FILT 0x01 +#define VT_60HZ 0x00 + +/* CSR_EVEN/ODD bit masks */ +#define CSR_ERROR 0x04 +#define CSR_SNGL 0x02 +#define CSR_DONE 0x01 + +/* CONFIG bit masks */ +#define PM_LUT_PGM 0x80 +#define PM_LUT_SEL 0x40 +#define CLIP_EN 0x20 +#define HSCALE_EN 0x10 +#define EXT_TRIG_UP 0x0C +#define EXT_TRIG_DOWN 0x04 +#define ACQ_MODE_NEXT 0x02 +#define ACQ_MODE_ODD 0x01 +#define ACQ_MODE_EVEN 0x00 + +/* AD_CMD bit masks */ +#define VIDEO_CNL_1 0x00 +#define VIDEO_CNL_2 0x40 +#define VIDEO_CNL_3 0x80 +#define VIDEO_CNL_4 0xC0 +#define SYNC_CNL_1 0x00 +#define SYNC_CNL_2 0x10 +#define SYNC_CNL_3 0x20 +#define SYNC_CNL_4 0x30 +#define SYNC_LVL_1 0x00 +#define SYNC_LVL_2 0x04 +#define SYNC_LVL_3 0x08 +#define SYNC_LVL_4 0x0C + +/* DT3155 identificator */ +#define DT3155_ID 0x20 + +/* per board private data structure */ +/** + * struct dt3155_priv - private data structure + * + * @v4l2_dev: v4l2_device structure + * @vdev: video_device structure + * @pdev: pointer to pci_dev structure + * @vidq: vb2_queue structure + * @alloc_ctx: dma_contig allocation context + * @curr_buf: pointer to curren buffer + * @mux: mutex to protect the instance + * @dmaq: queue for dma buffers + * @lock: spinlock for dma queue + * @std: input standard + * @width: frame width + * @height: frame height + * @input: current input + * @sequence: frame counter + * @stats: statistics structure + * @regs: local copy of mmio base register + * @csr2: local copy of csr2 register + * @config: local copy of config register + */ +struct dt3155_priv { + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct pci_dev *pdev; + struct vb2_queue vidq; + struct vb2_alloc_ctx *alloc_ctx; + struct vb2_buffer *curr_buf; + struct mutex mux; + struct list_head dmaq; + spinlock_t lock; + v4l2_std_id std; + unsigned width, height; + unsigned input; + unsigned int sequence; + void __iomem *regs; + u8 csr2, config; +}; + +#endif /* _DT3155_H_ */ diff --git a/drivers/media/pci/ivtv/ivtv-controls.c b/drivers/media/pci/ivtv/ivtv-controls.c index ccf548c..8a55ccb 100644 --- a/drivers/media/pci/ivtv/ivtv-controls.c +++ b/drivers/media/pci/ivtv/ivtv-controls.c @@ -64,13 +64,15 @@ static int ivtv_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) { struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl); int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_mbus_framefmt fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; /* fix videodecoder resolution */ - fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); - fmt.height = cxhdl->height; - fmt.code = MEDIA_BUS_FMT_FIXED; - v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &fmt); + format.format.width = cxhdl->width / (is_mpeg1 ? 2 : 1); + format.format.height = cxhdl->height; + format.format.code = MEDIA_BUS_FMT_FIXED; + v4l2_subdev_call(itv->sd_video, pad, set_fmt, NULL, &format); return 0; } diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index c2e60b4..8616fa8 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -805,11 +805,11 @@ static void ivtv_init_struct2(struct ivtv *itv) { int i; - for (i = 0; i < IVTV_CARD_MAX_VIDEO_INPUTS; i++) + for (i = 0; i < IVTV_CARD_MAX_VIDEO_INPUTS - 1; i++) if (itv->card->video_inputs[i].video_type == 0) break; itv->nof_inputs = i; - for (i = 0; i < IVTV_CARD_MAX_AUDIO_INPUTS; i++) + for (i = 0; i < IVTV_CARD_MAX_AUDIO_INPUTS - 1; i++) if (itv->card->audio_inputs[i].audio_type == 0) break; itv->nof_audio_inputs = i; diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h index e8b6c7a..ee0ef6e 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.h +++ b/drivers/media/pci/ivtv/ivtv-driver.h @@ -830,7 +830,8 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv) do { \ struct v4l2_subdev *__sd; \ __v4l2_device_call_subdevs_p(&(itv)->v4l2_dev, __sd, \ - !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \ + !(hw) ? true : (__sd->grp_id & (hw)), \ + o, f, ##args); \ } while (0) #define ivtv_call_all(itv, o, f, args...) ivtv_call_hw(itv, 0, o, f , ##args) diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 6fe6c4a..9a21c17 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -581,7 +581,9 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f { struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int ret = ivtv_try_fmt_vid_cap(file, fh, fmt); int w = fmt->fmt.pix.width; int h = fmt->fmt.pix.height; @@ -599,10 +601,10 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f itv->cxhdl.height = h; if (v4l2_ctrl_g_ctrl(itv->cxhdl.video_encoding) == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) fmt->fmt.pix.width /= 2; - mbus_fmt.width = fmt->fmt.pix.width; - mbus_fmt.height = h; - mbus_fmt.code = MEDIA_BUS_FMT_FIXED; - v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &mbus_fmt); + format.format.width = fmt->fmt.pix.width; + format.format.height = h; + format.format.code = MEDIA_BUS_FMT_FIXED; + v4l2_subdev_call(itv->sd_video, pad, set_fmt, NULL, &format); return ivtv_g_fmt_vid_cap(file, fh, fmt); } @@ -1529,7 +1531,8 @@ static int ivtv_log_status(struct file *file, void *fh) ivtv_get_audio_input(itv, itv->audio_input, &audin); IVTV_INFO("Video Input: %s\n", vidin.name); IVTV_INFO("Audio Input: %s%s\n", audin.name, - (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : ""); + itv->dualwatch_stereo_mode == V4L2_MPEG_AUDIO_MODE_DUAL ? + " (Bilingual)" : ""); if (has_output) { struct v4l2_output vidout; struct v4l2_audioout audout; diff --git a/drivers/media/pci/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c index 104914a..68b5800 100644 --- a/drivers/media/pci/mantis/hopper_cards.c +++ b/drivers/media/pci/mantis/hopper_cards.c @@ -106,6 +106,10 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id) } if (stat & MANTIS_INT_IRQ1) { dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]); + spin_lock(&mantis->intmask_lock); + mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ1, + MANTIS_INT_MASK); + spin_unlock(&mantis->intmask_lock); schedule_work(&mantis->uart_work); } if (stat & MANTIS_INT_OCERR) { @@ -154,6 +158,7 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id) static int hopper_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) { + struct mantis_pci_drvdata *drvdata; struct mantis_pci *mantis; struct mantis_hwconfig *config; int err = 0; @@ -165,12 +170,16 @@ static int hopper_pci_probe(struct pci_dev *pdev, goto fail0; } + drvdata = (void *)pci_id->driver_data; mantis->num = devs; mantis->verbose = verbose; mantis->pdev = pdev; - config = (struct mantis_hwconfig *) pci_id->driver_data; + config = drvdata->hwconfig; config->irq_handler = &hopper_irq_handler; mantis->hwconfig = config; + mantis->rc_map_name = drvdata->rc_map_name; + + spin_lock_init(&mantis->intmask_lock); err = mantis_pci_init(mantis); if (err) { @@ -247,7 +256,8 @@ static void hopper_pci_remove(struct pci_dev *pdev) } static struct pci_device_id hopper_pci_table[] = { - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config, + NULL), { } }; diff --git a/drivers/media/pci/mantis/mantis_cards.c b/drivers/media/pci/mantis/mantis_cards.c index 801fc55..cdefffc 100644 --- a/drivers/media/pci/mantis/mantis_cards.c +++ b/drivers/media/pci/mantis/mantis_cards.c @@ -25,6 +25,7 @@ #include <linux/slab.h> #include <asm/irq.h> #include <linux/interrupt.h> +#include <media/rc-map.h> #include "dmxdev.h" #include "dvbdev.h" @@ -49,6 +50,7 @@ #include "mantis_pci.h" #include "mantis_i2c.h" #include "mantis_reg.h" +#include "mantis_input.h" static unsigned int verbose; module_param(verbose, int, 0644); @@ -114,6 +116,10 @@ static irqreturn_t mantis_irq_handler(int irq, void *dev_id) } if (stat & MANTIS_INT_IRQ1) { dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]); + spin_lock(&mantis->intmask_lock); + mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ1, + MANTIS_INT_MASK); + spin_unlock(&mantis->intmask_lock); schedule_work(&mantis->uart_work); } if (stat & MANTIS_INT_OCERR) { @@ -162,6 +168,7 @@ static irqreturn_t mantis_irq_handler(int irq, void *dev_id) static int mantis_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) { + struct mantis_pci_drvdata *drvdata; struct mantis_pci *mantis; struct mantis_hwconfig *config; int err = 0; @@ -169,84 +176,91 @@ static int mantis_pci_probe(struct pci_dev *pdev, mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); if (mantis == NULL) { printk(KERN_ERR "%s ERROR: Out of memory\n", __func__); - err = -ENOMEM; - goto fail0; + return -ENOMEM; } + drvdata = (void *)pci_id->driver_data; mantis->num = devs; mantis->verbose = verbose; mantis->pdev = pdev; - config = (struct mantis_hwconfig *) pci_id->driver_data; + config = drvdata->hwconfig; config->irq_handler = &mantis_irq_handler; mantis->hwconfig = config; + mantis->rc_map_name = drvdata->rc_map_name; + + spin_lock_init(&mantis->intmask_lock); err = mantis_pci_init(mantis); if (err) { dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err); - goto fail1; + goto err_free_mantis; } err = mantis_stream_control(mantis, STREAM_TO_HIF); if (err < 0) { dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err); - goto fail1; + goto err_pci_exit; } err = mantis_i2c_init(mantis); if (err < 0) { dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err); - goto fail2; + goto err_pci_exit; } err = mantis_get_mac(mantis); if (err < 0) { dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err); - goto fail2; + goto err_i2c_exit; } err = mantis_dma_init(mantis); if (err < 0) { dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err); - goto fail3; + goto err_i2c_exit; } err = mantis_dvb_init(mantis); if (err < 0) { dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err); - goto fail4; + goto err_dma_exit; + } + + err = mantis_input_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, + "ERROR: Mantis DVB initialization failed <%d>", err); + goto err_dvb_exit; } + err = mantis_uart_init(mantis); if (err < 0) { dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART initialization failed <%d>", err); - goto fail6; + goto err_input_exit; } devs++; - return err; + return 0; +err_input_exit: + mantis_input_exit(mantis); - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART exit! <%d>", err); - mantis_uart_exit(mantis); +err_dvb_exit: + mantis_dvb_exit(mantis); -fail6: -fail4: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err); +err_dma_exit: mantis_dma_exit(mantis); -fail3: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err); +err_i2c_exit: mantis_i2c_exit(mantis); -fail2: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err); +err_pci_exit: mantis_pci_exit(mantis); -fail1: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err); +err_free_mantis: kfree(mantis); -fail0: return err; } @@ -257,6 +271,7 @@ static void mantis_pci_remove(struct pci_dev *pdev) if (mantis) { mantis_uart_exit(mantis); + mantis_input_exit(mantis); mantis_dvb_exit(mantis); mantis_dma_exit(mantis); mantis_i2c_exit(mantis); @@ -267,17 +282,28 @@ static void mantis_pci_remove(struct pci_dev *pdev) } static struct pci_device_id mantis_pci_table[] = { - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config), - MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config), - MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config), - MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config), - MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config), - MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2040_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config), + MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config, + RC_MAP_TECHNISAT_TS35), + MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config, + NULL), + MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config, + NULL), + MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2040_config, + RC_MAP_TERRATEC_CINERGY_C_PCI), + MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config, + RC_MAP_TERRATEC_CINERGY_S2_HD), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config, + NULL), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config, + NULL), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config, + RC_MAP_TWINHAN_DTV_CAB_CI), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config, + RC_MAP_TWINHAN_DTV_CAB_CI), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config, + NULL), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config, + NULL), { } }; diff --git a/drivers/media/pci/mantis/mantis_common.h b/drivers/media/pci/mantis/mantis_common.h index 8ff448b..d48778a 100644 --- a/drivers/media/pci/mantis/mantis_common.h +++ b/drivers/media/pci/mantis/mantis_common.h @@ -25,6 +25,7 @@ #include <linux/mutex.h> #include <linux/workqueue.h> +#include "mantis_reg.h" #include "mantis_uart.h" #include "mantis_link.h" @@ -68,12 +69,13 @@ #define TECHNISAT 0x1ae4 #define TERRATEC 0x153b -#define MAKE_ENTRY(__subven, __subdev, __configptr) { \ +#define MAKE_ENTRY(__subven, __subdev, __configptr, __rc) { \ .vendor = TWINHAN_TECHNOLOGIES, \ .device = MANTIS, \ .subvendor = (__subven), \ .subdevice = (__subdev), \ - .driver_data = (unsigned long) (__configptr) \ + .driver_data = (unsigned long) \ + &(struct mantis_pci_drvdata){__configptr, __rc} \ } enum mantis_i2c_mode { @@ -101,6 +103,11 @@ struct mantis_hwconfig { enum mantis_i2c_mode i2c_mode; }; +struct mantis_pci_drvdata { + struct mantis_hwconfig *hwconfig; + char *rc_map_name; +}; + struct mantis_pci { unsigned int verbose; @@ -131,6 +138,7 @@ struct mantis_pci { dma_addr_t risc_dma; struct tasklet_struct tasklet; + spinlock_t intmask_lock; struct i2c_adapter adapter; int i2c_rc; @@ -165,15 +173,32 @@ struct mantis_pci { struct mantis_ca *mantis_ca; - wait_queue_head_t uart_wq; struct work_struct uart_work; - spinlock_t uart_lock; struct rc_dev *rc; char input_name[80]; char input_phys[80]; + char *rc_map_name; }; #define MANTIS_HIF_STATUS (mantis->gpio_status) +static inline void mantis_mask_ints(struct mantis_pci *mantis, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&mantis->intmask_lock, flags); + mmwrite(mmread(MANTIS_INT_MASK) & ~mask, MANTIS_INT_MASK); + spin_unlock_irqrestore(&mantis->intmask_lock, flags); +} + +static inline void mantis_unmask_ints(struct mantis_pci *mantis, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&mantis->intmask_lock, flags); + mmwrite(mmread(MANTIS_INT_MASK) | mask, MANTIS_INT_MASK); + spin_unlock_irqrestore(&mantis->intmask_lock, flags); +} + #endif /* __MANTIS_COMMON_H */ diff --git a/drivers/media/pci/mantis/mantis_dma.c b/drivers/media/pci/mantis/mantis_dma.c index 566c407..1d59c7e 100644 --- a/drivers/media/pci/mantis/mantis_dma.c +++ b/drivers/media/pci/mantis/mantis_dma.c @@ -190,7 +190,7 @@ void mantis_dma_start(struct mantis_pci *mantis) mmwrite(0, MANTIS_DMA_CTL); mantis->last_block = mantis->busy_block = 0; - mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK); + mantis_unmask_ints(mantis, MANTIS_INT_RISCI); mmwrite(MANTIS_FIFO_EN | MANTIS_DCAP_EN | MANTIS_RISC_EN, MANTIS_DMA_CTL); @@ -209,8 +209,7 @@ void mantis_dma_stop(struct mantis_pci *mantis) mmwrite(mmread(MANTIS_INT_STAT), MANTIS_INT_STAT); - mmwrite(mmread(MANTIS_INT_MASK) & ~(MANTIS_INT_RISCI | - MANTIS_INT_RISCEN), MANTIS_INT_MASK); + mantis_mask_ints(mantis, MANTIS_INT_RISCI | MANTIS_INT_RISCEN); } diff --git a/drivers/media/pci/mantis/mantis_i2c.c b/drivers/media/pci/mantis/mantis_i2c.c index 895ddba..d72ee47 100644 --- a/drivers/media/pci/mantis/mantis_i2c.c +++ b/drivers/media/pci/mantis/mantis_i2c.c @@ -219,7 +219,7 @@ static struct i2c_algorithm mantis_algo = { int mantis_i2c_init(struct mantis_pci *mantis) { - u32 intstat, intmask; + u32 intstat; struct i2c_adapter *i2c_adapter = &mantis->adapter; struct pci_dev *pdev = mantis->pdev; @@ -242,11 +242,10 @@ int mantis_i2c_init(struct mantis_pci *mantis) dprintk(MANTIS_DEBUG, 1, "Initializing I2C .."); intstat = mmread(MANTIS_INT_STAT); - intmask = mmread(MANTIS_INT_MASK); + mmread(MANTIS_INT_MASK); mmwrite(intstat, MANTIS_INT_STAT); dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); - intmask = mmread(MANTIS_INT_MASK); - mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK); + mantis_mask_ints(mantis, MANTIS_INT_I2CDONE); return 0; } @@ -254,11 +253,8 @@ EXPORT_SYMBOL_GPL(mantis_i2c_init); int mantis_i2c_exit(struct mantis_pci *mantis) { - u32 intmask; - dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); - intmask = mmread(MANTIS_INT_MASK); - mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK); + mantis_mask_ints(mantis, MANTIS_INT_I2CDONE); dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter"); i2c_del_adapter(&mantis->adapter); diff --git a/drivers/media/pci/mantis/mantis_input.c b/drivers/media/pci/mantis/mantis_input.c index 0e5252e..7f7f1d4 100644 --- a/drivers/media/pci/mantis/mantis_input.c +++ b/drivers/media/pci/mantis/mantis_input.c @@ -12,14 +12,8 @@ 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. */ -#if 0 /* Currently unused */ - #include <media/rc-core.h> #include <linux/pci.h> @@ -30,100 +24,32 @@ #include "dvb_net.h" #include "mantis_common.h" -#include "mantis_reg.h" -#include "mantis_uart.h" +#include "mantis_input.h" #define MODULE_NAME "mantis_core" -#define RC_MAP_MANTIS "rc-mantis" - -static struct rc_map_table mantis_ir_table[] = { - { 0x29, KEY_POWER }, - { 0x28, KEY_FAVORITES }, - { 0x30, KEY_TEXT }, - { 0x17, KEY_INFO }, /* Preview */ - { 0x23, KEY_EPG }, - { 0x3b, KEY_F22 }, /* Record List */ - { 0x3c, KEY_1 }, - { 0x3e, KEY_2 }, - { 0x39, KEY_3 }, - { 0x36, KEY_4 }, - { 0x22, KEY_5 }, - { 0x20, KEY_6 }, - { 0x32, KEY_7 }, - { 0x26, KEY_8 }, - { 0x24, KEY_9 }, - { 0x2a, KEY_0 }, - - { 0x33, KEY_CANCEL }, - { 0x2c, KEY_BACK }, - { 0x15, KEY_CLEAR }, - { 0x3f, KEY_TAB }, - { 0x10, KEY_ENTER }, - { 0x14, KEY_UP }, - { 0x0d, KEY_RIGHT }, - { 0x0e, KEY_DOWN }, - { 0x11, KEY_LEFT }, - - { 0x21, KEY_VOLUMEUP }, - { 0x35, KEY_VOLUMEDOWN }, - { 0x3d, KEY_CHANNELDOWN }, - { 0x3a, KEY_CHANNELUP }, - { 0x2e, KEY_RECORD }, - { 0x2b, KEY_PLAY }, - { 0x13, KEY_PAUSE }, - { 0x25, KEY_STOP }, - - { 0x1f, KEY_REWIND }, - { 0x2d, KEY_FASTFORWARD }, - { 0x1e, KEY_PREVIOUS }, /* Replay |< */ - { 0x1d, KEY_NEXT }, /* Skip >| */ - - { 0x0b, KEY_CAMERA }, /* Capture */ - { 0x0f, KEY_LANGUAGE }, /* SAP */ - { 0x18, KEY_MODE }, /* PIP */ - { 0x12, KEY_ZOOM }, /* Full screen */ - { 0x1c, KEY_SUBTITLE }, - { 0x2f, KEY_MUTE }, - { 0x16, KEY_F20 }, /* L/R */ - { 0x38, KEY_F21 }, /* Hibernate */ - - { 0x37, KEY_SWITCHVIDEOMODE }, /* A/V */ - { 0x31, KEY_AGAIN }, /* Recall */ - { 0x1a, KEY_KPPLUS }, /* Zoom+ */ - { 0x19, KEY_KPMINUS }, /* Zoom- */ - { 0x27, KEY_RED }, - { 0x0C, KEY_GREEN }, - { 0x01, KEY_YELLOW }, - { 0x00, KEY_BLUE }, -}; - -static struct rc_map_list ir_mantis_map = { - .map = { - .scan = mantis_ir_table, - .size = ARRAY_SIZE(mantis_ir_table), - .rc_type = RC_TYPE_UNKNOWN, - .name = RC_MAP_MANTIS, - } -}; + +void mantis_input_process(struct mantis_pci *mantis, int scancode) +{ + if (mantis->rc) + rc_keydown(mantis->rc, RC_TYPE_UNKNOWN, scancode, 0); +} int mantis_input_init(struct mantis_pci *mantis) { struct rc_dev *dev; int err; - err = rc_map_register(&ir_mantis_map); - if (err) - goto out; - dev = rc_allocate_device(); if (!dev) { dprintk(MANTIS_ERROR, 1, "Remote device allocation failed"); err = -ENOMEM; - goto out_map; + goto out; } - sprintf(mantis->input_name, "Mantis %s IR receiver", mantis->hwconfig->model_name); - sprintf(mantis->input_phys, "pci-%s/ir0", pci_name(mantis->pdev)); + snprintf(mantis->input_name, sizeof(mantis->input_name), + "Mantis %s IR receiver", mantis->hwconfig->model_name); + snprintf(mantis->input_phys, sizeof(mantis->input_phys), + "pci-%s/ir0", pci_name(mantis->pdev)); dev->input_name = mantis->input_name; dev->input_phys = mantis->input_phys; @@ -132,7 +58,7 @@ int mantis_input_init(struct mantis_pci *mantis) dev->input_id.product = mantis->device_id; dev->input_id.version = 1; dev->driver_name = MODULE_NAME; - dev->map_name = RC_MAP_MANTIS; + dev->map_name = mantis->rc_map_name ? : RC_MAP_EMPTY; dev->dev.parent = &mantis->pdev->dev; err = rc_register_device(dev); @@ -146,17 +72,13 @@ int mantis_input_init(struct mantis_pci *mantis) out_dev: rc_free_device(dev); -out_map: - rc_map_unregister(&ir_mantis_map); out: return err; } +EXPORT_SYMBOL_GPL(mantis_input_init); -int mantis_init_exit(struct mantis_pci *mantis) +void mantis_input_exit(struct mantis_pci *mantis) { rc_unregister_device(mantis->rc); - rc_map_unregister(&ir_mantis_map); - return 0; } - -#endif +EXPORT_SYMBOL_GPL(mantis_input_exit); diff --git a/drivers/media/pci/mantis/mantis_input.h b/drivers/media/pci/mantis/mantis_input.h new file mode 100644 index 0000000..0fbd929 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_input.h @@ -0,0 +1,24 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +*/ + +#ifndef __MANTIS_INPUT_H +#define __MANTIS_INPUT_H + +int mantis_input_init(struct mantis_pci *mantis); +void mantis_input_exit(struct mantis_pci *mantis); +void mantis_input_process(struct mantis_pci *mantis, int scancode); + +#endif /* __MANTIS_UART_H */ diff --git a/drivers/media/pci/mantis/mantis_pcmcia.c b/drivers/media/pci/mantis/mantis_pcmcia.c index 2f188c0..b2dbc7b 100644 --- a/drivers/media/pci/mantis/mantis_pcmcia.c +++ b/drivers/media/pci/mantis/mantis_pcmcia.c @@ -89,7 +89,7 @@ int mantis_pcmcia_init(struct mantis_ca *ca) u32 gpif_stat, card_stat; - mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_IRQ0, MANTIS_INT_MASK); + mantis_unmask_ints(mantis, MANTIS_INT_IRQ0); gpif_stat = mmread(MANTIS_GPIF_STATUS); card_stat = mmread(MANTIS_GPIF_IRQCFG); @@ -117,5 +117,5 @@ void mantis_pcmcia_exit(struct mantis_ca *ca) struct mantis_pci *mantis = ca->ca_priv; mmwrite(mmread(MANTIS_GPIF_STATUS) & (~MANTIS_CARD_PLUGOUT | ~MANTIS_CARD_PLUGIN), MANTIS_GPIF_STATUS); - mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ0, MANTIS_INT_MASK); + mantis_mask_ints(mantis, MANTIS_INT_IRQ0); } diff --git a/drivers/media/pci/mantis/mantis_uart.c b/drivers/media/pci/mantis/mantis_uart.c index a707192..f1c96ae 100644 --- a/drivers/media/pci/mantis/mantis_uart.c +++ b/drivers/media/pci/mantis/mantis_uart.c @@ -25,6 +25,7 @@ #include <linux/signal.h> #include <linux/sched.h> #include <linux/interrupt.h> +#include <linux/pci.h> #include "dmxdev.h" #include "dvbdev.h" @@ -35,6 +36,7 @@ #include "mantis_common.h" #include "mantis_reg.h" #include "mantis_uart.h" +#include "mantis_input.h" struct mantis_uart_params { enum mantis_baud baud_rate; @@ -59,51 +61,54 @@ static struct { { "EVEN" } }; -#define UART_MAX_BUF 16 - -static int mantis_uart_read(struct mantis_pci *mantis, u8 *data) +static void mantis_uart_read(struct mantis_pci *mantis) { struct mantis_hwconfig *config = mantis->hwconfig; - u32 stat = 0, i; + int i, scancode = 0, err = 0; /* get data */ + dprintk(MANTIS_DEBUG, 1, "UART Reading ..."); for (i = 0; i < (config->bytes + 1); i++) { + int data = mmread(MANTIS_UART_RXD); - stat = mmread(MANTIS_UART_STAT); - - if (stat & MANTIS_UART_RXFIFO_FULL) { - dprintk(MANTIS_ERROR, 1, "RX Fifo FULL"); - } - data[i] = mmread(MANTIS_UART_RXD) & 0x3f; + dprintk(MANTIS_DEBUG, 0, " <%02x>", data); - dprintk(MANTIS_DEBUG, 1, "Reading ... <%02x>", data[i] & 0x3f); + scancode = (scancode << 8) | (data & 0x3f); + err |= data; - if (data[i] & (1 << 7)) { + if (data & (1 << 7)) dprintk(MANTIS_ERROR, 1, "UART framing error"); - return -EINVAL; - } - if (data[i] & (1 << 6)) { + + if (data & (1 << 6)) dprintk(MANTIS_ERROR, 1, "UART parity error"); - return -EINVAL; - } } + dprintk(MANTIS_DEBUG, 0, "\n"); - return 0; + if ((err & 0xC0) == 0) + mantis_input_process(mantis, scancode); } static void mantis_uart_work(struct work_struct *work) { struct mantis_pci *mantis = container_of(work, struct mantis_pci, uart_work); - struct mantis_hwconfig *config = mantis->hwconfig; - u8 buf[16]; - int i; + u32 stat; - mantis_uart_read(mantis, buf); + stat = mmread(MANTIS_UART_STAT); - for (i = 0; i < (config->bytes + 1); i++) - dprintk(MANTIS_INFO, 1, "UART BUF:%d <%02x> ", i, buf[i]); + if (stat & MANTIS_UART_RXFIFO_FULL) + dprintk(MANTIS_ERROR, 1, "RX Fifo FULL"); - dprintk(MANTIS_DEBUG, 0, "\n"); + /* + * MANTIS_UART_RXFIFO_DATA is only set if at least + * config->bytes + 1 bytes are in the FIFO. + */ + while (stat & MANTIS_UART_RXFIFO_DATA) { + mantis_uart_read(mantis); + stat = mmread(MANTIS_UART_STAT); + } + + /* re-enable UART (RX) interrupt */ + mantis_unmask_ints(mantis, MANTIS_INT_IRQ1); } static int mantis_uart_setup(struct mantis_pci *mantis, @@ -152,9 +157,6 @@ int mantis_uart_init(struct mantis_pci *mantis) rates[params.baud_rate].string, parity[params.parity].string); - init_waitqueue_head(&mantis->uart_wq); - spin_lock_init(&mantis->uart_lock); - INIT_WORK(&mantis->uart_work, mantis_uart_work); /* disable interrupt */ @@ -169,8 +171,8 @@ int mantis_uart_init(struct mantis_pci *mantis) mmwrite((mmread(MANTIS_UART_CTL) | MANTIS_UART_RXFLUSH), MANTIS_UART_CTL); /* enable interrupt */ - mmwrite(mmread(MANTIS_INT_MASK) | 0x800, MANTIS_INT_MASK); mmwrite(mmread(MANTIS_UART_CTL) | MANTIS_UART_RXINT, MANTIS_UART_CTL); + mantis_unmask_ints(mantis, MANTIS_INT_IRQ1); schedule_work(&mantis->uart_work); dprintk(MANTIS_DEBUG, 1, "UART successfully initialized"); @@ -182,6 +184,7 @@ EXPORT_SYMBOL_GPL(mantis_uart_init); void mantis_uart_exit(struct mantis_pci *mantis) { /* disable interrupt */ + mantis_mask_ints(mantis, MANTIS_INT_IRQ1); mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL); flush_work(&mantis->uart_work); } diff --git a/drivers/media/pci/mantis/mantis_vp1034.c b/drivers/media/pci/mantis/mantis_vp1034.c index 7c1bd16..3b19285 100644 --- a/drivers/media/pci/mantis/mantis_vp1034.c +++ b/drivers/media/pci/mantis/mantis_vp1034.c @@ -44,7 +44,7 @@ static struct mb86a16_config vp1034_mb86a16_config = { #define MANTIS_MODEL_NAME "VP-1034" #define MANTIS_DEV_TYPE "DVB-S/DSS" -int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +int vp1034_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) { struct mantis_pci *mantis = fe->dvb->priv; diff --git a/drivers/media/pci/mantis/mantis_vp1034.h b/drivers/media/pci/mantis/mantis_vp1034.h index 323f38e..764b1c6 100644 --- a/drivers/media/pci/mantis/mantis_vp1034.h +++ b/drivers/media/pci/mantis/mantis_vp1034.h @@ -28,6 +28,7 @@ #define MANTIS_VP_1034_DVB_S 0x0014 extern struct mantis_hwconfig vp1034_config; -extern int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); +extern int vp1034_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage); #endif /* __MANTIS_VP1034_H */ diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index e29bc3af4..1b92d83 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -1526,10 +1526,12 @@ static int init_channel(struct ngene_channel *chan) if (chan->fe2) { if (dvb_register_frontend(adapter, chan->fe2) < 0) goto err; - chan->fe2->tuner_priv = chan->fe->tuner_priv; - memcpy(&chan->fe2->ops.tuner_ops, - &chan->fe->ops.tuner_ops, - sizeof(struct dvb_tuner_ops)); + if (chan->fe) { + chan->fe2->tuner_priv = chan->fe->tuner_priv; + memcpy(&chan->fe2->ops.tuner_ops, + &chan->fe->ops.tuner_ops, + sizeof(struct dvb_tuner_ops)); + } } if (chan->has_demux) { diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 51e2fbd..fa30930 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -682,7 +682,7 @@ struct ngene_channel { int AudioDTOUpdated; u32 AudioDTOValue; - int (*set_tone)(struct dvb_frontend *, fe_sec_tone_mode_t); + int (*set_tone)(struct dvb_frontend *, enum fe_sec_tone_mode); u8 lnbh; /* stuff from analog driver */ diff --git a/drivers/media/pci/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c index acc35b4..e7e4428 100644 --- a/drivers/media/pci/pt1/pt1.c +++ b/drivers/media/pci/pt1/pt1.c @@ -101,11 +101,11 @@ struct pt1_adapter { struct dmxdev dmxdev; struct dvb_frontend *fe; int (*orig_set_voltage)(struct dvb_frontend *fe, - fe_sec_voltage_t voltage); + enum fe_sec_voltage voltage); int (*orig_sleep)(struct dvb_frontend *fe); int (*orig_init)(struct dvb_frontend *fe); - fe_sec_voltage_t voltage; + enum fe_sec_voltage voltage; int sleep; }; @@ -575,7 +575,7 @@ pt1_update_power(struct pt1 *pt1) mutex_unlock(&pt1->lock); } -static int pt1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int pt1_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) { struct pt1_adapter *adap; diff --git a/drivers/media/pci/pt1/va1j5jf8007s.c b/drivers/media/pci/pt1/va1j5jf8007s.c index 1b637b7..d0e70dc0 100644 --- a/drivers/media/pci/pt1/va1j5jf8007s.c +++ b/drivers/media/pci/pt1/va1j5jf8007s.c @@ -108,7 +108,7 @@ static int va1j5jf8007s_get_frontend_algo(struct dvb_frontend *fe) } static int -va1j5jf8007s_read_status(struct dvb_frontend *fe, fe_status_t *status) +va1j5jf8007s_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct va1j5jf8007s_state *state; @@ -387,7 +387,7 @@ static int va1j5jf8007s_tune(struct dvb_frontend *fe, bool re_tune, unsigned int mode_flags, unsigned int *delay, - fe_status_t *status) + enum fe_status *status) { struct va1j5jf8007s_state *state; int ret; diff --git a/drivers/media/pci/pt1/va1j5jf8007t.c b/drivers/media/pci/pt1/va1j5jf8007t.c index 2db15159..0268f20 100644 --- a/drivers/media/pci/pt1/va1j5jf8007t.c +++ b/drivers/media/pci/pt1/va1j5jf8007t.c @@ -98,7 +98,7 @@ static int va1j5jf8007t_get_frontend_algo(struct dvb_frontend *fe) } static int -va1j5jf8007t_read_status(struct dvb_frontend *fe, fe_status_t *status) +va1j5jf8007t_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct va1j5jf8007t_state *state; @@ -266,7 +266,7 @@ static int va1j5jf8007t_tune(struct dvb_frontend *fe, bool re_tune, unsigned int mode_flags, unsigned int *delay, - fe_status_t *status) + enum fe_status *status) { struct va1j5jf8007t_state *state; int ret; diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c index 7a37e8f..0d2e2b2 100644 --- a/drivers/media/pci/pt3/pt3.c +++ b/drivers/media/pci/pt3/pt3.c @@ -188,7 +188,7 @@ static int pt3_set_lna(struct dvb_frontend *fe) return ret; } -static int pt3_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) +static int pt3_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage volt) { struct pt3_adapter *adap; struct pt3_board *pt3; diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c index ac3cd74..1d2c310 100644 --- a/drivers/media/pci/saa7134/saa7134-alsa.c +++ b/drivers/media/pci/saa7134/saa7134-alsa.c @@ -16,6 +16,9 @@ * */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/slab.h> #include <linux/time.h> @@ -29,13 +32,6 @@ #include <linux/interrupt.h> #include <linux/vmalloc.h> -#include "saa7134.h" -#include "saa7134-reg.h" - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"enable debug messages [alsa]"); - /* * Configuration macros */ @@ -57,11 +53,6 @@ module_param_array(enable, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for SAA7134 capture interface(s)."); MODULE_PARM_DESC(enable, "Enable (or not) the SAA7134 capture interface(s)."); -#define dprintk(fmt, arg...) if (debug) \ - printk(KERN_DEBUG "%s/alsa: " fmt, dev->name , ##arg) - - - /* * Main chip structure */ @@ -149,11 +140,11 @@ static void saa7134_irq_alsa_done(struct saa7134_dev *dev, spin_lock(&dev->slock); if (UNSET == dev->dmasound.dma_blk) { - dprintk("irq: recording stopped\n"); + pr_debug("irq: recording stopped\n"); goto done; } if (0 != (status & 0x0f000000)) - dprintk("irq: lost %ld\n", (status >> 24) & 0x0f); + pr_debug("irq: lost %ld\n", (status >> 24) & 0x0f); if (0 == (status & 0x10000000)) { /* odd */ if (0 == (dev->dmasound.dma_blk & 0x01)) @@ -164,13 +155,14 @@ static void saa7134_irq_alsa_done(struct saa7134_dev *dev, reg = SAA7134_RS_BA2(6); } if (0 == reg) { - dprintk("irq: field oops [%s]\n", + pr_debug("irq: field oops [%s]\n", (status & 0x10000000) ? "even" : "odd"); goto done; } if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) { - dprintk("irq: overrun [full=%d/%d] - Blocks in %d\n",dev->dmasound.read_count, + pr_debug("irq: overrun [full=%d/%d] - Blocks in %d\n", + dev->dmasound.read_count, dev->dmasound.bufsize, dev->dmasound.blocks); spin_unlock(&dev->slock); snd_pcm_stop_xrun(dev->dmasound.substream); @@ -180,10 +172,10 @@ static void saa7134_irq_alsa_done(struct saa7134_dev *dev, /* next block addr */ next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks; saa_writel(reg,next_blk * dev->dmasound.blksize); - if (debug > 2) - dprintk("irq: ok, %s, next_blk=%d, addr=%x, blocks=%u, size=%u, read=%u\n", - (status & 0x10000000) ? "even" : "odd ", next_blk, - next_blk * dev->dmasound.blksize, dev->dmasound.blocks, dev->dmasound.blksize, dev->dmasound.read_count); + pr_debug("irq: ok, %s, next_blk=%d, addr=%x, blocks=%u, size=%u, read=%u\n", + (status & 0x10000000) ? "even" : "odd ", next_blk, + next_blk * dev->dmasound.blksize, dev->dmasound.blocks, + dev->dmasound.blksize, dev->dmasound.read_count); /* update status & wake waiting readers */ dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks; @@ -233,7 +225,7 @@ static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id) } if (loop == 10) { - dprintk("error! looping IRQ!"); + pr_debug("error! looping IRQ!"); } out: @@ -281,11 +273,11 @@ static int saa7134_alsa_dma_init(struct saa7134_dev *dev, int nr_pages) dma->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT); if (NULL == dma->vaddr) { - dprintk("vmalloc_32(%d pages) failed\n", nr_pages); + pr_debug("vmalloc_32(%d pages) failed\n", nr_pages); return -ENOMEM; } - dprintk("vmalloc is at addr 0x%08lx, size=%d\n", + pr_debug("vmalloc is at addr 0x%08lx, size=%d\n", (unsigned long)dma->vaddr, nr_pages << PAGE_SHIFT); @@ -572,7 +564,7 @@ static int snd_card_saa7134_capture_prepare(struct snd_pcm_substream * substream break; } - dprintk("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n", + pr_debug("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n", runtime->format, runtime->channels, fmt, bswap ? 'b' : '-'); /* dma: setup channel 6 (= AUDIO) */ @@ -821,7 +813,7 @@ static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream) int amux, err; if (!saa7134) { - printk(KERN_ERR "BUG: saa7134 can't find device struct." + pr_err("BUG: saa7134 can't find device struct." " Can't proceed with open\n"); return -ENODEV; } @@ -1175,7 +1167,7 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum) (void*) &dev->dmasound); if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d for ALSA\n", + pr_err("%s: can't get IRQ %d for ALSA\n", dev->name, dev->pci->irq); goto __nodev; } @@ -1196,7 +1188,8 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum) sprintf(card->longname, "%s at 0x%lx irq %d", chip->dev->name, chip->iobase, chip->irq); - printk(KERN_INFO "%s/alsa: %s registered as card %d\n",dev->name,card->longname,index[devnum]); + pr_info("%s/alsa: %s registered as card %d\n", + dev->name, card->longname, index[devnum]); if ((err = snd_card_register(card)) == 0) { snd_saa7134_cards[devnum] = card; @@ -1240,19 +1233,19 @@ static int saa7134_alsa_init(void) saa7134_dmasound_init = alsa_device_init; saa7134_dmasound_exit = alsa_device_exit; - printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n"); + pr_info("saa7134 ALSA driver for DMA sound loaded\n"); list_for_each(list,&saa7134_devlist) { dev = list_entry(list, struct saa7134_dev, devlist); if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130) - printk(KERN_INFO "%s/alsa: %s doesn't support digital audio\n", + pr_info("%s/alsa: %s doesn't support digital audio\n", dev->name, saa7134_boards[dev->board].name); else alsa_device_init(dev); } if (dev == NULL) - printk(KERN_INFO "saa7134 ALSA: no saa7134 cards found\n"); + pr_info("saa7134 ALSA: no saa7134 cards found\n"); return 0; @@ -1272,7 +1265,7 @@ static void saa7134_alsa_exit(void) saa7134_dmasound_init = NULL; saa7134_dmasound_exit = NULL; - printk(KERN_INFO "saa7134 ALSA driver for DMA sound unloaded\n"); + pr_info("saa7134 ALSA driver for DMA sound unloaded\n"); return; } diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c index 3ca0780..c740576 100644 --- a/drivers/media/pci/saa7134/saa7134-cards.c +++ b/drivers/media/pci/saa7134/saa7134-cards.c @@ -20,13 +20,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/module.h> #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> -#include "saa7134-reg.h" -#include "saa7134.h" #include "tuner-xc2028.h" #include <media/v4l2-common.h> #include <media/tveeprom.h> @@ -5850,6 +5851,39 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, } }, }, + [SAA7134_BOARD_AVERMEDIA_505] = { + /* much like the "studio" version but without radio + * and another tuner (dbaryshkov@gmail.com) */ + .name = "AverMedia AverTV/505", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FQ1216ME, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + }, { + .name = name_comp2, + .vmux = 3, + .amux = LINE2, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + } }, + .mute = { + .name = name_mute, + .amux = LINE1, + }, + }, }; @@ -7109,6 +7143,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0x7007, .driver_data = SAA7134_BOARD_WIS_VOYAGER, }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0xa10a, + .driver_data = SAA7134_BOARD_AVERMEDIA_505, + }, { /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -7158,10 +7198,10 @@ MODULE_DEVICE_TABLE(pci, saa7134_pci_tbl); static void board_flyvideo(struct saa7134_dev *dev) { - printk("%s: there are different flyvideo cards with different tuners\n" - "%s: out there, you might have to use the tuner=<nr> insmod\n" - "%s: option to override the default value.\n", - dev->name, dev->name, dev->name); + pr_warn("%s: there are different flyvideo cards with different tuners\n" + "%s: out there, you might have to use the tuner=<nr> insmod\n" + "%s: option to override the default value.\n", + dev->name, dev->name, dev->name); } static int saa7134_xc2028_callback(struct saa7134_dev *dev, @@ -7194,7 +7234,7 @@ static int saa7134_xc2028_callback(struct saa7134_dev *dev, saa7134_set_gpio(dev, 20, 1); break; } - return 0; + return 0; } return -EINVAL; } @@ -7380,7 +7420,7 @@ int saa7134_tuner_callback(void *priv, int component, int command, int arg) return saa7134_xc5000_callback(dev, command, arg); } } else { - printk(KERN_ERR "saa7134: Error - device struct undefined.\n"); + pr_err("saa7134: Error - device struct undefined.\n"); return -EINVAL; } return -EINVAL; @@ -7411,12 +7451,12 @@ static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data) case 67659: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ break; default: - printk(KERN_WARNING "%s: warning: " + pr_warn("%s: warning: " "unknown hauppauge model #%d\n", dev->name, tv.model); break; } - printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", + pr_info("%s: hauppauge eeprom: model=%d\n", dev->name, tv.model); } @@ -7427,7 +7467,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) /* Always print gpio, often manufacturers encode tuner type and other info. */ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0); dev->gpio_value = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); - printk(KERN_INFO "%s: board init: gpio is %x\n", dev->name, dev->gpio_value); + pr_info("%s: board init: gpio is %x\n", dev->name, dev->gpio_value); switch (dev->board) { case SAA7134_BOARD_FLYVIDEO2000: @@ -7448,8 +7488,9 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_KWORLD_VSTREAM_XPERT: case SAA7134_BOARD_KWORLD_XPERT: case SAA7134_BOARD_AVERMEDIA_STUDIO_305: - case SAA7134_BOARD_AVERMEDIA_STUDIO_505: case SAA7134_BOARD_AVERMEDIA_305: + case SAA7134_BOARD_AVERMEDIA_STUDIO_505: + case SAA7134_BOARD_AVERMEDIA_505: case SAA7134_BOARD_AVERMEDIA_STUDIO_307: case SAA7134_BOARD_AVERMEDIA_307: case SAA7134_BOARD_AVERMEDIA_STUDIO_507: @@ -7512,10 +7553,10 @@ int saa7134_board_init1(struct saa7134_dev *dev) dev->has_remote = SAA7134_REMOTE_GPIO; break; case SAA7134_BOARD_MD5044: - printk("%s: seems there are two different versions of the MD5044\n" - "%s: (with the same ID) out there. If sound doesn't work for\n" - "%s: you try the audio_clock_override=0x200000 insmod option.\n", - dev->name,dev->name,dev->name); + pr_warn("%s: seems there are two different versions of the MD5044\n" + "%s: (with the same ID) out there. If sound doesn't work for\n" + "%s: you try the audio_clock_override=0x200000 insmod option.\n", + dev->name, dev->name, dev->name); break; case SAA7134_BOARD_CINERGY400_CARDBUS: /* power-up tuner chip */ @@ -7640,10 +7681,10 @@ int saa7134_board_init1(struct saa7134_dev *dev) dev->has_remote = SAA7134_REMOTE_I2C; break; case SAA7134_BOARD_AVERMEDIA_A169_B: - printk("%s: %s: dual saa713x broadcast decoders\n" - "%s: Sorry, none of the inputs to this chip are supported yet.\n" - "%s: Dual decoder functionality is disabled for now, use the other chip.\n", - dev->name,card(dev).name,dev->name,dev->name); + pr_warn("%s: %s: dual saa713x broadcast decoders\n" + "%s: Sorry, none of the inputs to this chip are supported yet.\n" + "%s: Dual decoder functionality is disabled for now, use the other chip.\n", + dev->name, card(dev).name, dev->name, dev->name); break; case SAA7134_BOARD_AVERMEDIA_M102: /* enable tuner */ @@ -7789,7 +7830,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) if (board == dev->board) break; dev->board = board; - printk("%s: board type fixup: %s\n", dev->name, + pr_warn("%s: board type fixup: %s\n", dev->name, saa7134_boards[dev->board].name); dev->tuner_type = saa7134_boards[dev->board].tuner_type; @@ -7797,10 +7838,11 @@ int saa7134_board_init2(struct saa7134_dev *dev) case SAA7134_BOARD_MD7134: { u8 subaddr; - u8 data[3]; + u8 data[3], data1[] = { 0x09, 0x9f, 0x86, 0x11}; int ret, tuner_t; - struct i2c_msg msg[] = {{.addr=0x50, .flags=0, .buf=&subaddr, .len = 1}, - {.addr=0x50, .flags=I2C_M_RD, .buf=data, .len = 3}}; + struct i2c_msg msg[] = {{.addr = 0x50, .flags = 0, .buf = &subaddr, .len = 1}, + {.addr = 0x50, .flags = I2C_M_RD, .buf = data, .len = 3}}, + msg1 = {.addr = 0x61, .flags = 0, .buf = data1, .len = sizeof(data1)}; subaddr= 0x14; tuner_t = 0; @@ -7810,7 +7852,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) */ ret = i2c_transfer(&dev->i2c_adap, msg, 2); if (ret != 2) { - printk(KERN_ERR "EEPROM read failure\n"); + pr_err("EEPROM read failure\n"); } else if ((data[0] != 0) && (data[0] != 0xff)) { /* old config structure */ subaddr = data[0] + 2; @@ -7825,7 +7867,8 @@ int saa7134_board_init2(struct saa7134_dev *dev) dev->tuner_type = TUNER_PHILIPS_FM1216ME_MK3; break; default: - printk(KERN_ERR "%s Can't determine tuner type %x from EEPROM\n", dev->name, tuner_t); + pr_err("%s Can't determine tuner type %x from EEPROM\n", + dev->name, tuner_t); } } else if ((data[1] != 0) && (data[1] != 0xff)) { /* new config structure */ @@ -7842,16 +7885,28 @@ int saa7134_board_init2(struct saa7134_dev *dev) break; case 0x001d: dev->tuner_type = TUNER_PHILIPS_FMD1216ME_MK3; - printk(KERN_INFO "%s Board has DVB-T\n", dev->name); + pr_info("%s Board has DVB-T\n", + dev->name); break; default: - printk(KERN_ERR "%s Can't determine tuner type %x from EEPROM\n", dev->name, tuner_t); + pr_err("%s Can't determine tuner type %x from EEPROM\n", + dev->name, tuner_t); } } else { - printk(KERN_ERR "%s unexpected config structure\n", dev->name); + pr_err("%s unexpected config structure\n", dev->name); } - printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type); + pr_info("%s Tuner type is %d\n", dev->name, dev->tuner_type); + + /* The tuner TUNER_PHILIPS_FMD1216ME_MK3 after hardware */ + /* start has disabled IF and enabled DVB-T. When saa7134 */ + /* scan I2C devices it will not detect IF tda9887 and can`t*/ + /* watch TV without software reboot. To solve this problem */ + /* switch the tuner to analog TV mode manually. */ + if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) { + if (i2c_transfer(&dev->i2c_adap, &msg1, 1) != 1) + printk(KERN_WARNING "%s: Unable to enable IF of the tuner.\n", dev->name); + } break; } case SAA7134_BOARD_PHILIPS_EUROPA: @@ -7859,7 +7914,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) /* Reconfigure board as Snake reference design */ dev->board = SAA7134_BOARD_PHILIPS_SNAKE; dev->tuner_type = saa7134_boards[dev->board].tuner_type; - printk(KERN_INFO "%s: Reconfigured board as %s\n", + pr_info("%s: Reconfigured board as %s\n", dev->name, saa7134_boards[dev->board].name); break; } @@ -7887,7 +7942,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; if (dev->autodetected && (dev->eedata[0x49] == 0x50)) { dev->board = SAA7134_BOARD_PHILIPS_TIGER_S; - printk(KERN_INFO "%s: Reconfigured board as %s\n", + pr_info("%s: Reconfigured board as %s\n", dev->name, saa7134_boards[dev->board].name); } if (dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) { @@ -7903,13 +7958,14 @@ int saa7134_board_init2(struct saa7134_dev *dev) case SAA7134_BOARD_ASUSTeK_TVFM7135: /* The card below is detected as card=53, but is different */ if (dev->autodetected && (dev->eedata[0x27] == 0x03)) { - dev->board = SAA7134_BOARD_ASUSTeK_P7131_ANALOG; - printk(KERN_INFO "%s: P7131 analog only, using " - "entry of %s\n", - dev->name, saa7134_boards[dev->board].name); + dev->board = SAA7134_BOARD_ASUSTeK_P7131_ANALOG; + pr_info("%s: P7131 analog only, using entry of %s\n", + dev->name, saa7134_boards[dev->board].name); - /* IR init has already happened for other cards, so - * we have to catch up. */ + /* + * IR init has already happened for other cards, so + * we have to catch up. + */ dev->has_remote = SAA7134_REMOTE_GPIO; saa7134_input_init1(dev); } @@ -7972,12 +8028,12 @@ int saa7134_board_init2(struct saa7134_dev *dev) msg.addr = 0x0b; msg.len = 1; if (1 != i2c_transfer(&dev->i2c_adap, &msg, 1)) { - printk(KERN_WARNING "%s: send wake up byte to pic16C505" + pr_warn("%s: send wake up byte to pic16C505" "(IR chip) failed\n", dev->name); } else { msg.flags = I2C_M_RD; rc = i2c_transfer(&dev->i2c_adap, &msg, 1); - printk(KERN_INFO "%s: probe IR chip @ i2c 0x%02x: %s\n", + pr_info("%s: probe IR chip @ i2c 0x%02x: %s\n", dev->name, msg.addr, (1 == rc) ? "yes" : "no"); if (rc == 1) @@ -8018,10 +8074,10 @@ int saa7134_board_init2(struct saa7134_dev *dev) dev->board = SAA7134_BOARD_VIDEOMATE_DVBT_200A; dev->tuner_type = saa7134_boards[dev->board].tuner_type; dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf; - printk(KERN_INFO "%s: Reconfigured board as %s\n", + pr_info("%s: Reconfigured board as %s\n", dev->name, saa7134_boards[dev->board].name); } else { - printk(KERN_WARNING "%s: Unexpected tuner type info: %x in eeprom\n", + pr_warn("%s: Unexpected tuner type info: %x in eeprom\n", dev->name, dev->eedata[0x41]); break; } @@ -8043,9 +8099,8 @@ int saa7134_board_init2(struct saa7134_dev *dev) msg.buf = &buffer[i][0]; msg.len = ARRAY_SIZE(buffer[0]); if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) - printk(KERN_WARNING - "%s: Unable to enable tuner(%i).\n", - dev->name, i); + pr_warn("%s: Unable to enable tuner(%i).\n", + dev->name, i); } break; } @@ -8061,9 +8116,8 @@ int saa7134_board_init2(struct saa7134_dev *dev) /* watch TV without software reboot. For solve this problem */ /* switch the tuner to analog TV mode manually. */ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) - printk(KERN_WARNING - "%s: Unable to enable IF of the tuner.\n", - dev->name); + pr_warn("%s: Unable to enable IF of the tuner.\n", + dev->name); break; } case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index a349e96..72d7f99 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/list.h> #include <linux/module.h> @@ -33,9 +36,6 @@ #include <linux/dma-mapping.h> #include <linux/pm.h> -#include "saa7134-reg.h" -#include "saa7134.h" - MODULE_DESCRIPTION("v4l2 driver module for saa7130/34 based TV cards"); MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); MODULE_LICENSE("GPL"); @@ -102,8 +102,15 @@ static unsigned int saa7134_devcount; int (*saa7134_dmasound_init)(struct saa7134_dev *dev); int (*saa7134_dmasound_exit)(struct saa7134_dev *dev); -#define dprintk(fmt, arg...) if (core_debug) \ - printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg) +#define core_dbg(fmt, arg...) do { \ + if (core_debug) \ + printk(KERN_DEBUG pr_fmt("core: " fmt), ## arg); \ + } while (0) + +#define irq_dbg(level, fmt, arg...) do {\ + if (irq_debug > level) \ + printk(KERN_DEBUG pr_fmt("irq: " fmt), ## arg); \ + } while (0) void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) { @@ -116,8 +123,7 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,SAA7134_GPIO_GPRESCAN); mode = saa_readl(SAA7134_GPIO_GPMODE0 >> 2) & 0xfffffff; status = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & 0xfffffff; - printk(KERN_DEBUG - "%s: gpio: mode=0x%07lx in=0x%07lx out=0x%07lx [%s]\n", + core_dbg("%s: gpio: mode=0x%07lx in=0x%07lx out=0x%07lx [%s]\n", dev->name, mode, (~mode) & status, mode & status, msg); } @@ -128,7 +134,8 @@ void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value) index = 1 << bit_no; switch (value) { case 0: /* static value */ - case 1: dprintk("setting GPIO%d to static %d\n", bit_no, value); + case 1: + core_dbg("setting GPIO%d to static %d\n", bit_no, value); /* turn sync mode off if necessary */ if (index & 0x00c00000) saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x00); @@ -140,7 +147,7 @@ void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value) saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, index, bitval); break; case 3: /* tristate */ - dprintk("setting GPIO%d to tristate\n", bit_no); + core_dbg("setting GPIO%d to tristate\n", bit_no); saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, 0); break; } @@ -274,7 +281,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev, unsigned long flags; spin_lock_irqsave(&dev->slock, flags); - dprintk("buffer_queue %p\n", buf); + core_dbg("buffer_queue %p\n", buf); if (NULL == q->curr) { if (!q->need_two) { q->curr = buf; @@ -298,7 +305,7 @@ void saa7134_buffer_finish(struct saa7134_dev *dev, struct saa7134_dmaqueue *q, unsigned int state) { - dprintk("buffer_finish %p\n", q->curr); + core_dbg("buffer_finish %p\n", q->curr); /* finish current buffer */ v4l2_get_timestamp(&q->curr->vb2.v4l2_buf.timestamp); @@ -318,18 +325,18 @@ void saa7134_buffer_next(struct saa7134_dev *dev, if (!list_empty(&q->queue)) { /* activate next one from queue */ buf = list_entry(q->queue.next, struct saa7134_buf, entry); - dprintk("buffer_next %p [prev=%p/next=%p]\n", + core_dbg("buffer_next %p [prev=%p/next=%p]\n", buf, q->queue.prev, q->queue.next); list_del(&buf->entry); if (!list_empty(&q->queue)) next = list_entry(q->queue.next, struct saa7134_buf, entry); q->curr = buf; buf->activate(dev, buf, next); - dprintk("buffer_next #2 prev=%p/next=%p\n", + core_dbg("buffer_next #2 prev=%p/next=%p\n", q->queue.prev, q->queue.next); } else { /* nothing to do -- just stop DMA */ - dprintk("buffer_next %p\n", NULL); + core_dbg("buffer_next %p\n", NULL); saa7134_set_dmabits(dev); del_timer(&q->timeout); } @@ -351,7 +358,7 @@ void saa7134_buffer_timeout(unsigned long data) /* flag current buffer as failed, try to start over with the next one. */ if (q->curr) { - dprintk("timeout on %p\n", q->curr); + core_dbg("timeout on %p\n", q->curr); saa7134_buffer_finish(dev, q, VB2_BUF_STATE_ERROR); } saa7134_buffer_next(dev, q); @@ -474,7 +481,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev) SAA7134_MAIN_CTRL_TE5 | SAA7134_MAIN_CTRL_TE6, ctrl); - dprintk("dmabits: task=0x%02x ctrl=0x%02x irq=0x%x split=%s\n", + core_dbg("dmabits: task=0x%02x ctrl=0x%02x irq=0x%x split=%s\n", task, ctrl, irq, split ? "no" : "yes"); return 0; @@ -496,21 +503,21 @@ static void print_irqstatus(struct saa7134_dev *dev, int loop, { unsigned int i; - printk(KERN_DEBUG "%s/irq[%d,%ld]: r=0x%lx s=0x%02lx", - dev->name,loop,jiffies,report,status); + irq_dbg(1, "[%d,%ld]: r=0x%lx s=0x%02lx", + loop, jiffies, report, status); for (i = 0; i < IRQBITS; i++) { if (!(report & (1 << i))) continue; - printk(" %s",irqbits[i]); + pr_cont(" %s", irqbits[i]); } if (report & SAA7134_IRQ_REPORT_DONE_RA0) { - printk(" | RA0=%s,%s,%s,%ld", - (status & 0x40) ? "vbi" : "video", - (status & 0x20) ? "b" : "a", - (status & 0x10) ? "odd" : "even", - (status & 0x0f)); + pr_cont(" | RA0=%s,%s,%s,%ld", + (status & 0x40) ? "vbi" : "video", + (status & 0x20) ? "b" : "a", + (status & 0x10) ? "odd" : "even", + (status & 0x0f)); } - printk("\n"); + pr_cont("\n"); } static irqreturn_t saa7134_irq(int irq, void *dev_id) @@ -532,16 +539,12 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id) if ((report & SAA7134_IRQ_REPORT_DONE_RA3) && (dev->dmasound.priv_data != NULL) ) { - if (irq_debug > 1) - printk(KERN_DEBUG "%s/irq: preserving DMA sound interrupt\n", - dev->name); + irq_dbg(2, "preserving DMA sound interrupt\n"); report &= ~SAA7134_IRQ_REPORT_DONE_RA3; } if (0 == report) { - if (irq_debug > 1) - printk(KERN_DEBUG "%s/irq: no (more) work\n", - dev->name); + irq_dbg(2, "no (more) work\n"); goto out; } @@ -614,24 +617,24 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id) print_irqstatus(dev,loop,report,status); if (report & SAA7134_IRQ_REPORT_PE) { /* disable all parity error */ - printk(KERN_WARNING "%s/irq: looping -- " + pr_warn("%s/irq: looping -- " "clearing PE (parity error!) enable bit\n",dev->name); saa_clearl(SAA7134_IRQ2,SAA7134_IRQ2_INTE_PE); } else if (report & SAA7134_IRQ_REPORT_GPIO16) { /* disable gpio16 IRQ */ - printk(KERN_WARNING "%s/irq: looping -- " + pr_warn("%s/irq: looping -- " "clearing GPIO16 enable bit\n",dev->name); saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16_P); saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16_N); } else if (report & SAA7134_IRQ_REPORT_GPIO18) { /* disable gpio18 IRQs */ - printk(KERN_WARNING "%s/irq: looping -- " + pr_warn("%s/irq: looping -- " "clearing GPIO18 enable bit\n",dev->name); saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_P); saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_N); } else { /* disable all irqs */ - printk(KERN_WARNING "%s/irq: looping -- " + pr_warn("%s/irq: looping -- " "clearing all enable bits\n",dev->name); saa_writel(SAA7134_IRQ1,0); saa_writel(SAA7134_IRQ2,0); @@ -680,7 +683,7 @@ static int saa7134_hw_enable1(struct saa7134_dev *dev) static int saa7134_hwinit1(struct saa7134_dev *dev) { - dprintk("hwinit1\n"); + core_dbg("hwinit1\n"); saa_writel(SAA7134_IRQ1, 0); saa_writel(SAA7134_IRQ2, 0); @@ -742,7 +745,7 @@ static int saa7134_hw_enable2(struct saa7134_dev *dev) static int saa7134_hwinit2(struct saa7134_dev *dev) { - dprintk("hwinit2\n"); + core_dbg("hwinit2\n"); saa7134_video_init2(dev); saa7134_tvaudio_init2(dev); @@ -756,7 +759,7 @@ static int saa7134_hwinit2(struct saa7134_dev *dev) /* shutdown */ static int saa7134_hwfini(struct saa7134_dev *dev) { - dprintk("hwfini\n"); + core_dbg("hwfini\n"); if (card_has_mpeg(dev)) saa7134_ts_fini(dev); @@ -772,34 +775,32 @@ static void must_configure_manually(int has_eeprom) unsigned int i,p; if (!has_eeprom) - printk(KERN_WARNING - "saa7134: <rant>\n" - "saa7134: Congratulations! Your TV card vendor saved a few\n" - "saa7134: cents for a eeprom, thus your pci board has no\n" - "saa7134: subsystem ID and I can't identify it automatically\n" - "saa7134: </rant>\n" - "saa7134: I feel better now. Ok, here are the good news:\n" - "saa7134: You can use the card=<nr> insmod option to specify\n" - "saa7134: which board do you have. The list:\n"); + pr_warn("saa7134: <rant>\n" + "saa7134: Congratulations! Your TV card vendor saved a few\n" + "saa7134: cents for a eeprom, thus your pci board has no\n" + "saa7134: subsystem ID and I can't identify it automatically\n" + "saa7134: </rant>\n" + "saa7134: I feel better now. Ok, here are the good news:\n" + "saa7134: You can use the card=<nr> insmod option to specify\n" + "saa7134: which board do you have. The list:\n"); else - printk(KERN_WARNING - "saa7134: Board is currently unknown. You might try to use the card=<nr>\n" - "saa7134: insmod option to specify which board do you have, but this is\n" - "saa7134: somewhat risky, as might damage your card. It is better to ask\n" - "saa7134: for support at linux-media@vger.kernel.org.\n" - "saa7134: The supported cards are:\n"); + pr_warn("saa7134: Board is currently unknown. You might try to use the card=<nr>\n" + "saa7134: insmod option to specify which board do you have, but this is\n" + "saa7134: somewhat risky, as might damage your card. It is better to ask\n" + "saa7134: for support at linux-media@vger.kernel.org.\n" + "saa7134: The supported cards are:\n"); for (i = 0; i < saa7134_bcount; i++) { - printk(KERN_WARNING "saa7134: card=%d -> %-40.40s", + pr_warn("saa7134: card=%d -> %-40.40s", i,saa7134_boards[i].name); for (p = 0; saa7134_pci_tbl[p].driver_data; p++) { if (saa7134_pci_tbl[p].driver_data != i) continue; - printk(" %04x:%04x", + pr_cont(" %04x:%04x", saa7134_pci_tbl[p].subvendor, saa7134_pci_tbl[p].subdevice); } - printk("\n"); + pr_cont("\n"); } } @@ -903,31 +904,31 @@ static int saa7134_initdev(struct pci_dev *pci_dev, /* pci quirks */ if (pci_pci_problems) { if (pci_pci_problems & PCIPCI_TRITON) - printk(KERN_INFO "%s: quirk: PCIPCI_TRITON\n", dev->name); + pr_info("%s: quirk: PCIPCI_TRITON\n", dev->name); if (pci_pci_problems & PCIPCI_NATOMA) - printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA\n", dev->name); + pr_info("%s: quirk: PCIPCI_NATOMA\n", dev->name); if (pci_pci_problems & PCIPCI_VIAETBF) - printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF\n", dev->name); + pr_info("%s: quirk: PCIPCI_VIAETBF\n", dev->name); if (pci_pci_problems & PCIPCI_VSFX) - printk(KERN_INFO "%s: quirk: PCIPCI_VSFX\n",dev->name); + pr_info("%s: quirk: PCIPCI_VSFX\n", dev->name); #ifdef PCIPCI_ALIMAGIK if (pci_pci_problems & PCIPCI_ALIMAGIK) { - printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n", + pr_info("%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n", dev->name); latency = 0x0A; } #endif if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) { - printk(KERN_INFO "%s: quirk: this driver and your " + pr_info("%s: quirk: this driver and your " "chipset may not work together" " in overlay mode.\n",dev->name); if (!saa7134_no_overlay) { - printk(KERN_INFO "%s: quirk: overlay " + pr_info("%s: quirk: overlay " "mode will be disabled.\n", dev->name); saa7134_no_overlay = 1; } else { - printk(KERN_INFO "%s: quirk: overlay " + pr_info("%s: quirk: overlay " "mode will be forced. Use this" " option at your own risk.\n", dev->name); @@ -935,7 +936,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, } } if (UNSET != latency) { - printk(KERN_INFO "%s: setting pci latency timer to %d\n", + pr_info("%s: setting pci latency timer to %d\n", dev->name,latency); pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency); } @@ -943,13 +944,13 @@ static int saa7134_initdev(struct pci_dev *pci_dev, /* print pci info */ dev->pci_rev = pci_dev->revision; pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, " + pr_info("%s: found at %s, rev: %d, irq: %d, " "latency: %d, mmio: 0x%llx\n", dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); pci_set_master(pci_dev); if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) { - printk("%s: Oops: no 32bit PCI DMA ???\n",dev->name); + pr_warn("%s: Oops: no 32bit PCI DMA ???\n", dev->name); err = -EIO; goto fail1; } @@ -972,7 +973,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf; if (UNSET != tuner[dev->nr]) dev->tuner_type = tuner[dev->nr]; - printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + pr_info("%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", dev->name,pci_dev->subsystem_vendor, pci_dev->subsystem_device,saa7134_boards[dev->board].name, dev->board, dev->autodetected ? @@ -983,7 +984,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, pci_resource_len(pci_dev,0), dev->name)) { err = -EBUSY; - printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", + pr_err("%s: can't get MMIO memory @ 0x%llx\n", dev->name,(unsigned long long)pci_resource_start(pci_dev,0)); goto fail1; } @@ -992,7 +993,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, dev->bmmio = (__u8 __iomem *)dev->lmmio; if (NULL == dev->lmmio) { err = -EIO; - printk(KERN_ERR "%s: can't ioremap() MMIO memory\n", + pr_err("%s: can't ioremap() MMIO memory\n", dev->name); goto fail2; } @@ -1010,7 +1011,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, err = request_irq(pci_dev->irq, saa7134_irq, IRQF_SHARED, dev->name, dev); if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", + pr_err("%s: can't get IRQ %d\n", dev->name,pci_dev->irq); goto fail4; } @@ -1040,7 +1041,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, &dev->i2c_adap, "saa6588", 0, I2C_ADDRS(saa7134_boards[dev->board].rds_addr)); if (sd) { - printk(KERN_INFO "%s: found RDS decoder\n", dev->name); + pr_info("%s: found RDS decoder\n", dev->name); dev->has_rds = 1; } } @@ -1059,7 +1060,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, /* register v4l devices */ if (saa7134_no_overlay > 0) - printk(KERN_INFO "%s: Overlay support disabled.\n", dev->name); + pr_info("%s: Overlay support disabled.\n", dev->name); dev->video_dev = vdev_init(dev,&saa7134_video_template,"video"); dev->video_dev->ctrl_handler = &dev->ctrl_handler; @@ -1068,11 +1069,11 @@ static int saa7134_initdev(struct pci_dev *pci_dev, err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, video_nr[dev->nr]); if (err < 0) { - printk(KERN_INFO "%s: can't register video device\n", + pr_info("%s: can't register video device\n", dev->name); goto fail5; } - printk(KERN_INFO "%s: registered device %s [v4l2]\n", + pr_info("%s: registered device %s [v4l2]\n", dev->name, video_device_node_name(dev->video_dev)); dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi"); @@ -1084,7 +1085,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, vbi_nr[dev->nr]); if (err < 0) goto fail5; - printk(KERN_INFO "%s: registered device %s\n", + pr_info("%s: registered device %s\n", dev->name, video_device_node_name(dev->vbi_dev)); if (card_has_radio(dev)) { @@ -1095,7 +1096,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, radio_nr[dev->nr]); if (err < 0) goto fail5; - printk(KERN_INFO "%s: registered device %s\n", + pr_info("%s: registered device %s\n", dev->name, video_device_node_name(dev->radio_dev)); } @@ -1204,12 +1205,12 @@ static int saa7134_buffer_requeue(struct saa7134_dev *dev, buf = q->curr; next = buf; - dprintk("buffer_requeue\n"); + core_dbg("buffer_requeue\n"); if (!buf) return 0; - dprintk("buffer_requeue : resending active buffers \n"); + core_dbg("buffer_requeue : resending active buffer\n"); if (!list_empty(&q->queue)) next = list_entry(q->queue.next, struct saa7134_buf, @@ -1358,7 +1359,7 @@ static struct pci_driver saa7134_pci_driver = { static int __init saa7134_init(void) { INIT_LIST_HEAD(&saa7134_devlist); - printk(KERN_INFO "saa7130/34: v4l2 driver version %s loaded\n", + pr_info("saa7130/34: v4l2 driver version %s loaded\n", SAA7134_VERSION); return pci_register_driver(&saa7134_pci_driver); } diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c index 73ffbab..101ba87 100644 --- a/drivers/media/pci/saa7134/saa7134-dvb.c +++ b/drivers/media/pci/saa7134/saa7134-dvb.c @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/list.h> #include <linux/module.h> @@ -28,8 +31,6 @@ #include <linux/kthread.h> #include <linux/suspend.h> -#include "saa7134-reg.h" -#include "saa7134.h" #include <media/v4l2-common.h> #include "dvb-pll.h" #include <dvb_frontend.h> @@ -75,19 +76,8 @@ static int use_frontend; module_param(use_frontend, int, 0644); MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)"); -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off module debugging (default:off)."); - DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -#define dprintk(fmt, arg...) do { if (debug) \ - printk(KERN_DEBUG "%s/dvb: " fmt, dev->name , ## arg); } while(0) - -/* Print a warning */ -#define wprintk(fmt, arg...) \ - printk(KERN_WARNING "%s/dvb: " fmt, dev->name, ## arg) - /* ------------------------------------------------------------------ * mt352 based DVB-T cards */ @@ -112,7 +102,7 @@ static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on) saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28)); udelay(10); ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27); - dprintk("%s %s\n", __func__, ok ? "on" : "off"); + pr_debug("%s %s\n", __func__, ok ? "on" : "off"); if (!ok) saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26)); @@ -130,9 +120,8 @@ static int mt352_pinnacle_init(struct dvb_frontend* fe) static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x0f }; static u8 scan_ctl_cfg [] = { SCAN_CTL, 0x0d }; static u8 irq_cfg [] = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 }; - struct saa7134_dev *dev= fe->dvb->priv; - dprintk("%s called\n", __func__); + pr_debug("%s called\n", __func__); mt352_write(fe, clock_config, sizeof(clock_config)); udelay(200); @@ -258,7 +247,7 @@ static int kworld_sbtvd_gate_ctrl(struct dvb_frontend* fe, int enable) struct i2c_msg msg = {.addr = 0x4b, .flags = 0, .buf = initmsg, .len = 2}; if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) { - wprintk("could not access the I2C gate\n"); + pr_warn("could not access the I2C gate\n"); return -EIO; } if (enable) @@ -266,7 +255,7 @@ static int kworld_sbtvd_gate_ctrl(struct dvb_frontend* fe, int enable) else msg.buf = msg_disable; if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) { - wprintk("could not access the I2C gate\n"); + pr_warn("could not access the I2C gate\n"); return -EIO; } msleep(20); @@ -369,7 +358,7 @@ static int philips_tda6651_pll_set(struct dvb_frontend *fe) if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) { - wprintk("could not write to tuner at addr: 0x%02x\n", + pr_warn("could not write to tuner at addr: 0x%02x\n", addr << 1); return -EIO; } @@ -556,8 +545,7 @@ static int tda8290_i2c_gate_ctrl( struct dvb_frontend* fe, int enable) tda8290_msg.buf = tda8290_open; } if (i2c_transfer(state->i2c, &tda8290_msg, 1) != 1) { - struct saa7134_dev *dev = fe->dvb->priv; - wprintk("could not access tda8290 I2C gate\n"); + pr_warn("could not access tda8290 I2C gate\n"); return -EIO; } msleep(20); @@ -570,11 +558,14 @@ static int philips_tda827x_tuner_init(struct dvb_frontend *fe) struct tda1004x_state *state = fe->demodulator_priv; switch (state->config->antenna_switch) { - case 0: break; - case 1: dprintk("setting GPIO21 to 0 (TV antenna?)\n"); + case 0: + break; + case 1: + pr_debug("setting GPIO21 to 0 (TV antenna?)\n"); saa7134_set_gpio(dev, 21, 0); break; - case 2: dprintk("setting GPIO21 to 1 (Radio antenna?)\n"); + case 2: + pr_debug("setting GPIO21 to 1 (Radio antenna?)\n"); saa7134_set_gpio(dev, 21, 1); break; } @@ -587,11 +578,14 @@ static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe) struct tda1004x_state *state = fe->demodulator_priv; switch (state->config->antenna_switch) { - case 0: break; - case 1: dprintk("setting GPIO21 to 1 (Radio antenna?)\n"); + case 0: + break; + case 1: + pr_debug("setting GPIO21 to 1 (Radio antenna?)\n"); saa7134_set_gpio(dev, 21, 1); break; - case 2: dprintk("setting GPIO21 to 0 (TV antenna?)\n"); + case 2: + pr_debug("setting GPIO21 to 0 (TV antenna?)\n"); saa7134_set_gpio(dev, 21, 0); break; } @@ -619,7 +613,7 @@ static int configure_tda827x_fe(struct saa7134_dev *dev, &dev->i2c_adap, tuner_conf)) return 0; - wprintk("no tda827x tuner found at addr: %02x\n", + pr_warn("no tda827x tuner found at addr: %02x\n", cdec_conf->tuner_address); } return -EINVAL; @@ -993,7 +987,8 @@ static struct tda10086_config sd1878_4m = { * special case: lnb supply is connected to the gated i2c */ -static int md8800_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int md8800_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { int res = -EIO; struct saa7134_dev *dev = fe->dvb->priv; @@ -1019,7 +1014,8 @@ static int md8800_set_high_voltage(struct dvb_frontend *fe, long arg) return res; }; -static int md8800_set_voltage2(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int md8800_set_voltage2(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct saa7134_dev *dev = fe->dvb->priv; u8 wbuf[2] = { 0x1f, 00 }; @@ -1041,8 +1037,8 @@ static int md8800_set_voltage2(struct dvb_frontend *fe, fe_sec_voltage_t voltage static int md8800_set_high_voltage2(struct dvb_frontend *fe, long arg) { - struct saa7134_dev *dev = fe->dvb->priv; - wprintk("%s: sorry can't set high LNB supply voltage from here\n", __func__); + pr_warn("%s: sorry can't set high LNB supply voltage from here\n", + __func__); return -EIO; } @@ -1222,10 +1218,10 @@ static int dvb_init(struct saa7134_dev *dev) mutex_init(&dev->frontends.lock); INIT_LIST_HEAD(&dev->frontends.felist); - printk(KERN_INFO "%s() allocating 1 frontend\n", __func__); + pr_info("%s() allocating 1 frontend\n", __func__); fe0 = vb2_dvb_alloc_frontend(&dev->frontends, 1); if (!fe0) { - printk(KERN_ERR "%s() failed to alloc\n", __func__); + pr_err("%s() failed to alloc\n", __func__); return -ENOMEM; } @@ -1250,7 +1246,7 @@ static int dvb_init(struct saa7134_dev *dev) switch (dev->board) { case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: - dprintk("pinnacle 300i dvb setup\n"); + pr_debug("pinnacle 300i dvb setup\n"); fe0->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i, &dev->i2c_adap); if (fe0->dvb.frontend) { @@ -1259,7 +1255,7 @@ static int dvb_init(struct saa7134_dev *dev) break; case SAA7134_BOARD_AVERMEDIA_777: case SAA7134_BOARD_AVERMEDIA_A16AR: - dprintk("avertv 777 dvb setup\n"); + pr_debug("avertv 777 dvb setup\n"); fe0->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777, &dev->i2c_adap); if (fe0->dvb.frontend) { @@ -1269,7 +1265,7 @@ static int dvb_init(struct saa7134_dev *dev) } break; case SAA7134_BOARD_AVERMEDIA_A16D: - dprintk("AverMedia A16D dvb setup\n"); + pr_debug("AverMedia A16D dvb setup\n"); fe0->dvb.frontend = dvb_attach(mt352_attach, &avermedia_xc3028_mt352_dev, &dev->i2c_adap); @@ -1401,13 +1397,15 @@ static int dvb_init(struct saa7134_dev *dev) if (fe0->dvb.frontend) { if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x63, &dev->i2c_adap, 0) == NULL) { - wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__); + pr_warn("%s: Lifeview Trio, No tda826x found!\n", + __func__); goto detach_frontend; } if (dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->i2c_adap, 0x08, 0, 0, false) == NULL) { - wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__); + pr_warn("%s: Lifeview Trio, No ISL6421 found!\n", + __func__); goto detach_frontend; } } @@ -1422,12 +1420,12 @@ static int dvb_init(struct saa7134_dev *dev) if (dvb_attach(tda827x_attach,fe0->dvb.frontend, ads_tech_duo_config.tuner_address, &dev->i2c_adap, &ads_duo_cfg) == NULL) { - wprintk("no tda827x tuner found at addr: %02x\n", + pr_warn("no tda827x tuner found at addr: %02x\n", ads_tech_duo_config.tuner_address); goto detach_frontend; } } else - wprintk("failed to attach tda10046\n"); + pr_warn("failed to attach tda10046\n"); break; case SAA7134_BOARD_TEVION_DVBT_220RF: if (configure_tda827x_fe(dev, &tevion_dvbt220rf_config, @@ -1450,7 +1448,7 @@ static int dvb_init(struct saa7134_dev *dev) if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, 0) == NULL) { - wprintk("%s: Medion Quadro, no tda826x " + pr_warn("%s: Medion Quadro, no tda826x " "found !\n", __func__); goto detach_frontend; } @@ -1459,7 +1457,7 @@ static int dvb_init(struct saa7134_dev *dev) fe->ops.i2c_gate_ctrl(fe, 1); if (dvb_attach(isl6405_attach, fe, &dev->i2c_adap, 0x08, 0, 0) == NULL) { - wprintk("%s: Medion Quadro, no ISL6405 " + pr_warn("%s: Medion Quadro, no ISL6405 " "found !\n", __func__); goto detach_frontend; } @@ -1519,13 +1517,13 @@ static int dvb_init(struct saa7134_dev *dev) if (fe0->dvb.frontend) { if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, 0) == NULL) { - wprintk("%s: No tda826x found!\n", __func__); + pr_warn("%s: No tda826x found!\n", __func__); goto detach_frontend; } if (dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->i2c_adap, 0x08, 0, 0, false) == NULL) { - wprintk("%s: No ISL6421 found!\n", __func__); + pr_warn("%s: No ISL6421 found!\n", __func__); goto detach_frontend; } } @@ -1593,12 +1591,12 @@ static int dvb_init(struct saa7134_dev *dev) if (fe0->dvb.frontend) { if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, 0) == NULL) { - wprintk("%s: No tda826x found!\n", __func__); + pr_warn("%s: No tda826x found!\n", __func__); goto detach_frontend; } if (dvb_attach(lnbp21_attach, fe0->dvb.frontend, &dev->i2c_adap, 0, 0) == NULL) { - wprintk("%s: No lnbp21 found!\n", __func__); + pr_warn("%s: No lnbp21 found!\n", __func__); goto detach_frontend; } } @@ -1614,7 +1612,7 @@ static int dvb_init(struct saa7134_dev *dev) goto detach_frontend; break; case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: - dprintk("AverMedia E506R dvb setup\n"); + pr_debug("AverMedia E506R dvb setup\n"); saa7134_set_gpio(dev, 25, 0); msleep(10); saa7134_set_gpio(dev, 25, 1); @@ -1630,7 +1628,7 @@ static int dvb_init(struct saa7134_dev *dev) struct dvb_frontend *fe; if (dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) { - wprintk("%s: MD7134 DVB-S, no SD1878 " + pr_warn("%s: MD7134 DVB-S, no SD1878 " "found !\n", __func__); goto detach_frontend; } @@ -1639,7 +1637,7 @@ static int dvb_init(struct saa7134_dev *dev) fe->ops.i2c_gate_ctrl(fe, 1); if (dvb_attach(isl6405_attach, fe, &dev->i2c_adap, 0x08, 0, 0) == NULL) { - wprintk("%s: MD7134 DVB-S, no ISL6405 " + pr_warn("%s: MD7134 DVB-S, no ISL6405 " "found !\n", __func__); goto detach_frontend; } @@ -1671,15 +1669,15 @@ static int dvb_init(struct saa7134_dev *dev) if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, 0) == NULL) { - wprintk("%s: Asus Tiger 3in1, no " + pr_warn("%s: Asus Tiger 3in1, no " "tda826x found!\n", __func__); goto detach_frontend; } if (dvb_attach(lnbp21_attach, fe0->dvb.frontend, &dev->i2c_adap, 0, 0) == NULL) { - wprintk("%s: Asus Tiger 3in1, no lnbp21" + pr_warn("%s: Asus Tiger 3in1, no lnbp21" " found!\n", __func__); - goto detach_frontend; + goto detach_frontend; } } } @@ -1696,13 +1694,13 @@ static int dvb_init(struct saa7134_dev *dev) if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, 0) == NULL) { - wprintk("%s: Asus My Cinema PS3-100, no " + pr_warn("%s: Asus My Cinema PS3-100, no " "tda826x found!\n", __func__); goto detach_frontend; } if (dvb_attach(lnbp21_attach, fe0->dvb.frontend, &dev->i2c_adap, 0, 0) == NULL) { - wprintk("%s: Asus My Cinema PS3-100, no lnbp21" + pr_warn("%s: Asus My Cinema PS3-100, no lnbp21" " found!\n", __func__); goto detach_frontend; } @@ -1750,7 +1748,7 @@ static int dvb_init(struct saa7134_dev *dev) if (fe0->dvb.frontend) { if (dvb_attach(zl10036_attach, fe0->dvb.frontend, &avertv_a700_tuner, &dev->i2c_adap) == NULL) { - wprintk("%s: No zl10036 found!\n", + pr_warn("%s: No zl10036 found!\n", __func__); } } @@ -1761,7 +1759,7 @@ static int dvb_init(struct saa7134_dev *dev) if (fe0->dvb.frontend) if (dvb_attach(zl10039_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap) == NULL) - wprintk("%s: No zl10039 found!\n", + pr_warn("%s: No zl10039 found!\n", __func__); break; @@ -1774,7 +1772,7 @@ static int dvb_init(struct saa7134_dev *dev) fe0->dvb.frontend, &dev->i2c_adap, &videomate_t750_qt1010_config) == NULL) - wprintk("error attaching QT1010\n"); + pr_warn("error attaching QT1010\n"); } break; case SAA7134_BOARD_ZOLID_HYBRID_PCI: @@ -1850,12 +1848,12 @@ static int dvb_init(struct saa7134_dev *dev) fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; if (dvb_attach(zl10039_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap) == NULL) - wprintk("%s: No zl10039 found!\n", + pr_warn("%s: No zl10039 found!\n", __func__); } break; default: - wprintk("Huh? unknown DVB card?\n"); + pr_warn("Huh? unknown DVB card?\n"); break; } @@ -1871,14 +1869,14 @@ static int dvb_init(struct saa7134_dev *dev) fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg); if (!fe) { - printk(KERN_ERR "%s/2: xc3028 attach failed\n", + pr_err("%s/2: xc3028 attach failed\n", dev->name); goto detach_frontend; } } if (NULL == fe0->dvb.frontend) { - printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name); + pr_err("%s/dvb: frontend initialization failed\n", dev->name); goto detach_frontend; } /* define general-purpose callback pointer */ diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index 594dc3a..56b932c 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c @@ -17,6 +17,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/list.h> #include <linux/module.h> @@ -26,9 +29,6 @@ #include <media/v4l2-common.h> #include <media/v4l2-event.h> -#include "saa7134-reg.h" -#include "saa7134.h" - /* ------------------------------------------------------------------ */ MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); @@ -39,13 +39,6 @@ static unsigned int empress_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; module_param_array(empress_nr, int, NULL, 0444); MODULE_PARM_DESC(empress_nr,"ts device number"); -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"enable debug messages"); - -#define dprintk(fmt, arg...) if (debug) \ - printk(KERN_DEBUG "%s/empress: " fmt, dev->name , ## arg) - /* ------------------------------------------------------------------ */ static int start_streaming(struct vb2_queue *vq, unsigned int count) @@ -121,11 +114,14 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_dev *dev = video_drvdata(file); - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mbus_fmt = &fmt.format; - saa_call_all(dev, video, g_mbus_fmt, &mbus_fmt); + saa_call_all(dev, pad, get_fmt, NULL, &fmt); - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); + v4l2_fill_pix_format(&f->fmt.pix, mbus_fmt); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; f->fmt.pix.bytesperline = 0; @@ -137,11 +133,13 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_dev *dev = video_drvdata(file); - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; - v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); - saa_call_all(dev, video, s_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); + v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); + saa_call_all(dev, pad, set_fmt, NULL, &format); + v4l2_fill_pix_format(&f->fmt.pix, &format.format); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; @@ -154,11 +152,14 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_dev *dev = video_drvdata(file); - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; - v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); - saa_call_all(dev, video, try_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); + v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); + saa_call_all(dev, pad, set_fmt, &pad_cfg, &format); + v4l2_fill_pix_format(&f->fmt.pix, &format.format); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; @@ -221,9 +222,9 @@ static void empress_signal_update(struct work_struct *work) container_of(work, struct saa7134_dev, empress_workqueue); if (dev->nosignal) { - dprintk("no video signal\n"); + pr_debug("no video signal\n"); } else { - dprintk("video signal acquired\n"); + pr_debug("video signal acquired\n"); } } @@ -255,7 +256,7 @@ static int empress_init(struct saa7134_dev *dev) struct vb2_queue *q; int err; - dprintk("%s: %s\n",dev->name,__func__); + pr_debug("%s: %s\n", dev->name, __func__); dev->empress_dev = video_device_alloc(); if (NULL == dev->empress_dev) return -ENOMEM; @@ -302,13 +303,13 @@ static int empress_init(struct saa7134_dev *dev) err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER, empress_nr[dev->nr]); if (err < 0) { - printk(KERN_INFO "%s: can't register video device\n", + pr_info("%s: can't register video device\n", dev->name); video_device_release(dev->empress_dev); dev->empress_dev = NULL; return err; } - printk(KERN_INFO "%s: registered device %s [mpeg]\n", + pr_info("%s: registered device %s [mpeg]\n", dev->name, video_device_node_name(dev->empress_dev)); empress_signal_update(&dev->empress_workqueue); @@ -317,7 +318,7 @@ static int empress_init(struct saa7134_dev *dev) static int empress_fini(struct saa7134_dev *dev) { - dprintk("%s: %s\n",dev->name,__func__); + pr_debug("%s: %s\n", dev->name, __func__); if (NULL == dev->empress_dev) return 0; diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c index 54e650b..8a2abb3 100644 --- a/drivers/media/pci/saa7134/saa7134-go7007.c +++ b/drivers/media/pci/saa7134/saa7134-go7007.c @@ -11,6 +11,9 @@ * GNU General Public License for more details. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -27,8 +30,6 @@ #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> -#include "saa7134.h" -#include "saa7134-reg.h" #include "go7007-priv.h" /*#define GO7007_HPI_DEBUG*/ @@ -288,9 +289,9 @@ static int saa7134_go7007_stream_start(struct go7007 *go) /* Set up transfer block size */ saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 128 - 1); - saa_writeb(SAA7134_TS_DMA0, (PAGE_SIZE >> 7) - 1); - saa_writeb(SAA7134_TS_DMA1, 0); - saa_writeb(SAA7134_TS_DMA2, 0); + saa_writeb(SAA7134_TS_DMA0, ((PAGE_SIZE >> 7) - 1) & 0xff); + saa_writeb(SAA7134_TS_DMA1, (PAGE_SIZE >> 15) & 0xff); + saa_writeb(SAA7134_TS_DMA2, (PAGE_SIZE >> 31) & 0x3f); /* Enable video streaming mode */ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO); diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c index f4da674..8ef6399 100644 --- a/drivers/media/pci/saa7134/saa7134-i2c.c +++ b/drivers/media/pci/saa7134/saa7134-i2c.c @@ -20,14 +20,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/list.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> -#include "saa7134-reg.h" -#include "saa7134.h" #include <media/v4l2-common.h> /* ----------------------------------------------------------- */ @@ -40,8 +41,15 @@ static unsigned int i2c_scan; module_param(i2c_scan, int, 0444); MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); -#define d1printk if (1 == i2c_debug) printk -#define d2printk if (2 == i2c_debug) printk +#define i2c_dbg(level, fmt, arg...) do { \ + if (i2c_debug == level) \ + printk(KERN_DEBUG pr_fmt("i2c: " fmt), ## arg); \ + } while (0) + +#define i2c_cont(level, fmt, arg...) do { \ + if (i2c_debug == level) \ + pr_cont(fmt, ## arg); \ + } while (0) #define I2C_WAIT_DELAY 32 #define I2C_WAIT_RETRY 16 @@ -89,23 +97,20 @@ static inline enum i2c_status i2c_get_status(struct saa7134_dev *dev) enum i2c_status status; status = saa_readb(SAA7134_I2C_ATTR_STATUS) & 0x0f; - d2printk(KERN_DEBUG "%s: i2c stat <= %s\n",dev->name, - str_i2c_status[status]); + i2c_dbg(2, "i2c stat <= %s\n", str_i2c_status[status]); return status; } static inline void i2c_set_status(struct saa7134_dev *dev, enum i2c_status status) { - d2printk(KERN_DEBUG "%s: i2c stat => %s\n",dev->name, - str_i2c_status[status]); + i2c_dbg(2, "i2c stat => %s\n", str_i2c_status[status]); saa_andorb(SAA7134_I2C_ATTR_STATUS,0x0f,status); } static inline void i2c_set_attr(struct saa7134_dev *dev, enum i2c_attr attr) { - d2printk(KERN_DEBUG "%s: i2c attr => %s\n",dev->name, - str_i2c_attr[attr]); + i2c_dbg(2, "i2c attr => %s\n", str_i2c_attr[attr]); saa_andorb(SAA7134_I2C_ATTR_STATUS,0xc0,attr << 6); } @@ -168,7 +173,7 @@ static int i2c_reset(struct saa7134_dev *dev) enum i2c_status status; int count; - d2printk(KERN_DEBUG "%s: i2c reset\n",dev->name); + i2c_dbg(2, "i2c reset\n"); status = i2c_get_status(dev); if (!i2c_is_error(status)) return true; @@ -206,7 +211,7 @@ static inline int i2c_send_byte(struct saa7134_dev *dev, // dword |= 0x40 << 16; /* 400 kHz */ dword |= 0xf0 << 24; saa_writel(SAA7134_I2C_ATTR_STATUS >> 2, dword); - d2printk(KERN_DEBUG "%s: i2c data => 0x%x\n",dev->name,data); + i2c_dbg(2, "i2c data => 0x%x\n", data); if (!i2c_is_busy_wait(dev)) return -EIO; @@ -228,7 +233,7 @@ static inline int i2c_recv_byte(struct saa7134_dev *dev) if (i2c_is_error(status)) return -EIO; data = saa_readb(SAA7134_I2C_DATA); - d2printk(KERN_DEBUG "%s: i2c data <= 0x%x\n",dev->name,data); + i2c_dbg(2, "i2c data <= 0x%x\n", data); return data; } @@ -245,12 +250,12 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, if (!i2c_reset(dev)) return -EIO; - d2printk("start xfer\n"); - d1printk(KERN_DEBUG "%s: i2c xfer:",dev->name); + i2c_dbg(2, "start xfer\n"); + i2c_dbg(1, "i2c xfer:"); for (i = 0; i < num; i++) { if (!(msgs[i].flags & I2C_M_NOSTART) || 0 == i) { /* send address */ - d2printk("send address\n"); + i2c_dbg(2, "send address\n"); addr = msgs[i].addr << 1; if (msgs[i].flags & I2C_M_RD) addr |= 1; @@ -262,50 +267,50 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, * needed to talk to the mt352 demux * thanks to pinnacle for the hint */ int quirk = 0xfe; - d1printk(" [%02x quirk]",quirk); + i2c_cont(1, " [%02x quirk]", quirk); i2c_send_byte(dev,START,quirk); i2c_recv_byte(dev); } - d1printk(" < %02x", addr); + i2c_cont(1, " < %02x", addr); rc = i2c_send_byte(dev,START,addr); if (rc < 0) goto err; } if (msgs[i].flags & I2C_M_RD) { /* read bytes */ - d2printk("read bytes\n"); + i2c_dbg(2, "read bytes\n"); for (byte = 0; byte < msgs[i].len; byte++) { - d1printk(" ="); + i2c_cont(1, " ="); rc = i2c_recv_byte(dev); if (rc < 0) goto err; - d1printk("%02x", rc); + i2c_cont(1, "%02x", rc); msgs[i].buf[byte] = rc; } /* discard mysterious extra byte when reading from Samsung S5H1411. i2c bus gets error if we do not. */ if (0x19 == msgs[i].addr) { - d1printk(" ?"); + i2c_cont(1, " ?"); rc = i2c_recv_byte(dev); if (rc < 0) goto err; - d1printk("%02x", rc); + i2c_cont(1, "%02x", rc); } } else { /* write bytes */ - d2printk("write bytes\n"); + i2c_dbg(2, "write bytes\n"); for (byte = 0; byte < msgs[i].len; byte++) { data = msgs[i].buf[byte]; - d1printk(" %02x", data); + i2c_cont(1, " %02x", data); rc = i2c_send_byte(dev,CONTINUE,data); if (rc < 0) goto err; } } } - d2printk("xfer done\n"); - d1printk(" >"); + i2c_dbg(2, "xfer done\n"); + i2c_cont(1, " >"); i2c_set_attr(dev,STOP); rc = -EIO; if (!i2c_is_busy_wait(dev)) @@ -316,12 +321,12 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, /* ensure that the bus is idle for at least one bit slot */ msleep(1); - d1printk("\n"); + i2c_cont(1, "\n"); return num; err: if (1 == i2c_debug) { status = i2c_get_status(dev); - printk(" ERROR: %s\n",str_i2c_status[status]); + i2c_cont(1, " ERROR: %s\n", str_i2c_status[status]); } return rc; } @@ -359,22 +364,22 @@ saa7134_i2c_eeprom(struct saa7134_dev *dev, unsigned char *eedata, int len) dev->i2c_client.addr = 0xa0 >> 1; buf = 0; if (1 != (err = i2c_master_send(&dev->i2c_client,&buf,1))) { - printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", + pr_info("%s: Huh, no eeprom present (err=%d)?\n", dev->name,err); return -1; } if (len != (err = i2c_master_recv(&dev->i2c_client,eedata,len))) { - printk(KERN_WARNING "%s: i2c eeprom read error (err=%d)\n", + pr_warn("%s: i2c eeprom read error (err=%d)\n", dev->name,err); return -1; } - for (i = 0; i < len; i++) { - if (0 == (i % 16)) - printk(KERN_INFO "%s: i2c eeprom %02x:",dev->name,i); - printk(" %02x",eedata[i]); - if (15 == (i % 16)) - printk("\n"); + + for (i = 0; i < len; i += 16) { + int size = (len - i) > 16 ? 16 : len - i; + + pr_info("i2c eeprom %02x: %*ph\n", i, size, &eedata[i]); } + return 0; } @@ -386,7 +391,7 @@ static char *i2c_devs[128] = { [ 0x5a >> 1 ] = "remote control", }; -static void do_i2c_scan(char *name, struct i2c_client *c) +static void do_i2c_scan(struct i2c_client *c) { unsigned char buf; int i,rc; @@ -396,8 +401,8 @@ static void do_i2c_scan(char *name, struct i2c_client *c) rc = i2c_master_recv(c,&buf,0); if (rc < 0) continue; - printk("%s: i2c scan: found device @ 0x%x [%s]\n", - name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + pr_info("i2c scan: found device @ 0x%x [%s]\n", + i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); } } @@ -415,7 +420,7 @@ int saa7134_i2c_register(struct saa7134_dev *dev) saa7134_i2c_eeprom(dev,dev->eedata,sizeof(dev->eedata)); if (i2c_scan) - do_i2c_scan(dev->name,&dev->i2c_client); + do_i2c_scan(&dev->i2c_client); /* Instantiate the IR receiver device, if present */ saa7134_probe_i2c_ir(dev); diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c index dc3d651..11a1720 100644 --- a/drivers/media/pci/saa7134/saa7134-input.c +++ b/drivers/media/pci/saa7134/saa7134-input.c @@ -18,15 +18,15 @@ * */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/module.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/slab.h> -#include "saa7134-reg.h" -#include "saa7134.h" - #define MODULE_NAME "saa7134" static unsigned int disable_ir; @@ -41,10 +41,14 @@ static int pinnacle_remote; module_param(pinnacle_remote, int, 0644); /* Choose Pinnacle PCTV remote */ MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)"); -#define dprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg) -#define i2cdprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg) +#define input_dbg(fmt, arg...) do { \ + if (ir_debug) \ + printk(KERN_DEBUG pr_fmt("input: " fmt), ## arg); \ + } while (0) +#define ir_dbg(ir, fmt, arg...) do { \ + if (ir_debug) \ + printk(KERN_DEBUG pr_fmt("ir %s: " fmt), ir->name, ## arg); \ + } while (0) /* Helper function for raw decoding at GPIO16 or GPIO18 */ static int saa7134_raw_decode_irq(struct saa7134_dev *dev); @@ -75,7 +79,7 @@ static int build_key(struct saa7134_dev *dev) } data = ir_extract_bits(gpio, ir->mask_keycode); - dprintk("build_key gpio=0x%x mask=0x%x data=%d\n", + input_dbg("build_key gpio=0x%x mask=0x%x data=%d\n", gpio, ir->mask_keycode, data); switch (dev->board) { @@ -119,7 +123,7 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_type *protocol, struct saa7134_dev *dev = ir->c->adapter->algo_data; if (dev == NULL) { - i2cdprintk("get_key_flydvb_trio: " + ir_dbg(ir, "get_key_flydvb_trio: " "ir->c->adapter->algo_data is NULL!\n"); return -EIO; } @@ -146,12 +150,12 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_type *protocol, msleep(10); continue; } - i2cdprintk("send wake up byte to pic16C505 (IR chip)" + ir_dbg(ir, "send wake up byte to pic16C505 (IR chip)" "failed %dx\n", attempt); return -EIO; } if (1 != i2c_master_recv(ir->c, &b, 1)) { - i2cdprintk("read error\n"); + ir_dbg(ir, "read error\n"); return -EIO; } @@ -170,7 +174,7 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, enum rc_type *protocol /* <dev> is needed to access GPIO. Used by the saa_readl macro. */ struct saa7134_dev *dev = ir->c->adapter->algo_data; if (dev == NULL) { - i2cdprintk("get_key_msi_tvanywhere_plus: " + ir_dbg(ir, "get_key_msi_tvanywhere_plus: " "ir->c->adapter->algo_data is NULL!\n"); return -EIO; } @@ -191,7 +195,7 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, enum rc_type *protocol /* GPIO says there is a button press. Get it. */ if (1 != i2c_master_recv(ir->c, &b, 1)) { - i2cdprintk("read error\n"); + ir_dbg(ir, "read error\n"); return -EIO; } @@ -202,7 +206,7 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, enum rc_type *protocol /* Button pressed */ - dprintk("get_key_msi_tvanywhere_plus: Key = 0x%02X\n", b); + input_dbg("get_key_msi_tvanywhere_plus: Key = 0x%02X\n", b); *protocol = RC_TYPE_UNKNOWN; *scancode = b; *toggle = 0; @@ -219,7 +223,7 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_type *protocol, /* <dev> is needed to access GPIO. Used by the saa_readl macro. */ struct saa7134_dev *dev = ir->c->adapter->algo_data; if (dev == NULL) { - i2cdprintk("get_key_kworld_pc150u: " + ir_dbg(ir, "get_key_kworld_pc150u: " "ir->c->adapter->algo_data is NULL!\n"); return -EIO; } @@ -240,7 +244,7 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_type *protocol, /* GPIO says there is a button press. Get it. */ if (1 != i2c_master_recv(ir->c, &b, 1)) { - i2cdprintk("read error\n"); + ir_dbg(ir, "read error\n"); return -EIO; } @@ -251,7 +255,7 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_type *protocol, /* Button pressed */ - dprintk("get_key_kworld_pc150u: Key = 0x%02X\n", b); + input_dbg("get_key_kworld_pc150u: Key = 0x%02X\n", b); *protocol = RC_TYPE_UNKNOWN; *scancode = b; *toggle = 0; @@ -265,7 +269,7 @@ static int get_key_purpletv(struct IR_i2c *ir, enum rc_type *protocol, /* poll IR chip */ if (1 != i2c_master_recv(ir->c, &b, 1)) { - i2cdprintk("read error\n"); + ir_dbg(ir, "read error\n"); return -EIO; } @@ -334,7 +338,7 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_type *protocol, ir->c->addr = 0x5a >> 1; if (12 != i2c_master_recv(ir->c, data, 12)) { - i2cdprintk("read error\n"); + ir_dbg(ir, "read error\n"); return -EIO; } @@ -359,7 +363,7 @@ static int get_key_pinnacle(struct IR_i2c *ir, enum rc_type *protocol, /* poll IR chip */ if (4 != i2c_master_recv(ir->c, b, 4)) { - i2cdprintk("read error\n"); + ir_dbg(ir, "read error\n"); return -EIO; } @@ -391,7 +395,7 @@ static int get_key_pinnacle(struct IR_i2c *ir, enum rc_type *protocol, *scancode = code; *toggle = 0; - i2cdprintk("Pinnacle PCTV key %02x\n", code); + ir_dbg(ir, "Pinnacle PCTV key %02x\n", code); return 1; } @@ -481,6 +485,7 @@ static int __saa7134_ir_start(void *priv) case SAA7134_BOARD_KWORLD_VSTREAM_XPERT: case SAA7134_BOARD_AVERMEDIA_305: case SAA7134_BOARD_AVERMEDIA_307: + case SAA7134_BOARD_AVERMEDIA_505: case SAA7134_BOARD_AVERMEDIA_STUDIO_305: case SAA7134_BOARD_AVERMEDIA_STUDIO_505: case SAA7134_BOARD_AVERMEDIA_STUDIO_307: @@ -629,6 +634,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_KWORLD_VSTREAM_XPERT: case SAA7134_BOARD_AVERMEDIA_305: case SAA7134_BOARD_AVERMEDIA_307: + case SAA7134_BOARD_AVERMEDIA_505: case SAA7134_BOARD_AVERMEDIA_STUDIO_305: case SAA7134_BOARD_AVERMEDIA_STUDIO_505: case SAA7134_BOARD_AVERMEDIA_STUDIO_307: @@ -831,8 +837,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) break; } if (NULL == ir_codes) { - printk("%s: Oops: IR config error [card=%d]\n", - dev->name, dev->board); + pr_err("Oops: IR config error [card=%d]\n", dev->board); return -ENODEV; } @@ -916,7 +921,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) int rc; if (disable_ir) { - dprintk("IR has been disabled, not probing for i2c remote\n"); + input_dbg("IR has been disabled, not probing for i2c remote\n"); return; } @@ -959,7 +964,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) an existing device. Weird... REVISIT: might no longer be needed */ rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1); - dprintk("probe 0x%02x @ %s: %s\n", + input_dbg("probe 0x%02x @ %s: %s\n", msg_msi.addr, dev->i2c_adap.name, (1 == rc) ? "yes" : "no"); break; @@ -974,7 +979,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) an existing device. Weird... REVISIT: might no longer be needed */ rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1); - dprintk("probe 0x%02x @ %s: %s\n", + input_dbg("probe 0x%02x @ %s: %s\n", msg_msi.addr, dev->i2c_adap.name, (1 == rc) ? "yes" : "no"); break; @@ -1019,7 +1024,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) info.addr = 0x0b; break; default: - dprintk("No I2C IR support for board %x\n", dev->board); + input_dbg("No I2C IR support for board %x\n", dev->board); return; } diff --git a/drivers/media/pci/saa7134/saa7134-ts.c b/drivers/media/pci/saa7134/saa7134-ts.c index 2709b83..4b202fa 100644 --- a/drivers/media/pci/saa7134/saa7134-ts.c +++ b/drivers/media/pci/saa7134/saa7134-ts.c @@ -20,23 +20,25 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/list.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> -#include "saa7134-reg.h" -#include "saa7134.h" - /* ------------------------------------------------------------------ */ static unsigned int ts_debug; module_param(ts_debug, int, 0644); MODULE_PARM_DESC(ts_debug,"enable debug messages [ts]"); -#define dprintk(fmt, arg...) if (ts_debug) \ - printk(KERN_DEBUG "%s/ts: " fmt, dev->name , ## arg) +#define ts_dbg(fmt, arg...) do { \ + if (ts_debug) \ + printk(KERN_DEBUG pr_fmt("ts: " fmt), ## arg); \ + } while (0) /* ------------------------------------------------------------------ */ static int buffer_activate(struct saa7134_dev *dev, @@ -44,7 +46,7 @@ static int buffer_activate(struct saa7134_dev *dev, struct saa7134_buf *next) { - dprintk("buffer_activate [%p]",buf); + ts_dbg("buffer_activate [%p]", buf); buf->top_seen = 0; if (!dev->ts_started) @@ -53,12 +55,12 @@ static int buffer_activate(struct saa7134_dev *dev, if (NULL == next) next = buf; if (V4L2_FIELD_TOP == dev->ts_field) { - dprintk("- [top] buf=%p next=%p\n",buf,next); + ts_dbg("- [top] buf=%p next=%p\n", buf, next); saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(buf)); saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(next)); dev->ts_field = V4L2_FIELD_BOTTOM; } else { - dprintk("- [bottom] buf=%p next=%p\n",buf,next); + ts_dbg("- [bottom] buf=%p next=%p\n", buf, next); saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next)); saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf)); dev->ts_field = V4L2_FIELD_TOP; @@ -95,7 +97,7 @@ int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2) struct sg_table *dma = vb2_dma_sg_plane_desc(vb2, 0); unsigned int lines, llength, size; - dprintk("buffer_prepare [%p]\n", buf); + ts_dbg("buffer_prepare [%p]\n", buf); llength = TS_PACKET_SIZE; lines = dev->ts.nr_packets; @@ -239,7 +241,7 @@ int saa7134_ts_init1(struct saa7134_dev *dev) /* Function for stop TS */ int saa7134_ts_stop(struct saa7134_dev *dev) { - dprintk("TS stop\n"); + ts_dbg("TS stop\n"); if (!dev->ts_started) return 0; @@ -261,7 +263,7 @@ int saa7134_ts_stop(struct saa7134_dev *dev) /* Function for start TS */ int saa7134_ts_start(struct saa7134_dev *dev) { - dprintk("TS start\n"); + ts_dbg("TS start\n"); if (WARN_ON(dev->ts_started)) return 0; diff --git a/drivers/media/pci/saa7134/saa7134-tvaudio.c b/drivers/media/pci/saa7134/saa7134-tvaudio.c index 3afbcb7..21a5793 100644 --- a/drivers/media/pci/saa7134/saa7134-tvaudio.c +++ b/drivers/media/pci/saa7134/saa7134-tvaudio.c @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/list.h> #include <linux/module.h> @@ -29,9 +32,6 @@ #include <linux/freezer.h> #include <asm/div64.h> -#include "saa7134-reg.h" -#include "saa7134.h" - /* ------------------------------------------------------------------ */ static unsigned int audio_debug; @@ -49,13 +49,10 @@ static int audio_clock_tweak; module_param(audio_clock_tweak, int, 0644); MODULE_PARM_DESC(audio_clock_tweak, "Audio clock tick fine tuning for cards with audio crystal that's slightly off (range [-1024 .. 1024])"); -#define dprintk(fmt, arg...) if (audio_debug) \ - printk(KERN_DEBUG "%s/audio: " fmt, dev->name , ## arg) -#define d2printk(fmt, arg...) if (audio_debug > 1) \ - printk(KERN_DEBUG "%s/audio: " fmt, dev->name, ## arg) - -#define print_regb(reg) printk("%s: reg 0x%03x [%-16s]: 0x%02x\n", \ - dev->name,(SAA7134_##reg),(#reg),saa_readb((SAA7134_##reg))) +#define audio_dbg(level, fmt, arg...) do { \ + if (audio_debug >= level) \ + printk(KERN_DEBUG pr_fmt("audio: " fmt), ## arg); \ + } while (0) /* msecs */ #define SCAN_INITIAL_DELAY 1000 @@ -206,13 +203,14 @@ static void mute_input_7134(struct saa7134_dev *dev) if (dev->hw_mute == mute && dev->hw_input == in && !dev->insuspend) { - dprintk("mute/input: nothing to do [mute=%d,input=%s]\n", - mute,in->name); + audio_dbg(1, "mute/input: nothing to do [mute=%d,input=%s]\n", + mute, in->name); return; } - dprintk("ctl_mute=%d automute=%d input=%s => mute=%d input=%s\n", - dev->ctl_mute,dev->automute,dev->input->name,mute,in->name); + audio_dbg(1, "ctl_mute=%d automute=%d input=%s => mute=%d input=%s\n", + dev->ctl_mute, dev->automute, + dev->input->name, mute, in->name); dev->hw_mute = mute; dev->hw_input = in; @@ -265,8 +263,8 @@ static void tvaudio_setmode(struct saa7134_dev *dev, tweak = audio_clock_tweak; if (note) - dprintk("tvaudio_setmode: %s %s [%d.%03d/%d.%03d MHz] acpf=%d%+d\n", - note,audio->name, + audio_dbg(1, "tvaudio_setmode: %s %s [%d.%03d/%d.%03d MHz] acpf=%d%+d\n", + note, audio->name, audio->carr1 / 1000, audio->carr1 % 1000, audio->carr2 / 1000, audio->carr2 % 1000, acpf, tweak); @@ -334,14 +332,14 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan) if (!(dev->tvnorm->id & scan->std)) { value = 0; - dprintk("skipping %d.%03d MHz [%4s]\n", - scan->carr / 1000, scan->carr % 1000, scan->name); + audio_dbg(1, "skipping %d.%03d MHz [%4s]\n", + scan->carr / 1000, scan->carr % 1000, scan->name); return 0; } if (audio_debug > 1) { int i; - dprintk("debug %d:",scan->carr); + audio_dbg(1, "debug %d:", scan->carr); for (i = -150; i <= 150; i += 30) { tvaudio_setcarrier(dev,scan->carr+i,scan->carr+i); saa_readl(SAA7134_LEVEL_READOUT1 >> 2); @@ -349,11 +347,11 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan) return -1; value = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); if (0 == i) - printk(" # %6d # ",value >> 16); + pr_cont(" # %6d # ", value >> 16); else - printk(" %6d",value >> 16); + pr_cont(" %6d", value >> 16); } - printk("\n"); + pr_cont("\n"); } tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90); @@ -371,9 +369,9 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan) left >>= 16; right >>= 16; value = left > right ? left - right : right - left; - dprintk("scanning %d.%03d MHz [%4s] => dc is %5d [%d/%d]\n", - scan->carr / 1000, scan->carr % 1000, - scan->name, value, left, right); + audio_dbg(1, "scanning %d.%03d MHz [%4s] => dc is %5d [%d/%d]\n", + scan->carr / 1000, scan->carr % 1000, + scan->name, value, left, right); return value; } @@ -389,7 +387,7 @@ static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au case TVAUDIO_FM_K_STEREO: case TVAUDIO_FM_BG_STEREO: idp = (saa_readb(SAA7134_IDENT_SIF) & 0xe0) >> 5; - dprintk("getstereo: fm/stereo: idp=0x%x\n",idp); + audio_dbg(1, "getstereo: fm/stereo: idp=0x%x\n", idp); if (0x03 == (idp & 0x03)) retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; else if (0x05 == (idp & 0x05)) @@ -403,10 +401,11 @@ static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au case TVAUDIO_NICAM_FM: case TVAUDIO_NICAM_AM: nicam = saa_readb(SAA7134_AUDIO_STATUS); - dprintk("getstereo: nicam=0x%x\n",nicam); + audio_dbg(1, "getstereo: nicam=0x%x\n", nicam); if (nicam & 0x1) { nicam_status = saa_readb(SAA7134_NICAM_STATUS); - dprintk("getstereo: nicam_status=0x%x\n", nicam_status); + audio_dbg(1, "getstereo: nicam_status=0x%x\n", + nicam_status); switch (nicam_status & 0x03) { case 0x01: @@ -424,7 +423,7 @@ static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au break; } if (retval != -1) - dprintk("found audio subchannels:%s%s%s%s\n", + audio_dbg(1, "found audio subchannels:%s%s%s%s\n", (retval & V4L2_TUNER_SUB_MONO) ? " mono" : "", (retval & V4L2_TUNER_SUB_STEREO) ? " stereo" : "", (retval & V4L2_TUNER_SUB_LANG1) ? " lang1" : "", @@ -459,8 +458,8 @@ static int tvaudio_setstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au case TVAUDIO_FM_BG_STEREO: case TVAUDIO_NICAM_AM: case TVAUDIO_NICAM_FM: - dprintk("setstereo [fm] => %s\n", - name[ mode % ARRAY_SIZE(name) ]); + audio_dbg(1, "setstereo [fm] => %s\n", + name[mode % ARRAY_SIZE(name)]); reg = fm[ mode % ARRAY_SIZE(fm) ]; saa_writeb(SAA7134_FM_DEMATRIX, reg); break; @@ -489,7 +488,8 @@ static int tvaudio_thread(void *data) try_to_freeze(); dev->thread.scan1 = dev->thread.scan2; - dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1); + audio_dbg(1, "tvaudio thread scan start [%d]\n", + dev->thread.scan1); dev->tvaudio = NULL; saa_writeb(SAA7134_MONITOR_SELECT, 0xa0); @@ -519,7 +519,7 @@ static int tvaudio_thread(void *data) if (1 == nscan) { /* only one candidate -- skip scan ;) */ - dprintk("only one main carrier candidate - skipping scan\n"); + audio_dbg(1, "only one main carrier candidate - skipping scan\n"); max1 = 12345; carrier = default_carrier; } else { @@ -544,26 +544,24 @@ static int tvaudio_thread(void *data) if (0 != carrier && max1 > 2000 && max1 > max2*3) { /* found good carrier */ - dprintk("found %s main sound carrier @ %d.%03d MHz [%d/%d]\n", - dev->tvnorm->name, carrier/1000, carrier%1000, - max1, max2); + audio_dbg(1, "found %s main sound carrier @ %d.%03d MHz [%d/%d]\n", + dev->tvnorm->name, carrier/1000, carrier%1000, + max1, max2); dev->last_carrier = carrier; dev->automute = 0; } else if (0 != dev->last_carrier) { /* no carrier -- try last detected one as fallback */ carrier = dev->last_carrier; - dprintk("audio carrier scan failed, " - "using %d.%03d MHz [last detected]\n", - carrier/1000, carrier%1000); + audio_dbg(1, "audio carrier scan failed, using %d.%03d MHz [last detected]\n", + carrier/1000, carrier%1000); dev->automute = 1; } else { /* no carrier + no fallback -- use default */ carrier = default_carrier; - dprintk("audio carrier scan failed, " - "using %d.%03d MHz [default]\n", - carrier/1000, carrier%1000); + audio_dbg(1, "audio carrier scan failed, using %d.%03d MHz [default]\n", + carrier/1000, carrier%1000); dev->automute = 1; } tvaudio_setcarrier(dev,carrier,carrier); @@ -661,7 +659,7 @@ static inline int saa_dsp_reset_error_bit(struct saa7134_dev *dev) { int state = saa_readb(SAA7135_DSP_RWSTATE); if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) { - d2printk("%s: resetting error bit\n", dev->name); + audio_dbg(2, "%s: resetting error bit\n", dev->name); saa_writeb(SAA7135_DSP_RWCLEAR, SAA7135_DSP_RWCLEAR_RERR); } return 0; @@ -673,18 +671,17 @@ static inline int saa_dsp_wait_bit(struct saa7134_dev *dev, int bit) state = saa_readb(SAA7135_DSP_RWSTATE); if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) { - printk(KERN_WARNING "%s: dsp access error\n", dev->name); + pr_warn("%s: dsp access error\n", dev->name); saa_dsp_reset_error_bit(dev); return -EIO; } while (0 == (state & bit)) { if (unlikely(0 == count)) { - printk("%s: dsp access wait timeout [bit=%s]\n", - dev->name, - (bit & SAA7135_DSP_RWSTATE_WRR) ? "WRR" : - (bit & SAA7135_DSP_RWSTATE_RDB) ? "RDB" : - (bit & SAA7135_DSP_RWSTATE_IDA) ? "IDA" : - "???"); + pr_err("dsp access wait timeout [bit=%s]\n", + (bit & SAA7135_DSP_RWSTATE_WRR) ? "WRR" : + (bit & SAA7135_DSP_RWSTATE_RDB) ? "RDB" : + (bit & SAA7135_DSP_RWSTATE_IDA) ? "IDA" : + "???"); return -EIO; } saa_wait(DSP_DELAY); @@ -699,7 +696,7 @@ int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value) { int err; - d2printk("dsp write reg 0x%x = 0x%06x\n",reg<<2,value); + audio_dbg(2, "dsp write reg 0x%x = 0x%06x\n", reg << 2, value); err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR); if (err < 0) return err; @@ -786,14 +783,16 @@ static int tvaudio_thread_ddep(void *data) try_to_freeze(); dev->thread.scan1 = dev->thread.scan2; - dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1); + audio_dbg(1, "tvaudio thread scan start [%d]\n", + dev->thread.scan1); if (audio_ddep >= 0x04 && audio_ddep <= 0x0e) { /* insmod option override */ norms = (audio_ddep << 2) | 0x01; - dprintk("ddep override: %s\n",stdres[audio_ddep]); + audio_dbg(1, "ddep override: %s\n", + stdres[audio_ddep]); } else if (&card(dev).radio == dev->input) { - dprintk("FM Radio\n"); + audio_dbg(1, "FM Radio\n"); if (dev->tuner_type == TUNER_PHILIPS_TDA8290) { norms = (0x11 << 2) | 0x01; /* set IF frequency to 5.5 MHz */ @@ -816,12 +815,12 @@ static int tvaudio_thread_ddep(void *data) norms |= 0x10; if (0 == norms) norms = 0x7c; /* all */ - dprintk("scanning:%s%s%s%s%s\n", - (norms & 0x04) ? " B/G" : "", - (norms & 0x08) ? " D/K" : "", - (norms & 0x10) ? " L/L'" : "", - (norms & 0x20) ? " I" : "", - (norms & 0x40) ? " M" : ""); + audio_dbg(1, "scanning:%s%s%s%s%s\n", + (norms & 0x04) ? " B/G" : "", + (norms & 0x08) ? " D/K" : "", + (norms & 0x10) ? " L/L'" : "", + (norms & 0x20) ? " I" : "", + (norms & 0x40) ? " M" : ""); } /* kick automatic standard detection */ @@ -836,29 +835,28 @@ static int tvaudio_thread_ddep(void *data) goto restart; value = saa_readl(0x528 >> 2) & 0xffffff; - dprintk("tvaudio thread status: 0x%x [%s%s%s]\n", - value, stdres[value & 0x1f], - (value & 0x000020) ? ",stereo" : "", - (value & 0x000040) ? ",dual" : ""); - dprintk("detailed status: " - "%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n", - (value & 0x000080) ? " A2/EIAJ pilot tone " : "", - (value & 0x000100) ? " A2/EIAJ dual " : "", - (value & 0x000200) ? " A2/EIAJ stereo " : "", - (value & 0x000400) ? " A2/EIAJ noise mute " : "", - - (value & 0x000800) ? " BTSC/FM radio pilot " : "", - (value & 0x001000) ? " SAP carrier " : "", - (value & 0x002000) ? " BTSC stereo noise mute " : "", - (value & 0x004000) ? " SAP noise mute " : "", - (value & 0x008000) ? " VDSP " : "", - - (value & 0x010000) ? " NICST " : "", - (value & 0x020000) ? " NICDU " : "", - (value & 0x040000) ? " NICAM muted " : "", - (value & 0x080000) ? " NICAM reserve sound " : "", - - (value & 0x100000) ? " init done " : ""); + audio_dbg(1, "tvaudio thread status: 0x%x [%s%s%s]\n", + value, stdres[value & 0x1f], + (value & 0x000020) ? ",stereo" : "", + (value & 0x000040) ? ",dual" : ""); + audio_dbg(1, "detailed status: %s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n", + (value & 0x000080) ? " A2/EIAJ pilot tone " : "", + (value & 0x000100) ? " A2/EIAJ dual " : "", + (value & 0x000200) ? " A2/EIAJ stereo " : "", + (value & 0x000400) ? " A2/EIAJ noise mute " : "", + + (value & 0x000800) ? " BTSC/FM radio pilot " : "", + (value & 0x001000) ? " SAP carrier " : "", + (value & 0x002000) ? " BTSC stereo noise mute " : "", + (value & 0x004000) ? " SAP noise mute " : "", + (value & 0x008000) ? " VDSP " : "", + + (value & 0x010000) ? " NICST " : "", + (value & 0x020000) ? " NICDU " : "", + (value & 0x040000) ? " NICAM muted " : "", + (value & 0x080000) ? " NICAM reserve sound " : "", + + (value & 0x100000) ? " init done " : ""); } done: @@ -1031,7 +1029,7 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev) /* start tvaudio thread */ dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name); if (IS_ERR(dev->thread.thread)) { - printk(KERN_WARNING "%s: kernel_thread() failed\n", + pr_warn("%s: kernel_thread() failed\n", dev->name); /* XXX: missing error handling here */ } @@ -1061,7 +1059,7 @@ int saa7134_tvaudio_fini(struct saa7134_dev *dev) int saa7134_tvaudio_do_scan(struct saa7134_dev *dev) { if (dev->input->amux != TV) { - dprintk("sound IF not in use, skipping scan\n"); + audio_dbg(1, "sound IF not in use, skipping scan\n"); dev->automute = 0; saa7134_tvaudio_setmute(dev); } else if (dev->thread.thread) { diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c index 5306e54..4d36586 100644 --- a/drivers/media/pci/saa7134/saa7134-vbi.c +++ b/drivers/media/pci/saa7134/saa7134-vbi.c @@ -20,14 +20,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/list.h> #include <linux/module.h> #include <linux/kernel.h> -#include "saa7134-reg.h" -#include "saa7134.h" - /* ------------------------------------------------------------------ */ static unsigned int vbi_debug; @@ -38,8 +38,10 @@ static unsigned int vbibufs = 4; module_param(vbibufs, int, 0444); MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32"); -#define dprintk(fmt, arg...) if (vbi_debug) \ - printk(KERN_DEBUG "%s/vbi: " fmt, dev->name , ## arg) +#define vbi_dbg(fmt, arg...) do { \ + if (vbi_debug) \ + printk(KERN_DEBUG pr_fmt("vbi: " fmt), ## arg); \ + } while (0) /* ------------------------------------------------------------------ */ @@ -84,7 +86,7 @@ static int buffer_activate(struct saa7134_dev *dev, struct saa7134_dmaqueue *dmaq = buf->vb2.vb2_queue->drv_priv; unsigned long control, base; - dprintk("buffer_activate [%p]\n", buf); + vbi_dbg("buffer_activate [%p]\n", buf); buf->top_seen = 0; task_init(dev, buf, TASK_A); diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 99d09a7..035039c 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/list.h> #include <linux/module.h> @@ -31,9 +34,6 @@ #include <media/v4l2-event.h> #include <media/saa6588.h> -#include "saa7134-reg.h" -#include "saa7134.h" - /* ------------------------------------------------------------------ */ unsigned int video_debug; @@ -52,8 +52,10 @@ module_param_string(secam, secam, sizeof(secam), 0644); MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); -#define dprintk(fmt, arg...) if (video_debug&0x04) \ - printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg) +#define video_dbg(fmt, arg...) do { \ + if (video_debug & 0x04) \ + printk(KERN_DEBUG pr_fmt("video: " fmt), ## arg); \ + } while (0) /* ------------------------------------------------------------------ */ /* Defines for Video Output Port Register at address 0x191 */ @@ -385,7 +387,7 @@ static struct saa7134_format* format_by_fourcc(unsigned int fourcc) static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) { - dprintk("set tv norm = %s\n",norm->name); + video_dbg("set tv norm = %s\n", norm->name); dev->tvnorm = norm; /* setup cropping */ @@ -407,7 +409,7 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) static void video_mux(struct saa7134_dev *dev, int input) { - dprintk("video input = %d [%s]\n", input, card_in(dev, input).name); + video_dbg("video input = %d [%s]\n", input, card_in(dev, input).name); dev->ctl_input = input; set_tvnorm(dev, dev->tvnorm); saa7134_tvaudio_setinput(dev, &card_in(dev, input)); @@ -531,14 +533,14 @@ static void set_v_scale(struct saa7134_dev *dev, int task, int yscale) mirror = (dev->ctl_mirror) ? 0x02 : 0x00; if (yscale < 2048) { /* LPI */ - dprintk("yscale LPI yscale=%d\n",yscale); + video_dbg("yscale LPI yscale=%d\n", yscale); saa_writeb(SAA7134_V_FILTER(task), 0x00 | mirror); saa_writeb(SAA7134_LUMA_CONTRAST(task), 0x40); saa_writeb(SAA7134_CHROMA_SATURATION(task), 0x40); } else { /* ACM */ val = 0x40 * 1024 / yscale; - dprintk("yscale ACM yscale=%d val=0x%x\n",yscale,val); + video_dbg("yscale ACM yscale=%d val=0x%x\n", yscale, val); saa_writeb(SAA7134_V_FILTER(task), 0x01 | mirror); saa_writeb(SAA7134_LUMA_CONTRAST(task), val); saa_writeb(SAA7134_CHROMA_SATURATION(task), val); @@ -573,7 +575,8 @@ static void set_size(struct saa7134_dev *dev, int task, prescale = 1; xscale = 1024 * dev->crop_current.width / prescale / width; yscale = 512 * div * dev->crop_current.height / height; - dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale); + video_dbg("prescale=%d xscale=%d yscale=%d\n", + prescale, xscale, yscale); set_h_prescale(dev,task,prescale); saa_writeb(SAA7134_H_SCALE_INC1(task), xscale & 0xff); saa_writeb(SAA7134_H_SCALE_INC2(task), xscale >> 8); @@ -615,7 +618,7 @@ static void set_cliplist(struct saa7134_dev *dev, int reg, saa_writeb(reg + 0, winbits); saa_writeb(reg + 2, cl[i].position & 0xff); saa_writeb(reg + 3, cl[i].position >> 8); - dprintk("clip: %s winbits=%02x pos=%d\n", + video_dbg("clip: %s winbits=%02x pos=%d\n", name,winbits,cl[i].position); reg += 8; } @@ -730,7 +733,7 @@ static int start_preview(struct saa7134_dev *dev) return err; dev->ovfield = dev->win.field; - dprintk("start_preview %dx%d+%d+%d %s field=%s\n", + video_dbg("start_preview %dx%d+%d+%d %s field=%s\n", dev->win.w.width, dev->win.w.height, dev->win.w.left, dev->win.w.top, dev->ovfmt->name, v4l2_field_names[dev->ovfield]); @@ -792,7 +795,7 @@ static int buffer_activate(struct saa7134_dev *dev, unsigned long base,control,bpl; unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */ - dprintk("buffer_activate buf=%p\n",buf); + video_dbg("buffer_activate buf=%p\n", buf); buf->top_seen = 0; set_size(dev, TASK_A, dev->width, dev->height, @@ -837,7 +840,7 @@ static int buffer_activate(struct saa7134_dev *dev, base3 = base2 + bpl_uv * lines_uv; if (dev->fmt->uvswap) tmp = base2, base2 = base3, base3 = tmp; - dprintk("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n", + video_dbg("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n", bpl_uv,lines_uv,base2,base3); if (V4L2_FIELD_HAS_BOTH(dev->field)) { /* interlaced */ @@ -1229,7 +1232,7 @@ static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv, int i; if (saa7134_no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } f->fmt.win = dev->win; @@ -1305,7 +1308,7 @@ static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv, struct saa7134_dev *dev = video_drvdata(file); if (saa7134_no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } @@ -1339,7 +1342,7 @@ static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv, unsigned long flags; if (saa7134_no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } if (f->fmt.win.clips == NULL) @@ -1738,7 +1741,7 @@ static int saa7134_enum_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (saa7134_no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } @@ -1795,7 +1798,7 @@ static int saa7134_overlay(struct file *file, void *priv, unsigned int on) if (on) { if (saa7134_no_overlay > 0) { - dprintk("no_overlay\n"); + video_dbg("no_overlay\n"); return -EINVAL; } @@ -2184,7 +2187,7 @@ void saa7134_irq_video_signalchange(struct saa7134_dev *dev) st1 = saa_readb(SAA7134_STATUS_VIDEO1); st2 = saa_readb(SAA7134_STATUS_VIDEO2); - dprintk("DCSDT: pll: %s, sync: %s, norm: %s\n", + video_dbg("DCSDT: pll: %s, sync: %s, norm: %s\n", (st1 & 0x40) ? "not locked" : "locked", (st2 & 0x40) ? "no" : "yes", st[st1 & 0x03]); diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index 8bf0553..6b5f6f4 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -21,6 +21,8 @@ #define SAA7134_VERSION "0, 2, 17" +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/pci.h> #include <linux/i2c.h> #include <linux/videodev2.h> @@ -339,6 +341,7 @@ struct saa7134_card_ir { #define SAA7134_BOARD_HAWELL_HW_9004V1 191 #define SAA7134_BOARD_AVERMEDIA_A706 192 #define SAA7134_BOARD_WIS_VOYAGER 193 +#define SAA7134_BOARD_AVERMEDIA_505 194 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 @@ -654,7 +657,8 @@ struct saa7134_dev { /* SAA7134_MPEG_DVB only */ struct vb2_dvb_frontends frontends; int (*original_demod_sleep)(struct dvb_frontend *fe); - int (*original_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage); + int (*original_set_voltage)(struct dvb_frontend *fe, + enum fe_sec_voltage voltage); int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg); #endif void (*gate_ctrl)(struct saa7134_dev *dev, int open); diff --git a/drivers/media/pci/saa7164/saa7164-api.c b/drivers/media/pci/saa7164/saa7164-api.c index 4f3b1dd..e7e586c 100644 --- a/drivers/media/pci/saa7164/saa7164-api.c +++ b/drivers/media/pci/saa7164/saa7164-api.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.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 @@ -1373,7 +1373,8 @@ int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg, u8 buf[256]; int ret; - dprintk(DBGLVL_API, "%s()\n", __func__); + dprintk(DBGLVL_API, "%s() addr=%x reglen=%d datalen=%d\n", + __func__, addr, reglen, datalen); if (reglen > 4) return -EIO; @@ -1434,7 +1435,8 @@ int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen, u8 buf[256]; int ret; - dprintk(DBGLVL_API, "%s()\n", __func__); + dprintk(DBGLVL_API, "%s() addr=0x%2x len=0x%x\n", + __func__, addr, datalen); if ((datalen == 0) || (datalen > 232)) return -EIO; @@ -1464,7 +1466,8 @@ int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen, return -EIO; } - dprintk(DBGLVL_API, "%s() len = %d bytes\n", __func__, len); + dprintk(DBGLVL_API, "%s() len = %d bytes unitid=0x%x\n", __func__, + len, unitid); /* Prepare the send buffer */ /* Bytes 00-03 dest register length diff --git a/drivers/media/pci/saa7164/saa7164-buffer.c b/drivers/media/pci/saa7164/saa7164-buffer.c index 9bd1f73..f30758e 100644 --- a/drivers/media/pci/saa7164/saa7164-buffer.c +++ b/drivers/media/pci/saa7164/saa7164-buffer.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.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 diff --git a/drivers/media/pci/saa7164/saa7164-bus.c b/drivers/media/pci/saa7164/saa7164-bus.c index 6c73f5b..a18fe5d 100644 --- a/drivers/media/pci/saa7164/saa7164-bus.c +++ b/drivers/media/pci/saa7164/saa7164-bus.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.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 diff --git a/drivers/media/pci/saa7164/saa7164-cards.c b/drivers/media/pci/saa7164/saa7164-cards.c index 5b72da5..c2b7382 100644 --- a/drivers/media/pci/saa7164/saa7164-cards.c +++ b/drivers/media/pci/saa7164/saa7164-cards.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.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 @@ -30,6 +30,7 @@ * attached I2C devices, so we can simplify the virtual i2c mechansms * and keep the -i2c.c implementation clean. */ +#define REGLEN_0bit 0 #define REGLEN_8bit 1 #define REGLEN_16bit 2 @@ -499,6 +500,144 @@ struct saa7164_board saa7164_boards[] = { .i2c_reg_len = REGLEN_8bit, } }, }, + [SAA7164_BOARD_HAUPPAUGE_HVR2255proto] = { + .name = "Hauppauge WinTV-HVR2255(proto)", + .porta = SAA7164_MPEG_DVB, + .portb = SAA7164_MPEG_DVB, + .portc = SAA7164_MPEG_ENCODER, + .portd = SAA7164_MPEG_ENCODER, + .porte = SAA7164_MPEG_VBI, + .portf = SAA7164_MPEG_VBI, + .chiprev = SAA7164_CHIP_REV3, + .unit = {{ + .id = 0x27, + .type = SAA7164_UNIT_EEPROM, + .name = "4K EEPROM", + .i2c_bus_nr = SAA7164_I2C_BUS_0, + .i2c_bus_addr = 0xa0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x04, + .type = SAA7164_UNIT_TUNER, + .name = "SI2157-1", + .i2c_bus_nr = SAA7164_I2C_BUS_0, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_0bit, + }, { + .id = 0x06, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "LGDT3306", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0xb2 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x24, + .type = SAA7164_UNIT_TUNER, + .name = "SI2157-2", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_0bit, + }, { + .id = 0x26, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "LGDT3306-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0x1c >> 1, + .i2c_reg_len = REGLEN_8bit, + } }, + }, + [SAA7164_BOARD_HAUPPAUGE_HVR2255] = { + .name = "Hauppauge WinTV-HVR2255", + .porta = SAA7164_MPEG_DVB, + .portb = SAA7164_MPEG_DVB, + .portc = SAA7164_MPEG_ENCODER, + .portd = SAA7164_MPEG_ENCODER, + .porte = SAA7164_MPEG_VBI, + .portf = SAA7164_MPEG_VBI, + .chiprev = SAA7164_CHIP_REV3, + .unit = {{ + .id = 0x28, + .type = SAA7164_UNIT_EEPROM, + .name = "4K EEPROM", + .i2c_bus_nr = SAA7164_I2C_BUS_0, + .i2c_bus_addr = 0xa0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x04, + .type = SAA7164_UNIT_TUNER, + .name = "SI2157-1", + .i2c_bus_nr = SAA7164_I2C_BUS_0, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_0bit, + }, { + .id = 0x06, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "LGDT3306-1", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0xb2 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x25, + .type = SAA7164_UNIT_TUNER, + .name = "SI2157-2", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_0bit, + }, { + .id = 0x27, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "LGDT3306-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0x1c >> 1, + .i2c_reg_len = REGLEN_8bit, + } }, + }, + [SAA7164_BOARD_HAUPPAUGE_HVR2205] = { + .name = "Hauppauge WinTV-HVR2205", + .porta = SAA7164_MPEG_DVB, + .portb = SAA7164_MPEG_DVB, + .portc = SAA7164_MPEG_ENCODER, + .portd = SAA7164_MPEG_ENCODER, + .porte = SAA7164_MPEG_VBI, + .portf = SAA7164_MPEG_VBI, + .chiprev = SAA7164_CHIP_REV3, + .unit = {{ + .id = 0x28, + .type = SAA7164_UNIT_EEPROM, + .name = "4K EEPROM", + .i2c_bus_nr = SAA7164_I2C_BUS_0, + .i2c_bus_addr = 0xa0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x04, + .type = SAA7164_UNIT_TUNER, + .name = "SI2157-1", + .i2c_bus_nr = SAA7164_I2C_BUS_0, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_0bit, + }, { + .id = 0x06, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "SI2168-1", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0xc8 >> 1, + .i2c_reg_len = REGLEN_0bit, + }, { + .id = 0x25, + .type = SAA7164_UNIT_TUNER, + .name = "SI2157-2", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_0bit, + }, { + .id = 0x27, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "SI2168-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0xcc >> 1, + .i2c_reg_len = REGLEN_0bit, + } }, + }, }; const unsigned int saa7164_bcount = ARRAY_SIZE(saa7164_boards); @@ -546,6 +685,21 @@ struct saa7164_subid saa7164_subids[] = { .subvendor = 0x0070, .subdevice = 0x8953, .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_5, + }, { + .subvendor = 0x0070, + .subdevice = 0xf111, + .card = SAA7164_BOARD_HAUPPAUGE_HVR2255, + /* Prototype card left here for documenation purposes. + .card = SAA7164_BOARD_HAUPPAUGE_HVR2255proto, + */ + }, { + .subvendor = 0x0070, + .subdevice = 0xf123, + .card = SAA7164_BOARD_HAUPPAUGE_HVR2205, + }, { + .subvendor = 0x0070, + .subdevice = 0xf120, + .card = SAA7164_BOARD_HAUPPAUGE_HVR2205, }, }; const unsigned int saa7164_idcount = ARRAY_SIZE(saa7164_subids); @@ -594,12 +748,26 @@ void saa7164_gpio_setup(struct saa7164_dev *dev) case SAA7164_BOARD_HAUPPAUGE_HVR2250: case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: + case SAA7164_BOARD_HAUPPAUGE_HVR2255proto: + case SAA7164_BOARD_HAUPPAUGE_HVR2255: + case SAA7164_BOARD_HAUPPAUGE_HVR2205: /* + HVR2200 / HVR2250 GPIO 2: s5h1411 / tda10048-1 demod reset GPIO 3: s5h1411 / tda10048-2 demod reset GPIO 7: IRBlaster Zilog reset */ + /* HVR2255 + * GPIO 2: lgdg3306-1 demod reset + * GPIO 3: lgdt3306-2 demod reset + */ + + /* HVR2205 + * GPIO 2: si2168-1 demod reset + * GPIO 3: si2168-2 demod reset + */ + /* Reset parts by going in and out of reset */ saa7164_api_clear_gpiobit(dev, PCIEBRIDGE_UNITID, 2); saa7164_api_clear_gpiobit(dev, PCIEBRIDGE_UNITID, 3); @@ -647,6 +815,21 @@ static void hauppauge_eeprom(struct saa7164_dev *dev, u8 *eeprom_data) /* WinTV-HVR2200 (PCIe, Retail, half-height) * DVB-T (TDA18271/TDA10048) and basic analog, no IR */ break; + case 151009: + /* First production board rev B2I6 */ + /* WinTV-HVR2205 (PCIe, Retail, full-height bracket) + * DVB-T/T2/C (SI2157/SI2168) and basic analog, FM */ + break; + case 151609: + /* First production board rev B2I6 */ + /* WinTV-HVR2205 (PCIe, Retail, half-height bracket) + * DVB-T/T2/C (SI2157/SI2168) and basic analog, FM */ + break; + case 151061: + /* First production board rev B1I6 */ + /* WinTV-HVR2255 (PCIe, Retail, full-height bracket) + * ATSC/QAM (SI2157/LGDT3306) and basic analog, FM */ + break; default: printk(KERN_ERR "%s: Warning: Unknown Hauppauge model #%d\n", dev->name, tv.model); @@ -676,6 +859,9 @@ void saa7164_card_setup(struct saa7164_dev *dev) case SAA7164_BOARD_HAUPPAUGE_HVR2250: case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: + case SAA7164_BOARD_HAUPPAUGE_HVR2255proto: + case SAA7164_BOARD_HAUPPAUGE_HVR2255: + case SAA7164_BOARD_HAUPPAUGE_HVR2205: hauppauge_eeprom(dev, &eeprom[0]); break; } diff --git a/drivers/media/pci/saa7164/saa7164-cmd.c b/drivers/media/pci/saa7164/saa7164-cmd.c index cfabcba..3285c37 100644 --- a/drivers/media/pci/saa7164/saa7164-cmd.c +++ b/drivers/media/pci/saa7164/saa7164-cmd.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.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 diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index 9cf3c6c..3206a82 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.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 @@ -85,6 +85,11 @@ module_param(guard_checking, int, 0644); MODULE_PARM_DESC(guard_checking, "enable dma sanity checking for buffer overruns"); +static bool enable_msi = true; +module_param(enable_msi, bool, 0444); +MODULE_PARM_DESC(enable_msi, + "enable the use of an msi interrupt if available"); + static unsigned int saa7164_devcount; static DEFINE_MUTEX(devlist); @@ -618,12 +623,7 @@ static irqreturn_t saa7164_irq_ts(struct saa7164_port *port) static irqreturn_t saa7164_irq(int irq, void *dev_id) { struct saa7164_dev *dev = dev_id; - struct saa7164_port *porta = &dev->ports[SAA7164_PORT_TS1]; - struct saa7164_port *portb = &dev->ports[SAA7164_PORT_TS2]; - struct saa7164_port *portc = &dev->ports[SAA7164_PORT_ENC1]; - struct saa7164_port *portd = &dev->ports[SAA7164_PORT_ENC2]; - struct saa7164_port *porte = &dev->ports[SAA7164_PORT_VBI1]; - struct saa7164_port *portf = &dev->ports[SAA7164_PORT_VBI2]; + struct saa7164_port *porta, *portb, *portc, *portd, *porte, *portf; u32 intid, intstat[INT_SIZE/4]; int i, handled = 0, bit; @@ -634,6 +634,13 @@ static irqreturn_t saa7164_irq(int irq, void *dev_id) goto out; } + porta = &dev->ports[SAA7164_PORT_TS1]; + portb = &dev->ports[SAA7164_PORT_TS2]; + portc = &dev->ports[SAA7164_PORT_ENC1]; + portd = &dev->ports[SAA7164_PORT_ENC2]; + porte = &dev->ports[SAA7164_PORT_VBI1]; + portf = &dev->ports[SAA7164_PORT_VBI2]; + /* Check that the hardware is accessible. If the status bytes are * 0xFF then the device is not accessible, the the IRQ belongs * to another driver. @@ -1184,6 +1191,39 @@ static int saa7164_thread_function(void *data) return 0; } +static bool saa7164_enable_msi(struct pci_dev *pci_dev, struct saa7164_dev *dev) +{ + int err; + + if (!enable_msi) { + printk(KERN_WARNING "%s() MSI disabled by module parameter 'enable_msi'" + , __func__); + return false; + } + + err = pci_enable_msi(pci_dev); + + if (err) { + printk(KERN_ERR "%s() Failed to enable MSI interrupt." + " Falling back to a shared IRQ\n", __func__); + return false; + } + + /* no error - so request an msi interrupt */ + err = request_irq(pci_dev->irq, saa7164_irq, 0, + dev->name, dev); + + if (err) { + /* fall back to legacy interrupt */ + printk(KERN_ERR "%s() Failed to get an MSI interrupt." + " Falling back to a shared IRQ\n", __func__); + pci_disable_msi(pci_dev); + return false; + } + + return true; +} + static int saa7164_initdev(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { @@ -1230,13 +1270,22 @@ static int saa7164_initdev(struct pci_dev *pci_dev, goto fail_irq; } - err = request_irq(pci_dev->irq, saa7164_irq, - IRQF_SHARED, dev->name, dev); - if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name, - pci_dev->irq); - err = -EIO; - goto fail_irq; + /* irq bit */ + if (saa7164_enable_msi(pci_dev, dev)) { + dev->msi = true; + } else { + /* if we have an error (i.e. we don't have an interrupt) + or msi is not enabled - fallback to shared interrupt */ + + err = request_irq(pci_dev->irq, saa7164_irq, + IRQF_SHARED, dev->name, dev); + + if (err < 0) { + printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name, + pci_dev->irq); + err = -EIO; + goto fail_irq; + } } pci_set_drvdata(pci_dev, dev); @@ -1439,6 +1488,11 @@ static void saa7164_finidev(struct pci_dev *pci_dev) /* unregister stuff */ free_irq(pci_dev->irq, dev); + if (dev->msi) { + pci_disable_msi(pci_dev); + dev->msi = false; + } + pci_disable_device(pci_dev); mutex_lock(&devlist); diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c b/drivers/media/pci/saa7164/saa7164-dvb.c index 16ae715..e9a783b 100644 --- a/drivers/media/pci/saa7164/saa7164-dvb.c +++ b/drivers/media/pci/saa7164/saa7164-dvb.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.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 @@ -24,6 +24,9 @@ #include "tda10048.h" #include "tda18271.h" #include "s5h1411.h" +#include "si2157.h" +#include "si2168.h" +#include "lgdt3306a.h" #define DRIVER_NAME "saa7164" @@ -82,6 +85,65 @@ static struct s5h1411_config hauppauge_s5h1411_config = { .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; +static struct lgdt3306a_config hauppauge_hvr2255a_config = { + .i2c_addr = 0xb2 >> 1, + .qam_if_khz = 4000, + .vsb_if_khz = 3250, + .deny_i2c_rptr = 1, /* Disabled */ + .spectral_inversion = 0, /* Disabled */ + .mpeg_mode = LGDT3306A_MPEG_SERIAL, + .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE, + .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH, + .xtalMHz = 25, /* 24 or 25 */ +}; + +static struct lgdt3306a_config hauppauge_hvr2255b_config = { + .i2c_addr = 0x1c >> 1, + .qam_if_khz = 4000, + .vsb_if_khz = 3250, + .deny_i2c_rptr = 1, /* Disabled */ + .spectral_inversion = 0, /* Disabled */ + .mpeg_mode = LGDT3306A_MPEG_SERIAL, + .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE, + .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH, + .xtalMHz = 25, /* 24 or 25 */ +}; + +static struct si2157_config hauppauge_hvr2255_tuner_config = { + .inversion = 1, + .if_port = 1, +}; + +static int si2157_attach(struct saa7164_port *port, struct i2c_adapter *adapter, + struct dvb_frontend *fe, u8 addr8bit, struct si2157_config *cfg) +{ + struct i2c_board_info bi; + struct i2c_client *tuner; + + cfg->fe = fe; + + memset(&bi, 0, sizeof(bi)); + + strlcpy(bi.type, "si2157", I2C_NAME_SIZE); + bi.platform_data = cfg; + bi.addr = addr8bit >> 1; + + request_module(bi.type); + + tuner = i2c_new_device(adapter, &bi); + if (tuner == NULL || tuner->dev.driver == NULL) + return -ENODEV; + + if (!try_module_get(tuner->dev.driver->owner)) { + i2c_unregister_device(tuner); + return -ENODEV; + } + + port->i2c_client_tuner = tuner; + + return 0; +} + static int saa7164_dvb_stop_port(struct saa7164_port *port) { struct saa7164_dev *dev = port->dev; @@ -242,14 +304,16 @@ static int saa7164_dvb_start_feed(struct dvb_demux_feed *feed) if (!demux->dmx.frontend) return -EINVAL; - mutex_lock(&dvb->lock); - if (dvb->feeding++ == 0) { - /* Start transport */ - ret = saa7164_dvb_start_port(port); + if (dvb) { + mutex_lock(&dvb->lock); + if (dvb->feeding++ == 0) { + /* Start transport */ + ret = saa7164_dvb_start_port(port); + } + mutex_unlock(&dvb->lock); + dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", + __func__, port->nr, dvb->feeding); } - mutex_unlock(&dvb->lock); - dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", - __func__, port->nr, dvb->feeding); return ret; } @@ -264,14 +328,16 @@ static int saa7164_dvb_stop_feed(struct dvb_demux_feed *feed) dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); - mutex_lock(&dvb->lock); - if (--dvb->feeding == 0) { - /* Stop transport */ - ret = saa7164_dvb_stop_streaming(port); + if (dvb) { + mutex_lock(&dvb->lock); + if (--dvb->feeding == 0) { + /* Stop transport */ + ret = saa7164_dvb_stop_streaming(port); + } + mutex_unlock(&dvb->lock); + dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", + __func__, port->nr, dvb->feeding); } - mutex_unlock(&dvb->lock); - dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", - __func__, port->nr, dvb->feeding); return ret; } @@ -425,6 +491,7 @@ int saa7164_dvb_unregister(struct saa7164_port *port) struct saa7164_dev *dev = port->dev; struct saa7164_buffer *b; struct list_head *c, *n; + struct i2c_client *client; dprintk(DBGLVL_DVB, "%s()\n", __func__); @@ -443,6 +510,20 @@ int saa7164_dvb_unregister(struct saa7164_port *port) if (dvb->frontend == NULL) return 0; + /* remove I2C client for tuner */ + client = port->i2c_client_tuner; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + /* remove I2C client for demodulator */ + client = port->i2c_client_demod; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + dvb_net_release(&dvb->net); dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); @@ -462,6 +543,12 @@ int saa7164_dvb_register(struct saa7164_port *port) struct saa7164_dev *dev = port->dev; struct saa7164_dvb *dvb = &port->dvb; struct saa7164_i2c *i2c_bus = NULL; + struct si2168_config si2168_config; + struct si2157_config si2157_config; + struct i2c_adapter *adapter; + struct i2c_board_info info; + struct i2c_client *client_demod; + struct i2c_client *client_tuner; int ret; dprintk(DBGLVL_DVB, "%s()\n", __func__); @@ -528,6 +615,126 @@ int saa7164_dvb_register(struct saa7164_port *port) } break; + case SAA7164_BOARD_HAUPPAUGE_HVR2255proto: + case SAA7164_BOARD_HAUPPAUGE_HVR2255: + i2c_bus = &dev->i2c_bus[2]; + + if (port->nr == 0) { + port->dvb.frontend = dvb_attach(lgdt3306a_attach, + &hauppauge_hvr2255a_config, &i2c_bus->i2c_adap); + } else { + port->dvb.frontend = dvb_attach(lgdt3306a_attach, + &hauppauge_hvr2255b_config, &i2c_bus->i2c_adap); + } + + if (port->dvb.frontend != NULL) { + + if (port->nr == 0) { + si2157_attach(port, &dev->i2c_bus[0].i2c_adap, + port->dvb.frontend, 0xc0, + &hauppauge_hvr2255_tuner_config); + } else { + si2157_attach(port, &dev->i2c_bus[1].i2c_adap, + port->dvb.frontend, 0xc0, + &hauppauge_hvr2255_tuner_config); + } + } + break; + case SAA7164_BOARD_HAUPPAUGE_HVR2205: + + if (port->nr == 0) { + /* attach frontend */ + memset(&si2168_config, 0, sizeof(si2168_config)); + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &port->dvb.frontend; + si2168_config.ts_mode = SI2168_TS_SERIAL; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2168", I2C_NAME_SIZE); + info.addr = 0xc8 >> 1; + info.platform_data = &si2168_config; + request_module(info.type); + client_demod = i2c_new_device(&dev->i2c_bus[2].i2c_adap, + &info); + if (!client_demod || !client_demod->dev.driver) + goto frontend_detach; + + if (!try_module_get(client_demod->dev.driver->owner)) { + i2c_unregister_device(client_demod); + goto frontend_detach; + } + port->i2c_client_demod = client_demod; + + /* attach tuner */ + memset(&si2157_config, 0, sizeof(si2157_config)); + si2157_config.if_port = 1; + si2157_config.fe = port->dvb.frontend; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = 0xc0 >> 1; + info.platform_data = &si2157_config; + request_module(info.type); + client_tuner = i2c_new_device(&dev->i2c_bus[0].i2c_adap, + &info); + if (!client_tuner || !client_tuner->dev.driver) { + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + goto frontend_detach; + } + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + goto frontend_detach; + } + port->i2c_client_tuner = client_tuner; + } else { + /* attach frontend */ + memset(&si2168_config, 0, sizeof(si2168_config)); + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &port->dvb.frontend; + si2168_config.ts_mode = SI2168_TS_SERIAL; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2168", I2C_NAME_SIZE); + info.addr = 0xcc >> 1; + info.platform_data = &si2168_config; + request_module(info.type); + client_demod = i2c_new_device(&dev->i2c_bus[2].i2c_adap, + &info); + if (!client_demod || !client_demod->dev.driver) + goto frontend_detach; + + if (!try_module_get(client_demod->dev.driver->owner)) { + i2c_unregister_device(client_demod); + goto frontend_detach; + } + port->i2c_client_demod = client_demod; + + /* attach tuner */ + memset(&si2157_config, 0, sizeof(si2157_config)); + si2157_config.fe = port->dvb.frontend; + si2157_config.if_port = 1; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = 0xc0 >> 1; + info.platform_data = &si2157_config; + request_module(info.type); + client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, + &info); + if (!client_tuner || !client_tuner->dev.driver) { + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + goto frontend_detach; + } + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + goto frontend_detach; + } + port->i2c_client_tuner = client_tuner; + } + + break; default: printk(KERN_ERR "%s: The frontend isn't supported\n", dev->name); @@ -548,5 +755,9 @@ int saa7164_dvb_register(struct saa7164_port *port) } return 0; + +frontend_detach: + printk(KERN_ERR "%s() Frontend/I2C initialization failed\n", __func__); + return -1; } diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index 9266965..4434e0f 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.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 @@ -721,13 +721,14 @@ static int vidioc_querycap(struct file *file, void *priv, sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->capabilities = + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - 0; + V4L2_CAP_READWRITE | + V4L2_CAP_TUNER; - cap->capabilities |= V4L2_CAP_TUNER; - cap->version = 0; + cap->capabilities = cap->device_caps | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_DEVICE_CAPS; return 0; } diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c index add06ab..269e078 100644 --- a/drivers/media/pci/saa7164/saa7164-fw.c +++ b/drivers/media/pci/saa7164/saa7164-fw.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.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 diff --git a/drivers/media/pci/saa7164/saa7164-i2c.c b/drivers/media/pci/saa7164/saa7164-i2c.c index 4f7e3b4..0342d84 100644 --- a/drivers/media/pci/saa7164/saa7164-i2c.c +++ b/drivers/media/pci/saa7164/saa7164-i2c.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.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 @@ -39,9 +39,10 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) dprintk(DBGLVL_I2C, "%s(num = %d) addr = 0x%02x len = 0x%x\n", __func__, num, msgs[i].addr, msgs[i].len); if (msgs[i].flags & I2C_M_RD) { - /* Unsupported - Yet*/ - printk(KERN_ERR "%s() Unsupported - Yet\n", __func__); - continue; + retval = saa7164_api_i2c_read(bus, + msgs[i].addr, + 0 /* reglen */, + NULL /* reg */, msgs[i].len, msgs[i].buf); } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && msgs[i].addr == msgs[i + 1].addr) { /* write then read from same address */ diff --git a/drivers/media/pci/saa7164/saa7164-reg.h b/drivers/media/pci/saa7164/saa7164-reg.h index 2bbf815..37521a2 100644 --- a/drivers/media/pci/saa7164/saa7164-reg.h +++ b/drivers/media/pci/saa7164/saa7164-reg.h @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.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 diff --git a/drivers/media/pci/saa7164/saa7164-types.h b/drivers/media/pci/saa7164/saa7164-types.h index f48ba97..1efba6c 100644 --- a/drivers/media/pci/saa7164/saa7164-types.h +++ b/drivers/media/pci/saa7164/saa7164-types.h @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.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 diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c index 6e025fe..859fd03 100644 --- a/drivers/media/pci/saa7164/saa7164-vbi.c +++ b/drivers/media/pci/saa7164/saa7164-vbi.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.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 @@ -660,13 +660,14 @@ static int vidioc_querycap(struct file *file, void *priv, sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->capabilities = + cap->device_caps = V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_READWRITE | - 0; + V4L2_CAP_READWRITE | + V4L2_CAP_TUNER; - cap->capabilities |= V4L2_CAP_TUNER; - cap->version = 0; + cap->capabilities = cap->device_caps | + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_DEVICE_CAPS; return 0; } diff --git a/drivers/media/pci/saa7164/saa7164.h b/drivers/media/pci/saa7164/saa7164.h index cd1a07c..18906e0 100644 --- a/drivers/media/pci/saa7164/saa7164.h +++ b/drivers/media/pci/saa7164/saa7164.h @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.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 @@ -83,6 +83,9 @@ #define SAA7164_BOARD_HAUPPAUGE_HVR2250_3 8 #define SAA7164_BOARD_HAUPPAUGE_HVR2200_4 9 #define SAA7164_BOARD_HAUPPAUGE_HVR2200_5 10 +#define SAA7164_BOARD_HAUPPAUGE_HVR2255proto 11 +#define SAA7164_BOARD_HAUPPAUGE_HVR2255 12 +#define SAA7164_BOARD_HAUPPAUGE_HVR2205 13 #define SAA7164_MAX_UNITS 8 #define SAA7164_TS_NUMBER_OF_LINES 312 @@ -371,6 +374,8 @@ struct saa7164_port { /* --- DVB Transport Specific --- */ struct saa7164_dvb dvb; + struct i2c_client *i2c_client_demod; + struct i2c_client *i2c_client_tuner; /* --- Encoder/V4L related attributes --- */ /* Encoder */ @@ -459,6 +464,7 @@ struct saa7164_dev { /* Interrupt status and ack registers */ u32 int_status; u32 int_ack; + bool msi; struct cmd cmds[SAA_CMD_MAX_MSG_UNITS]; struct mutex lock; diff --git a/drivers/media/pci/smipcie/smipcie.c b/drivers/media/pci/smipcie/smipcie.c index 4115925..143fd78 100644 --- a/drivers/media/pci/smipcie/smipcie.c +++ b/drivers/media/pci/smipcie/smipcie.c @@ -657,6 +657,7 @@ static int smi_dvbsky_sit2_fe_attach(struct smi_port *port) /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = port->fe; + si2157_config.if_port = 1; memset(&client_info, 0, sizeof(struct i2c_board_info)); strlcpy(client_info.type, "si2157", I2C_NAME_SIZE); diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index d384a6b..59b3a36 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -813,7 +813,7 @@ static irqreturn_t vip_irq(int irq, struct sta2x11_vip *vip) /* Disable acquisition */ reg_write(vip, DVP_CTL, reg_read(vip, DVP_CTL) & ~DVP_CTL_ENA); /* Remove the active buffer from the list */ - do_gettimeofday(&vip->active->vb.v4l2_buf.timestamp); + v4l2_get_timestamp(&vip->active->vb.v4l2_buf.timestamp); vip->active->vb.v4l2_buf.sequence = vip->sequence++; vb2_buffer_done(&vip->active->vb, VB2_BUF_STATE_DONE); } @@ -864,6 +864,7 @@ static int sta2x11_vip_init_buffer(struct sta2x11_vip *vip) vip->vb_vidq.buf_struct_size = sizeof(struct vip_buffer); vip->vb_vidq.ops = &vip_video_qops; vip->vb_vidq.mem_ops = &vb2_dma_contig_memops; + vip->vb_vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; err = vb2_queue_init(&vip->vb_vidq); if (err) return err; diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index 45199a1..3f24fce 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -1172,7 +1172,7 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num, ******************************************************************************/ -static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int av7110_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) { struct av7110* av7110 = fe->dvb->priv; @@ -1197,7 +1197,7 @@ static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe, } static int av7110_diseqc_send_burst(struct dvb_frontend* fe, - fe_sec_mini_cmd_t minicmd) + enum fe_sec_mini_cmd minicmd) { struct av7110* av7110 = fe->dvb->priv; @@ -1946,7 +1946,7 @@ static struct l64781_config grundig_29504_401_config = { -static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) +static int av7110_fe_lock_fix(struct av7110 *av7110, enum fe_status status) { int ret = 0; int synced = (status & FE_HAS_LOCK) ? 1 : 0; @@ -2008,7 +2008,8 @@ static int av7110_fe_init(struct dvb_frontend* fe) return ret; } -static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int av7110_fe_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct av7110* av7110 = fe->dvb->priv; @@ -2043,7 +2044,8 @@ static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, return ret; } -static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +static int av7110_fe_diseqc_send_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd minicmd) { struct av7110* av7110 = fe->dvb->priv; @@ -2055,7 +2057,8 @@ static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_ return ret; } -static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int av7110_fe_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct av7110* av7110 = fe->dvb->priv; @@ -2067,7 +2070,8 @@ static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) return ret; } -static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int av7110_fe_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct av7110* av7110 = fe->dvb->priv; diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h index 835635b..3a55927 100644 --- a/drivers/media/pci/ttpci/av7110.h +++ b/drivers/media/pci/ttpci/av7110.h @@ -269,25 +269,30 @@ struct av7110 { unsigned long size_root; struct dvb_frontend* fe; - fe_status_t fe_status; + enum fe_status fe_status; struct mutex ioctl_mutex; /* crash recovery */ void (*recover)(struct av7110* av7110); - fe_sec_voltage_t saved_voltage; - fe_sec_tone_mode_t saved_tone; + enum fe_sec_voltage saved_voltage; + enum fe_sec_tone_mode saved_tone; struct dvb_diseqc_master_cmd saved_master_cmd; - fe_sec_mini_cmd_t saved_minicmd; + enum fe_sec_mini_cmd saved_minicmd; int (*fe_init)(struct dvb_frontend* fe); - int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status); - int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe); - int (*fe_diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd); - int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); - int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); - int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); - int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); + int (*fe_read_status)(struct dvb_frontend *fe, enum fe_status *status); + int (*fe_diseqc_reset_overload)(struct dvb_frontend *fe); + int (*fe_diseqc_send_master_cmd)(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd); + int (*fe_diseqc_send_burst)(struct dvb_frontend *fe, + enum fe_sec_mini_cmd minicmd); + int (*fe_set_tone)(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone); + int (*fe_set_voltage)(struct dvb_frontend *fe, + enum fe_sec_voltage voltage); + int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend *fe, + unsigned long cmd); int (*fe_set_frontend)(struct dvb_frontend *fe); }; diff --git a/drivers/media/pci/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c index 23e0549..e9674b4 100644 --- a/drivers/media/pci/ttpci/budget-core.c +++ b/drivers/media/pci/ttpci/budget-core.c @@ -161,7 +161,8 @@ static int start_ts_capture(struct budget *budget) return 0; } -static int budget_read_fe_status(struct dvb_frontend *fe, fe_status_t *status) +static int budget_read_fe_status(struct dvb_frontend *fe, + enum fe_status *status) { struct budget *budget = (struct budget *) fe->dvb->priv; int synced; diff --git a/drivers/media/pci/ttpci/budget-patch.c b/drivers/media/pci/ttpci/budget-patch.c index a4d8867..b5b6596 100644 --- a/drivers/media/pci/ttpci/budget-patch.c +++ b/drivers/media/pci/ttpci/budget-patch.c @@ -128,9 +128,9 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long return 0; } -/* shamelessly copy/pasted from budget.c -*/ -static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +/* shamelessly copy/pasted from budget.c */ +static int budget_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct budget* budget = (struct budget*) fe->dvb->priv; @@ -159,7 +159,8 @@ static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_dis return 0; } -static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +static int budget_diseqc_send_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd minicmd) { struct budget* budget = (struct budget*) fe->dvb->priv; @@ -223,7 +224,8 @@ static int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg, return 0; } -static int budget_patch_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int budget_patch_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; @@ -252,7 +254,8 @@ static int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct d return 0; } -static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +static int budget_patch_diseqc_send_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd minicmd) { struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c index 6ccc488..99972be 100644 --- a/drivers/media/pci/ttpci/budget.c +++ b/drivers/media/pci/ttpci/budget.c @@ -132,7 +132,8 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long * Voltage must be set here. * GPIO 1: LNBP EN, GPIO 2: LNBP VSEL */ -static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage) +static int SetVoltage_Activy(struct budget *budget, + enum fe_sec_voltage voltage) { struct saa7146_dev *dev=budget->dev; @@ -157,14 +158,16 @@ static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage) return 0; } -static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int siemens_budget_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct budget* budget = (struct budget*) fe->dvb->priv; return SetVoltage_Activy (budget, voltage); } -static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int budget_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct budget* budget = (struct budget*) fe->dvb->priv; @@ -193,7 +196,8 @@ static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_dis return 0; } -static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +static int budget_diseqc_send_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd minicmd) { struct budget* budget = (struct budget*) fe->dvb->priv; diff --git a/drivers/media/pci/ttpci/budget.h b/drivers/media/pci/ttpci/budget.h index 3d8a806..1ccbe1a 100644 --- a/drivers/media/pci/ttpci/budget.h +++ b/drivers/media/pci/ttpci/budget.h @@ -72,7 +72,7 @@ struct budget { struct dvb_adapter dvb_adapter; struct dvb_frontend *dvb_frontend; - int (*read_fe_status)(struct dvb_frontend *fe, fe_status_t *status); + int (*read_fe_status)(struct dvb_frontend *fe, enum fe_status *status); int fe_synced; void *priv; diff --git a/drivers/media/pci/zoran/zoran_device.c b/drivers/media/pci/zoran/zoran_device.c index b6801e0..40119b3 100644 --- a/drivers/media/pci/zoran/zoran_device.c +++ b/drivers/media/pci/zoran/zoran_device.c @@ -1584,14 +1584,11 @@ zoran_init_hardware (struct zoran *zr) jpeg_codec_sleep(zr, 1); jpeg_codec_sleep(zr, 0); - /* set individual interrupt enables (without GIRQ1) - * but don't global enable until zoran_open() */ - - //btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ1, ZR36057_ICR); // SW - // It looks like using only JPEGRepIRQEn is not always reliable, - // may be when JPEG codec crashes it won't generate IRQ? So, - /*CP*/ // btwrite(IRQ_MASK, ZR36057_ICR); // Enable Vsync interrupts too. SM WHY ? LP - zr36057_init_vfe(zr); + /* + * set individual interrupt enables (without GIRQ1) + * but don't global enable until zoran_open() + */ + zr36057_init_vfe(zr); zr36057_enable_jpg(zr, BUZ_MODE_IDLE); diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 421f531..a4e7d21 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -212,6 +212,16 @@ config VIDEO_SAMSUNG_EXYNOS_GSC help This is a v4l2 driver for Samsung EXYNOS5 SoC G-Scaler. +config VIDEO_STI_BDISP + tristate "STMicroelectronics BDISP 2D blitter driver" + depends on VIDEO_DEV && VIDEO_V4L2 + depends on ARCH_STI || COMPILE_TEST + depends on HAVE_DMA_ATTRS + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + help + This v4l2 mem2mem driver is a 2D blitter for STMicroelectronics SoC. + config VIDEO_SH_VEU tristate "SuperH VEU mem2mem video processing driver" depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 8f85561..114f9ab 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -34,6 +34,8 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV) += s5p-tv/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/ obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC) += exynos-gsc/ +obj-$(CONFIG_VIDEO_STI_BDISP) += sti/bdisp/ + obj-$(CONFIG_BLACKFIN) += blackfin/ obj-$(CONFIG_ARCH_DAVINCI) += davinci/ diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index a30cc2f..1fba339 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -288,7 +288,8 @@ cmp_v4l2_format(const struct v4l2_format *lhs, const struct v4l2_format *rhs) lhs->fmt.pix.field == rhs->fmt.pix.field && lhs->fmt.pix.colorspace == rhs->fmt.pix.colorspace && lhs->fmt.pix.ycbcr_enc == rhs->fmt.pix.ycbcr_enc && - lhs->fmt.pix.quantization == rhs->fmt.pix.quantization; + lhs->fmt.pix.quantization == rhs->fmt.pix.quantization && + lhs->fmt.pix.xfer_func == rhs->fmt.pix.xfer_func; } static inline u32 vpfe_reg_read(struct vpfe_ccdc *ccdc, u32 offset) @@ -430,7 +431,7 @@ vpfe_ccdc_update_raw_params(struct vpfe_ccdc *ccdc, struct vpfe_ccdc_config_params_raw *config_params = &ccdc->ccdc_cfg.bayer.config_params; - config_params = raw_params; + *config_params = *raw_params; } /* @@ -510,7 +511,7 @@ static int vpfe_ccdc_set_params(struct vpfe_ccdc *ccdc, void __user *params) if (!vpfe_ccdc_validate_param(ccdc, &raw_params)) { vpfe_ccdc_update_raw_params(ccdc, &raw_params); - return 0; + return 0; } return -EINVAL; @@ -1095,7 +1096,7 @@ static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe) * For a given standard, this functions sets up the default * pix format & crop values in the vpfe device and ccdc. It first * starts with defaults based values from the standard table. - * It then checks if sub device support g_mbus_fmt and then override the + * It then checks if sub device supports get_fmt and then override the * values based on that.Sets crop values to match with scan resolution * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the * values in ccdc @@ -1432,8 +1433,8 @@ static int __vpfe_get_format(struct vpfe_device *vpfe, } else { ret = v4l2_device_call_until_err(&vpfe->v4l2_dev, sdinfo->grp_id, - video, g_mbus_fmt, - &mbus_fmt); + pad, get_fmt, + NULL, &fmt); if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) return ret; v4l2_fill_pix_format(&format->fmt.pix, &mbus_fmt); @@ -1455,7 +1456,6 @@ static int __vpfe_get_format(struct vpfe_device *vpfe, static int __vpfe_set_format(struct vpfe_device *vpfe, struct v4l2_format *format, unsigned int *bpp) { - struct v4l2_mbus_framefmt mbus_fmt; struct vpfe_subdev_info *sdinfo; struct v4l2_subdev_format fmt; int ret; @@ -1472,23 +1472,11 @@ static int __vpfe_set_format(struct vpfe_device *vpfe, pix_to_mbus(vpfe, &format->fmt.pix, &fmt.format); ret = v4l2_subdev_call(sdinfo->sd, pad, set_fmt, NULL, &fmt); - if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) + if (ret) return ret; - if (!ret) { - v4l2_fill_pix_format(&format->fmt.pix, &fmt.format); - mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp); - } else { - ret = v4l2_device_call_until_err(&vpfe->v4l2_dev, - sdinfo->grp_id, - video, s_mbus_fmt, - &mbus_fmt); - if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) - return ret; - - v4l2_fill_pix_format(&format->fmt.pix, &mbus_fmt); - mbus_to_pix(vpfe, &mbus_fmt, &format->fmt.pix, bpp); - } + v4l2_fill_pix_format(&format->fmt.pix, &fmt.format); + mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp); format->type = vpfe->fmt.type; @@ -1675,12 +1663,9 @@ vpfe_get_subdev_input_index(struct vpfe_device *vpfe, int *subdev_input_index, int app_input_index) { - struct vpfe_config *cfg = vpfe->cfg; - struct vpfe_subdev_info *sdinfo; int i, j = 0; for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { - sdinfo = &cfg->sub_devs[i]; if (app_input_index < (j + 1)) { *subdev_index = i; *subdev_input_index = app_input_index - j; diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 6a437f8..b7e70fb 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -156,14 +156,18 @@ static struct bcap_buffer *to_bcap_vb(struct vb2_buffer *vb) static int bcap_init_sensor_formats(struct bcap_device *bcap_dev) { - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; struct bcap_format *sf; unsigned int num_formats = 0; int i, j; - while (!v4l2_subdev_call(bcap_dev->sd, video, - enum_mbus_fmt, num_formats, &code)) + while (!v4l2_subdev_call(bcap_dev->sd, pad, + enum_mbus_code, NULL, &code)) { num_formats++; + code.index++; + } if (!num_formats) return -ENXIO; @@ -172,10 +176,11 @@ static int bcap_init_sensor_formats(struct bcap_device *bcap_dev) return -ENOMEM; for (i = 0; i < num_formats; i++) { - v4l2_subdev_call(bcap_dev->sd, video, - enum_mbus_fmt, i, &code); + code.index = i; + v4l2_subdev_call(bcap_dev->sd, pad, + enum_mbus_code, NULL, &code); for (j = 0; j < BCAP_MAX_FMTS; j++) - if (code == bcap_formats[j].mbus_code) + if (code.code == bcap_formats[j].mbus_code) break; if (j == BCAP_MAX_FMTS) { /* we don't allow this sensor working with our bridge */ @@ -597,7 +602,10 @@ static int bcap_try_format(struct bcap_device *bcap, { struct bcap_format *sf = bcap->sensor_formats; struct bcap_format *fmt = NULL; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; int ret, i; for (i = 0; i < bcap->num_sensor_formats; i++) { @@ -608,16 +616,16 @@ static int bcap_try_format(struct bcap_device *bcap, if (i == bcap->num_sensor_formats) fmt = &sf[0]; - v4l2_fill_mbus_format(&mbus_fmt, pixfmt, fmt->mbus_code); - ret = v4l2_subdev_call(bcap->sd, video, - try_mbus_fmt, &mbus_fmt); + v4l2_fill_mbus_format(&format.format, pixfmt, fmt->mbus_code); + ret = v4l2_subdev_call(bcap->sd, pad, set_fmt, &pad_cfg, + &format); if (ret < 0) return ret; - v4l2_fill_pix_format(pixfmt, &mbus_fmt); + v4l2_fill_pix_format(pixfmt, &format.format); if (bcap_fmt) { for (i = 0; i < bcap->num_sensor_formats; i++) { fmt = &sf[i]; - if (mbus_fmt.code == fmt->mbus_code) + if (format.format.code == fmt->mbus_code) break; } *bcap_fmt = *fmt; @@ -666,7 +674,9 @@ static int bcap_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct bcap_device *bcap_dev = video_drvdata(file); - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; struct bcap_format bcap_fmt; struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; int ret; @@ -679,8 +689,8 @@ static int bcap_s_fmt_vid_cap(struct file *file, void *priv, if (ret < 0) return ret; - v4l2_fill_mbus_format(&mbus_fmt, pixfmt, bcap_fmt.mbus_code); - ret = v4l2_subdev_call(bcap_dev->sd, video, s_mbus_fmt, &mbus_fmt); + v4l2_fill_mbus_format(&format.format, pixfmt, bcap_fmt.mbus_code); + ret = v4l2_subdev_call(bcap_dev->sd, pad, set_fmt, NULL, &format); if (ret < 0) return ret; bcap_dev->fmt = *pixfmt; diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index d043007..109797b 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1305,7 +1305,7 @@ static void coda_finish_encode(struct coda_ctx *ctx) v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); ctx->gopcounter--; if (ctx->gopcounter < 0) @@ -1975,7 +1975,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) } vb2_set_plane_payload(dst_buf, 0, payload); - v4l2_m2m_buf_done(dst_buf, ctx->frame_errors[display_idx] ? + coda_m2m_buf_done(ctx, dst_buf, ctx->frame_errors[display_idx] ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); v4l2_dbg(1, coda_debug, &dev->v4l2_dev, diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 8e6fe02..6d6e0ca 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -724,35 +724,30 @@ static int coda_qbuf(struct file *file, void *priv, } static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx, - struct v4l2_buffer *buf) + struct vb2_buffer *buf) { struct vb2_queue *src_vq; src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) && - (buf->sequence == (ctx->qsequence - 1))); + (buf->v4l2_buf.sequence == (ctx->qsequence - 1))); } -static int coda_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) +void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_buffer *buf, + enum vb2_buffer_state state) { - struct coda_ctx *ctx = fh_to_ctx(priv); - int ret; + const struct v4l2_event eos_event = { + .type = V4L2_EVENT_EOS + }; - ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf); - - /* If this is the last capture buffer, emit an end-of-stream event */ - if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && - coda_buf_is_end_of_stream(ctx, buf)) { - const struct v4l2_event eos_event = { - .type = V4L2_EVENT_EOS - }; + if (coda_buf_is_end_of_stream(ctx, buf)) { + buf->v4l2_buf.flags |= V4L2_BUF_FLAG_LAST; v4l2_event_queue_fh(&ctx->fh, &eos_event); } - return ret; + v4l2_m2m_buf_done(buf, state); } static int coda_g_selection(struct file *file, void *fh, @@ -865,7 +860,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_qbuf = coda_qbuf, .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, - .vidioc_dqbuf = coda_dqbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, .vidioc_streamon = v4l2_m2m_ioctl_streamon, diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 6a5c8f6..8e0af22 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -287,6 +287,9 @@ static inline unsigned int coda_get_bitstream_payload(struct coda_ctx *ctx) void coda_bit_stream_end_flag(struct coda_ctx *ctx); +void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_buffer *buf, + enum vb2_buffer_state state); + int coda_h264_padding(int size, char *p); bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb); diff --git a/drivers/media/platform/coda/trace.h b/drivers/media/platform/coda/trace.h index d1d06cb..781bf72 100644 --- a/drivers/media/platform/coda/trace.h +++ b/drivers/media/platform/coda/trace.h @@ -9,8 +9,6 @@ #include "coda.h" -#define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM) - TRACE_EVENT(coda_bit_run, TP_PROTO(struct coda_ctx *ctx, int cmd), diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index c4ab46f..f69cdd7 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -71,15 +71,10 @@ static int venc_is_second_field(struct vpbe_display *disp_dev) static void vpbe_isr_even_field(struct vpbe_display *disp_obj, struct vpbe_layer *layer) { - struct timespec timevalue; - if (layer->cur_frm == layer->next_frm) return; - ktime_get_ts(&timevalue); - layer->cur_frm->vb.v4l2_buf.timestamp.tv_sec = - timevalue.tv_sec; - layer->cur_frm->vb.v4l2_buf.timestamp.tv_usec = - timevalue.tv_nsec / NSEC_PER_USEC; + + v4l2_get_timestamp(&layer->cur_frm->vb.v4l2_buf.timestamp); vb2_buffer_done(&layer->cur_frm->vb, VB2_BUF_STATE_DONE); /* Make cur_frm pointing to next_frm */ layer->cur_frm = layer->next_frm; diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index ccfcf3f..7767e07 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -370,7 +370,7 @@ static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev) * For a given standard, this functions sets up the default * pix format & crop values in the vpfe device and ccdc. It first * starts with defaults based values from the standard table. - * It then checks if sub device support g_mbus_fmt and then override the + * It then checks if sub device supports get_fmt and then override the * values based on that.Sets crop values to match with scan resolution * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the * values in ccdc @@ -379,7 +379,10 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, v4l2_std_id std_id) { struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mbus_fmt = &fmt.format; struct v4l2_pix_format *pix = &vpfe_dev->fmt.fmt.pix; int i, ret = 0; @@ -413,26 +416,26 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, pix->field = V4L2_FIELD_INTERLACED; /* assume V4L2_PIX_FMT_UYVY as default */ pix->pixelformat = V4L2_PIX_FMT_UYVY; - v4l2_fill_mbus_format(&mbus_fmt, pix, + v4l2_fill_mbus_format(mbus_fmt, pix, MEDIA_BUS_FMT_YUYV10_2X10); } else { pix->field = V4L2_FIELD_NONE; /* assume V4L2_PIX_FMT_SBGGR8 */ pix->pixelformat = V4L2_PIX_FMT_SBGGR8; - v4l2_fill_mbus_format(&mbus_fmt, pix, + v4l2_fill_mbus_format(mbus_fmt, pix, MEDIA_BUS_FMT_SBGGR8_1X8); } - /* if sub device supports g_mbus_fmt, override the defaults */ + /* if sub device supports get_fmt, override the defaults */ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, - sdinfo->grp_id, video, g_mbus_fmt, &mbus_fmt); + sdinfo->grp_id, pad, get_fmt, NULL, &fmt); if (ret && ret != -ENOIOCTLCMD) { v4l2_err(&vpfe_dev->v4l2_dev, - "error in getting g_mbus_fmt from sub device\n"); + "error in getting get_fmt from sub device\n"); return ret; } - v4l2_fill_pix_format(pix, &mbus_fmt); + v4l2_fill_pix_format(pix, mbus_fmt); pix->bytesperline = pix->width * 2; pix->sizeimage = pix->bytesperline * pix->height; diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index fd2891c..9b9e423 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -967,7 +967,7 @@ static struct gsc_driverdata gsc_v_100_drvdata = { .lclk_frequency = 266000000UL, }; -static struct platform_device_id gsc_driver_ids[] = { +static const struct platform_device_id gsc_driver_ids[] = { { .name = "exynos-gsc", .driver_data = (unsigned long)&gsc_v_100_drvdata, diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig index b7b2e47..40423c6 100644 --- a/drivers/media/platform/exynos4-is/Kconfig +++ b/drivers/media/platform/exynos4-is/Kconfig @@ -57,6 +57,7 @@ endif config VIDEO_EXYNOS4_FIMC_IS tristate "EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver" + depends on I2C depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG depends on OF diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index f315ef9..4f5586a 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -1451,7 +1451,7 @@ static int fimc_md_remove(struct platform_device *pdev) return 0; } -static struct platform_device_id fimc_driver_ids[] __always_unused = { +static const struct platform_device_id fimc_driver_ids[] __always_unused = { { .name = "s5p-fimc-md" }, { }, }; diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index bbf4281..5b76e3d 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c @@ -1664,7 +1664,7 @@ static int viu_resume(struct platform_device *op) /* * Initialization and module stuff */ -static struct of_device_id mpc512x_viu_of_match[] = { +static const struct of_device_id mpc512x_viu_of_match[] = { { .compatible = "fsl,mpc5121-viu", }, diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 92d9549..c07f367 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -1060,7 +1060,6 @@ static int deinterlace_probe(struct platform_device *pdev) return 0; - v4l2_m2m_release(pcdev->m2m_dev); err_m2m: video_unregister_device(&pcdev->vfd); err_ctx: diff --git a/drivers/media/platform/marvell-ccic/cafe-driver.c b/drivers/media/platform/marvell-ccic/cafe-driver.c index 5628453..77890bd 100644 --- a/drivers/media/platform/marvell-ccic/cafe-driver.c +++ b/drivers/media/platform/marvell-ccic/cafe-driver.c @@ -339,17 +339,21 @@ static int cafe_smbus_setup(struct cafe_camera *cam) adap = kzalloc(sizeof(*adap), GFP_KERNEL); if (adap == NULL) return -ENOMEM; - cam->mcam.i2c_adapter = adap; - cafe_smbus_enable_irq(cam); adap->owner = THIS_MODULE; adap->algo = &cafe_smbus_algo; strcpy(adap->name, "cafe_ccic"); adap->dev.parent = &cam->pdev->dev; i2c_set_adapdata(adap, cam); ret = i2c_add_adapter(adap); - if (ret) + if (ret) { printk(KERN_ERR "Unable to register cafe i2c adapter\n"); - return ret; + kfree(adap); + return ret; + } + + cam->mcam.i2c_adapter = adap; + cafe_smbus_enable_irq(cam); + return 0; } static void cafe_smbus_shutdown(struct cafe_camera *cam) @@ -476,6 +480,7 @@ static int cafe_pci_probe(struct pci_dev *pdev, mcam->plat_power_up = cafe_ctlr_power_up; mcam->plat_power_down = cafe_ctlr_power_down; mcam->dev = &pdev->dev; + snprintf(mcam->bus_info, sizeof(mcam->bus_info), "PCI:%s", pci_name(pdev)); /* * Set the clock speed for the XO 1; I don't believe this * driver has ever run anywhere else. diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 110fd70..5e2b4df 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -24,6 +24,7 @@ #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> #include <media/ov7670.h> #include <media/videobuf2-vmalloc.h> #include <media/videobuf2-dma-contig.h> @@ -123,29 +124,22 @@ static struct mcam_format_struct { .planar = false, }, { - .desc = "YUV 4:2:2 PLANAR", - .pixelformat = V4L2_PIX_FMT_YUV422P, - .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, - .bpp = 2, - .planar = true, - }, - { .desc = "YUV 4:2:0 PLANAR", .pixelformat = V4L2_PIX_FMT_YUV420, .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, - .bpp = 2, + .bpp = 1, .planar = true, }, { .desc = "YVU 4:2:0 PLANAR", .pixelformat = V4L2_PIX_FMT_YVU420, .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, - .bpp = 2, + .bpp = 1, .planar = true, }, { - .desc = "RGB 444", - .pixelformat = V4L2_PIX_FMT_RGB444, + .desc = "XRGB 444", + .pixelformat = V4L2_PIX_FMT_XRGB444, .mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, .bpp = 2, .planar = false, @@ -188,6 +182,7 @@ static const struct v4l2_pix_format mcam_def_pix_format = { .field = V4L2_FIELD_NONE, .bytesperline = VGA_WIDTH*2, .sizeimage = VGA_WIDTH*VGA_HEIGHT*2, + .colorspace = V4L2_COLORSPACE_SRGB, }; static const u32 mcam_def_mbus_code = MEDIA_BUS_FMT_YUYV8_2X8; @@ -204,12 +199,6 @@ struct mcam_dma_desc { u32 segment_len; }; -struct yuv_pointer_t { - dma_addr_t y; - dma_addr_t u; - dma_addr_t v; -}; - /* * Our buffer type for working with videobuf2. Note that the vb2 * developers have decreed that struct vb2_buffer must be at the @@ -221,7 +210,6 @@ struct mcam_vb_buffer { struct mcam_dma_desc *dma_desc; /* Descriptor virtual address */ dma_addr_t dma_desc_pa; /* Descriptor physical address */ int dma_desc_nent; /* Number of mapped descriptors */ - struct yuv_pointer_t yuv_p; }; static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_buffer *vb) @@ -237,6 +225,8 @@ static void mcam_buffer_done(struct mcam_camera *cam, int frame, { vbuf->v4l2_buf.bytesused = cam->pix_format.sizeimage; vbuf->v4l2_buf.sequence = cam->buf_seq[frame]; + vbuf->v4l2_buf.field = V4L2_FIELD_NONE; + v4l2_get_timestamp(&vbuf->v4l2_buf.timestamp); vb2_set_plane_payload(vbuf, 0, cam->pix_format.sizeimage); vb2_buffer_done(vbuf, VB2_BUF_STATE_DONE); } @@ -337,6 +327,43 @@ static void mcam_disable_mipi(struct mcam_camera *mcam) mcam->mipi_enabled = false; } +static bool mcam_fmt_is_planar(__u32 pfmt) +{ + struct mcam_format_struct *f; + + f = mcam_find_format(pfmt); + return f->planar; +} + +static void mcam_write_yuv_bases(struct mcam_camera *cam, + unsigned frame, dma_addr_t base) +{ + struct v4l2_pix_format *fmt = &cam->pix_format; + u32 pixel_count = fmt->width * fmt->height; + dma_addr_t y, u = 0, v = 0; + + y = base; + + switch (fmt->pixelformat) { + case V4L2_PIX_FMT_YUV420: + u = y + pixel_count; + v = u + pixel_count / 4; + break; + case V4L2_PIX_FMT_YVU420: + v = y + pixel_count; + u = v + pixel_count / 4; + break; + default: + break; + } + + mcam_reg_write(cam, REG_Y0BAR + frame * 4, y); + if (mcam_fmt_is_planar(fmt->pixelformat)) { + mcam_reg_write(cam, REG_U0BAR + frame * 4, u); + mcam_reg_write(cam, REG_V0BAR + frame * 4, v); + } +} + /* ------------------------------------------------------------------- */ #ifdef MCAM_MODE_VMALLOC @@ -407,15 +434,14 @@ static void mcam_free_dma_bufs(struct mcam_camera *cam) static void mcam_ctlr_dma_vmalloc(struct mcam_camera *cam) { /* - * Store the first two Y buffers (we aren't supporting - * planar formats for now, so no UV bufs). Then either + * Store the first two YUV buffers. Then either * set the third if it exists, or tell the controller * to just use two. */ - mcam_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]); - mcam_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]); + mcam_write_yuv_bases(cam, 0, cam->dma_handles[0]); + mcam_write_yuv_bases(cam, 1, cam->dma_handles[1]); if (cam->nbufs > 2) { - mcam_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]); + mcam_write_yuv_bases(cam, 2, cam->dma_handles[2]); mcam_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS); } else mcam_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS); @@ -510,14 +536,6 @@ static inline int mcam_check_dma_buffers(struct mcam_camera *cam) * DMA-contiguous code. */ -static bool mcam_fmt_is_planar(__u32 pfmt) -{ - struct mcam_format_struct *f; - - f = mcam_find_format(pfmt); - return f->planar; -} - /* * Set up a contiguous buffer for the given frame. Here also is where * the underrun strategy is set: if there is no buffer available, reuse @@ -529,9 +547,7 @@ static bool mcam_fmt_is_planar(__u32 pfmt) static void mcam_set_contig_buffer(struct mcam_camera *cam, int frame) { struct mcam_vb_buffer *buf; - struct v4l2_pix_format *fmt = &cam->pix_format; dma_addr_t dma_handle; - u32 pixel_count = fmt->width * fmt->height; struct vb2_buffer *vb; /* @@ -555,32 +571,7 @@ static void mcam_set_contig_buffer(struct mcam_camera *cam, int frame) vb = &buf->vb_buf; dma_handle = vb2_dma_contig_plane_dma_addr(vb, 0); - buf->yuv_p.y = dma_handle; - - switch (cam->pix_format.pixelformat) { - case V4L2_PIX_FMT_YUV422P: - buf->yuv_p.u = buf->yuv_p.y + pixel_count; - buf->yuv_p.v = buf->yuv_p.u + pixel_count / 2; - break; - case V4L2_PIX_FMT_YUV420: - buf->yuv_p.u = buf->yuv_p.y + pixel_count; - buf->yuv_p.v = buf->yuv_p.u + pixel_count / 4; - break; - case V4L2_PIX_FMT_YVU420: - buf->yuv_p.v = buf->yuv_p.y + pixel_count; - buf->yuv_p.u = buf->yuv_p.v + pixel_count / 4; - break; - default: - break; - } - - mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR, buf->yuv_p.y); - if (mcam_fmt_is_planar(fmt->pixelformat)) { - mcam_reg_write(cam, frame == 0 ? - REG_U0BAR : REG_U1BAR, buf->yuv_p.u); - mcam_reg_write(cam, frame == 0 ? - REG_V0BAR : REG_V1BAR, buf->yuv_p.v); - } + mcam_write_yuv_bases(cam, frame, dma_handle); } /* @@ -603,6 +594,7 @@ static void mcam_dma_contig_done(struct mcam_camera *cam, int frame) if (!test_bit(CF_SINGLE_BUFFER, &cam->flags)) { cam->frame_state.delivered++; + cam->vb_bufs[frame] = NULL; mcam_buffer_done(cam, frame, &buf->vb_buf); } mcam_set_contig_buffer(cam, frame); @@ -752,12 +744,6 @@ static void mcam_ctlr_image(struct mcam_camera *cam) widthy = fmt->width * 2; widthuv = 0; break; - case V4L2_PIX_FMT_JPEG: - imgsz_h = (fmt->sizeimage / fmt->bytesperline) << IMGSZ_V_SHIFT; - widthy = fmt->bytesperline; - widthuv = 0; - break; - case V4L2_PIX_FMT_YUV422P: case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: widthy = fmt->width; @@ -766,6 +752,7 @@ static void mcam_ctlr_image(struct mcam_camera *cam) default: widthy = fmt->bytesperline; widthuv = 0; + break; } mcam_reg_write_mask(cam, REG_IMGPITCH, widthuv << 16 | widthy, @@ -777,10 +764,6 @@ static void mcam_ctlr_image(struct mcam_camera *cam) * Tell the controller about the image format we are using. */ switch (fmt->pixelformat) { - case V4L2_PIX_FMT_YUV422P: - mcam_reg_write_mask(cam, REG_CTRL0, - C0_DF_YUV | C0_YUV_PLANAR | C0_YUVE_YVYU, C0_DF_MASK); - break; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: mcam_reg_write_mask(cam, REG_CTRL0, @@ -794,19 +777,18 @@ static void mcam_ctlr_image(struct mcam_camera *cam) mcam_reg_write_mask(cam, REG_CTRL0, C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_SWAP24, C0_DF_MASK); break; - case V4L2_PIX_FMT_JPEG: - mcam_reg_write_mask(cam, REG_CTRL0, - C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_YUYV, C0_DF_MASK); - break; - case V4L2_PIX_FMT_RGB444: + case V4L2_PIX_FMT_XRGB444: mcam_reg_write_mask(cam, REG_CTRL0, - C0_DF_RGB | C0_RGBF_444 | C0_RGB4_XRGB, C0_DF_MASK); - /* Alpha value? */ + C0_DF_RGB | C0_RGBF_444 | C0_RGB4_XBGR, C0_DF_MASK); break; case V4L2_PIX_FMT_RGB565: mcam_reg_write_mask(cam, REG_CTRL0, C0_DF_RGB | C0_RGBF_565 | C0_RGB5_BGGR, C0_DF_MASK); break; + case V4L2_PIX_FMT_SBGGR8: + mcam_reg_write_mask(cam, REG_CTRL0, + C0_DF_RGB | C0_RGB5_GRBG, C0_DF_MASK); + break; default: cam_err(cam, "camera: unknown format: %#x\n", fmt->pixelformat); break; @@ -969,7 +951,6 @@ static int mcam_cam_init(struct mcam_camera *cam) { int ret; - mutex_lock(&cam->s_mutex); if (cam->state != S_NOTREADY) cam_warn(cam, "Cam init with device in funky state %d", cam->state); @@ -977,7 +958,6 @@ static int mcam_cam_init(struct mcam_camera *cam) /* Get/set parameters? */ cam->state = S_IDLE; mcam_ctlr_power_down(cam); - mutex_unlock(&cam->s_mutex); return ret; } @@ -998,13 +978,15 @@ static int mcam_cam_set_flip(struct mcam_camera *cam) static int mcam_cam_configure(struct mcam_camera *cam) { - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int ret; - v4l2_fill_mbus_format(&mbus_fmt, &cam->pix_format, cam->mbus_code); + v4l2_fill_mbus_format(&format.format, &cam->pix_format, cam->mbus_code); ret = sensor_call(cam, core, init, 0); if (ret == 0) - ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt); + ret = sensor_call(cam, pad, set_fmt, NULL, &format); /* * OV7670 does weird things if flip is set *before* format... */ @@ -1073,7 +1055,9 @@ static int mcam_vb_queue_setup(struct vb2_queue *vq, struct mcam_camera *cam = vb2_get_drv_priv(vq); int minbufs = (cam->buffer_mode == B_DMA_contig) ? 3 : 2; - sizes[0] = cam->pix_format.sizeimage; + if (fmt && fmt->fmt.pix.sizeimage < cam->pix_format.sizeimage) + return -EINVAL; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : cam->pix_format.sizeimage; *num_planes = 1; /* Someday we have to support planar formats... */ if (*nbufs < minbufs) *nbufs = minbufs; @@ -1102,6 +1086,30 @@ static void mcam_vb_buf_queue(struct vb2_buffer *vb) mcam_read_setup(cam); } +static void mcam_vb_requeue_bufs(struct vb2_queue *vq, + enum vb2_buffer_state state) +{ + struct mcam_camera *cam = vb2_get_drv_priv(vq); + struct mcam_vb_buffer *buf, *node; + unsigned long flags; + unsigned i; + + spin_lock_irqsave(&cam->dev_lock, flags); + list_for_each_entry_safe(buf, node, &cam->buffers, queue) { + vb2_buffer_done(&buf->vb_buf, state); + list_del(&buf->queue); + } + for (i = 0; i < MAX_DMA_BUFS; i++) { + buf = cam->vb_bufs[i]; + + if (buf) { + vb2_buffer_done(&buf->vb_buf, state); + cam->vb_bufs[i] = NULL; + } + } + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + /* * These need to be called with the mutex held from vb2 */ @@ -1109,11 +1117,15 @@ static int mcam_vb_start_streaming(struct vb2_queue *vq, unsigned int count) { struct mcam_camera *cam = vb2_get_drv_priv(vq); unsigned int frame; + int ret; if (cam->state != S_IDLE) { - INIT_LIST_HEAD(&cam->buffers); + mcam_vb_requeue_bufs(vq, VB2_BUF_STATE_QUEUED); return -EINVAL; } + cam->frame_state.frames = 0; + cam->frame_state.singles = 0; + cam->frame_state.delivered = 0; cam->sequence = 0; /* * Videobuf2 sneakily hoards all the buffers and won't @@ -1134,14 +1146,19 @@ static int mcam_vb_start_streaming(struct vb2_queue *vq, unsigned int count) for (frame = 0; frame < cam->nbufs; frame++) clear_bit(CF_FRAME_SOF0 + frame, &cam->flags); - return mcam_read_setup(cam); + ret = mcam_read_setup(cam); + if (ret) + mcam_vb_requeue_bufs(vq, VB2_BUF_STATE_QUEUED); + return ret; } static void mcam_vb_stop_streaming(struct vb2_queue *vq) { struct mcam_camera *cam = vb2_get_drv_priv(vq); - unsigned long flags; + cam_dbg(cam, "stop_streaming: %d frames, %d singles, %d delivered\n", + cam->frame_state.frames, cam->frame_state.singles, + cam->frame_state.delivered); if (cam->state == S_BUFWAIT) { /* They never gave us buffers */ cam->state = S_IDLE; @@ -1160,9 +1177,7 @@ static void mcam_vb_stop_streaming(struct vb2_queue *vq) * VB2 reclaims the buffers, so we need to forget * about them. */ - spin_lock_irqsave(&cam->dev_lock, flags); - INIT_LIST_HEAD(&cam->buffers); - spin_unlock_irqrestore(&cam->dev_lock, flags); + mcam_vb_requeue_bufs(vq, VB2_BUF_STATE_ERROR); } @@ -1246,14 +1261,15 @@ static int mcam_setup_vb2(struct mcam_camera *cam) vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vq->drv_priv = cam; vq->lock = &cam->s_mutex; + vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + vq->buf_struct_size = sizeof(struct mcam_vb_buffer); INIT_LIST_HEAD(&cam->buffers); switch (cam->buffer_mode) { case B_DMA_contig: #ifdef MCAM_MODE_DMA_CONTIG vq->ops = &mcam_vb2_ops; vq->mem_ops = &vb2_dma_contig_memops; - vq->buf_struct_size = sizeof(struct mcam_vb_buffer); - vq->io_modes = VB2_MMAP | VB2_USERPTR; cam->dma_setup = mcam_ctlr_dma_contig; cam->frame_complete = mcam_dma_contig_done; cam->vb_alloc_ctx = vb2_dma_contig_init_ctx(cam->dev); @@ -1265,8 +1281,6 @@ static int mcam_setup_vb2(struct mcam_camera *cam) #ifdef MCAM_MODE_DMA_SG vq->ops = &mcam_vb2_sg_ops; vq->mem_ops = &vb2_dma_sg_memops; - vq->buf_struct_size = sizeof(struct mcam_vb_buffer); - vq->io_modes = VB2_MMAP | VB2_USERPTR; cam->dma_setup = mcam_ctlr_dma_sg; cam->frame_complete = mcam_dma_sg_done; cam->vb_alloc_ctx_sg = vb2_dma_sg_init_ctx(cam->dev); @@ -1280,8 +1294,6 @@ static int mcam_setup_vb2(struct mcam_camera *cam) (unsigned long) cam); vq->ops = &mcam_vb2_ops; vq->mem_ops = &vb2_vmalloc_memops; - vq->buf_struct_size = sizeof(struct mcam_vb_buffer); - vq->io_modes = VB2_MMAP; cam->dma_setup = mcam_ctlr_dma_vmalloc; cam->frame_complete = mcam_vmalloc_done; #endif @@ -1292,7 +1304,6 @@ static int mcam_setup_vb2(struct mcam_camera *cam) static void mcam_cleanup_vb2(struct mcam_camera *cam) { - vb2_queue_release(&cam->vb_queue); #ifdef MCAM_MODE_DMA_CONTIG if (cam->buffer_mode == B_DMA_contig) vb2_dma_contig_cleanup_ctx(cam->vb_alloc_ctx); @@ -1309,86 +1320,14 @@ static void mcam_cleanup_vb2(struct mcam_camera *cam) * The long list of V4L2 ioctl() operations. */ -static int mcam_vidioc_streamon(struct file *filp, void *priv, - enum v4l2_buf_type type) -{ - struct mcam_camera *cam = filp->private_data; - int ret; - - mutex_lock(&cam->s_mutex); - ret = vb2_streamon(&cam->vb_queue, type); - mutex_unlock(&cam->s_mutex); - return ret; -} - - -static int mcam_vidioc_streamoff(struct file *filp, void *priv, - enum v4l2_buf_type type) -{ - struct mcam_camera *cam = filp->private_data; - int ret; - - mutex_lock(&cam->s_mutex); - ret = vb2_streamoff(&cam->vb_queue, type); - mutex_unlock(&cam->s_mutex); - return ret; -} - - -static int mcam_vidioc_reqbufs(struct file *filp, void *priv, - struct v4l2_requestbuffers *req) -{ - struct mcam_camera *cam = filp->private_data; - int ret; - - mutex_lock(&cam->s_mutex); - ret = vb2_reqbufs(&cam->vb_queue, req); - mutex_unlock(&cam->s_mutex); - return ret; -} - - -static int mcam_vidioc_querybuf(struct file *filp, void *priv, - struct v4l2_buffer *buf) -{ - struct mcam_camera *cam = filp->private_data; - int ret; - - mutex_lock(&cam->s_mutex); - ret = vb2_querybuf(&cam->vb_queue, buf); - mutex_unlock(&cam->s_mutex); - return ret; -} - -static int mcam_vidioc_qbuf(struct file *filp, void *priv, - struct v4l2_buffer *buf) -{ - struct mcam_camera *cam = filp->private_data; - int ret; - - mutex_lock(&cam->s_mutex); - ret = vb2_qbuf(&cam->vb_queue, buf); - mutex_unlock(&cam->s_mutex); - return ret; -} - -static int mcam_vidioc_dqbuf(struct file *filp, void *priv, - struct v4l2_buffer *buf) -{ - struct mcam_camera *cam = filp->private_data; - int ret; - - mutex_lock(&cam->s_mutex); - ret = vb2_dqbuf(&cam->vb_queue, buf, filp->f_flags & O_NONBLOCK); - mutex_unlock(&cam->s_mutex); - return ret; -} - static int mcam_vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { + struct mcam_camera *cam = video_drvdata(file); + strcpy(cap->driver, "marvell_ccic"); strcpy(cap->card, "marvell_ccic"); + strlcpy(cap->bus_info, cam->bus_info, sizeof(cap->bus_info)); cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; @@ -1410,36 +1349,38 @@ static int mcam_vidioc_enum_fmt_vid_cap(struct file *filp, static int mcam_vidioc_try_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *fmt) { - struct mcam_camera *cam = priv; + struct mcam_camera *cam = video_drvdata(filp); struct mcam_format_struct *f; struct v4l2_pix_format *pix = &fmt->fmt.pix; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; int ret; f = mcam_find_format(pix->pixelformat); pix->pixelformat = f->pixelformat; - v4l2_fill_mbus_format(&mbus_fmt, pix, f->mbus_code); - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt); - mutex_unlock(&cam->s_mutex); - v4l2_fill_pix_format(pix, &mbus_fmt); + v4l2_fill_mbus_format(&format.format, pix, f->mbus_code); + ret = sensor_call(cam, pad, set_fmt, &pad_cfg, &format); + v4l2_fill_pix_format(pix, &format.format); + pix->bytesperline = pix->width * f->bpp; switch (f->pixelformat) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: - pix->bytesperline = pix->width * 3 / 2; + pix->sizeimage = pix->height * pix->bytesperline * 3 / 2; break; default: - pix->bytesperline = pix->width * f->bpp; + pix->sizeimage = pix->height * pix->bytesperline; break; } - pix->sizeimage = pix->height * pix->bytesperline; + pix->colorspace = V4L2_COLORSPACE_SRGB; return ret; } static int mcam_vidioc_s_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *fmt) { - struct mcam_camera *cam = priv; + struct mcam_camera *cam = video_drvdata(filp); struct mcam_format_struct *f; int ret; @@ -1447,7 +1388,7 @@ static int mcam_vidioc_s_fmt_vid_cap(struct file *filp, void *priv, * Can't do anything if the device is not idle * Also can't if there are streaming buffers in place. */ - if (cam->state != S_IDLE || cam->vb_queue.num_buffers > 0) + if (cam->state != S_IDLE || vb2_is_busy(&cam->vb_queue)) return -EBUSY; f = mcam_find_format(fmt->fmt.pix.pixelformat); @@ -1462,7 +1403,6 @@ static int mcam_vidioc_s_fmt_vid_cap(struct file *filp, void *priv, * Now we start to change things for real, so let's do it * under lock. */ - mutex_lock(&cam->s_mutex); cam->pix_format = fmt->fmt.pix; cam->mbus_code = f->mbus_code; @@ -1476,7 +1416,6 @@ static int mcam_vidioc_s_fmt_vid_cap(struct file *filp, void *priv, } mcam_set_config_needed(cam, 1); out: - mutex_unlock(&cam->s_mutex); return ret; } @@ -1488,7 +1427,7 @@ out: static int mcam_vidioc_g_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *f) { - struct mcam_camera *cam = priv; + struct mcam_camera *cam = video_drvdata(filp); f->fmt.pix = cam->pix_format; return 0; @@ -1504,7 +1443,6 @@ static int mcam_vidioc_enum_input(struct file *filp, void *priv, return -EINVAL; input->type = V4L2_INPUT_TYPE_CAMERA; - input->std = V4L2_STD_ALL; /* Not sure what should go here */ strcpy(input->name, "Camera"); return 0; } @@ -1522,18 +1460,6 @@ static int mcam_vidioc_s_input(struct file *filp, void *priv, unsigned int i) return 0; } -/* from vivi.c */ -static int mcam_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id a) -{ - return 0; -} - -static int mcam_vidioc_g_std(struct file *filp, void *priv, v4l2_std_id *a) -{ - *a = V4L2_STD_NTSC_M; - return 0; -} - /* * G/S_PARM. Most of this is done by the sensor, but we are * the level which controls the number of read buffers. @@ -1541,12 +1467,10 @@ static int mcam_vidioc_g_std(struct file *filp, void *priv, v4l2_std_id *a) static int mcam_vidioc_g_parm(struct file *filp, void *priv, struct v4l2_streamparm *parms) { - struct mcam_camera *cam = priv; + struct mcam_camera *cam = video_drvdata(filp); int ret; - mutex_lock(&cam->s_mutex); ret = sensor_call(cam, video, g_parm, parms); - mutex_unlock(&cam->s_mutex); parms->parm.capture.readbuffers = n_dma_bufs; return ret; } @@ -1554,12 +1478,10 @@ static int mcam_vidioc_g_parm(struct file *filp, void *priv, static int mcam_vidioc_s_parm(struct file *filp, void *priv, struct v4l2_streamparm *parms) { - struct mcam_camera *cam = priv; + struct mcam_camera *cam = video_drvdata(filp); int ret; - mutex_lock(&cam->s_mutex); ret = sensor_call(cam, video, s_parm, parms); - mutex_unlock(&cam->s_mutex); parms->parm.capture.readbuffers = n_dma_bufs; return ret; } @@ -1567,7 +1489,7 @@ static int mcam_vidioc_s_parm(struct file *filp, void *priv, static int mcam_vidioc_enum_framesizes(struct file *filp, void *priv, struct v4l2_frmsizeenum *sizes) { - struct mcam_camera *cam = priv; + struct mcam_camera *cam = video_drvdata(filp); struct mcam_format_struct *f; struct v4l2_subdev_frame_size_enum fse = { .index = sizes->index, @@ -1579,9 +1501,7 @@ static int mcam_vidioc_enum_framesizes(struct file *filp, void *priv, if (f->pixelformat != sizes->pixel_format) return -EINVAL; fse.code = f->mbus_code; - mutex_lock(&cam->s_mutex); ret = sensor_call(cam, pad, enum_frame_size, NULL, &fse); - mutex_unlock(&cam->s_mutex); if (ret) return ret; if (fse.min_width == fse.max_width && @@ -1604,7 +1524,7 @@ static int mcam_vidioc_enum_framesizes(struct file *filp, void *priv, static int mcam_vidioc_enum_frameintervals(struct file *filp, void *priv, struct v4l2_frmivalenum *interval) { - struct mcam_camera *cam = priv; + struct mcam_camera *cam = video_drvdata(filp); struct mcam_format_struct *f; struct v4l2_subdev_frame_interval_enum fie = { .index = interval->index, @@ -1618,9 +1538,7 @@ static int mcam_vidioc_enum_frameintervals(struct file *filp, void *priv, if (f->pixelformat != interval->pixel_format) return -EINVAL; fie.code = f->mbus_code; - mutex_lock(&cam->s_mutex); ret = sensor_call(cam, pad, enum_frame_interval, NULL, &fie); - mutex_unlock(&cam->s_mutex); if (ret) return ret; interval->type = V4L2_FRMIVAL_TYPE_DISCRETE; @@ -1632,7 +1550,7 @@ static int mcam_vidioc_enum_frameintervals(struct file *filp, void *priv, static int mcam_vidioc_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) { - struct mcam_camera *cam = priv; + struct mcam_camera *cam = video_drvdata(file); if (reg->reg > cam->regs_size - 4) return -EINVAL; @@ -1644,7 +1562,7 @@ static int mcam_vidioc_g_register(struct file *file, void *priv, static int mcam_vidioc_s_register(struct file *file, void *priv, const struct v4l2_dbg_register *reg) { - struct mcam_camera *cam = priv; + struct mcam_camera *cam = video_drvdata(file); if (reg->reg > cam->regs_size - 4) return -EINVAL; @@ -1662,18 +1580,20 @@ static const struct v4l2_ioctl_ops mcam_v4l_ioctl_ops = { .vidioc_enum_input = mcam_vidioc_enum_input, .vidioc_g_input = mcam_vidioc_g_input, .vidioc_s_input = mcam_vidioc_s_input, - .vidioc_s_std = mcam_vidioc_s_std, - .vidioc_g_std = mcam_vidioc_g_std, - .vidioc_reqbufs = mcam_vidioc_reqbufs, - .vidioc_querybuf = mcam_vidioc_querybuf, - .vidioc_qbuf = mcam_vidioc_qbuf, - .vidioc_dqbuf = mcam_vidioc_dqbuf, - .vidioc_streamon = mcam_vidioc_streamon, - .vidioc_streamoff = mcam_vidioc_streamoff, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_g_parm = mcam_vidioc_g_parm, .vidioc_s_parm = mcam_vidioc_s_parm, .vidioc_enum_framesizes = mcam_vidioc_enum_framesizes, .vidioc_enum_frameintervals = mcam_vidioc_enum_frameintervals, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = mcam_vidioc_g_register, .vidioc_s_register = mcam_vidioc_s_register, @@ -1687,43 +1607,36 @@ static const struct v4l2_ioctl_ops mcam_v4l_ioctl_ops = { static int mcam_v4l_open(struct file *filp) { struct mcam_camera *cam = video_drvdata(filp); - int ret = 0; - - filp->private_data = cam; + int ret; - cam->frame_state.frames = 0; - cam->frame_state.singles = 0; - cam->frame_state.delivered = 0; mutex_lock(&cam->s_mutex); - if (cam->users == 0) { - ret = mcam_setup_vb2(cam); - if (ret) - goto out; + ret = v4l2_fh_open(filp); + if (ret) + goto out; + if (v4l2_fh_is_singular_file(filp)) { ret = mcam_ctlr_power_up(cam); if (ret) goto out; __mcam_cam_reset(cam); mcam_set_config_needed(cam, 1); } - (cam->users)++; out: mutex_unlock(&cam->s_mutex); + if (ret) + v4l2_fh_release(filp); return ret; } static int mcam_v4l_release(struct file *filp) { - struct mcam_camera *cam = filp->private_data; + struct mcam_camera *cam = video_drvdata(filp); + bool last_open; - cam_dbg(cam, "Release, %d frames, %d singles, %d delivered\n", - cam->frame_state.frames, cam->frame_state.singles, - cam->frame_state.delivered); mutex_lock(&cam->s_mutex); - (cam->users)--; - if (cam->users == 0) { - mcam_ctlr_stop_dma(cam); - mcam_cleanup_vb2(cam); + last_open = v4l2_fh_is_singular_file(filp); + _vb2_fop_release(filp, NULL); + if (last_open) { mcam_disable_mipi(cam); mcam_ctlr_power_down(cam); if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read) @@ -1734,54 +1647,13 @@ static int mcam_v4l_release(struct file *filp) return 0; } -static ssize_t mcam_v4l_read(struct file *filp, - char __user *buffer, size_t len, loff_t *pos) -{ - struct mcam_camera *cam = filp->private_data; - int ret; - - mutex_lock(&cam->s_mutex); - ret = vb2_read(&cam->vb_queue, buffer, len, pos, - filp->f_flags & O_NONBLOCK); - mutex_unlock(&cam->s_mutex); - return ret; -} - - - -static unsigned int mcam_v4l_poll(struct file *filp, - struct poll_table_struct *pt) -{ - struct mcam_camera *cam = filp->private_data; - int ret; - - mutex_lock(&cam->s_mutex); - ret = vb2_poll(&cam->vb_queue, filp, pt); - mutex_unlock(&cam->s_mutex); - return ret; -} - - -static int mcam_v4l_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct mcam_camera *cam = filp->private_data; - int ret; - - mutex_lock(&cam->s_mutex); - ret = vb2_mmap(&cam->vb_queue, vma); - mutex_unlock(&cam->s_mutex); - return ret; -} - - - static const struct v4l2_file_operations mcam_v4l_fops = { .owner = THIS_MODULE, .open = mcam_v4l_open, .release = mcam_v4l_release, - .read = mcam_v4l_read, - .poll = mcam_v4l_poll, - .mmap = mcam_v4l_mmap, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, .unlocked_ioctl = video_ioctl2, }; @@ -1792,8 +1664,6 @@ static const struct v4l2_file_operations mcam_v4l_fops = { */ static struct video_device mcam_v4l_template = { .name = "mcam", - .tvnorms = V4L2_STD_NTSC_M, - .fops = &mcam_v4l_fops, .ioctl_ops = &mcam_v4l_ioctl_ops, .release = video_device_release_empty, @@ -1811,7 +1681,7 @@ static void mcam_frame_complete(struct mcam_camera *cam, int frame) set_bit(frame, &cam->flags); clear_bit(CF_DMA_ACTIVE, &cam->flags); cam->next_buf = frame; - cam->buf_seq[frame] = ++(cam->sequence); + cam->buf_seq[frame] = cam->sequence++; cam->frame_state.frames++; /* * "This should never happen" @@ -1924,10 +1794,17 @@ int mccic_register(struct mcam_camera *cam) mcam_set_config_needed(cam, 1); cam->pix_format = mcam_def_pix_format; cam->mbus_code = mcam_def_mbus_code; - INIT_LIST_HEAD(&cam->buffers); mcam_ctlr_init(cam); /* + * Get the v4l2 setup done. + */ + ret = v4l2_ctrl_handler_init(&cam->ctrl_handler, 10); + if (ret) + goto out_unregister; + cam->v4l2_dev.ctrl_handler = &cam->ctrl_handler; + + /* * Try to find the sensor. */ sensor_cfg.clock_speed = cam->clock_speed; @@ -1943,21 +1820,22 @@ int mccic_register(struct mcam_camera *cam) ret = mcam_cam_init(cam); if (ret) goto out_unregister; - /* - * Get the v4l2 setup done. - */ - ret = v4l2_ctrl_handler_init(&cam->ctrl_handler, 10); + + ret = mcam_setup_vb2(cam); if (ret) goto out_unregister; - cam->v4l2_dev.ctrl_handler = &cam->ctrl_handler; mutex_lock(&cam->s_mutex); cam->vdev = mcam_v4l_template; cam->vdev.v4l2_dev = &cam->v4l2_dev; + cam->vdev.lock = &cam->s_mutex; + cam->vdev.queue = &cam->vb_queue; video_set_drvdata(&cam->vdev, cam); ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); - if (ret) - goto out; + if (ret) { + mutex_unlock(&cam->s_mutex); + goto out_unregister; + } /* * If so requested, try to get our DMA buffers now. @@ -1968,11 +1846,11 @@ int mccic_register(struct mcam_camera *cam) " will try again later."); } -out: - v4l2_ctrl_handler_free(&cam->ctrl_handler); mutex_unlock(&cam->s_mutex); - return ret; + return 0; + out_unregister: + v4l2_ctrl_handler_free(&cam->ctrl_handler); v4l2_device_unregister(&cam->v4l2_dev); return ret; } @@ -1986,11 +1864,11 @@ void mccic_shutdown(struct mcam_camera *cam) * take it down again will wedge the machine, which is frowned * upon. */ - if (cam->users > 0) { + if (!list_empty(&cam->vdev.fh_list)) { cam_warn(cam, "Removing a device with users!\n"); mcam_ctlr_power_down(cam); } - vb2_queue_release(&cam->vb_queue); + mcam_cleanup_vb2(cam); if (cam->buffer_mode == B_vmalloc) mcam_free_dma_bufs(cam); video_unregister_device(&cam->vdev); @@ -2006,7 +1884,7 @@ void mccic_shutdown(struct mcam_camera *cam) void mccic_suspend(struct mcam_camera *cam) { mutex_lock(&cam->s_mutex); - if (cam->users > 0) { + if (!list_empty(&cam->vdev.fh_list)) { enum mcam_state cstate = cam->state; mcam_ctlr_stop_dma(cam); @@ -2021,7 +1899,7 @@ int mccic_resume(struct mcam_camera *cam) int ret = 0; mutex_lock(&cam->s_mutex); - if (cam->users > 0) { + if (!list_empty(&cam->vdev.fh_list)) { ret = mcam_ctlr_power_up(cam); if (ret) { mutex_unlock(&cam->s_mutex); diff --git a/drivers/media/platform/marvell-ccic/mcam-core.h b/drivers/media/platform/marvell-ccic/mcam-core.h index 7ffdf4d..97167f6 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.h +++ b/drivers/media/platform/marvell-ccic/mcam-core.h @@ -146,7 +146,6 @@ struct mcam_camera { struct v4l2_ctrl_handler ctrl_handler; enum mcam_state state; unsigned long flags; /* Buffer status, mainly (dev_lock) */ - int users; /* How many open FDs */ struct mcam_frame_state frame_state; /* Frame state counter */ /* @@ -163,6 +162,8 @@ struct mcam_camera { unsigned int nbufs; /* How many are alloc'd */ int next_buf; /* Next to consume (dev_lock) */ + char bus_info[32]; /* querycap bus_info */ + /* DMA buffers - vmalloc mode */ #ifdef MCAM_MODE_VMALLOC unsigned int dma_buf_size; /* allocated size */ diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index 0ed9b3a..b5f165a 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -371,6 +371,7 @@ static int mmpcam_probe(struct platform_device *pdev) mcam->lane = pdata->lane; mcam->chip_id = MCAM_ARMADA610; mcam->buffer_mode = B_DMA_sg; + strlcpy(mcam->bus_info, "platform:mmp-camera", sizeof(mcam->bus_info)); spin_lock_init(&mcam->dev_lock); /* * Get our I/O memory. diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index 17b189a..f09c5f1 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -445,7 +445,7 @@ static int omapvid_init(struct omap_vout_device *vout, u32 addr) int ret = 0, i; struct v4l2_window *win; struct omap_overlay *ovl; - int posx, posy, outw, outh, temp; + int posx, posy, outw, outh; struct omap_video_timings *timing; struct omapvideo_info *ovid = &vout->vid_info; @@ -468,9 +468,7 @@ static int omapvid_init(struct omap_vout_device *vout, u32 addr) /* Invert the height and width for 90 * and 270 degree rotation */ - temp = outw; - outw = outh; - outh = temp; + swap(outw, outh); posy = (timing->y_res - win->w.width) - win->w.left; posx = win->w.top; break; @@ -481,9 +479,7 @@ static int omapvid_init(struct omap_vout_device *vout, u32 addr) break; case dss_rotation_270_degree: - temp = outw; - outw = outh; - outh = temp; + swap(outw, outh); posy = win->w.left; posx = (timing->x_res - win->w.height) - win->w.top; break; diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c index 15cb254..1380327 100644 --- a/drivers/media/platform/omap3isp/isppreview.c +++ b/drivers/media/platform/omap3isp/isppreview.c @@ -929,14 +929,10 @@ static void preview_setup_hw(struct isp_prev_device *prev, u32 update, u32 active) { unsigned int i; - u32 features; if (update == 0) return; - features = (prev->params.params[0].features & active) - | (prev->params.params[1].features & ~active); - for (i = 0; i < ARRAY_SIZE(update_attrs); i++) { const struct preview_update *attr = &update_attrs[i]; struct prev_params *params; diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index f6a61b9..76e6289 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -115,7 +115,7 @@ static int sensor_set_power(struct camif_dev *camif, int on) struct cam_sensor *sensor = &camif->sensor; int err = 0; - if (!on == camif->sensor.power_count) + if (camif->sensor.power_count == !on) err = v4l2_subdev_call(sensor->sd, core, s_power, on); if (!err) sensor->power_count += on ? 1 : -1; @@ -131,7 +131,7 @@ static int sensor_set_streaming(struct camif_dev *camif, int on) struct cam_sensor *sensor = &camif->sensor; int err = 0; - if (!on == camif->sensor.stream_count) + if (camif->sensor.stream_count == !on) err = v4l2_subdev_call(sensor->sd, video, s_stream, on); if (!err) sensor->stream_count += on ? 1 : -1; @@ -449,19 +449,22 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, struct camif_vp *vp = vb2_get_drv_priv(vq); struct camif_dev *camif = vp->camif; struct camif_frame *frame = &vp->out_frame; - const struct camif_fmt *fmt = vp->out_fmt; + const struct camif_fmt *fmt; unsigned int size; if (pfmt) { pix = &pfmt->fmt.pix; fmt = s3c_camif_find_format(vp, &pix->pixelformat, -1); + if (fmt == NULL) + return -EINVAL; size = (pix->width * pix->height * fmt->depth) / 8; } else { + fmt = vp->out_fmt; + if (fmt == NULL) + return -EINVAL; size = (frame->f_width * frame->f_height * fmt->depth) / 8; } - if (fmt == NULL) - return -EINVAL; *num_planes = 1; if (pix) diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c index 2d5bd3a..f47b332 100644 --- a/drivers/media/platform/s3c-camif/camif-core.c +++ b/drivers/media/platform/s3c-camif/camif-core.c @@ -628,7 +628,7 @@ static struct s3c_camif_drvdata s3c6410_camif_drvdata = { .bus_clk_freq = 133000000UL, }; -static struct platform_device_id s3c_camif_driver_ids[] = { +static const struct platform_device_id s3c_camif_driver_ids[] = { { .name = "s3c2440-camif", .driver_data = (unsigned long)&s3c244x_camif_drvdata, diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index ec3e124..421a7c3 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -787,7 +787,7 @@ static const struct of_device_id exynos_g2d_match[] = { }; MODULE_DEVICE_TABLE(of, exynos_g2d_match); -static struct platform_device_id g2d_driver_ids[] = { +static const struct platform_device_id g2d_driver_ids[] = { { .name = "s5p-g2d", .driver_data = (unsigned long)&g2d_drvdata_v3x, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 8333fbc2..8de61dc 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -211,6 +211,7 @@ static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx) dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE; else dst_buf->b->v4l2_buf.field = V4L2_FIELD_INTERLACED; + dst_buf->b->v4l2_buf.flags |= V4L2_BUF_FLAG_LAST; ctx->dec_dst_flag &= ~(1 << dst_buf->b->v4l2_buf.index); vb2_buffer_done(dst_buf->b, VB2_BUF_STATE_DONE); @@ -1337,8 +1338,6 @@ static int s5p_mfc_runtime_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev); - if (!m_dev->alloc_ctx) - return 0; atomic_set(&m_dev->pm.power, 1); return 0; } @@ -1463,7 +1462,7 @@ static struct s5p_mfc_variant mfc_drvdata_v8 = { .fw_name[0] = "s5p-mfc-v8.fw", }; -static struct platform_device_id mfc_driver_ids[] = { +static const struct platform_device_id mfc_driver_ids[] = { { .name = "s5p-mfc", .driver_data = (unsigned long)&mfc_drvdata_v5, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index b09bcd1..9a923b1 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -184,7 +184,7 @@ static int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx) ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_r, &ctx->bank2); if (ret) { mfc_err("Failed to allocate Bank2 temporary buffer\n"); - s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->bank1); + s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->bank1); return ret; } BUG_ON(ctx->bank2.dma & ((1 << MFC_BANK2_ALIGN_ORDER) - 1)); @@ -263,7 +263,7 @@ static void s5p_mfc_release_dev_context_buffer_v5(struct s5p_mfc_dev *dev) static void s5p_mfc_write_info_v5(struct s5p_mfc_ctx *ctx, unsigned int data, unsigned int ofs) { - writel(data, (void *)(ctx->shm.virt + ofs)); + *(u32 *)(ctx->shm.virt + ofs) = data; wmb(); } @@ -271,7 +271,7 @@ static unsigned int s5p_mfc_read_info_v5(struct s5p_mfc_ctx *ctx, unsigned long ofs) { rmb(); - return readl((void *)(ctx->shm.virt + ofs)); + return *(u32 *)(ctx->shm.virt + ofs); } static void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index cefad18..12497f5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -1852,7 +1852,7 @@ static void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data, unsigned int ofs) { s5p_mfc_clock_on(); - writel(data, (void *)((unsigned long)ofs)); + writel(data, (void __iomem *)((unsigned long)ofs)); s5p_mfc_clock_off(); } @@ -1862,7 +1862,7 @@ s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned long ofs) int ret; s5p_mfc_clock_on(); - ret = readl((void *)ofs); + ret = readl((void __iomem *)ofs); s5p_mfc_clock_off(); return ret; diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c index 0e74aab..7994075 100644 --- a/drivers/media/platform/s5p-tv/hdmi_drv.c +++ b/drivers/media/platform/s5p-tv/hdmi_drv.c @@ -96,7 +96,7 @@ struct hdmi_device { struct hdmi_resources res; }; -static struct platform_device_id hdmi_driver_types[] = { +static const struct platform_device_id hdmi_driver_types[] = { { .name = "s5pv210-hdmi", }, { @@ -648,15 +648,20 @@ static int hdmi_g_dv_timings(struct v4l2_subdev *sd, return 0; } -static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int hdmi_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *fmt = &format->format; struct hdmi_device *hdev = sd_to_hdmi_dev(sd); const struct hdmi_timings *t = hdev->cur_conf; dev_dbg(hdev->dev, "%s\n", __func__); if (!hdev->cur_conf) return -EINVAL; + if (format->pad) + return -EINVAL; + memset(fmt, 0, sizeof(*fmt)); fmt->width = t->hact.end - t->hact.beg; fmt->height = t->vact[0].end - t->vact[0].beg; @@ -712,18 +717,19 @@ static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = { static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = { .s_dv_timings = hdmi_s_dv_timings, .g_dv_timings = hdmi_g_dv_timings, - .g_mbus_fmt = hdmi_g_mbus_fmt, .s_stream = hdmi_s_stream, }; static const struct v4l2_subdev_pad_ops hdmi_sd_pad_ops = { .enum_dv_timings = hdmi_enum_dv_timings, .dv_timings_cap = hdmi_dv_timings_cap, + .get_fmt = hdmi_get_fmt, }; static const struct v4l2_subdev_ops hdmi_sd_ops = { .core = &hdmi_sd_core_ops, .video = &hdmi_sd_video_ops, + .pad = &hdmi_sd_pad_ops, }; static int hdmi_runtime_suspend(struct device *dev) diff --git a/drivers/media/platform/s5p-tv/mixer_drv.c b/drivers/media/platform/s5p-tv/mixer_drv.c index 2a9501d..5ef6777 100644 --- a/drivers/media/platform/s5p-tv/mixer_drv.c +++ b/drivers/media/platform/s5p-tv/mixer_drv.c @@ -46,11 +46,15 @@ void mxr_get_mbus_fmt(struct mxr_device *mdev, struct v4l2_mbus_framefmt *mbus_fmt) { struct v4l2_subdev *sd; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int ret; mutex_lock(&mdev->mutex); sd = to_outsd(mdev); - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, mbus_fmt); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); + *mbus_fmt = fmt.format; WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name); mutex_unlock(&mdev->mutex); } @@ -62,7 +66,10 @@ void mxr_streamer_get(struct mxr_device *mdev) mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer); if (mdev->n_streamer == 1) { struct v4l2_subdev *sd = to_outsd(mdev); - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mbus_fmt = &fmt.format; struct mxr_resources *res = &mdev->res; int ret; @@ -72,12 +79,12 @@ void mxr_streamer_get(struct mxr_device *mdev) clk_set_parent(res->sclk_mixer, res->sclk_hdmi); mxr_reg_s_output(mdev, to_output(mdev)->cookie); - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name); ret = v4l2_subdev_call(sd, video, s_stream, 1); WARN(ret, "starting stream failed for output %s\n", sd->name); - mxr_reg_set_mbus_fmt(mdev, &mbus_fmt); + mxr_reg_set_mbus_fmt(mdev, mbus_fmt); mxr_reg_streamon(mdev); ret = mxr_reg_wait4vsync(mdev); WARN(ret, "failed to get vsync (%d) from output\n", ret); diff --git a/drivers/media/platform/s5p-tv/sdo_drv.c b/drivers/media/platform/s5p-tv/sdo_drv.c index 3621af9..c75d435 100644 --- a/drivers/media/platform/s5p-tv/sdo_drv.c +++ b/drivers/media/platform/s5p-tv/sdo_drv.c @@ -160,13 +160,17 @@ static int sdo_g_std_output(struct v4l2_subdev *sd, v4l2_std_id *std) return 0; } -static int sdo_g_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int sdo_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *fmt = &format->format; struct sdo_device *sdev = sd_to_sdev(sd); if (!sdev->fmt) return -ENXIO; + if (format->pad) + return -EINVAL; /* all modes are 720 pixels wide */ fmt->width = 720; fmt->height = sdev->fmt->height; @@ -256,13 +260,17 @@ static const struct v4l2_subdev_video_ops sdo_sd_video_ops = { .s_std_output = sdo_s_std_output, .g_std_output = sdo_g_std_output, .g_tvnorms_output = sdo_g_tvnorms_output, - .g_mbus_fmt = sdo_g_mbus_fmt, .s_stream = sdo_s_stream, }; +static const struct v4l2_subdev_pad_ops sdo_sd_pad_ops = { + .get_fmt = sdo_get_fmt, +}; + static const struct v4l2_subdev_ops sdo_sd_ops = { .core = &sdo_sd_core_ops, .video = &sdo_sd_video_ops, + .pad = &sdo_sd_pad_ops, }; static int sdo_runtime_suspend(struct device *dev) diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index dde1ccc..8b799ba 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -600,7 +600,7 @@ static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std) { unsigned int best_err = UINT_MAX, best = geo->in_width, width_max, height_max, img_height_max; - int i, idx = 0; + int i, idx_h = 0, idx_v = 0; if (std & V4L2_STD_525_60) { width_max = 858; @@ -625,7 +625,7 @@ static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std) err = abs(found - geo->output.width); if (err < best_err) { best_err = err; - idx = i; + idx_h = i; best = found; } if (!err) @@ -633,12 +633,12 @@ static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std) } geo->output.width = best; - geo->scale_idx_h = idx; + geo->scale_idx_h = idx_h; if (geo->output.left + best > width_max) geo->output.left = width_max - best; pr_debug("%s(): W %u * %u/%u = %u\n", __func__, geo->in_width, - vou_scale_h_num[idx], vou_scale_h_den[idx], best); + vou_scale_h_num[idx_h], vou_scale_h_den[idx_h], best); best_err = UINT_MAX; @@ -655,7 +655,7 @@ static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std) err = abs(found - geo->output.height); if (err < best_err) { best_err = err; - idx = i; + idx_v = i; best = found; } if (!err) @@ -663,12 +663,12 @@ static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std) } geo->output.height = best; - geo->scale_idx_v = idx; + geo->scale_idx_v = idx_v; if (geo->output.top + best > height_max) geo->output.top = height_max - best; pr_debug("%s(): H %u * %u/%u = %u\n", __func__, geo->in_height, - vou_scale_v_num[idx], vou_scale_v_den[idx], best); + vou_scale_v_num[idx_v], vou_scale_v_den[idx_v], best); } static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, @@ -679,12 +679,14 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, unsigned int img_height_max; int pix_idx; struct sh_vou_geometry geo; - struct v4l2_mbus_framefmt mbfmt = { + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, /* Revisit: is this the correct code? */ - .code = MEDIA_BUS_FMT_YUYV8_2X8, - .field = V4L2_FIELD_INTERLACED, - .colorspace = V4L2_COLORSPACE_SMPTE170M, + .format.code = MEDIA_BUS_FMT_YUYV8_2X8, + .format.field = V4L2_FIELD_INTERLACED, + .format.colorspace = V4L2_COLORSPACE_SMPTE170M, }; + struct v4l2_mbus_framefmt *mbfmt = &format.format; int ret; dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__, @@ -720,27 +722,27 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, vou_adjust_output(&geo, vou_dev->std); - mbfmt.width = geo.output.width; - mbfmt.height = geo.output.height; - ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, - s_mbus_fmt, &mbfmt); + mbfmt->width = geo.output.width; + mbfmt->height = geo.output.height; + ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, pad, + set_fmt, NULL, &format); /* Must be implemented, so, don't check for -ENOIOCTLCMD */ if (ret < 0) return ret; dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__, - geo.output.width, geo.output.height, mbfmt.width, mbfmt.height); + geo.output.width, geo.output.height, mbfmt->width, mbfmt->height); /* Sanity checks */ - if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH || - (unsigned)mbfmt.height > img_height_max || - mbfmt.code != MEDIA_BUS_FMT_YUYV8_2X8) + if ((unsigned)mbfmt->width > VOU_MAX_IMAGE_WIDTH || + (unsigned)mbfmt->height > img_height_max || + mbfmt->code != MEDIA_BUS_FMT_YUYV8_2X8) return -EIO; - if (mbfmt.width != geo.output.width || - mbfmt.height != geo.output.height) { - geo.output.width = mbfmt.width; - geo.output.height = mbfmt.height; + if (mbfmt->width != geo.output.width || + mbfmt->height != geo.output.height) { + geo.output.width = mbfmt->width; + geo.output.height = mbfmt->height; vou_adjust_input(&geo, vou_dev->std); } @@ -942,11 +944,12 @@ static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT}; struct v4l2_pix_format *pix = &vou_dev->pix; struct sh_vou_geometry geo; - struct v4l2_mbus_framefmt mbfmt = { + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, /* Revisit: is this the correct code? */ - .code = MEDIA_BUS_FMT_YUYV8_2X8, - .field = V4L2_FIELD_INTERLACED, - .colorspace = V4L2_COLORSPACE_SMPTE170M, + .format.code = MEDIA_BUS_FMT_YUYV8_2X8, + .format.field = V4L2_FIELD_INTERLACED, + .format.colorspace = V4L2_COLORSPACE_SMPTE170M, }; unsigned int img_height_max; int ret; @@ -984,22 +987,22 @@ static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) */ v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, s_crop, &sd_crop); - mbfmt.width = geo.output.width; - mbfmt.height = geo.output.height; - ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, - s_mbus_fmt, &mbfmt); + format.format.width = geo.output.width; + format.format.height = geo.output.height; + ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, pad, + set_fmt, NULL, &format); /* Must be implemented, so, don't check for -ENOIOCTLCMD */ if (ret < 0) return ret; /* Sanity checks */ - if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH || - (unsigned)mbfmt.height > img_height_max || - mbfmt.code != MEDIA_BUS_FMT_YUYV8_2X8) + if ((unsigned)format.format.width > VOU_MAX_IMAGE_WIDTH || + (unsigned)format.format.height > img_height_max || + format.format.code != MEDIA_BUS_FMT_YUYV8_2X8) return -EIO; - geo.output.width = mbfmt.width; - geo.output.height = mbfmt.height; + geo.output.width = format.format.width; + geo.output.height = format.format.height; /* * No down-scaling. According to the API, current call has precedence: diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index c835beb..2879026 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -487,7 +487,10 @@ static int isi_camera_set_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &format.format; int ret; xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); @@ -500,27 +503,27 @@ static int isi_camera_set_fmt(struct soc_camera_device *icd, dev_dbg(icd->parent, "Plan to set format %dx%d\n", pix->width, pix->height); - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); if (ret < 0) return ret; - if (mf.code != xlate->code) + if (mf->code != xlate->code) return -EINVAL; ret = configure_geometry(isi, pix->width, pix->height, xlate->code); if (ret < 0) return ret; - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->field = mf->field; + pix->colorspace = mf->colorspace; icd->current_fmt = xlate; dev_dbg(icd->parent, "Finally set format %dx%d\n", @@ -535,7 +538,11 @@ static int isi_camera_try_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + struct v4l2_mbus_framefmt *mf = &format.format; u32 pixfmt = pix->pixelformat; int ret; @@ -552,21 +559,21 @@ static int isi_camera_try_fmt(struct soc_camera_device *icd, pix->width = MAX_SUPPORT_WIDTH; /* limit to sensor capabilities */ - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; - pix->width = mf.width; - pix->height = mf.height; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->colorspace = mf->colorspace; - switch (mf.field) { + switch (mf->field) { case V4L2_FIELD_ANY: pix->field = V4L2_FIELD_NONE; break; @@ -574,7 +581,7 @@ static int isi_camera_try_fmt(struct soc_camera_device *icd, break; default: dev_err(icd->parent, "Field type %d unsupported.\n", - mf.field); + mf->field); ret = -EINVAL; } @@ -648,19 +655,22 @@ static int isi_camera_get_formats(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); int formats = 0, ret; /* sensor format */ - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = idx, + }; /* soc camera host format */ const struct soc_mbus_pixelfmt *fmt; - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); if (ret < 0) /* No more formats */ return 0; - fmt = soc_mbus_get_fmtdesc(code); + fmt = soc_mbus_get_fmtdesc(code.code); if (!fmt) { dev_err(icd->parent, - "Invalid format code #%u: %d\n", idx, code); + "Invalid format code #%u: %d\n", idx, code.code); return 0; } @@ -672,7 +682,7 @@ static int isi_camera_get_formats(struct soc_camera_device *icd, return 0; } - switch (code) { + switch (code.code) { case MEDIA_BUS_FMT_UYVY8_2X8: case MEDIA_BUS_FMT_VYUY8_2X8: case MEDIA_BUS_FMT_YUYV8_2X8: @@ -680,10 +690,10 @@ static int isi_camera_get_formats(struct soc_camera_device *icd, formats++; if (xlate) { xlate->host_fmt = &isi_camera_formats[0]; - xlate->code = code; + xlate->code = code.code; xlate++; dev_dbg(icd->parent, "Providing format %s using code %d\n", - isi_camera_formats[0].name, code); + isi_camera_formats[0].name, code.code); } break; default: @@ -699,7 +709,7 @@ static int isi_camera_get_formats(struct soc_camera_device *icd, formats++; if (xlate) { xlate->host_fmt = fmt; - xlate->code = code; + xlate->code = code.code; xlate++; } diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 192377f..ea4c423 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -912,7 +912,10 @@ static int mx2_camera_set_crop(struct soc_camera_device *icd, struct v4l2_crop a_writable = *a; struct v4l2_rect *rect = &a_writable.c; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; int ret; soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); @@ -923,15 +926,15 @@ static int mx2_camera_set_crop(struct soc_camera_device *icd, return ret; /* The capture device might have changed its output */ - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) return ret; dev_dbg(icd->parent, "Sensor cropped %dx%d\n", - mf.width, mf.height); + mf->width, mf->height); - icd->user_width = mf.width; - icd->user_height = mf.height; + icd->user_width = mf->width; + icd->user_height = mf->height; return ret; } @@ -943,22 +946,25 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_mbus_pixelfmt *fmt; struct device *dev = icd->parent; - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = idx, + }; int ret, formats = 0; - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); if (ret < 0) /* no more formats */ return 0; - fmt = soc_mbus_get_fmtdesc(code); + fmt = soc_mbus_get_fmtdesc(code.code); if (!fmt) { - dev_err(dev, "Invalid format code #%u: %d\n", idx, code); + dev_err(dev, "Invalid format code #%u: %d\n", idx, code.code); return 0; } - if (code == MEDIA_BUS_FMT_YUYV8_2X8 || - code == MEDIA_BUS_FMT_UYVY8_2X8) { + if (code.code == MEDIA_BUS_FMT_YUYV8_2X8 || + code.code == MEDIA_BUS_FMT_UYVY8_2X8) { formats++; if (xlate) { /* @@ -967,21 +973,21 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd, */ xlate->host_fmt = soc_mbus_get_fmtdesc(MEDIA_BUS_FMT_YUYV8_1_5X8); - xlate->code = code; + xlate->code = code.code; dev_dbg(dev, "Providing host format %s for sensor code %d\n", - xlate->host_fmt->name, code); + xlate->host_fmt->name, code.code); xlate++; } } - if (code == MEDIA_BUS_FMT_UYVY8_2X8) { + if (code.code == MEDIA_BUS_FMT_UYVY8_2X8) { formats++; if (xlate) { xlate->host_fmt = soc_mbus_get_fmtdesc(MEDIA_BUS_FMT_YUYV8_2X8); - xlate->code = code; + xlate->code = code.code; dev_dbg(dev, "Providing host format %s for sensor code %d\n", - xlate->host_fmt->name, code); + xlate->host_fmt->name, code.code); xlate++; } } @@ -990,7 +996,7 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd, formats++; if (xlate) { xlate->host_fmt = fmt; - xlate->code = code; + xlate->code = code.code; xlate++; } return formats; @@ -1121,7 +1127,10 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &format.format; int ret; dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n", @@ -1134,19 +1143,19 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd, return -EINVAL; } - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); if (ret < 0 && ret != -ENOIOCTLCMD) return ret; /* Store width and height returned by the sensor for resizing */ - pcdev->s_width = mf.width; - pcdev->s_height = mf.height; + pcdev->s_width = mf->width; + pcdev->s_height = mf->height; dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n", __func__, pcdev->s_width, pcdev->s_height); @@ -1154,19 +1163,19 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd, xlate->host_fmt->fourcc); memset(pcdev->resizing, 0, sizeof(pcdev->resizing)); - if ((mf.width != pix->width || mf.height != pix->height) && + if ((mf->width != pix->width || mf->height != pix->height) && pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { - if (mx2_emmaprp_resize(pcdev, &mf, pix, true) < 0) + if (mx2_emmaprp_resize(pcdev, mf, pix, true) < 0) dev_dbg(icd->parent, "%s: can't resize\n", __func__); } - if (mf.code != xlate->code) + if (mf->code != xlate->code) return -EINVAL; - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->field = mf->field; + pix->colorspace = mf->colorspace; icd->current_fmt = xlate; dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n", @@ -1181,7 +1190,11 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + struct v4l2_mbus_framefmt *mf = &format.format; __u32 pixfmt = pix->pixelformat; struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx2_camera_dev *pcdev = ici->priv; @@ -1204,13 +1217,13 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, pix->width &= ~0x7; /* limit to sensor capabilities */ - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; @@ -1221,29 +1234,29 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, emma_prp = mx27_emma_prp_get_format(xlate->code, xlate->host_fmt->fourcc); - if ((mf.width != pix->width || mf.height != pix->height) && + if ((mf->width != pix->width || mf->height != pix->height) && emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { - if (mx2_emmaprp_resize(pcdev, &mf, pix, false) < 0) + if (mx2_emmaprp_resize(pcdev, mf, pix, false) < 0) dev_dbg(icd->parent, "%s: can't resize\n", __func__); } - if (mf.field == V4L2_FIELD_ANY) - mf.field = V4L2_FIELD_NONE; + if (mf->field == V4L2_FIELD_ANY) + mf->field = V4L2_FIELD_NONE; /* * Driver supports interlaced images provided they have * both fields so that they can be processed as if they * were progressive. */ - if (mf.field != V4L2_FIELD_NONE && !V4L2_FIELD_HAS_BOTH(mf.field)) { + if (mf->field != V4L2_FIELD_NONE && !V4L2_FIELD_HAS_BOTH(mf->field)) { dev_err(icd->parent, "Field type %d unsupported.\n", - mf.field); + mf->field); return -EINVAL; } - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->field = mf->field; + pix->colorspace = mf->colorspace; dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n", __func__, pix->width, pix->height); diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index 3435fd2..ace41f5 100644 --- a/drivers/media/platform/soc_camera/mx3_camera.c +++ b/drivers/media/platform/soc_camera/mx3_camera.c @@ -659,18 +659,21 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->parent; int formats = 0, ret; - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = idx, + }; const struct soc_mbus_pixelfmt *fmt; - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); if (ret < 0) /* No more formats */ return 0; - fmt = soc_mbus_get_fmtdesc(code); + fmt = soc_mbus_get_fmtdesc(code.code); if (!fmt) { dev_warn(icd->parent, - "Unsupported format code #%u: 0x%x\n", idx, code); + "Unsupported format code #%u: 0x%x\n", idx, code.code); return 0; } @@ -679,25 +682,25 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id if (ret < 0) return 0; - switch (code) { + switch (code.code) { case MEDIA_BUS_FMT_SBGGR10_1X10: formats++; if (xlate) { xlate->host_fmt = &mx3_camera_formats[0]; - xlate->code = code; + xlate->code = code.code; xlate++; dev_dbg(dev, "Providing format %s using code 0x%x\n", - mx3_camera_formats[0].name, code); + mx3_camera_formats[0].name, code.code); } break; case MEDIA_BUS_FMT_Y10_1X10: formats++; if (xlate) { xlate->host_fmt = &mx3_camera_formats[1]; - xlate->code = code; + xlate->code = code.code; xlate++; dev_dbg(dev, "Providing format %s using code 0x%x\n", - mx3_camera_formats[1].name, code); + mx3_camera_formats[1].name, code.code); } break; default: @@ -709,7 +712,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id formats++; if (xlate) { xlate->host_fmt = fmt; - xlate->code = code; + xlate->code = code.code; dev_dbg(dev, "Providing format %c%c%c%c in pass-through mode\n", (fmt->fourcc >> (0*8)) & 0xFF, (fmt->fourcc >> (1*8)) & 0xFF, @@ -801,7 +804,10 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; int ret; soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); @@ -812,30 +818,30 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, return ret; /* The capture device might have changed its output sizes */ - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) return ret; - if (mf.code != icd->current_fmt->code) + if (mf->code != icd->current_fmt->code) return -EINVAL; - if (mf.width & 7) { + if (mf->width & 7) { /* Ouch! We can only handle 8-byte aligned width... */ - stride_align(&mf.width); - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + stride_align(&mf->width); + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &fmt); if (ret < 0) return ret; } - if (mf.width != icd->user_width || mf.height != icd->user_height) - configure_geometry(mx3_cam, mf.width, mf.height, + if (mf->width != icd->user_width || mf->height != icd->user_height) + configure_geometry(mx3_cam, mf->width, mf->height, icd->current_fmt->host_fmt); dev_dbg(icd->parent, "Sensor cropped %dx%d\n", - mf.width, mf.height); + mf->width, mf->height); - icd->user_width = mf.width; - icd->user_height = mf.height; + icd->user_width = mf->width; + icd->user_height = mf->height; return ret; } @@ -848,7 +854,10 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &format.format; int ret; xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); @@ -869,17 +878,17 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, configure_geometry(mx3_cam, pix->width, pix->height, xlate->host_fmt); - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); if (ret < 0) return ret; - if (mf.code != xlate->code) + if (mf->code != xlate->code) return -EINVAL; if (!mx3_cam->idmac_channel[0]) { @@ -888,11 +897,11 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, return ret; } - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - mx3_cam->field = mf.field; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->field = mf->field; + mx3_cam->field = mf->field; + pix->colorspace = mf->colorspace; icd->current_fmt = xlate; dev_dbg(icd->parent, "Sensor set %dx%d\n", pix->width, pix->height); @@ -906,7 +915,11 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + struct v4l2_mbus_framefmt *mf = &format.format; __u32 pixfmt = pix->pixelformat; int ret; @@ -923,21 +936,21 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, pix->width = 4096; /* limit to sensor capabilities */ - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; - pix->width = mf.width; - pix->height = mf.height; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->colorspace = mf->colorspace; - switch (mf.field) { + switch (mf->field) { case V4L2_FIELD_ANY: pix->field = V4L2_FIELD_NONE; break; @@ -945,7 +958,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, break; default: dev_err(icd->parent, "Field type %d unsupported.\n", - mf.field); + mf->field); ret = -EINVAL; } diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c index 16f65ec..ba8dcd1 100644 --- a/drivers/media/platform/soc_camera/omap1_camera.c +++ b/drivers/media/platform/soc_camera/omap1_camera.c @@ -1068,18 +1068,21 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->parent; int formats = 0, ret; - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = idx, + }; const struct soc_mbus_pixelfmt *fmt; - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); if (ret < 0) /* No more formats */ return 0; - fmt = soc_mbus_get_fmtdesc(code); + fmt = soc_mbus_get_fmtdesc(code.code); if (!fmt) { dev_warn(dev, "%s: unsupported format code #%d: %d\n", __func__, - idx, code); + idx, code.code); return 0; } @@ -1087,7 +1090,7 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd, if (fmt->bits_per_sample != 8) return 0; - switch (code) { + switch (code.code) { case MEDIA_BUS_FMT_YUYV8_2X8: case MEDIA_BUS_FMT_YVYU8_2X8: case MEDIA_BUS_FMT_UYVY8_2X8: @@ -1098,14 +1101,14 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd, case MEDIA_BUS_FMT_RGB565_2X8_LE: formats++; if (xlate) { - xlate->host_fmt = soc_mbus_find_fmtdesc(code, + xlate->host_fmt = soc_mbus_find_fmtdesc(code.code, omap1_cam_formats, ARRAY_SIZE(omap1_cam_formats)); - xlate->code = code; + xlate->code = code.code; xlate++; dev_dbg(dev, "%s: providing format %s as byte swapped code #%d\n", - __func__, xlate->host_fmt->name, code); + __func__, xlate->host_fmt->name, code.code); } default: if (xlate) @@ -1116,7 +1119,7 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd, formats++; if (xlate) { xlate->host_fmt = fmt; - xlate->code = code; + xlate->code = code.code; xlate++; } @@ -1154,7 +1157,7 @@ static int dma_align(int *width, int *height, return 1; } -#define subdev_call_with_sense(pcdev, dev, icd, sd, function, args...) \ +#define subdev_call_with_sense(pcdev, dev, icd, sd, op, function, args...) \ ({ \ struct soc_camera_sense sense = { \ .master_clock = pcdev->camexclk, \ @@ -1165,7 +1168,7 @@ static int dma_align(int *width, int *height, if (pcdev->pdata) \ sense.pixel_clock_max = pcdev->pdata->lclk_khz_max * 1000; \ icd->sense = &sense; \ - __ret = v4l2_subdev_call(sd, video, function, ##args); \ + __ret = v4l2_subdev_call(sd, op, function, ##args); \ icd->sense = NULL; \ \ if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { \ @@ -1179,16 +1182,17 @@ static int dma_align(int *width, int *height, __ret; \ }) -static int set_mbus_format(struct omap1_cam_dev *pcdev, struct device *dev, +static int set_format(struct omap1_cam_dev *pcdev, struct device *dev, struct soc_camera_device *icd, struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf, + struct v4l2_subdev_format *format, const struct soc_camera_format_xlate *xlate) { s32 bytes_per_line; - int ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_mbus_fmt, mf); + struct v4l2_mbus_framefmt *mf = &format->format; + int ret = subdev_call_with_sense(pcdev, dev, icd, sd, pad, set_fmt, NULL, format); if (ret < 0) { - dev_err(dev, "%s: s_mbus_fmt failed\n", __func__); + dev_err(dev, "%s: set_fmt failed\n", __func__); return ret; } @@ -1221,42 +1225,45 @@ static int omap1_cam_set_crop(struct soc_camera_device *icd, struct device *dev = icd->parent; struct soc_camera_host *ici = to_soc_camera_host(dev); struct omap1_cam_dev *pcdev = ici->priv; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; int ret; - ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_crop, crop); + ret = subdev_call_with_sense(pcdev, dev, icd, sd, video, s_crop, crop); if (ret < 0) { dev_warn(dev, "%s: failed to crop to %ux%u@%u:%u\n", __func__, rect->width, rect->height, rect->left, rect->top); return ret; } - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) { dev_warn(dev, "%s: failed to fetch current format\n", __func__); return ret; } - ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode, + ret = dma_align(&mf->width, &mf->height, xlate->host_fmt, pcdev->vb_mode, false); if (ret < 0) { dev_err(dev, "%s: failed to align %ux%u %s with DMA\n", - __func__, mf.width, mf.height, + __func__, mf->width, mf->height, xlate->host_fmt->name); return ret; } if (!ret) { /* sensor returned geometry not DMA aligned, trying to fix */ - ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate); + ret = set_format(pcdev, dev, icd, sd, &fmt, xlate); if (ret < 0) { dev_err(dev, "%s: failed to set format\n", __func__); return ret; } } - icd->user_width = mf.width; - icd->user_height = mf.height; + icd->user_width = mf->width; + icd->user_height = mf->height; return 0; } @@ -1270,7 +1277,10 @@ static int omap1_cam_set_fmt(struct soc_camera_device *icd, struct soc_camera_host *ici = to_soc_camera_host(dev); struct omap1_cam_dev *pcdev = ici->priv; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &format.format; int ret; xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); @@ -1280,13 +1290,13 @@ static int omap1_cam_set_fmt(struct soc_camera_device *icd, return -EINVAL; } - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode, + ret = dma_align(&mf->width, &mf->height, xlate->host_fmt, pcdev->vb_mode, true); if (ret < 0) { dev_err(dev, "%s: failed to align %ux%u %s with DMA\n", @@ -1295,16 +1305,16 @@ static int omap1_cam_set_fmt(struct soc_camera_device *icd, return ret; } - ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate); + ret = set_format(pcdev, dev, icd, sd, &format, xlate); if (ret < 0) { dev_err(dev, "%s: failed to set format\n", __func__); return ret; } - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->field = mf->field; + pix->colorspace = mf->colorspace; icd->current_fmt = xlate; return 0; @@ -1316,7 +1326,11 @@ static int omap1_cam_try_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + struct v4l2_mbus_framefmt *mf = &format.format; int ret; /* TODO: limit to mx1 hardware capabilities */ @@ -1327,21 +1341,21 @@ static int omap1_cam_try_fmt(struct soc_camera_device *icd, return -EINVAL; } - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; /* limit to sensor capabilities */ - ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->field = mf->field; + pix->colorspace = mf->colorspace; return 0; } diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index 8d6e343..fcb942d 100644 --- a/drivers/media/platform/soc_camera/pxa_camera.c +++ b/drivers/media/platform/soc_camera/pxa_camera.c @@ -1253,17 +1253,20 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id struct device *dev = icd->parent; int formats = 0, ret; struct pxa_cam *cam; - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = idx, + }; const struct soc_mbus_pixelfmt *fmt; - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); if (ret < 0) /* No more formats */ return 0; - fmt = soc_mbus_get_fmtdesc(code); + fmt = soc_mbus_get_fmtdesc(code.code); if (!fmt) { - dev_err(dev, "Invalid format code #%u: %d\n", idx, code); + dev_err(dev, "Invalid format code #%u: %d\n", idx, code.code); return 0; } @@ -1282,15 +1285,15 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id cam = icd->host_priv; } - switch (code) { + switch (code.code) { case MEDIA_BUS_FMT_UYVY8_2X8: formats++; if (xlate) { xlate->host_fmt = &pxa_camera_formats[0]; - xlate->code = code; + xlate->code = code.code; xlate++; dev_dbg(dev, "Providing format %s using code %d\n", - pxa_camera_formats[0].name, code); + pxa_camera_formats[0].name, code.code); } case MEDIA_BUS_FMT_VYUY8_2X8: case MEDIA_BUS_FMT_YUYV8_2X8: @@ -1314,7 +1317,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id formats++; if (xlate) { xlate->host_fmt = fmt; - xlate->code = code; + xlate->code = code.code; xlate++; } @@ -1346,7 +1349,10 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd, .master_clock = pcdev->mclk, .pixel_clock_max = pcdev->ciclk / 4, }; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; struct pxa_cam *cam = icd->host_priv; u32 fourcc = icd->current_fmt->host_fmt->fourcc; int ret; @@ -1365,23 +1371,23 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd, return ret; } - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) return ret; - if (pxa_camera_check_frame(mf.width, mf.height)) { + if (pxa_camera_check_frame(mf->width, mf->height)) { /* * Camera cropping produced a frame beyond our capabilities. * FIXME: just extract a subframe, that we can process. */ - v4l_bound_align_image(&mf.width, 48, 2048, 1, - &mf.height, 32, 2048, 0, + v4l_bound_align_image(&mf->width, 48, 2048, 1, + &mf->height, 32, 2048, 0, fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0); - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &fmt); if (ret < 0) return ret; - if (pxa_camera_check_frame(mf.width, mf.height)) { + if (pxa_camera_check_frame(mf->width, mf->height)) { dev_warn(icd->parent, "Inconsistent state. Use S_FMT to repair\n"); return -EINVAL; @@ -1398,8 +1404,8 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd, recalculate_fifo_timeout(pcdev, sense.pixel_clock); } - icd->user_width = mf.width; - icd->user_height = mf.height; + icd->user_width = mf->width; + icd->user_height = mf->height; pxa_camera_setup_cicr(icd, cam->flags, fourcc); @@ -1419,7 +1425,10 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, .pixel_clock_max = pcdev->ciclk / 4, }; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &format.format; int ret; xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); @@ -1433,15 +1442,15 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, /* The caller holds a mutex. */ icd->sense = &sense; - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); - if (mf.code != xlate->code) + if (mf->code != xlate->code) return -EINVAL; icd->sense = NULL; @@ -1449,10 +1458,10 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, if (ret < 0) { dev_warn(dev, "Failed to configure for format %x\n", pix->pixelformat); - } else if (pxa_camera_check_frame(mf.width, mf.height)) { + } else if (pxa_camera_check_frame(mf->width, mf->height)) { dev_warn(dev, "Camera driver produced an unsupported frame %dx%d\n", - mf.width, mf.height); + mf->width, mf->height); ret = -EINVAL; } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { if (sense.pixel_clock > sense.pixel_clock_max) { @@ -1467,10 +1476,10 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, if (ret < 0) return ret; - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->field = mf->field; + pix->colorspace = mf->colorspace; icd->current_fmt = xlate; return ret; @@ -1482,7 +1491,11 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + struct v4l2_mbus_framefmt *mf = &format.format; __u32 pixfmt = pix->pixelformat; int ret; @@ -1503,22 +1516,22 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0); /* limit to sensor capabilities */ - mf.width = pix->width; - mf.height = pix->height; + mf->width = pix->width; + mf->height = pix->height; /* Only progressive video supported so far */ - mf.field = V4L2_FIELD_NONE; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->field = V4L2_FIELD_NONE; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; - pix->width = mf.width; - pix->height = mf.height; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->colorspace = mf->colorspace; - switch (mf.field) { + switch (mf->field) { case V4L2_FIELD_ANY: case V4L2_FIELD_NONE: pix->field = V4L2_FIELD_NONE; @@ -1526,7 +1539,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, default: /* TODO: support interlaced at least in pass-through mode */ dev_err(icd->parent, "Field type %d unsupported.\n", - mf.field); + mf->field); return -EINVAL; } diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index 6460f8e..db7700b 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -899,7 +899,7 @@ static irqreturn_t rcar_vin_irq(int irq, void *data) priv->queue_buf[slot]->v4l2_buf.field = priv->field; priv->queue_buf[slot]->v4l2_buf.sequence = priv->sequence++; - do_gettimeofday(&priv->queue_buf[slot]->v4l2_buf.timestamp); + v4l2_get_timestamp(&priv->queue_buf[slot]->v4l2_buf.timestamp); vb2_buffer_done(priv->queue_buf[slot], VB2_BUF_STATE_DONE); priv->queue_buf[slot] = NULL; @@ -1323,16 +1323,19 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, int ret, k, n; int formats = 0; struct rcar_vin_cam *cam; - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = idx, + }; const struct soc_mbus_pixelfmt *fmt; - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); if (ret < 0) return 0; - fmt = soc_mbus_get_fmtdesc(code); + fmt = soc_mbus_get_fmtdesc(code.code); if (!fmt) { - dev_warn(dev, "unsupported format code #%u: %d\n", idx, code); + dev_warn(dev, "unsupported format code #%u: %d\n", idx, code.code); return 0; } @@ -1341,12 +1344,15 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, return 0; if (!icd->host_priv) { - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; struct v4l2_rect rect; struct device *dev = icd->parent; int shift; - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) return ret; @@ -1356,8 +1362,8 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, /* Sensor driver doesn't support cropping */ rect.left = 0; rect.top = 0; - rect.width = mf.width; - rect.height = mf.height; + rect.width = mf->width; + rect.height = mf->height; } else if (ret < 0) { return ret; } @@ -1367,16 +1373,16 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, * 1280x960, 640x480, 320x240 */ for (shift = 0; shift < 3; shift++) { - if (mf.width <= VIN_MAX_WIDTH && - mf.height <= VIN_MAX_HEIGHT) + if (mf->width <= VIN_MAX_WIDTH && + mf->height <= VIN_MAX_HEIGHT) break; - mf.width = 1280 >> shift; - mf.height = 960 >> shift; + mf->width = 1280 >> shift; + mf->height = 960 >> shift; ret = v4l2_device_call_until_err(sd->v4l2_dev, soc_camera_grp_id(icd), - video, s_mbus_fmt, - &mf); + pad, set_fmt, NULL, + &fmt); if (ret < 0) return ret; } @@ -1384,11 +1390,11 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, if (shift == 3) { dev_err(dev, "Failed to configure the client below %ux%u\n", - mf.width, mf.height); + mf->width, mf->height); return -EIO; } - dev_dbg(dev, "camera fmt %ux%u\n", mf.width, mf.height); + dev_dbg(dev, "camera fmt %ux%u\n", mf->width, mf->height); cam = kzalloc(sizeof(*cam), GFP_KERNEL); if (!cam) @@ -1399,10 +1405,10 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, */ cam->rect = rect; cam->subrect = rect; - cam->width = mf.width; - cam->height = mf.height; - cam->out_width = mf.width; - cam->out_height = mf.height; + cam->width = mf->width; + cam->height = mf->height; + cam->out_width = mf->width; + cam->out_height = mf->height; icd->host_priv = cam; } else { @@ -1413,7 +1419,7 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, if (!idx) cam->extra_fmt = NULL; - switch (code) { + switch (code.code) { case MEDIA_BUS_FMT_YUYV8_1X16: case MEDIA_BUS_FMT_YUYV8_2X8: case MEDIA_BUS_FMT_YUYV10_2X10: @@ -1427,9 +1433,9 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, formats += n; for (k = 0; xlate && k < n; k++, xlate++) { xlate->host_fmt = &rcar_vin_formats[k]; - xlate->code = code; + xlate->code = code.code; dev_dbg(dev, "Providing format %s using code %d\n", - rcar_vin_formats[k].name, code); + rcar_vin_formats[k].name, code.code); } break; default: @@ -1445,7 +1451,7 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, formats++; if (xlate) { xlate->host_fmt = fmt; - xlate->code = code; + xlate->code = code.code; xlate++; } @@ -1470,7 +1476,10 @@ static int rcar_vin_set_crop(struct soc_camera_device *icd, struct v4l2_rect *cam_rect = &cam_crop.c; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->parent; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; u32 vnmc; int ret, i; @@ -1494,16 +1503,16 @@ static int rcar_vin_set_crop(struct soc_camera_device *icd, /* On success cam_crop contains current camera crop */ /* Retrieve camera output window */ - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) return ret; - if (mf.width > VIN_MAX_WIDTH || mf.height > VIN_MAX_HEIGHT) + if (mf->width > VIN_MAX_WIDTH || mf->height > VIN_MAX_HEIGHT) return -EINVAL; /* Cache camera output window */ - cam->width = mf.width; - cam->height = mf.height; + cam->width = mf->width; + cam->height = mf->height; icd->user_width = cam->width; icd->user_height = cam->height; @@ -1679,7 +1688,11 @@ static int rcar_vin_try_fmt(struct soc_camera_device *icd, const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + struct v4l2_mbus_framefmt *mf = &format.format; __u32 pixfmt = pix->pixelformat; int width, height; int ret; @@ -1706,25 +1719,25 @@ static int rcar_vin_try_fmt(struct soc_camera_device *icd, pix->sizeimage = 0; /* limit to sensor capabilities */ - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.code = xlate->code; - mf.colorspace = pix->colorspace; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->code = xlate->code; + mf->colorspace = pix->colorspace; ret = v4l2_device_call_until_err(sd->v4l2_dev, soc_camera_grp_id(icd), - video, try_mbus_fmt, &mf); + pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; /* Adjust only if VIN cannot scale */ - if (pix->width > mf.width * 2) - pix->width = mf.width * 2; - if (pix->height > mf.height * 3) - pix->height = mf.height * 3; + if (pix->width > mf->width * 2) + pix->width = mf->width * 2; + if (pix->height > mf->height * 3) + pix->height = mf->height * 3; - pix->field = mf.field; - pix->colorspace = mf.colorspace; + pix->field = mf->field; + pix->colorspace = mf->colorspace; if (pixfmt == V4L2_PIX_FMT_NV16) { /* FIXME: check against rect_max after converting soc-camera */ @@ -1735,12 +1748,12 @@ static int rcar_vin_try_fmt(struct soc_camera_device *icd, * requested a bigger rectangle, it will not return a * smaller one. */ - mf.width = VIN_MAX_WIDTH; - mf.height = VIN_MAX_HEIGHT; + mf->width = VIN_MAX_WIDTH; + mf->height = VIN_MAX_HEIGHT; ret = v4l2_device_call_until_err(sd->v4l2_dev, soc_camera_grp_id(icd), - video, try_mbus_fmt, - &mf); + pad, set_fmt, &pad_cfg, + &format); if (ret < 0) { dev_err(icd->parent, "client try_fmt() = %d\n", ret); @@ -1748,9 +1761,9 @@ static int rcar_vin_try_fmt(struct soc_camera_device *icd, } } /* We will scale exactly */ - if (mf.width > width) + if (mf->width > width) pix->width = width; - if (mf.height > height) + if (mf->height > height) pix->height = height; } @@ -1808,7 +1821,7 @@ static struct soc_camera_host_ops rcar_vin_host_ops = { }; #ifdef CONFIG_OF -static struct of_device_id rcar_vin_of_table[] = { +static const struct of_device_id rcar_vin_of_table[] = { { .compatible = "renesas,vin-r8a7794", .data = (void *)RCAR_GEN2 }, { .compatible = "renesas,vin-r8a7793", .data = (void *)RCAR_GEN2 }, { .compatible = "renesas,vin-r8a7791", .data = (void *)RCAR_GEN2 }, diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index 9ce202f..c5c6c4e 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -1048,17 +1048,20 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int int ret, k, n; int formats = 0; struct sh_mobile_ceu_cam *cam; - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = idx, + }; const struct soc_mbus_pixelfmt *fmt; - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); if (ret < 0) /* No more formats */ return 0; - fmt = soc_mbus_get_fmtdesc(code); + fmt = soc_mbus_get_fmtdesc(code.code); if (!fmt) { - dev_warn(dev, "unsupported format code #%u: %d\n", idx, code); + dev_warn(dev, "unsupported format code #%u: %d\n", idx, code.code); return 0; } @@ -1070,7 +1073,10 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int } if (!icd->host_priv) { - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; struct v4l2_rect rect; int shift = 0; @@ -1088,7 +1094,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int return ret; /* First time */ - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) return ret; @@ -1099,14 +1105,14 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int * sizes, just try VGA multiples. If needed, this can be * adjusted in the future. */ - while ((mf.width > pcdev->max_width || - mf.height > pcdev->max_height) && shift < 4) { + while ((mf->width > pcdev->max_width || + mf->height > pcdev->max_height) && shift < 4) { /* Try 2560x1920, 1280x960, 640x480, 320x240 */ - mf.width = 2560 >> shift; - mf.height = 1920 >> shift; + mf->width = 2560 >> shift; + mf->height = 1920 >> shift; ret = v4l2_device_call_until_err(sd->v4l2_dev, - soc_camera_grp_id(icd), video, - s_mbus_fmt, &mf); + soc_camera_grp_id(icd), pad, + set_fmt, NULL, &fmt); if (ret < 0) return ret; shift++; @@ -1114,11 +1120,11 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int if (shift == 4) { dev_err(dev, "Failed to configure the client below %ux%x\n", - mf.width, mf.height); + mf->width, mf->height); return -EIO; } - dev_geo(dev, "camera fmt %ux%u\n", mf.width, mf.height); + dev_geo(dev, "camera fmt %ux%u\n", mf->width, mf->height); cam = kzalloc(sizeof(*cam), GFP_KERNEL); if (!cam) @@ -1128,8 +1134,8 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int cam->rect = rect; cam->subrect = rect; - cam->width = mf.width; - cam->height = mf.height; + cam->width = mf->width; + cam->height = mf->height; icd->host_priv = cam; } else { @@ -1140,7 +1146,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int if (!idx) cam->extra_fmt = NULL; - switch (code) { + switch (code.code) { case MEDIA_BUS_FMT_UYVY8_2X8: case MEDIA_BUS_FMT_VYUY8_2X8: case MEDIA_BUS_FMT_YUYV8_2X8: @@ -1163,10 +1169,10 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int formats += n; for (k = 0; xlate && k < n; k++) { xlate->host_fmt = &sh_mobile_ceu_formats[k]; - xlate->code = code; + xlate->code = code.code; xlate++; dev_dbg(dev, "Providing format %s using code %d\n", - sh_mobile_ceu_formats[k].name, code); + sh_mobile_ceu_formats[k].name, code.code); } break; default: @@ -1178,7 +1184,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int formats++; if (xlate) { xlate->host_fmt = fmt; - xlate->code = code; + xlate->code = code.code; xlate++; dev_dbg(dev, "Providing format %s in pass-through mode\n", fmt->name); @@ -1214,7 +1220,10 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, struct sh_mobile_ceu_cam *cam = icd->host_priv; struct v4l2_rect *cam_rect = &cam_crop.c; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; unsigned int scale_cam_h, scale_cam_v, scale_ceu_h, scale_ceu_v, out_width, out_height; int interm_width, interm_height; @@ -1244,16 +1253,16 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, /* On success cam_crop contains current camera crop */ /* 3. Retrieve camera output window */ - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) return ret; - if (mf.width > pcdev->max_width || mf.height > pcdev->max_height) + if (mf->width > pcdev->max_width || mf->height > pcdev->max_height) return -EINVAL; /* 4. Calculate camera scales */ - scale_cam_h = calc_generic_scale(cam_rect->width, mf.width); - scale_cam_v = calc_generic_scale(cam_rect->height, mf.height); + scale_cam_h = calc_generic_scale(cam_rect->width, mf->width); + scale_cam_v = calc_generic_scale(cam_rect->height, mf->height); /* Calculate intermediate window */ interm_width = scale_down(rect->width, scale_cam_h); @@ -1264,7 +1273,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, new_scale_h = calc_generic_scale(rect->width, icd->user_width); - mf.width = scale_down(cam_rect->width, new_scale_h); + mf->width = scale_down(cam_rect->width, new_scale_h); } if (interm_height < icd->user_height) { @@ -1272,26 +1281,26 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, new_scale_v = calc_generic_scale(rect->height, icd->user_height); - mf.height = scale_down(cam_rect->height, new_scale_v); + mf->height = scale_down(cam_rect->height, new_scale_v); } if (interm_width < icd->user_width || interm_height < icd->user_height) { ret = v4l2_device_call_until_err(sd->v4l2_dev, - soc_camera_grp_id(icd), video, - s_mbus_fmt, &mf); + soc_camera_grp_id(icd), pad, + set_fmt, NULL, &fmt); if (ret < 0) return ret; - dev_geo(dev, "New camera output %ux%u\n", mf.width, mf.height); - scale_cam_h = calc_generic_scale(cam_rect->width, mf.width); - scale_cam_v = calc_generic_scale(cam_rect->height, mf.height); + dev_geo(dev, "New camera output %ux%u\n", mf->width, mf->height); + scale_cam_h = calc_generic_scale(cam_rect->width, mf->width); + scale_cam_v = calc_generic_scale(cam_rect->height, mf->height); interm_width = scale_down(rect->width, scale_cam_h); interm_height = scale_down(rect->height, scale_cam_v); } /* Cache camera output window */ - cam->width = mf.width; - cam->height = mf.height; + cam->width = mf->width; + cam->height = mf->height; if (pcdev->image_mode) { out_width = min(interm_width, icd->user_width); @@ -1490,7 +1499,11 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + struct v4l2_mbus_framefmt *mf = &format.format; __u32 pixfmt = pix->pixelformat; int width, height; int ret; @@ -1518,21 +1531,21 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, height = pix->height; /* limit to sensor capabilities */ - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.code = xlate->code; - mf.colorspace = pix->colorspace; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->code = xlate->code; + mf->colorspace = pix->colorspace; ret = v4l2_device_call_until_err(sd->v4l2_dev, soc_camera_grp_id(icd), - video, try_mbus_fmt, &mf); + pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->field = mf->field; + pix->colorspace = mf->colorspace; switch (pixfmt) { case V4L2_PIX_FMT_NV12: @@ -1547,11 +1560,11 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, * requested a bigger rectangle, it will not return a * smaller one. */ - mf.width = pcdev->max_width; - mf.height = pcdev->max_height; + mf->width = pcdev->max_width; + mf->height = pcdev->max_height; ret = v4l2_device_call_until_err(sd->v4l2_dev, - soc_camera_grp_id(icd), video, - try_mbus_fmt, &mf); + soc_camera_grp_id(icd), pad, + set_fmt, &pad_cfg, &format); if (ret < 0) { /* Shouldn't actually happen... */ dev_err(icd->parent, @@ -1560,9 +1573,9 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, } } /* We will scale exactly */ - if (mf.width > width) + if (mf->width > width) pix->width = width; - if (mf.height > height) + if (mf->height > height) pix->height = height; pix->bytesperline = max(pix->bytesperline, pix->width); diff --git a/drivers/media/platform/soc_camera/sh_mobile_csi2.c b/drivers/media/platform/soc_camera/sh_mobile_csi2.c index cd93241..12d3626 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_csi2.c +++ b/drivers/media/platform/soc_camera/sh_mobile_csi2.c @@ -45,11 +45,17 @@ struct sh_csi2 { static void sh_csi2_hwinit(struct sh_csi2 *priv); -static int sh_csi2_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int sh_csi2_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; + struct v4l2_mbus_framefmt *mf = &format->format; + u32 tmp = (priv->client->channel & 3) << 8; + + if (format->pad) + return -EINVAL; if (mf->width > 8188) mf->width = 8188; @@ -85,21 +91,11 @@ static int sh_csi2_try_fmt(struct v4l2_subdev *sd, break; } - return 0; -} - -/* - * We have done our best in try_fmt to try and tell the sensor, which formats - * we support. If now the configuration is unsuitable for us we can only - * error out. - */ -static int sh_csi2_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); - u32 tmp = (priv->client->channel & 3) << 8; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *mf; + return 0; + } - dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); if (mf->width > 8188 || mf->width & 1) return -EINVAL; @@ -211,12 +207,14 @@ static int sh_csi2_s_mbus_config(struct v4l2_subdev *sd, } static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = { - .s_mbus_fmt = sh_csi2_s_fmt, - .try_mbus_fmt = sh_csi2_try_fmt, .g_mbus_config = sh_csi2_g_mbus_config, .s_mbus_config = sh_csi2_s_mbus_config, }; +static struct v4l2_subdev_pad_ops sh_csi2_subdev_pad_ops = { + .set_fmt = sh_csi2_set_fmt, +}; + static void sh_csi2_hwinit(struct sh_csi2 *priv) { struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; @@ -313,6 +311,7 @@ static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops = { static struct v4l2_subdev_ops sh_csi2_subdev_ops = { .core = &sh_csi2_subdev_core_ops, .video = &sh_csi2_subdev_video_ops, + .pad = &sh_csi2_subdev_pad_ops, }; static int sh_csi2_probe(struct platform_device *pdev) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 7bfe7665..d708df4 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -484,10 +484,14 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) struct soc_camera_host *ici = to_soc_camera_host(icd->parent); unsigned int i, fmts = 0, raw_fmts = 0; int ret; - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; - while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code)) + while (!v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code)) { raw_fmts++; + code.index++; + } if (!ici->ops->get_formats) /* @@ -521,11 +525,12 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) fmts = 0; for (i = 0; i < raw_fmts; i++) if (!ici->ops->get_formats) { - v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &code); + code.index = i; + v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); icd->user_formats[fmts].host_fmt = - soc_mbus_get_fmtdesc(code); + soc_mbus_get_fmtdesc(code.code); if (icd->user_formats[fmts].host_fmt) - icd->user_formats[fmts++].code = code; + icd->user_formats[fmts++].code = code.code; } else { ret = ici->ops->get_formats(icd, i, &icd->user_formats[fmts]); @@ -1284,7 +1289,10 @@ static struct soc_camera_device *soc_camera_add_pdev(struct soc_camera_async_cli static int soc_camera_probe_finish(struct soc_camera_device *icd) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; int ret; sd->grp_id = soc_camera_grp_id(icd); @@ -1314,11 +1322,11 @@ static int soc_camera_probe_finish(struct soc_camera_device *icd) goto evidstart; /* Try to improve our guess of a reasonable window format */ - if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { - icd->user_width = mf.width; - icd->user_height = mf.height; - icd->colorspace = mf.colorspace; - icd->field = mf.field; + if (!v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt)) { + icd->user_width = mf->width; + icd->user_height = mf->height; + icd->colorspace = mf->colorspace; + icd->field = mf->field; } soc_camera_remove_device(icd); diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c index f535910..cc8eb07 100644 --- a/drivers/media/platform/soc_camera/soc_camera_platform.c +++ b/drivers/media/platform/soc_camera/soc_camera_platform.c @@ -37,9 +37,11 @@ static int soc_camera_platform_s_stream(struct v4l2_subdev *sd, int enable) } static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *mf = &format->format; mf->width = p->format.width; mf->height = p->format.height; @@ -61,15 +63,16 @@ static struct v4l2_subdev_core_ops platform_subdev_core_ops = { .s_power = soc_camera_platform_s_power, }; -static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int soc_camera_platform_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); - if (index) + if (code->pad || code->index) return -EINVAL; - *code = p->format.code; + code->code = p->format.code; return 0; } @@ -117,18 +120,21 @@ static int soc_camera_platform_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops platform_subdev_video_ops = { .s_stream = soc_camera_platform_s_stream, - .enum_mbus_fmt = soc_camera_platform_enum_fmt, .cropcap = soc_camera_platform_cropcap, .g_crop = soc_camera_platform_g_crop, - .try_mbus_fmt = soc_camera_platform_fill_fmt, - .g_mbus_fmt = soc_camera_platform_fill_fmt, - .s_mbus_fmt = soc_camera_platform_fill_fmt, .g_mbus_config = soc_camera_platform_g_mbus_config, }; +static const struct v4l2_subdev_pad_ops platform_subdev_pad_ops = { + .enum_mbus_code = soc_camera_platform_enum_mbus_code, + .get_fmt = soc_camera_platform_fill_fmt, + .set_fmt = soc_camera_platform_fill_fmt, +}; + static struct v4l2_subdev_ops platform_subdev_ops = { .core = &platform_subdev_core_ops, .video = &platform_subdev_video_ops, + .pad = &platform_subdev_pad_ops, }; static int soc_camera_platform_probe(struct platform_device *pdev) diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c b/drivers/media/platform/soc_camera/soc_scale_crop.c index 8e74fb7..bda29bc 100644 --- a/drivers/media/platform/soc_camera/soc_scale_crop.c +++ b/drivers/media/platform/soc_camera/soc_scale_crop.c @@ -211,22 +211,23 @@ int soc_camera_client_s_crop(struct v4l2_subdev *sd, } EXPORT_SYMBOL(soc_camera_client_s_crop); -/* Iterative s_mbus_fmt, also updates cached client crop on success */ -static int client_s_fmt(struct soc_camera_device *icd, +/* Iterative set_fmt, also updates cached client crop on success */ +static int client_set_fmt(struct soc_camera_device *icd, struct v4l2_rect *rect, struct v4l2_rect *subrect, unsigned int max_width, unsigned int max_height, - struct v4l2_mbus_framefmt *mf, bool host_can_scale) + struct v4l2_subdev_format *format, bool host_can_scale) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->parent; + struct v4l2_mbus_framefmt *mf = &format->format; unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h; struct v4l2_cropcap cap; bool host_1to1; int ret; ret = v4l2_device_call_until_err(sd->v4l2_dev, - soc_camera_grp_id(icd), video, - s_mbus_fmt, mf); + soc_camera_grp_id(icd), pad, + set_fmt, NULL, format); if (ret < 0) return ret; @@ -265,8 +266,8 @@ static int client_s_fmt(struct soc_camera_device *icd, mf->width = tmp_w; mf->height = tmp_h; ret = v4l2_device_call_until_err(sd->v4l2_dev, - soc_camera_grp_id(icd), video, - s_mbus_fmt, mf); + soc_camera_grp_id(icd), pad, + set_fmt, NULL, format); dev_geo(dev, "Camera scaled to %ux%u\n", mf->width, mf->height); if (ret < 0) { @@ -309,7 +310,11 @@ int soc_camera_client_scale(struct soc_camera_device *icd, bool host_can_scale, unsigned int shift) { struct device *dev = icd->parent; - struct v4l2_mbus_framefmt mf_tmp = *mf; + struct v4l2_subdev_format fmt_tmp = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .format = *mf, + }; + struct v4l2_mbus_framefmt *mf_tmp = &fmt_tmp.format; unsigned int scale_h, scale_v; int ret; @@ -317,25 +322,25 @@ int soc_camera_client_scale(struct soc_camera_device *icd, * 5. Apply iterative camera S_FMT for camera user window (also updates * client crop cache and the imaginary sub-rectangle). */ - ret = client_s_fmt(icd, rect, subrect, *width, *height, - &mf_tmp, host_can_scale); + ret = client_set_fmt(icd, rect, subrect, *width, *height, + &fmt_tmp, host_can_scale); if (ret < 0) return ret; dev_geo(dev, "5: camera scaled to %ux%u\n", - mf_tmp.width, mf_tmp.height); + mf_tmp->width, mf_tmp->height); /* 6. Retrieve camera output window (g_fmt) */ /* unneeded - it is already in "mf_tmp" */ /* 7. Calculate new client scales. */ - scale_h = soc_camera_calc_scale(rect->width, shift, mf_tmp.width); - scale_v = soc_camera_calc_scale(rect->height, shift, mf_tmp.height); + scale_h = soc_camera_calc_scale(rect->width, shift, mf_tmp->width); + scale_v = soc_camera_calc_scale(rect->height, shift, mf_tmp->height); - mf->width = mf_tmp.width; - mf->height = mf_tmp.height; - mf->colorspace = mf_tmp.colorspace; + mf->width = mf_tmp->width; + mf->height = mf_tmp->height; + mf->colorspace = mf_tmp->colorspace; /* * 8. Calculate new host crop - apply camera scales to previously diff --git a/drivers/media/platform/sti/bdisp/Makefile b/drivers/media/platform/sti/bdisp/Makefile new file mode 100644 index 0000000..bc53496 --- /dev/null +++ b/drivers/media/platform/sti/bdisp/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_VIDEO_STI_BDISP) := bdisp.o + +bdisp-objs := bdisp-v4l2.o bdisp-hw.o bdisp-debug.o diff --git a/drivers/media/platform/sti/bdisp/bdisp-debug.c b/drivers/media/platform/sti/bdisp/bdisp-debug.c new file mode 100644 index 0000000..18282a0 --- /dev/null +++ b/drivers/media/platform/sti/bdisp/bdisp-debug.c @@ -0,0 +1,679 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include <linux/debugfs.h> +#include <linux/pm_runtime.h> + +#include "bdisp.h" +#include "bdisp-filter.h" +#include "bdisp-reg.h" + +void bdisp_dbg_perf_begin(struct bdisp_dev *bdisp) +{ + bdisp->dbg.hw_start = ktime_get(); +} + +void bdisp_dbg_perf_end(struct bdisp_dev *bdisp) +{ + s64 time_us; + + time_us = ktime_us_delta(ktime_get(), bdisp->dbg.hw_start); + + if (!bdisp->dbg.min_duration) + bdisp->dbg.min_duration = time_us; + else + bdisp->dbg.min_duration = min(time_us, bdisp->dbg.min_duration); + + bdisp->dbg.last_duration = time_us; + bdisp->dbg.max_duration = max(time_us, bdisp->dbg.max_duration); + bdisp->dbg.tot_duration += time_us; +} + +static void bdisp_dbg_dump_ins(struct seq_file *s, u32 val) +{ + seq_printf(s, "INS\t0x%08X\t", val); + + switch (val & BLT_INS_S1_MASK) { + case BLT_INS_S1_OFF: + break; + case BLT_INS_S1_MEM: + seq_puts(s, "SRC1=mem - "); + break; + case BLT_INS_S1_CF: + seq_puts(s, "SRC1=ColorFill - "); + break; + case BLT_INS_S1_COPY: + seq_puts(s, "SRC1=copy - "); + break; + case BLT_INS_S1_FILL: + seq_puts(s, "SRC1=fil - "); + break; + default: + seq_puts(s, "SRC1=??? - "); + break; + } + + switch (val & BLT_INS_S2_MASK) { + case BLT_INS_S2_OFF: + break; + case BLT_INS_S2_MEM: + seq_puts(s, "SRC2=mem - "); + break; + case BLT_INS_S2_CF: + seq_puts(s, "SRC2=ColorFill - "); + break; + default: + seq_puts(s, "SRC2=??? - "); + break; + } + + if ((val & BLT_INS_S3_MASK) == BLT_INS_S3_MEM) + seq_puts(s, "SRC3=mem - "); + + if (val & BLT_INS_IVMX) + seq_puts(s, "IVMX - "); + if (val & BLT_INS_CLUT) + seq_puts(s, "CLUT - "); + if (val & BLT_INS_SCALE) + seq_puts(s, "Scale - "); + if (val & BLT_INS_FLICK) + seq_puts(s, "Flicker - "); + if (val & BLT_INS_CLIP) + seq_puts(s, "Clip - "); + if (val & BLT_INS_CKEY) + seq_puts(s, "ColorKey - "); + if (val & BLT_INS_OVMX) + seq_puts(s, "OVMX - "); + if (val & BLT_INS_DEI) + seq_puts(s, "Deint - "); + if (val & BLT_INS_PMASK) + seq_puts(s, "PlaneMask - "); + if (val & BLT_INS_VC1R) + seq_puts(s, "VC1R - "); + if (val & BLT_INS_ROTATE) + seq_puts(s, "Rotate - "); + if (val & BLT_INS_GRAD) + seq_puts(s, "GradFill - "); + if (val & BLT_INS_AQLOCK) + seq_puts(s, "AQLock - "); + if (val & BLT_INS_PACE) + seq_puts(s, "Pace - "); + if (val & BLT_INS_IRQ) + seq_puts(s, "IRQ - "); + + seq_puts(s, "\n"); +} + +static void bdisp_dbg_dump_tty(struct seq_file *s, u32 val) +{ + seq_printf(s, "TTY\t0x%08X\t", val); + seq_printf(s, "Pitch=%d - ", val & 0xFFFF); + + switch ((val & BLT_TTY_COL_MASK) >> BLT_TTY_COL_SHIFT) { + case BDISP_RGB565: + seq_puts(s, "RGB565 - "); + break; + case BDISP_XRGB8888: + seq_puts(s, "xRGB888 - "); + break; + case BDISP_ARGB8888: + seq_puts(s, "ARGB8888 - "); + break; + case BDISP_NV12: + seq_puts(s, "NV12 - "); + break; + case BDISP_YUV_3B: + seq_puts(s, "YUV420P - "); + break; + default: + seq_puts(s, "ColorFormat ??? - "); + break; + } + + if (val & BLT_TTY_ALPHA_R) + seq_puts(s, "AlphaRange - "); + if (val & BLT_TTY_CR_NOT_CB) + seq_puts(s, "CrNotCb - "); + if (val & BLT_TTY_MB) + seq_puts(s, "MB - "); + if (val & BLT_TTY_HSO) + seq_puts(s, "HSO inverse - "); + if (val & BLT_TTY_VSO) + seq_puts(s, "VSO inverse - "); + if (val & BLT_TTY_DITHER) + seq_puts(s, "Dither - "); + if (val & BLT_TTY_CHROMA) + seq_puts(s, "Write CHROMA - "); + if (val & BLT_TTY_BIG_END) + seq_puts(s, "BigEndian - "); + + seq_puts(s, "\n"); +} + +static void bdisp_dbg_dump_xy(struct seq_file *s, u32 val, char *name) +{ + seq_printf(s, "%s\t0x%08X\t", name, val); + seq_printf(s, "(%d,%d)\n", val & 0xFFFF, (val >> 16)); +} + +static void bdisp_dbg_dump_sz(struct seq_file *s, u32 val, char *name) +{ + seq_printf(s, "%s\t0x%08X\t", name, val); + seq_printf(s, "%dx%d\n", val & 0x1FFF, (val >> 16) & 0x1FFF); +} + +static void bdisp_dbg_dump_sty(struct seq_file *s, + u32 val, u32 addr, char *name) +{ + bool s1, s2, s3; + + seq_printf(s, "%s\t0x%08X\t", name, val); + + if (!addr || !name || (strlen(name) < 2)) + goto done; + + s1 = name[strlen(name) - 1] == '1'; + s2 = name[strlen(name) - 1] == '2'; + s3 = name[strlen(name) - 1] == '3'; + + seq_printf(s, "Pitch=%d - ", val & 0xFFFF); + + switch ((val & BLT_TTY_COL_MASK) >> BLT_TTY_COL_SHIFT) { + case BDISP_RGB565: + seq_puts(s, "RGB565 - "); + break; + case BDISP_XRGB8888: + seq_puts(s, "xRGB888 - "); + break; + case BDISP_ARGB8888: + seq_puts(s, "ARGB888 - "); + break; + case BDISP_NV12: + seq_puts(s, "NV12 - "); + break; + case BDISP_YUV_3B: + seq_puts(s, "YUV420P - "); + break; + default: + seq_puts(s, "ColorFormat ??? - "); + break; + } + + if ((val & BLT_TTY_ALPHA_R) && !s3) + seq_puts(s, "AlphaRange - "); + if ((val & BLT_S1TY_A1_SUBSET) && !s3) + seq_puts(s, "A1SubSet - "); + if ((val & BLT_TTY_MB) && !s1) + seq_puts(s, "MB - "); + if (val & BLT_TTY_HSO) + seq_puts(s, "HSO inverse - "); + if (val & BLT_TTY_VSO) + seq_puts(s, "VSO inverse - "); + if ((val & BLT_S1TY_CHROMA_EXT) && (s1 || s2)) + seq_puts(s, "ChromaExt - "); + if ((val & BLT_S3TY_BLANK_ACC) && s3) + seq_puts(s, "Blank Acc - "); + if ((val & BTL_S1TY_SUBBYTE) && !s3) + seq_puts(s, "SubByte - "); + if ((val & BLT_S1TY_RGB_EXP) && !s3) + seq_puts(s, "RGBExpand - "); + if ((val & BLT_TTY_BIG_END) && !s3) + seq_puts(s, "BigEndian - "); + +done: + seq_puts(s, "\n"); +} + +static void bdisp_dbg_dump_fctl(struct seq_file *s, u32 val) +{ + seq_printf(s, "FCTL\t0x%08X\t", val); + + if ((val & BLT_FCTL_Y_HV_SCALE) == BLT_FCTL_Y_HV_SCALE) + seq_puts(s, "Resize Luma - "); + else if ((val & BLT_FCTL_Y_HV_SCALE) == BLT_FCTL_Y_HV_SAMPLE) + seq_puts(s, "Sample Luma - "); + + if ((val & BLT_FCTL_HV_SCALE) == BLT_FCTL_HV_SCALE) + seq_puts(s, "Resize Chroma"); + else if ((val & BLT_FCTL_HV_SCALE) == BLT_FCTL_HV_SAMPLE) + seq_puts(s, "Sample Chroma"); + + seq_puts(s, "\n"); +} + +static void bdisp_dbg_dump_rsf(struct seq_file *s, u32 val, char *name) +{ + u32 inc; + + seq_printf(s, "%s\t0x%08X\t", name, val); + + if (!val) + goto done; + + inc = val & 0xFFFF; + seq_printf(s, "H: %d(6.10) / scale~%dx0.1 - ", inc, 1024 * 10 / inc); + + inc = val >> 16; + seq_printf(s, "V: %d(6.10) / scale~%dx0.1", inc, 1024 * 10 / inc); + +done: + seq_puts(s, "\n"); +} + +static void bdisp_dbg_dump_rzi(struct seq_file *s, u32 val, char *name) +{ + seq_printf(s, "%s\t0x%08X\t", name, val); + + if (!val) + goto done; + + seq_printf(s, "H: init=%d repeat=%d - ", val & 0x3FF, (val >> 12) & 7); + val >>= 16; + seq_printf(s, "V: init=%d repeat=%d", val & 0x3FF, (val >> 12) & 7); + +done: + seq_puts(s, "\n"); +} + +static void bdisp_dbg_dump_ivmx(struct seq_file *s, + u32 c0, u32 c1, u32 c2, u32 c3) +{ + seq_printf(s, "IVMX0\t0x%08X\n", c0); + seq_printf(s, "IVMX1\t0x%08X\n", c1); + seq_printf(s, "IVMX2\t0x%08X\n", c2); + seq_printf(s, "IVMX3\t0x%08X\t", c3); + + if (!c0 && !c1 && !c2 && !c3) { + seq_puts(s, "\n"); + return; + } + + if ((c0 == bdisp_rgb_to_yuv[0]) && + (c1 == bdisp_rgb_to_yuv[1]) && + (c2 == bdisp_rgb_to_yuv[2]) && + (c3 == bdisp_rgb_to_yuv[3])) { + seq_puts(s, "RGB to YUV\n"); + return; + } + + if ((c0 == bdisp_yuv_to_rgb[0]) && + (c1 == bdisp_yuv_to_rgb[1]) && + (c2 == bdisp_yuv_to_rgb[2]) && + (c3 == bdisp_yuv_to_rgb[3])) { + seq_puts(s, "YUV to RGB\n"); + return; + } + seq_puts(s, "Unknown conversion\n"); +} + +static int bdisp_dbg_last_nodes(struct seq_file *s, void *data) +{ + /* Not dumping all fields, focusing on significant ones */ + struct bdisp_dev *bdisp = s->private; + struct bdisp_node *node; + int i = 0; + + if (!bdisp->dbg.copy_node[0]) { + seq_puts(s, "No node built yet\n"); + return 0; + } + + do { + node = bdisp->dbg.copy_node[i]; + if (!node) + break; + seq_printf(s, "--------\nNode %d:\n", i); + seq_puts(s, "-- General --\n"); + seq_printf(s, "NIP\t0x%08X\n", node->nip); + seq_printf(s, "CIC\t0x%08X\n", node->cic); + bdisp_dbg_dump_ins(s, node->ins); + seq_printf(s, "ACK\t0x%08X\n", node->ack); + seq_puts(s, "-- Target --\n"); + seq_printf(s, "TBA\t0x%08X\n", node->tba); + bdisp_dbg_dump_tty(s, node->tty); + bdisp_dbg_dump_xy(s, node->txy, "TXY"); + bdisp_dbg_dump_sz(s, node->tsz, "TSZ"); + /* Color Fill not dumped */ + seq_puts(s, "-- Source 1 --\n"); + seq_printf(s, "S1BA\t0x%08X\n", node->s1ba); + bdisp_dbg_dump_sty(s, node->s1ty, node->s1ba, "S1TY"); + bdisp_dbg_dump_xy(s, node->s1xy, "S1XY"); + seq_puts(s, "-- Source 2 --\n"); + seq_printf(s, "S2BA\t0x%08X\n", node->s2ba); + bdisp_dbg_dump_sty(s, node->s2ty, node->s2ba, "S2TY"); + bdisp_dbg_dump_xy(s, node->s2xy, "S2XY"); + bdisp_dbg_dump_sz(s, node->s2sz, "S2SZ"); + seq_puts(s, "-- Source 3 --\n"); + seq_printf(s, "S3BA\t0x%08X\n", node->s3ba); + bdisp_dbg_dump_sty(s, node->s3ty, node->s3ba, "S3TY"); + bdisp_dbg_dump_xy(s, node->s3xy, "S3XY"); + bdisp_dbg_dump_sz(s, node->s3sz, "S3SZ"); + /* Clipping not dumped */ + /* CLUT not dumped */ + seq_puts(s, "-- Filter & Mask --\n"); + bdisp_dbg_dump_fctl(s, node->fctl); + /* PMK not dumped */ + seq_puts(s, "-- Chroma Filter --\n"); + bdisp_dbg_dump_rsf(s, node->rsf, "RSF"); + bdisp_dbg_dump_rzi(s, node->rzi, "RZI"); + seq_printf(s, "HFP\t0x%08X\n", node->hfp); + seq_printf(s, "VFP\t0x%08X\n", node->vfp); + seq_puts(s, "-- Luma Filter --\n"); + bdisp_dbg_dump_rsf(s, node->y_rsf, "Y_RSF"); + bdisp_dbg_dump_rzi(s, node->y_rzi, "Y_RZI"); + seq_printf(s, "Y_HFP\t0x%08X\n", node->y_hfp); + seq_printf(s, "Y_VFP\t0x%08X\n", node->y_vfp); + /* Flicker not dumped */ + /* Color key not dumped */ + /* Reserved not dumped */ + /* Static Address & User not dumped */ + seq_puts(s, "-- Input Versatile Matrix --\n"); + bdisp_dbg_dump_ivmx(s, node->ivmx0, node->ivmx1, + node->ivmx2, node->ivmx3); + /* Output Versatile Matrix not dumped */ + /* Pace not dumped */ + /* VC1R & DEI not dumped */ + /* Gradient Fill not dumped */ + } while ((++i < MAX_NB_NODE) && node->nip); + + return 0; +} + +static int bdisp_dbg_last_nodes_raw(struct seq_file *s, void *data) +{ + struct bdisp_dev *bdisp = s->private; + struct bdisp_node *node; + u32 *val; + int j, i = 0; + + if (!bdisp->dbg.copy_node[0]) { + seq_puts(s, "No node built yet\n"); + return 0; + } + + do { + node = bdisp->dbg.copy_node[i]; + if (!node) + break; + + seq_printf(s, "--------\nNode %d:\n", i); + val = (u32 *)node; + for (j = 0; j < sizeof(struct bdisp_node) / sizeof(u32); j++) + seq_printf(s, "0x%08X\n", *val++); + } while ((++i < MAX_NB_NODE) && node->nip); + + return 0; +} + +static const char *bdisp_fmt_to_str(struct bdisp_frame frame) +{ + switch (frame.fmt->pixelformat) { + case V4L2_PIX_FMT_YUV420: + return "YUV420P"; + case V4L2_PIX_FMT_NV12: + if (frame.field == V4L2_FIELD_INTERLACED) + return "NV12 interlaced"; + else + return "NV12"; + case V4L2_PIX_FMT_RGB565: + return "RGB16"; + case V4L2_PIX_FMT_XBGR32: + return "XRGB"; + case V4L2_PIX_FMT_ABGR32: + return "ARGB"; + default: + return "????"; + } +} + +static int bdisp_dbg_last_request(struct seq_file *s, void *data) +{ + struct bdisp_dev *bdisp = s->private; + struct bdisp_request *request = &bdisp->dbg.copy_request; + struct bdisp_frame src, dst; + + if (!request->nb_req) { + seq_puts(s, "No request\n"); + return 0; + } + + src = request->src; + dst = request->dst; + + seq_printf(s, "\nRequest #%d\n", request->nb_req); + + seq_printf(s, "Format: %s\t\t\t%s\n", + bdisp_fmt_to_str(src), bdisp_fmt_to_str(dst)); + seq_printf(s, "Crop area: %dx%d @ %d,%d ==>\t%dx%d @ %d,%d\n", + src.crop.width, src.crop.height, + src.crop.left, src.crop.top, + dst.crop.width, dst.crop.height, + dst.crop.left, dst.crop.top); + seq_printf(s, "Buff size: %dx%d\t\t%dx%d\n\n", + src.width, src.height, dst.width, dst.height); + + if (request->hflip) + seq_puts(s, "Horizontal flip\n\n"); + + if (request->vflip) + seq_puts(s, "Vertical flip\n\n"); + + return 0; +} + +#define DUMP(reg) seq_printf(s, #reg " \t0x%08X\n", readl(bdisp->regs + reg)) + +static int bdisp_dbg_regs(struct seq_file *s, void *data) +{ + struct bdisp_dev *bdisp = s->private; + int ret; + unsigned int i; + + ret = pm_runtime_get_sync(bdisp->dev); + if (ret < 0) { + seq_puts(s, "Cannot wake up IP\n"); + return 0; + } + + seq_printf(s, "Reg @ = 0x%p\n", bdisp->regs); + + seq_puts(s, "\nStatic:\n"); + DUMP(BLT_CTL); + DUMP(BLT_ITS); + DUMP(BLT_STA1); + DUMP(BLT_AQ1_CTL); + DUMP(BLT_AQ1_IP); + DUMP(BLT_AQ1_LNA); + DUMP(BLT_AQ1_STA); + DUMP(BLT_ITM0); + + seq_puts(s, "\nPlugs:\n"); + DUMP(BLT_PLUGS1_OP2); + DUMP(BLT_PLUGS1_CHZ); + DUMP(BLT_PLUGS1_MSZ); + DUMP(BLT_PLUGS1_PGZ); + DUMP(BLT_PLUGS2_OP2); + DUMP(BLT_PLUGS2_CHZ); + DUMP(BLT_PLUGS2_MSZ); + DUMP(BLT_PLUGS2_PGZ); + DUMP(BLT_PLUGS3_OP2); + DUMP(BLT_PLUGS3_CHZ); + DUMP(BLT_PLUGS3_MSZ); + DUMP(BLT_PLUGS3_PGZ); + DUMP(BLT_PLUGT_OP2); + DUMP(BLT_PLUGT_CHZ); + DUMP(BLT_PLUGT_MSZ); + DUMP(BLT_PLUGT_PGZ); + + seq_puts(s, "\nNode:\n"); + DUMP(BLT_NIP); + DUMP(BLT_CIC); + DUMP(BLT_INS); + DUMP(BLT_ACK); + DUMP(BLT_TBA); + DUMP(BLT_TTY); + DUMP(BLT_TXY); + DUMP(BLT_TSZ); + DUMP(BLT_S1BA); + DUMP(BLT_S1TY); + DUMP(BLT_S1XY); + DUMP(BLT_S2BA); + DUMP(BLT_S2TY); + DUMP(BLT_S2XY); + DUMP(BLT_S2SZ); + DUMP(BLT_S3BA); + DUMP(BLT_S3TY); + DUMP(BLT_S3XY); + DUMP(BLT_S3SZ); + DUMP(BLT_FCTL); + DUMP(BLT_RSF); + DUMP(BLT_RZI); + DUMP(BLT_HFP); + DUMP(BLT_VFP); + DUMP(BLT_Y_RSF); + DUMP(BLT_Y_RZI); + DUMP(BLT_Y_HFP); + DUMP(BLT_Y_VFP); + DUMP(BLT_IVMX0); + DUMP(BLT_IVMX1); + DUMP(BLT_IVMX2); + DUMP(BLT_IVMX3); + DUMP(BLT_OVMX0); + DUMP(BLT_OVMX1); + DUMP(BLT_OVMX2); + DUMP(BLT_OVMX3); + DUMP(BLT_DEI); + + seq_puts(s, "\nFilter:\n"); + for (i = 0; i < BLT_NB_H_COEF; i++) { + seq_printf(s, "BLT_HFC%d \t0x%08X\n", i, + readl(bdisp->regs + BLT_HFC_N + i * 4)); + } + for (i = 0; i < BLT_NB_V_COEF; i++) { + seq_printf(s, "BLT_VFC%d \t0x%08X\n", i, + readl(bdisp->regs + BLT_VFC_N + i * 4)); + } + + seq_puts(s, "\nLuma filter:\n"); + for (i = 0; i < BLT_NB_H_COEF; i++) { + seq_printf(s, "BLT_Y_HFC%d \t0x%08X\n", i, + readl(bdisp->regs + BLT_Y_HFC_N + i * 4)); + } + for (i = 0; i < BLT_NB_V_COEF; i++) { + seq_printf(s, "BLT_Y_VFC%d \t0x%08X\n", i, + readl(bdisp->regs + BLT_Y_VFC_N + i * 4)); + } + + pm_runtime_put(bdisp->dev); + + return 0; +} + +#define SECOND 1000000 + +static int bdisp_dbg_perf(struct seq_file *s, void *data) +{ + struct bdisp_dev *bdisp = s->private; + struct bdisp_request *request = &bdisp->dbg.copy_request; + s64 avg_time_us; + int avg_fps, min_fps, max_fps, last_fps; + + if (!request->nb_req) { + seq_puts(s, "No request\n"); + return 0; + } + + avg_time_us = div64_s64(bdisp->dbg.tot_duration, request->nb_req); + if (avg_time_us > SECOND) + avg_fps = 0; + else + avg_fps = SECOND / (s32)avg_time_us; + + if (bdisp->dbg.min_duration > SECOND) + min_fps = 0; + else + min_fps = SECOND / (s32)bdisp->dbg.min_duration; + + if (bdisp->dbg.max_duration > SECOND) + max_fps = 0; + else + max_fps = SECOND / (s32)bdisp->dbg.max_duration; + + if (bdisp->dbg.last_duration > SECOND) + last_fps = 0; + else + last_fps = SECOND / (s32)bdisp->dbg.last_duration; + + seq_printf(s, "HW processing (%d requests):\n", request->nb_req); + seq_printf(s, " Average: %5lld us (%3d fps)\n", + avg_time_us, avg_fps); + seq_printf(s, " Min-Max: %5lld us (%3d fps) - %5lld us (%3d fps)\n", + bdisp->dbg.min_duration, min_fps, + bdisp->dbg.max_duration, max_fps); + seq_printf(s, " Last: %5lld us (%3d fps)\n", + bdisp->dbg.last_duration, last_fps); + + return 0; +} + +#define bdisp_dbg_declare(name) \ + static int bdisp_dbg_##name##_open(struct inode *i, struct file *f) \ + { \ + return single_open(f, bdisp_dbg_##name, i->i_private); \ + } \ + static const struct file_operations bdisp_dbg_##name##_fops = { \ + .open = bdisp_dbg_##name##_open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ + } + +#define bdisp_dbg_create_entry(name) \ + debugfs_create_file(#name, S_IRUGO, bdisp->dbg.debugfs_entry, bdisp, \ + &bdisp_dbg_##name##_fops) + +bdisp_dbg_declare(regs); +bdisp_dbg_declare(last_nodes); +bdisp_dbg_declare(last_nodes_raw); +bdisp_dbg_declare(last_request); +bdisp_dbg_declare(perf); + +int bdisp_debugfs_create(struct bdisp_dev *bdisp) +{ + char dirname[16]; + + snprintf(dirname, sizeof(dirname), "%s%d", BDISP_NAME, bdisp->id); + bdisp->dbg.debugfs_entry = debugfs_create_dir(dirname, NULL); + if (!bdisp->dbg.debugfs_entry) + goto err; + + if (!bdisp_dbg_create_entry(regs)) + goto err; + + if (!bdisp_dbg_create_entry(last_nodes)) + goto err; + + if (!bdisp_dbg_create_entry(last_nodes_raw)) + goto err; + + if (!bdisp_dbg_create_entry(last_request)) + goto err; + + if (!bdisp_dbg_create_entry(perf)) + goto err; + + return 0; + +err: + bdisp_debugfs_remove(bdisp); + return 0; +} + +void bdisp_debugfs_remove(struct bdisp_dev *bdisp) +{ + debugfs_remove_recursive(bdisp->dbg.debugfs_entry); + bdisp->dbg.debugfs_entry = NULL; +} diff --git a/drivers/media/platform/sti/bdisp/bdisp-filter.h b/drivers/media/platform/sti/bdisp/bdisp-filter.h new file mode 100644 index 0000000..fc8c54f --- /dev/null +++ b/drivers/media/platform/sti/bdisp/bdisp-filter.h @@ -0,0 +1,346 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#define BDISP_HF_NB 64 +#define BDISP_VF_NB 40 + +/** + * struct bdisp_filter_h_spec - Horizontal filter specification + * + * @min: min scale factor for this filter (6.10 fixed point) + * @max: max scale factor for this filter (6.10 fixed point) + * coef: filter coefficients + */ +struct bdisp_filter_h_spec { + const u16 min; + const u16 max; + const u8 coef[BDISP_HF_NB]; +}; + +static const struct bdisp_filter_h_spec bdisp_h_spec[] = { + { + .min = 0, + .max = 921, + .coef = { + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x07, 0x3d, 0xfc, 0x01, 0x00, + 0x00, 0x01, 0xfd, 0x11, 0x36, 0xf9, 0x02, 0x00, + 0x00, 0x01, 0xfb, 0x1b, 0x2e, 0xf9, 0x02, 0x00, + 0x00, 0x01, 0xf9, 0x26, 0x26, 0xf9, 0x01, 0x00, + 0x00, 0x02, 0xf9, 0x30, 0x19, 0xfb, 0x01, 0x00, + 0x00, 0x02, 0xf9, 0x39, 0x0e, 0xfd, 0x01, 0x00, + 0x00, 0x01, 0xfc, 0x3e, 0x06, 0xff, 0x00, 0x00 + } + }, + { + .min = 921, + .max = 1024, + .coef = { + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0xff, 0x03, 0xfd, 0x08, 0x3e, 0xf9, 0x04, 0xfe, + 0xfd, 0x06, 0xf8, 0x13, 0x3b, 0xf4, 0x07, 0xfc, + 0xfb, 0x08, 0xf5, 0x1f, 0x34, 0xf1, 0x09, 0xfb, + 0xfb, 0x09, 0xf2, 0x2b, 0x2a, 0xf1, 0x09, 0xfb, + 0xfb, 0x09, 0xf2, 0x35, 0x1e, 0xf4, 0x08, 0xfb, + 0xfc, 0x07, 0xf5, 0x3c, 0x12, 0xf7, 0x06, 0xfd, + 0xfe, 0x04, 0xfa, 0x3f, 0x07, 0xfc, 0x03, 0xff + } + }, + { + .min = 1024, + .max = 1126, + .coef = { + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0xff, 0x03, 0xfd, 0x08, 0x3e, 0xf9, 0x04, 0xfe, + 0xfd, 0x06, 0xf8, 0x13, 0x3b, 0xf4, 0x07, 0xfc, + 0xfb, 0x08, 0xf5, 0x1f, 0x34, 0xf1, 0x09, 0xfb, + 0xfb, 0x09, 0xf2, 0x2b, 0x2a, 0xf1, 0x09, 0xfb, + 0xfb, 0x09, 0xf2, 0x35, 0x1e, 0xf4, 0x08, 0xfb, + 0xfc, 0x07, 0xf5, 0x3c, 0x12, 0xf7, 0x06, 0xfd, + 0xfe, 0x04, 0xfa, 0x3f, 0x07, 0xfc, 0x03, 0xff + } + }, + { + .min = 1126, + .max = 1228, + .coef = { + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0xff, 0x03, 0xfd, 0x08, 0x3e, 0xf9, 0x04, 0xfe, + 0xfd, 0x06, 0xf8, 0x13, 0x3b, 0xf4, 0x07, 0xfc, + 0xfb, 0x08, 0xf5, 0x1f, 0x34, 0xf1, 0x09, 0xfb, + 0xfb, 0x09, 0xf2, 0x2b, 0x2a, 0xf1, 0x09, 0xfb, + 0xfb, 0x09, 0xf2, 0x35, 0x1e, 0xf4, 0x08, 0xfb, + 0xfc, 0x07, 0xf5, 0x3c, 0x12, 0xf7, 0x06, 0xfd, + 0xfe, 0x04, 0xfa, 0x3f, 0x07, 0xfc, 0x03, 0xff + } + }, + { + .min = 1228, + .max = 1331, + .coef = { + 0xfd, 0x04, 0xfc, 0x05, 0x39, 0x05, 0xfc, 0x04, + 0xfc, 0x06, 0xf9, 0x0c, 0x39, 0xfe, 0x00, 0x02, + 0xfb, 0x08, 0xf6, 0x17, 0x35, 0xf9, 0x02, 0x00, + 0xfc, 0x08, 0xf4, 0x20, 0x30, 0xf4, 0x05, 0xff, + 0xfd, 0x07, 0xf4, 0x29, 0x28, 0xf3, 0x07, 0xfd, + 0xff, 0x05, 0xf5, 0x31, 0x1f, 0xf3, 0x08, 0xfc, + 0x00, 0x02, 0xf9, 0x38, 0x14, 0xf6, 0x08, 0xfb, + 0x02, 0x00, 0xff, 0x3a, 0x0b, 0xf8, 0x06, 0xfc + } + }, + { + .min = 1331, + .max = 1433, + .coef = { + 0xfc, 0x06, 0xf9, 0x09, 0x34, 0x09, 0xf9, 0x06, + 0xfd, 0x07, 0xf7, 0x10, 0x32, 0x02, 0xfc, 0x05, + 0xfe, 0x07, 0xf6, 0x17, 0x2f, 0xfc, 0xff, 0x04, + 0xff, 0x06, 0xf5, 0x20, 0x2a, 0xf9, 0x01, 0x02, + 0x00, 0x04, 0xf6, 0x27, 0x25, 0xf6, 0x04, 0x00, + 0x02, 0x01, 0xf9, 0x2d, 0x1d, 0xf5, 0x06, 0xff, + 0x04, 0xff, 0xfd, 0x31, 0x15, 0xf5, 0x07, 0xfe, + 0x05, 0xfc, 0x02, 0x35, 0x0d, 0xf7, 0x07, 0xfd + } + }, + { + .min = 1433, + .max = 1536, + .coef = { + 0xfe, 0x06, 0xf8, 0x0b, 0x30, 0x0b, 0xf8, 0x06, + 0xff, 0x06, 0xf7, 0x12, 0x2d, 0x05, 0xfa, 0x06, + 0x00, 0x04, 0xf6, 0x18, 0x2c, 0x00, 0xfc, 0x06, + 0x01, 0x02, 0xf7, 0x1f, 0x27, 0xfd, 0xff, 0x04, + 0x03, 0x00, 0xf9, 0x24, 0x24, 0xf9, 0x00, 0x03, + 0x04, 0xff, 0xfd, 0x29, 0x1d, 0xf7, 0x02, 0x01, + 0x06, 0xfc, 0x00, 0x2d, 0x17, 0xf6, 0x04, 0x00, + 0x06, 0xfa, 0x05, 0x30, 0x0f, 0xf7, 0x06, 0xff + } + }, + { + .min = 1536, + .max = 2048, + .coef = { + 0x05, 0xfd, 0xfb, 0x13, 0x25, 0x13, 0xfb, 0xfd, + 0x05, 0xfc, 0xfd, 0x17, 0x24, 0x0f, 0xf9, 0xff, + 0x04, 0xfa, 0xff, 0x1b, 0x24, 0x0b, 0xf9, 0x00, + 0x03, 0xf9, 0x01, 0x1f, 0x23, 0x08, 0xf8, 0x01, + 0x02, 0xf9, 0x04, 0x22, 0x20, 0x04, 0xf9, 0x02, + 0x01, 0xf8, 0x08, 0x25, 0x1d, 0x01, 0xf9, 0x03, + 0x00, 0xf9, 0x0c, 0x25, 0x1a, 0xfe, 0xfa, 0x04, + 0xff, 0xf9, 0x10, 0x26, 0x15, 0xfc, 0xfc, 0x05 + } + }, + { + .min = 2048, + .max = 3072, + .coef = { + 0xfc, 0xfd, 0x06, 0x13, 0x18, 0x13, 0x06, 0xfd, + 0xfc, 0xfe, 0x08, 0x15, 0x17, 0x12, 0x04, 0xfc, + 0xfb, 0xfe, 0x0a, 0x16, 0x18, 0x10, 0x03, 0xfc, + 0xfb, 0x00, 0x0b, 0x18, 0x17, 0x0f, 0x01, 0xfb, + 0xfb, 0x00, 0x0d, 0x19, 0x17, 0x0d, 0x00, 0xfb, + 0xfb, 0x01, 0x0f, 0x19, 0x16, 0x0b, 0x00, 0xfb, + 0xfc, 0x03, 0x11, 0x19, 0x15, 0x09, 0xfe, 0xfb, + 0xfc, 0x04, 0x12, 0x1a, 0x12, 0x08, 0xfe, 0xfc + } + }, + { + .min = 3072, + .max = 4096, + .coef = { + 0xfe, 0x02, 0x09, 0x0f, 0x0e, 0x0f, 0x09, 0x02, + 0xff, 0x02, 0x09, 0x0f, 0x10, 0x0e, 0x08, 0x01, + 0xff, 0x03, 0x0a, 0x10, 0x10, 0x0d, 0x07, 0x00, + 0x00, 0x04, 0x0b, 0x10, 0x0f, 0x0c, 0x06, 0x00, + 0x00, 0x05, 0x0c, 0x10, 0x0e, 0x0c, 0x05, 0x00, + 0x00, 0x06, 0x0c, 0x11, 0x0e, 0x0b, 0x04, 0x00, + 0x00, 0x07, 0x0d, 0x11, 0x0f, 0x0a, 0x03, 0xff, + 0x01, 0x08, 0x0e, 0x11, 0x0e, 0x09, 0x02, 0xff + } + }, + { + .min = 4096, + .max = 5120, + .coef = { + 0x00, 0x04, 0x09, 0x0c, 0x0e, 0x0c, 0x09, 0x04, + 0x01, 0x05, 0x09, 0x0c, 0x0d, 0x0c, 0x08, 0x04, + 0x01, 0x05, 0x0a, 0x0c, 0x0e, 0x0b, 0x08, 0x03, + 0x02, 0x06, 0x0a, 0x0d, 0x0c, 0x0b, 0x07, 0x03, + 0x02, 0x07, 0x0a, 0x0d, 0x0d, 0x0a, 0x07, 0x02, + 0x03, 0x07, 0x0b, 0x0d, 0x0c, 0x0a, 0x06, 0x02, + 0x03, 0x08, 0x0b, 0x0d, 0x0d, 0x0a, 0x05, 0x01, + 0x04, 0x08, 0x0c, 0x0d, 0x0c, 0x09, 0x05, 0x01 + } + }, + { + .min = 5120, + .max = 65535, + .coef = { + 0x03, 0x06, 0x09, 0x0b, 0x09, 0x0b, 0x09, 0x06, + 0x03, 0x06, 0x09, 0x0b, 0x0c, 0x0a, 0x08, 0x05, + 0x03, 0x06, 0x09, 0x0b, 0x0c, 0x0a, 0x08, 0x05, + 0x04, 0x07, 0x09, 0x0b, 0x0b, 0x0a, 0x08, 0x04, + 0x04, 0x07, 0x0a, 0x0b, 0x0b, 0x0a, 0x07, 0x04, + 0x04, 0x08, 0x0a, 0x0b, 0x0b, 0x09, 0x07, 0x04, + 0x05, 0x08, 0x0a, 0x0b, 0x0c, 0x09, 0x06, 0x03, + 0x05, 0x08, 0x0a, 0x0b, 0x0c, 0x09, 0x06, 0x03 + } + } +}; + +/** + * struct bdisp_filter_v_spec - Vertical filter specification + * + * @min: min scale factor for this filter (6.10 fixed point) + * @max: max scale factor for this filter (6.10 fixed point) + * coef: filter coefficients + */ +struct bdisp_filter_v_spec { + const u16 min; + const u16 max; + const u8 coef[BDISP_VF_NB]; +}; + +static const struct bdisp_filter_v_spec bdisp_v_spec[] = { + { + .min = 0, + .max = 1024, + .coef = { + 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x06, 0x3d, 0xfd, 0x00, + 0xfe, 0x0f, 0x38, 0xfb, 0x00, + 0xfd, 0x19, 0x2f, 0xfb, 0x00, + 0xfc, 0x24, 0x24, 0xfc, 0x00, + 0xfb, 0x2f, 0x19, 0xfd, 0x00, + 0xfb, 0x38, 0x0f, 0xfe, 0x00, + 0xfd, 0x3d, 0x06, 0x00, 0x00 + } + }, + { + .min = 1024, + .max = 1331, + .coef = { + 0xfc, 0x05, 0x3e, 0x05, 0xfc, + 0xf8, 0x0e, 0x3b, 0xff, 0x00, + 0xf5, 0x18, 0x38, 0xf9, 0x02, + 0xf4, 0x21, 0x31, 0xf5, 0x05, + 0xf4, 0x2a, 0x27, 0xf4, 0x07, + 0xf6, 0x30, 0x1e, 0xf4, 0x08, + 0xf9, 0x35, 0x15, 0xf6, 0x07, + 0xff, 0x37, 0x0b, 0xf9, 0x06 + } + }, + { + .min = 1331, + .max = 1433, + .coef = { + 0xf8, 0x0a, 0x3c, 0x0a, 0xf8, + 0xf6, 0x12, 0x3b, 0x02, 0xfb, + 0xf4, 0x1b, 0x35, 0xfd, 0xff, + 0xf4, 0x23, 0x30, 0xf8, 0x01, + 0xf6, 0x29, 0x27, 0xf6, 0x04, + 0xf9, 0x2e, 0x1e, 0xf5, 0x06, + 0xfd, 0x31, 0x16, 0xf6, 0x06, + 0x02, 0x32, 0x0d, 0xf8, 0x07 + } + }, + { + .min = 1433, + .max = 1536, + .coef = { + 0xf6, 0x0e, 0x38, 0x0e, 0xf6, + 0xf5, 0x15, 0x38, 0x06, 0xf8, + 0xf5, 0x1d, 0x33, 0x00, 0xfb, + 0xf6, 0x23, 0x2d, 0xfc, 0xfe, + 0xf9, 0x28, 0x26, 0xf9, 0x00, + 0xfc, 0x2c, 0x1e, 0xf7, 0x03, + 0x00, 0x2e, 0x18, 0xf6, 0x04, + 0x05, 0x2e, 0x11, 0xf7, 0x05 + } + }, + { + .min = 1536, + .max = 2048, + .coef = { + 0xfb, 0x13, 0x24, 0x13, 0xfb, + 0xfd, 0x17, 0x23, 0x0f, 0xfa, + 0xff, 0x1a, 0x23, 0x0b, 0xf9, + 0x01, 0x1d, 0x22, 0x07, 0xf9, + 0x04, 0x20, 0x1f, 0x04, 0xf9, + 0x07, 0x22, 0x1c, 0x01, 0xfa, + 0x0b, 0x24, 0x17, 0xff, 0xfb, + 0x0f, 0x24, 0x14, 0xfd, 0xfc + } + }, + { + .min = 2048, + .max = 3072, + .coef = { + 0x05, 0x10, 0x16, 0x10, 0x05, + 0x06, 0x11, 0x16, 0x0f, 0x04, + 0x08, 0x13, 0x15, 0x0e, 0x02, + 0x09, 0x14, 0x16, 0x0c, 0x01, + 0x0b, 0x15, 0x15, 0x0b, 0x00, + 0x0d, 0x16, 0x13, 0x0a, 0x00, + 0x0f, 0x17, 0x13, 0x08, 0xff, + 0x11, 0x18, 0x12, 0x07, 0xfe + } + }, + { + .min = 3072, + .max = 4096, + .coef = { + 0x09, 0x0f, 0x10, 0x0f, 0x09, + 0x09, 0x0f, 0x12, 0x0e, 0x08, + 0x0a, 0x10, 0x11, 0x0e, 0x07, + 0x0b, 0x11, 0x11, 0x0d, 0x06, + 0x0c, 0x11, 0x12, 0x0c, 0x05, + 0x0d, 0x12, 0x11, 0x0c, 0x04, + 0x0e, 0x12, 0x11, 0x0b, 0x04, + 0x0f, 0x13, 0x11, 0x0a, 0x03 + } + }, + { + .min = 4096, + .max = 5120, + .coef = { + 0x0a, 0x0e, 0x10, 0x0e, 0x0a, + 0x0b, 0x0e, 0x0f, 0x0e, 0x0a, + 0x0b, 0x0f, 0x10, 0x0d, 0x09, + 0x0c, 0x0f, 0x10, 0x0d, 0x08, + 0x0d, 0x0f, 0x0f, 0x0d, 0x08, + 0x0d, 0x10, 0x10, 0x0c, 0x07, + 0x0e, 0x10, 0x0f, 0x0c, 0x07, + 0x0f, 0x10, 0x10, 0x0b, 0x06 + } + }, + { + .min = 5120, + .max = 65535, + .coef = { + 0x0b, 0x0e, 0x0e, 0x0e, 0x0b, + 0x0b, 0x0e, 0x0f, 0x0d, 0x0b, + 0x0c, 0x0e, 0x0f, 0x0d, 0x0a, + 0x0c, 0x0e, 0x0f, 0x0d, 0x0a, + 0x0d, 0x0f, 0x0e, 0x0d, 0x09, + 0x0d, 0x0f, 0x0f, 0x0c, 0x09, + 0x0e, 0x0f, 0x0e, 0x0c, 0x09, + 0x0e, 0x0f, 0x0f, 0x0c, 0x08 + } + } +}; + +#define NB_H_FILTER ARRAY_SIZE(bdisp_h_spec) +#define NB_V_FILTER ARRAY_SIZE(bdisp_v_spec) + +/* RGB YUV 601 standard conversion */ +static const u32 bdisp_rgb_to_yuv[] = { + 0x0e1e8bee, 0x08420419, 0xfb5ed471, 0x08004080, +}; + +static const u32 bdisp_yuv_to_rgb[] = { + 0x3324a800, 0xe604ab9c, 0x0004a957, 0x32121eeb, +}; diff --git a/drivers/media/platform/sti/bdisp/bdisp-hw.c b/drivers/media/platform/sti/bdisp/bdisp-hw.c new file mode 100644 index 0000000..465828e --- /dev/null +++ b/drivers/media/platform/sti/bdisp/bdisp-hw.c @@ -0,0 +1,823 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include <linux/delay.h> + +#include "bdisp.h" +#include "bdisp-filter.h" +#include "bdisp-reg.h" + +/* Max width of the source frame in a single node */ +#define MAX_SRC_WIDTH 2048 + +/* Reset & boot poll config */ +#define POLL_RST_MAX 50 +#define POLL_RST_DELAY_MS 20 + +enum bdisp_target_plan { + BDISP_RGB, + BDISP_Y, + BDISP_CBCR +}; + +struct bdisp_op_cfg { + bool cconv; /* RGB - YUV conversion */ + bool hflip; /* Horizontal flip */ + bool vflip; /* Vertical flip */ + bool wide; /* Wide (>MAX_SRC_WIDTH) */ + bool scale; /* Scale */ + u16 h_inc; /* Horizontal increment in 6.10 format */ + u16 v_inc; /* Vertical increment in 6.10 format */ + bool src_interlaced; /* is the src an interlaced buffer */ + u8 src_nbp; /* nb of planes of the src */ + bool src_yuv; /* is the src a YUV color format */ + bool src_420; /* is the src 4:2:0 chroma subsampled */ + u8 dst_nbp; /* nb of planes of the dst */ + bool dst_yuv; /* is the dst a YUV color format */ + bool dst_420; /* is the dst 4:2:0 chroma subsampled */ +}; + +struct bdisp_filter_addr { + u16 min; /* Filter min scale factor (6.10 fixed point) */ + u16 max; /* Filter max scale factor (6.10 fixed point) */ + void *virt; /* Virtual address for filter table */ + dma_addr_t paddr; /* Physical address for filter table */ +}; + +static struct bdisp_filter_addr bdisp_h_filter[NB_H_FILTER]; +static struct bdisp_filter_addr bdisp_v_filter[NB_V_FILTER]; + +/** + * bdisp_hw_reset + * @bdisp: bdisp entity + * + * Resets HW + * + * RETURNS: + * 0 on success. + */ +int bdisp_hw_reset(struct bdisp_dev *bdisp) +{ + unsigned int i; + + dev_dbg(bdisp->dev, "%s\n", __func__); + + /* Mask Interrupt */ + writel(0, bdisp->regs + BLT_ITM0); + + /* Reset */ + writel(readl(bdisp->regs + BLT_CTL) | BLT_CTL_RESET, + bdisp->regs + BLT_CTL); + writel(0, bdisp->regs + BLT_CTL); + + /* Wait for reset done */ + for (i = 0; i < POLL_RST_MAX; i++) { + if (readl(bdisp->regs + BLT_STA1) & BLT_STA1_IDLE) + break; + msleep(POLL_RST_DELAY_MS); + } + if (i == POLL_RST_MAX) + dev_err(bdisp->dev, "Reset timeout\n"); + + return (i == POLL_RST_MAX) ? -EAGAIN : 0; +} + +/** + * bdisp_hw_get_and_clear_irq + * @bdisp: bdisp entity + * + * Read then reset interrupt status + * + * RETURNS: + * 0 if expected interrupt was raised. + */ +int bdisp_hw_get_and_clear_irq(struct bdisp_dev *bdisp) +{ + u32 its; + + its = readl(bdisp->regs + BLT_ITS); + + /* Check for the only expected IT: LastNode of AQ1 */ + if (!(its & BLT_ITS_AQ1_LNA)) { + dev_dbg(bdisp->dev, "Unexpected IT status: 0x%08X\n", its); + writel(its, bdisp->regs + BLT_ITS); + return -1; + } + + /* Clear and mask */ + writel(its, bdisp->regs + BLT_ITS); + writel(0, bdisp->regs + BLT_ITM0); + + return 0; +} + +/** + * bdisp_hw_free_nodes + * @ctx: bdisp context + * + * Free node memory + * + * RETURNS: + * None + */ +void bdisp_hw_free_nodes(struct bdisp_ctx *ctx) +{ + if (ctx && ctx->node[0]) { + DEFINE_DMA_ATTRS(attrs); + + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); + dma_free_attrs(ctx->bdisp_dev->dev, + sizeof(struct bdisp_node) * MAX_NB_NODE, + ctx->node[0], ctx->node_paddr[0], &attrs); + } +} + +/** + * bdisp_hw_alloc_nodes + * @ctx: bdisp context + * + * Allocate dma memory for nodes + * + * RETURNS: + * 0 on success + */ +int bdisp_hw_alloc_nodes(struct bdisp_ctx *ctx) +{ + struct device *dev = ctx->bdisp_dev->dev; + unsigned int i, node_size = sizeof(struct bdisp_node); + void *base; + dma_addr_t paddr; + DEFINE_DMA_ATTRS(attrs); + + /* Allocate all the nodes within a single memory page */ + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); + base = dma_alloc_attrs(dev, node_size * MAX_NB_NODE, &paddr, + GFP_KERNEL | GFP_DMA, &attrs); + if (!base) { + dev_err(dev, "%s no mem\n", __func__); + return -ENOMEM; + } + + memset(base, 0, node_size * MAX_NB_NODE); + + for (i = 0; i < MAX_NB_NODE; i++) { + ctx->node[i] = base; + ctx->node_paddr[i] = paddr; + dev_dbg(dev, "node[%d]=0x%p (paddr=%pad)\n", i, ctx->node[i], + &paddr); + base += node_size; + paddr += node_size; + } + + return 0; +} + +/** + * bdisp_hw_free_filters + * @dev: device + * + * Free filters memory + * + * RETURNS: + * None + */ +void bdisp_hw_free_filters(struct device *dev) +{ + int size = (BDISP_HF_NB * NB_H_FILTER) + (BDISP_VF_NB * NB_V_FILTER); + + if (bdisp_h_filter[0].virt) { + DEFINE_DMA_ATTRS(attrs); + + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); + dma_free_attrs(dev, size, bdisp_h_filter[0].virt, + bdisp_h_filter[0].paddr, &attrs); + } +} + +/** + * bdisp_hw_alloc_filters + * @dev: device + * + * Allocate dma memory for filters + * + * RETURNS: + * 0 on success + */ +int bdisp_hw_alloc_filters(struct device *dev) +{ + unsigned int i, size; + void *base; + dma_addr_t paddr; + DEFINE_DMA_ATTRS(attrs); + + /* Allocate all the filters within a single memory page */ + size = (BDISP_HF_NB * NB_H_FILTER) + (BDISP_VF_NB * NB_V_FILTER); + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); + base = dma_alloc_attrs(dev, size, &paddr, GFP_KERNEL | GFP_DMA, &attrs); + if (!base) + return -ENOMEM; + + /* Setup filter addresses */ + for (i = 0; i < NB_H_FILTER; i++) { + bdisp_h_filter[i].min = bdisp_h_spec[i].min; + bdisp_h_filter[i].max = bdisp_h_spec[i].max; + memcpy(base, bdisp_h_spec[i].coef, BDISP_HF_NB); + bdisp_h_filter[i].virt = base; + bdisp_h_filter[i].paddr = paddr; + base += BDISP_HF_NB; + paddr += BDISP_HF_NB; + } + + for (i = 0; i < NB_V_FILTER; i++) { + bdisp_v_filter[i].min = bdisp_v_spec[i].min; + bdisp_v_filter[i].max = bdisp_v_spec[i].max; + memcpy(base, bdisp_v_spec[i].coef, BDISP_VF_NB); + bdisp_v_filter[i].virt = base; + bdisp_v_filter[i].paddr = paddr; + base += BDISP_VF_NB; + paddr += BDISP_VF_NB; + } + + return 0; +} + +/** + * bdisp_hw_get_hf_addr + * @inc: resize increment + * + * Find the horizontal filter table that fits the resize increment + * + * RETURNS: + * table physical address + */ +static dma_addr_t bdisp_hw_get_hf_addr(u16 inc) +{ + unsigned int i; + + for (i = NB_H_FILTER - 1; i > 0; i--) + if ((bdisp_h_filter[i].min < inc) && + (inc <= bdisp_h_filter[i].max)) + break; + + return bdisp_h_filter[i].paddr; +} + +/** + * bdisp_hw_get_vf_addr + * @inc: resize increment + * + * Find the vertical filter table that fits the resize increment + * + * RETURNS: + * table physical address + */ +static dma_addr_t bdisp_hw_get_vf_addr(u16 inc) +{ + unsigned int i; + + for (i = NB_V_FILTER - 1; i > 0; i--) + if ((bdisp_v_filter[i].min < inc) && + (inc <= bdisp_v_filter[i].max)) + break; + + return bdisp_v_filter[i].paddr; +} + +/** + * bdisp_hw_get_inc + * @from: input size + * @to: output size + * @inc: resize increment in 6.10 format + * + * Computes the increment (inverse of scale) in 6.10 format + * + * RETURNS: + * 0 on success + */ +static int bdisp_hw_get_inc(u32 from, u32 to, u16 *inc) +{ + u32 tmp; + + if (!to) + return -EINVAL; + + if (to == from) { + *inc = 1 << 10; + return 0; + } + + tmp = (from << 10) / to; + if ((tmp > 0xFFFF) || (!tmp)) + /* overflow (downscale x 63) or too small (upscale x 1024) */ + return -EINVAL; + + *inc = (u16)tmp; + + return 0; +} + +/** + * bdisp_hw_get_hv_inc + * @ctx: device context + * @h_inc: horizontal increment + * @v_inc: vertical increment + * + * Computes the horizontal & vertical increments (inverse of scale) + * + * RETURNS: + * 0 on success + */ +static int bdisp_hw_get_hv_inc(struct bdisp_ctx *ctx, u16 *h_inc, u16 *v_inc) +{ + u32 src_w, src_h, dst_w, dst_h; + + src_w = ctx->src.crop.width; + src_h = ctx->src.crop.height; + dst_w = ctx->dst.width; + dst_h = ctx->dst.height; + + if (bdisp_hw_get_inc(src_w, dst_w, h_inc) || + bdisp_hw_get_inc(src_h, dst_h, v_inc)) { + dev_err(ctx->bdisp_dev->dev, + "scale factors failed (%dx%d)->(%dx%d)\n", + src_w, src_h, dst_w, dst_h); + return -EINVAL; + } + + return 0; +} + +/** + * bdisp_hw_get_op_cfg + * @ctx: device context + * @c: operation configuration + * + * Check which blitter operations are expected and sets the scaling increments + * + * RETURNS: + * 0 on success + */ +static int bdisp_hw_get_op_cfg(struct bdisp_ctx *ctx, struct bdisp_op_cfg *c) +{ + struct device *dev = ctx->bdisp_dev->dev; + struct bdisp_frame *src = &ctx->src; + struct bdisp_frame *dst = &ctx->dst; + + if (src->width > MAX_SRC_WIDTH * MAX_VERTICAL_STRIDES) { + dev_err(dev, "Image width out of HW caps\n"); + return -EINVAL; + } + + c->wide = src->width > MAX_SRC_WIDTH; + + c->hflip = ctx->hflip; + c->vflip = ctx->vflip; + + c->src_interlaced = (src->field == V4L2_FIELD_INTERLACED); + + c->src_nbp = src->fmt->nb_planes; + c->src_yuv = (src->fmt->pixelformat == V4L2_PIX_FMT_NV12) || + (src->fmt->pixelformat == V4L2_PIX_FMT_YUV420); + c->src_420 = c->src_yuv; + + c->dst_nbp = dst->fmt->nb_planes; + c->dst_yuv = (dst->fmt->pixelformat == V4L2_PIX_FMT_NV12) || + (dst->fmt->pixelformat == V4L2_PIX_FMT_YUV420); + c->dst_420 = c->dst_yuv; + + c->cconv = (c->src_yuv != c->dst_yuv); + + if (bdisp_hw_get_hv_inc(ctx, &c->h_inc, &c->v_inc)) { + dev_err(dev, "Scale factor out of HW caps\n"); + return -EINVAL; + } + + /* Deinterlacing adjustment : stretch a field to a frame */ + if (c->src_interlaced) + c->v_inc /= 2; + + if ((c->h_inc != (1 << 10)) || (c->v_inc != (1 << 10))) + c->scale = true; + else + c->scale = false; + + return 0; +} + +/** + * bdisp_hw_color_format + * @pixelformat: v4l2 pixel format + * + * v4l2 to bdisp pixel format convert + * + * RETURNS: + * bdisp pixel format + */ +static u32 bdisp_hw_color_format(u32 pixelformat) +{ + u32 ret; + + switch (pixelformat) { + case V4L2_PIX_FMT_YUV420: + ret = (BDISP_YUV_3B << BLT_TTY_COL_SHIFT); + break; + case V4L2_PIX_FMT_NV12: + ret = (BDISP_NV12 << BLT_TTY_COL_SHIFT) | BLT_TTY_BIG_END; + break; + case V4L2_PIX_FMT_RGB565: + ret = (BDISP_RGB565 << BLT_TTY_COL_SHIFT); + break; + case V4L2_PIX_FMT_XBGR32: /* This V4L format actually refers to xRGB */ + ret = (BDISP_XRGB8888 << BLT_TTY_COL_SHIFT); + break; + case V4L2_PIX_FMT_RGB24: /* RGB888 format */ + ret = (BDISP_RGB888 << BLT_TTY_COL_SHIFT) | BLT_TTY_BIG_END; + break; + case V4L2_PIX_FMT_ABGR32: /* This V4L format actually refers to ARGB */ + + default: + ret = (BDISP_ARGB8888 << BLT_TTY_COL_SHIFT) | BLT_TTY_ALPHA_R; + break; + } + + return ret; +} + +/** + * bdisp_hw_build_node + * @ctx: device context + * @cfg: operation configuration + * @node: node to be set + * @t_plan: whether the node refers to a RGB/Y or a CbCr plane + * @src_x_offset: x offset in the source image + * + * Build a node + * + * RETURNS: + * None + */ +static void bdisp_hw_build_node(struct bdisp_ctx *ctx, + struct bdisp_op_cfg *cfg, + struct bdisp_node *node, + enum bdisp_target_plan t_plan, int src_x_offset) +{ + struct bdisp_frame *src = &ctx->src; + struct bdisp_frame *dst = &ctx->dst; + u16 h_inc, v_inc, yh_inc, yv_inc; + struct v4l2_rect src_rect = src->crop; + struct v4l2_rect dst_rect = dst->crop; + int dst_x_offset; + s32 dst_width = dst->crop.width; + u32 src_fmt, dst_fmt; + const u32 *ivmx; + + dev_dbg(ctx->bdisp_dev->dev, "%s\n", __func__); + + memset(node, 0, sizeof(*node)); + + /* Adjust src and dst areas wrt src_x_offset */ + src_rect.left += src_x_offset; + src_rect.width -= src_x_offset; + src_rect.width = min_t(__s32, MAX_SRC_WIDTH, src_rect.width); + + dst_x_offset = (src_x_offset * dst->width) / ctx->src.crop.width; + dst_rect.left += dst_x_offset; + dst_rect.width = (src_rect.width * dst->width) / ctx->src.crop.width; + + /* General */ + src_fmt = src->fmt->pixelformat; + dst_fmt = dst->fmt->pixelformat; + + node->nip = 0; + node->cic = BLT_CIC_ALL_GRP; + node->ack = BLT_ACK_BYPASS_S2S3; + + switch (cfg->src_nbp) { + case 1: + /* Src2 = RGB / Src1 = Src3 = off */ + node->ins = BLT_INS_S1_OFF | BLT_INS_S2_MEM | BLT_INS_S3_OFF; + break; + case 2: + /* Src3 = Y + * Src2 = CbCr or ColorFill if writing the Y plane + * Src1 = off */ + node->ins = BLT_INS_S1_OFF | BLT_INS_S3_MEM; + if (t_plan == BDISP_Y) + node->ins |= BLT_INS_S2_CF; + else + node->ins |= BLT_INS_S2_MEM; + break; + case 3: + default: + /* Src3 = Y + * Src2 = Cb or ColorFill if writing the Y plane + * Src1 = Cr or ColorFill if writing the Y plane */ + node->ins = BLT_INS_S3_MEM; + if (t_plan == BDISP_Y) + node->ins |= BLT_INS_S2_CF | BLT_INS_S1_CF; + else + node->ins |= BLT_INS_S2_MEM | BLT_INS_S1_MEM; + break; + } + + /* Color convert */ + node->ins |= cfg->cconv ? BLT_INS_IVMX : 0; + /* Scale needed if scaling OR 4:2:0 up/downsampling */ + node->ins |= (cfg->scale || cfg->src_420 || cfg->dst_420) ? + BLT_INS_SCALE : 0; + + /* Target */ + node->tba = (t_plan == BDISP_CBCR) ? dst->paddr[1] : dst->paddr[0]; + + node->tty = dst->bytesperline; + node->tty |= bdisp_hw_color_format(dst_fmt); + node->tty |= BLT_TTY_DITHER; + node->tty |= (t_plan == BDISP_CBCR) ? BLT_TTY_CHROMA : 0; + node->tty |= cfg->hflip ? BLT_TTY_HSO : 0; + node->tty |= cfg->vflip ? BLT_TTY_VSO : 0; + + if (cfg->dst_420 && (t_plan == BDISP_CBCR)) { + /* 420 chroma downsampling */ + dst_rect.height /= 2; + dst_rect.width /= 2; + dst_rect.left /= 2; + dst_rect.top /= 2; + dst_x_offset /= 2; + dst_width /= 2; + } + + node->txy = cfg->vflip ? (dst_rect.height - 1) : dst_rect.top; + node->txy <<= 16; + node->txy |= cfg->hflip ? (dst_width - dst_x_offset - 1) : + dst_rect.left; + + node->tsz = dst_rect.height << 16 | dst_rect.width; + + if (cfg->src_interlaced) { + /* handle only the top field which is half height of a frame */ + src_rect.top /= 2; + src_rect.height /= 2; + } + + if (cfg->src_nbp == 1) { + /* Src 2 : RGB */ + node->s2ba = src->paddr[0]; + + node->s2ty = src->bytesperline; + if (cfg->src_interlaced) + node->s2ty *= 2; + + node->s2ty |= bdisp_hw_color_format(src_fmt); + + node->s2xy = src_rect.top << 16 | src_rect.left; + node->s2sz = src_rect.height << 16 | src_rect.width; + } else { + /* Src 2 : Cb or CbCr */ + if (cfg->src_420) { + /* 420 chroma upsampling */ + src_rect.top /= 2; + src_rect.left /= 2; + src_rect.width /= 2; + src_rect.height /= 2; + } + + node->s2ba = src->paddr[1]; + + node->s2ty = src->bytesperline; + if (cfg->src_nbp == 3) + node->s2ty /= 2; + if (cfg->src_interlaced) + node->s2ty *= 2; + + node->s2ty |= bdisp_hw_color_format(src_fmt); + + node->s2xy = src_rect.top << 16 | src_rect.left; + node->s2sz = src_rect.height << 16 | src_rect.width; + + if (cfg->src_nbp == 3) { + /* Src 1 : Cr */ + node->s1ba = src->paddr[2]; + + node->s1ty = node->s2ty; + node->s1xy = node->s2xy; + } + + /* Src 3 : Y */ + node->s3ba = src->paddr[0]; + + node->s3ty = src->bytesperline; + if (cfg->src_interlaced) + node->s3ty *= 2; + node->s3ty |= bdisp_hw_color_format(src_fmt); + + if ((t_plan != BDISP_CBCR) && cfg->src_420) { + /* No chroma upsampling for output RGB / Y plane */ + node->s3xy = node->s2xy * 2; + node->s3sz = node->s2sz * 2; + } else { + /* No need to read Y (Src3) when writing Chroma */ + node->s3ty |= BLT_S3TY_BLANK_ACC; + node->s3xy = node->s2xy; + node->s3sz = node->s2sz; + } + } + + /* Resize (scale OR 4:2:0: chroma up/downsampling) */ + if (node->ins & BLT_INS_SCALE) { + /* no need to compute Y when writing CbCr from RGB input */ + bool skip_y = (t_plan == BDISP_CBCR) && !cfg->src_yuv; + + /* FCTL */ + if (cfg->scale) { + node->fctl = BLT_FCTL_HV_SCALE; + if (!skip_y) + node->fctl |= BLT_FCTL_Y_HV_SCALE; + } else { + node->fctl = BLT_FCTL_HV_SAMPLE; + if (!skip_y) + node->fctl |= BLT_FCTL_Y_HV_SAMPLE; + } + + /* RSF - Chroma may need to be up/downsampled */ + h_inc = cfg->h_inc; + v_inc = cfg->v_inc; + if (!cfg->src_420 && cfg->dst_420 && (t_plan == BDISP_CBCR)) { + /* RGB to 4:2:0 for Chroma: downsample */ + h_inc *= 2; + v_inc *= 2; + } else if (cfg->src_420 && !cfg->dst_420) { + /* 4:2:0: to RGB: upsample*/ + h_inc /= 2; + v_inc /= 2; + } + node->rsf = v_inc << 16 | h_inc; + + /* RZI */ + node->rzi = BLT_RZI_DEFAULT; + + /* Filter table physical addr */ + node->hfp = bdisp_hw_get_hf_addr(h_inc); + node->vfp = bdisp_hw_get_vf_addr(v_inc); + + /* Y version */ + if (!skip_y) { + yh_inc = cfg->h_inc; + yv_inc = cfg->v_inc; + + node->y_rsf = yv_inc << 16 | yh_inc; + node->y_rzi = BLT_RZI_DEFAULT; + node->y_hfp = bdisp_hw_get_hf_addr(yh_inc); + node->y_vfp = bdisp_hw_get_vf_addr(yv_inc); + } + } + + /* Versatile matrix for RGB / YUV conversion */ + if (cfg->cconv) { + ivmx = cfg->src_yuv ? bdisp_yuv_to_rgb : bdisp_rgb_to_yuv; + + node->ivmx0 = ivmx[0]; + node->ivmx1 = ivmx[1]; + node->ivmx2 = ivmx[2]; + node->ivmx3 = ivmx[3]; + } +} + +/** + * bdisp_hw_build_all_nodes + * @ctx: device context + * + * Build all the nodes for the blitter operation + * + * RETURNS: + * 0 on success + */ +static int bdisp_hw_build_all_nodes(struct bdisp_ctx *ctx) +{ + struct bdisp_op_cfg cfg; + unsigned int i, nid = 0; + int src_x_offset = 0; + + for (i = 0; i < MAX_NB_NODE; i++) + if (!ctx->node[i]) { + dev_err(ctx->bdisp_dev->dev, "node %d is null\n", i); + return -EINVAL; + } + + /* Get configuration (scale, flip, ...) */ + if (bdisp_hw_get_op_cfg(ctx, &cfg)) + return -EINVAL; + + /* Split source in vertical strides (HW constraint) */ + for (i = 0; i < MAX_VERTICAL_STRIDES; i++) { + /* Build RGB/Y node and link it to the previous node */ + bdisp_hw_build_node(ctx, &cfg, ctx->node[nid], + cfg.dst_nbp == 1 ? BDISP_RGB : BDISP_Y, + src_x_offset); + if (nid) + ctx->node[nid - 1]->nip = ctx->node_paddr[nid]; + nid++; + + /* Build additional Cb(Cr) node, link it to the previous one */ + if (cfg.dst_nbp > 1) { + bdisp_hw_build_node(ctx, &cfg, ctx->node[nid], + BDISP_CBCR, src_x_offset); + ctx->node[nid - 1]->nip = ctx->node_paddr[nid]; + nid++; + } + + /* Next stride until full width covered */ + src_x_offset += MAX_SRC_WIDTH; + if (src_x_offset >= ctx->src.crop.width) + break; + } + + /* Mark last node as the last */ + ctx->node[nid - 1]->nip = 0; + + return 0; +} + +/** + * bdisp_hw_save_request + * @ctx: device context + * + * Save a copy of the request and of the built nodes + * + * RETURNS: + * None + */ +static void bdisp_hw_save_request(struct bdisp_ctx *ctx) +{ + struct bdisp_node **copy_node = ctx->bdisp_dev->dbg.copy_node; + struct bdisp_request *request = &ctx->bdisp_dev->dbg.copy_request; + struct bdisp_node **node = ctx->node; + int i; + + /* Request copy */ + request->src = ctx->src; + request->dst = ctx->dst; + request->hflip = ctx->hflip; + request->vflip = ctx->vflip; + request->nb_req++; + + /* Nodes copy */ + for (i = 0; i < MAX_NB_NODE; i++) { + /* Allocate memory if not done yet */ + if (!copy_node[i]) { + copy_node[i] = devm_kzalloc(ctx->bdisp_dev->dev, + sizeof(*copy_node), + GFP_KERNEL); + if (!copy_node[i]) + return; + } + copy_node[i] = node[i]; + } +} + +/** + * bdisp_hw_update + * @ctx: device context + * + * Send the request to the HW + * + * RETURNS: + * 0 on success + */ +int bdisp_hw_update(struct bdisp_ctx *ctx) +{ + int ret; + struct bdisp_dev *bdisp = ctx->bdisp_dev; + struct device *dev = bdisp->dev; + unsigned int node_id; + + dev_dbg(dev, "%s\n", __func__); + + /* build nodes */ + ret = bdisp_hw_build_all_nodes(ctx); + if (ret) { + dev_err(dev, "cannot build nodes (%d)\n", ret); + return ret; + } + + /* Save a copy of the request */ + bdisp_hw_save_request(ctx); + + /* Configure interrupt to 'Last Node Reached for AQ1' */ + writel(BLT_AQ1_CTL_CFG, bdisp->regs + BLT_AQ1_CTL); + writel(BLT_ITS_AQ1_LNA, bdisp->regs + BLT_ITM0); + + /* Write first node addr */ + writel(ctx->node_paddr[0], bdisp->regs + BLT_AQ1_IP); + + /* Find and write last node addr : this starts the HW processing */ + for (node_id = 0; node_id < MAX_NB_NODE - 1; node_id++) { + if (!ctx->node[node_id]->nip) + break; + } + writel(ctx->node_paddr[node_id], bdisp->regs + BLT_AQ1_LNA); + + return 0; +} diff --git a/drivers/media/platform/sti/bdisp/bdisp-reg.h b/drivers/media/platform/sti/bdisp/bdisp-reg.h new file mode 100644 index 0000000..e7e1a42 --- /dev/null +++ b/drivers/media/platform/sti/bdisp/bdisp-reg.h @@ -0,0 +1,235 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +struct bdisp_node { + /* 0 - General */ + u32 nip; + u32 cic; + u32 ins; + u32 ack; + /* 1 - Target */ + u32 tba; + u32 tty; + u32 txy; + u32 tsz; + /* 2 - Color Fill */ + u32 s1cf; + u32 s2cf; + /* 3 - Source 1 */ + u32 s1ba; + u32 s1ty; + u32 s1xy; + u32 s1sz_tsz; + /* 4 - Source 2 */ + u32 s2ba; + u32 s2ty; + u32 s2xy; + u32 s2sz; + /* 5 - Source 3 */ + u32 s3ba; + u32 s3ty; + u32 s3xy; + u32 s3sz; + /* 6 - Clipping */ + u32 cwo; + u32 cws; + /* 7 - CLUT */ + u32 cco; + u32 cml; + /* 8 - Filter & Mask */ + u32 fctl; + u32 pmk; + /* 9 - Chroma Filter */ + u32 rsf; + u32 rzi; + u32 hfp; + u32 vfp; + /* 10 - Luma Filter */ + u32 y_rsf; + u32 y_rzi; + u32 y_hfp; + u32 y_vfp; + /* 11 - Flicker */ + u32 ff0; + u32 ff1; + u32 ff2; + u32 ff3; + /* 12 - Color Key */ + u32 key1; + u32 key2; + /* 14 - Static Address & User */ + u32 sar; + u32 usr; + /* 15 - Input Versatile Matrix */ + u32 ivmx0; + u32 ivmx1; + u32 ivmx2; + u32 ivmx3; + /* 16 - Output Versatile Matrix */ + u32 ovmx0; + u32 ovmx1; + u32 ovmx2; + u32 ovmx3; + /* 17 - Pace */ + u32 pace; + /* 18 - VC1R & DEI */ + u32 vc1r; + u32 dei; + /* 19 - Gradient Fill */ + u32 hgf; + u32 vgf; +}; + +/* HW registers : static */ +#define BLT_CTL 0x0A00 +#define BLT_ITS 0x0A04 +#define BLT_STA1 0x0A08 +#define BLT_AQ1_CTL 0x0A60 +#define BLT_AQ1_IP 0x0A64 +#define BLT_AQ1_LNA 0x0A68 +#define BLT_AQ1_STA 0x0A6C +#define BLT_ITM0 0x0AD0 +/* HW registers : plugs */ +#define BLT_PLUGS1_OP2 0x0B04 +#define BLT_PLUGS1_CHZ 0x0B08 +#define BLT_PLUGS1_MSZ 0x0B0C +#define BLT_PLUGS1_PGZ 0x0B10 +#define BLT_PLUGS2_OP2 0x0B24 +#define BLT_PLUGS2_CHZ 0x0B28 +#define BLT_PLUGS2_MSZ 0x0B2C +#define BLT_PLUGS2_PGZ 0x0B30 +#define BLT_PLUGS3_OP2 0x0B44 +#define BLT_PLUGS3_CHZ 0x0B48 +#define BLT_PLUGS3_MSZ 0x0B4C +#define BLT_PLUGS3_PGZ 0x0B50 +#define BLT_PLUGT_OP2 0x0B84 +#define BLT_PLUGT_CHZ 0x0B88 +#define BLT_PLUGT_MSZ 0x0B8C +#define BLT_PLUGT_PGZ 0x0B90 +/* HW registers : node */ +#define BLT_NIP 0x0C00 +#define BLT_CIC 0x0C04 +#define BLT_INS 0x0C08 +#define BLT_ACK 0x0C0C +#define BLT_TBA 0x0C10 +#define BLT_TTY 0x0C14 +#define BLT_TXY 0x0C18 +#define BLT_TSZ 0x0C1C +#define BLT_S1BA 0x0C28 +#define BLT_S1TY 0x0C2C +#define BLT_S1XY 0x0C30 +#define BLT_S2BA 0x0C38 +#define BLT_S2TY 0x0C3C +#define BLT_S2XY 0x0C40 +#define BLT_S2SZ 0x0C44 +#define BLT_S3BA 0x0C48 +#define BLT_S3TY 0x0C4C +#define BLT_S3XY 0x0C50 +#define BLT_S3SZ 0x0C54 +#define BLT_FCTL 0x0C68 +#define BLT_RSF 0x0C70 +#define BLT_RZI 0x0C74 +#define BLT_HFP 0x0C78 +#define BLT_VFP 0x0C7C +#define BLT_Y_RSF 0x0C80 +#define BLT_Y_RZI 0x0C84 +#define BLT_Y_HFP 0x0C88 +#define BLT_Y_VFP 0x0C8C +#define BLT_IVMX0 0x0CC0 +#define BLT_IVMX1 0x0CC4 +#define BLT_IVMX2 0x0CC8 +#define BLT_IVMX3 0x0CCC +#define BLT_OVMX0 0x0CD0 +#define BLT_OVMX1 0x0CD4 +#define BLT_OVMX2 0x0CD8 +#define BLT_OVMX3 0x0CDC +#define BLT_DEI 0x0CEC +/* HW registers : filters */ +#define BLT_HFC_N 0x0D00 +#define BLT_VFC_N 0x0D90 +#define BLT_Y_HFC_N 0x0E00 +#define BLT_Y_VFC_N 0x0E90 +#define BLT_NB_H_COEF 16 +#define BLT_NB_V_COEF 10 + +/* Registers values */ +#define BLT_CTL_RESET BIT(31) /* Global soft reset */ + +#define BLT_ITS_AQ1_LNA BIT(12) /* AQ1 LNA reached */ + +#define BLT_STA1_IDLE BIT(0) /* BDISP idle */ + +#define BLT_AQ1_CTL_CFG 0x80400003 /* Enable, P3, LNA reached */ + +#define BLT_INS_S1_MASK (BIT(0) | BIT(1) | BIT(2)) +#define BLT_INS_S1_OFF 0x00000000 /* src1 disabled */ +#define BLT_INS_S1_MEM 0x00000001 /* src1 fetched from memory */ +#define BLT_INS_S1_CF 0x00000003 /* src1 color fill */ +#define BLT_INS_S1_COPY 0x00000004 /* src1 direct copy */ +#define BLT_INS_S1_FILL 0x00000007 /* src1 firect fill */ +#define BLT_INS_S2_MASK (BIT(3) | BIT(4)) +#define BLT_INS_S2_OFF 0x00000000 /* src2 disabled */ +#define BLT_INS_S2_MEM 0x00000008 /* src2 fetched from memory */ +#define BLT_INS_S2_CF 0x00000018 /* src2 color fill */ +#define BLT_INS_S3_MASK BIT(5) +#define BLT_INS_S3_OFF 0x00000000 /* src3 disabled */ +#define BLT_INS_S3_MEM 0x00000020 /* src3 fetched from memory */ +#define BLT_INS_IVMX BIT(6) /* Input versatile matrix */ +#define BLT_INS_CLUT BIT(7) /* Color Look Up Table */ +#define BLT_INS_SCALE BIT(8) /* Scaling */ +#define BLT_INS_FLICK BIT(9) /* Flicker filter */ +#define BLT_INS_CLIP BIT(10) /* Clipping */ +#define BLT_INS_CKEY BIT(11) /* Color key */ +#define BLT_INS_OVMX BIT(12) /* Output versatile matrix */ +#define BLT_INS_DEI BIT(13) /* Deinterlace */ +#define BLT_INS_PMASK BIT(14) /* Plane mask */ +#define BLT_INS_VC1R BIT(17) /* VC1 Range mapping */ +#define BLT_INS_ROTATE BIT(18) /* Rotation */ +#define BLT_INS_GRAD BIT(19) /* Gradient fill */ +#define BLT_INS_AQLOCK BIT(29) /* AQ lock */ +#define BLT_INS_PACE BIT(30) /* Pace down */ +#define BLT_INS_IRQ BIT(31) /* Raise IRQ when node done */ +#define BLT_CIC_ALL_GRP 0x000FDFFC /* all valid groups present */ +#define BLT_ACK_BYPASS_S2S3 0x00000007 /* Bypass src2 and src3 */ + +#define BLT_TTY_COL_SHIFT 16 /* Color format */ +#define BLT_TTY_COL_MASK 0x001F0000 /* Color format mask */ +#define BLT_TTY_ALPHA_R BIT(21) /* Alpha range */ +#define BLT_TTY_CR_NOT_CB BIT(22) /* CR not Cb */ +#define BLT_TTY_MB BIT(23) /* MB frame / field*/ +#define BLT_TTY_HSO BIT(24) /* H scan order */ +#define BLT_TTY_VSO BIT(25) /* V scan order */ +#define BLT_TTY_DITHER BIT(26) /* Dithering */ +#define BLT_TTY_CHROMA BIT(27) /* Write chroma / luma */ +#define BLT_TTY_BIG_END BIT(30) /* Big endianness */ + +#define BLT_S1TY_A1_SUBSET BIT(22) /* A1 subset */ +#define BLT_S1TY_CHROMA_EXT BIT(26) /* Chroma Extended */ +#define BTL_S1TY_SUBBYTE BIT(28) /* Sub-byte fmt, pixel order */ +#define BLT_S1TY_RGB_EXP BIT(29) /* RGB expansion mode */ + +#define BLT_S2TY_A1_SUBSET BIT(22) /* A1 subset */ +#define BLT_S2TY_CHROMA_EXT BIT(26) /* Chroma Extended */ +#define BTL_S2TY_SUBBYTE BIT(28) /* Sub-byte fmt, pixel order */ +#define BLT_S2TY_RGB_EXP BIT(29) /* RGB expansion mode */ + +#define BLT_S3TY_BLANK_ACC BIT(26) /* Blank access */ + +#define BLT_FCTL_HV_SCALE 0x00000055 /* H/V resize + color filter */ +#define BLT_FCTL_Y_HV_SCALE 0x33000000 /* Luma version */ + +#define BLT_FCTL_HV_SAMPLE 0x00000044 /* H/V resize */ +#define BLT_FCTL_Y_HV_SAMPLE 0x22000000 /* Luma version */ + +#define BLT_RZI_DEFAULT 0x20003000 /* H/VNB_repeat = 3/2 */ + +/* Color format */ +#define BDISP_RGB565 0x00 /* RGB565 */ +#define BDISP_RGB888 0x01 /* RGB888 */ +#define BDISP_XRGB8888 0x02 /* RGB888_32 */ +#define BDISP_ARGB8888 0x05 /* ARGB888 */ +#define BDISP_NV12 0x16 /* YCbCr42x R2B */ +#define BDISP_YUV_3B 0x1E /* YUV (3 buffer) */ diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c new file mode 100644 index 0000000..9e782eb --- /dev/null +++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c @@ -0,0 +1,1416 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> + +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> + +#include "bdisp.h" + +#define BDISP_MAX_CTRL_NUM 10 + +#define BDISP_WORK_TIMEOUT ((100 * HZ) / 1000) + +/* User configuration change */ +#define BDISP_PARAMS BIT(0) /* Config updated */ +#define BDISP_SRC_FMT BIT(1) /* Source set */ +#define BDISP_DST_FMT BIT(2) /* Destination set */ +#define BDISP_CTX_STOP_REQ BIT(3) /* Stop request */ +#define BDISP_CTX_ABORT BIT(4) /* Abort while device run */ + +#define BDISP_MIN_W 1 +#define BDISP_MAX_W 8191 +#define BDISP_MIN_H 1 +#define BDISP_MAX_H 8191 + +#define fh_to_ctx(__fh) container_of(__fh, struct bdisp_ctx, fh) + +enum bdisp_dev_flags { + ST_M2M_OPEN, /* Driver opened */ + ST_M2M_RUNNING, /* HW device running */ + ST_M2M_SUSPENDED, /* Driver suspended */ + ST_M2M_SUSPENDING, /* Driver being suspended */ +}; + +static const struct bdisp_fmt bdisp_formats[] = { + /* ARGB888. [31:0] A:R:G:B 8:8:8:8 little endian */ + { + .pixelformat = V4L2_PIX_FMT_ABGR32, /* is actually ARGB */ + .nb_planes = 1, + .bpp = 32, + .bpp_plane0 = 32, + .w_align = 1, + .h_align = 1 + }, + /* XRGB888. [31:0] x:R:G:B 8:8:8:8 little endian */ + { + .pixelformat = V4L2_PIX_FMT_XBGR32, /* is actually xRGB */ + .nb_planes = 1, + .bpp = 32, + .bpp_plane0 = 32, + .w_align = 1, + .h_align = 1 + }, + /* RGB565. [15:0] R:G:B 5:6:5 little endian */ + { + .pixelformat = V4L2_PIX_FMT_RGB565, + .nb_planes = 1, + .bpp = 16, + .bpp_plane0 = 16, + .w_align = 1, + .h_align = 1 + }, + /* NV12. YUV420SP - 1 plane for Y + 1 plane for (CbCr) */ + { + .pixelformat = V4L2_PIX_FMT_NV12, + .nb_planes = 2, + .bpp = 12, + .bpp_plane0 = 8, + .w_align = 2, + .h_align = 2 + }, + /* RGB888. [23:0] B:G:R 8:8:8 little endian */ + { + .pixelformat = V4L2_PIX_FMT_RGB24, + .nb_planes = 1, + .bpp = 24, + .bpp_plane0 = 24, + .w_align = 1, + .h_align = 1 + }, + /* YU12. YUV420P - 1 plane for Y + 1 plane for Cb + 1 plane for Cr + * To keep as the LAST element of this table (no support on capture) + */ + { + .pixelformat = V4L2_PIX_FMT_YUV420, + .nb_planes = 3, + .bpp = 12, + .bpp_plane0 = 8, + .w_align = 2, + .h_align = 2 + } +}; + +/* Default format : HD ARGB32*/ +#define BDISP_DEF_WIDTH 1920 +#define BDISP_DEF_HEIGHT 1080 + +static const struct bdisp_frame bdisp_dflt_fmt = { + .width = BDISP_DEF_WIDTH, + .height = BDISP_DEF_HEIGHT, + .fmt = &bdisp_formats[0], + .field = V4L2_FIELD_NONE, + .bytesperline = BDISP_DEF_WIDTH * 4, + .sizeimage = BDISP_DEF_WIDTH * BDISP_DEF_HEIGHT * 4, + .colorspace = V4L2_COLORSPACE_REC709, + .crop = {0, 0, BDISP_DEF_WIDTH, BDISP_DEF_HEIGHT}, + .paddr = {0, 0, 0, 0} +}; + +static inline void bdisp_ctx_state_lock_set(u32 state, struct bdisp_ctx *ctx) +{ + unsigned long flags; + + spin_lock_irqsave(&ctx->bdisp_dev->slock, flags); + ctx->state |= state; + spin_unlock_irqrestore(&ctx->bdisp_dev->slock, flags); +} + +static inline void bdisp_ctx_state_lock_clear(u32 state, struct bdisp_ctx *ctx) +{ + unsigned long flags; + + spin_lock_irqsave(&ctx->bdisp_dev->slock, flags); + ctx->state &= ~state; + spin_unlock_irqrestore(&ctx->bdisp_dev->slock, flags); +} + +static inline bool bdisp_ctx_state_is_set(u32 mask, struct bdisp_ctx *ctx) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&ctx->bdisp_dev->slock, flags); + ret = (ctx->state & mask) == mask; + spin_unlock_irqrestore(&ctx->bdisp_dev->slock, flags); + + return ret; +} + +static const struct bdisp_fmt *bdisp_find_fmt(u32 pixelformat) +{ + const struct bdisp_fmt *fmt; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(bdisp_formats); i++) { + fmt = &bdisp_formats[i]; + if (fmt->pixelformat == pixelformat) + return fmt; + } + + return NULL; +} + +static struct bdisp_frame *ctx_get_frame(struct bdisp_ctx *ctx, + enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return &ctx->src; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &ctx->dst; + default: + dev_err(ctx->bdisp_dev->dev, + "Wrong buffer/video queue type (%d)\n", type); + break; + } + + return ERR_PTR(-EINVAL); +} + +static void bdisp_job_finish(struct bdisp_ctx *ctx, int vb_state) +{ + struct vb2_buffer *src_vb, *dst_vb; + + if (WARN(!ctx || !ctx->fh.m2m_ctx, "Null hardware context\n")) + return; + + dev_dbg(ctx->bdisp_dev->dev, "%s\n", __func__); + + src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + if (src_vb && dst_vb) { + dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp; + dst_vb->v4l2_buf.timecode = src_vb->v4l2_buf.timecode; + dst_vb->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst_vb->v4l2_buf.flags |= src_vb->v4l2_buf.flags & + V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + + v4l2_m2m_buf_done(src_vb, vb_state); + v4l2_m2m_buf_done(dst_vb, vb_state); + + v4l2_m2m_job_finish(ctx->bdisp_dev->m2m.m2m_dev, + ctx->fh.m2m_ctx); + } +} + +static int bdisp_ctx_stop_req(struct bdisp_ctx *ctx) +{ + struct bdisp_ctx *curr_ctx; + struct bdisp_dev *bdisp = ctx->bdisp_dev; + int ret; + + dev_dbg(ctx->bdisp_dev->dev, "%s\n", __func__); + + cancel_delayed_work(&bdisp->timeout_work); + + curr_ctx = v4l2_m2m_get_curr_priv(bdisp->m2m.m2m_dev); + if (!test_bit(ST_M2M_RUNNING, &bdisp->state) || (curr_ctx != ctx)) + return 0; + + bdisp_ctx_state_lock_set(BDISP_CTX_STOP_REQ, ctx); + + ret = wait_event_timeout(bdisp->irq_queue, + !bdisp_ctx_state_is_set(BDISP_CTX_STOP_REQ, ctx), + BDISP_WORK_TIMEOUT); + + if (!ret) { + dev_err(ctx->bdisp_dev->dev, "%s IRQ timeout\n", __func__); + return -ETIMEDOUT; + } + + return 0; +} + +static void __bdisp_job_abort(struct bdisp_ctx *ctx) +{ + int ret; + + ret = bdisp_ctx_stop_req(ctx); + if ((ret == -ETIMEDOUT) || (ctx->state & BDISP_CTX_ABORT)) { + bdisp_ctx_state_lock_clear(BDISP_CTX_STOP_REQ | BDISP_CTX_ABORT, + ctx); + bdisp_job_finish(ctx, VB2_BUF_STATE_ERROR); + } +} + +static void bdisp_job_abort(void *priv) +{ + __bdisp_job_abort((struct bdisp_ctx *)priv); +} + +static int bdisp_get_addr(struct bdisp_ctx *ctx, struct vb2_buffer *vb, + struct bdisp_frame *frame, dma_addr_t *paddr) +{ + if (!vb || !frame) + return -EINVAL; + + paddr[0] = vb2_dma_contig_plane_dma_addr(vb, 0); + + if (frame->fmt->nb_planes > 1) + /* UV (NV12) or U (420P) */ + paddr[1] = (dma_addr_t)(paddr[0] + + frame->bytesperline * frame->height); + + if (frame->fmt->nb_planes > 2) + /* V (420P) */ + paddr[2] = (dma_addr_t)(paddr[1] + + (frame->bytesperline * frame->height) / 4); + + if (frame->fmt->nb_planes > 3) + dev_dbg(ctx->bdisp_dev->dev, "ignoring some planes\n"); + + dev_dbg(ctx->bdisp_dev->dev, + "%s plane[0]=%pad plane[1]=%pad plane[2]=%pad\n", + __func__, &paddr[0], &paddr[1], &paddr[2]); + + return 0; +} + +static int bdisp_get_bufs(struct bdisp_ctx *ctx) +{ + struct bdisp_frame *src, *dst; + struct vb2_buffer *src_vb, *dst_vb; + int ret; + + src = &ctx->src; + dst = &ctx->dst; + + src_vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + ret = bdisp_get_addr(ctx, src_vb, src, src->paddr); + if (ret) + return ret; + + dst_vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + ret = bdisp_get_addr(ctx, dst_vb, dst, dst->paddr); + if (ret) + return ret; + + dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp; + + return 0; +} + +static void bdisp_device_run(void *priv) +{ + struct bdisp_ctx *ctx = priv; + struct bdisp_dev *bdisp; + unsigned long flags; + int err = 0; + + if (WARN(!ctx, "Null hardware context\n")) + return; + + bdisp = ctx->bdisp_dev; + dev_dbg(bdisp->dev, "%s\n", __func__); + spin_lock_irqsave(&bdisp->slock, flags); + + if (bdisp->m2m.ctx != ctx) { + dev_dbg(bdisp->dev, "ctx updated: %p -> %p\n", + bdisp->m2m.ctx, ctx); + ctx->state |= BDISP_PARAMS; + bdisp->m2m.ctx = ctx; + } + + if (ctx->state & BDISP_CTX_STOP_REQ) { + ctx->state &= ~BDISP_CTX_STOP_REQ; + ctx->state |= BDISP_CTX_ABORT; + wake_up(&bdisp->irq_queue); + goto out; + } + + err = bdisp_get_bufs(ctx); + if (err) { + dev_err(bdisp->dev, "cannot get address\n"); + goto out; + } + + bdisp_dbg_perf_begin(bdisp); + + err = bdisp_hw_reset(bdisp); + if (err) { + dev_err(bdisp->dev, "could not get HW ready\n"); + goto out; + } + + err = bdisp_hw_update(ctx); + if (err) { + dev_err(bdisp->dev, "could not send HW request\n"); + goto out; + } + + queue_delayed_work(bdisp->work_queue, &bdisp->timeout_work, + BDISP_WORK_TIMEOUT); + set_bit(ST_M2M_RUNNING, &bdisp->state); +out: + ctx->state &= ~BDISP_PARAMS; + spin_unlock_irqrestore(&bdisp->slock, flags); + if (err) + bdisp_job_finish(ctx, VB2_BUF_STATE_ERROR); +} + +static struct v4l2_m2m_ops bdisp_m2m_ops = { + .device_run = bdisp_device_run, + .job_abort = bdisp_job_abort, +}; + +static int __bdisp_s_ctrl(struct bdisp_ctx *ctx, struct v4l2_ctrl *ctrl) +{ + if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) + return 0; + + switch (ctrl->id) { + case V4L2_CID_HFLIP: + ctx->hflip = ctrl->val; + break; + case V4L2_CID_VFLIP: + ctx->vflip = ctrl->val; + break; + default: + dev_err(ctx->bdisp_dev->dev, "unknown control %d\n", ctrl->id); + return -EINVAL; + } + + ctx->state |= BDISP_PARAMS; + + return 0; +} + +static int bdisp_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct bdisp_ctx *ctx = container_of(ctrl->handler, struct bdisp_ctx, + ctrl_handler); + unsigned long flags; + int ret; + + spin_lock_irqsave(&ctx->bdisp_dev->slock, flags); + ret = __bdisp_s_ctrl(ctx, ctrl); + spin_unlock_irqrestore(&ctx->bdisp_dev->slock, flags); + + return ret; +} + +static const struct v4l2_ctrl_ops bdisp_c_ops = { + .s_ctrl = bdisp_s_ctrl, +}; + +static int bdisp_ctrls_create(struct bdisp_ctx *ctx) +{ + if (ctx->ctrls_rdy) + return 0; + + v4l2_ctrl_handler_init(&ctx->ctrl_handler, BDISP_MAX_CTRL_NUM); + + ctx->bdisp_ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, + &bdisp_c_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); + ctx->bdisp_ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, + &bdisp_c_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); + + if (ctx->ctrl_handler.error) { + int err = ctx->ctrl_handler.error; + + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + return err; + } + + ctx->ctrls_rdy = true; + + return 0; +} + +static void bdisp_ctrls_delete(struct bdisp_ctx *ctx) +{ + if (ctx->ctrls_rdy) { + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + ctx->ctrls_rdy = false; + } +} + +static int bdisp_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, + unsigned int *nb_buf, unsigned int *nb_planes, + unsigned int sizes[], void *allocators[]) +{ + struct bdisp_ctx *ctx = vb2_get_drv_priv(vq); + struct bdisp_frame *frame = ctx_get_frame(ctx, vq->type); + + if (IS_ERR(frame)) { + dev_err(ctx->bdisp_dev->dev, "Invalid frame (%p)\n", frame); + return PTR_ERR(frame); + } + + if (!frame->fmt) { + dev_err(ctx->bdisp_dev->dev, "Invalid format\n"); + return -EINVAL; + } + + if (fmt && fmt->fmt.pix.sizeimage < frame->sizeimage) + return -EINVAL; + + *nb_planes = 1; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : frame->sizeimage; + allocators[0] = ctx->bdisp_dev->alloc_ctx; + + return 0; +} + +static int bdisp_buf_prepare(struct vb2_buffer *vb) +{ + struct bdisp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct bdisp_frame *frame = ctx_get_frame(ctx, vb->vb2_queue->type); + + if (IS_ERR(frame)) { + dev_err(ctx->bdisp_dev->dev, "Invalid frame (%p)\n", frame); + return PTR_ERR(frame); + } + + if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + vb2_set_plane_payload(vb, 0, frame->sizeimage); + + return 0; +} + +static void bdisp_buf_queue(struct vb2_buffer *vb) +{ + struct bdisp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + /* return to V4L2 any 0-size buffer so it can be dequeued by user */ + if (!vb2_get_plane_payload(vb, 0)) { + dev_dbg(ctx->bdisp_dev->dev, "0 data buffer, skip it\n"); + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + return; + } + + if (ctx->fh.m2m_ctx) + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); +} + +static int bdisp_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct bdisp_ctx *ctx = q->drv_priv; + struct vb2_buffer *buf; + int ret = pm_runtime_get_sync(ctx->bdisp_dev->dev); + + if (ret < 0) { + dev_err(ctx->bdisp_dev->dev, "failed to set runtime PM\n"); + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); + } else { + while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); + } + + return ret; + } + + return 0; +} + +static void bdisp_stop_streaming(struct vb2_queue *q) +{ + struct bdisp_ctx *ctx = q->drv_priv; + + __bdisp_job_abort(ctx); + + pm_runtime_put(ctx->bdisp_dev->dev); +} + +static struct vb2_ops bdisp_qops = { + .queue_setup = bdisp_queue_setup, + .buf_prepare = bdisp_buf_prepare, + .buf_queue = bdisp_buf_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .stop_streaming = bdisp_stop_streaming, + .start_streaming = bdisp_start_streaming, +}; + +static int queue_init(void *priv, + struct vb2_queue *src_vq, struct vb2_queue *dst_vq) +{ + struct bdisp_ctx *ctx = priv; + int ret; + + memset(src_vq, 0, sizeof(*src_vq)); + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->ops = &bdisp_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->bdisp_dev->lock; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + memset(dst_vq, 0, sizeof(*dst_vq)); + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->ops = &bdisp_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &ctx->bdisp_dev->lock; + + return vb2_queue_init(dst_vq); +} + +static int bdisp_open(struct file *file) +{ + struct bdisp_dev *bdisp = video_drvdata(file); + struct bdisp_ctx *ctx = NULL; + int ret; + + if (mutex_lock_interruptible(&bdisp->lock)) + return -ERESTARTSYS; + + /* Allocate memory for both context and node */ + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + ret = -ENOMEM; + goto unlock; + } + ctx->bdisp_dev = bdisp; + + if (bdisp_hw_alloc_nodes(ctx)) { + dev_err(bdisp->dev, "no memory for nodes\n"); + ret = -ENOMEM; + goto mem_ctx; + } + + v4l2_fh_init(&ctx->fh, bdisp->m2m.vdev); + + ret = bdisp_ctrls_create(ctx); + if (ret) { + dev_err(bdisp->dev, "Failed to create control\n"); + goto error_fh; + } + + /* Use separate control handler per file handle */ + ctx->fh.ctrl_handler = &ctx->ctrl_handler; + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + + /* Default format */ + ctx->src = bdisp_dflt_fmt; + ctx->dst = bdisp_dflt_fmt; + + /* Setup the device context for mem2mem mode. */ + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(bdisp->m2m.m2m_dev, ctx, + queue_init); + if (IS_ERR(ctx->fh.m2m_ctx)) { + dev_err(bdisp->dev, "Failed to initialize m2m context\n"); + ret = PTR_ERR(ctx->fh.m2m_ctx); + goto error_ctrls; + } + + bdisp->m2m.refcnt++; + set_bit(ST_M2M_OPEN, &bdisp->state); + + dev_dbg(bdisp->dev, "driver opened, ctx = 0x%p\n", ctx); + + mutex_unlock(&bdisp->lock); + + return 0; + +error_ctrls: + bdisp_ctrls_delete(ctx); +error_fh: + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + bdisp_hw_free_nodes(ctx); +mem_ctx: + kfree(ctx); +unlock: + mutex_unlock(&bdisp->lock); + + return ret; +} + +static int bdisp_release(struct file *file) +{ + struct bdisp_ctx *ctx = fh_to_ctx(file->private_data); + struct bdisp_dev *bdisp = ctx->bdisp_dev; + + dev_dbg(bdisp->dev, "%s\n", __func__); + + if (mutex_lock_interruptible(&bdisp->lock)) + return -ERESTARTSYS; + + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + + bdisp_ctrls_delete(ctx); + + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + + if (--bdisp->m2m.refcnt <= 0) + clear_bit(ST_M2M_OPEN, &bdisp->state); + + bdisp_hw_free_nodes(ctx); + + kfree(ctx); + + mutex_unlock(&bdisp->lock); + + return 0; +} + +static const struct v4l2_file_operations bdisp_fops = { + .owner = THIS_MODULE, + .open = bdisp_open, + .release = bdisp_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static int bdisp_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct bdisp_ctx *ctx = fh_to_ctx(fh); + struct bdisp_dev *bdisp = ctx->bdisp_dev; + + strlcpy(cap->driver, bdisp->pdev->name, sizeof(cap->driver)); + strlcpy(cap->card, bdisp->pdev->name, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s%d", + BDISP_NAME, bdisp->id); + + cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M; + + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + + return 0; +} + +static int bdisp_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct bdisp_ctx *ctx = fh_to_ctx(fh); + const struct bdisp_fmt *fmt; + + if (f->index >= ARRAY_SIZE(bdisp_formats)) + return -EINVAL; + + fmt = &bdisp_formats[f->index]; + + if ((fmt->pixelformat == V4L2_PIX_FMT_YUV420) && + (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)) { + dev_dbg(ctx->bdisp_dev->dev, "No YU12 on capture\n"); + return -EINVAL; + } + f->pixelformat = fmt->pixelformat; + + return 0; +} + +static int bdisp_g_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct bdisp_ctx *ctx = fh_to_ctx(fh); + struct v4l2_pix_format *pix = &f->fmt.pix; + struct bdisp_frame *frame = ctx_get_frame(ctx, f->type); + + if (IS_ERR(frame)) { + dev_err(ctx->bdisp_dev->dev, "Invalid frame (%p)\n", frame); + return PTR_ERR(frame); + } + + pix = &f->fmt.pix; + pix->width = frame->width; + pix->height = frame->height; + pix->pixelformat = frame->fmt->pixelformat; + pix->field = frame->field; + pix->bytesperline = frame->bytesperline; + pix->sizeimage = frame->sizeimage; + pix->colorspace = (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ? + frame->colorspace : bdisp_dflt_fmt.colorspace; + + return 0; +} + +static int bdisp_try_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct bdisp_ctx *ctx = fh_to_ctx(fh); + struct v4l2_pix_format *pix = &f->fmt.pix; + const struct bdisp_fmt *format; + u32 in_w, in_h; + + format = bdisp_find_fmt(pix->pixelformat); + if (!format) { + dev_dbg(ctx->bdisp_dev->dev, "Unknown format 0x%x\n", + pix->pixelformat); + return -EINVAL; + } + + /* YUV420P only supported for VIDEO_OUTPUT */ + if ((format->pixelformat == V4L2_PIX_FMT_YUV420) && + (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)) { + dev_dbg(ctx->bdisp_dev->dev, "No YU12 on capture\n"); + return -EINVAL; + } + + /* Field (interlaced only supported on OUTPUT) */ + if ((f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) || + (pix->field != V4L2_FIELD_INTERLACED)) + pix->field = V4L2_FIELD_NONE; + + /* Adjust width & height */ + in_w = pix->width; + in_h = pix->height; + v4l_bound_align_image(&pix->width, + BDISP_MIN_W, BDISP_MAX_W, + ffs(format->w_align) - 1, + &pix->height, + BDISP_MIN_H, BDISP_MAX_H, + ffs(format->h_align) - 1, + 0); + if ((pix->width != in_w) || (pix->height != in_h)) + dev_dbg(ctx->bdisp_dev->dev, + "%s size updated: %dx%d -> %dx%d\n", __func__, + in_w, in_h, pix->width, pix->height); + + pix->bytesperline = (pix->width * format->bpp_plane0) / 8; + pix->sizeimage = (pix->width * pix->height * format->bpp) / 8; + + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + pix->colorspace = bdisp_dflt_fmt.colorspace; + + return 0; +} + +static int bdisp_s_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct bdisp_ctx *ctx = fh_to_ctx(fh); + struct vb2_queue *vq; + struct bdisp_frame *frame; + struct v4l2_pix_format *pix; + int ret; + u32 state; + + ret = bdisp_try_fmt(file, fh, f); + if (ret) { + dev_err(ctx->bdisp_dev->dev, "Cannot set format\n"); + return ret; + } + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (vb2_is_streaming(vq)) { + dev_err(ctx->bdisp_dev->dev, "queue (%d) busy\n", f->type); + return -EBUSY; + } + + frame = (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ? + &ctx->src : &ctx->dst; + pix = &f->fmt.pix; + frame->fmt = bdisp_find_fmt(pix->pixelformat); + if (!frame->fmt) { + dev_err(ctx->bdisp_dev->dev, "Unknown format 0x%x\n", + pix->pixelformat); + return -EINVAL; + } + + frame->width = pix->width; + frame->height = pix->height; + frame->bytesperline = pix->bytesperline; + frame->sizeimage = pix->sizeimage; + frame->field = pix->field; + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + frame->colorspace = pix->colorspace; + + frame->crop.width = frame->width; + frame->crop.height = frame->height; + frame->crop.left = 0; + frame->crop.top = 0; + + state = BDISP_PARAMS; + state |= (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ? + BDISP_DST_FMT : BDISP_SRC_FMT; + bdisp_ctx_state_lock_set(state, ctx); + + return 0; +} + +static int bdisp_g_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct bdisp_frame *frame; + struct bdisp_ctx *ctx = fh_to_ctx(fh); + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { + /* Composing / capture is not supported */ + dev_dbg(ctx->bdisp_dev->dev, "Not supported for capture\n"); + return -EINVAL; + } + + frame = ctx_get_frame(ctx, s->type); + if (IS_ERR(frame)) { + dev_err(ctx->bdisp_dev->dev, "Invalid frame (%p)\n", frame); + return PTR_ERR(frame); + } + + switch (s->target) { + case V4L2_SEL_TGT_CROP: + /* cropped frame */ + s->r = frame->crop; + break; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + /* complete frame */ + s->r.left = 0; + s->r.top = 0; + s->r.width = frame->width; + s->r.height = frame->height; + break; + default: + dev_dbg(ctx->bdisp_dev->dev, "Invalid target\n"); + return -EINVAL; + } + + return 0; +} + +static int is_rect_enclosed(struct v4l2_rect *a, struct v4l2_rect *b) +{ + /* Return 1 if a is enclosed in b, or 0 otherwise. */ + + if (a->left < b->left || a->top < b->top) + return 0; + + if (a->left + a->width > b->left + b->width) + return 0; + + if (a->top + a->height > b->top + b->height) + return 0; + + return 1; +} + +static int bdisp_s_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct bdisp_frame *frame; + struct bdisp_ctx *ctx = fh_to_ctx(fh); + struct v4l2_rect *in, out; + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { + /* Composing / capture is not supported */ + dev_dbg(ctx->bdisp_dev->dev, "Not supported for capture\n"); + return -EINVAL; + } + + if (s->target != V4L2_SEL_TGT_CROP) { + dev_dbg(ctx->bdisp_dev->dev, "Invalid target\n"); + return -EINVAL; + } + + frame = ctx_get_frame(ctx, s->type); + if (IS_ERR(frame)) { + dev_err(ctx->bdisp_dev->dev, "Invalid frame (%p)\n", frame); + return PTR_ERR(frame); + } + + in = &s->r; + out = *in; + + /* Align and check origin */ + out.left = ALIGN(in->left, frame->fmt->w_align); + out.top = ALIGN(in->top, frame->fmt->h_align); + + if ((out.left < 0) || (out.left >= frame->width) || + (out.top < 0) || (out.top >= frame->height)) { + dev_err(ctx->bdisp_dev->dev, + "Invalid crop: %dx%d@(%d,%d) vs frame: %dx%d\n", + out.width, out.height, out.left, out.top, + frame->width, frame->height); + return -EINVAL; + } + + /* Align and check size */ + out.width = ALIGN(in->width, frame->fmt->w_align); + out.height = ALIGN(in->height, frame->fmt->w_align); + + if (((out.left + out.width) > frame->width) || + ((out.top + out.height) > frame->height)) { + dev_err(ctx->bdisp_dev->dev, + "Invalid crop: %dx%d@(%d,%d) vs frame: %dx%d\n", + out.width, out.height, out.left, out.top, + frame->width, frame->height); + return -EINVAL; + } + + /* Checks adjust constraints flags */ + if (s->flags & V4L2_SEL_FLAG_LE && !is_rect_enclosed(&out, in)) + return -ERANGE; + + if (s->flags & V4L2_SEL_FLAG_GE && !is_rect_enclosed(in, &out)) + return -ERANGE; + + if ((out.left != in->left) || (out.top != in->top) || + (out.width != in->width) || (out.height != in->height)) { + dev_dbg(ctx->bdisp_dev->dev, + "%s crop updated: %dx%d@(%d,%d) -> %dx%d@(%d,%d)\n", + __func__, in->width, in->height, in->left, in->top, + out.width, out.height, out.left, out.top); + *in = out; + } + + frame->crop = out; + + bdisp_ctx_state_lock_set(BDISP_PARAMS, ctx); + + return 0; +} + +static int bdisp_streamon(struct file *file, void *fh, enum v4l2_buf_type type) +{ + struct bdisp_ctx *ctx = fh_to_ctx(fh); + + if ((type == V4L2_BUF_TYPE_VIDEO_OUTPUT) && + !bdisp_ctx_state_is_set(BDISP_SRC_FMT, ctx)) { + dev_err(ctx->bdisp_dev->dev, "src not defined\n"); + return -EINVAL; + } + + if ((type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && + !bdisp_ctx_state_is_set(BDISP_DST_FMT, ctx)) { + dev_err(ctx->bdisp_dev->dev, "dst not defined\n"); + return -EINVAL; + } + + return v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, type); +} + +static const struct v4l2_ioctl_ops bdisp_ioctl_ops = { + .vidioc_querycap = bdisp_querycap, + .vidioc_enum_fmt_vid_cap = bdisp_enum_fmt, + .vidioc_enum_fmt_vid_out = bdisp_enum_fmt, + .vidioc_g_fmt_vid_cap = bdisp_g_fmt, + .vidioc_g_fmt_vid_out = bdisp_g_fmt, + .vidioc_try_fmt_vid_cap = bdisp_try_fmt, + .vidioc_try_fmt_vid_out = bdisp_try_fmt, + .vidioc_s_fmt_vid_cap = bdisp_s_fmt, + .vidioc_s_fmt_vid_out = bdisp_s_fmt, + .vidioc_g_selection = bdisp_g_selection, + .vidioc_s_selection = bdisp_s_selection, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_streamon = bdisp_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int bdisp_register_device(struct bdisp_dev *bdisp) +{ + int ret; + + if (!bdisp) + return -ENODEV; + + bdisp->vdev.fops = &bdisp_fops; + bdisp->vdev.ioctl_ops = &bdisp_ioctl_ops; + bdisp->vdev.release = video_device_release_empty; + bdisp->vdev.lock = &bdisp->lock; + bdisp->vdev.vfl_dir = VFL_DIR_M2M; + bdisp->vdev.v4l2_dev = &bdisp->v4l2_dev; + snprintf(bdisp->vdev.name, sizeof(bdisp->vdev.name), "%s.%d", + BDISP_NAME, bdisp->id); + + video_set_drvdata(&bdisp->vdev, bdisp); + + bdisp->m2m.vdev = &bdisp->vdev; + bdisp->m2m.m2m_dev = v4l2_m2m_init(&bdisp_m2m_ops); + if (IS_ERR(bdisp->m2m.m2m_dev)) { + dev_err(bdisp->dev, "failed to initialize v4l2-m2m device\n"); + return PTR_ERR(bdisp->m2m.m2m_dev); + } + + ret = video_register_device(&bdisp->vdev, VFL_TYPE_GRABBER, -1); + if (ret) { + dev_err(bdisp->dev, + "%s(): failed to register video device\n", __func__); + v4l2_m2m_release(bdisp->m2m.m2m_dev); + return ret; + } + + return 0; +} + +static void bdisp_unregister_device(struct bdisp_dev *bdisp) +{ + if (!bdisp) + return; + + if (bdisp->m2m.m2m_dev) + v4l2_m2m_release(bdisp->m2m.m2m_dev); + + video_unregister_device(bdisp->m2m.vdev); +} + +static irqreturn_t bdisp_irq_thread(int irq, void *priv) +{ + struct bdisp_dev *bdisp = priv; + struct bdisp_ctx *ctx; + + spin_lock(&bdisp->slock); + + bdisp_dbg_perf_end(bdisp); + + cancel_delayed_work(&bdisp->timeout_work); + + if (!test_and_clear_bit(ST_M2M_RUNNING, &bdisp->state)) + goto isr_unlock; + + if (test_and_clear_bit(ST_M2M_SUSPENDING, &bdisp->state)) { + set_bit(ST_M2M_SUSPENDED, &bdisp->state); + wake_up(&bdisp->irq_queue); + goto isr_unlock; + } + + ctx = v4l2_m2m_get_curr_priv(bdisp->m2m.m2m_dev); + if (!ctx || !ctx->fh.m2m_ctx) + goto isr_unlock; + + spin_unlock(&bdisp->slock); + + bdisp_job_finish(ctx, VB2_BUF_STATE_DONE); + + if (bdisp_ctx_state_is_set(BDISP_CTX_STOP_REQ, ctx)) { + bdisp_ctx_state_lock_clear(BDISP_CTX_STOP_REQ, ctx); + wake_up(&bdisp->irq_queue); + } + + return IRQ_HANDLED; + +isr_unlock: + spin_unlock(&bdisp->slock); + + return IRQ_HANDLED; +} + +static irqreturn_t bdisp_irq_handler(int irq, void *priv) +{ + if (bdisp_hw_get_and_clear_irq((struct bdisp_dev *)priv)) + return IRQ_NONE; + else + return IRQ_WAKE_THREAD; +} + +static void bdisp_irq_timeout(struct work_struct *ptr) +{ + struct delayed_work *twork = to_delayed_work(ptr); + struct bdisp_dev *bdisp = container_of(twork, struct bdisp_dev, + timeout_work); + struct bdisp_ctx *ctx; + + ctx = v4l2_m2m_get_curr_priv(bdisp->m2m.m2m_dev); + + dev_err(ctx->bdisp_dev->dev, "Device work timeout\n"); + + spin_lock(&bdisp->slock); + clear_bit(ST_M2M_RUNNING, &bdisp->state); + spin_unlock(&bdisp->slock); + + bdisp_hw_reset(bdisp); + + bdisp_job_finish(ctx, VB2_BUF_STATE_ERROR); +} + +static int bdisp_m2m_suspend(struct bdisp_dev *bdisp) +{ + unsigned long flags; + int timeout; + + spin_lock_irqsave(&bdisp->slock, flags); + if (!test_bit(ST_M2M_RUNNING, &bdisp->state)) { + spin_unlock_irqrestore(&bdisp->slock, flags); + return 0; + } + clear_bit(ST_M2M_SUSPENDED, &bdisp->state); + set_bit(ST_M2M_SUSPENDING, &bdisp->state); + spin_unlock_irqrestore(&bdisp->slock, flags); + + timeout = wait_event_timeout(bdisp->irq_queue, + test_bit(ST_M2M_SUSPENDED, &bdisp->state), + BDISP_WORK_TIMEOUT); + + clear_bit(ST_M2M_SUSPENDING, &bdisp->state); + + if (!timeout) { + dev_err(bdisp->dev, "%s IRQ timeout\n", __func__); + return -EAGAIN; + } + + return 0; +} + +static int bdisp_m2m_resume(struct bdisp_dev *bdisp) +{ + struct bdisp_ctx *ctx; + unsigned long flags; + + spin_lock_irqsave(&bdisp->slock, flags); + ctx = bdisp->m2m.ctx; + bdisp->m2m.ctx = NULL; + spin_unlock_irqrestore(&bdisp->slock, flags); + + if (test_and_clear_bit(ST_M2M_SUSPENDED, &bdisp->state)) + bdisp_job_finish(ctx, VB2_BUF_STATE_ERROR); + + return 0; +} + +static int bdisp_runtime_resume(struct device *dev) +{ + struct bdisp_dev *bdisp = dev_get_drvdata(dev); + int ret = clk_enable(bdisp->clock); + + if (ret) + return ret; + + return bdisp_m2m_resume(bdisp); +} + +static int bdisp_runtime_suspend(struct device *dev) +{ + struct bdisp_dev *bdisp = dev_get_drvdata(dev); + int ret = bdisp_m2m_suspend(bdisp); + + if (!ret) + clk_disable(bdisp->clock); + + return ret; +} + +static int bdisp_resume(struct device *dev) +{ + struct bdisp_dev *bdisp = dev_get_drvdata(dev); + unsigned long flags; + int opened; + + spin_lock_irqsave(&bdisp->slock, flags); + opened = test_bit(ST_M2M_OPEN, &bdisp->state); + spin_unlock_irqrestore(&bdisp->slock, flags); + + if (!opened) + return 0; + + if (!pm_runtime_suspended(dev)) + return bdisp_runtime_resume(dev); + + return 0; +} + +static int bdisp_suspend(struct device *dev) +{ + if (!pm_runtime_suspended(dev)) + return bdisp_runtime_suspend(dev); + + return 0; +} + +static const struct dev_pm_ops bdisp_pm_ops = { + .suspend = bdisp_suspend, + .resume = bdisp_resume, + .runtime_suspend = bdisp_runtime_suspend, + .runtime_resume = bdisp_runtime_resume, +}; + +static int bdisp_remove(struct platform_device *pdev) +{ + struct bdisp_dev *bdisp = platform_get_drvdata(pdev); + + bdisp_unregister_device(bdisp); + + bdisp_hw_free_filters(bdisp->dev); + + vb2_dma_contig_cleanup_ctx(bdisp->alloc_ctx); + + pm_runtime_disable(&pdev->dev); + + bdisp_debugfs_remove(bdisp); + + v4l2_device_unregister(&bdisp->v4l2_dev); + + if (!IS_ERR(bdisp->clock)) + clk_unprepare(bdisp->clock); + + dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name); + + return 0; +} + +static int bdisp_probe(struct platform_device *pdev) +{ + struct bdisp_dev *bdisp; + struct resource *res; + struct device *dev = &pdev->dev; + int ret; + + dev_dbg(dev, "%s\n", __func__); + + bdisp = devm_kzalloc(dev, sizeof(struct bdisp_dev), GFP_KERNEL); + if (!bdisp) + return -ENOMEM; + + bdisp->pdev = pdev; + bdisp->dev = dev; + platform_set_drvdata(pdev, bdisp); + + if (dev->of_node) + bdisp->id = of_alias_get_id(pdev->dev.of_node, BDISP_NAME); + else + bdisp->id = pdev->id; + + init_waitqueue_head(&bdisp->irq_queue); + INIT_DELAYED_WORK(&bdisp->timeout_work, bdisp_irq_timeout); + bdisp->work_queue = create_workqueue(BDISP_NAME); + + spin_lock_init(&bdisp->slock); + mutex_init(&bdisp->lock); + + /* get resources */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + bdisp->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(bdisp->regs)) { + dev_err(dev, "failed to get regs\n"); + return PTR_ERR(bdisp->regs); + } + + bdisp->clock = devm_clk_get(dev, BDISP_NAME); + if (IS_ERR(bdisp->clock)) { + dev_err(dev, "failed to get clock\n"); + return PTR_ERR(bdisp->clock); + } + + ret = clk_prepare(bdisp->clock); + if (ret < 0) { + dev_err(dev, "clock prepare failed\n"); + bdisp->clock = ERR_PTR(-EINVAL); + return ret; + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(dev, "failed to get IRQ resource\n"); + goto err_clk; + } + + ret = devm_request_threaded_irq(dev, res->start, bdisp_irq_handler, + bdisp_irq_thread, IRQF_ONESHOT, + pdev->name, bdisp); + if (ret) { + dev_err(dev, "failed to install irq\n"); + goto err_clk; + } + + /* v4l2 register */ + ret = v4l2_device_register(dev, &bdisp->v4l2_dev); + if (ret) { + dev_err(dev, "failed to register\n"); + goto err_clk; + } + + /* Debug */ + ret = bdisp_debugfs_create(bdisp); + if (ret) { + dev_err(dev, "failed to create debugfs\n"); + goto err_v4l2; + } + + /* Power management */ + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + dev_err(dev, "failed to set PM\n"); + goto err_dbg; + } + + /* Continuous memory allocator */ + bdisp->alloc_ctx = vb2_dma_contig_init_ctx(dev); + if (IS_ERR(bdisp->alloc_ctx)) { + ret = PTR_ERR(bdisp->alloc_ctx); + goto err_pm; + } + + /* Filters */ + if (bdisp_hw_alloc_filters(bdisp->dev)) { + dev_err(bdisp->dev, "no memory for filters\n"); + ret = -ENOMEM; + goto err_vb2_dma; + } + + /* Register */ + ret = bdisp_register_device(bdisp); + if (ret) { + dev_err(dev, "failed to register\n"); + goto err_filter; + } + + dev_info(dev, "%s%d registered as /dev/video%d\n", BDISP_NAME, + bdisp->id, bdisp->vdev.num); + + pm_runtime_put(dev); + + return 0; + +err_filter: + bdisp_hw_free_filters(bdisp->dev); +err_vb2_dma: + vb2_dma_contig_cleanup_ctx(bdisp->alloc_ctx); +err_pm: + pm_runtime_put(dev); +err_dbg: + bdisp_debugfs_remove(bdisp); +err_v4l2: + v4l2_device_unregister(&bdisp->v4l2_dev); +err_clk: + if (!IS_ERR(bdisp->clock)) + clk_unprepare(bdisp->clock); + + return ret; +} + +static const struct of_device_id bdisp_match_types[] = { + { + .compatible = "st,stih407-bdisp", + }, + { /* end node */ } +}; + +MODULE_DEVICE_TABLE(of, bdisp_match_types); + +static struct platform_driver bdisp_driver = { + .probe = bdisp_probe, + .remove = bdisp_remove, + .driver = { + .name = BDISP_NAME, + .of_match_table = bdisp_match_types, + .pm = &bdisp_pm_ops, + }, +}; + +module_platform_driver(bdisp_driver); + +MODULE_DESCRIPTION("2D blitter for STMicroelectronics SoC"); +MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/sti/bdisp/bdisp.h b/drivers/media/platform/sti/bdisp/bdisp.h new file mode 100644 index 0000000..0cf9857 --- /dev/null +++ b/drivers/media/platform/sti/bdisp/bdisp.h @@ -0,0 +1,216 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include <linux/clk.h> +#include <linux/ktime.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-mem2mem.h> + +#include <media/videobuf2-dma-contig.h> + +#define BDISP_NAME "bdisp" + +/* + * Max nb of nodes in node-list: + * - 2 nodes to handle wide 4K pictures + * - 2 nodes to handle two planes (Y & CbCr) */ +#define MAX_OUTPUT_PLANES 2 +#define MAX_VERTICAL_STRIDES 2 +#define MAX_NB_NODE (MAX_OUTPUT_PLANES * MAX_VERTICAL_STRIDES) + +/* struct bdisp_ctrls - bdisp control set + * @hflip: horizontal flip + * @vflip: vertical flip + */ +struct bdisp_ctrls { + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; +}; + +/** + * struct bdisp_fmt - driver's internal color format data + * @pixelformat:fourcc code for this format + * @nb_planes: number of planes (ex: [0]=RGB/Y - [1]=Cb/Cr, ...) + * @bpp: bits per pixel (general) + * @bpp_plane0: byte per pixel for the 1st plane + * @w_align: width alignment in pixel (multiple of) + * @h_align: height alignment in pixel (multiple of) + */ +struct bdisp_fmt { + u32 pixelformat; + u8 nb_planes; + u8 bpp; + u8 bpp_plane0; + u8 w_align; + u8 h_align; +}; + +/** + * struct bdisp_frame - frame properties + * + * @width: frame width (including padding) + * @height: frame height (including padding) + * @fmt: pointer to frame format descriptor + * @field: frame / field type + * @bytesperline: stride of the 1st plane + * @sizeimage: image size in bytes + * @colorspace: colorspace + * @crop: crop area + * @paddr: image physical addresses per plane ([0]=RGB/Y - [1]=Cb/Cr, ...) + */ +struct bdisp_frame { + u32 width; + u32 height; + const struct bdisp_fmt *fmt; + enum v4l2_field field; + u32 bytesperline; + u32 sizeimage; + enum v4l2_colorspace colorspace; + struct v4l2_rect crop; + dma_addr_t paddr[4]; +}; + +/** + * struct bdisp_request - bdisp request + * + * @src: source frame properties + * @dst: destination frame properties + * @hflip: horizontal flip + * @vflip: vertical flip + * @nb_req: number of run request + */ +struct bdisp_request { + struct bdisp_frame src; + struct bdisp_frame dst; + unsigned int hflip:1; + unsigned int vflip:1; + int nb_req; +}; + +/** + * struct bdisp_ctx - device context data + * + * @src: source frame properties + * @dst: destination frame properties + * @state: flags to keep track of user configuration + * @hflip: horizontal flip + * @vflip: vertical flip + * @bdisp_dev: the device this context applies to + * @node: node array + * @node_paddr: node physical address array + * @fh: v4l2 file handle + * @ctrl_handler: v4l2 controls handler + * @bdisp_ctrls: bdisp control set + * @ctrls_rdy: true if the control handler is initialized + */ +struct bdisp_ctx { + struct bdisp_frame src; + struct bdisp_frame dst; + u32 state; + unsigned int hflip:1; + unsigned int vflip:1; + struct bdisp_dev *bdisp_dev; + struct bdisp_node *node[MAX_NB_NODE]; + dma_addr_t node_paddr[MAX_NB_NODE]; + struct v4l2_fh fh; + struct v4l2_ctrl_handler ctrl_handler; + struct bdisp_ctrls bdisp_ctrls; + bool ctrls_rdy; +}; + +/** + * struct bdisp_m2m_device - v4l2 memory-to-memory device data + * + * @vdev: video device node for v4l2 m2m mode + * @m2m_dev: v4l2 m2m device data + * @ctx: hardware context data + * @refcnt: reference counter + */ +struct bdisp_m2m_device { + struct video_device *vdev; + struct v4l2_m2m_dev *m2m_dev; + struct bdisp_ctx *ctx; + int refcnt; +}; + +/** + * struct bdisp_dbg - debug info + * + * @debugfs_entry: debugfs + * @copy_node: array of last used nodes + * @copy_request: last bdisp request + * @hw_start: start time of last HW request + * @last_duration: last HW processing duration in microsecs + * @min_duration: min HW processing duration in microsecs + * @max_duration: max HW processing duration in microsecs + * @tot_duration: total HW processing duration in microsecs + */ +struct bdisp_dbg { + struct dentry *debugfs_entry; + struct bdisp_node *copy_node[MAX_NB_NODE]; + struct bdisp_request copy_request; + ktime_t hw_start; + s64 last_duration; + s64 min_duration; + s64 max_duration; + s64 tot_duration; +}; + +/** + * struct bdisp_dev - abstraction for bdisp entity + * + * @v4l2_dev: v4l2 device + * @vdev: video device + * @pdev: platform device + * @dev: device + * @lock: mutex protecting this data structure + * @slock: spinlock protecting this data structure + * @id: device index + * @m2m: memory-to-memory V4L2 device information + * @state: flags used to synchronize m2m and capture mode operation + * @alloc_ctx: videobuf2 memory allocator context + * @clock: IP clock + * @regs: registers + * @irq_queue: interrupt handler waitqueue + * @work_queue: workqueue to handle timeouts + * @timeout_work: IRQ timeout structure + * @dbg: debug info + */ +struct bdisp_dev { + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct platform_device *pdev; + struct device *dev; + spinlock_t slock; + struct mutex lock; + u16 id; + struct bdisp_m2m_device m2m; + unsigned long state; + struct vb2_alloc_ctx *alloc_ctx; + struct clk *clock; + void __iomem *regs; + wait_queue_head_t irq_queue; + struct workqueue_struct *work_queue; + struct delayed_work timeout_work; + struct bdisp_dbg dbg; +}; + +void bdisp_hw_free_nodes(struct bdisp_ctx *ctx); +int bdisp_hw_alloc_nodes(struct bdisp_ctx *ctx); +void bdisp_hw_free_filters(struct device *dev); +int bdisp_hw_alloc_filters(struct device *dev); +int bdisp_hw_reset(struct bdisp_dev *bdisp); +int bdisp_hw_get_and_clear_irq(struct bdisp_dev *bdisp); +int bdisp_hw_update(struct bdisp_ctx *ctx); + +void bdisp_debugfs_remove(struct bdisp_dev *bdisp); +int bdisp_debugfs_create(struct bdisp_dev *bdisp); +void bdisp_dbg_perf_begin(struct bdisp_dev *bdisp); +void bdisp_dbg_perf_end(struct bdisp_dev *bdisp); diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index 678ed9f..32e4ff4 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -249,13 +249,15 @@ static int viacam_set_flip(struct via_camera *cam) */ static int viacam_configure_sensor(struct via_camera *cam) { - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int ret; - v4l2_fill_mbus_format(&mbus_fmt, &cam->sensor_format, cam->mbus_code); + v4l2_fill_mbus_format(&format.format, &cam->sensor_format, cam->mbus_code); ret = sensor_call(cam, core, init, 0); if (ret == 0) - ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt); + ret = sensor_call(cam, pad, set_fmt, NULL, &format); /* * OV7670 does weird things if flip is set *before* format... */ @@ -903,14 +905,17 @@ static int viacam_do_try_fmt(struct via_camera *cam, struct v4l2_pix_format *upix, struct v4l2_pix_format *spix) { int ret; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; struct via_format *f = via_find_format(upix->pixelformat); upix->pixelformat = f->pixelformat; viacam_fmt_pre(upix, spix); - v4l2_fill_mbus_format(&mbus_fmt, spix, f->mbus_code); - ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(spix, &mbus_fmt); + v4l2_fill_mbus_format(&format.format, spix, f->mbus_code); + ret = sensor_call(cam, pad, set_fmt, &pad_cfg, &format); + v4l2_fill_pix_format(spix, &format.format); viacam_fmt_post(upix, spix); return ret; } diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c index 4d6b4cc..295fde5 100644 --- a/drivers/media/platform/vim2m.c +++ b/drivers/media/platform/vim2m.c @@ -80,7 +80,6 @@ static struct platform_device vim2m_pdev = { }; struct vim2m_fmt { - char *name; u32 fourcc; int depth; /* Types the format can be used for */ @@ -89,14 +88,12 @@ struct vim2m_fmt { static struct vim2m_fmt formats[] = { { - .name = "RGB565 (BE)", .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ .depth = 16, /* Both capture and output format */ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, }, { - .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, /* Output-only format */ @@ -458,7 +455,6 @@ static int enum_fmt(struct v4l2_fmtdesc *f, u32 type) if (i < NUM_FORMATS) { /* Format found */ fmt = &formats[i]; - strncpy(f->description, fmt->name, sizeof(f->description) - 1); f->pixelformat = fmt->fourcc; return 0; } @@ -697,6 +693,8 @@ static const struct v4l2_ioctl_ops vim2m_ioctl_ops = { .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, .vidioc_streamon = v4l2_m2m_ioctl_streamon, @@ -724,6 +722,12 @@ static int vim2m_queue_setup(struct vb2_queue *vq, size = q_data->width * q_data->height * q_data->fmt->depth >> 3; + if (fmt) { + if (fmt->fmt.pix.sizeimage < size) + return -EINVAL; + size = fmt->fmt.pix.sizeimage; + } + while (size * count > MEM2MEM_VID_MEM_LIMIT) (count)--; diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index d33f164..a047b47 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -392,6 +392,17 @@ static int vidioc_s_parm(struct file *file, void *fh, return vivid_vid_out_g_parm(file, fh, parm); } +static int vidioc_log_status(struct file *file, void *fh) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + v4l2_ctrl_log_status(file, fh); + if (vdev->vfl_dir == VFL_DIR_RX && vdev->vfl_type == VFL_TYPE_GRABBER) + tpg_log_status(&dev->tpg); + return 0; +} + static ssize_t vivid_radio_read(struct file *file, char __user *buf, size_t size, loff_t *offset) { @@ -548,8 +559,8 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = { .vidioc_enum_fmt_sdr_cap = vidioc_enum_fmt_sdr_cap, .vidioc_g_fmt_sdr_cap = vidioc_g_fmt_sdr_cap, - .vidioc_try_fmt_sdr_cap = vidioc_g_fmt_sdr_cap, - .vidioc_s_fmt_sdr_cap = vidioc_g_fmt_sdr_cap, + .vidioc_try_fmt_sdr_cap = vidioc_try_fmt_sdr_cap, + .vidioc_s_fmt_sdr_cap = vidioc_s_fmt_sdr_cap, .vidioc_overlay = vidioc_overlay, .vidioc_enum_framesizes = vidioc_enum_framesizes, @@ -610,7 +621,7 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = { .vidioc_g_edid = vidioc_g_edid, .vidioc_s_edid = vidioc_s_edid, - .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_log_status = vidioc_log_status, .vidioc_subscribe_event = vidioc_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; @@ -966,6 +977,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->radio_tx_subchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_RDS; dev->sdr_adc_freq = 300000; dev->sdr_fm_freq = 50000000; + dev->sdr_pixelformat = V4L2_SDR_FMT_CU8; + dev->sdr_buffersize = SDR_CAP_SAMPLES_PER_BUF * 2; + dev->edid_max_blocks = dev->edid_blocks = 2; memcpy(dev->edid, vivid_hdmi_edid, sizeof(vivid_hdmi_edid)); ktime_get_ts(&dev->radio_rds_init_ts); diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index 9e15aee..c72349c 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -77,7 +77,6 @@ extern const struct v4l2_rect vivid_max_rect; extern unsigned vivid_debug; struct vivid_fmt { - const char *name; u32 fourcc; /* v4l2 format id */ bool is_yuv; bool can_do_overlay; @@ -140,7 +139,7 @@ struct vivid_dev { struct v4l2_ctrl_handler ctrl_hdl_user_aud; struct v4l2_ctrl_handler ctrl_hdl_streaming; struct v4l2_ctrl_handler ctrl_hdl_sdtv_cap; - struct v4l2_ctrl_handler ctrl_hdl_loop_out; + struct v4l2_ctrl_handler ctrl_hdl_loop_cap; struct video_device vid_cap_dev; struct v4l2_ctrl_handler ctrl_hdl_vid_cap; struct video_device vid_out_dev; @@ -333,6 +332,7 @@ struct vivid_dev { u32 colorspace_out; u32 ycbcr_enc_out; u32 quantization_out; + u32 xfer_func_out; u32 service_set_out; unsigned bytesperline_out[TPG_MAX_PLANES]; unsigned tv_field_out; @@ -447,6 +447,8 @@ struct vivid_dev { /* SDR capture */ struct vb2_queue vb_sdr_cap_q; struct list_head sdr_cap_active; + u32 sdr_pixelformat; /* v4l2 format id */ + unsigned sdr_buffersize; unsigned sdr_adc_freq; unsigned sdr_fm_freq; int sdr_fixp_src_phase; diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index 2b90700..339c8b7 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -62,21 +62,22 @@ #define VIVID_CID_DV_TIMINGS_ASPECT_RATIO (VIVID_CID_VIVID_BASE + 23) #define VIVID_CID_TSTAMP_SRC (VIVID_CID_VIVID_BASE + 24) #define VIVID_CID_COLORSPACE (VIVID_CID_VIVID_BASE + 25) -#define VIVID_CID_YCBCR_ENC (VIVID_CID_VIVID_BASE + 26) -#define VIVID_CID_QUANTIZATION (VIVID_CID_VIVID_BASE + 27) -#define VIVID_CID_LIMITED_RGB_RANGE (VIVID_CID_VIVID_BASE + 28) -#define VIVID_CID_ALPHA_MODE (VIVID_CID_VIVID_BASE + 29) -#define VIVID_CID_HAS_CROP_CAP (VIVID_CID_VIVID_BASE + 30) -#define VIVID_CID_HAS_COMPOSE_CAP (VIVID_CID_VIVID_BASE + 31) -#define VIVID_CID_HAS_SCALER_CAP (VIVID_CID_VIVID_BASE + 32) -#define VIVID_CID_HAS_CROP_OUT (VIVID_CID_VIVID_BASE + 33) -#define VIVID_CID_HAS_COMPOSE_OUT (VIVID_CID_VIVID_BASE + 34) -#define VIVID_CID_HAS_SCALER_OUT (VIVID_CID_VIVID_BASE + 35) -#define VIVID_CID_LOOP_VIDEO (VIVID_CID_VIVID_BASE + 36) -#define VIVID_CID_SEQ_WRAP (VIVID_CID_VIVID_BASE + 37) -#define VIVID_CID_TIME_WRAP (VIVID_CID_VIVID_BASE + 38) -#define VIVID_CID_MAX_EDID_BLOCKS (VIVID_CID_VIVID_BASE + 39) -#define VIVID_CID_PERCENTAGE_FILL (VIVID_CID_VIVID_BASE + 40) +#define VIVID_CID_XFER_FUNC (VIVID_CID_VIVID_BASE + 26) +#define VIVID_CID_YCBCR_ENC (VIVID_CID_VIVID_BASE + 27) +#define VIVID_CID_QUANTIZATION (VIVID_CID_VIVID_BASE + 28) +#define VIVID_CID_LIMITED_RGB_RANGE (VIVID_CID_VIVID_BASE + 29) +#define VIVID_CID_ALPHA_MODE (VIVID_CID_VIVID_BASE + 30) +#define VIVID_CID_HAS_CROP_CAP (VIVID_CID_VIVID_BASE + 31) +#define VIVID_CID_HAS_COMPOSE_CAP (VIVID_CID_VIVID_BASE + 32) +#define VIVID_CID_HAS_SCALER_CAP (VIVID_CID_VIVID_BASE + 33) +#define VIVID_CID_HAS_CROP_OUT (VIVID_CID_VIVID_BASE + 34) +#define VIVID_CID_HAS_COMPOSE_OUT (VIVID_CID_VIVID_BASE + 35) +#define VIVID_CID_HAS_SCALER_OUT (VIVID_CID_VIVID_BASE + 36) +#define VIVID_CID_LOOP_VIDEO (VIVID_CID_VIVID_BASE + 37) +#define VIVID_CID_SEQ_WRAP (VIVID_CID_VIVID_BASE + 38) +#define VIVID_CID_TIME_WRAP (VIVID_CID_VIVID_BASE + 39) +#define VIVID_CID_MAX_EDID_BLOCKS (VIVID_CID_VIVID_BASE + 40) +#define VIVID_CID_PERCENTAGE_FILL (VIVID_CID_VIVID_BASE + 41) #define VIVID_CID_STD_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 60) #define VIVID_CID_STANDARD (VIVID_CID_VIVID_BASE + 61) @@ -360,6 +361,13 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl) vivid_send_source_change(dev, HDMI); vivid_send_source_change(dev, WEBCAM); break; + case VIVID_CID_XFER_FUNC: + tpg_s_xfer_func(&dev->tpg, ctrl->val); + vivid_send_source_change(dev, TV); + vivid_send_source_change(dev, SVID); + vivid_send_source_change(dev, HDMI); + vivid_send_source_change(dev, WEBCAM); + break; case VIVID_CID_YCBCR_ENC: tpg_s_ycbcr_enc(&dev->tpg, ctrl->val); vivid_send_source_change(dev, TV); @@ -709,6 +717,25 @@ static const struct v4l2_ctrl_config vivid_ctrl_colorspace = { .qmenu = vivid_ctrl_colorspace_strings, }; +static const char * const vivid_ctrl_xfer_func_strings[] = { + "Default", + "Rec. 709", + "sRGB", + "AdobeRGB", + "SMPTE 240M", + "None", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_xfer_func = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_XFER_FUNC, + .name = "Transfer Function", + .type = V4L2_CTRL_TYPE_MENU, + .max = 5, + .qmenu = vivid_ctrl_xfer_func_strings, +}; + static const char * const vivid_ctrl_ycbcr_enc_strings[] = { "Default", "ITU-R 601", @@ -766,6 +793,37 @@ static const struct v4l2_ctrl_config vivid_ctrl_limited_rgb_range = { }; +/* Video Loop Control */ + +static int vivid_loop_cap_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_loop_cap); + + switch (ctrl->id) { + case VIVID_CID_LOOP_VIDEO: + dev->loop_video = ctrl->val; + vivid_update_quality(dev); + vivid_send_source_change(dev, SVID); + vivid_send_source_change(dev, HDMI); + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_loop_cap_ctrl_ops = { + .s_ctrl = vivid_loop_cap_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_loop_video = { + .ops = &vivid_loop_cap_ctrl_ops, + .id = VIVID_CID_LOOP_VIDEO, + .name = "Loop Video", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + + /* VBI Capture Control */ static int vivid_vbi_cap_s_ctrl(struct v4l2_ctrl *ctrl) @@ -1199,38 +1257,6 @@ static const struct v4l2_ctrl_config vivid_ctrl_radio_tx_rds_blockio = { }; - -/* Video Loop Control */ - -static int vivid_loop_out_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_loop_out); - - switch (ctrl->id) { - case VIVID_CID_LOOP_VIDEO: - dev->loop_video = ctrl->val; - vivid_update_quality(dev); - vivid_send_source_change(dev, SVID); - vivid_send_source_change(dev, HDMI); - break; - } - return 0; -} - -static const struct v4l2_ctrl_ops vivid_loop_out_ctrl_ops = { - .s_ctrl = vivid_loop_out_s_ctrl, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_loop_video = { - .ops = &vivid_loop_out_ctrl_ops, - .id = VIVID_CID_LOOP_VIDEO, - .name = "Loop Video", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, -}; - - static const struct v4l2_ctrl_config vivid_ctrl_class = { .ops = &vivid_user_gen_ctrl_ops, .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY, @@ -1248,7 +1274,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, struct v4l2_ctrl_handler *hdl_user_aud = &dev->ctrl_hdl_user_aud; struct v4l2_ctrl_handler *hdl_streaming = &dev->ctrl_hdl_streaming; struct v4l2_ctrl_handler *hdl_sdtv_cap = &dev->ctrl_hdl_sdtv_cap; - struct v4l2_ctrl_handler *hdl_loop_out = &dev->ctrl_hdl_loop_out; + struct v4l2_ctrl_handler *hdl_loop_cap = &dev->ctrl_hdl_loop_cap; struct v4l2_ctrl_handler *hdl_vid_cap = &dev->ctrl_hdl_vid_cap; struct v4l2_ctrl_handler *hdl_vid_out = &dev->ctrl_hdl_vid_out; struct v4l2_ctrl_handler *hdl_vbi_cap = &dev->ctrl_hdl_vbi_cap; @@ -1274,8 +1300,8 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_class, NULL); v4l2_ctrl_handler_init(hdl_sdtv_cap, 2); v4l2_ctrl_new_custom(hdl_sdtv_cap, &vivid_ctrl_class, NULL); - v4l2_ctrl_handler_init(hdl_loop_out, 1); - v4l2_ctrl_new_custom(hdl_loop_out, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_loop_cap, 1); + v4l2_ctrl_new_custom(hdl_loop_cap, &vivid_ctrl_class, NULL); v4l2_ctrl_handler_init(hdl_vid_cap, 55); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_class, NULL); v4l2_ctrl_handler_init(hdl_vid_out, 26); @@ -1365,6 +1391,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_tstamp_src, NULL); dev->colorspace = v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_colorspace, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_xfer_func, NULL); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_ycbcr_enc, NULL); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_quantization, NULL); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_alpha_mode, NULL); @@ -1445,7 +1472,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, } if ((dev->has_vid_cap && dev->has_vid_out) || (dev->has_vbi_cap && dev->has_vbi_out)) - v4l2_ctrl_new_custom(hdl_loop_out, &vivid_ctrl_loop_video, NULL); + v4l2_ctrl_new_custom(hdl_loop_cap, &vivid_ctrl_loop_video, NULL); if (dev->has_fb) v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_clear_fb, NULL); @@ -1528,8 +1555,8 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, return hdl_streaming->error; if (hdl_sdr_cap->error) return hdl_sdr_cap->error; - if (hdl_loop_out->error) - return hdl_loop_out->error; + if (hdl_loop_cap->error) + return hdl_loop_cap->error; if (dev->autogain) v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true); @@ -1540,6 +1567,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_aud, NULL); v4l2_ctrl_add_handler(hdl_vid_cap, hdl_streaming, NULL); v4l2_ctrl_add_handler(hdl_vid_cap, hdl_sdtv_cap, NULL); + v4l2_ctrl_add_handler(hdl_vid_cap, hdl_loop_cap, NULL); if (hdl_vid_cap->error) return hdl_vid_cap->error; dev->vid_cap_dev.ctrl_handler = hdl_vid_cap; @@ -1548,7 +1576,6 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_gen, NULL); v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_aud, NULL); v4l2_ctrl_add_handler(hdl_vid_out, hdl_streaming, NULL); - v4l2_ctrl_add_handler(hdl_vid_out, hdl_loop_out, NULL); if (hdl_vid_out->error) return hdl_vid_out->error; dev->vid_out_dev.ctrl_handler = hdl_vid_out; @@ -1557,6 +1584,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_user_gen, NULL); v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_streaming, NULL); v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_sdtv_cap, NULL); + v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_loop_cap, NULL); if (hdl_vbi_cap->error) return hdl_vbi_cap->error; dev->vbi_cap_dev.ctrl_handler = hdl_vbi_cap; @@ -1564,7 +1592,6 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, if (dev->has_vbi_out) { v4l2_ctrl_add_handler(hdl_vbi_out, hdl_user_gen, NULL); v4l2_ctrl_add_handler(hdl_vbi_out, hdl_streaming, NULL); - v4l2_ctrl_add_handler(hdl_vbi_out, hdl_loop_out, NULL); if (hdl_vbi_out->error) return hdl_vbi_out->error; dev->vbi_out_dev.ctrl_handler = hdl_vbi_out; @@ -1607,5 +1634,5 @@ void vivid_free_controls(struct vivid_dev *dev) v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_aud); v4l2_ctrl_handler_free(&dev->ctrl_hdl_streaming); v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdtv_cap); - v4l2_ctrl_handler_free(&dev->ctrl_hdl_loop_out); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_loop_cap); } diff --git a/drivers/media/platform/vivid/vivid-radio-rx.c b/drivers/media/platform/vivid/vivid-radio-rx.c index c7651a5..f99092c 100644 --- a/drivers/media/platform/vivid/vivid-radio-rx.c +++ b/drivers/media/platform/vivid/vivid-radio-rx.c @@ -195,6 +195,8 @@ int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2 if (dev->radio_rx_freq >= vivid_radio_bands[band].rangelow && dev->radio_rx_freq <= vivid_radio_bands[band].rangehigh) break; + if (band == TOT_BANDS) + return -EINVAL; low = vivid_radio_bands[band].rangelow; high = vivid_radio_bands[band].rangehigh; } diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c index caf1316..d2f2188 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.c +++ b/drivers/media/platform/vivid/vivid-sdr-cap.c @@ -33,6 +33,25 @@ #include "vivid-ctrls.h" #include "vivid-sdr-cap.h" +/* stream formats */ +struct vivid_format { + u32 pixelformat; + u32 buffersize; +}; + +/* format descriptions for capture and preview */ +static struct vivid_format formats[] = { + { + .pixelformat = V4L2_SDR_FMT_CU8, + .buffersize = SDR_CAP_SAMPLES_PER_BUF * 2, + }, { + .pixelformat = V4L2_SDR_FMT_CS8, + .buffersize = SDR_CAP_SAMPLES_PER_BUF * 2, + }, +}; + +static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats); + static const struct v4l2_frequency_band bands_adc[] = { { .tuner = 0, @@ -409,21 +428,63 @@ int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - if (f->index) + if (f->index >= ARRAY_SIZE(formats)) return -EINVAL; - f->pixelformat = V4L2_SDR_FMT_CU8; - strlcpy(f->description, "IQ U8", sizeof(f->description)); + f->pixelformat = formats[f->index].pixelformat; return 0; } int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) { - f->fmt.sdr.pixelformat = V4L2_SDR_FMT_CU8; - f->fmt.sdr.buffersize = SDR_CAP_SAMPLES_PER_BUF * 2; + struct vivid_dev *dev = video_drvdata(file); + + f->fmt.sdr.pixelformat = dev->sdr_pixelformat; + f->fmt.sdr.buffersize = dev->sdr_buffersize; memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); return 0; } +int vidioc_s_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct vb2_queue *q = &dev->vb_sdr_cap_q; + int i; + + if (vb2_is_busy(q)) + return -EBUSY; + + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); + for (i = 0; i < ARRAY_SIZE(formats); i++) { + if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { + dev->sdr_pixelformat = formats[i].pixelformat; + dev->sdr_buffersize = formats[i].buffersize; + f->fmt.sdr.buffersize = formats[i].buffersize; + return 0; + } + } + dev->sdr_pixelformat = formats[0].pixelformat; + dev->sdr_buffersize = formats[0].buffersize; + f->fmt.sdr.pixelformat = formats[0].pixelformat; + f->fmt.sdr.buffersize = formats[0].buffersize; + return 0; +} + +int vidioc_try_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + int i; + + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); + for (i = 0; i < ARRAY_SIZE(formats); i++) { + if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { + f->fmt.sdr.buffersize = formats[i].buffersize; + return 0; + } + } + f->fmt.sdr.pixelformat = formats[0].pixelformat; + f->fmt.sdr.buffersize = formats[0].buffersize; + return 0; +} + #define FIXP_N (15) #define FIXP_FRAC (1 << FIXP_N) #define FIXP_2PI ((int)(2 * 3.141592653589 * FIXP_FRAC)) @@ -477,11 +538,24 @@ void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) fixp_i >>= (31 - FIXP_N); fixp_q >>= (31 - FIXP_N); - /* convert 'fixp float' to u8 */ - /* u8 = X * 127.5f + 127.5f; where X is float [-1.0 / +1.0] */ - fixp_i = fixp_i * 1275 + FIXP_FRAC * 1275; - fixp_q = fixp_q * 1275 + FIXP_FRAC * 1275; - *vbuf++ = DIV_ROUND_CLOSEST(fixp_i, FIXP_FRAC * 10); - *vbuf++ = DIV_ROUND_CLOSEST(fixp_q, FIXP_FRAC * 10); + switch (dev->sdr_pixelformat) { + case V4L2_SDR_FMT_CU8: + /* convert 'fixp float' to u8 */ + /* u8 = X * 127.5 + 127.5; X is float [-1.0, +1.0] */ + fixp_i = fixp_i * 1275 + FIXP_FRAC * 1275; + fixp_q = fixp_q * 1275 + FIXP_FRAC * 1275; + *vbuf++ = DIV_ROUND_CLOSEST(fixp_i, FIXP_FRAC * 10); + *vbuf++ = DIV_ROUND_CLOSEST(fixp_q, FIXP_FRAC * 10); + break; + case V4L2_SDR_FMT_CS8: + /* convert 'fixp float' to s8 */ + fixp_i = fixp_i * 1275; + fixp_q = fixp_q * 1275; + *vbuf++ = DIV_ROUND_CLOSEST(fixp_i, FIXP_FRAC * 10); + *vbuf++ = DIV_ROUND_CLOSEST(fixp_q, FIXP_FRAC * 10); + break; + default: + break; + } } } diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.h b/drivers/media/platform/vivid/vivid-sdr-cap.h index 79c1890..43014b2 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.h +++ b/drivers/media/platform/vivid/vivid-sdr-cap.h @@ -27,6 +27,8 @@ int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt); int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt); int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f); int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f); +int vidioc_s_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f); +int vidioc_try_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f); void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf); extern const struct vb2_ops vivid_sdr_cap_qops; diff --git a/drivers/media/platform/vivid/vivid-tpg-colors.c b/drivers/media/platform/vivid/vivid-tpg-colors.c index 424aa7a..8f231a6 100644 --- a/drivers/media/platform/vivid/vivid-tpg-colors.c +++ b/drivers/media/platform/vivid/vivid-tpg-colors.c @@ -598,71 +598,327 @@ const unsigned short tpg_linear_to_rec709[255 * 16 + 1] = { }; /* Generated table */ -const struct color16 tpg_csc_colors[V4L2_COLORSPACE_BT2020 + 1][TPG_COLOR_CSC_BLACK + 1] = { - [V4L2_COLORSPACE_SMPTE170M][0] = { 2939, 2939, 2939 }, - [V4L2_COLORSPACE_SMPTE170M][1] = { 2953, 2963, 586 }, - [V4L2_COLORSPACE_SMPTE170M][2] = { 0, 2967, 2937 }, - [V4L2_COLORSPACE_SMPTE170M][3] = { 88, 2990, 575 }, - [V4L2_COLORSPACE_SMPTE170M][4] = { 3016, 259, 2933 }, - [V4L2_COLORSPACE_SMPTE170M][5] = { 3030, 405, 558 }, - [V4L2_COLORSPACE_SMPTE170M][6] = { 478, 428, 2931 }, - [V4L2_COLORSPACE_SMPTE170M][7] = { 547, 547, 547 }, - [V4L2_COLORSPACE_SMPTE240M][0] = { 2926, 2926, 2926 }, - [V4L2_COLORSPACE_SMPTE240M][1] = { 2941, 2950, 546 }, - [V4L2_COLORSPACE_SMPTE240M][2] = { 0, 2954, 2924 }, - [V4L2_COLORSPACE_SMPTE240M][3] = { 78, 2978, 536 }, - [V4L2_COLORSPACE_SMPTE240M][4] = { 3004, 230, 2920 }, - [V4L2_COLORSPACE_SMPTE240M][5] = { 3018, 363, 518 }, - [V4L2_COLORSPACE_SMPTE240M][6] = { 437, 387, 2918 }, - [V4L2_COLORSPACE_SMPTE240M][7] = { 507, 507, 507 }, - [V4L2_COLORSPACE_REC709][0] = { 2939, 2939, 2939 }, - [V4L2_COLORSPACE_REC709][1] = { 2939, 2939, 547 }, - [V4L2_COLORSPACE_REC709][2] = { 547, 2939, 2939 }, - [V4L2_COLORSPACE_REC709][3] = { 547, 2939, 547 }, - [V4L2_COLORSPACE_REC709][4] = { 2939, 547, 2939 }, - [V4L2_COLORSPACE_REC709][5] = { 2939, 547, 547 }, - [V4L2_COLORSPACE_REC709][6] = { 547, 547, 2939 }, - [V4L2_COLORSPACE_REC709][7] = { 547, 547, 547 }, - [V4L2_COLORSPACE_470_SYSTEM_M][0] = { 2892, 2988, 2807 }, - [V4L2_COLORSPACE_470_SYSTEM_M][1] = { 2846, 3070, 843 }, - [V4L2_COLORSPACE_470_SYSTEM_M][2] = { 1656, 2962, 2783 }, - [V4L2_COLORSPACE_470_SYSTEM_M][3] = { 1572, 3045, 763 }, - [V4L2_COLORSPACE_470_SYSTEM_M][4] = { 2476, 229, 2742 }, - [V4L2_COLORSPACE_470_SYSTEM_M][5] = { 2420, 672, 614 }, - [V4L2_COLORSPACE_470_SYSTEM_M][6] = { 725, 63, 2718 }, - [V4L2_COLORSPACE_470_SYSTEM_M][7] = { 534, 561, 509 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][0] = { 2939, 2939, 2939 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][1] = { 2939, 2939, 464 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][2] = { 786, 2939, 2939 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][3] = { 786, 2939, 464 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][4] = { 2879, 547, 2956 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][5] = { 2879, 547, 547 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][6] = { 547, 547, 2956 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][7] = { 547, 547, 547 }, - [V4L2_COLORSPACE_SRGB][0] = { 3056, 3056, 3056 }, - [V4L2_COLORSPACE_SRGB][1] = { 3056, 3056, 800 }, - [V4L2_COLORSPACE_SRGB][2] = { 800, 3056, 3056 }, - [V4L2_COLORSPACE_SRGB][3] = { 800, 3056, 800 }, - [V4L2_COLORSPACE_SRGB][4] = { 3056, 800, 3056 }, - [V4L2_COLORSPACE_SRGB][5] = { 3056, 800, 800 }, - [V4L2_COLORSPACE_SRGB][6] = { 800, 800, 3056 }, - [V4L2_COLORSPACE_SRGB][7] = { 800, 800, 800 }, - [V4L2_COLORSPACE_ADOBERGB][0] = { 3033, 3033, 3033 }, - [V4L2_COLORSPACE_ADOBERGB][1] = { 3033, 3033, 1063 }, - [V4L2_COLORSPACE_ADOBERGB][2] = { 1828, 3033, 3033 }, - [V4L2_COLORSPACE_ADOBERGB][3] = { 1828, 3033, 1063 }, - [V4L2_COLORSPACE_ADOBERGB][4] = { 2633, 851, 2979 }, - [V4L2_COLORSPACE_ADOBERGB][5] = { 2633, 851, 851 }, - [V4L2_COLORSPACE_ADOBERGB][6] = { 851, 851, 2979 }, - [V4L2_COLORSPACE_ADOBERGB][7] = { 851, 851, 851 }, - [V4L2_COLORSPACE_BT2020][0] = { 2939, 2939, 2939 }, - [V4L2_COLORSPACE_BT2020][1] = { 2877, 2923, 1058 }, - [V4L2_COLORSPACE_BT2020][2] = { 1837, 2840, 2916 }, - [V4L2_COLORSPACE_BT2020][3] = { 1734, 2823, 993 }, - [V4L2_COLORSPACE_BT2020][4] = { 2427, 961, 2812 }, - [V4L2_COLORSPACE_BT2020][5] = { 2351, 912, 648 }, - [V4L2_COLORSPACE_BT2020][6] = { 792, 618, 2788 }, - [V4L2_COLORSPACE_BT2020][7] = { 547, 547, 547 }, +const struct color16 tpg_csc_colors[V4L2_COLORSPACE_BT2020 + 1][V4L2_XFER_FUNC_NONE + 1][TPG_COLOR_CSC_BLACK + 1] = { + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][1] = { 2953, 2963, 586 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][2] = { 0, 2967, 2937 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][3] = { 88, 2990, 575 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][4] = { 3016, 259, 2933 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][5] = { 3030, 405, 558 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][6] = { 478, 428, 2931 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][1] = { 3068, 3077, 838 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][2] = { 0, 3081, 3053 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][3] = { 241, 3102, 828 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][4] = { 3126, 504, 3050 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][5] = { 3138, 657, 810 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][6] = { 731, 680, 3048 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][7] = { 800, 799, 800 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][1] = { 3046, 3054, 886 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][2] = { 0, 3058, 3031 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][3] = { 360, 3079, 877 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][4] = { 3103, 587, 3027 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][5] = { 3116, 723, 861 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][6] = { 789, 744, 3025 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][1] = { 2941, 2950, 546 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][2] = { 0, 2954, 2924 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][3] = { 78, 2978, 536 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][4] = { 3004, 230, 2920 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][5] = { 3018, 363, 518 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][6] = { 437, 387, 2918 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][1] = { 2145, 2159, 142 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][2] = { 0, 2164, 2122 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][3] = { 19, 2198, 138 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][4] = { 2236, 57, 2116 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][5] = { 2256, 90, 133 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][6] = { 110, 96, 2113 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][1] = { 2953, 2963, 586 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][2] = { 0, 2967, 2937 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][3] = { 88, 2990, 575 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][4] = { 3016, 259, 2933 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][5] = { 3030, 405, 558 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][6] = { 478, 428, 2931 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][1] = { 3068, 3077, 838 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][2] = { 0, 3081, 3053 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][3] = { 241, 3102, 828 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][4] = { 3126, 504, 3050 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][5] = { 3138, 657, 810 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][6] = { 731, 680, 3048 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][7] = { 800, 799, 800 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][1] = { 3046, 3054, 886 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][2] = { 0, 3058, 3031 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][3] = { 360, 3079, 877 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][4] = { 3103, 587, 3027 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][5] = { 3116, 723, 861 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][6] = { 789, 744, 3025 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][1] = { 2941, 2950, 546 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][2] = { 0, 2954, 2924 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][3] = { 78, 2978, 536 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][4] = { 3004, 230, 2920 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][5] = { 3018, 363, 518 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][6] = { 437, 387, 2918 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][1] = { 2145, 2159, 142 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][2] = { 0, 2164, 2122 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][3] = { 19, 2198, 138 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][4] = { 2236, 57, 2116 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][5] = { 2256, 90, 133 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][6] = { 110, 96, 2113 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 547 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][2] = { 547, 2939, 2939 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][3] = { 547, 2939, 547 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][4] = { 2939, 547, 2939 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][5] = { 2939, 547, 547 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][6] = { 547, 547, 2939 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][1] = { 3056, 3056, 800 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][2] = { 800, 3056, 3056 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][3] = { 800, 3056, 800 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][4] = { 3056, 800, 3056 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][5] = { 3056, 800, 800 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3056 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 851 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][2] = { 851, 3033, 3033 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][3] = { 851, 3033, 851 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][4] = { 3033, 851, 3033 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][5] = { 3033, 851, 851 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 3033 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 507 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][2] = { 507, 2926, 2926 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][3] = { 507, 2926, 507 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][4] = { 2926, 507, 2926 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][5] = { 2926, 507, 507 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][6] = { 507, 507, 2926 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][1] = { 2125, 2125, 130 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][2] = { 130, 2125, 2125 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][3] = { 130, 2125, 130 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][4] = { 2125, 130, 2125 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][5] = { 2125, 130, 130 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][6] = { 130, 130, 2125 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][0] = { 2892, 2988, 2807 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][1] = { 2846, 3070, 843 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][2] = { 1656, 2962, 2783 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][3] = { 1572, 3045, 763 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][4] = { 2476, 229, 2742 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][5] = { 2420, 672, 614 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][6] = { 725, 63, 2718 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][7] = { 534, 561, 509 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][0] = { 3013, 3099, 2935 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][1] = { 2970, 3174, 1091 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][2] = { 1871, 3076, 2913 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][3] = { 1791, 3152, 1013 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][4] = { 2632, 468, 2876 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][5] = { 2581, 924, 866 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][6] = { 976, 180, 2854 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][7] = { 786, 813, 762 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][0] = { 2990, 3077, 2912 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][1] = { 2947, 3153, 1119 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][2] = { 1859, 3053, 2889 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][3] = { 1782, 3130, 1047 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][4] = { 2608, 556, 2852 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][5] = { 2557, 964, 912 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][6] = { 1013, 309, 2830 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][7] = { 839, 864, 817 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][0] = { 2879, 2975, 2793 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][1] = { 2832, 3059, 806 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][2] = { 1629, 2949, 2768 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][3] = { 1543, 3033, 725 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][4] = { 2457, 203, 2727 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][5] = { 2401, 633, 574 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][6] = { 687, 56, 2702 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][7] = { 493, 521, 469 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][0] = { 2060, 2194, 1943 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][1] = { 1995, 2314, 237 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][2] = { 725, 2157, 1911 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][3] = { 660, 2278, 205 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][4] = { 1525, 50, 1857 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][5] = { 1461, 171, 151 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][6] = { 190, 14, 1825 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_NONE][7] = { 126, 134, 118 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 464 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][2] = { 786, 2939, 2939 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][3] = { 786, 2939, 464 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][4] = { 2879, 547, 2956 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][5] = { 2879, 547, 547 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][6] = { 547, 547, 2956 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][1] = { 3056, 3056, 717 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][2] = { 1036, 3056, 3056 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][3] = { 1036, 3056, 717 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][4] = { 3001, 800, 3071 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][5] = { 3001, 800, 799 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3071 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 799 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 776 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][2] = { 1068, 3033, 3033 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][3] = { 1068, 3033, 776 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][4] = { 2977, 851, 3048 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][5] = { 2977, 851, 851 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 3048 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 423 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][2] = { 749, 2926, 2926 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][3] = { 749, 2926, 423 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][4] = { 2865, 507, 2943 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][5] = { 2865, 507, 507 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][6] = { 507, 507, 2943 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][1] = { 2125, 2125, 106 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][2] = { 214, 2125, 2125 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][3] = { 214, 2125, 106 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][4] = { 2041, 130, 2149 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][5] = { 2041, 130, 130 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][6] = { 130, 130, 2149 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 547 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][2] = { 547, 2939, 2939 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][3] = { 547, 2939, 547 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][4] = { 2939, 547, 2939 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][5] = { 2939, 547, 547 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][6] = { 547, 547, 2939 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][1] = { 3056, 3056, 800 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][2] = { 800, 3056, 3056 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][3] = { 800, 3056, 800 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][4] = { 3056, 800, 3056 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][5] = { 3056, 800, 800 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3056 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 851 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][2] = { 851, 3033, 3033 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][3] = { 851, 3033, 851 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][4] = { 3033, 851, 3033 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][5] = { 3033, 851, 851 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 3033 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 507 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][2] = { 507, 2926, 2926 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][3] = { 507, 2926, 507 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][4] = { 2926, 507, 2926 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][5] = { 2926, 507, 507 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][6] = { 507, 507, 2926 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][1] = { 2125, 2125, 130 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][2] = { 130, 2125, 2125 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][3] = { 130, 2125, 130 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][4] = { 2125, 130, 2125 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][5] = { 2125, 130, 130 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][6] = { 130, 130, 2125 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 781 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][2] = { 1622, 2939, 2939 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][3] = { 1622, 2939, 781 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][4] = { 2502, 547, 2881 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][5] = { 2502, 547, 547 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][6] = { 547, 547, 2881 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][1] = { 3056, 3056, 1031 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][2] = { 1838, 3056, 3056 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][3] = { 1838, 3056, 1031 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][4] = { 2657, 800, 3002 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][5] = { 2657, 800, 800 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3002 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 1063 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][2] = { 1828, 3033, 3033 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][3] = { 1828, 3033, 1063 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][4] = { 2633, 851, 2979 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][5] = { 2633, 851, 851 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 2979 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 744 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][2] = { 1594, 2926, 2926 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][3] = { 1594, 2926, 744 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][4] = { 2484, 507, 2867 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][5] = { 2484, 507, 507 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][6] = { 507, 507, 2867 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][1] = { 2125, 2125, 212 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][2] = { 698, 2125, 2125 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][3] = { 698, 2125, 212 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][4] = { 1557, 130, 2043 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][5] = { 1557, 130, 130 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][6] = { 130, 130, 2043 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][1] = { 2877, 2923, 1058 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][2] = { 1837, 2840, 2916 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][3] = { 1734, 2823, 993 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][4] = { 2427, 961, 2812 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][5] = { 2351, 912, 648 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][6] = { 792, 618, 2788 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][1] = { 2999, 3041, 1301 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][2] = { 2040, 2965, 3034 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][3] = { 1944, 2950, 1238 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][4] = { 2587, 1207, 2940 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][5] = { 2517, 1159, 900 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][6] = { 1042, 870, 2917 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][1] = { 2976, 3018, 1315 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][2] = { 2024, 2942, 3011 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][3] = { 1930, 2926, 1256 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][4] = { 2563, 1227, 2916 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][5] = { 2494, 1183, 943 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][6] = { 1073, 916, 2894 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][1] = { 2864, 2910, 1024 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][2] = { 1811, 2826, 2903 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][3] = { 1707, 2809, 958 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][4] = { 2408, 926, 2798 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][5] = { 2331, 876, 609 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][6] = { 755, 579, 2773 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][1] = { 2039, 2102, 338 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][2] = { 873, 1987, 2092 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][3] = { 787, 1965, 305 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][4] = { 1468, 290, 1949 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][5] = { 1382, 268, 162 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][6] = { 216, 152, 1917 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 }, }; #else @@ -764,50 +1020,38 @@ static double transfer_srgb_to_rec709(double v) return transfer_rgb_to_rec709(transfer_srgb_to_rgb(v)); } -static void csc(enum v4l2_colorspace colorspace, double *r, double *g, double *b) +static void csc(enum v4l2_colorspace colorspace, enum v4l2_xfer_func xfer_func, + double *r, double *g, double *b) { int clamp = 1; + *r = transfer_srgb_to_rgb(*r); + *g = transfer_srgb_to_rgb(*g); + *b = transfer_srgb_to_rgb(*b); + /* Convert the primaries of Rec. 709 Linear RGB */ switch (colorspace) { case V4L2_COLORSPACE_SMPTE240M: - *r = transfer_srgb_to_rgb(*r); - *g = transfer_srgb_to_rgb(*g); - *b = transfer_srgb_to_rgb(*b); mult_matrix(r, g, b, rec709_to_240m); break; case V4L2_COLORSPACE_SMPTE170M: - *r = transfer_srgb_to_rgb(*r); - *g = transfer_srgb_to_rgb(*g); - *b = transfer_srgb_to_rgb(*b); mult_matrix(r, g, b, rec709_to_170m); break; case V4L2_COLORSPACE_470_SYSTEM_BG: - *r = transfer_srgb_to_rgb(*r); - *g = transfer_srgb_to_rgb(*g); - *b = transfer_srgb_to_rgb(*b); mult_matrix(r, g, b, rec709_to_ebu); break; case V4L2_COLORSPACE_470_SYSTEM_M: - *r = transfer_srgb_to_rgb(*r); - *g = transfer_srgb_to_rgb(*g); - *b = transfer_srgb_to_rgb(*b); mult_matrix(r, g, b, rec709_to_ntsc1953); break; case V4L2_COLORSPACE_ADOBERGB: - *r = transfer_srgb_to_rgb(*r); - *g = transfer_srgb_to_rgb(*g); - *b = transfer_srgb_to_rgb(*b); mult_matrix(r, g, b, rec709_to_adobergb); break; case V4L2_COLORSPACE_BT2020: - *r = transfer_srgb_to_rgb(*r); - *g = transfer_srgb_to_rgb(*g); - *b = transfer_srgb_to_rgb(*b); mult_matrix(r, g, b, rec709_to_bt2020); break; case V4L2_COLORSPACE_SRGB: case V4L2_COLORSPACE_REC709: + break; default: break; } @@ -818,33 +1062,28 @@ static void csc(enum v4l2_colorspace colorspace, double *r, double *g, double *b *b = ((*b) < 0) ? 0 : (((*b) > 1) ? 1 : (*b)); } - /* Encode to gamma corrected colorspace */ - switch (colorspace) { - case V4L2_COLORSPACE_SMPTE240M: - *r = transfer_rgb_to_smpte240m(*r); - *g = transfer_rgb_to_smpte240m(*g); - *b = transfer_rgb_to_smpte240m(*b); - break; - case V4L2_COLORSPACE_SMPTE170M: - case V4L2_COLORSPACE_470_SYSTEM_M: - case V4L2_COLORSPACE_470_SYSTEM_BG: - case V4L2_COLORSPACE_BT2020: + switch (xfer_func) { + case V4L2_XFER_FUNC_709: *r = transfer_rgb_to_rec709(*r); *g = transfer_rgb_to_rec709(*g); *b = transfer_rgb_to_rec709(*b); break; - case V4L2_COLORSPACE_SRGB: + case V4L2_XFER_FUNC_SRGB: + *r = transfer_rgb_to_srgb(*r); + *g = transfer_rgb_to_srgb(*g); + *b = transfer_rgb_to_srgb(*b); break; - case V4L2_COLORSPACE_ADOBERGB: + case V4L2_XFER_FUNC_ADOBERGB: *r = transfer_rgb_to_adobergb(*r); *g = transfer_rgb_to_adobergb(*g); *b = transfer_rgb_to_adobergb(*b); break; - case V4L2_COLORSPACE_REC709: - default: - *r = transfer_srgb_to_rec709(*r); - *g = transfer_srgb_to_rec709(*g); - *b = transfer_srgb_to_rec709(*b); + case V4L2_XFER_FUNC_SMPTE240M: + *r = transfer_rgb_to_smpte240m(*r); + *g = transfer_rgb_to_smpte240m(*g); + *b = transfer_rgb_to_smpte240m(*b); + break; + case V4L2_XFER_FUNC_NONE: break; } } @@ -877,7 +1116,16 @@ int main(int argc, char **argv) "V4L2_COLORSPACE_ADOBERGB", "V4L2_COLORSPACE_BT2020", }; + static const char * const xfer_func_names[] = { + "", + "V4L2_XFER_FUNC_709", + "V4L2_XFER_FUNC_SRGB", + "V4L2_XFER_FUNC_ADOBERGB", + "V4L2_XFER_FUNC_SMPTE240M", + "V4L2_XFER_FUNC_NONE", + }; int i; + int x; int c; printf("/* Generated table */\n"); @@ -905,22 +1153,26 @@ int main(int argc, char **argv) printf("\n};\n\n"); printf("/* Generated table */\n"); - printf("const struct color16 tpg_csc_colors[V4L2_COLORSPACE_BT2020 + 1][TPG_COLOR_CSC_BLACK + 1] = {\n"); + printf("const struct color16 tpg_csc_colors[V4L2_COLORSPACE_BT2020 + 1][V4L2_XFER_FUNC_NONE + 1][TPG_COLOR_CSC_BLACK + 1] = {\n"); for (c = 0; c <= V4L2_COLORSPACE_BT2020; c++) { - for (i = 0; i <= TPG_COLOR_CSC_BLACK; i++) { - double r, g, b; + for (x = 1; x <= V4L2_XFER_FUNC_NONE; x++) { + for (i = 0; i <= TPG_COLOR_CSC_BLACK; i++) { + double r, g, b; - if (colorspaces[c] == 0) - continue; + if (colorspaces[c] == 0) + continue; - r = tpg_colors[i].r / 255.0; - g = tpg_colors[i].g / 255.0; - b = tpg_colors[i].b / 255.0; + r = tpg_colors[i].r / 255.0; + g = tpg_colors[i].g / 255.0; + b = tpg_colors[i].b / 255.0; - csc(c, &r, &g, &b); + csc(c, x, &r, &g, &b); - printf("\t[%s][%d] = { %d, %d, %d },\n", colorspace_names[c], i, - (int)(r * 4080), (int)(g * 4080), (int)(b * 4080)); + printf("\t[%s][%s][%d] = { %d, %d, %d },\n", + colorspace_names[c], + xfer_func_names[x], i, + (int)(r * 4080), (int)(g * 4080), (int)(b * 4080)); + } } } printf("};\n\n"); diff --git a/drivers/media/platform/vivid/vivid-tpg-colors.h b/drivers/media/platform/vivid/vivid-tpg-colors.h index 2c33335..86b8bf3 100644 --- a/drivers/media/platform/vivid/vivid-tpg-colors.h +++ b/drivers/media/platform/vivid/vivid-tpg-colors.h @@ -61,6 +61,8 @@ enum tpg_color { extern const struct color tpg_colors[TPG_COLOR_MAX]; extern const unsigned short tpg_rec709_to_linear[255 * 16 + 1]; extern const unsigned short tpg_linear_to_rec709[255 * 16 + 1]; -extern const struct color16 tpg_csc_colors[V4L2_COLORSPACE_BT2020 + 1][TPG_COLOR_CSC_BLACK + 1]; +extern const struct color16 tpg_csc_colors[V4L2_COLORSPACE_BT2020 + 1] + [V4L2_XFER_FUNC_NONE + 1] + [TPG_COLOR_CSC_BLACK + 1]; #endif diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index cb766eb..1458c79 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -220,6 +220,8 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_ARGB32: case V4L2_PIX_FMT_ABGR32: case V4L2_PIX_FMT_GREY: + case V4L2_PIX_FMT_Y16: + case V4L2_PIX_FMT_Y16_BE: tpg->is_yuv = false; break; case V4L2_PIX_FMT_YUV444: @@ -292,6 +294,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) } switch (fourcc) { + case V4L2_PIX_FMT_GREY: case V4L2_PIX_FMT_RGB332: tpg->twopixelsize[0] = 2; break; @@ -313,6 +316,8 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_YUV444: case V4L2_PIX_FMT_YUV555: case V4L2_PIX_FMT_YUV565: + case V4L2_PIX_FMT_Y16: + case V4L2_PIX_FMT_Y16_BE: tpg->twopixelsize[0] = 2 * 2; break; case V4L2_PIX_FMT_RGB24: @@ -329,9 +334,6 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_YUV32: tpg->twopixelsize[0] = 2 * 4; break; - case V4L2_PIX_FMT_GREY: - tpg->twopixelsize[0] = 2; - break; case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV12M: @@ -479,44 +481,71 @@ static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b, { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) }, { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) }, }; + static const int smpte240m_full[3][3] = { + { COEFF(0.212, 255), COEFF(0.701, 255), COEFF(0.087, 255) }, + { COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255) }, + { COEFF(0.5, 255), COEFF(-0.445, 255), COEFF(-0.055, 255) }, + }; static const int bt2020[3][3] = { { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) }, { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) }, { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) }, }; + static const int bt2020_full[3][3] = { + { COEFF(0.2627, 255), COEFF(0.6780, 255), COEFF(0.0593, 255) }, + { COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255) }, + { COEFF(0.5, 255), COEFF(-0.4698, 255), COEFF(-0.0402, 255) }, + }; + static const int bt2020c[4] = { + COEFF(1.0 / 1.9404, 224), COEFF(1.0 / 1.5816, 224), + COEFF(1.0 / 1.7184, 224), COEFF(1.0 / 0.9936, 224), + }; + static const int bt2020c_full[4] = { + COEFF(1.0 / 1.9404, 255), COEFF(1.0 / 1.5816, 255), + COEFF(1.0 / 1.7184, 255), COEFF(1.0 / 0.9936, 255), + }; + bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE; unsigned y_offset = full ? 0 : 16; int lin_y, yc; switch (tpg->real_ycbcr_enc) { case V4L2_YCBCR_ENC_601: - case V4L2_YCBCR_ENC_XV601: case V4L2_YCBCR_ENC_SYCC: rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr); break; + case V4L2_YCBCR_ENC_XV601: + /* Ignore quantization range, there is only one possible + * Y'CbCr encoding. */ + rgb2ycbcr(bt601, r, g, b, 16, y, cb, cr); + break; + case V4L2_YCBCR_ENC_XV709: + /* Ignore quantization range, there is only one possible + * Y'CbCr encoding. */ + rgb2ycbcr(rec709, r, g, b, 16, y, cb, cr); + break; case V4L2_YCBCR_ENC_BT2020: - rgb2ycbcr(bt2020, r, g, b, 16, y, cb, cr); + rgb2ycbcr(full ? bt2020_full : bt2020, r, g, b, y_offset, y, cb, cr); break; case V4L2_YCBCR_ENC_BT2020_CONST_LUM: lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) + COEFF(0.6780, 255) * rec709_to_linear(g) + COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16; yc = linear_to_rec709(lin_y); - *y = (yc * 219) / 255 + (16 << 4); + *y = full ? yc : (yc * 219) / 255 + (16 << 4); if (b <= yc) - *cb = (((b - yc) * COEFF(1.0 / 1.9404, 224)) >> 16) + (128 << 4); + *cb = (((b - yc) * (full ? bt2020c_full[0] : bt2020c[0])) >> 16) + (128 << 4); else - *cb = (((b - yc) * COEFF(1.0 / 1.5816, 224)) >> 16) + (128 << 4); + *cb = (((b - yc) * (full ? bt2020c_full[1] : bt2020c[1])) >> 16) + (128 << 4); if (r <= yc) - *cr = (((r - yc) * COEFF(1.0 / 1.7184, 224)) >> 16) + (128 << 4); + *cr = (((r - yc) * (full ? bt2020c_full[2] : bt2020c[2])) >> 16) + (128 << 4); else - *cr = (((r - yc) * COEFF(1.0 / 0.9936, 224)) >> 16) + (128 << 4); + *cr = (((r - yc) * (full ? bt2020c_full[3] : bt2020c[3])) >> 16) + (128 << 4); break; case V4L2_YCBCR_ENC_SMPTE240M: - rgb2ycbcr(smpte240m, r, g, b, 16, y, cb, cr); + rgb2ycbcr(full ? smpte240m_full : smpte240m, r, g, b, y_offset, y, cb, cr); break; case V4L2_YCBCR_ENC_709: - case V4L2_YCBCR_ENC_XV709: default: rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr); break; @@ -567,42 +596,71 @@ static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr, { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) }, { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) }, }; + static const int smpte240m_full[3][3] = { + { COEFF(1, 255), COEFF(0, 255), COEFF(1.5756, 255) }, + { COEFF(1, 255), COEFF(-0.2253, 255), COEFF(-0.4767, 255) }, + { COEFF(1, 255), COEFF(1.8270, 255), COEFF(0, 255) }, + }; static const int bt2020[3][3] = { { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) }, { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) }, { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) }, }; + static const int bt2020_full[3][3] = { + { COEFF(1, 255), COEFF(0, 255), COEFF(1.4746, 255) }, + { COEFF(1, 255), COEFF(-0.1646, 255), COEFF(-0.5714, 255) }, + { COEFF(1, 255), COEFF(1.8814, 255), COEFF(0, 255) }, + }; + static const int bt2020c[4] = { + COEFF(1.9404, 224), COEFF(1.5816, 224), + COEFF(1.7184, 224), COEFF(0.9936, 224), + }; + static const int bt2020c_full[4] = { + COEFF(1.9404, 255), COEFF(1.5816, 255), + COEFF(1.7184, 255), COEFF(0.9936, 255), + }; + bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE; unsigned y_offset = full ? 0 : 16; + int y_fac = full ? COEFF(1.0, 255) : COEFF(1.0, 219); int lin_r, lin_g, lin_b, lin_y; switch (tpg->real_ycbcr_enc) { case V4L2_YCBCR_ENC_601: - case V4L2_YCBCR_ENC_XV601: case V4L2_YCBCR_ENC_SYCC: ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b); break; + case V4L2_YCBCR_ENC_XV601: + /* Ignore quantization range, there is only one possible + * Y'CbCr encoding. */ + ycbcr2rgb(bt601, y, cb, cr, 16, r, g, b); + break; + case V4L2_YCBCR_ENC_XV709: + /* Ignore quantization range, there is only one possible + * Y'CbCr encoding. */ + ycbcr2rgb(rec709, y, cb, cr, 16, r, g, b); + break; case V4L2_YCBCR_ENC_BT2020: - ycbcr2rgb(bt2020, y, cb, cr, 16, r, g, b); + ycbcr2rgb(full ? bt2020_full : bt2020, y, cb, cr, y_offset, r, g, b); break; case V4L2_YCBCR_ENC_BT2020_CONST_LUM: - y -= 16 << 4; + y -= full ? 0 : 16 << 4; cb -= 128 << 4; cr -= 128 << 4; if (cb <= 0) - *b = COEFF(1.0, 219) * y + COEFF(1.9404, 224) * cb; + *b = y_fac * y + (full ? bt2020c_full[0] : bt2020c[0]) * cb; else - *b = COEFF(1.0, 219) * y + COEFF(1.5816, 224) * cb; + *b = y_fac * y + (full ? bt2020c_full[1] : bt2020c[1]) * cb; *b = *b >> 12; if (cr <= 0) - *r = COEFF(1.0, 219) * y + COEFF(1.7184, 224) * cr; + *r = y_fac * y + (full ? bt2020c_full[2] : bt2020c[2]) * cr; else - *r = COEFF(1.0, 219) * y + COEFF(0.9936, 224) * cr; + *r = y_fac * y + (full ? bt2020c_full[3] : bt2020c[3]) * cr; *r = *r >> 12; lin_r = rec709_to_linear(*r); lin_b = rec709_to_linear(*b); - lin_y = rec709_to_linear((y * 255) / 219); + lin_y = rec709_to_linear((y * 255) / (full ? 255 : 219)); lin_g = COEFF(1.0 / 0.6780, 255) * lin_y - COEFF(0.2627 / 0.6780, 255) * lin_r - @@ -610,10 +668,9 @@ static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr, *g = linear_to_rec709(lin_g >> 12); break; case V4L2_YCBCR_ENC_SMPTE240M: - ycbcr2rgb(smpte240m, y, cb, cr, 16, r, g, b); + ycbcr2rgb(full ? smpte240m_full : smpte240m, y, cb, cr, y_offset, r, g, b); break; case V4L2_YCBCR_ENC_709: - case V4L2_YCBCR_ENC_XV709: default: ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b); break; @@ -649,15 +706,17 @@ static void precalculate_color(struct tpg_data *tpg, int k) } if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) { - r = tpg_csc_colors[tpg->colorspace][col].r; - g = tpg_csc_colors[tpg->colorspace][col].g; - b = tpg_csc_colors[tpg->colorspace][col].b; + r = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].r; + g = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].g; + b = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].b; } else { r <<= 4; g <<= 4; b <<= 4; } - if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY) { + if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY || + tpg->fourcc == V4L2_PIX_FMT_Y16 || + tpg->fourcc == V4L2_PIX_FMT_Y16_BE) { /* Rec. 709 Luma function */ /* (0.2126, 0.7152, 0.0722) * (255 * 256) */ r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16; @@ -840,6 +899,21 @@ static void gen_twopix(struct tpg_data *tpg, case V4L2_PIX_FMT_GREY: buf[0][offset] = r_y; break; + case V4L2_PIX_FMT_Y16: + /* + * Ideally both bytes should be set to r_y, but then you won't + * be able to detect endian problems. So keep it 0 except for + * the corner case where r_y is 0xff so white really will be + * white (0xffff). + */ + buf[0][offset] = r_y == 0xff ? r_y : 0; + buf[0][offset+1] = r_y; + break; + case V4L2_PIX_FMT_Y16_BE: + /* See comment for V4L2_PIX_FMT_Y16 above */ + buf[0][offset] = r_y; + buf[0][offset+1] = r_y == 0xff ? r_y : 0; + break; case V4L2_PIX_FMT_YUV422P: case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YUV420M: @@ -1395,42 +1469,10 @@ static void tpg_precalculate_line(struct tpg_data *tpg) /* need this to do rgb24 rendering */ typedef struct { u16 __; u8 _; } __packed x24; -void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], - int y, int x, char *text) -{ - int line; - unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; - unsigned div = step; - unsigned first = 0; - unsigned len = strlen(text); - unsigned p; - - if (font8x16 == NULL || basep == NULL) - return; - - /* Checks if it is possible to show string */ - if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width) - return; - - if (len > (tpg->compose.width - x) / 8) - len = (tpg->compose.width - x) / 8; - if (tpg->vflip) - y = tpg->compose.height - y - 16; - if (tpg->hflip) - x = tpg->compose.width - x - 8; - y += tpg->compose.top; - x += tpg->compose.left; - if (tpg->field == V4L2_FIELD_BOTTOM) - first = 1; - else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT) - div = 2; - - for (p = 0; p < tpg->planes; p++) { - unsigned vdiv = tpg->vdownsampling[p]; - unsigned hdiv = tpg->hdownsampling[p]; - - /* Print text */ #define PRINTSTR(PIXTYPE) do { \ + unsigned vdiv = tpg->vdownsampling[p]; \ + unsigned hdiv = tpg->hdownsampling[p]; \ + int line; \ PIXTYPE fg; \ PIXTYPE bg; \ memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \ @@ -1481,15 +1523,82 @@ void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], } \ } while (0) +static noinline void tpg_print_str_2(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], + unsigned p, unsigned first, unsigned div, unsigned step, + int y, int x, char *text, unsigned len) +{ + PRINTSTR(u8); +} + +static noinline void tpg_print_str_4(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], + unsigned p, unsigned first, unsigned div, unsigned step, + int y, int x, char *text, unsigned len) +{ + PRINTSTR(u16); +} + +static noinline void tpg_print_str_6(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], + unsigned p, unsigned first, unsigned div, unsigned step, + int y, int x, char *text, unsigned len) +{ + PRINTSTR(x24); +} + +static noinline void tpg_print_str_8(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], + unsigned p, unsigned first, unsigned div, unsigned step, + int y, int x, char *text, unsigned len) +{ + PRINTSTR(u32); +} + +void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], + int y, int x, char *text) +{ + unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; + unsigned div = step; + unsigned first = 0; + unsigned len = strlen(text); + unsigned p; + + if (font8x16 == NULL || basep == NULL) + return; + + /* Checks if it is possible to show string */ + if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width) + return; + + if (len > (tpg->compose.width - x) / 8) + len = (tpg->compose.width - x) / 8; + if (tpg->vflip) + y = tpg->compose.height - y - 16; + if (tpg->hflip) + x = tpg->compose.width - x - 8; + y += tpg->compose.top; + x += tpg->compose.left; + if (tpg->field == V4L2_FIELD_BOTTOM) + first = 1; + else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT) + div = 2; + + for (p = 0; p < tpg->planes; p++) { + /* Print text */ switch (tpg->twopixelsize[p]) { case 2: - PRINTSTR(u8); break; + tpg_print_str_2(tpg, basep, p, first, div, step, y, x, + text, len); + break; case 4: - PRINTSTR(u16); break; + tpg_print_str_4(tpg, basep, p, first, div, step, y, x, + text, len); + break; case 6: - PRINTSTR(x24); break; + tpg_print_str_6(tpg, basep, p, first, div, step, y, x, + text, len); + break; case 8: - PRINTSTR(u32); break; + tpg_print_str_8(tpg, basep, p, first, div, step, y, x, + text, len); + break; } } } @@ -1583,50 +1692,23 @@ static void tpg_recalc(struct tpg_data *tpg) if (tpg->recalc_colors) { tpg->recalc_colors = false; tpg->recalc_lines = true; + tpg->real_xfer_func = tpg->xfer_func; tpg->real_ycbcr_enc = tpg->ycbcr_enc; tpg->real_quantization = tpg->quantization; - if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) { - switch (tpg->colorspace) { - case V4L2_COLORSPACE_REC709: - tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_709; - break; - case V4L2_COLORSPACE_SRGB: - tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SYCC; - break; - case V4L2_COLORSPACE_BT2020: - tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_BT2020; - break; - case V4L2_COLORSPACE_SMPTE240M: - tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SMPTE240M; - break; - case V4L2_COLORSPACE_SMPTE170M: - case V4L2_COLORSPACE_470_SYSTEM_M: - case V4L2_COLORSPACE_470_SYSTEM_BG: - case V4L2_COLORSPACE_ADOBERGB: - default: - tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_601; - break; - } - } - if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT) { - tpg->real_quantization = V4L2_QUANTIZATION_FULL_RANGE; - if (tpg->is_yuv) { - switch (tpg->real_ycbcr_enc) { - case V4L2_YCBCR_ENC_SYCC: - case V4L2_YCBCR_ENC_XV601: - case V4L2_YCBCR_ENC_XV709: - break; - default: - tpg->real_quantization = - V4L2_QUANTIZATION_LIM_RANGE; - break; - } - } else if (tpg->colorspace == V4L2_COLORSPACE_BT2020) { - /* R'G'B' BT.2020 is limited range */ - tpg->real_quantization = - V4L2_QUANTIZATION_LIM_RANGE; - } - } + + if (tpg->xfer_func == V4L2_XFER_FUNC_DEFAULT) + tpg->real_xfer_func = + V4L2_MAP_XFER_FUNC_DEFAULT(tpg->colorspace); + + if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) + tpg->real_ycbcr_enc = + V4L2_MAP_YCBCR_ENC_DEFAULT(tpg->colorspace); + + if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT) + tpg->real_quantization = + V4L2_MAP_QUANTIZATION_DEFAULT(!tpg->is_yuv, + tpg->colorspace, tpg->real_ycbcr_enc); + tpg_precalculate_colors(tpg); } if (tpg->recalc_square_border) { @@ -1670,6 +1752,23 @@ static int tpg_pattern_avg(const struct tpg_data *tpg, return -1; } +void tpg_log_status(struct tpg_data *tpg) +{ + pr_info("tpg source WxH: %ux%u (%s)\n", + tpg->src_width, tpg->src_height, + tpg->is_yuv ? "YCbCr" : "RGB"); + pr_info("tpg field: %u\n", tpg->field); + pr_info("tpg crop: %ux%u@%dx%d\n", tpg->crop.width, tpg->crop.height, + tpg->crop.left, tpg->crop.top); + pr_info("tpg compose: %ux%u@%dx%d\n", tpg->compose.width, tpg->compose.height, + tpg->compose.left, tpg->compose.top); + pr_info("tpg colorspace: %d\n", tpg->colorspace); + pr_info("tpg transfer function: %d/%d\n", tpg->xfer_func, tpg->real_xfer_func); + pr_info("tpg Y'CbCr encoding: %d/%d\n", tpg->ycbcr_enc, tpg->real_ycbcr_enc); + pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization); + pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range); +} + /* * This struct contains common parameters used by both the drawing of the * test pattern and the drawing of the extras (borders, square, etc.) diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h index a50cd2e..9baed6a 100644 --- a/drivers/media/platform/vivid/vivid-tpg.h +++ b/drivers/media/platform/vivid/vivid-tpg.h @@ -122,8 +122,14 @@ struct tpg_data { u32 fourcc; bool is_yuv; u32 colorspace; + u32 xfer_func; u32 ycbcr_enc; /* + * Stores the actual transfer function, i.e. will never be + * V4L2_XFER_FUNC_DEFAULT. + */ + u32 real_xfer_func; + /* * Stores the actual Y'CbCr encoding, i.e. will never be * V4L2_YCBCR_ENC_DEFAULT. */ @@ -192,6 +198,7 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w); void tpg_free(struct tpg_data *tpg); void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height, u32 field); +void tpg_log_status(struct tpg_data *tpg); void tpg_set_font(const u8 *f); void tpg_gen_text(const struct tpg_data *tpg, @@ -328,6 +335,19 @@ static inline u32 tpg_g_ycbcr_enc(const struct tpg_data *tpg) return tpg->ycbcr_enc; } +static inline void tpg_s_xfer_func(struct tpg_data *tpg, u32 xfer_func) +{ + if (tpg->xfer_func == xfer_func) + return; + tpg->xfer_func = xfer_func; + tpg->recalc_colors = true; +} + +static inline u32 tpg_g_xfer_func(const struct tpg_data *tpg) +{ + return tpg->xfer_func; +} + static inline void tpg_s_quantization(struct tpg_data *tpg, u32 quantization) { if (tpg->quantization == quantization) diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index dab5990..c4268d1 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -40,7 +40,6 @@ static const struct v4l2_fract static const struct vivid_fmt formats_ovl[] = { { - .name = "RGB565 (LE)", .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -48,7 +47,6 @@ static const struct vivid_fmt formats_ovl[] = { .buffers = 1, }, { - .name = "XRGB555 (LE)", .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -56,7 +54,6 @@ static const struct vivid_fmt formats_ovl[] = { .buffers = 1, }, { - .name = "ARGB555 (LE)", .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -66,7 +63,7 @@ static const struct vivid_fmt formats_ovl[] = { }; /* The number of discrete webcam framesizes */ -#define VIVID_WEBCAM_SIZES 3 +#define VIVID_WEBCAM_SIZES 4 /* The number of discrete webcam frameintervals */ #define VIVID_WEBCAM_IVALS (VIVID_WEBCAM_SIZES * 2) @@ -75,6 +72,7 @@ static const struct v4l2_frmsize_discrete webcam_sizes[VIVID_WEBCAM_SIZES] = { { 320, 180 }, { 640, 360 }, { 1280, 720 }, + { 1920, 1080 }, }; /* @@ -82,6 +80,8 @@ static const struct v4l2_frmsize_discrete webcam_sizes[VIVID_WEBCAM_SIZES] = { * elements in this array as there are in webcam_sizes. */ static const struct v4l2_fract webcam_intervals[VIVID_WEBCAM_IVALS] = { + { 1, 2 }, + { 1, 5 }, { 1, 10 }, { 1, 15 }, { 1, 25 }, @@ -501,6 +501,13 @@ static unsigned vivid_colorspace_cap(struct vivid_dev *dev) return dev->colorspace_out; } +static unsigned vivid_xfer_func_cap(struct vivid_dev *dev) +{ + if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) + return tpg_g_xfer_func(&dev->tpg); + return dev->xfer_func_out; +} + static unsigned vivid_ycbcr_enc_cap(struct vivid_dev *dev) { if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) @@ -527,6 +534,7 @@ int vivid_g_fmt_vid_cap(struct file *file, void *priv, mp->field = dev->field_cap; mp->pixelformat = dev->fmt_cap->fourcc; mp->colorspace = vivid_colorspace_cap(dev); + mp->xfer_func = vivid_xfer_func_cap(dev); mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); mp->quantization = vivid_quantization_cap(dev); mp->num_planes = dev->fmt_cap->buffers; @@ -616,6 +624,7 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, } mp->colorspace = vivid_colorspace_cap(dev); mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); + mp->xfer_func = vivid_xfer_func_cap(dev); mp->quantization = vivid_quantization_cap(dev); memset(mp->reserved, 0, sizeof(mp->reserved)); return 0; @@ -720,8 +729,8 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv, webcam_sizes[i].height == mp->height) break; dev->webcam_size_idx = i; - if (dev->webcam_ival_idx >= 2 * (3 - i)) - dev->webcam_ival_idx = 2 * (3 - i) - 1; + if (dev->webcam_ival_idx >= 2 * (VIVID_WEBCAM_SIZES - i)) + dev->webcam_ival_idx = 2 * (VIVID_WEBCAM_SIZES - i) - 1; vivid_update_format_cap(dev, false); } else { struct v4l2_rect r = { 0, 0, mp->width, mp->height }; @@ -1030,7 +1039,6 @@ int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, fmt = &formats_ovl[f->index]; - strlcpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; return 0; } @@ -1620,7 +1628,7 @@ static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_CVT)) { if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync, - bt->polarities, timings)) + bt->polarities, bt->interlaced, timings)) return true; } @@ -1631,7 +1639,8 @@ static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) &aspect_ratio.numerator, &aspect_ratio.denominator); if (v4l2_detect_gtf(total_v_lines, h_freq, bt->vsync, - bt->polarities, aspect_ratio, timings)) + bt->polarities, bt->interlaced, + aspect_ratio, timings)) return true; } return false; @@ -1768,7 +1777,7 @@ int vidioc_enum_frameintervals(struct file *file, void *priv, break; if (i == ARRAY_SIZE(webcam_sizes)) return -EINVAL; - if (fival->index >= 2 * (3 - i)) + if (fival->index >= 2 * (VIVID_WEBCAM_SIZES - i)) return -EINVAL; fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; fival->discrete = webcam_intervals[fival->index]; @@ -1798,7 +1807,7 @@ int vivid_vid_cap_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) { struct vivid_dev *dev = video_drvdata(file); - unsigned ival_sz = 2 * (3 - dev->webcam_size_idx); + unsigned ival_sz = 2 * (VIVID_WEBCAM_SIZES - dev->webcam_size_idx); struct v4l2_fract tpf; unsigned i; diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index aa44627..fc73927 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -45,7 +45,6 @@ const struct v4l2_dv_timings_cap vivid_dv_timings_cap = { struct vivid_fmt vivid_formats[] = { { - .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -55,7 +54,6 @@ struct vivid_fmt vivid_formats[] = { .data_offset = { PLANE0_DATA_OFFSET }, }, { - .name = "4:2:2, packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -64,7 +62,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "4:2:2, packed, YVYU", .fourcc = V4L2_PIX_FMT_YVYU, .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -73,7 +70,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "4:2:2, packed, VYUY", .fourcc = V4L2_PIX_FMT_VYUY, .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -82,7 +78,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "YUV 4:2:2 triplanar", .fourcc = V4L2_PIX_FMT_YUV422P, .vdownsampling = { 1, 1, 1 }, .bit_depth = { 8, 4, 4 }, @@ -91,7 +86,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "YUV 4:2:0 triplanar", .fourcc = V4L2_PIX_FMT_YUV420, .vdownsampling = { 1, 2, 2 }, .bit_depth = { 8, 4, 4 }, @@ -100,7 +94,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "YVU 4:2:0 triplanar", .fourcc = V4L2_PIX_FMT_YVU420, .vdownsampling = { 1, 2, 2 }, .bit_depth = { 8, 4, 4 }, @@ -109,7 +102,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "YUV 4:2:0 biplanar", .fourcc = V4L2_PIX_FMT_NV12, .vdownsampling = { 1, 2 }, .bit_depth = { 8, 8 }, @@ -118,7 +110,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "YVU 4:2:0 biplanar", .fourcc = V4L2_PIX_FMT_NV21, .vdownsampling = { 1, 2 }, .bit_depth = { 8, 8 }, @@ -127,7 +118,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "YUV 4:2:2 biplanar", .fourcc = V4L2_PIX_FMT_NV16, .vdownsampling = { 1, 1 }, .bit_depth = { 8, 8 }, @@ -136,7 +126,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "YVU 4:2:2 biplanar", .fourcc = V4L2_PIX_FMT_NV61, .vdownsampling = { 1, 1 }, .bit_depth = { 8, 8 }, @@ -145,7 +134,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "YUV 4:4:4 biplanar", .fourcc = V4L2_PIX_FMT_NV24, .vdownsampling = { 1, 1 }, .bit_depth = { 8, 16 }, @@ -154,7 +142,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "YVU 4:4:4 biplanar", .fourcc = V4L2_PIX_FMT_NV42, .vdownsampling = { 1, 1 }, .bit_depth = { 8, 16 }, @@ -163,7 +150,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "YUV555 (LE)", .fourcc = V4L2_PIX_FMT_YUV555, /* uuuvvvvv ayyyyyuu */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -172,7 +158,6 @@ struct vivid_fmt vivid_formats[] = { .alpha_mask = 0x8000, }, { - .name = "YUV565 (LE)", .fourcc = V4L2_PIX_FMT_YUV565, /* uuuvvvvv yyyyyuuu */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -180,7 +165,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "YUV444", .fourcc = V4L2_PIX_FMT_YUV444, /* uuuuvvvv aaaayyyy */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -189,7 +173,6 @@ struct vivid_fmt vivid_formats[] = { .alpha_mask = 0xf000, }, { - .name = "YUV32 (LE)", .fourcc = V4L2_PIX_FMT_YUV32, /* ayuv */ .vdownsampling = { 1 }, .bit_depth = { 32 }, @@ -198,7 +181,6 @@ struct vivid_fmt vivid_formats[] = { .alpha_mask = 0x000000ff, }, { - .name = "Monochrome", .fourcc = V4L2_PIX_FMT_GREY, .vdownsampling = { 1 }, .bit_depth = { 8 }, @@ -207,7 +189,22 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "RGB332", + .fourcc = V4L2_PIX_FMT_Y16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .is_yuv = true, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_Y16_BE, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .is_yuv = true, + .planes = 1, + .buffers = 1, + }, + { .fourcc = V4L2_PIX_FMT_RGB332, /* rrrgggbb */ .vdownsampling = { 1 }, .bit_depth = { 8 }, @@ -215,7 +212,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "RGB565 (LE)", .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -224,7 +220,6 @@ struct vivid_fmt vivid_formats[] = { .can_do_overlay = true, }, { - .name = "RGB565 (BE)", .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -233,7 +228,6 @@ struct vivid_fmt vivid_formats[] = { .can_do_overlay = true, }, { - .name = "RGB444", .fourcc = V4L2_PIX_FMT_RGB444, /* xxxxrrrr ggggbbbb */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -241,7 +235,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "XRGB444", .fourcc = V4L2_PIX_FMT_XRGB444, /* xxxxrrrr ggggbbbb */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -249,7 +242,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "ARGB444", .fourcc = V4L2_PIX_FMT_ARGB444, /* aaaarrrr ggggbbbb */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -258,7 +250,6 @@ struct vivid_fmt vivid_formats[] = { .alpha_mask = 0x00f0, }, { - .name = "RGB555 (LE)", .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb xrrrrrgg */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -267,7 +258,6 @@ struct vivid_fmt vivid_formats[] = { .can_do_overlay = true, }, { - .name = "XRGB555 (LE)", .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb xrrrrrgg */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -276,7 +266,6 @@ struct vivid_fmt vivid_formats[] = { .can_do_overlay = true, }, { - .name = "ARGB555 (LE)", .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -286,7 +275,6 @@ struct vivid_fmt vivid_formats[] = { .alpha_mask = 0x8000, }, { - .name = "RGB555 (BE)", .fourcc = V4L2_PIX_FMT_RGB555X, /* xrrrrrgg gggbbbbb */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -294,7 +282,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "XRGB555 (BE)", .fourcc = V4L2_PIX_FMT_XRGB555X, /* xrrrrrgg gggbbbbb */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -302,7 +289,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "ARGB555 (BE)", .fourcc = V4L2_PIX_FMT_ARGB555X, /* arrrrrgg gggbbbbb */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -311,7 +297,6 @@ struct vivid_fmt vivid_formats[] = { .alpha_mask = 0x0080, }, { - .name = "RGB24 (LE)", .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ .vdownsampling = { 1 }, .bit_depth = { 24 }, @@ -319,7 +304,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "RGB24 (BE)", .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ .vdownsampling = { 1 }, .bit_depth = { 24 }, @@ -327,7 +311,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "BGR666", .fourcc = V4L2_PIX_FMT_BGR666, /* bbbbbbgg ggggrrrr rrxxxxxx */ .vdownsampling = { 1 }, .bit_depth = { 32 }, @@ -335,7 +318,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "RGB32 (LE)", .fourcc = V4L2_PIX_FMT_RGB32, /* xrgb */ .vdownsampling = { 1 }, .bit_depth = { 32 }, @@ -343,7 +325,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "RGB32 (BE)", .fourcc = V4L2_PIX_FMT_BGR32, /* bgrx */ .vdownsampling = { 1 }, .bit_depth = { 32 }, @@ -351,7 +332,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "XRGB32 (LE)", .fourcc = V4L2_PIX_FMT_XRGB32, /* xrgb */ .vdownsampling = { 1 }, .bit_depth = { 32 }, @@ -359,7 +339,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "XRGB32 (BE)", .fourcc = V4L2_PIX_FMT_XBGR32, /* bgrx */ .vdownsampling = { 1 }, .bit_depth = { 32 }, @@ -367,7 +346,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "ARGB32 (LE)", .fourcc = V4L2_PIX_FMT_ARGB32, /* argb */ .vdownsampling = { 1 }, .bit_depth = { 32 }, @@ -376,7 +354,6 @@ struct vivid_fmt vivid_formats[] = { .alpha_mask = 0x000000ff, }, { - .name = "ARGB32 (BE)", .fourcc = V4L2_PIX_FMT_ABGR32, /* bgra */ .vdownsampling = { 1 }, .bit_depth = { 32 }, @@ -385,7 +362,6 @@ struct vivid_fmt vivid_formats[] = { .alpha_mask = 0xff000000, }, { - .name = "Bayer BG/GR", .fourcc = V4L2_PIX_FMT_SBGGR8, /* Bayer BG/GR */ .vdownsampling = { 1 }, .bit_depth = { 8 }, @@ -393,7 +369,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "Bayer GB/RG", .fourcc = V4L2_PIX_FMT_SGBRG8, /* Bayer GB/RG */ .vdownsampling = { 1 }, .bit_depth = { 8 }, @@ -401,7 +376,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "Bayer GR/BG", .fourcc = V4L2_PIX_FMT_SGRBG8, /* Bayer GR/BG */ .vdownsampling = { 1 }, .bit_depth = { 8 }, @@ -409,7 +383,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "Bayer RG/GB", .fourcc = V4L2_PIX_FMT_SRGGB8, /* Bayer RG/GB */ .vdownsampling = { 1 }, .bit_depth = { 8 }, @@ -417,7 +390,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { - .name = "4:2:2, biplanar, YUV", .fourcc = V4L2_PIX_FMT_NV16M, .vdownsampling = { 1, 1 }, .bit_depth = { 8, 8 }, @@ -427,7 +399,6 @@ struct vivid_fmt vivid_formats[] = { .data_offset = { PLANE0_DATA_OFFSET, 0 }, }, { - .name = "4:2:2, biplanar, YVU", .fourcc = V4L2_PIX_FMT_NV61M, .vdownsampling = { 1, 1 }, .bit_depth = { 8, 8 }, @@ -437,7 +408,6 @@ struct vivid_fmt vivid_formats[] = { .data_offset = { 0, PLANE0_DATA_OFFSET }, }, { - .name = "4:2:0, triplanar, YUV", .fourcc = V4L2_PIX_FMT_YUV420M, .vdownsampling = { 1, 2, 2 }, .bit_depth = { 8, 4, 4 }, @@ -446,7 +416,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 3, }, { - .name = "4:2:0, triplanar, YVU", .fourcc = V4L2_PIX_FMT_YVU420M, .vdownsampling = { 1, 2, 2 }, .bit_depth = { 8, 4, 4 }, @@ -455,7 +424,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 3, }, { - .name = "4:2:0, biplanar, YUV", .fourcc = V4L2_PIX_FMT_NV12M, .vdownsampling = { 1, 2 }, .bit_depth = { 8, 8 }, @@ -464,7 +432,6 @@ struct vivid_fmt vivid_formats[] = { .buffers = 2, }, { - .name = "4:2:0, biplanar, YVU", .fourcc = V4L2_PIX_FMT_NV21M, .vdownsampling = { 1, 2 }, .bit_depth = { 8, 8 }, @@ -557,6 +524,7 @@ void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt) mp->pixelformat = pix->pixelformat; mp->field = pix->field; mp->colorspace = pix->colorspace; + mp->xfer_func = pix->xfer_func; mp->ycbcr_enc = pix->ycbcr_enc; mp->quantization = pix->quantization; mp->num_planes = 1; @@ -585,6 +553,7 @@ int fmt_sp2mp_func(struct file *file, void *priv, pix->pixelformat = mp->pixelformat; pix->field = mp->field; pix->colorspace = mp->colorspace; + pix->xfer_func = mp->xfer_func; pix->ycbcr_enc = mp->ycbcr_enc; pix->quantization = mp->quantization; pix->sizeimage = ppix->sizeimage; @@ -750,7 +719,6 @@ int vivid_enum_fmt_vid(struct file *file, void *priv, fmt = &vivid_formats[f->index]; - strlcpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; return 0; } diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 0af43dc..0862c1f 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -258,6 +258,7 @@ void vivid_update_format_out(struct vivid_dev *dev) } break; } + dev->xfer_func_out = V4L2_XFER_FUNC_DEFAULT; dev->ycbcr_enc_out = V4L2_YCBCR_ENC_DEFAULT; dev->quantization_out = V4L2_QUANTIZATION_DEFAULT; dev->compose_out = dev->sink_rect; @@ -320,6 +321,7 @@ int vivid_g_fmt_vid_out(struct file *file, void *priv, mp->field = dev->field_out; mp->pixelformat = fmt->fourcc; mp->colorspace = dev->colorspace_out; + mp->xfer_func = dev->xfer_func_out; mp->ycbcr_enc = dev->ycbcr_enc_out; mp->quantization = dev->quantization_out; mp->num_planes = fmt->buffers; @@ -407,6 +409,7 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, for (p = fmt->buffers; p < fmt->planes; p++) pfmt[0].sizeimage += (pfmt[0].bytesperline * fmt->bit_depth[p]) / (fmt->bit_depth[0] * fmt->vdownsampling[p]); + mp->xfer_func = V4L2_XFER_FUNC_DEFAULT; mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; mp->quantization = V4L2_QUANTIZATION_DEFAULT; if (vivid_is_svid_out(dev)) { @@ -546,6 +549,7 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv, set_colorspace: dev->colorspace_out = mp->colorspace; + dev->xfer_func_out = mp->xfer_func; dev->ycbcr_enc_out = mp->ycbcr_enc; dev->quantization_out = mp->quantization; if (dev->loop_video) { @@ -1152,7 +1156,8 @@ int vivid_vid_out_g_parm(struct file *file, void *priv, parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; parm->parm.output.timeperframe = dev->timeperframe_vid_out; parm->parm.output.writebuffers = 1; -return 0; + + return 0; } int vidioc_subscribe_event(struct v4l2_fh *fh, diff --git a/drivers/media/platform/xilinx/Kconfig b/drivers/media/platform/xilinx/Kconfig index d7324c7..84bae79 100644 --- a/drivers/media/platform/xilinx/Kconfig +++ b/drivers/media/platform/xilinx/Kconfig @@ -1,6 +1,6 @@ config VIDEO_XILINX tristate "Xilinx Video IP (EXPERIMENTAL)" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF && HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- Driver for Xilinx Video IP Pipelines diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index efde88a..98e50e4 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -653,7 +653,7 @@ static const struct v4l2_file_operations xvip_dma_fops = { int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma, enum v4l2_buf_type type, unsigned int port) { - char name[14]; + char name[16]; int ret; dma->xdev = xdev; @@ -725,7 +725,7 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma, } /* ... and the DMA channel. */ - sprintf(name, "port%u", port); + snprintf(name, sizeof(name), "port%u", port); dma->dma = dma_request_slave_channel(dma->xdev->dev, name); if (dma->dma == NULL) { dev_err(dma->xdev->dev, "no VDMA channel found\n"); diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index dccf586..9cbb8cd 100644 --- a/drivers/media/radio/radio-si476x.c +++ b/drivers/media/radio/radio-si476x.c @@ -568,8 +568,8 @@ static int si476x_radio_do_post_powerup_init(struct si476x_radio *radio, err = regcache_sync_region(radio->core->regmap, SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE, SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT); - if (err < 0) - return err; + if (err < 0) + return err; err = regcache_sync_region(radio->core->regmap, SI476X_PROP_AUDIO_DEEMPHASIS, diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index e6b55ed..04baafe 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -138,8 +138,10 @@ static int timbradio_probe(struct platform_device *pdev) i2c_get_adapter(pdata->i2c_adapter), pdata->tuner, NULL); tr->sd_dsp = v4l2_i2c_new_subdev_board(&tr->v4l2_dev, i2c_get_adapter(pdata->i2c_adapter), pdata->dsp, NULL); - if (tr->sd_tuner == NULL || tr->sd_dsp == NULL) + if (tr->sd_tuner == NULL || tr->sd_dsp == NULL) { + err = -ENODEV; goto err_video_req; + } tr->v4l2_dev.ctrl_handler = tr->sd_dsp->ctrl_handler; diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index 2a497c8..471d6a8 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -384,14 +384,14 @@ static int si470x_i2c_probe(struct i2c_client *client, goto err_radio; } dev_info(&client->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", - radio->registers[DEVICEID], radio->registers[CHIPID]); - if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) < RADIO_FW_VERSION) { + radio->registers[DEVICEID], radio->registers[SI_CHIPID]); + if ((radio->registers[SI_CHIPID] & SI_CHIPID_FIRMWARE) < RADIO_FW_VERSION) { dev_warn(&client->dev, "This driver is known to work with " "firmware version %hu,\n", RADIO_FW_VERSION); dev_warn(&client->dev, "but the device has firmware version %hu.\n", - radio->registers[CHIPID] & CHIPID_FIRMWARE); + radio->registers[SI_CHIPID] & SI_CHIPID_FIRMWARE); version_warning = 1; } @@ -421,7 +421,8 @@ static int si470x_i2c_probe(struct i2c_client *client, init_waitqueue_head(&radio->read_queue); retval = request_threaded_irq(client->irq, NULL, si470x_i2c_interrupt, - IRQF_TRIGGER_FALLING, DRIVER_NAME, radio); + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, DRIVER_NAME, + radio); if (retval) { dev_err(&client->dev, "Failed to register interrupt\n"); goto err_rds; diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index 57f0bc3..091d793 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -686,14 +686,14 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, goto err_ctrl; } dev_info(&intf->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", - radio->registers[DEVICEID], radio->registers[CHIPID]); - if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) < RADIO_FW_VERSION) { + radio->registers[DEVICEID], radio->registers[SI_CHIPID]); + if ((radio->registers[SI_CHIPID] & SI_CHIPID_FIRMWARE) < RADIO_FW_VERSION) { dev_warn(&intf->dev, "This driver is known to work with " "firmware version %hu,\n", RADIO_FW_VERSION); dev_warn(&intf->dev, "but the device has firmware version %hu.\n", - radio->registers[CHIPID] & CHIPID_FIRMWARE); + radio->registers[SI_CHIPID] & SI_CHIPID_FIRMWARE); version_warning = 1; } diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h index 4b76604..6c0ca90 100644 --- a/drivers/media/radio/si470x/radio-si470x.h +++ b/drivers/media/radio/si470x/radio-si470x.h @@ -54,10 +54,10 @@ #define DEVICEID_PN 0xf000 /* bits 15..12: Part Number */ #define DEVICEID_MFGID 0x0fff /* bits 11..00: Manufacturer ID */ -#define CHIPID 1 /* Chip ID */ -#define CHIPID_REV 0xfc00 /* bits 15..10: Chip Version */ -#define CHIPID_DEV 0x0200 /* bits 09..09: Device */ -#define CHIPID_FIRMWARE 0x01ff /* bits 08..00: Firmware Version */ +#define SI_CHIPID 1 /* Chip ID */ +#define SI_CHIPID_REV 0xfc00 /* bits 15..10: Chip Version */ +#define SI_CHIPID_DEV 0x0200 /* bits 09..09: Device */ +#define SI_CHIPID_FIRMWARE 0x01ff /* bits 08..00: Firmware Version */ #define POWERCFG 2 /* Power Configuration */ #define POWERCFG_DSMUTE 0x8000 /* bits 15..15: Softmute Disable */ diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c index e9d03ac..0b04b56 100644 --- a/drivers/media/radio/si4713/si4713.c +++ b/drivers/media/radio/si4713/si4713.c @@ -1609,8 +1609,10 @@ static int si4713_probe(struct i2c_client *client, return 0; si4713_pdev = platform_device_alloc("radio-si4713", -1); - if (!si4713_pdev) + if (!si4713_pdev) { + rval = -ENOMEM; goto put_main_pdev; + } si4713_pdev_pdata.subdev = client; rval = platform_device_add_data(si4713_pdev, &si4713_pdev_pdata, diff --git a/drivers/media/radio/wl128x/Kconfig b/drivers/media/radio/wl128x/Kconfig index 9d6574b..c9e349b 100644 --- a/drivers/media/radio/wl128x/Kconfig +++ b/drivers/media/radio/wl128x/Kconfig @@ -4,8 +4,8 @@ menu "Texas Instruments WL128x FM driver (ST based)" config RADIO_WL128X tristate "Texas Instruments WL128x FM Radio" - depends on VIDEO_V4L2 && RFKILL && GPIOLIB && TTY - depends on TI_ST + depends on VIDEO_V4L2 && RFKILL && TTY && TI_ST + depends on GPIOLIB || COMPILE_TEST help Choose Y here if you have this FM radio chip. diff --git a/drivers/media/radio/wl128x/fmdrv.h b/drivers/media/radio/wl128x/fmdrv.h index a587c9b..dd203de 100644 --- a/drivers/media/radio/wl128x/fmdrv.h +++ b/drivers/media/radio/wl128x/fmdrv.h @@ -210,7 +210,7 @@ struct fmdev { spinlock_t resp_skb_lock; /* To protect access to received SKB */ long flag; /* FM driver state machine info */ - u8 streg_cbdata; /* status of ST registration */ + int streg_cbdata; /* status of ST registration */ struct sk_buff_head rx_q; /* RX queue */ struct tasklet_struct rx_task; /* RX Tasklet */ diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c index 5c63c2e..bd7b3bd 100644 --- a/drivers/media/rc/fintek-cir.c +++ b/drivers/media/rc/fintek-cir.c @@ -33,7 +33,6 @@ #include <linux/sched.h> #include <linux/slab.h> #include <media/rc-core.h> -#include <linux/pci_ids.h> #include "fintek-cir.h" diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 229853d..7dbc9ca 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -59,7 +59,7 @@ static int gpio_ir_recv_get_devtree_pdata(struct device *dev, return 0; } -static struct of_device_id gpio_ir_recv_of_match[] = { +static const struct of_device_id gpio_ir_recv_of_match[] = { { .compatible = "gpio-ir-receiver", }, { }, }; @@ -78,7 +78,7 @@ static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id) int rc = 0; enum raw_event_type type = IR_SPACE; - gval = gpio_get_value_cansleep(gpio_dev->gpio_nr); + gval = gpio_get_value(gpio_dev->gpio_nr); if (gval < 0) goto err_get_value; diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index 58ec598..1c087cb 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -63,7 +63,7 @@ struct hix5hd2_ir_priv { int irq; - void volatile __iomem *base; + void __iomem *base; struct device *dev; struct rc_dev *rdev; struct regmap *regmap; @@ -213,8 +213,8 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->base = devm_ioremap_resource(dev, res); - if (IS_ERR((__force void *)priv->base)) - return PTR_ERR((__force void *)priv->base); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); priv->irq = platform_get_irq(pdev, 0); if (priv->irq < 0) { @@ -319,7 +319,7 @@ static int hix5hd2_ir_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(hix5hd2_ir_pm_ops, hix5hd2_ir_suspend, hix5hd2_ir_resume); -static struct of_device_id hix5hd2_ir_table[] = { +static const struct of_device_id hix5hd2_ir_table[] = { { .compatible = "hisilicon,hix5hd2-ir", }, {}, }; diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c index 84fa6e9..8939ebd 100644 --- a/drivers/media/rc/ir-rc5-decoder.c +++ b/drivers/media/rc/ir-rc5-decoder.c @@ -184,9 +184,125 @@ out: return -EINVAL; } +static struct ir_raw_timings_manchester ir_rc5_timings = { + .leader = RC5_UNIT, + .pulse_space_start = 0, + .clock = RC5_UNIT, + .trailer_space = RC5_UNIT * 10, +}; + +static struct ir_raw_timings_manchester ir_rc5x_timings[2] = { + { + .leader = RC5_UNIT, + .pulse_space_start = 0, + .clock = RC5_UNIT, + .trailer_space = RC5X_SPACE, + }, + { + .clock = RC5_UNIT, + .trailer_space = RC5_UNIT * 10, + }, +}; + +static struct ir_raw_timings_manchester ir_rc5_sz_timings = { + .leader = RC5_UNIT, + .pulse_space_start = 0, + .clock = RC5_UNIT, + .trailer_space = RC5_UNIT * 10, +}; + +static int ir_rc5_validate_filter(const struct rc_scancode_filter *scancode, + unsigned int important_bits) +{ + /* all important bits of scancode should be set in mask */ + if (~scancode->mask & important_bits) + return -EINVAL; + /* extra bits in mask should be zero in data */ + if (scancode->mask & scancode->data & ~important_bits) + return -EINVAL; + return 0; +} + +/** + * ir_rc5_encode() - Encode a scancode as a stream of raw events + * + * @protocols: allowed protocols + * @scancode: scancode filter describing scancode (helps distinguish between + * protocol subtypes when scancode is ambiguous) + * @events: array of raw ir events to write into + * @max: maximum size of @events + * + * Returns: The number of events written. + * -ENOBUFS if there isn't enough space in the array to fit the + * encoding. In this case all @max events will have been written. + * -EINVAL if the scancode is ambiguous or invalid. + */ +static int ir_rc5_encode(u64 protocols, + const struct rc_scancode_filter *scancode, + struct ir_raw_event *events, unsigned int max) +{ + int ret; + struct ir_raw_event *e = events; + unsigned int data, xdata, command, commandx, system; + + /* Detect protocol and convert scancode to raw data */ + if (protocols & RC_BIT_RC5 && + !ir_rc5_validate_filter(scancode, 0x1f7f)) { + /* decode scancode */ + command = (scancode->data & 0x003f) >> 0; + commandx = (scancode->data & 0x0040) >> 6; + system = (scancode->data & 0x1f00) >> 8; + /* encode data */ + data = !commandx << 12 | system << 6 | command; + + /* Modulate the data */ + ret = ir_raw_gen_manchester(&e, max, &ir_rc5_timings, RC5_NBITS, + data); + if (ret < 0) + return ret; + } else if (protocols & RC_BIT_RC5X && + !ir_rc5_validate_filter(scancode, 0x1f7f3f)) { + /* decode scancode */ + xdata = (scancode->data & 0x00003f) >> 0; + command = (scancode->data & 0x003f00) >> 8; + commandx = (scancode->data & 0x004000) >> 14; + system = (scancode->data & 0x1f0000) >> 16; + /* commandx and system overlap, bits must match when encoded */ + if (commandx == (system & 0x1)) + return -EINVAL; + /* encode data */ + data = 1 << 18 | system << 12 | command << 6 | xdata; + + /* Modulate the data */ + ret = ir_raw_gen_manchester(&e, max, &ir_rc5x_timings[0], + CHECK_RC5X_NBITS, + data >> (RC5X_NBITS-CHECK_RC5X_NBITS)); + if (ret < 0) + return ret; + ret = ir_raw_gen_manchester(&e, max - (e - events), + &ir_rc5x_timings[1], + RC5X_NBITS - CHECK_RC5X_NBITS, + data); + if (ret < 0) + return ret; + } else if (protocols & RC_BIT_RC5_SZ && + !ir_rc5_validate_filter(scancode, 0x2fff)) { + /* RC5-SZ scancode is raw enough for Manchester as it is */ + ret = ir_raw_gen_manchester(&e, max, &ir_rc5_sz_timings, + RC5_SZ_NBITS, scancode->data & 0x2fff); + if (ret < 0) + return ret; + } else { + return -EINVAL; + } + + return e - events; +} + static struct ir_raw_handler rc5_handler = { .protocols = RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ, .decode = ir_rc5_decode, + .encode = ir_rc5_encode, }; static int __init ir_rc5_decode_init(void) diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index d16bc67..f9c70ba 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -291,11 +291,133 @@ out: return -EINVAL; } +static struct ir_raw_timings_manchester ir_rc6_timings[4] = { + { + .leader = RC6_PREFIX_PULSE, + .pulse_space_start = 0, + .clock = RC6_UNIT, + .invert = 1, + .trailer_space = RC6_PREFIX_SPACE, + }, + { + .clock = RC6_UNIT, + .invert = 1, + }, + { + .clock = RC6_UNIT * 2, + .invert = 1, + }, + { + .clock = RC6_UNIT, + .invert = 1, + .trailer_space = RC6_SUFFIX_SPACE, + }, +}; + +static int ir_rc6_validate_filter(const struct rc_scancode_filter *scancode, + unsigned int important_bits) +{ + /* all important bits of scancode should be set in mask */ + if (~scancode->mask & important_bits) + return -EINVAL; + /* extra bits in mask should be zero in data */ + if (scancode->mask & scancode->data & ~important_bits) + return -EINVAL; + return 0; +} + +/** + * ir_rc6_encode() - Encode a scancode as a stream of raw events + * + * @protocols: allowed protocols + * @scancode: scancode filter describing scancode (helps distinguish between + * protocol subtypes when scancode is ambiguous) + * @events: array of raw ir events to write into + * @max: maximum size of @events + * + * Returns: The number of events written. + * -ENOBUFS if there isn't enough space in the array to fit the + * encoding. In this case all @max events will have been written. + * -EINVAL if the scancode is ambiguous or invalid. + */ +static int ir_rc6_encode(u64 protocols, + const struct rc_scancode_filter *scancode, + struct ir_raw_event *events, unsigned int max) +{ + int ret; + struct ir_raw_event *e = events; + + if (protocols & RC_BIT_RC6_0 && + !ir_rc6_validate_filter(scancode, 0xffff)) { + + /* Modulate the preamble */ + ret = ir_raw_gen_manchester(&e, max, &ir_rc6_timings[0], 0, 0); + if (ret < 0) + return ret; + + /* Modulate the header (Start Bit & Mode-0) */ + ret = ir_raw_gen_manchester(&e, max - (e - events), + &ir_rc6_timings[1], + RC6_HEADER_NBITS, (1 << 3)); + if (ret < 0) + return ret; + + /* Modulate Trailer Bit */ + ret = ir_raw_gen_manchester(&e, max - (e - events), + &ir_rc6_timings[2], 1, 0); + if (ret < 0) + return ret; + + /* Modulate rest of the data */ + ret = ir_raw_gen_manchester(&e, max - (e - events), + &ir_rc6_timings[3], RC6_0_NBITS, + scancode->data); + if (ret < 0) + return ret; + + } else if (protocols & (RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | + RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE) && + !ir_rc6_validate_filter(scancode, 0x8fffffff)) { + + /* Modulate the preamble */ + ret = ir_raw_gen_manchester(&e, max, &ir_rc6_timings[0], 0, 0); + if (ret < 0) + return ret; + + /* Modulate the header (Start Bit & Header-version 6 */ + ret = ir_raw_gen_manchester(&e, max - (e - events), + &ir_rc6_timings[1], + RC6_HEADER_NBITS, (1 << 3 | 6)); + if (ret < 0) + return ret; + + /* Modulate Trailer Bit */ + ret = ir_raw_gen_manchester(&e, max - (e - events), + &ir_rc6_timings[2], 1, 0); + if (ret < 0) + return ret; + + /* Modulate rest of the data */ + ret = ir_raw_gen_manchester(&e, max - (e - events), + &ir_rc6_timings[3], + fls(scancode->mask), + scancode->data); + if (ret < 0) + return ret; + + } else { + return -EINVAL; + } + + return e - events; +} + static struct ir_raw_handler rc6_handler = { .protocols = RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE, .decode = ir_rc6_decode, + .encode = ir_rc6_encode, }; static int __init ir_rc6_decode_init(void) diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c index d12dc3d..58ef06f 100644 --- a/drivers/media/rc/ir-sony-decoder.c +++ b/drivers/media/rc/ir-sony-decoder.c @@ -125,30 +125,27 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) switch (data->count) { case 12: - if (!(dev->enabled_protocols & RC_BIT_SONY12)) { - data->state = STATE_INACTIVE; - return 0; - } + if (!(dev->enabled_protocols & RC_BIT_SONY12)) + goto finish_state_machine; + device = bitrev8((data->bits << 3) & 0xF8); subdevice = 0; function = bitrev8((data->bits >> 4) & 0xFE); protocol = RC_TYPE_SONY12; break; case 15: - if (!(dev->enabled_protocols & RC_BIT_SONY15)) { - data->state = STATE_INACTIVE; - return 0; - } + if (!(dev->enabled_protocols & RC_BIT_SONY15)) + goto finish_state_machine; + device = bitrev8((data->bits >> 0) & 0xFF); subdevice = 0; function = bitrev8((data->bits >> 7) & 0xFE); protocol = RC_TYPE_SONY15; break; case 20: - if (!(dev->enabled_protocols & RC_BIT_SONY20)) { - data->state = STATE_INACTIVE; - return 0; - } + if (!(dev->enabled_protocols & RC_BIT_SONY20)) + goto finish_state_machine; + device = bitrev8((data->bits >> 5) & 0xF8); subdevice = bitrev8((data->bits >> 0) & 0xFF); function = bitrev8((data->bits >> 12) & 0xFE); @@ -162,8 +159,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) scancode = device << 16 | subdevice << 8 | function; IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode); rc_keydown(dev, protocol, scancode, 0); - data->state = STATE_INACTIVE; - return 0; + goto finish_state_machine; } out: @@ -171,6 +167,10 @@ out: data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; + +finish_state_machine: + data->state = STATE_INACTIVE; + return 0; } static struct ir_raw_handler sony_handler = { diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index abf6079..fbbd3bb 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -84,7 +84,10 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-snapstream-firefly.o \ rc-streamzap.o \ rc-tbs-nec.o \ + rc-technisat-ts35.o \ rc-technisat-usb2.o \ + rc-terratec-cinergy-c-pci.o \ + rc-terratec-cinergy-s2-hd.o \ rc-terratec-cinergy-xs.o \ rc-terratec-slim.o \ rc-terratec-slim-2.o \ @@ -94,6 +97,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-total-media-in-hand-02.o \ rc-trekstor.o \ rc-tt-1500.o \ + rc-twinhan-dtv-cab-ci.o \ rc-twinhan1027.o \ rc-videomate-m1f.o \ rc-videomate-s350.o \ diff --git a/drivers/media/rc/keymaps/rc-technisat-ts35.c b/drivers/media/rc/keymaps/rc-technisat-ts35.c new file mode 100644 index 0000000..3328cbe --- /dev/null +++ b/drivers/media/rc/keymaps/rc-technisat-ts35.c @@ -0,0 +1,76 @@ +/* rc-technisat-ts35.c - Keytable for TechniSat TS35 remote + * + * Copyright (c) 2013 by Jan Klötzke <jan@kloetzke.net> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + */ + +#include <media/rc-map.h> +#include <linux/module.h> + +static struct rc_map_table technisat_ts35[] = { + {0x32, KEY_MUTE}, + {0x07, KEY_MEDIA}, + {0x1c, KEY_AB}, + {0x33, KEY_POWER}, + + {0x3e, KEY_1}, + {0x3d, KEY_2}, + {0x3c, KEY_3}, + {0x3b, KEY_4}, + {0x3a, KEY_5}, + {0x39, KEY_6}, + {0x38, KEY_7}, + {0x37, KEY_8}, + {0x36, KEY_9}, + {0x3f, KEY_0}, + {0x35, KEY_DIGITS}, + {0x2c, KEY_TV}, + + {0x20, KEY_INFO}, + {0x2d, KEY_MENU}, + {0x1f, KEY_UP}, + {0x1e, KEY_DOWN}, + {0x2e, KEY_LEFT}, + {0x2f, KEY_RIGHT}, + {0x28, KEY_OK}, + {0x10, KEY_EPG}, + {0x1d, KEY_BACK}, + + {0x14, KEY_RED}, + {0x13, KEY_GREEN}, + {0x12, KEY_YELLOW}, + {0x11, KEY_BLUE}, + + {0x09, KEY_SELECT}, + {0x03, KEY_TEXT}, + {0x16, KEY_STOP}, + {0x30, KEY_HELP}, +}; + +static struct rc_map_list technisat_ts35_map = { + .map = { + .scan = technisat_ts35, + .size = ARRAY_SIZE(technisat_ts35), + .rc_type = RC_TYPE_UNKNOWN, + .name = RC_MAP_TECHNISAT_TS35, + } +}; + +static int __init init_rc_map(void) +{ + return rc_map_register(&technisat_ts35_map); +} + +static void __exit exit_rc_map(void) +{ + rc_map_unregister(&technisat_ts35_map); +} + +module_init(init_rc_map) +module_exit(exit_rc_map) + +MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c new file mode 100644 index 0000000..7958f45 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c @@ -0,0 +1,88 @@ +/* keytable for Terratec Cinergy C PCI Remote Controller + * + * Copyright (c) 2010 by Igor M. Liplianin <liplianin@me.by> + * + * 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. + */ + +#include <media/rc-map.h> +#include <linux/module.h> + +static struct rc_map_table terratec_cinergy_c_pci[] = { + { 0x3e, KEY_POWER}, + { 0x3d, KEY_1}, + { 0x3c, KEY_2}, + { 0x3b, KEY_3}, + { 0x3a, KEY_4}, + { 0x39, KEY_5}, + { 0x38, KEY_6}, + { 0x37, KEY_7}, + { 0x36, KEY_8}, + { 0x35, KEY_9}, + { 0x34, KEY_VIDEO_NEXT}, /* AV */ + { 0x33, KEY_0}, + { 0x32, KEY_REFRESH}, + { 0x30, KEY_EPG}, + { 0x2f, KEY_UP}, + { 0x2e, KEY_LEFT}, + { 0x2d, KEY_OK}, + { 0x2c, KEY_RIGHT}, + { 0x2b, KEY_DOWN}, + { 0x29, KEY_INFO}, + { 0x28, KEY_RED}, + { 0x27, KEY_GREEN}, + { 0x26, KEY_YELLOW}, + { 0x25, KEY_BLUE}, + { 0x24, KEY_CHANNELUP}, + { 0x23, KEY_VOLUMEUP}, + { 0x22, KEY_MUTE}, + { 0x21, KEY_VOLUMEDOWN}, + { 0x20, KEY_CHANNELDOWN}, + { 0x1f, KEY_PAUSE}, + { 0x1e, KEY_HOME}, + { 0x1d, KEY_MENU}, /* DVD Menu */ + { 0x1c, KEY_SUBTITLE}, + { 0x1b, KEY_TEXT}, /* Teletext */ + { 0x1a, KEY_DELETE}, + { 0x19, KEY_TV}, + { 0x18, KEY_DVD}, + { 0x17, KEY_STOP}, + { 0x16, KEY_VIDEO}, + { 0x15, KEY_AUDIO}, /* Music */ + { 0x14, KEY_SCREEN}, /* Pic */ + { 0x13, KEY_PLAY}, + { 0x12, KEY_BACK}, + { 0x11, KEY_REWIND}, + { 0x10, KEY_FASTFORWARD}, + { 0x0b, KEY_PREVIOUS}, + { 0x07, KEY_RECORD}, + { 0x03, KEY_NEXT}, + +}; + +static struct rc_map_list terratec_cinergy_c_pci_map = { + .map = { + .scan = terratec_cinergy_c_pci, + .size = ARRAY_SIZE(terratec_cinergy_c_pci), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_TERRATEC_CINERGY_C_PCI, + } +}; + +static int __init init_rc_map_terratec_cinergy_c_pci(void) +{ + return rc_map_register(&terratec_cinergy_c_pci_map); +} + +static void __exit exit_rc_map_terratec_cinergy_c_pci(void) +{ + rc_map_unregister(&terratec_cinergy_c_pci_map); +} + +module_init(init_rc_map_terratec_cinergy_c_pci); +module_exit(exit_rc_map_terratec_cinergy_c_pci); + +MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c new file mode 100644 index 0000000..1e096bb --- /dev/null +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c @@ -0,0 +1,86 @@ +/* keytable for Terratec Cinergy S2 HD Remote Controller + * + * 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. + */ + +#include <media/rc-map.h> +#include <linux/module.h> + +static struct rc_map_table terratec_cinergy_s2_hd[] = { + { 0x03, KEY_NEXT}, /* >| */ + { 0x07, KEY_RECORD}, + { 0x0b, KEY_PREVIOUS}, /* |< */ + { 0x10, KEY_FASTFORWARD}, /* >> */ + { 0x11, KEY_REWIND}, /* << */ + { 0x12, KEY_ESC}, /* Back */ + { 0x13, KEY_PLAY}, + { 0x14, KEY_IMAGES}, + { 0x15, KEY_AUDIO}, + { 0x16, KEY_MEDIA}, /* Video-Menu */ + { 0x17, KEY_STOP}, + { 0x18, KEY_DVD}, + { 0x19, KEY_TV}, + { 0x1a, KEY_DELETE}, + { 0x1b, KEY_TEXT}, + { 0x1c, KEY_SUBTITLE}, + { 0x1d, KEY_MENU}, /* DVD-Menu */ + { 0x1e, KEY_HOME}, + { 0x1f, KEY_PAUSE}, + { 0x20, KEY_CHANNELDOWN}, + { 0x21, KEY_VOLUMEDOWN}, + { 0x22, KEY_MUTE}, + { 0x23, KEY_VOLUMEUP}, + { 0x24, KEY_CHANNELUP}, + { 0x25, KEY_BLUE}, + { 0x26, KEY_YELLOW}, + { 0x27, KEY_GREEN}, + { 0x28, KEY_RED}, + { 0x29, KEY_INFO}, + { 0x2b, KEY_DOWN}, + { 0x2c, KEY_RIGHT}, + { 0x2d, KEY_OK}, + { 0x2e, KEY_LEFT}, + { 0x2f, KEY_UP}, + { 0x30, KEY_EPG}, + { 0x32, KEY_VIDEO}, /* A<=>B */ + { 0x33, KEY_0}, + { 0x34, KEY_VCR}, /* AV */ + { 0x35, KEY_9}, + { 0x36, KEY_8}, + { 0x37, KEY_7}, + { 0x38, KEY_6}, + { 0x39, KEY_5}, + { 0x3a, KEY_4}, + { 0x3b, KEY_3}, + { 0x3c, KEY_2}, + { 0x3d, KEY_1}, + { 0x3e, KEY_POWER}, + +}; + +static struct rc_map_list terratec_cinergy_s2_hd_map = { + .map = { + .scan = terratec_cinergy_s2_hd, + .size = ARRAY_SIZE(terratec_cinergy_s2_hd), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_TERRATEC_CINERGY_S2_HD, + } +}; + +static int __init init_rc_map_terratec_cinergy_s2_hd(void) +{ + return rc_map_register(&terratec_cinergy_s2_hd_map); +} + +static void __exit exit_rc_map_terratec_cinergy_s2_hd(void) +{ + rc_map_unregister(&terratec_cinergy_s2_hd_map); +} + +module_init(init_rc_map_terratec_cinergy_s2_hd); +module_exit(exit_rc_map_terratec_cinergy_s2_hd); + +MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c b/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c new file mode 100644 index 0000000..202500c --- /dev/null +++ b/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c @@ -0,0 +1,98 @@ +/* keytable for Twinhan DTV CAB CI Remote Controller + * + * Copyright (c) 2010 by Igor M. Liplianin <liplianin@me.by> + * + * 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. + */ + +#include <media/rc-map.h> +#include <linux/module.h> + +static struct rc_map_table twinhan_dtv_cab_ci[] = { + { 0x29, KEY_POWER}, + { 0x28, KEY_FAVORITES}, + { 0x30, KEY_TEXT}, + { 0x17, KEY_INFO}, /* Preview */ + { 0x23, KEY_EPG}, + { 0x3b, KEY_F22}, /* Record List */ + + { 0x3c, KEY_1}, + { 0x3e, KEY_2}, + { 0x39, KEY_3}, + { 0x36, KEY_4}, + { 0x22, KEY_5}, + { 0x20, KEY_6}, + { 0x32, KEY_7}, + { 0x26, KEY_8}, + { 0x24, KEY_9}, + { 0x2a, KEY_0}, + + { 0x33, KEY_CANCEL}, + { 0x2c, KEY_BACK}, + { 0x15, KEY_CLEAR}, + { 0x3f, KEY_TAB}, + { 0x10, KEY_ENTER}, + { 0x14, KEY_UP}, + { 0x0d, KEY_RIGHT}, + { 0x0e, KEY_DOWN}, + { 0x11, KEY_LEFT}, + + { 0x21, KEY_VOLUMEUP}, + { 0x35, KEY_VOLUMEDOWN}, + { 0x3d, KEY_CHANNELDOWN}, + { 0x3a, KEY_CHANNELUP}, + { 0x2e, KEY_RECORD}, + { 0x2b, KEY_PLAY}, + { 0x13, KEY_PAUSE}, + { 0x25, KEY_STOP}, + + { 0x1f, KEY_REWIND}, + { 0x2d, KEY_FASTFORWARD}, + { 0x1e, KEY_PREVIOUS}, /* Replay |< */ + { 0x1d, KEY_NEXT}, /* Skip >| */ + + { 0x0b, KEY_CAMERA}, /* Capture */ + { 0x0f, KEY_LANGUAGE}, /* SAP */ + { 0x18, KEY_MODE}, /* PIP */ + { 0x12, KEY_ZOOM}, /* Full screen */ + { 0x1c, KEY_SUBTITLE}, + { 0x2f, KEY_MUTE}, + { 0x16, KEY_F20}, /* L/R */ + { 0x38, KEY_F21}, /* Hibernate */ + + { 0x37, KEY_SWITCHVIDEOMODE}, /* A/V */ + { 0x31, KEY_AGAIN}, /* Recall */ + { 0x1a, KEY_KPPLUS}, /* Zoom+ */ + { 0x19, KEY_KPMINUS}, /* Zoom- */ + { 0x27, KEY_RED}, + { 0x0C, KEY_GREEN}, + { 0x01, KEY_YELLOW}, + { 0x00, KEY_BLUE}, +}; + +static struct rc_map_list twinhan_dtv_cab_ci_map = { + .map = { + .scan = twinhan_dtv_cab_ci, + .size = ARRAY_SIZE(twinhan_dtv_cab_ci), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_TWINHAN_DTV_CAB_CI, + } +}; + +static int __init init_rc_map_twinhan_dtv_cab_ci(void) +{ + return rc_map_register(&twinhan_dtv_cab_ci_map); +} + +static void __exit exit_rc_map_twinhan_dtv_cab_ci(void) +{ + rc_map_unregister(&twinhan_dtv_cab_ci_map); +} + +module_init(init_rc_map_twinhan_dtv_cab_ci); +module_exit(exit_rc_map_twinhan_dtv_cab_ci); + +MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 85af7a8..baeb597 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -526,6 +526,130 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier) return 0; } +static int nvt_write_wakeup_codes(struct rc_dev *dev, + const u8 *wakeup_sample_buf, int count) +{ + int i = 0; + u8 reg, reg_learn_mode; + unsigned long flags; + struct nvt_dev *nvt = dev->priv; + + nvt_dbg_wake("writing wakeup samples"); + + reg = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON); + reg_learn_mode = reg & ~CIR_WAKE_IRCON_MODE0; + reg_learn_mode |= CIR_WAKE_IRCON_MODE1; + + /* Lock the learn area to prevent racing with wake-isr */ + spin_lock_irqsave(&nvt->nvt_lock, flags); + + /* Enable fifo writes */ + nvt_cir_wake_reg_write(nvt, reg_learn_mode, CIR_WAKE_IRCON); + + /* Clear cir wake rx fifo */ + nvt_clear_cir_wake_fifo(nvt); + + if (count > WAKE_FIFO_LEN) { + nvt_dbg_wake("HW FIFO too small for all wake samples"); + count = WAKE_FIFO_LEN; + } + + if (count) + pr_info("Wake samples (%d) =", count); + else + pr_info("Wake sample fifo cleared"); + + /* Write wake samples to fifo */ + for (i = 0; i < count; i++) { + pr_cont(" %02x", wakeup_sample_buf[i]); + nvt_cir_wake_reg_write(nvt, wakeup_sample_buf[i], + CIR_WAKE_WR_FIFO_DATA); + } + pr_cont("\n"); + + /* Switch cir to wakeup mode and disable fifo writing */ + nvt_cir_wake_reg_write(nvt, reg, CIR_WAKE_IRCON); + + /* Set number of bytes needed for wake */ + nvt_cir_wake_reg_write(nvt, count ? count : + CIR_WAKE_FIFO_CMP_BYTES, + CIR_WAKE_FIFO_CMP_DEEP); + + spin_unlock_irqrestore(&nvt->nvt_lock, flags); + + return 0; +} + +static int nvt_ir_raw_set_wakeup_filter(struct rc_dev *dev, + struct rc_scancode_filter *sc_filter) +{ + u8 *reg_buf; + u8 buf_val; + int i, ret, count; + unsigned int val; + struct ir_raw_event *raw; + bool complete; + + /* Require both mask and data to be set before actually committing */ + if (!sc_filter->mask || !sc_filter->data) + return 0; + + raw = kmalloc_array(WAKE_FIFO_LEN, sizeof(*raw), GFP_KERNEL); + if (!raw) + return -ENOMEM; + + ret = ir_raw_encode_scancode(dev->enabled_wakeup_protocols, sc_filter, + raw, WAKE_FIFO_LEN); + complete = (ret != -ENOBUFS); + if (!complete) + ret = WAKE_FIFO_LEN; + else if (ret < 0) + goto out_raw; + + reg_buf = kmalloc_array(WAKE_FIFO_LEN, sizeof(*reg_buf), GFP_KERNEL); + if (!reg_buf) { + ret = -ENOMEM; + goto out_raw; + } + + /* Inspect the ir samples */ + for (i = 0, count = 0; i < ret && count < WAKE_FIFO_LEN; ++i) { + val = NS_TO_US((raw[i]).duration) / SAMPLE_PERIOD; + + /* Split too large values into several smaller ones */ + while (val > 0 && count < WAKE_FIFO_LEN) { + + /* Skip last value for better comparison tolerance */ + if (complete && i == ret - 1 && val < BUF_LEN_MASK) + break; + + /* Clamp values to BUF_LEN_MASK at most */ + buf_val = (val > BUF_LEN_MASK) ? BUF_LEN_MASK : val; + + reg_buf[count] = buf_val; + val -= buf_val; + if ((raw[i]).pulse) + reg_buf[count] |= BUF_PULSE_BIT; + count++; + } + } + + ret = nvt_write_wakeup_codes(dev, reg_buf, count); + + kfree(reg_buf); +out_raw: + kfree(raw); + + return ret; +} + +/* Dummy implementation. nuvoton is agnostic to the protocol used */ +static int nvt_ir_raw_change_wakeup_protocol(struct rc_dev *dev, + u64 *rc_type) +{ + return 0; +} + /* * nvt_tx_ir * @@ -1043,11 +1167,14 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) /* Set up the rc device */ rdev->priv = nvt; rdev->driver_type = RC_DRIVER_IR_RAW; + rdev->encode_wakeup = true; rdev->allowed_protocols = RC_BIT_ALL; rdev->open = nvt_open; rdev->close = nvt_close; rdev->tx_ir = nvt_tx_ir; rdev->s_tx_carrier = nvt_set_tx_carrier; + rdev->s_wakeup_filter = nvt_ir_raw_set_wakeup_filter; + rdev->change_wakeup_protocol = nvt_ir_raw_change_wakeup_protocol; rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver"; rdev->input_phys = "nuvoton/cir0"; rdev->input_id.bustype = BUS_HOST; diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h index e1cf23c..9d0e161 100644 --- a/drivers/media/rc/nuvoton-cir.h +++ b/drivers/media/rc/nuvoton-cir.h @@ -63,6 +63,7 @@ static int debug; */ #define TX_BUF_LEN 256 #define RX_BUF_LEN 32 +#define WAKE_FIFO_LEN 67 struct nvt_dev { struct pnp_dev *pdev; diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index b68d4f76..4b994aa 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -25,6 +25,8 @@ struct ir_raw_handler { u64 protocols; /* which are handled by this handler */ int (*decode)(struct rc_dev *dev, struct ir_raw_event event); + int (*encode)(u64 protocols, const struct rc_scancode_filter *scancode, + struct ir_raw_event *events, unsigned int max); /* These two should only be used by the lirc decoder */ int (*raw_register)(struct rc_dev *dev); @@ -150,10 +152,44 @@ static inline bool is_timing_event(struct ir_raw_event ev) #define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000) #define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space") +/* functions for IR encoders */ + +static inline void init_ir_raw_event_duration(struct ir_raw_event *ev, + unsigned int pulse, + u32 duration) +{ + init_ir_raw_event(ev); + ev->duration = duration; + ev->pulse = pulse; +} + +/** + * struct ir_raw_timings_manchester - Manchester coding timings + * @leader: duration of leader pulse (if any) 0 if continuing + * existing signal (see @pulse_space_start) + * @pulse_space_start: 1 for starting with pulse (0 for starting with space) + * @clock: duration of each pulse/space in ns + * @invert: if set clock logic is inverted + * (0 = space + pulse, 1 = pulse + space) + * @trailer_space: duration of trailer space in ns + */ +struct ir_raw_timings_manchester { + unsigned int leader; + unsigned int pulse_space_start:1; + unsigned int clock; + unsigned int invert:1; + unsigned int trailer_space; +}; + +int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max, + const struct ir_raw_timings_manchester *timings, + unsigned int n, unsigned int data); + /* * Routines from rc-raw.c to be used internally and by decoders */ u64 ir_raw_get_allowed_protocols(void); +u64 ir_raw_get_encode_protocols(void); int ir_raw_event_register(struct rc_dev *dev); void ir_raw_event_unregister(struct rc_dev *dev); int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler); diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index b732ac6..b9e4645 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -30,6 +30,7 @@ static LIST_HEAD(ir_raw_client_list); static DEFINE_MUTEX(ir_raw_handler_lock); static LIST_HEAD(ir_raw_handler_list); static u64 available_protocols; +static u64 encode_protocols; static int ir_raw_event_thread(void *data) { @@ -240,12 +241,146 @@ ir_raw_get_allowed_protocols(void) return protocols; } +/* used internally by the sysfs interface */ +u64 +ir_raw_get_encode_protocols(void) +{ + u64 protocols; + + mutex_lock(&ir_raw_handler_lock); + protocols = encode_protocols; + mutex_unlock(&ir_raw_handler_lock); + return protocols; +} + static int change_protocol(struct rc_dev *dev, u64 *rc_type) { /* the caller will update dev->enabled_protocols */ return 0; } +/** + * ir_raw_gen_manchester() - Encode data with Manchester (bi-phase) modulation. + * @ev: Pointer to pointer to next free event. *@ev is incremented for + * each raw event filled. + * @max: Maximum number of raw events to fill. + * @timings: Manchester modulation timings. + * @n: Number of bits of data. + * @data: Data bits to encode. + * + * Encodes the @n least significant bits of @data using Manchester (bi-phase) + * modulation with the timing characteristics described by @timings, writing up + * to @max raw IR events using the *@ev pointer. + * + * Returns: 0 on success. + * -ENOBUFS if there isn't enough space in the array to fit the + * full encoded data. In this case all @max events will have been + * written. + */ +int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max, + const struct ir_raw_timings_manchester *timings, + unsigned int n, unsigned int data) +{ + bool need_pulse; + unsigned int i; + int ret = -ENOBUFS; + + i = 1 << (n - 1); + + if (timings->leader) { + if (!max--) + return ret; + if (timings->pulse_space_start) { + init_ir_raw_event_duration((*ev)++, 1, timings->leader); + + if (!max--) + return ret; + init_ir_raw_event_duration((*ev), 0, timings->leader); + } else { + init_ir_raw_event_duration((*ev), 1, timings->leader); + } + i >>= 1; + } else { + /* continue existing signal */ + --(*ev); + } + /* from here on *ev will point to the last event rather than the next */ + + while (n && i > 0) { + need_pulse = !(data & i); + if (timings->invert) + need_pulse = !need_pulse; + if (need_pulse == !!(*ev)->pulse) { + (*ev)->duration += timings->clock; + } else { + if (!max--) + goto nobufs; + init_ir_raw_event_duration(++(*ev), need_pulse, + timings->clock); + } + + if (!max--) + goto nobufs; + init_ir_raw_event_duration(++(*ev), !need_pulse, + timings->clock); + i >>= 1; + } + + if (timings->trailer_space) { + if (!(*ev)->pulse) + (*ev)->duration += timings->trailer_space; + else if (!max--) + goto nobufs; + else + init_ir_raw_event_duration(++(*ev), 0, + timings->trailer_space); + } + + ret = 0; +nobufs: + /* point to the next event rather than last event before returning */ + ++(*ev); + return ret; +} +EXPORT_SYMBOL(ir_raw_gen_manchester); + +/** + * ir_raw_encode_scancode() - Encode a scancode as raw events + * + * @protocols: permitted protocols + * @scancode: scancode filter describing a single scancode + * @events: array of raw events to write into + * @max: max number of raw events + * + * Attempts to encode the scancode as raw events. + * + * Returns: The number of events written. + * -ENOBUFS if there isn't enough space in the array to fit the + * encoding. In this case all @max events will have been written. + * -EINVAL if the scancode is ambiguous or invalid, or if no + * compatible encoder was found. + */ +int ir_raw_encode_scancode(u64 protocols, + const struct rc_scancode_filter *scancode, + struct ir_raw_event *events, unsigned int max) +{ + struct ir_raw_handler *handler; + int ret = -EINVAL; + + mutex_lock(&ir_raw_handler_lock); + list_for_each_entry(handler, &ir_raw_handler_list, list) { + if (handler->protocols & protocols && handler->encode) { + ret = handler->encode(protocols, scancode, events, max); + if (ret >= 0 || ret == -ENOBUFS) + break; + } + } + mutex_unlock(&ir_raw_handler_lock); + + return ret; +} +EXPORT_SYMBOL(ir_raw_encode_scancode); + /* * Used to (un)register raw event clients */ @@ -328,6 +463,8 @@ int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler) list_for_each_entry(raw, &ir_raw_client_list, list) ir_raw_handler->raw_register(raw->dev); available_protocols |= ir_raw_handler->protocols; + if (ir_raw_handler->encode) + encode_protocols |= ir_raw_handler->protocols; mutex_unlock(&ir_raw_handler_lock); return 0; @@ -344,6 +481,8 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) list_for_each_entry(raw, &ir_raw_client_list, list) ir_raw_handler->raw_unregister(raw->dev); available_protocols &= ~ir_raw_handler->protocols; + if (ir_raw_handler->encode) + encode_protocols &= ~ir_raw_handler->protocols; mutex_unlock(&ir_raw_handler_lock); } EXPORT_SYMBOL(ir_raw_handler_unregister); diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c index 63dace8..d8bdf63 100644 --- a/drivers/media/rc/rc-loopback.c +++ b/drivers/media/rc/rc-loopback.c @@ -26,6 +26,7 @@ #include <linux/device.h> #include <linux/module.h> #include <linux/sched.h> +#include <linux/slab.h> #include <media/rc-core.h> #define DRIVER_NAME "rc-loopback" @@ -176,6 +177,39 @@ static int loop_set_carrier_report(struct rc_dev *dev, int enable) return 0; } +static int loop_set_wakeup_filter(struct rc_dev *dev, + struct rc_scancode_filter *sc_filter) +{ + static const unsigned int max = 512; + struct ir_raw_event *raw; + int ret; + int i; + + /* fine to disable filter */ + if (!sc_filter->mask) + return 0; + + /* encode the specified filter and loop it back */ + raw = kmalloc_array(max, sizeof(*raw), GFP_KERNEL); + ret = ir_raw_encode_scancode(dev->enabled_wakeup_protocols, sc_filter, + raw, max); + /* still loop back the partial raw IR even if it's incomplete */ + if (ret == -ENOBUFS) + ret = max; + if (ret >= 0) { + /* do the loopback */ + for (i = 0; i < ret; ++i) + ir_raw_event_store(dev, &raw[i]); + ir_raw_event_handle(dev); + + ret = 0; + } + + kfree(raw); + + return ret; +} + static int __init loop_init(void) { struct rc_dev *rc; @@ -195,6 +229,7 @@ static int __init loop_init(void) rc->map_name = RC_MAP_EMPTY; rc->priv = &loopdev; rc->driver_type = RC_DRIVER_IR_RAW; + rc->encode_wakeup = true; rc->allowed_protocols = RC_BIT_ALL; rc->timeout = 100 * 1000 * 1000; /* 100 ms */ rc->min_timeout = 1; @@ -209,6 +244,7 @@ static int __init loop_init(void) rc->s_idle = loop_set_idle; rc->s_learning_mode = loop_set_learning_mode; rc->s_carrier_report = loop_set_carrier_report; + rc->s_wakeup_filter = loop_set_wakeup_filter; loopdev.txmask = RXMASK_REGULAR; loopdev.txcarrier = 36000; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index f8c5e47..9d015db 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -746,7 +746,7 @@ void rc_close(struct rc_dev *rdev) if (rdev) { mutex_lock(&rdev->lock); - if (!--rdev->users && rdev->close != NULL) + if (!--rdev->users && rdev->close != NULL) rdev->close(rdev); mutex_unlock(&rdev->lock); @@ -865,6 +865,8 @@ static ssize_t show_protocols(struct device *device, } else { enabled = dev->enabled_wakeup_protocols; allowed = dev->allowed_wakeup_protocols; + if (dev->encode_wakeup && !allowed) + allowed = ir_raw_get_encode_protocols(); } mutex_unlock(&dev->lock); @@ -1406,13 +1408,16 @@ int rc_register_device(struct rc_dev *dev) path ? path : "N/A"); kfree(path); - if (dev->driver_type == RC_DRIVER_IR_RAW) { + if (dev->driver_type == RC_DRIVER_IR_RAW || dev->encode_wakeup) { /* Load raw decoders, if they aren't already */ if (!raw_init) { IR_dprintk(1, "Loading raw decoders\n"); ir_raw_init(); raw_init = true; } + } + + if (dev->driver_type == RC_DRIVER_IR_RAW) { /* calls ir_register_device so unlock mutex here*/ mutex_unlock(&dev->lock); rc = ir_raw_event_register(dev); diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index c4def66..ec74244 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -322,7 +322,7 @@ static u32 redrat3_us_to_len(u32 microsec) u32 result; u32 divisor; - microsec &= IR_MAX_DURATION; + microsec = (microsec > IR_MAX_DURATION) ? IR_MAX_DURATION : microsec; divisor = (RR3_CLK_CONV_FACTOR / 1000); result = (u32)(microsec * divisor) / 1000; @@ -380,7 +380,8 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) if (i == 0) trailer = rawir.duration; /* cap the value to IR_MAX_DURATION */ - rawir.duration &= IR_MAX_DURATION; + rawir.duration = (rawir.duration > IR_MAX_DURATION) ? + IR_MAX_DURATION : rawir.duration; dev_dbg(dev, "storing %s with duration %d (i: %d)\n", rawir.pulse ? "pulse" : "space", rawir.duration, i); @@ -405,7 +406,7 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) } /* Util fn to send rr3 cmds */ -static u8 redrat3_send_cmd(int cmd, struct redrat3_dev *rr3) +static int redrat3_send_cmd(int cmd, struct redrat3_dev *rr3) { struct usb_device *udev; u8 *data; diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index 0e758ae..37d0401 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -22,8 +22,8 @@ struct st_rc_device { int irq; int irq_wake; struct clk *sys_clock; - volatile void __iomem *base; /* Register base address */ - volatile void __iomem *rx_base;/* RX Register base address */ + void __iomem *base; /* Register base address */ + void __iomem *rx_base;/* RX Register base address */ struct rc_dev *rdev; bool overclocking; int sample_mult; @@ -267,8 +267,8 @@ static int st_rc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); rc_dev->base = devm_ioremap_resource(dev, res); - if (IS_ERR((__force void *)rc_dev->base)) { - ret = PTR_ERR((__force void *)rc_dev->base); + if (IS_ERR(rc_dev->base)) { + ret = PTR_ERR(rc_dev->base); goto err; } @@ -334,7 +334,7 @@ err: return ret; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int st_rc_suspend(struct device *dev) { struct st_rc_device *rc_dev = dev_get_drvdata(dev); @@ -381,7 +381,7 @@ static int st_rc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(st_rc_pm_ops, st_rc_suspend, st_rc_resume); #ifdef CONFIG_OF -static struct of_device_id st_rc_match[] = { +static const struct of_device_id st_rc_match[] = { { .compatible = "st,comms-irb", }, {}, }; diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index bf4a442..5a17cb8 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -152,7 +152,8 @@ static void sz_push_full_pulse(struct streamzap_ir *sz, sz->signal_last.tv_usec); rawir.duration -= sz->sum; rawir.duration = US_TO_NS(rawir.duration); - rawir.duration &= IR_MAX_DURATION; + rawir.duration = (rawir.duration > IR_MAX_DURATION) ? + IR_MAX_DURATION : rawir.duration; } sz_push(sz, rawir); @@ -165,7 +166,8 @@ static void sz_push_full_pulse(struct streamzap_ir *sz, rawir.duration += SZ_RESOLUTION / 2; sz->sum += rawir.duration; rawir.duration = US_TO_NS(rawir.duration); - rawir.duration &= IR_MAX_DURATION; + rawir.duration = (rawir.duration > IR_MAX_DURATION) ? + IR_MAX_DURATION : rawir.duration; sz_push(sz, rawir); } diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index 983510d..8294af9 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -220,6 +220,7 @@ config MEDIA_TUNER_E4000 config MEDIA_TUNER_FC2580 tristate "FCI FC2580 silicon tuner" depends on MEDIA_SUPPORT && I2C + select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT help FCI FC2580 silicon tuner driver. @@ -233,8 +234,9 @@ config MEDIA_TUNER_M88RS6000T Montage M88RS6000 internal tuner. config MEDIA_TUNER_TUA9001 - tristate "Infineon TUA 9001 silicon tuner" + tristate "Infineon TUA9001 silicon tuner" depends on MEDIA_SUPPORT && I2C + select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT help Infineon TUA 9001 silicon tuner driver. @@ -258,6 +260,7 @@ config MEDIA_TUNER_R820T tristate "Rafael Micro R820T silicon tuner" depends on MEDIA_SUPPORT && I2C default m if !MEDIA_SUBDRV_AUTOSELECT + select BITREVERSE help Rafael Micro R820T silicon tuner driver. diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c index 510239f..03538f8 100644 --- a/drivers/media/tuners/e4000.c +++ b/drivers/media/tuners/e4000.c @@ -19,164 +19,176 @@ */ #include "e4000_priv.h" -#include <linux/math64.h> -static int e4000_init(struct dvb_frontend *fe) +static int e4000_init(struct e4000_dev *dev) { - struct e4000 *s = fe->tuner_priv; + struct i2c_client *client = dev->client; int ret; - dev_dbg(&s->client->dev, "\n"); - - /* dummy I2C to ensure I2C wakes up */ - ret = regmap_write(s->regmap, 0x02, 0x40); + dev_dbg(&client->dev, "\n"); /* reset */ - ret = regmap_write(s->regmap, 0x00, 0x01); + ret = regmap_write(dev->regmap, 0x00, 0x01); if (ret) goto err; /* disable output clock */ - ret = regmap_write(s->regmap, 0x06, 0x00); + ret = regmap_write(dev->regmap, 0x06, 0x00); if (ret) goto err; - ret = regmap_write(s->regmap, 0x7a, 0x96); + ret = regmap_write(dev->regmap, 0x7a, 0x96); if (ret) goto err; /* configure gains */ - ret = regmap_bulk_write(s->regmap, 0x7e, "\x01\xfe", 2); + ret = regmap_bulk_write(dev->regmap, 0x7e, "\x01\xfe", 2); if (ret) goto err; - ret = regmap_write(s->regmap, 0x82, 0x00); + ret = regmap_write(dev->regmap, 0x82, 0x00); if (ret) goto err; - ret = regmap_write(s->regmap, 0x24, 0x05); + ret = regmap_write(dev->regmap, 0x24, 0x05); if (ret) goto err; - ret = regmap_bulk_write(s->regmap, 0x87, "\x20\x01", 2); + ret = regmap_bulk_write(dev->regmap, 0x87, "\x20\x01", 2); if (ret) goto err; - ret = regmap_bulk_write(s->regmap, 0x9f, "\x7f\x07", 2); + ret = regmap_bulk_write(dev->regmap, 0x9f, "\x7f\x07", 2); if (ret) goto err; /* DC offset control */ - ret = regmap_write(s->regmap, 0x2d, 0x1f); + ret = regmap_write(dev->regmap, 0x2d, 0x1f); if (ret) goto err; - ret = regmap_bulk_write(s->regmap, 0x70, "\x01\x01", 2); + ret = regmap_bulk_write(dev->regmap, 0x70, "\x01\x01", 2); if (ret) goto err; /* gain control */ - ret = regmap_write(s->regmap, 0x1a, 0x17); + ret = regmap_write(dev->regmap, 0x1a, 0x17); if (ret) goto err; - ret = regmap_write(s->regmap, 0x1f, 0x1a); + ret = regmap_write(dev->regmap, 0x1f, 0x1a); if (ret) goto err; - s->active = true; -err: - if (ret) - dev_dbg(&s->client->dev, "failed=%d\n", ret); + dev->active = true; + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } -static int e4000_sleep(struct dvb_frontend *fe) +static int e4000_sleep(struct e4000_dev *dev) { - struct e4000 *s = fe->tuner_priv; + struct i2c_client *client = dev->client; int ret; - dev_dbg(&s->client->dev, "\n"); + dev_dbg(&client->dev, "\n"); - s->active = false; + dev->active = false; - ret = regmap_write(s->regmap, 0x00, 0x00); + ret = regmap_write(dev->regmap, 0x00, 0x00); if (ret) goto err; -err: - if (ret) - dev_dbg(&s->client->dev, "failed=%d\n", ret); + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } -static int e4000_set_params(struct dvb_frontend *fe) +static int e4000_set_params(struct e4000_dev *dev) { - struct e4000 *s = fe->tuner_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret, i, sigma_delta; - unsigned int pll_n, pll_f; + struct i2c_client *client = dev->client; + int ret, i; + unsigned int div_n, k, k_cw, div_out; u64 f_vco; u8 buf[5], i_data[4], q_data[4]; - dev_dbg(&s->client->dev, - "delivery_system=%d frequency=%u bandwidth_hz=%u\n", - c->delivery_system, c->frequency, c->bandwidth_hz); + if (!dev->active) { + dev_dbg(&client->dev, "tuner is sleeping\n"); + return 0; + } /* gain control manual */ - ret = regmap_write(s->regmap, 0x1a, 0x00); - if (ret) - goto err; - - /* PLL */ + ret = regmap_write(dev->regmap, 0x1a, 0x00); + if (ret) + goto err; + + /* + * Fractional-N synthesizer + * + * +----------------------------+ + * v | + * Fref +----+ +-------+ +------+ +---+ + * ------> | PD | --> | VCO | ------> | /N.F | <-- | K | + * +----+ +-------+ +------+ +---+ + * | + * | + * v + * +-------+ Fout + * | /Rout | ------> + * +-------+ + */ for (i = 0; i < ARRAY_SIZE(e4000_pll_lut); i++) { - if (c->frequency <= e4000_pll_lut[i].freq) + if (dev->f_frequency <= e4000_pll_lut[i].freq) break; } - if (i == ARRAY_SIZE(e4000_pll_lut)) { ret = -EINVAL; goto err; } - f_vco = 1ull * c->frequency * e4000_pll_lut[i].mul; - pll_n = div_u64_rem(f_vco, s->clock, &pll_f); - sigma_delta = div_u64(0x10000ULL * pll_f, s->clock); - buf[0] = pll_n; - buf[1] = (sigma_delta >> 0) & 0xff; - buf[2] = (sigma_delta >> 8) & 0xff; + #define F_REF dev->clk + div_out = e4000_pll_lut[i].div_out; + f_vco = (u64) dev->f_frequency * div_out; + /* calculate PLL integer and fractional control word */ + div_n = div_u64_rem(f_vco, F_REF, &k); + k_cw = div_u64((u64) k * 0x10000, F_REF); + + dev_dbg(&client->dev, + "frequency=%u bandwidth=%u f_vco=%llu F_REF=%u div_n=%u k=%u k_cw=%04x div_out=%u\n", + dev->f_frequency, dev->f_bandwidth, f_vco, F_REF, div_n, k, + k_cw, div_out); + + buf[0] = div_n; + buf[1] = (k_cw >> 0) & 0xff; + buf[2] = (k_cw >> 8) & 0xff; buf[3] = 0x00; - buf[4] = e4000_pll_lut[i].div; - - dev_dbg(&s->client->dev, "f_vco=%llu pll div=%d sigma_delta=%04x\n", - f_vco, buf[0], sigma_delta); - - ret = regmap_bulk_write(s->regmap, 0x09, buf, 5); + buf[4] = e4000_pll_lut[i].div_out_reg; + ret = regmap_bulk_write(dev->regmap, 0x09, buf, 5); if (ret) goto err; /* LNA filter (RF filter) */ for (i = 0; i < ARRAY_SIZE(e400_lna_filter_lut); i++) { - if (c->frequency <= e400_lna_filter_lut[i].freq) + if (dev->f_frequency <= e400_lna_filter_lut[i].freq) break; } - if (i == ARRAY_SIZE(e400_lna_filter_lut)) { ret = -EINVAL; goto err; } - ret = regmap_write(s->regmap, 0x10, e400_lna_filter_lut[i].val); + ret = regmap_write(dev->regmap, 0x10, e400_lna_filter_lut[i].val); if (ret) goto err; /* IF filters */ for (i = 0; i < ARRAY_SIZE(e4000_if_filter_lut); i++) { - if (c->bandwidth_hz <= e4000_if_filter_lut[i].freq) + if (dev->f_bandwidth <= e4000_if_filter_lut[i].freq) break; } - if (i == ARRAY_SIZE(e4000_if_filter_lut)) { ret = -EINVAL; goto err; @@ -185,48 +197,47 @@ static int e4000_set_params(struct dvb_frontend *fe) buf[0] = e4000_if_filter_lut[i].reg11_val; buf[1] = e4000_if_filter_lut[i].reg12_val; - ret = regmap_bulk_write(s->regmap, 0x11, buf, 2); + ret = regmap_bulk_write(dev->regmap, 0x11, buf, 2); if (ret) goto err; /* frequency band */ for (i = 0; i < ARRAY_SIZE(e4000_band_lut); i++) { - if (c->frequency <= e4000_band_lut[i].freq) + if (dev->f_frequency <= e4000_band_lut[i].freq) break; } - if (i == ARRAY_SIZE(e4000_band_lut)) { ret = -EINVAL; goto err; } - ret = regmap_write(s->regmap, 0x07, e4000_band_lut[i].reg07_val); + ret = regmap_write(dev->regmap, 0x07, e4000_band_lut[i].reg07_val); if (ret) goto err; - ret = regmap_write(s->regmap, 0x78, e4000_band_lut[i].reg78_val); + ret = regmap_write(dev->regmap, 0x78, e4000_band_lut[i].reg78_val); if (ret) goto err; /* DC offset */ for (i = 0; i < 4; i++) { if (i == 0) - ret = regmap_bulk_write(s->regmap, 0x15, "\x00\x7e\x24", 3); + ret = regmap_bulk_write(dev->regmap, 0x15, "\x00\x7e\x24", 3); else if (i == 1) - ret = regmap_bulk_write(s->regmap, 0x15, "\x00\x7f", 2); + ret = regmap_bulk_write(dev->regmap, 0x15, "\x00\x7f", 2); else if (i == 2) - ret = regmap_bulk_write(s->regmap, 0x15, "\x01", 1); + ret = regmap_bulk_write(dev->regmap, 0x15, "\x01", 1); else - ret = regmap_bulk_write(s->regmap, 0x16, "\x7e", 1); + ret = regmap_bulk_write(dev->regmap, 0x16, "\x7e", 1); if (ret) goto err; - ret = regmap_write(s->regmap, 0x29, 0x01); + ret = regmap_write(dev->regmap, 0x29, 0x01); if (ret) goto err; - ret = regmap_bulk_read(s->regmap, 0x2a, buf, 3); + ret = regmap_bulk_read(dev->regmap, 0x2a, buf, 3); if (ret) goto err; @@ -237,174 +248,294 @@ static int e4000_set_params(struct dvb_frontend *fe) swap(q_data[2], q_data[3]); swap(i_data[2], i_data[3]); - ret = regmap_bulk_write(s->regmap, 0x50, q_data, 4); + ret = regmap_bulk_write(dev->regmap, 0x50, q_data, 4); if (ret) goto err; - ret = regmap_bulk_write(s->regmap, 0x60, i_data, 4); + ret = regmap_bulk_write(dev->regmap, 0x60, i_data, 4); if (ret) goto err; /* gain control auto */ - ret = regmap_write(s->regmap, 0x1a, 0x17); + ret = regmap_write(dev->regmap, 0x1a, 0x17); if (ret) goto err; + + return 0; err: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + +/* + * V4L2 API + */ +#if IS_ENABLED(CONFIG_VIDEO_V4L2) +static const struct v4l2_frequency_band bands[] = { + { + .type = V4L2_TUNER_RF, + .index = 0, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 59000000, + .rangehigh = 1105000000, + }, + { + .type = V4L2_TUNER_RF, + .index = 1, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 1249000000, + .rangehigh = 2208000000UL, + }, +}; + +static inline struct e4000_dev *e4000_subdev_to_dev(struct v4l2_subdev *sd) +{ + return container_of(sd, struct e4000_dev, sd); +} + +static int e4000_s_power(struct v4l2_subdev *sd, int on) +{ + struct e4000_dev *dev = e4000_subdev_to_dev(sd); + struct i2c_client *client = dev->client; + int ret; + + dev_dbg(&client->dev, "on=%d\n", on); + + if (on) + ret = e4000_init(dev); + else + ret = e4000_sleep(dev); if (ret) - dev_dbg(&s->client->dev, "failed=%d\n", ret); + return ret; - return ret; + return e4000_set_params(dev); +} + +static const struct v4l2_subdev_core_ops e4000_subdev_core_ops = { + .s_power = e4000_s_power, +}; + +static int e4000_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) +{ + struct e4000_dev *dev = e4000_subdev_to_dev(sd); + struct i2c_client *client = dev->client; + + dev_dbg(&client->dev, "index=%d\n", v->index); + + strlcpy(v->name, "Elonics E4000", sizeof(v->name)); + v->type = V4L2_TUNER_RF; + v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; + v->rangelow = bands[0].rangelow; + v->rangehigh = bands[1].rangehigh; + return 0; } -static int e4000_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +static int e4000_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *v) { - struct e4000 *s = fe->tuner_priv; + struct e4000_dev *dev = e4000_subdev_to_dev(sd); + struct i2c_client *client = dev->client; - dev_dbg(&s->client->dev, "\n"); + dev_dbg(&client->dev, "index=%d\n", v->index); + return 0; +} - *frequency = 0; /* Zero-IF */ +static int e4000_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) +{ + struct e4000_dev *dev = e4000_subdev_to_dev(sd); + struct i2c_client *client = dev->client; + dev_dbg(&client->dev, "tuner=%d\n", f->tuner); + f->frequency = dev->f_frequency; return 0; } -#if IS_ENABLED(CONFIG_VIDEO_V4L2) +static int e4000_s_frequency(struct v4l2_subdev *sd, + const struct v4l2_frequency *f) +{ + struct e4000_dev *dev = e4000_subdev_to_dev(sd); + struct i2c_client *client = dev->client; + + dev_dbg(&client->dev, "tuner=%d type=%d frequency=%u\n", + f->tuner, f->type, f->frequency); + + dev->f_frequency = clamp_t(unsigned int, f->frequency, + bands[0].rangelow, bands[1].rangehigh); + return e4000_set_params(dev); +} + +static int e4000_enum_freq_bands(struct v4l2_subdev *sd, + struct v4l2_frequency_band *band) +{ + struct e4000_dev *dev = e4000_subdev_to_dev(sd); + struct i2c_client *client = dev->client; + + dev_dbg(&client->dev, "tuner=%d type=%d index=%d\n", + band->tuner, band->type, band->index); + + if (band->index >= ARRAY_SIZE(bands)) + return -EINVAL; + + band->capability = bands[band->index].capability; + band->rangelow = bands[band->index].rangelow; + band->rangehigh = bands[band->index].rangehigh; + return 0; +} + +static const struct v4l2_subdev_tuner_ops e4000_subdev_tuner_ops = { + .g_tuner = e4000_g_tuner, + .s_tuner = e4000_s_tuner, + .g_frequency = e4000_g_frequency, + .s_frequency = e4000_s_frequency, + .enum_freq_bands = e4000_enum_freq_bands, +}; + +static const struct v4l2_subdev_ops e4000_subdev_ops = { + .core = &e4000_subdev_core_ops, + .tuner = &e4000_subdev_tuner_ops, +}; + static int e4000_set_lna_gain(struct dvb_frontend *fe) { - struct e4000 *s = fe->tuner_priv; + struct e4000_dev *dev = fe->tuner_priv; + struct i2c_client *client = dev->client; int ret; u8 u8tmp; - dev_dbg(&s->client->dev, "lna auto=%d->%d val=%d->%d\n", - s->lna_gain_auto->cur.val, s->lna_gain_auto->val, - s->lna_gain->cur.val, s->lna_gain->val); + dev_dbg(&client->dev, "lna auto=%d->%d val=%d->%d\n", + dev->lna_gain_auto->cur.val, dev->lna_gain_auto->val, + dev->lna_gain->cur.val, dev->lna_gain->val); - if (s->lna_gain_auto->val && s->if_gain_auto->cur.val) + if (dev->lna_gain_auto->val && dev->if_gain_auto->cur.val) u8tmp = 0x17; - else if (s->lna_gain_auto->val) + else if (dev->lna_gain_auto->val) u8tmp = 0x19; - else if (s->if_gain_auto->cur.val) + else if (dev->if_gain_auto->cur.val) u8tmp = 0x16; else u8tmp = 0x10; - ret = regmap_write(s->regmap, 0x1a, u8tmp); + ret = regmap_write(dev->regmap, 0x1a, u8tmp); if (ret) goto err; - if (s->lna_gain_auto->val == false) { - ret = regmap_write(s->regmap, 0x14, s->lna_gain->val); + if (dev->lna_gain_auto->val == false) { + ret = regmap_write(dev->regmap, 0x14, dev->lna_gain->val); if (ret) goto err; } -err: - if (ret) - dev_dbg(&s->client->dev, "failed=%d\n", ret); + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int e4000_set_mixer_gain(struct dvb_frontend *fe) { - struct e4000 *s = fe->tuner_priv; + struct e4000_dev *dev = fe->tuner_priv; + struct i2c_client *client = dev->client; int ret; u8 u8tmp; - dev_dbg(&s->client->dev, "mixer auto=%d->%d val=%d->%d\n", - s->mixer_gain_auto->cur.val, s->mixer_gain_auto->val, - s->mixer_gain->cur.val, s->mixer_gain->val); + dev_dbg(&client->dev, "mixer auto=%d->%d val=%d->%d\n", + dev->mixer_gain_auto->cur.val, dev->mixer_gain_auto->val, + dev->mixer_gain->cur.val, dev->mixer_gain->val); - if (s->mixer_gain_auto->val) + if (dev->mixer_gain_auto->val) u8tmp = 0x15; else u8tmp = 0x14; - ret = regmap_write(s->regmap, 0x20, u8tmp); + ret = regmap_write(dev->regmap, 0x20, u8tmp); if (ret) goto err; - if (s->mixer_gain_auto->val == false) { - ret = regmap_write(s->regmap, 0x15, s->mixer_gain->val); + if (dev->mixer_gain_auto->val == false) { + ret = regmap_write(dev->regmap, 0x15, dev->mixer_gain->val); if (ret) goto err; } -err: - if (ret) - dev_dbg(&s->client->dev, "failed=%d\n", ret); + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int e4000_set_if_gain(struct dvb_frontend *fe) { - struct e4000 *s = fe->tuner_priv; + struct e4000_dev *dev = fe->tuner_priv; + struct i2c_client *client = dev->client; int ret; u8 buf[2]; u8 u8tmp; - dev_dbg(&s->client->dev, "if auto=%d->%d val=%d->%d\n", - s->if_gain_auto->cur.val, s->if_gain_auto->val, - s->if_gain->cur.val, s->if_gain->val); + dev_dbg(&client->dev, "if auto=%d->%d val=%d->%d\n", + dev->if_gain_auto->cur.val, dev->if_gain_auto->val, + dev->if_gain->cur.val, dev->if_gain->val); - if (s->if_gain_auto->val && s->lna_gain_auto->cur.val) + if (dev->if_gain_auto->val && dev->lna_gain_auto->cur.val) u8tmp = 0x17; - else if (s->lna_gain_auto->cur.val) + else if (dev->lna_gain_auto->cur.val) u8tmp = 0x19; - else if (s->if_gain_auto->val) + else if (dev->if_gain_auto->val) u8tmp = 0x16; else u8tmp = 0x10; - ret = regmap_write(s->regmap, 0x1a, u8tmp); + ret = regmap_write(dev->regmap, 0x1a, u8tmp); if (ret) goto err; - if (s->if_gain_auto->val == false) { - buf[0] = e4000_if_gain_lut[s->if_gain->val].reg16_val; - buf[1] = e4000_if_gain_lut[s->if_gain->val].reg17_val; - ret = regmap_bulk_write(s->regmap, 0x16, buf, 2); + if (dev->if_gain_auto->val == false) { + buf[0] = e4000_if_gain_lut[dev->if_gain->val].reg16_val; + buf[1] = e4000_if_gain_lut[dev->if_gain->val].reg17_val; + ret = regmap_bulk_write(dev->regmap, 0x16, buf, 2); if (ret) goto err; } -err: - if (ret) - dev_dbg(&s->client->dev, "failed=%d\n", ret); + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int e4000_pll_lock(struct dvb_frontend *fe) { - struct e4000 *s = fe->tuner_priv; + struct e4000_dev *dev = fe->tuner_priv; + struct i2c_client *client = dev->client; int ret; - unsigned int utmp; + unsigned int uitmp; - ret = regmap_read(s->regmap, 0x07, &utmp); + ret = regmap_read(dev->regmap, 0x07, &uitmp); if (ret) goto err; - s->pll_lock->val = (utmp & 0x01); -err: - if (ret) - dev_dbg(&s->client->dev, "failed=%d\n", ret); + dev->pll_lock->val = (uitmp & 0x01); + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { - struct e4000 *s = container_of(ctrl->handler, struct e4000, hdl); + struct e4000_dev *dev = container_of(ctrl->handler, struct e4000_dev, hdl); + struct i2c_client *client = dev->client; int ret; - if (!s->active) + if (!dev->active) return 0; switch (ctrl->id) { case V4L2_CID_RF_TUNER_PLL_LOCK: - ret = e4000_pll_lock(s->fe); + ret = e4000_pll_lock(dev->fe); break; default: - dev_dbg(&s->client->dev, "unknown ctrl: id=%d name=%s\n", - ctrl->id, ctrl->name); + dev_dbg(&client->dev, "unknown ctrl: id=%d name=%s\n", + ctrl->id, ctrl->name); ret = -EINVAL; } @@ -413,35 +544,39 @@ static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl) static int e4000_s_ctrl(struct v4l2_ctrl *ctrl) { - struct e4000 *s = container_of(ctrl->handler, struct e4000, hdl); - struct dvb_frontend *fe = s->fe; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct e4000_dev *dev = container_of(ctrl->handler, struct e4000_dev, hdl); + struct i2c_client *client = dev->client; int ret; - if (!s->active) + if (!dev->active) return 0; switch (ctrl->id) { case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: case V4L2_CID_RF_TUNER_BANDWIDTH: - c->bandwidth_hz = s->bandwidth->val; - ret = e4000_set_params(s->fe); + /* + * TODO: Auto logic does not work 100% correctly as tuner driver + * do not have information to calculate maximum suitable + * bandwidth. Calculating it is responsible of master driver. + */ + dev->f_bandwidth = dev->bandwidth->val; + ret = e4000_set_params(dev); break; case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: case V4L2_CID_RF_TUNER_LNA_GAIN: - ret = e4000_set_lna_gain(s->fe); + ret = e4000_set_lna_gain(dev->fe); break; case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: case V4L2_CID_RF_TUNER_MIXER_GAIN: - ret = e4000_set_mixer_gain(s->fe); + ret = e4000_set_mixer_gain(dev->fe); break; case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: case V4L2_CID_RF_TUNER_IF_GAIN: - ret = e4000_set_if_gain(s->fe); + ret = e4000_set_if_gain(dev->fe); break; default: - dev_dbg(&s->client->dev, "unknown ctrl: id=%d name=%s\n", - ctrl->id, ctrl->name); + dev_dbg(&client->dev, "unknown ctrl: id=%d name=%s\n", + ctrl->id, ctrl->name); ret = -EINVAL; } @@ -454,157 +589,176 @@ static const struct v4l2_ctrl_ops e4000_ctrl_ops = { }; #endif -static const struct dvb_tuner_ops e4000_tuner_ops = { +/* + * DVB API + */ +static int e4000_dvb_set_params(struct dvb_frontend *fe) +{ + struct e4000_dev *dev = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + dev->f_frequency = c->frequency; + dev->f_bandwidth = c->bandwidth_hz; + return e4000_set_params(dev); +} + +static int e4000_dvb_init(struct dvb_frontend *fe) +{ + return e4000_init(fe->tuner_priv); +} + +static int e4000_dvb_sleep(struct dvb_frontend *fe) +{ + return e4000_sleep(fe->tuner_priv); +} + +static int e4000_dvb_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + *frequency = 0; /* Zero-IF */ + return 0; +} + +static const struct dvb_tuner_ops e4000_dvb_tuner_ops = { .info = { .name = "Elonics E4000", .frequency_min = 174000000, .frequency_max = 862000000, }, - .init = e4000_init, - .sleep = e4000_sleep, - .set_params = e4000_set_params, + .init = e4000_dvb_init, + .sleep = e4000_dvb_sleep, + .set_params = e4000_dvb_set_params, - .get_if_frequency = e4000_get_if_frequency, + .get_if_frequency = e4000_dvb_get_if_frequency, }; -/* - * Use V4L2 subdev to carry V4L2 control handler, even we don't implement - * subdev itself, just to avoid reinventing the wheel. - */ static int e4000_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { + struct e4000_dev *dev; struct e4000_config *cfg = client->dev.platform_data; struct dvb_frontend *fe = cfg->fe; - struct e4000 *s; int ret; - unsigned int utmp; + unsigned int uitmp; static const struct regmap_config regmap_config = { .reg_bits = 8, .val_bits = 8, - .max_register = 0xff, }; - s = kzalloc(sizeof(struct e4000), GFP_KERNEL); - if (!s) { + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { ret = -ENOMEM; - dev_err(&client->dev, "kzalloc() failed\n"); goto err; } - s->clock = cfg->clock; - s->client = client; - s->fe = cfg->fe; - s->regmap = devm_regmap_init_i2c(client, ®map_config); - if (IS_ERR(s->regmap)) { - ret = PTR_ERR(s->regmap); - goto err; + dev->clk = cfg->clock; + dev->client = client; + dev->fe = cfg->fe; + dev->regmap = devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(dev->regmap)) { + ret = PTR_ERR(dev->regmap); + goto err_kfree; } /* check if the tuner is there */ - ret = regmap_read(s->regmap, 0x02, &utmp); + ret = regmap_read(dev->regmap, 0x02, &uitmp); if (ret) - goto err; + goto err_kfree; - dev_dbg(&s->client->dev, "chip id=%02x\n", utmp); + dev_dbg(&client->dev, "chip id=%02x\n", uitmp); - if (utmp != 0x40) { + if (uitmp != 0x40) { ret = -ENODEV; - goto err; + goto err_kfree; } /* put sleep as chip seems to be in normal mode by default */ - ret = regmap_write(s->regmap, 0x00, 0x00); + ret = regmap_write(dev->regmap, 0x00, 0x00); if (ret) - goto err; + goto err_kfree; #if IS_ENABLED(CONFIG_VIDEO_V4L2) /* Register controls */ - v4l2_ctrl_handler_init(&s->hdl, 9); - s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, + v4l2_ctrl_handler_init(&dev->hdl, 9); + dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1); - s->bandwidth = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, + dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_BANDWIDTH, 4300000, 11000000, 100000, 4300000); - v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false); - s->lna_gain_auto = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, + v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false); + dev->lna_gain_auto = v4l2_ctrl_new_std(&dev->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_LNA_GAIN_AUTO, 0, 1, 1, 1); - s->lna_gain = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, + dev->lna_gain = v4l2_ctrl_new_std(&dev->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_LNA_GAIN, 0, 15, 1, 10); - v4l2_ctrl_auto_cluster(2, &s->lna_gain_auto, 0, false); - s->mixer_gain_auto = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, + v4l2_ctrl_auto_cluster(2, &dev->lna_gain_auto, 0, false); + dev->mixer_gain_auto = v4l2_ctrl_new_std(&dev->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO, 0, 1, 1, 1); - s->mixer_gain = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, + dev->mixer_gain = v4l2_ctrl_new_std(&dev->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_MIXER_GAIN, 0, 1, 1, 1); - v4l2_ctrl_auto_cluster(2, &s->mixer_gain_auto, 0, false); - s->if_gain_auto = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, + v4l2_ctrl_auto_cluster(2, &dev->mixer_gain_auto, 0, false); + dev->if_gain_auto = v4l2_ctrl_new_std(&dev->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_IF_GAIN_AUTO, 0, 1, 1, 1); - s->if_gain = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, + dev->if_gain = v4l2_ctrl_new_std(&dev->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_IF_GAIN, 0, 54, 1, 0); - v4l2_ctrl_auto_cluster(2, &s->if_gain_auto, 0, false); - s->pll_lock = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, + v4l2_ctrl_auto_cluster(2, &dev->if_gain_auto, 0, false); + dev->pll_lock = v4l2_ctrl_new_std(&dev->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_PLL_LOCK, 0, 1, 1, 0); - if (s->hdl.error) { - ret = s->hdl.error; - dev_err(&s->client->dev, "Could not initialize controls\n"); - v4l2_ctrl_handler_free(&s->hdl); - goto err; + if (dev->hdl.error) { + ret = dev->hdl.error; + dev_err(&client->dev, "Could not initialize controls\n"); + v4l2_ctrl_handler_free(&dev->hdl); + goto err_kfree; } - s->sd.ctrl_handler = &s->hdl; + dev->sd.ctrl_handler = &dev->hdl; + dev->f_frequency = bands[0].rangelow; + dev->f_bandwidth = dev->bandwidth->val; + v4l2_i2c_subdev_init(&dev->sd, client, &e4000_subdev_ops); #endif + fe->tuner_priv = dev; + memcpy(&fe->ops.tuner_ops, &e4000_dvb_tuner_ops, + sizeof(fe->ops.tuner_ops)); + v4l2_set_subdevdata(&dev->sd, client); + i2c_set_clientdata(client, &dev->sd); - dev_info(&s->client->dev, "Elonics E4000 successfully identified\n"); - - fe->tuner_priv = s; - memcpy(&fe->ops.tuner_ops, &e4000_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - v4l2_set_subdevdata(&s->sd, client); - i2c_set_clientdata(client, &s->sd); - + dev_info(&client->dev, "Elonics E4000 successfully identified\n"); return 0; +err_kfree: + kfree(dev); err: - if (ret) { - dev_dbg(&client->dev, "failed=%d\n", ret); - kfree(s); - } - + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int e4000_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct e4000 *s = container_of(sd, struct e4000, sd); - struct dvb_frontend *fe = s->fe; + struct e4000_dev *dev = container_of(sd, struct e4000_dev, sd); dev_dbg(&client->dev, "\n"); #if IS_ENABLED(CONFIG_VIDEO_V4L2) - v4l2_ctrl_handler_free(&s->hdl); + v4l2_ctrl_handler_free(&dev->hdl); #endif - memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = NULL; - kfree(s); + kfree(dev); return 0; } -static const struct i2c_device_id e4000_id[] = { +static const struct i2c_device_id e4000_id_table[] = { {"e4000", 0}, {} }; -MODULE_DEVICE_TABLE(i2c, e4000_id); +MODULE_DEVICE_TABLE(i2c, e4000_id_table); static struct i2c_driver e4000_driver = { .driver = { .owner = THIS_MODULE, .name = "e4000", + .suppress_bind_attrs = true, }, .probe = e4000_probe, .remove = e4000_remove, - .id_table = e4000_id, + .id_table = e4000_id_table, }; module_i2c_driver(e4000_driver); diff --git a/drivers/media/tuners/e4000.h b/drivers/media/tuners/e4000.h index e74b8b2..aa9340c 100644 --- a/drivers/media/tuners/e4000.h +++ b/drivers/media/tuners/e4000.h @@ -21,7 +21,6 @@ #ifndef E4000_H #define E4000_H -#include <linux/kconfig.h> #include "dvb_frontend.h" /* diff --git a/drivers/media/tuners/e4000_priv.h b/drivers/media/tuners/e4000_priv.h index cb00704..d6d5d11 100644 --- a/drivers/media/tuners/e4000_priv.h +++ b/drivers/media/tuners/e4000_priv.h @@ -22,17 +22,20 @@ #define E4000_PRIV_H #include "e4000.h" +#include <linux/math64.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-subdev.h> #include <linux/regmap.h> -struct e4000 { +struct e4000_dev { struct i2c_client *client; struct regmap *regmap; - u32 clock; + u32 clk; struct dvb_frontend *fe; struct v4l2_subdev sd; bool active; + unsigned int f_frequency; + unsigned int f_bandwidth; /* Controls */ struct v4l2_ctrl_handler hdl; @@ -49,8 +52,8 @@ struct e4000 { struct e4000_pll { u32 freq; - u8 div; - u8 mul; + u8 div_out_reg; + u8 div_out; }; static const struct e4000_pll e4000_pll_lut[] = { diff --git a/drivers/media/tuners/fc0013.c b/drivers/media/tuners/fc0013.c index b416231..522690d 100644 --- a/drivers/media/tuners/fc0013.c +++ b/drivers/media/tuners/fc0013.c @@ -217,8 +217,6 @@ static int fc0013_set_vhf_track(struct fc0013_priv *priv, u32 freq) } else { /* UHF and GPS */ ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c); } - if (ret) - goto error_out; error_out: return ret; } diff --git a/drivers/media/tuners/fc2580.c b/drivers/media/tuners/fc2580.c index f0c9c42..12f916e 100644 --- a/drivers/media/tuners/fc2580.c +++ b/drivers/media/tuners/fc2580.c @@ -20,535 +20,628 @@ #include "fc2580_priv.h" -/* Max transfer size done by I2C transfer functions */ -#define MAX_XFER_SIZE 64 - /* * TODO: * I2C write and read works only for one single register. Multiple registers * could not be accessed using normal register address auto-increment. * There could be (very likely) register to change that behavior.... - * - * Due to that limitation functions: - * fc2580_wr_regs() - * fc2580_rd_regs() - * could not be used for accessing more than one register at once. - * - * TODO: - * Currently it blind writes bunch of static registers from the - * fc2580_freq_regs_lut[] when fc2580_set_params() is called. Add some - * logic to reduce unneeded register writes. */ -/* write multiple registers */ -static int fc2580_wr_regs(struct fc2580_priv *priv, u8 reg, u8 *val, int len) -{ - int ret; - u8 buf[MAX_XFER_SIZE]; - struct i2c_msg msg[1] = { - { - .addr = priv->cfg->i2c_addr, - .flags = 0, - .len = 1 + len, - .buf = buf, - } - }; - - if (1 + len > sizeof(buf)) { - dev_warn(&priv->i2c->dev, - "%s: i2c wr reg=%04x: len=%d is too big!\n", - KBUILD_MODNAME, reg, len); - return -EINVAL; - } - - buf[0] = reg; - memcpy(&buf[1], val, len); - - ret = i2c_transfer(priv->i2c, msg, 1); - if (ret == 1) { - ret = 0; - } else { - dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } - return ret; -} - -/* read multiple registers */ -static int fc2580_rd_regs(struct fc2580_priv *priv, u8 reg, u8 *val, int len) -{ - int ret; - u8 buf[MAX_XFER_SIZE]; - struct i2c_msg msg[2] = { - { - .addr = priv->cfg->i2c_addr, - .flags = 0, - .len = 1, - .buf = ®, - }, { - .addr = priv->cfg->i2c_addr, - .flags = I2C_M_RD, - .len = len, - .buf = buf, - } - }; - - if (len > sizeof(buf)) { - dev_warn(&priv->i2c->dev, - "%s: i2c rd reg=%04x: len=%d is too big!\n", - KBUILD_MODNAME, reg, len); - return -EINVAL; - } - - ret = i2c_transfer(priv->i2c, msg, 2); - if (ret == 2) { - memcpy(val, buf, len); - ret = 0; - } else { - dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } - - return ret; -} - -/* write single register */ -static int fc2580_wr_reg(struct fc2580_priv *priv, u8 reg, u8 val) -{ - return fc2580_wr_regs(priv, reg, &val, 1); -} - -/* read single register */ -static int fc2580_rd_reg(struct fc2580_priv *priv, u8 reg, u8 *val) -{ - return fc2580_rd_regs(priv, reg, val, 1); -} - /* write single register conditionally only when value differs from 0xff * XXX: This is special routine meant only for writing fc2580_freq_regs_lut[] * values. Do not use for the other purposes. */ -static int fc2580_wr_reg_ff(struct fc2580_priv *priv, u8 reg, u8 val) +static int fc2580_wr_reg_ff(struct fc2580_dev *dev, u8 reg, u8 val) { if (val == 0xff) return 0; else - return fc2580_wr_regs(priv, reg, &val, 1); + return regmap_write(dev->regmap, reg, val); } -static int fc2580_set_params(struct dvb_frontend *fe) +static int fc2580_set_params(struct fc2580_dev *dev) { - struct fc2580_priv *priv = fe->tuner_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret = 0, i; - unsigned int r_val, n_val, k_val, k_val_reg, f_ref; - u8 tmp_val, r18_val; + struct i2c_client *client = dev->client; + int ret, i; + unsigned int uitmp, div_ref, div_ref_val, div_n, k, k_cw, div_out; u64 f_vco; + u8 synth_config; + unsigned long timeout; + + if (!dev->active) { + dev_dbg(&client->dev, "tuner is sleeping\n"); + return 0; + } /* - * Fractional-N synthesizer/PLL. - * Most likely all those PLL calculations are not correct. I am not - * sure, but it looks like it is divider based Fractional-N synthesizer. - * There is divider for reference clock too? - * Anyhow, synthesizer calculation results seems to be quite correct. + * Fractional-N synthesizer + * + * +---------------------------------------+ + * v | + * Fref +----+ +----+ +-------+ +----+ +------+ +---+ + * ------> | /R | --> | PD | --> | VCO | ------> | /2 | --> | /N.F | <-- | K | + * +----+ +----+ +-------+ +----+ +------+ +---+ + * | + * | + * v + * +-------+ Fout + * | /Rout | ------> + * +-------+ */ - - dev_dbg(&priv->i2c->dev, "%s: delivery_system=%d frequency=%d " \ - "bandwidth_hz=%d\n", __func__, - c->delivery_system, c->frequency, c->bandwidth_hz); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - /* PLL */ for (i = 0; i < ARRAY_SIZE(fc2580_pll_lut); i++) { - if (c->frequency <= fc2580_pll_lut[i].freq) + if (dev->f_frequency <= fc2580_pll_lut[i].freq) break; } - - if (i == ARRAY_SIZE(fc2580_pll_lut)) + if (i == ARRAY_SIZE(fc2580_pll_lut)) { + ret = -EINVAL; goto err; + } - f_vco = c->frequency; - f_vco *= fc2580_pll_lut[i].div; - - if (f_vco >= 2600000000UL) - tmp_val = 0x0e | fc2580_pll_lut[i].band; + #define DIV_PRE_N 2 + #define F_REF dev->clk + div_out = fc2580_pll_lut[i].div_out; + f_vco = (u64) dev->f_frequency * div_out; + synth_config = fc2580_pll_lut[i].band; + if (f_vco < 2600000000ULL) + synth_config |= 0x06; else - tmp_val = 0x06 | fc2580_pll_lut[i].band; - - ret = fc2580_wr_reg(priv, 0x02, tmp_val); - if (ret < 0) - goto err; - - if (f_vco >= 2UL * 76 * priv->cfg->clock) { - r_val = 1; - r18_val = 0x00; - } else if (f_vco >= 1UL * 76 * priv->cfg->clock) { - r_val = 2; - r18_val = 0x10; + synth_config |= 0x0e; + + /* select reference divider R (keep PLL div N in valid range) */ + #define DIV_N_MIN 76 + if (f_vco >= div_u64((u64) DIV_PRE_N * DIV_N_MIN * F_REF, 1)) { + div_ref = 1; + div_ref_val = 0x00; + } else if (f_vco >= div_u64((u64) DIV_PRE_N * DIV_N_MIN * F_REF, 2)) { + div_ref = 2; + div_ref_val = 0x10; } else { - r_val = 4; - r18_val = 0x20; + div_ref = 4; + div_ref_val = 0x20; } - f_ref = 2UL * priv->cfg->clock / r_val; - n_val = div_u64_rem(f_vco, f_ref, &k_val); - k_val_reg = div_u64(1ULL * k_val * (1 << 20), f_ref); + /* calculate PLL integer and fractional control word */ + uitmp = DIV_PRE_N * F_REF / div_ref; + div_n = div_u64_rem(f_vco, uitmp, &k); + k_cw = div_u64((u64) k * 0x100000, uitmp); - ret = fc2580_wr_reg(priv, 0x18, r18_val | ((k_val_reg >> 16) & 0xff)); - if (ret < 0) - goto err; + dev_dbg(&client->dev, + "frequency=%u bandwidth=%u f_vco=%llu F_REF=%u div_ref=%u div_n=%u k=%u div_out=%u k_cw=%0x\n", + dev->f_frequency, dev->f_bandwidth, f_vco, F_REF, div_ref, + div_n, k, div_out, k_cw); - ret = fc2580_wr_reg(priv, 0x1a, (k_val_reg >> 8) & 0xff); - if (ret < 0) + ret = regmap_write(dev->regmap, 0x02, synth_config); + if (ret) goto err; - ret = fc2580_wr_reg(priv, 0x1b, (k_val_reg >> 0) & 0xff); - if (ret < 0) + ret = regmap_write(dev->regmap, 0x18, div_ref_val << 0 | k_cw >> 16); + if (ret) goto err; - ret = fc2580_wr_reg(priv, 0x1c, n_val); - if (ret < 0) + ret = regmap_write(dev->regmap, 0x1a, (k_cw >> 8) & 0xff); + if (ret) goto err; - if (priv->cfg->clock >= 28000000) { - ret = fc2580_wr_reg(priv, 0x4b, 0x22); - if (ret < 0) - goto err; - } - - if (fc2580_pll_lut[i].band == 0x00) { - if (c->frequency <= 794000000) - tmp_val = 0x9f; - else - tmp_val = 0x8f; + ret = regmap_write(dev->regmap, 0x1b, (k_cw >> 0) & 0xff); + if (ret) + goto err; - ret = fc2580_wr_reg(priv, 0x2d, tmp_val); - if (ret < 0) - goto err; - } + ret = regmap_write(dev->regmap, 0x1c, div_n); + if (ret) + goto err; /* registers */ for (i = 0; i < ARRAY_SIZE(fc2580_freq_regs_lut); i++) { - if (c->frequency <= fc2580_freq_regs_lut[i].freq) + if (dev->f_frequency <= fc2580_freq_regs_lut[i].freq) break; } - - if (i == ARRAY_SIZE(fc2580_freq_regs_lut)) + if (i == ARRAY_SIZE(fc2580_freq_regs_lut)) { + ret = -EINVAL; goto err; + } - ret = fc2580_wr_reg_ff(priv, 0x25, fc2580_freq_regs_lut[i].r25_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x25, fc2580_freq_regs_lut[i].r25_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x27, fc2580_freq_regs_lut[i].r27_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x27, fc2580_freq_regs_lut[i].r27_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x28, fc2580_freq_regs_lut[i].r28_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x28, fc2580_freq_regs_lut[i].r28_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x29, fc2580_freq_regs_lut[i].r29_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x29, fc2580_freq_regs_lut[i].r29_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x2b, fc2580_freq_regs_lut[i].r2b_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x2b, fc2580_freq_regs_lut[i].r2b_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x2c, fc2580_freq_regs_lut[i].r2c_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x2c, fc2580_freq_regs_lut[i].r2c_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x2d, fc2580_freq_regs_lut[i].r2d_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x2d, fc2580_freq_regs_lut[i].r2d_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x30, fc2580_freq_regs_lut[i].r30_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x30, fc2580_freq_regs_lut[i].r30_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x44, fc2580_freq_regs_lut[i].r44_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x44, fc2580_freq_regs_lut[i].r44_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x50, fc2580_freq_regs_lut[i].r50_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x50, fc2580_freq_regs_lut[i].r50_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x53, fc2580_freq_regs_lut[i].r53_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x53, fc2580_freq_regs_lut[i].r53_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x5f, fc2580_freq_regs_lut[i].r5f_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x5f, fc2580_freq_regs_lut[i].r5f_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x61, fc2580_freq_regs_lut[i].r61_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x61, fc2580_freq_regs_lut[i].r61_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x62, fc2580_freq_regs_lut[i].r62_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x62, fc2580_freq_regs_lut[i].r62_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x63, fc2580_freq_regs_lut[i].r63_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x63, fc2580_freq_regs_lut[i].r63_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x67, fc2580_freq_regs_lut[i].r67_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x67, fc2580_freq_regs_lut[i].r67_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x68, fc2580_freq_regs_lut[i].r68_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x68, fc2580_freq_regs_lut[i].r68_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x69, fc2580_freq_regs_lut[i].r69_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x69, fc2580_freq_regs_lut[i].r69_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x6a, fc2580_freq_regs_lut[i].r6a_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x6a, fc2580_freq_regs_lut[i].r6a_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x6b, fc2580_freq_regs_lut[i].r6b_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x6b, fc2580_freq_regs_lut[i].r6b_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x6c, fc2580_freq_regs_lut[i].r6c_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x6c, fc2580_freq_regs_lut[i].r6c_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x6d, fc2580_freq_regs_lut[i].r6d_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x6d, fc2580_freq_regs_lut[i].r6d_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x6e, fc2580_freq_regs_lut[i].r6e_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x6e, fc2580_freq_regs_lut[i].r6e_val); + if (ret) goto err; - ret = fc2580_wr_reg_ff(priv, 0x6f, fc2580_freq_regs_lut[i].r6f_val); - if (ret < 0) + ret = fc2580_wr_reg_ff(dev, 0x6f, fc2580_freq_regs_lut[i].r6f_val); + if (ret) goto err; /* IF filters */ for (i = 0; i < ARRAY_SIZE(fc2580_if_filter_lut); i++) { - if (c->bandwidth_hz <= fc2580_if_filter_lut[i].freq) + if (dev->f_bandwidth <= fc2580_if_filter_lut[i].freq) break; } - - if (i == ARRAY_SIZE(fc2580_if_filter_lut)) - goto err; - - ret = fc2580_wr_reg(priv, 0x36, fc2580_if_filter_lut[i].r36_val); - if (ret < 0) + if (i == ARRAY_SIZE(fc2580_if_filter_lut)) { + ret = -EINVAL; goto err; + } - ret = fc2580_wr_reg(priv, 0x37, div_u64(1ULL * priv->cfg->clock * - fc2580_if_filter_lut[i].mul, 1000000000)); - if (ret < 0) + ret = regmap_write(dev->regmap, 0x36, fc2580_if_filter_lut[i].r36_val); + if (ret) goto err; - ret = fc2580_wr_reg(priv, 0x39, fc2580_if_filter_lut[i].r39_val); - if (ret < 0) + uitmp = (unsigned int) 8058000 - (dev->f_bandwidth * 122 / 100 / 2); + uitmp = div64_u64((u64) dev->clk * uitmp, 1000000000000ULL); + ret = regmap_write(dev->regmap, 0x37, uitmp); + if (ret) goto err; - /* calibration? */ - ret = fc2580_wr_reg(priv, 0x2e, 0x09); - if (ret < 0) + ret = regmap_write(dev->regmap, 0x39, fc2580_if_filter_lut[i].r39_val); + if (ret) goto err; - for (i = 0; i < 5; i++) { - ret = fc2580_rd_reg(priv, 0x2f, &tmp_val); - if (ret < 0) + timeout = jiffies + msecs_to_jiffies(30); + for (uitmp = ~0xc0; !time_after(jiffies, timeout) && uitmp != 0xc0;) { + /* trigger filter */ + ret = regmap_write(dev->regmap, 0x2e, 0x09); + if (ret) goto err; - /* done when [7:6] are set */ - if ((tmp_val & 0xc0) == 0xc0) - break; - - ret = fc2580_wr_reg(priv, 0x2e, 0x01); - if (ret < 0) + /* locked when [7:6] are set (val: d7 6MHz, d5 7MHz, cd 8MHz) */ + ret = regmap_read(dev->regmap, 0x2f, &uitmp); + if (ret) goto err; + uitmp &= 0xc0; - ret = fc2580_wr_reg(priv, 0x2e, 0x09); - if (ret < 0) + ret = regmap_write(dev->regmap, 0x2e, 0x01); + if (ret) goto err; - - usleep_range(5000, 25000); } - - dev_dbg(&priv->i2c->dev, "%s: loop=%i\n", __func__, i); - - ret = fc2580_wr_reg(priv, 0x2e, 0x01); - if (ret < 0) - goto err; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); + if (uitmp != 0xc0) + dev_dbg(&client->dev, "filter did not lock %02x\n", uitmp); return 0; err: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } -static int fc2580_init(struct dvb_frontend *fe) +static int fc2580_init(struct fc2580_dev *dev) { - struct fc2580_priv *priv = fe->tuner_priv; + struct i2c_client *client = dev->client; int ret, i; - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); + dev_dbg(&client->dev, "\n"); for (i = 0; i < ARRAY_SIZE(fc2580_init_reg_vals); i++) { - ret = fc2580_wr_reg(priv, fc2580_init_reg_vals[i].reg, + ret = regmap_write(dev->regmap, fc2580_init_reg_vals[i].reg, fc2580_init_reg_vals[i].val); - if (ret < 0) + if (ret) goto err; } - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - + dev->active = true; return 0; err: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } -static int fc2580_sleep(struct dvb_frontend *fe) +static int fc2580_sleep(struct fc2580_dev *dev) { - struct fc2580_priv *priv = fe->tuner_priv; + struct i2c_client *client = dev->client; int ret; - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); + dev->active = false; - ret = fc2580_wr_reg(priv, 0x02, 0x0a); - if (ret < 0) + ret = regmap_write(dev->regmap, 0x02, 0x0a); + if (ret) goto err; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - return 0; err: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } -static int fc2580_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +/* + * DVB API + */ +static int fc2580_dvb_set_params(struct dvb_frontend *fe) { - struct fc2580_priv *priv = fe->tuner_priv; - - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); - - *frequency = 0; /* Zero-IF */ + struct fc2580_dev *dev = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; - return 0; + dev->f_frequency = c->frequency; + dev->f_bandwidth = c->bandwidth_hz; + return fc2580_set_params(dev); } -static int fc2580_release(struct dvb_frontend *fe) +static int fc2580_dvb_init(struct dvb_frontend *fe) { - struct fc2580_priv *priv = fe->tuner_priv; - - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); + return fc2580_init(fe->tuner_priv); +} - kfree(fe->tuner_priv); +static int fc2580_dvb_sleep(struct dvb_frontend *fe) +{ + return fc2580_sleep(fe->tuner_priv); +} +static int fc2580_dvb_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + *frequency = 0; /* Zero-IF */ return 0; } -static const struct dvb_tuner_ops fc2580_tuner_ops = { +static const struct dvb_tuner_ops fc2580_dvb_tuner_ops = { .info = { .name = "FCI FC2580", .frequency_min = 174000000, .frequency_max = 862000000, }, - .release = fc2580_release, + .init = fc2580_dvb_init, + .sleep = fc2580_dvb_sleep, + .set_params = fc2580_dvb_set_params, + + .get_if_frequency = fc2580_dvb_get_if_frequency, +}; + +/* + * V4L2 API + */ +#if IS_ENABLED(CONFIG_VIDEO_V4L2) +static const struct v4l2_frequency_band bands[] = { + { + .type = V4L2_TUNER_RF, + .index = 0, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 130000000, + .rangehigh = 2000000000, + }, +}; + +static inline struct fc2580_dev *fc2580_subdev_to_dev(struct v4l2_subdev *sd) +{ + return container_of(sd, struct fc2580_dev, subdev); +} + +static int fc2580_s_power(struct v4l2_subdev *sd, int on) +{ + struct fc2580_dev *dev = fc2580_subdev_to_dev(sd); + struct i2c_client *client = dev->client; + int ret; + + dev_dbg(&client->dev, "on=%d\n", on); + + if (on) + ret = fc2580_init(dev); + else + ret = fc2580_sleep(dev); + if (ret) + return ret; + + return fc2580_set_params(dev); +} + +static const struct v4l2_subdev_core_ops fc2580_subdev_core_ops = { + .s_power = fc2580_s_power, +}; + +static int fc2580_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) +{ + struct fc2580_dev *dev = fc2580_subdev_to_dev(sd); + struct i2c_client *client = dev->client; + + dev_dbg(&client->dev, "index=%d\n", v->index); + + strlcpy(v->name, "FCI FC2580", sizeof(v->name)); + v->type = V4L2_TUNER_RF; + v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; + v->rangelow = bands[0].rangelow; + v->rangehigh = bands[0].rangehigh; + return 0; +} + +static int fc2580_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *v) +{ + struct fc2580_dev *dev = fc2580_subdev_to_dev(sd); + struct i2c_client *client = dev->client; + + dev_dbg(&client->dev, "index=%d\n", v->index); + return 0; +} + +static int fc2580_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) +{ + struct fc2580_dev *dev = fc2580_subdev_to_dev(sd); + struct i2c_client *client = dev->client; + + dev_dbg(&client->dev, "tuner=%d\n", f->tuner); + f->frequency = dev->f_frequency; + return 0; +} + +static int fc2580_s_frequency(struct v4l2_subdev *sd, + const struct v4l2_frequency *f) +{ + struct fc2580_dev *dev = fc2580_subdev_to_dev(sd); + struct i2c_client *client = dev->client; + + dev_dbg(&client->dev, "tuner=%d type=%d frequency=%u\n", + f->tuner, f->type, f->frequency); + + dev->f_frequency = clamp_t(unsigned int, f->frequency, + bands[0].rangelow, bands[0].rangehigh); + return fc2580_set_params(dev); +} + +static int fc2580_enum_freq_bands(struct v4l2_subdev *sd, + struct v4l2_frequency_band *band) +{ + struct fc2580_dev *dev = fc2580_subdev_to_dev(sd); + struct i2c_client *client = dev->client; + + dev_dbg(&client->dev, "tuner=%d type=%d index=%d\n", + band->tuner, band->type, band->index); - .init = fc2580_init, - .sleep = fc2580_sleep, - .set_params = fc2580_set_params, + if (band->index >= ARRAY_SIZE(bands)) + return -EINVAL; - .get_if_frequency = fc2580_get_if_frequency, + band->capability = bands[band->index].capability; + band->rangelow = bands[band->index].rangelow; + band->rangehigh = bands[band->index].rangehigh; + return 0; +} + +static const struct v4l2_subdev_tuner_ops fc2580_subdev_tuner_ops = { + .g_tuner = fc2580_g_tuner, + .s_tuner = fc2580_s_tuner, + .g_frequency = fc2580_g_frequency, + .s_frequency = fc2580_s_frequency, + .enum_freq_bands = fc2580_enum_freq_bands, +}; + +static const struct v4l2_subdev_ops fc2580_subdev_ops = { + .core = &fc2580_subdev_core_ops, + .tuner = &fc2580_subdev_tuner_ops, }; -struct dvb_frontend *fc2580_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, const struct fc2580_config *cfg) +static int fc2580_s_ctrl(struct v4l2_ctrl *ctrl) { - struct fc2580_priv *priv; + struct fc2580_dev *dev = container_of(ctrl->handler, struct fc2580_dev, hdl); + struct i2c_client *client = dev->client; int ret; - u8 chip_id; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); + dev_dbg(&client->dev, "ctrl: id=%d name=%s cur.val=%d val=%d\n", + ctrl->id, ctrl->name, ctrl->cur.val, ctrl->val); + + switch (ctrl->id) { + case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: + case V4L2_CID_RF_TUNER_BANDWIDTH: + /* + * TODO: Auto logic does not work 100% correctly as tuner driver + * do not have information to calculate maximum suitable + * bandwidth. Calculating it is responsible of master driver. + */ + dev->f_bandwidth = dev->bandwidth->val; + ret = fc2580_set_params(dev); + break; + default: + dev_dbg(&client->dev, "unknown ctrl"); + ret = -EINVAL; + } + return ret; +} + +static const struct v4l2_ctrl_ops fc2580_ctrl_ops = { + .s_ctrl = fc2580_s_ctrl, +}; +#endif + +static struct v4l2_subdev *fc2580_get_v4l2_subdev(struct i2c_client *client) +{ + struct fc2580_dev *dev = i2c_get_clientdata(client); + + if (dev->subdev.ops) + return &dev->subdev; + else + return NULL; +} + +static int fc2580_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct fc2580_dev *dev; + struct fc2580_platform_data *pdata = client->dev.platform_data; + struct dvb_frontend *fe = pdata->dvb_frontend; + int ret; + unsigned int uitmp; + static const struct regmap_config regmap_config = { + .reg_bits = 8, + .val_bits = 8, + }; - priv = kzalloc(sizeof(struct fc2580_priv), GFP_KERNEL); - if (!priv) { + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { ret = -ENOMEM; - dev_err(&i2c->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); goto err; } - priv->cfg = cfg; - priv->i2c = i2c; + if (pdata->clk) + dev->clk = pdata->clk; + else + dev->clk = 16384000; /* internal clock */ + dev->client = client; + dev->regmap = devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(dev->regmap)) { + ret = PTR_ERR(dev->regmap); + goto err_kfree; + } /* check if the tuner is there */ - ret = fc2580_rd_reg(priv, 0x01, &chip_id); - if (ret < 0) - goto err; + ret = regmap_read(dev->regmap, 0x01, &uitmp); + if (ret) + goto err_kfree; - dev_dbg(&priv->i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id); + dev_dbg(&client->dev, "chip_id=%02x\n", uitmp); - switch (chip_id) { + switch (uitmp) { case 0x56: case 0x5a: break; default: - goto err; + ret = -ENODEV; + goto err_kfree; } - dev_info(&priv->i2c->dev, - "%s: FCI FC2580 successfully identified\n", - KBUILD_MODNAME); - - fe->tuner_priv = priv; - memcpy(&fe->ops.tuner_ops, &fc2580_tuner_ops, - sizeof(struct dvb_tuner_ops)); +#if IS_ENABLED(CONFIG_VIDEO_V4L2) + /* Register controls */ + v4l2_ctrl_handler_init(&dev->hdl, 2); + dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, &fc2580_ctrl_ops, + V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, + 0, 1, 1, 1); + dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, &fc2580_ctrl_ops, + V4L2_CID_RF_TUNER_BANDWIDTH, + 3000, 10000000, 1, 3000); + v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false); + if (dev->hdl.error) { + ret = dev->hdl.error; + dev_err(&client->dev, "Could not initialize controls\n"); + v4l2_ctrl_handler_free(&dev->hdl); + goto err_kfree; + } + dev->subdev.ctrl_handler = &dev->hdl; + dev->f_frequency = bands[0].rangelow; + dev->f_bandwidth = dev->bandwidth->val; + v4l2_i2c_subdev_init(&dev->subdev, client, &fc2580_subdev_ops); +#endif + fe->tuner_priv = dev; + memcpy(&fe->ops.tuner_ops, &fc2580_dvb_tuner_ops, + sizeof(fe->ops.tuner_ops)); + pdata->get_v4l2_subdev = fc2580_get_v4l2_subdev; + i2c_set_clientdata(client, dev); + + dev_info(&client->dev, "FCI FC2580 successfully identified\n"); + return 0; +err_kfree: + kfree(dev); +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); +static int fc2580_remove(struct i2c_client *client) +{ + struct fc2580_dev *dev = i2c_get_clientdata(client); - return fe; -err: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); + dev_dbg(&client->dev, "\n"); - dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); - kfree(priv); - return NULL; +#if IS_ENABLED(CONFIG_VIDEO_V4L2) + v4l2_ctrl_handler_free(&dev->hdl); +#endif + kfree(dev); + return 0; } -EXPORT_SYMBOL(fc2580_attach); + +static const struct i2c_device_id fc2580_id_table[] = { + {"fc2580", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, fc2580_id_table); + +static struct i2c_driver fc2580_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "fc2580", + .suppress_bind_attrs = true, + }, + .probe = fc2580_probe, + .remove = fc2580_remove, + .id_table = fc2580_id_table, +}; + +module_i2c_driver(fc2580_driver); MODULE_DESCRIPTION("FCI FC2580 silicon tuner driver"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); diff --git a/drivers/media/tuners/fc2580.h b/drivers/media/tuners/fc2580.h index b1ce677..862ea46 100644 --- a/drivers/media/tuners/fc2580.h +++ b/drivers/media/tuners/fc2580.h @@ -21,32 +21,26 @@ #ifndef FC2580_H #define FC2580_H -#include <linux/kconfig.h> #include "dvb_frontend.h" +#include <media/v4l2-subdev.h> +#include <linux/i2c.h> -struct fc2580_config { - /* - * I2C address - * 0x56, ... - */ - u8 i2c_addr; +/* + * I2C address + * 0x56, ... + */ - /* - * clock - */ - u32 clock; -}; +/** + * struct fc2580_platform_data - Platform data for the fc2580 driver + * @clk: Clock frequency (0 = internal clock). + * @dvb_frontend: DVB frontend. + * @get_v4l2_subdev: Get V4L2 subdev. + */ +struct fc2580_platform_data { + u32 clk; + struct dvb_frontend *dvb_frontend; -#if IS_REACHABLE(CONFIG_MEDIA_TUNER_FC2580) -extern struct dvb_frontend *fc2580_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, const struct fc2580_config *cfg); -#else -static inline struct dvb_frontend *fc2580_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, const struct fc2580_config *cfg) -{ - pr_warn("%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif + struct v4l2_subdev* (*get_v4l2_subdev)(struct i2c_client *); +}; #endif diff --git a/drivers/media/tuners/fc2580_priv.h b/drivers/media/tuners/fc2580_priv.h index 646c994..031a43d 100644 --- a/drivers/media/tuners/fc2580_priv.h +++ b/drivers/media/tuners/fc2580_priv.h @@ -22,6 +22,9 @@ #define FC2580_PRIV_H #include "fc2580.h" +#include <media/v4l2-ctrls.h> +#include <media/v4l2-subdev.h> +#include <linux/regmap.h> #include <linux/math64.h> struct fc2580_reg_val { @@ -50,7 +53,7 @@ static const struct fc2580_reg_val fc2580_init_reg_vals[] = { struct fc2580_pll { u32 freq; - u8 div; + u8 div_out; u8 band; }; @@ -63,16 +66,15 @@ static const struct fc2580_pll fc2580_pll_lut[] = { struct fc2580_if_filter { u32 freq; - u16 mul; u8 r36_val; u8 r39_val; }; static const struct fc2580_if_filter fc2580_if_filter_lut[] = { - { 6000000, 4400, 0x18, 0x00}, - { 7000000, 3910, 0x18, 0x80}, - { 8000000, 3300, 0x18, 0x80}, - {0xffffffff, 3300, 0x18, 0x80}, + { 6000000, 0x18, 0x00}, + { 7000000, 0x18, 0x80}, + { 8000000, 0x18, 0x80}, + {0xffffffff, 0x18, 0x80}, }; struct fc2580_freq_regs { @@ -110,15 +112,15 @@ static const struct fc2580_freq_regs fc2580_freq_regs_lut[] = { 0x50, 0x0f, 0x07, 0x00, 0x15, 0x03, 0x05, 0x10, 0x12, 0x08, 0x0a, 0x78, 0x32, 0x54}, { 538000000, - 0xf0, 0x77, 0x53, 0x60, 0xff, 0xff, 0xff, 0x09, 0xff, 0x8c, + 0xf0, 0x77, 0x53, 0x60, 0xff, 0xff, 0x9f, 0x09, 0xff, 0x8c, 0x50, 0x13, 0x07, 0x06, 0x15, 0x06, 0x08, 0x10, 0x12, 0x0b, 0x0c, 0x78, 0x32, 0x14}, { 794000000, - 0xf0, 0x77, 0x53, 0x60, 0xff, 0xff, 0xff, 0x09, 0xff, 0x8c, + 0xf0, 0x77, 0x53, 0x60, 0xff, 0xff, 0x9f, 0x09, 0xff, 0x8c, 0x50, 0x15, 0x03, 0x03, 0x15, 0x03, 0x05, 0x0c, 0x0e, 0x0b, 0x0c, 0x78, 0x32, 0x14}, {1000000000, - 0xf0, 0x77, 0x53, 0x60, 0xff, 0xff, 0xff, 0x09, 0xff, 0x8c, + 0xf0, 0x77, 0x53, 0x60, 0xff, 0xff, 0x8f, 0x09, 0xff, 0x8c, 0x50, 0x15, 0x07, 0x06, 0x15, 0x07, 0x09, 0x10, 0x12, 0x0b, 0x0c, 0x78, 0x32, 0x14}, {0xffffffff, @@ -127,9 +129,19 @@ static const struct fc2580_freq_regs fc2580_freq_regs_lut[] = { 0x0a, 0xa0, 0x50, 0x14}, }; -struct fc2580_priv { - const struct fc2580_config *cfg; - struct i2c_adapter *i2c; +struct fc2580_dev { + u32 clk; + struct i2c_client *client; + struct regmap *regmap; + struct v4l2_subdev subdev; + bool active; + unsigned int f_frequency; + unsigned int f_bandwidth; + + /* Controls */ + struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *bandwidth_auto; + struct v4l2_ctrl *bandwidth; }; #endif diff --git a/drivers/media/tuners/msi001.c b/drivers/media/tuners/msi001.c index 74cfc3c..b533240 100644 --- a/drivers/media/tuners/msi001.c +++ b/drivers/media/tuners/msi001.c @@ -36,7 +36,7 @@ static const struct v4l2_frequency_band bands[] = { }, }; -struct msi001 { +struct msi001_dev { struct spi_device *spi; struct v4l2_subdev sd; @@ -51,25 +51,26 @@ struct msi001 { unsigned int f_tuner; }; -static inline struct msi001 *sd_to_msi001(struct v4l2_subdev *sd) +static inline struct msi001_dev *sd_to_msi001_dev(struct v4l2_subdev *sd) { - return container_of(sd, struct msi001, sd); + return container_of(sd, struct msi001_dev, sd); } -static int msi001_wreg(struct msi001 *s, u32 data) +static int msi001_wreg(struct msi001_dev *dev, u32 data) { /* Register format: 4 bits addr + 20 bits value */ - return spi_write(s->spi, &data, 3); + return spi_write(dev->spi, &data, 3); }; -static int msi001_set_gain(struct msi001 *s, int lna_gain, int mixer_gain, - int if_gain) +static int msi001_set_gain(struct msi001_dev *dev, int lna_gain, int mixer_gain, + int if_gain) { + struct spi_device *spi = dev->spi; int ret; u32 reg; - dev_dbg(&s->spi->dev, "lna=%d mixer=%d if=%d\n", - lna_gain, mixer_gain, if_gain); + dev_dbg(&spi->dev, "lna=%d mixer=%d if=%d\n", + lna_gain, mixer_gain, if_gain); reg = 1 << 0; reg |= (59 - if_gain) << 4; @@ -78,28 +79,29 @@ static int msi001_set_gain(struct msi001 *s, int lna_gain, int mixer_gain, reg |= (1 - lna_gain) << 13; reg |= 4 << 14; reg |= 0 << 17; - ret = msi001_wreg(s, reg); + ret = msi001_wreg(dev, reg); if (ret) goto err; return 0; err: - dev_dbg(&s->spi->dev, "failed %d\n", ret); + dev_dbg(&spi->dev, "failed %d\n", ret); return ret; }; -static int msi001_set_tuner(struct msi001 *s) +static int msi001_set_tuner(struct msi001_dev *dev) { + struct spi_device *spi = dev->spi; int ret, i; - unsigned int n, m, thresh, frac, vco_step, tmp, f_if1; + unsigned int uitmp, div_n, k, k_thresh, k_frac, div_lo, f_if1; u32 reg; - u64 f_vco, tmp64; - u8 mode, filter_mode, lo_div; + u64 f_vco; + u8 mode, filter_mode; static const struct { u32 rf; u8 mode; - u8 lo_div; + u8 div_lo; } band_lut[] = { { 50000000, 0xe1, 16}, /* AM_MODE2, antenna 2 */ {108000000, 0x42, 32}, /* VHF_MODE */ @@ -130,7 +132,7 @@ static int msi001_set_tuner(struct msi001 *s) {8000000, 0x07}, /* 8 MHz */ }; - unsigned int f_rf = s->f_tuner; + unsigned int f_rf = dev->f_tuner; /* * bandwidth (Hz) @@ -144,19 +146,18 @@ static int msi001_set_tuner(struct msi001 *s) */ unsigned int f_if = 0; #define F_REF 24000000 - #define R_REF 4 - #define F_OUT_STEP 1 + #define DIV_PRE_N 4 + #define F_VCO_STEP div_lo - dev_dbg(&s->spi->dev, "f_rf=%d f_if=%d\n", f_rf, f_if); + dev_dbg(&spi->dev, "f_rf=%d f_if=%d\n", f_rf, f_if); for (i = 0; i < ARRAY_SIZE(band_lut); i++) { if (f_rf <= band_lut[i].rf) { mode = band_lut[i].mode; - lo_div = band_lut[i].lo_div; + div_lo = band_lut[i].div_lo; break; } } - if (i == ARRAY_SIZE(band_lut)) { ret = -EINVAL; goto err; @@ -174,14 +175,13 @@ static int msi001_set_tuner(struct msi001 *s) break; } } - if (i == ARRAY_SIZE(if_freq_lut)) { ret = -EINVAL; goto err; } /* filters */ - bandwidth = s->bandwidth->val; + bandwidth = dev->bandwidth->val; bandwidth = clamp(bandwidth, 200000U, 8000000U); for (i = 0; i < ARRAY_SIZE(bandwidth_lut); i++) { @@ -190,48 +190,61 @@ static int msi001_set_tuner(struct msi001 *s) break; } } - if (i == ARRAY_SIZE(bandwidth_lut)) { ret = -EINVAL; goto err; } - s->bandwidth->val = bandwidth_lut[i].freq; + dev->bandwidth->val = bandwidth_lut[i].freq; - dev_dbg(&s->spi->dev, "bandwidth selected=%d\n", bandwidth_lut[i].freq); + dev_dbg(&spi->dev, "bandwidth selected=%d\n", bandwidth_lut[i].freq); - f_vco = (u64) (f_rf + f_if + f_if1) * lo_div; - tmp64 = f_vco; - m = do_div(tmp64, F_REF * R_REF); - n = (unsigned int) tmp64; + /* + * Fractional-N synthesizer + * + * +---------------------------------------+ + * v | + * Fref +----+ +-------+ +----+ +------+ +---+ + * ------> | PD | --> | VCO | ------> | /4 | --> | /N.F | <-- | K | + * +----+ +-------+ +----+ +------+ +---+ + * | + * | + * v + * +-------+ Fout + * | /Rout | ------> + * +-------+ + */ - vco_step = F_OUT_STEP * lo_div; - thresh = (F_REF * R_REF) / vco_step; - frac = 1ul * thresh * m / (F_REF * R_REF); + /* Calculate PLL integer and fractional control word. */ + f_vco = (u64) (f_rf + f_if + f_if1) * div_lo; + div_n = div_u64_rem(f_vco, DIV_PRE_N * F_REF, &k); + k_thresh = (DIV_PRE_N * F_REF) / F_VCO_STEP; + k_frac = div_u64((u64) k * k_thresh, (DIV_PRE_N * F_REF)); /* Find out greatest common divisor and divide to smaller. */ - tmp = gcd(thresh, frac); - thresh /= tmp; - frac /= tmp; + uitmp = gcd(k_thresh, k_frac); + k_thresh /= uitmp; + k_frac /= uitmp; /* Force divide to reg max. Resolution will be reduced. */ - tmp = DIV_ROUND_UP(thresh, 4095); - thresh = DIV_ROUND_CLOSEST(thresh, tmp); - frac = DIV_ROUND_CLOSEST(frac, tmp); + uitmp = DIV_ROUND_UP(k_thresh, 4095); + k_thresh = DIV_ROUND_CLOSEST(k_thresh, uitmp); + k_frac = DIV_ROUND_CLOSEST(k_frac, uitmp); - /* calc real RF set */ - tmp = 1ul * F_REF * R_REF * n; - tmp += 1ul * F_REF * R_REF * frac / thresh; - tmp /= lo_div; + /* Calculate real RF set. */ + uitmp = (unsigned int) F_REF * DIV_PRE_N * div_n; + uitmp += (unsigned int) F_REF * DIV_PRE_N * k_frac / k_thresh; + uitmp /= div_lo; - dev_dbg(&s->spi->dev, "rf=%u:%u n=%d thresh=%d frac=%d\n", - f_rf, tmp, n, thresh, frac); + dev_dbg(&spi->dev, + "f_rf=%u:%u f_vco=%llu div_n=%u k_thresh=%u k_frac=%u div_lo=%u\n", + f_rf, uitmp, f_vco, div_n, k_thresh, k_frac, div_lo); - ret = msi001_wreg(s, 0x00000e); + ret = msi001_wreg(dev, 0x00000e); if (ret) goto err; - ret = msi001_wreg(s, 0x000003); + ret = msi001_wreg(dev, 0x000003); if (ret) goto err; @@ -241,54 +254,55 @@ static int msi001_set_tuner(struct msi001 *s) reg |= bandwidth << 14; reg |= 0x02 << 17; reg |= 0x00 << 20; - ret = msi001_wreg(s, reg); + ret = msi001_wreg(dev, reg); if (ret) goto err; reg = 5 << 0; - reg |= thresh << 4; + reg |= k_thresh << 4; reg |= 1 << 19; reg |= 1 << 21; - ret = msi001_wreg(s, reg); + ret = msi001_wreg(dev, reg); if (ret) goto err; reg = 2 << 0; - reg |= frac << 4; - reg |= n << 16; - ret = msi001_wreg(s, reg); + reg |= k_frac << 4; + reg |= div_n << 16; + ret = msi001_wreg(dev, reg); if (ret) goto err; - ret = msi001_set_gain(s, s->lna_gain->cur.val, s->mixer_gain->cur.val, - s->if_gain->cur.val); + ret = msi001_set_gain(dev, dev->lna_gain->cur.val, + dev->mixer_gain->cur.val, dev->if_gain->cur.val); if (ret) goto err; reg = 6 << 0; reg |= 63 << 4; reg |= 4095 << 10; - ret = msi001_wreg(s, reg); + ret = msi001_wreg(dev, reg); if (ret) goto err; return 0; err: - dev_dbg(&s->spi->dev, "failed %d\n", ret); + dev_dbg(&spi->dev, "failed %d\n", ret); return ret; -}; +} static int msi001_s_power(struct v4l2_subdev *sd, int on) { - struct msi001 *s = sd_to_msi001(sd); + struct msi001_dev *dev = sd_to_msi001_dev(sd); + struct spi_device *spi = dev->spi; int ret; - dev_dbg(&s->spi->dev, "on=%d\n", on); + dev_dbg(&spi->dev, "on=%d\n", on); if (on) ret = 0; else - ret = msi001_wreg(s, 0x000000); + ret = msi001_wreg(dev, 0x000000); return ret; } @@ -299,9 +313,10 @@ static const struct v4l2_subdev_core_ops msi001_core_ops = { static int msi001_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) { - struct msi001 *s = sd_to_msi001(sd); + struct msi001_dev *dev = sd_to_msi001_dev(sd); + struct spi_device *spi = dev->spi; - dev_dbg(&s->spi->dev, "index=%d\n", v->index); + dev_dbg(&spi->dev, "index=%d\n", v->index); strlcpy(v->name, "Mirics MSi001", sizeof(v->name)); v->type = V4L2_TUNER_RF; @@ -314,47 +329,51 @@ static int msi001_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) static int msi001_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *v) { - struct msi001 *s = sd_to_msi001(sd); + struct msi001_dev *dev = sd_to_msi001_dev(sd); + struct spi_device *spi = dev->spi; - dev_dbg(&s->spi->dev, "index=%d\n", v->index); + dev_dbg(&spi->dev, "index=%d\n", v->index); return 0; } static int msi001_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) { - struct msi001 *s = sd_to_msi001(sd); + struct msi001_dev *dev = sd_to_msi001_dev(sd); + struct spi_device *spi = dev->spi; - dev_dbg(&s->spi->dev, "tuner=%d\n", f->tuner); - f->frequency = s->f_tuner; + dev_dbg(&spi->dev, "tuner=%d\n", f->tuner); + f->frequency = dev->f_tuner; return 0; } static int msi001_s_frequency(struct v4l2_subdev *sd, - const struct v4l2_frequency *f) + const struct v4l2_frequency *f) { - struct msi001 *s = sd_to_msi001(sd); + struct msi001_dev *dev = sd_to_msi001_dev(sd); + struct spi_device *spi = dev->spi; unsigned int band; - dev_dbg(&s->spi->dev, "tuner=%d type=%d frequency=%u\n", - f->tuner, f->type, f->frequency); + dev_dbg(&spi->dev, "tuner=%d type=%d frequency=%u\n", + f->tuner, f->type, f->frequency); if (f->frequency < ((bands[0].rangehigh + bands[1].rangelow) / 2)) band = 0; else band = 1; - s->f_tuner = clamp_t(unsigned int, f->frequency, - bands[band].rangelow, bands[band].rangehigh); + dev->f_tuner = clamp_t(unsigned int, f->frequency, + bands[band].rangelow, bands[band].rangehigh); - return msi001_set_tuner(s); + return msi001_set_tuner(dev); } static int msi001_enum_freq_bands(struct v4l2_subdev *sd, - struct v4l2_frequency_band *band) + struct v4l2_frequency_band *band) { - struct msi001 *s = sd_to_msi001(sd); + struct msi001_dev *dev = sd_to_msi001_dev(sd); + struct spi_device *spi = dev->spi; - dev_dbg(&s->spi->dev, "tuner=%d type=%d index=%d\n", - band->tuner, band->type, band->index); + dev_dbg(&spi->dev, "tuner=%d type=%d index=%d\n", + band->tuner, band->type, band->index); if (band->index >= ARRAY_SIZE(bands)) return -EINVAL; @@ -381,34 +400,37 @@ static const struct v4l2_subdev_ops msi001_ops = { static int msi001_s_ctrl(struct v4l2_ctrl *ctrl) { - struct msi001 *s = container_of(ctrl->handler, struct msi001, hdl); + struct msi001_dev *dev = container_of(ctrl->handler, struct msi001_dev, hdl); + struct spi_device *spi = dev->spi; int ret; - dev_dbg(&s->spi->dev, - "id=%d name=%s val=%d min=%lld max=%lld step=%lld\n", - ctrl->id, ctrl->name, ctrl->val, - ctrl->minimum, ctrl->maximum, ctrl->step); + dev_dbg(&spi->dev, "id=%d name=%s val=%d min=%lld max=%lld step=%lld\n", + ctrl->id, ctrl->name, ctrl->val, ctrl->minimum, ctrl->maximum, + ctrl->step); switch (ctrl->id) { case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: case V4L2_CID_RF_TUNER_BANDWIDTH: - ret = msi001_set_tuner(s); + ret = msi001_set_tuner(dev); break; case V4L2_CID_RF_TUNER_LNA_GAIN: - ret = msi001_set_gain(s, s->lna_gain->val, - s->mixer_gain->cur.val, s->if_gain->cur.val); + ret = msi001_set_gain(dev, dev->lna_gain->val, + dev->mixer_gain->cur.val, + dev->if_gain->cur.val); break; case V4L2_CID_RF_TUNER_MIXER_GAIN: - ret = msi001_set_gain(s, s->lna_gain->cur.val, - s->mixer_gain->val, s->if_gain->cur.val); + ret = msi001_set_gain(dev, dev->lna_gain->cur.val, + dev->mixer_gain->val, + dev->if_gain->cur.val); break; case V4L2_CID_RF_TUNER_IF_GAIN: - ret = msi001_set_gain(s, s->lna_gain->cur.val, - s->mixer_gain->cur.val, s->if_gain->val); + ret = msi001_set_gain(dev, dev->lna_gain->cur.val, + dev->mixer_gain->cur.val, + dev->if_gain->val); break; default: - dev_dbg(&s->spi->dev, "unknown control %d\n", ctrl->id); + dev_dbg(&spi->dev, "unknown control %d\n", ctrl->id); ret = -EINVAL; } @@ -421,56 +443,54 @@ static const struct v4l2_ctrl_ops msi001_ctrl_ops = { static int msi001_probe(struct spi_device *spi) { - struct msi001 *s; + struct msi001_dev *dev; int ret; dev_dbg(&spi->dev, "\n"); - s = kzalloc(sizeof(struct msi001), GFP_KERNEL); - if (s == NULL) { + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { ret = -ENOMEM; - dev_dbg(&spi->dev, "Could not allocate memory for msi001\n"); - goto err_kfree; + goto err; } - s->spi = spi; - s->f_tuner = bands[0].rangelow; - v4l2_spi_subdev_init(&s->sd, spi, &msi001_ops); + dev->spi = spi; + dev->f_tuner = bands[0].rangelow; + v4l2_spi_subdev_init(&dev->sd, spi, &msi001_ops); /* Register controls */ - v4l2_ctrl_handler_init(&s->hdl, 5); - s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, &msi001_ctrl_ops, + v4l2_ctrl_handler_init(&dev->hdl, 5); + dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, &msi001_ctrl_ops, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1); - s->bandwidth = v4l2_ctrl_new_std(&s->hdl, &msi001_ctrl_ops, + dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, &msi001_ctrl_ops, V4L2_CID_RF_TUNER_BANDWIDTH, 200000, 8000000, 1, 200000); - v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false); - s->lna_gain = v4l2_ctrl_new_std(&s->hdl, &msi001_ctrl_ops, + v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false); + dev->lna_gain = v4l2_ctrl_new_std(&dev->hdl, &msi001_ctrl_ops, V4L2_CID_RF_TUNER_LNA_GAIN, 0, 1, 1, 1); - s->mixer_gain = v4l2_ctrl_new_std(&s->hdl, &msi001_ctrl_ops, + dev->mixer_gain = v4l2_ctrl_new_std(&dev->hdl, &msi001_ctrl_ops, V4L2_CID_RF_TUNER_MIXER_GAIN, 0, 1, 1, 1); - s->if_gain = v4l2_ctrl_new_std(&s->hdl, &msi001_ctrl_ops, + dev->if_gain = v4l2_ctrl_new_std(&dev->hdl, &msi001_ctrl_ops, V4L2_CID_RF_TUNER_IF_GAIN, 0, 59, 1, 0); - if (s->hdl.error) { - ret = s->hdl.error; - dev_err(&s->spi->dev, "Could not initialize controls\n"); + if (dev->hdl.error) { + ret = dev->hdl.error; + dev_err(&spi->dev, "Could not initialize controls\n"); /* control init failed, free handler */ goto err_ctrl_handler_free; } - s->sd.ctrl_handler = &s->hdl; + dev->sd.ctrl_handler = &dev->hdl; return 0; - err_ctrl_handler_free: - v4l2_ctrl_handler_free(&s->hdl); -err_kfree: - kfree(s); + v4l2_ctrl_handler_free(&dev->hdl); + kfree(dev); +err: return ret; } static int msi001_remove(struct spi_device *spi) { struct v4l2_subdev *sd = spi_get_drvdata(spi); - struct msi001 *s = sd_to_msi001(sd); + struct msi001_dev *dev = sd_to_msi001_dev(sd); dev_dbg(&spi->dev, "\n"); @@ -478,26 +498,27 @@ static int msi001_remove(struct spi_device *spi) * Registered by v4l2_spi_new_subdev() from master driver, but we must * unregister it from here. Weird. */ - v4l2_device_unregister_subdev(&s->sd); - v4l2_ctrl_handler_free(&s->hdl); - kfree(s); + v4l2_device_unregister_subdev(&dev->sd); + v4l2_ctrl_handler_free(&dev->hdl); + kfree(dev); return 0; } -static const struct spi_device_id msi001_id[] = { +static const struct spi_device_id msi001_id_table[] = { {"msi001", 0}, {} }; -MODULE_DEVICE_TABLE(spi, msi001_id); +MODULE_DEVICE_TABLE(spi, msi001_id_table); static struct spi_driver msi001_driver = { .driver = { .name = "msi001", .owner = THIS_MODULE, + .suppress_bind_attrs = true, }, .probe = msi001_probe, .remove = msi001_remove, - .id_table = msi001_id, + .id_table = msi001_id_table, }; module_spi_driver(msi001_driver); diff --git a/drivers/media/tuners/qt1010.c b/drivers/media/tuners/qt1010.c index bc419f8..ae8cbec 100644 --- a/drivers/media/tuners/qt1010.c +++ b/drivers/media/tuners/qt1010.c @@ -294,7 +294,7 @@ static int qt1010_init(struct dvb_frontend *fe) int err = 0; u8 i, tmpval, *valptr = NULL; - qt1010_i2c_oper_t i2c_data[] = { + static const qt1010_i2c_oper_t i2c_data[] = { { QT1010_WR, 0x01, 0x80 }, { QT1010_WR, 0x0d, 0x84 }, { QT1010_WR, 0x0e, 0xb7 }, @@ -354,13 +354,17 @@ static int qt1010_init(struct dvb_frontend *fe) valptr = &priv->reg1f_init_val; else valptr = &tmpval; + + BUG_ON(i >= ARRAY_SIZE(i2c_data) - 1); + err = qt1010_init_meas1(priv, i2c_data[i+1].reg, i2c_data[i].reg, i2c_data[i].val, valptr); i++; break; } - if (err) return err; + if (err) + return err; } for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */ diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 71159a5..a7a8452 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -941,8 +941,8 @@ static int r820t_sysfreq_sel(struct r820t_priv *priv, u32 freq, rc = r820t_write_reg_mask(priv, 0x10, 0x00, 0x04); if (rc < 0) return rc; - } - return 0; + } + return 0; } static int r820t_set_tv_standard(struct r820t_priv *priv, diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index d74ae26..a6245ef 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -79,6 +79,7 @@ static int si2157_init(struct dvb_frontend *fe) { struct i2c_client *client = fe->tuner_priv; struct si2157_dev *dev = i2c_get_clientdata(client); + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, len, remaining; struct si2157_cmd cmd; const struct firmware *fw; @@ -201,9 +202,14 @@ skip_fw_download: dev->fw_loaded = true; warm: + /* init statistics in order signal app which are supported */ + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + /* start statistics polling */ + schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(1000)); + dev->active = true; return 0; - err_release_firmware: release_firmware(fw); err: @@ -222,6 +228,9 @@ static int si2157_sleep(struct dvb_frontend *fe) dev->active = false; + /* stop statistics polling */ + cancel_delayed_work_sync(&dev->stat_work); + /* standby */ memcpy(cmd.args, "\x16\x00", 2); cmd.wlen = 2; @@ -298,7 +307,8 @@ static int si2157_set_params(struct dvb_frontend *fe) if (dev->chiptype == SI2157_CHIPTYPE_SI2146) memcpy(cmd.args, "\x14\x00\x02\x07\x00\x01", 6); else - memcpy(cmd.args, "\x14\x00\x02\x07\x01\x00", 6); + memcpy(cmd.args, "\x14\x00\x02\x07\x00\x00", 6); + cmd.args[4] = dev->if_port; cmd.wlen = 6; cmd.rlen = 4; ret = si2157_cmd_execute(client, &cmd); @@ -359,6 +369,34 @@ static const struct dvb_tuner_ops si2157_ops = { .get_if_frequency = si2157_get_if_frequency, }; +static void si2157_stat_work(struct work_struct *work) +{ + struct si2157_dev *dev = container_of(work, struct si2157_dev, stat_work.work); + struct dvb_frontend *fe = dev->fe; + struct i2c_client *client = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct si2157_cmd cmd; + int ret; + + dev_dbg(&client->dev, "\n"); + + memcpy(cmd.args, "\x42\x00", 2); + cmd.wlen = 2; + cmd.rlen = 12; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + c->strength.stat[0].svalue = (s8) cmd.args[3] * 1000; + + schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000)); + return; +err: + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + dev_dbg(&client->dev, "failed=%d\n", ret); +} + static int si2157_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -378,10 +416,12 @@ static int si2157_probe(struct i2c_client *client, i2c_set_clientdata(client, dev); dev->fe = cfg->fe; dev->inversion = cfg->inversion; + dev->if_port = cfg->if_port; dev->fw_loaded = false; dev->chiptype = (u8)id->driver_data; dev->if_frequency = 5000000; /* default value of property 0x0706 */ mutex_init(&dev->i2c_mutex); + INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work); /* check if the tuner is there */ cmd.wlen = 0; diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h index a564c4a..4db97ab 100644 --- a/drivers/media/tuners/si2157.h +++ b/drivers/media/tuners/si2157.h @@ -34,6 +34,12 @@ struct si2157_config { * Spectral Inversion */ bool inversion; + + /* + * Port selection + * Select the RF interface to use (pins 9+11 or 12+13) + */ + u8 if_port; }; #endif diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h index cd8fa5b..ecc463d 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h @@ -28,7 +28,9 @@ struct si2157_dev { bool fw_loaded; bool inversion; u8 chiptype; + u8 if_port; u32 if_frequency; + struct delayed_work stat_work; }; #define SI2157_CHIPTYPE_SI2157 0 diff --git a/drivers/media/tuners/tua9001.c b/drivers/media/tuners/tua9001.c index 83a6240..d4f6ca0 100644 --- a/drivers/media/tuners/tua9001.c +++ b/drivers/media/tuners/tua9001.c @@ -1,5 +1,5 @@ /* - * Infineon TUA 9001 silicon tuner driver + * Infineon TUA9001 silicon tuner driver * * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> * @@ -12,138 +12,87 @@ * 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 "tua9001.h" #include "tua9001_priv.h" -/* write register */ -static int tua9001_wr_reg(struct tua9001_priv *priv, u8 reg, u16 val) -{ - int ret; - u8 buf[3] = { reg, (val >> 8) & 0xff, (val >> 0) & 0xff }; - struct i2c_msg msg[1] = { - { - .addr = priv->cfg->i2c_addr, - .flags = 0, - .len = sizeof(buf), - .buf = buf, - } - }; - - ret = i2c_transfer(priv->i2c, msg, 1); - if (ret == 1) { - ret = 0; - } else { - dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x\n", - KBUILD_MODNAME, ret, reg); - ret = -EREMOTEIO; - } - - return ret; -} - -static int tua9001_release(struct dvb_frontend *fe) -{ - struct tua9001_priv *priv = fe->tuner_priv; - int ret = 0; - - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); - - if (fe->callback) - ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, - TUA9001_CMD_CEN, 0); - - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - - return ret; -} - static int tua9001_init(struct dvb_frontend *fe) { - struct tua9001_priv *priv = fe->tuner_priv; - int ret = 0; - u8 i; - struct reg_val data[] = { - { 0x1e, 0x6512 }, - { 0x25, 0xb888 }, - { 0x39, 0x5460 }, - { 0x3b, 0x00c0 }, - { 0x3a, 0xf000 }, - { 0x08, 0x0000 }, - { 0x32, 0x0030 }, - { 0x41, 0x703a }, - { 0x40, 0x1c78 }, - { 0x2c, 0x1c00 }, - { 0x36, 0xc013 }, - { 0x37, 0x6f18 }, - { 0x27, 0x0008 }, - { 0x2a, 0x0001 }, - { 0x34, 0x0a40 }, + struct tua9001_dev *dev = fe->tuner_priv; + struct i2c_client *client = dev->client; + int ret, i; + static const struct tua9001_reg_val data[] = { + {0x1e, 0x6512}, + {0x25, 0xb888}, + {0x39, 0x5460}, + {0x3b, 0x00c0}, + {0x3a, 0xf000}, + {0x08, 0x0000}, + {0x32, 0x0030}, + {0x41, 0x703a}, + {0x40, 0x1c78}, + {0x2c, 0x1c00}, + {0x36, 0xc013}, + {0x37, 0x6f18}, + {0x27, 0x0008}, + {0x2a, 0x0001}, + {0x34, 0x0a40}, }; - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); if (fe->callback) { - ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, - TUA9001_CMD_RESETN, 0); - if (ret < 0) + ret = fe->callback(client->adapter, + DVB_FRONTEND_COMPONENT_TUNER, + TUA9001_CMD_RESETN, 0); + if (ret) goto err; } - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */ - for (i = 0; i < ARRAY_SIZE(data); i++) { - ret = tua9001_wr_reg(priv, data[i].reg, data[i].val); - if (ret < 0) - goto err_i2c_gate_ctrl; + ret = regmap_write(dev->regmap, data[i].reg, data[i].val); + if (ret) + goto err; } - -err_i2c_gate_ctrl: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */ + return 0; err: - if (ret < 0) - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int tua9001_sleep(struct dvb_frontend *fe) { - struct tua9001_priv *priv = fe->tuner_priv; - int ret = 0; - - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); - - if (fe->callback) - ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, - TUA9001_CMD_RESETN, 1); + struct tua9001_dev *dev = fe->tuner_priv; + struct i2c_client *client = dev->client; + int ret; - if (ret < 0) - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "\n"); + if (fe->callback) { + ret = fe->callback(client->adapter, + DVB_FRONTEND_COMPONENT_TUNER, + TUA9001_CMD_RESETN, 1); + if (ret) + goto err; + } + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int tua9001_set_params(struct dvb_frontend *fe) { - struct tua9001_priv *priv = fe->tuner_priv; + struct tua9001_dev *dev = fe->tuner_priv; + struct i2c_client *client = dev->client; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret = 0, i; + int ret, i; u16 val; - u32 frequency; - struct reg_val data[2]; + struct tua9001_reg_val data[2]; - dev_dbg(&priv->i2c->dev, "%s: delivery_system=%d frequency=%d " \ - "bandwidth_hz=%d\n", __func__, - c->delivery_system, c->frequency, c->bandwidth_hz); + dev_dbg(&client->dev, + "delivery_system=%u frequency=%u bandwidth_hz=%u\n", + c->delivery_system, c->frequency, c->bandwidth_hz); switch (c->delivery_system) { case SYS_DVBT: @@ -172,70 +121,54 @@ static int tua9001_set_params(struct dvb_frontend *fe) data[0].reg = 0x04; data[0].val = val; - - frequency = (c->frequency - 150000000); - frequency /= 100; - frequency *= 48; - frequency /= 10000; - data[1].reg = 0x1f; - data[1].val = frequency; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */ + data[1].val = div_u64((u64) (c->frequency - 150000000) * 48, 1000000); if (fe->callback) { - ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, - TUA9001_CMD_RXEN, 0); - if (ret < 0) - goto err_i2c_gate_ctrl; + ret = fe->callback(client->adapter, + DVB_FRONTEND_COMPONENT_TUNER, + TUA9001_CMD_RXEN, 0); + if (ret) + goto err; } for (i = 0; i < ARRAY_SIZE(data); i++) { - ret = tua9001_wr_reg(priv, data[i].reg, data[i].val); - if (ret < 0) - goto err_i2c_gate_ctrl; + ret = regmap_write(dev->regmap, data[i].reg, data[i].val); + if (ret) + goto err; } if (fe->callback) { - ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, - TUA9001_CMD_RXEN, 1); - if (ret < 0) - goto err_i2c_gate_ctrl; + ret = fe->callback(client->adapter, + DVB_FRONTEND_COMPONENT_TUNER, + TUA9001_CMD_RXEN, 1); + if (ret) + goto err; } - -err_i2c_gate_ctrl: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */ + return 0; err: - if (ret < 0) - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) { - struct tua9001_priv *priv = fe->tuner_priv; + struct tua9001_dev *dev = fe->tuner_priv; + struct i2c_client *client = dev->client; - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); *frequency = 0; /* Zero-IF */ - return 0; } static const struct dvb_tuner_ops tua9001_tuner_ops = { .info = { - .name = "Infineon TUA 9001", - + .name = "Infineon TUA9001", .frequency_min = 170000000, .frequency_max = 862000000, - .frequency_step = 0, }, - .release = tua9001_release, - .init = tua9001_init, .sleep = tua9001_sleep, .set_params = tua9001_set_params, @@ -243,52 +176,108 @@ static const struct dvb_tuner_ops tua9001_tuner_ops = { .get_if_frequency = tua9001_get_if_frequency, }; -struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tua9001_config *cfg) +static int tua9001_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - struct tua9001_priv *priv = NULL; + struct tua9001_dev *dev; + struct tua9001_platform_data *pdata = client->dev.platform_data; + struct dvb_frontend *fe = pdata->dvb_frontend; int ret; + static const struct regmap_config regmap_config = { + .reg_bits = 8, + .val_bits = 16, + }; - priv = kzalloc(sizeof(struct tua9001_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + ret = -ENOMEM; + goto err; + } - priv->cfg = cfg; - priv->i2c = i2c; + dev->fe = pdata->dvb_frontend; + dev->client = client; + dev->regmap = devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(dev->regmap)) { + ret = PTR_ERR(dev->regmap); + goto err_kfree; + } if (fe->callback) { - ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, - TUA9001_CMD_CEN, 1); - if (ret < 0) - goto err; - - ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, - TUA9001_CMD_RXEN, 0); - if (ret < 0) - goto err; - - ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, - TUA9001_CMD_RESETN, 1); - if (ret < 0) - goto err; + ret = fe->callback(client->adapter, + DVB_FRONTEND_COMPONENT_TUNER, + TUA9001_CMD_CEN, 1); + if (ret) + goto err_kfree; + + ret = fe->callback(client->adapter, + DVB_FRONTEND_COMPONENT_TUNER, + TUA9001_CMD_RXEN, 0); + if (ret) + goto err_kfree; + + ret = fe->callback(client->adapter, + DVB_FRONTEND_COMPONENT_TUNER, + TUA9001_CMD_RESETN, 1); + if (ret) + goto err_kfree; } - dev_info(&priv->i2c->dev, - "%s: Infineon TUA 9001 successfully attached\n", - KBUILD_MODNAME); - + fe->tuner_priv = dev; memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops, sizeof(struct dvb_tuner_ops)); + i2c_set_clientdata(client, dev); - fe->tuner_priv = priv; - return fe; + dev_info(&client->dev, "Infineon TUA9001 successfully attached\n"); + return 0; +err_kfree: + kfree(dev); err: - dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); - kfree(priv); - return NULL; + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + +static int tua9001_remove(struct i2c_client *client) +{ + struct tua9001_dev *dev = i2c_get_clientdata(client); + struct dvb_frontend *fe = dev->fe; + int ret; + + dev_dbg(&client->dev, "\n"); + + if (fe->callback) { + ret = fe->callback(client->adapter, + DVB_FRONTEND_COMPONENT_TUNER, + TUA9001_CMD_CEN, 0); + if (ret) + goto err_kfree; + } + kfree(dev); + return 0; +err_kfree: + kfree(dev); + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; } -EXPORT_SYMBOL(tua9001_attach); -MODULE_DESCRIPTION("Infineon TUA 9001 silicon tuner driver"); +static const struct i2c_device_id tua9001_id_table[] = { + {"tua9001", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, tua9001_id_table); + +static struct i2c_driver tua9001_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "tua9001", + .suppress_bind_attrs = true, + }, + .probe = tua9001_probe, + .remove = tua9001_remove, + .id_table = tua9001_id_table, +}; + +module_i2c_driver(tua9001_driver); + +MODULE_DESCRIPTION("Infineon TUA9001 silicon tuner driver"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/tua9001.h b/drivers/media/tuners/tua9001.h index 2c3375c..7b05481 100644 --- a/drivers/media/tuners/tua9001.h +++ b/drivers/media/tuners/tua9001.h @@ -1,5 +1,5 @@ /* - * Infineon TUA 9001 silicon tuner driver + * Infineon TUA9001 silicon tuner driver * * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> * @@ -12,23 +12,24 @@ * 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. */ #ifndef TUA9001_H #define TUA9001_H -#include <linux/kconfig.h> #include "dvb_frontend.h" -struct tua9001_config { - /* - * I2C address - */ - u8 i2c_addr; +/* + * I2C address + * 0x60, + */ + +/** + * struct tua9001_platform_data - Platform data for the tua9001 driver + * @dvb_frontend: DVB frontend. + */ +struct tua9001_platform_data { + struct dvb_frontend *dvb_frontend; }; /* @@ -51,16 +52,4 @@ struct tua9001_config { #define TUA9001_CMD_RESETN 1 #define TUA9001_CMD_RXEN 2 -#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TUA9001) -extern struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tua9001_config *cfg); -#else -static inline struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tua9001_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - #endif diff --git a/drivers/media/tuners/tua9001_priv.h b/drivers/media/tuners/tua9001_priv.h index 73cc1ce..bc406c5 100644 --- a/drivers/media/tuners/tua9001_priv.h +++ b/drivers/media/tuners/tua9001_priv.h @@ -1,5 +1,5 @@ /* - * Infineon TUA 9001 silicon tuner driver + * Infineon TUA9001 silicon tuner driver * * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> * @@ -12,23 +12,24 @@ * 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. */ #ifndef TUA9001_PRIV_H #define TUA9001_PRIV_H -struct reg_val { +#include "tua9001.h" +#include <linux/math64.h> +#include <linux/regmap.h> + +struct tua9001_reg_val { u8 reg; u16 val; }; -struct tua9001_priv { - struct tua9001_config *cfg; - struct i2c_adapter *i2c; +struct tua9001_dev { + struct dvb_frontend *fe; + struct i2c_client *client; + struct regmap *regmap; }; #endif diff --git a/drivers/media/tuners/tuner-i2c.h b/drivers/media/tuners/tuner-i2c.h index 18f0056..bda67a5 100644 --- a/drivers/media/tuners/tuner-i2c.h +++ b/drivers/media/tuners/tuner-i2c.h @@ -33,7 +33,8 @@ struct tuner_i2c_props { char *name; }; -static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len) +static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, + unsigned char *buf, int len) { struct i2c_msg msg = { .addr = props->addr, .flags = 0, .buf = buf, .len = len }; @@ -42,7 +43,8 @@ static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, return (ret == 1) ? len : ret; } -static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, int len) +static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, + unsigned char *buf, int len) { struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD, .buf = buf, .len = len }; @@ -52,8 +54,8 @@ static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, } static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props, - char *obuf, int olen, - char *ibuf, int ilen) + unsigned char *obuf, int olen, + unsigned char *ibuf, int ilen) { struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0, .buf = obuf, .len = olen }, diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c index d12f5e4..4e941f0 100644 --- a/drivers/media/tuners/tuner-xc2028.c +++ b/drivers/media/tuners/tuner-xc2028.c @@ -1094,7 +1094,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, * Still need tests for XC3028L (firmware 3.2 or upper) * So, for now, let's just comment the per-firmware * version of this change. Reports with xc3028l working - * with and without the lines bellow are welcome + * with and without the lines below are welcome */ if (priv->firm_version < 0x0302) { diff --git a/drivers/media/usb/as102/as102_drv.c b/drivers/media/usb/as102/as102_drv.c index 8be1474..9dd7c7c 100644 --- a/drivers/media/usb/as102/as102_drv.c +++ b/drivers/media/usb/as102/as102_drv.c @@ -337,6 +337,7 @@ int as102_dvb_register(struct as102_dev_t *as102_dev) &as102_dev->bus_adap, as102_dev->elna_cfg); if (!as102_dev->dvb_fe) { + ret = -ENODEV; dev_err(dev, "%s: as102_attach() failed: %d", __func__, ret); goto efereg; diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c index edc2735..6b469e8 100644 --- a/drivers/media/usb/au0828/au0828-cards.c +++ b/drivers/media/usb/au0828/au0828-cards.c @@ -195,8 +195,6 @@ void au0828_card_setup(struct au0828_dev *dev) dprintk(1, "%s()\n", __func__); - dev->board = au0828_boards[dev->boardnr]; - if (dev->i2c_rc == 0) { dev->i2c_client.addr = 0xa0 >> 1; tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom)); diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 082ae6b..0934024 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -222,6 +222,8 @@ static int au0828_usb_probe(struct usb_interface *interface, mutex_init(&dev->dvb.lock); dev->usbdev = usbdev; dev->boardnr = id->driver_info; + dev->board = au0828_boards[dev->boardnr]; + #ifdef CONFIG_VIDEO_AU0828_V4L2 dev->v4l2_dev.release = au0828_usb_v4l2_release; diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 983ea83..47a98a2 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1160,9 +1160,9 @@ static int cx231xx_initialize_codec(struct cx231xx *dev) } cx231xx_enable656(dev); - /* stop mpeg capture */ - cx231xx_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, - 3, 0, 1, 3, 4); + + /* stop mpeg capture */ + cx231xx_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, 1, 3, 4); cx231xx_codec_settings(dev); msleep(60); @@ -1249,8 +1249,7 @@ static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf) struct cx231xx *dev = fh->dev; unsigned long flags = 0; - if (in_interrupt()) - BUG(); + BUG_ON(in_interrupt()); spin_lock_irqsave(&dev->video_mode.slock, flags); if (dev->USE_ISO) { @@ -1878,13 +1877,15 @@ static int cx231xx_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) { struct cx231xx *dev = container_of(cxhdl, struct cx231xx, mpeg_ctrl_handler); int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_mbus_framefmt fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; /* fix videodecoder resolution */ - fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); - fmt.height = cxhdl->height; - fmt.code = MEDIA_BUS_FMT_FIXED; - v4l2_subdev_call(dev->sd_cx25840, video, s_mbus_fmt, &fmt); + format.format.width = cxhdl->width / (is_mpeg1 ? 2 : 1); + format.format.height = cxhdl->height; + format.format.code = MEDIA_BUS_FMT_FIXED; + v4l2_subdev_call(dev->sd_cx25840, pad, set_fmt, NULL, &format); return 0; } diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c index 39e8879..4919137 100644 --- a/drivers/media/usb/cx231xx/cx231xx-avcore.c +++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c @@ -1595,31 +1595,31 @@ void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq, /*pll_freq_word = 0x3463497;*/ vid_blk_write_word(dev, DIF_PLL_FREQ_WORD, pll_freq_word); - if (spectral_invert) { - if_freq -= 400000; - /* Enable Spectral Invert*/ - vid_blk_read_word(dev, DIF_MISC_CTRL, - &dif_misc_ctrl_value); - dif_misc_ctrl_value = dif_misc_ctrl_value | 0x00200000; - vid_blk_write_word(dev, DIF_MISC_CTRL, - dif_misc_ctrl_value); - } else { - if_freq += 400000; - /* Disable Spectral Invert*/ - vid_blk_read_word(dev, DIF_MISC_CTRL, - &dif_misc_ctrl_value); - dif_misc_ctrl_value = dif_misc_ctrl_value & 0xFFDFFFFF; - vid_blk_write_word(dev, DIF_MISC_CTRL, - dif_misc_ctrl_value); - } + if (spectral_invert) { + if_freq -= 400000; + /* Enable Spectral Invert*/ + vid_blk_read_word(dev, DIF_MISC_CTRL, + &dif_misc_ctrl_value); + dif_misc_ctrl_value = dif_misc_ctrl_value | 0x00200000; + vid_blk_write_word(dev, DIF_MISC_CTRL, + dif_misc_ctrl_value); + } else { + if_freq += 400000; + /* Disable Spectral Invert*/ + vid_blk_read_word(dev, DIF_MISC_CTRL, + &dif_misc_ctrl_value); + dif_misc_ctrl_value = dif_misc_ctrl_value & 0xFFDFFFFF; + vid_blk_write_word(dev, DIF_MISC_CTRL, + dif_misc_ctrl_value); + } - if_freq = (if_freq/100000)*100000; + if_freq = (if_freq / 100000) * 100000; - if (if_freq < 3000000) - if_freq = 3000000; + if (if_freq < 3000000) + if_freq = 3000000; - if (if_freq > 16000000) - if_freq = 16000000; + if (if_freq > 16000000) + if_freq = 16000000; } dev_dbg(dev->dev, "Enter IF=%zu\n", ARRAY_SIZE(Dif_set_array)); diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index fe00da1..4a117a5 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -815,6 +815,32 @@ struct cx231xx_board cx231xx_boards[] = { .gpio = NULL, } }, }, + [CX231XX_BOARD_TERRATEC_GRABBY] = { + .name = "Terratec Grabby", + .tuner_type = TUNER_ABSENT, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .norm = V4L2_STD_PAL, + .no_alt_vanc = 1, + .external_av = 1, + .input = {{ + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } }, + }, }; const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards); @@ -880,6 +906,8 @@ struct usb_device_id cx231xx_id_table[] = { .driver_info = CX231XX_BOARD_ELGATO_VIDEO_CAPTURE_V2}, {USB_DEVICE(0x1f4d, 0x0102), .driver_info = CX231XX_BOARD_OTG102}, + {USB_DEVICE(USB_VID_TERRATEC, 0x00a6), + .driver_info = CX231XX_BOARD_TERRATEC_GRABBY}, {}, }; @@ -1092,17 +1120,25 @@ void cx231xx_card_setup(struct cx231xx *dev) case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx: case CX231XX_BOARD_HAUPPAUGE_955Q: { - struct tveeprom tvee; - static u8 eeprom[256]; - struct i2c_client client; - - memset(&client, 0, sizeof(client)); - client.adapter = cx231xx_get_i2c_adap(dev, I2C_1_MUX_1); - client.addr = 0xa0 >> 1; + struct eeprom { + struct tveeprom tvee; + u8 eeprom[256]; + struct i2c_client client; + }; + struct eeprom *e = kzalloc(sizeof(*e), GFP_KERNEL); + + if (e == NULL) { + dev_err(dev->dev, + "failed to allocate memory to read eeprom\n"); + break; + } + e->client.adapter = cx231xx_get_i2c_adap(dev, I2C_1_MUX_1); + e->client.addr = 0xa0 >> 1; - read_eeprom(dev, &client, eeprom, sizeof(eeprom)); - tveeprom_hauppauge_analog(&client, - &tvee, eeprom + 0xc0); + read_eeprom(dev, &e->client, e->eeprom, sizeof(e->eeprom)); + tveeprom_hauppauge_analog(&e->client, + &e->tvee, e->eeprom + 0xc0); + kfree(e); break; } } diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index e42bde0..a2fd49b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -653,22 +653,20 @@ int cx231xx_demod_reset(struct cx231xx *dev) cx231xx_coredbg("Enter cx231xx_demod_reset()\n"); - value[1] = (u8) 0x3; - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(10); - - value[1] = (u8) 0x0; - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(10); - - value[1] = (u8) 0x3; - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(10); - - + value[1] = (u8) 0x3; + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(10); + + value[1] = (u8) 0x0; + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(10); + + value[1] = (u8) 0x3; + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(10); status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, value, 4); diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index 610d567..66ee161 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -797,6 +797,7 @@ static int dvb_init(struct cx231xx *dev) /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = dev->dvb->frontend; + si2157_config.if_port = 1; si2157_config.inversion = true; strlcpy(info.type, "si2157", I2C_NAME_SIZE); info.addr = 0x60; @@ -852,6 +853,7 @@ static int dvb_init(struct cx231xx *dev) /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = dev->dvb->frontend; + si2157_config.if_port = 1; si2157_config.inversion = true; strlcpy(info.type, "si2157", I2C_NAME_SIZE); info.addr = 0x60; diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c index 80261ac..a08014d 100644 --- a/drivers/media/usb/cx231xx/cx231xx-vbi.c +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c @@ -192,8 +192,7 @@ static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf) struct cx231xx_fh *fh = vq->priv_data; struct cx231xx *dev = fh->dev; unsigned long flags = 0; - if (in_interrupt()) - BUG(); + BUG_ON(in_interrupt()); /* 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, diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index c261e16..c6ff896 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -749,8 +749,7 @@ static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf) struct cx231xx *dev = fh->dev; unsigned long flags = 0; - if (in_interrupt()) - BUG(); + BUG_ON(in_interrupt()); /* 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, @@ -1013,7 +1012,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct cx231xx *dev = fh->dev; int rc; struct cx231xx_fmt *fmt; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; rc = check_dev(dev); if (rc < 0) @@ -1041,9 +1042,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, dev->height = f->fmt.pix.height; dev->format = fmt; - v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); - call_all(dev, video, s_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); + v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); + call_all(dev, pad, set_fmt, NULL, &format); + v4l2_fill_pix_format(&f->fmt.pix, &format.format); return rc; } @@ -1061,7 +1062,9 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int rc; rc = check_dev(dev); @@ -1085,11 +1088,10 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) /* We need to reset basic properties in the decoder related to resolution (since a standard change effects things like the number of lines in VACT, etc) */ - memset(&mbus_fmt, 0, sizeof(mbus_fmt)); - mbus_fmt.code = MEDIA_BUS_FMT_FIXED; - mbus_fmt.width = dev->width; - mbus_fmt.height = dev->height; - call_all(dev, video, s_mbus_fmt, &mbus_fmt); + format.format.code = MEDIA_BUS_FMT_FIXED; + format.format.width = dev->width; + format.format.height = dev->height; + call_all(dev, pad, set_fmt, NULL, &format); /* do mode control overrides */ cx231xx_do_mode_ctrl_overrides(dev); diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 00d3bce..54790fb 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -77,6 +77,7 @@ #define CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx 19 #define CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx 20 #define CX231XX_BOARD_HAUPPAUGE_955Q 21 +#define CX231XX_BOARD_TERRATEC_GRABBY 22 /* Limits minimum and default number of buffers */ #define CX231XX_MIN_BUF 4 diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 16c0b7d..95a7388 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -641,7 +641,7 @@ static int af9015_af9013_set_frontend(struct dvb_frontend *fe) /* override demod callbacks for resource locking */ static int af9015_af9013_read_status(struct dvb_frontend *fe, - fe_status_t *status) + enum fe_status *status) { int ret; struct af9015_state *state = fe_to_priv(fe); diff --git a/drivers/media/usb/dvb-usb-v2/af9015.h b/drivers/media/usb/dvb-usb-v2/af9015.h index 3a6f3ad..1db1bb0 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.h +++ b/drivers/media/usb/dvb-usb-v2/af9015.h @@ -133,7 +133,7 @@ struct af9015_state { /* for demod callback override */ int (*set_frontend[2]) (struct dvb_frontend *fe); - int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status); + int (*read_status[2]) (struct dvb_frontend *fe, enum fe_status *status); int (*init[2]) (struct dvb_frontend *fe); int (*sleep[2]) (struct dvb_frontend *fe); int (*tuner_init[2]) (struct dvb_frontend *fe); diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 80a29f5..6e02a15 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -1234,10 +1234,6 @@ static int af9035_frontend_detach(struct dvb_usb_adapter *adap) return 0; } -static struct tua9001_config af9035_tua9001_config = { - .i2c_addr = 0x60, -}; - static const struct fc0011_config af9035_fc0011_config = { .i2c_address = 0x60, }; @@ -1265,11 +1261,6 @@ static struct tda18218_config af9035_tda18218_config = { .i2c_wr_max = 21, }; -static const struct fc2580_config af9035_fc2580_config = { - .i2c_addr = 0x56, - .clock = 16384000, -}; - static const struct fc0012_config af9035_fc0012_config[] = { { .i2c_address = 0x63, @@ -1301,9 +1292,15 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) */ switch (state->af9033_config[adap->id].tuner) { - case AF9033_TUNER_TUA9001: - /* AF9035 gpiot3 = TUA9001 RESETN - AF9035 gpiot2 = TUA9001 RXEN */ + case AF9033_TUNER_TUA9001: { + struct tua9001_platform_data tua9001_pdata = { + .dvb_frontend = adap->fe[0], + }; + + /* + * AF9035 gpiot3 = TUA9001 RESETN + * AF9035 gpiot2 = TUA9001 RXEN + */ /* configure gpiot2 and gpiot2 as output */ ret = af9035_wr_reg_mask(d, 0x00d8ec, 0x01, 0x01); @@ -1323,9 +1320,14 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) goto err; /* attach tuner */ - fe = dvb_attach(tua9001_attach, adap->fe[0], - &d->i2c_adap, &af9035_tua9001_config); + ret = af9035_add_i2c_dev(d, "tua9001", 0x60, &tua9001_pdata, + &d->i2c_adap); + if (ret) + goto err; + + fe = adap->fe[0]; break; + } case AF9033_TUNER_FC0011: fe = dvb_attach(fc0011_attach, adap->fe[0], &d->i2c_adap, &af9035_fc0011_config); @@ -1390,7 +1392,11 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) fe = dvb_attach(tda18218_attach, adap->fe[0], &d->i2c_adap, &af9035_tda18218_config); break; - case AF9033_TUNER_FC2580: + case AF9033_TUNER_FC2580: { + struct fc2580_platform_data fc2580_pdata = { + .dvb_frontend = adap->fe[0], + }; + /* Tuner enable using gpiot2_o, gpiot2_en and gpiot2_on */ ret = af9035_wr_reg_mask(d, 0xd8eb, 0x01, 0x01); if (ret < 0) @@ -1406,9 +1412,14 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) usleep_range(10000, 50000); /* attach tuner */ - fe = dvb_attach(fc2580_attach, adap->fe[0], - &d->i2c_adap, &af9035_fc2580_config); + ret = af9035_add_i2c_dev(d, "fc2580", 0x56, &fc2580_pdata, + &d->i2c_adap); + if (ret) + goto err; + + fe = adap->fe[0]; break; + } case AF9033_TUNER_FC0012: /* * AF9035 gpiot2 = FC0012 enable @@ -1569,6 +1580,7 @@ static int it930x_tuner_attach(struct dvb_usb_adapter *adap) memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = adap->fe[0]; + si2157_config.if_port = 1; ret = af9035_add_i2c_dev(d, "si2157", 0x63, &si2157_config, state->i2c_adapter_demod); @@ -1611,6 +1623,8 @@ static int af9035_tuner_detach(struct dvb_usb_adapter *adap) dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id); switch (state->af9033_config[adap->id].tuner) { + case AF9033_TUNER_TUA9001: + case AF9033_TUNER_FC2580: case AF9033_TUNER_IT9135_38: case AF9033_TUNER_IT9135_51: case AF9033_TUNER_IT9135_52: @@ -2021,6 +2035,9 @@ static const struct usb_device_id af9035_id_table[] = { &af9035_props, "Asus U3100Mini Plus", NULL) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00aa, &af9035_props, "TerraTec Cinergy T Stick (rev. 2)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, 0x0337, + &af9035_props, "AVerMedia HD Volar (A867)", NULL) }, + /* IT9135 devices */ { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135, &af9035_props, "ITE 9135 Generic", RC_MAP_IT913X_V1) }, @@ -2046,9 +2063,6 @@ static const struct usb_device_id af9035_id_table[] = { { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2, &af9035_props, "Digital Dual TV Receiver CTVDIGDUAL_V2", RC_MAP_IT913X_V1) }, - /* IT930x devices */ - { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9303, - &it930x_props, "ITE 9303 Generic", NULL) }, /* XXX: that same ID [0ccd:0099] is used by af9015 driver too */ { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x0099, &af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)", @@ -2061,6 +2075,10 @@ static const struct usb_device_id af9035_id_table[] = { &af9035_props, "PCTV AndroiDTV (78e)", RC_MAP_IT913X_V1) }, { DVB_USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_79E, &af9035_props, "PCTV microStick (79e)", RC_MAP_IT913X_V2) }, + + /* IT930x devices */ + { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9303, + &it930x_props, "ITE 9303 Generic", NULL) }, { } }; MODULE_DEVICE_TABLE(usb, af9035_id_table); diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c index cdf59bc..0376c09 100644 --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c @@ -45,9 +45,9 @@ struct dvbsky_state { /* fe hook functions*/ int (*fe_set_voltage)(struct dvb_frontend *fe, - fe_sec_voltage_t voltage); + enum fe_sec_voltage voltage); int (*fe_read_status)(struct dvb_frontend *fe, - fe_status_t *status); + enum fe_status *status); }; static int dvbsky_usb_generic_rw(struct dvb_usb_device *d, @@ -237,7 +237,7 @@ static int dvbsky_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) #endif static int dvbsky_usb_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct dvb_usb_device *d = fe_to_d(fe); struct dvbsky_state *state = d_to_priv(d); @@ -277,7 +277,8 @@ static int dvbsky_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6]) return 0; } -static int dvbsky_usb_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int dvbsky_usb_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct dvb_usb_device *d = fe_to_d(fe); struct dvbsky_state *state = d_to_priv(d); @@ -331,6 +332,7 @@ static int dvbsky_s960_attach(struct dvb_usb_adapter *adap) /* attach tuner */ ts2020_config.fe = adap->fe[0]; + ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm; strlcpy(info.type, "ts2020", I2C_NAME_SIZE); info.addr = 0x60; info.platform_data = &ts2020_config; @@ -368,7 +370,7 @@ fail_attach: } static int dvbsky_usb_ci_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct dvb_usb_device *d = fe_to_d(fe); struct dvbsky_state *state = d_to_priv(d); @@ -453,6 +455,7 @@ static int dvbsky_s960c_attach(struct dvb_usb_adapter *adap) /* attach tuner */ ts2020_config.fe = adap->fe[0]; + ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm; strlcpy(info.type, "ts2020", I2C_NAME_SIZE); info.addr = 0x60; info.platform_data = &ts2020_config; @@ -549,6 +552,7 @@ static int dvbsky_t680c_attach(struct dvb_usb_adapter *adap) /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = adap->fe[0]; + si2157_config.if_port = 1; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2157", I2C_NAME_SIZE); info.addr = 0x60; @@ -615,7 +619,8 @@ static int dvbsky_t330_attach(struct dvb_usb_adapter *adap) memset(&si2168_config, 0, sizeof(si2168_config)); si2168_config.i2c_adapter = &i2c_adapter; si2168_config.fe = &adap->fe[0]; - si2168_config.ts_mode = SI2168_TS_PARALLEL | 0x40; + si2168_config.ts_mode = SI2168_TS_PARALLEL; + si2168_config.ts_clock_gapped = true; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2168", I2C_NAME_SIZE); info.addr = 0x64; @@ -632,6 +637,7 @@ static int dvbsky_t330_attach(struct dvb_usb_adapter *adap) /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = adap->fe[0]; + si2157_config.if_port = 1; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2157", I2C_NAME_SIZE); info.addr = 0x60; diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index 5de6f7c..4cc55b3 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -126,7 +126,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); struct lme2510_state { unsigned long int_urb_due; - fe_status_t lock_status; + enum fe_status lock_status; u8 id; u8 tuner_config; u8 signal_level; @@ -144,12 +144,12 @@ struct lme2510_state { struct urb *lme_urb; void *usb_buffer; /* Frontend original calls */ - int (*fe_read_status)(struct dvb_frontend *, fe_status_t *); + int (*fe_read_status)(struct dvb_frontend *, enum fe_status *); int (*fe_read_signal_strength)(struct dvb_frontend *, u16 *); int (*fe_read_snr)(struct dvb_frontend *, u16 *); int (*fe_read_ber)(struct dvb_frontend *, u32 *); int (*fe_read_ucblocks)(struct dvb_frontend *, u32 *); - int (*fe_set_voltage)(struct dvb_frontend *, fe_sec_voltage_t); + int (*fe_set_voltage)(struct dvb_frontend *, enum fe_sec_voltage); u8 dvb_usb_lme2510_firmware; }; @@ -257,6 +257,62 @@ static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out) return ret; } +/* Convert range from 0x00-0xff to 0x0000-0xffff */ +#define reg_to_16bits(x) ((x) | ((x) << 8)) + +static void lme2510_update_stats(struct dvb_usb_adapter *adap) +{ + struct lme2510_state *st = adap_to_priv(adap); + struct dvb_frontend *fe = adap->fe[0]; + struct dtv_frontend_properties *c; + u32 s_tmp = 0, c_tmp = 0; + + if (!fe) + return; + + c = &fe->dtv_property_cache; + + c->block_count.len = 1; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.len = 1; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + + if (st->i2c_talk_onoff) { + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return; + } + + switch (st->tuner_config) { + case TUNER_LG: + s_tmp = reg_to_16bits(0xff - st->signal_level); + c_tmp = reg_to_16bits(0xff - st->signal_sn); + break; + case TUNER_S7395: + case TUNER_S0194: + s_tmp = 0xffff - (((st->signal_level * 2) << 8) * 5 / 4); + c_tmp = reg_to_16bits((0xff - st->signal_sn - 0xa1) * 3); + break; + case TUNER_RS2000: + s_tmp = reg_to_16bits(st->signal_level); + c_tmp = reg_to_16bits(st->signal_sn); + } + + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_RELATIVE; + c->strength.stat[0].uvalue = (u64)s_tmp; + + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_RELATIVE; + c->cnr.stat[0].uvalue = (u64)c_tmp; +} + static void lme2510_int_response(struct urb *lme_urb) { struct dvb_usb_adapter *adap = lme_urb->context; @@ -337,6 +393,8 @@ static void lme2510_int_response(struct urb *lme_urb) if (!signal_lock) st->lock_status &= ~FE_HAS_LOCK; + lme2510_update_stats(adap); + debug_data_snipet(5, "INT Remote data snipet in", ibuf); break; case 0xcc: @@ -799,10 +857,11 @@ static struct m88rs2000_config m88rs2000_config = { static struct ts2020_config ts2020_config = { .tuner_address = 0x60, .clk_out_div = 7, + .dont_poll = true }; static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct dvb_usb_device *d = fe_to_d(fe); struct lme2510_state *st = fe_to_priv(fe); @@ -837,7 +896,7 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, return (ret < 0) ? -ENODEV : 0; } -static int dm04_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int dm04_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct dvb_usb_device *d = fe_to_d(fe); struct lme2510_state *st = d->priv; @@ -871,56 +930,45 @@ static int dm04_read_status(struct dvb_frontend *fe, fe_status_t *status) *status = st->lock_status; - if (!(*status & FE_HAS_LOCK)) + if (!(*status & FE_HAS_LOCK)) { + struct dvb_usb_adapter *adap = fe_to_adap(fe); + st->i2c_talk_onoff = 1; + lme2510_update_stats(adap); + } + return ret; } static int dm04_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct lme2510_state *st = fe_to_priv(fe); if (st->fe_read_signal_strength && !st->stream_on) return st->fe_read_signal_strength(fe, strength); - switch (st->tuner_config) { - case TUNER_LG: - *strength = 0xff - st->signal_level; - *strength |= *strength << 8; - break; - /* fall through */ - case TUNER_S7395: - case TUNER_S0194: - *strength = 0xffff - (((st->signal_level * 2) << 8) * 5 / 4); - break; - case TUNER_RS2000: - *strength = (u16)((u32)st->signal_level * 0xffff / 0xff); - } + if (c->strength.stat[0].scale == FE_SCALE_RELATIVE) + *strength = (u16)c->strength.stat[0].uvalue; + else + *strength = 0; return 0; } static int dm04_read_snr(struct dvb_frontend *fe, u16 *snr) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct lme2510_state *st = fe_to_priv(fe); if (st->fe_read_snr && !st->stream_on) return st->fe_read_snr(fe, snr); - switch (st->tuner_config) { - case TUNER_LG: - *snr = 0xff - st->signal_sn; - *snr |= *snr << 8; - break; - /* fall through */ - case TUNER_S7395: - case TUNER_S0194: - *snr = (u16)((0xff - st->signal_sn - 0xa1) * 3) << 8; - break; - case TUNER_RS2000: - *snr = (u16)((u32)st->signal_sn * 0xffff / 0x7f); - } + if (c->cnr.stat[0].scale == FE_SCALE_RELATIVE) + *snr = (u16)c->cnr.stat[0].uvalue; + else + *snr = 0; return 0; } diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c index ecefa5c..ea37536 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c @@ -72,7 +72,7 @@ int mxl111sf_demod_program_regs(struct mxl111sf_demod_state *state, static int mxl1x1sf_demod_get_tps_code_rate(struct mxl111sf_demod_state *state, - fe_code_rate_t *code_rate) + enum fe_code_rate *code_rate) { u8 val; int ret = mxl111sf_demod_read_reg(state, V6_CODE_RATE_TPS_REG, &val); @@ -103,7 +103,7 @@ fail: static int mxl1x1sf_demod_get_tps_modulation(struct mxl111sf_demod_state *state, - fe_modulation_t *modulation) + enum fe_modulation *modulation) { u8 val; int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val); @@ -128,7 +128,7 @@ fail: static int mxl1x1sf_demod_get_tps_guard_fft_mode(struct mxl111sf_demod_state *state, - fe_transmit_mode_t *fft_mode) + enum fe_transmit_mode *fft_mode) { u8 val; int ret = mxl111sf_demod_read_reg(state, V6_MODE_TPS_REG, &val); @@ -153,7 +153,7 @@ fail: static int mxl1x1sf_demod_get_tps_guard_interval(struct mxl111sf_demod_state *state, - fe_guard_interval_t *guard) + enum fe_guard_interval *guard) { u8 val; int ret = mxl111sf_demod_read_reg(state, V6_CP_TPS_REG, &val); @@ -181,7 +181,7 @@ fail: static int mxl1x1sf_demod_get_tps_hierarchy(struct mxl111sf_demod_state *state, - fe_hierarchy_t *hierarchy) + enum fe_hierarchy *hierarchy) { u8 val; int ret = mxl111sf_demod_read_reg(state, V6_TPS_HIERACHY_REG, &val); @@ -441,7 +441,7 @@ fail: } static int mxl111sf_demod_read_status(struct dvb_frontend *fe, - fe_status_t *status) + enum fe_status *status) { struct mxl111sf_demod_state *state = fe->demodulator_priv; int ret, locked, cr_lock, sync_lock, fec_lock; @@ -480,7 +480,7 @@ static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength) { struct mxl111sf_demod_state *state = fe->demodulator_priv; - fe_modulation_t modulation; + enum fe_modulation modulation; u16 snr; mxl111sf_demod_calc_snr(state, &snr); diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 895441f..c3cac4c 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -217,7 +217,7 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], req.data = &msg[0].buf[1]; ret = rtl28xxu_ctrl_msg(d, &req); } - } else if (msg[0].len < 23) { + } else if ((msg[0].len < 23) && (!dev->new_i2c_write)) { /* method 2 - old I2C */ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); req.index = CMD_I2C_WR; @@ -232,8 +232,14 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], req.data = msg[0].buf; ret = rtl28xxu_ctrl_msg(d, &req); } + } else if (num == 1 && (msg[0].flags & I2C_M_RD)) { + req.value = (msg[0].addr << 1); + req.index = CMD_I2C_DA_RD; + req.size = msg[0].len; + req.data = msg[0].buf; + ret = rtl28xxu_ctrl_msg(d, &req); } else { - ret = -EINVAL; + ret = -EOPNOTSUPP; } err_mutex_unlock: @@ -357,6 +363,8 @@ static int rtl2832u_read_config(struct dvb_usb_device *d) struct rtl28xxu_req req_r828d = {0x0074, CMD_I2C_RD, 1, buf}; struct rtl28xxu_req req_mn88472 = {0xff38, CMD_I2C_RD, 1, buf}; struct rtl28xxu_req req_mn88473 = {0xff38, CMD_I2C_RD, 1, buf}; + struct rtl28xxu_req req_si2157 = {0x00c0, CMD_I2C_RD, 1, buf}; + struct rtl28xxu_req req_si2168 = {0x00c8, CMD_I2C_RD, 1, buf}; dev_dbg(&d->intf->dev, "\n"); @@ -477,6 +485,35 @@ static int rtl2832u_read_config(struct dvb_usb_device *d) goto tuner_found; } + /* GPIO0 and GPIO5 to reset Si2157/Si2168 tuner and demod */ + ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x00, 0x21); + if (ret) + goto err; + + ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x00, 0x21); + if (ret) + goto err; + + msleep(50); + + ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x21, 0x21); + if (ret) + goto err; + + ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x21, 0x21); + if (ret) + goto err; + + msleep(50); + + /* check Si2157 ID register; reg=c0 val=80 */ + ret = rtl28xxu_ctrl_msg(d, &req_si2157); + if (ret == 0 && ((buf[0] & 0x80) == 0x80)) { + dev->tuner = TUNER_RTL2832_SI2157; + dev->tuner_name = "SI2157"; + goto tuner_found; + } + tuner_found: dev_dbg(&d->intf->dev, "tuner=%s\n", dev->tuner_name); @@ -510,6 +547,15 @@ tuner_found: goto demod_found; } } + if (dev->tuner == TUNER_RTL2832_SI2157) { + /* check Si2168 ID register; reg=c8 val=80 */ + ret = rtl28xxu_ctrl_msg(d, &req_si2168); + if (ret == 0 && ((buf[0] & 0x80) == 0x80)) { + dev_dbg(&d->intf->dev, "Si2168 found\n"); + dev->slave_demod = SLAVE_DEMOD_SI2168; + goto demod_found; + } + } demod_found: /* close demod I2C gate */ @@ -643,6 +689,11 @@ err: return ret; } +static const struct rtl2832_platform_data rtl2832_fc2580_platform_data = { + .clk = 28800000, + .tuner = TUNER_RTL2832_FC2580, +}; + static const struct rtl2832_platform_data rtl2832_fc0012_platform_data = { .clk = 28800000, .tuner = TUNER_RTL2832_FC0012 @@ -668,6 +719,11 @@ static const struct rtl2832_platform_data rtl2832_r820t_platform_data = { .tuner = TUNER_RTL2832_R820T, }; +static const struct rtl2832_platform_data rtl2832_si2157_platform_data = { + .clk = 28800000, + .tuner = TUNER_RTL2832_SI2157, +}; + static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d, int cmd, int arg) { @@ -804,8 +860,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) *pdata = rtl2832_fc0013_platform_data; break; case TUNER_RTL2832_FC2580: - /* FIXME: do not abuse fc0012 settings */ - *pdata = rtl2832_fc0012_platform_data; + *pdata = rtl2832_fc2580_platform_data; break; case TUNER_RTL2832_TUA9001: *pdata = rtl2832_tua9001_platform_data; @@ -817,6 +872,9 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) case TUNER_RTL2832_R828D: *pdata = rtl2832_r820t_platform_data; break; + case TUNER_RTL2832_SI2157: + *pdata = rtl2832_si2157_platform_data; + break; default: dev_err(&d->intf->dev, "unknown tuner %s\n", dev->tuner_name); ret = -ENODEV; @@ -884,7 +942,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) } dev->i2c_client_slave_demod = client; - } else { + } else if (dev->slave_demod == SLAVE_DEMOD_MN88473) { struct mn88473_config mn88473_config = {}; mn88473_config.fe = &adap->fe[1]; @@ -906,9 +964,37 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) } dev->i2c_client_slave_demod = client; + } else { + struct si2168_config si2168_config = {}; + struct i2c_adapter *adapter; + + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &adap->fe[1]; + si2168_config.ts_mode = SI2168_TS_SERIAL; + si2168_config.ts_clock_inv = false; + si2168_config.ts_clock_gapped = true; + strlcpy(info.type, "si2168", I2C_NAME_SIZE); + info.addr = 0x64; + info.platform_data = &si2168_config; + request_module(info.type); + client = i2c_new_device(&d->i2c_adap, &info); + if (client == NULL || client->dev.driver == NULL) { + dev->slave_demod = SLAVE_DEMOD_NONE; + goto err_slave_demod_failed; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + dev->slave_demod = SLAVE_DEMOD_NONE; + goto err_slave_demod_failed; + } + + dev->i2c_client_slave_demod = client; + + /* for Si2168 devices use only new I2C write method */ + dev->new_i2c_write = true; } } - return 0; err_slave_demod_failed: err: @@ -1018,15 +1104,6 @@ err: return ret; } -static const struct fc2580_config rtl2832u_fc2580_config = { - .i2c_addr = 0x56, - .clock = 16384000, -}; - -static struct tua9001_config rtl2832u_tua9001_config = { - .i2c_addr = 0x60, -}; - static const struct fc0012_config rtl2832u_fc0012_config = { .i2c_address = 0x63, /* 0xc6 >> 1 */ .xtal_freq = FC_XTAL_28_8_MHZ, @@ -1105,12 +1182,34 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) subdev = i2c_get_clientdata(client); } break; - case TUNER_RTL2832_FC2580: - fe = dvb_attach(fc2580_attach, adap->fe[0], - dev->demod_i2c_adapter, - &rtl2832u_fc2580_config); + case TUNER_RTL2832_FC2580: { + struct fc2580_platform_data fc2580_pdata = { + .dvb_frontend = adap->fe[0], + }; + struct i2c_board_info board_info = {}; + + strlcpy(board_info.type, "fc2580", I2C_NAME_SIZE); + board_info.addr = 0x56; + board_info.platform_data = &fc2580_pdata; + request_module("fc2580"); + client = i2c_new_device(dev->demod_i2c_adapter, + &board_info); + if (client == NULL || client->dev.driver == NULL) + break; + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + break; + } + dev->i2c_client_tuner = client; + subdev = fc2580_pdata.get_v4l2_subdev(client); + } break; - case TUNER_RTL2832_TUA9001: + case TUNER_RTL2832_TUA9001: { + struct tua9001_platform_data tua9001_pdata = { + .dvb_frontend = adap->fe[0], + }; + struct i2c_board_info board_info = {}; + /* enable GPIO1 and GPIO4 as output */ ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x12); if (ret) @@ -1120,10 +1219,20 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) if (ret) goto err; - fe = dvb_attach(tua9001_attach, adap->fe[0], - dev->demod_i2c_adapter, - &rtl2832u_tua9001_config); + strlcpy(board_info.type, "tua9001", I2C_NAME_SIZE); + board_info.addr = 0x60; + board_info.platform_data = &tua9001_pdata; + request_module("tua9001"); + client = i2c_new_device(dev->demod_i2c_adapter, &board_info); + if (client == NULL || client->dev.driver == NULL) + break; + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + break; + } + dev->i2c_client_tuner = client; break; + } case TUNER_RTL2832_R820T: fe = dvb_attach(r820t_attach, adap->fe[0], dev->demod_i2c_adapter, @@ -1148,6 +1257,39 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) adap->fe[1]->ops.tuner_ops.get_rf_strength; } break; + case TUNER_RTL2832_SI2157: { + struct si2157_config si2157_config = { + .fe = adap->fe[0], + .if_port = 0, + .inversion = false, + }; + + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &si2157_config; + request_module(info.type); + client = i2c_new_device(&d->i2c_adap, &info); + if (client == NULL || client->dev.driver == NULL) + break; + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + break; + } + + dev->i2c_client_tuner = client; + subdev = i2c_get_clientdata(client); + + /* copy tuner ops for 2nd FE as tuner is shared */ + if (adap->fe[1]) { + adap->fe[1]->tuner_priv = + adap->fe[0]->tuner_priv; + memcpy(&adap->fe[1]->ops.tuner_ops, + &adap->fe[0]->ops.tuner_ops, + sizeof(struct dvb_tuner_ops)); + } + } + break; default: dev_err(&d->intf->dev, "unknown tuner %d\n", dev->tuner); } @@ -1158,6 +1300,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) /* register SDR */ switch (dev->tuner) { + case TUNER_RTL2832_FC2580: case TUNER_RTL2832_FC0012: case TUNER_RTL2832_FC0013: case TUNER_RTL2832_E4000: @@ -1178,7 +1321,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) "rtl2832_sdr", PLATFORM_DEVID_AUTO, &pdata, sizeof(pdata)); - if (pdev == NULL || pdev->dev.driver == NULL) + if (IS_ERR(pdev) || pdev->dev.driver == NULL) break; dev->platform_device_sdr = pdev; break; @@ -1764,6 +1907,8 @@ static const struct usb_device_id rtl28xxu_id_table[] = { /* RTL2832P devices: */ { DVB_USB_DEVICE(USB_VID_HANFTEK, 0x0131, &rtl28xxu_props, "Astrometa DVB-T2", NULL) }, + { DVB_USB_DEVICE(0x5654, 0xca42, + &rtl28xxu_props, "GoTView MasterHD 3", NULL) }, { } }; MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table); diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h index 1b5d7ff..9f6115a 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h @@ -41,6 +41,8 @@ #include "fc2580.h" #include "tua9001.h" #include "r820t.h" +#include "si2168.h" +#include "si2157.h" /* * USB commands @@ -76,6 +78,7 @@ struct rtl28xxu_dev { u8 page; /* integrated demod active register page */ struct i2c_adapter *demod_i2c_adapter; bool rc_active; + bool new_i2c_write; struct i2c_client *i2c_client_demod; struct i2c_client *i2c_client_tuner; struct i2c_client *i2c_client_slave_demod; @@ -83,6 +86,7 @@ struct rtl28xxu_dev { #define SLAVE_DEMOD_NONE 0 #define SLAVE_DEMOD_MN88472 1 #define SLAVE_DEMOD_MN88473 2 + #define SLAVE_DEMOD_SI2168 3 unsigned int slave_demod:2; union { struct rtl2830_platform_data rtl2830_platform_data; @@ -116,6 +120,7 @@ enum rtl28xxu_tuner { TUNER_RTL2832_FC0013, TUNER_RTL2832_R820T, TUNER_RTL2832_R828D, + TUNER_RTL2832_SI2157, }; struct rtl28xxu_req { diff --git a/drivers/media/usb/dvb-usb/af9005-fe.c b/drivers/media/usb/dvb-usb/af9005-fe.c index 740f3f4..ac97075 100644 --- a/drivers/media/usb/dvb-usb/af9005-fe.c +++ b/drivers/media/usb/dvb-usb/af9005-fe.c @@ -29,7 +29,7 @@ struct af9005_fe_state { struct dvb_usb_device *d; - fe_status_t stat; + enum fe_status stat; /* retraining parameters */ u32 original_fcw; @@ -437,7 +437,8 @@ static int af9005_fe_refresh_state(struct dvb_frontend *fe) return 0; } -static int af9005_fe_read_status(struct dvb_frontend *fe, fe_status_t * stat) +static int af9005_fe_read_status(struct dvb_frontend *fe, + enum fe_status *stat) { struct af9005_fe_state *state = fe->demodulator_priv; u8 temp; @@ -481,7 +482,7 @@ static int af9005_fe_read_status(struct dvb_frontend *fe, fe_status_t * stat) return ret; if (temp != state->strong) { deb_info("adjust for strong signal %d\n", temp); - state->strong = temp; + state->strong = temp; } return 0; } diff --git a/drivers/media/usb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c index 0df52ab..92e47d6 100644 --- a/drivers/media/usb/dvb-usb/az6027.c +++ b/drivers/media/usb/dvb-usb/az6027.c @@ -778,7 +778,8 @@ static int az6027_read_mac_addr(struct dvb_usb_device *d, u8 mac[6]) } */ -static int az6027_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int az6027_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { u8 buf; diff --git a/drivers/media/usb/dvb-usb/cinergyT2-fe.c b/drivers/media/usb/dvb-usb/cinergyT2-fe.c index c890fe4..b3ec743 100644 --- a/drivers/media/usb/dvb-usb/cinergyT2-fe.c +++ b/drivers/media/usb/dvb-usb/cinergyT2-fe.c @@ -142,7 +142,7 @@ struct cinergyt2_fe_state { }; static int cinergyt2_fe_read_status(struct dvb_frontend *fe, - fe_status_t *status) + enum fe_status *status) { struct cinergyt2_fe_state *state = fe->demodulator_priv; struct dvbt_get_status_msg result; diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index ffc3704..ab71511 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -1350,6 +1350,7 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap) /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = adap->fe_adap[0].fe; + si2157_config.if_port = 1; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2157", I2C_NAME_SIZE); info.addr = 0x60; diff --git a/drivers/media/usb/dvb-usb/dib0700.h b/drivers/media/usb/dvb-usb/dib0700.h index 927617d..8fd8f5b 100644 --- a/drivers/media/usb/dvb-usb/dib0700.h +++ b/drivers/media/usb/dvb-usb/dib0700.h @@ -48,7 +48,7 @@ struct dib0700_state { u8 disable_streaming_master_mode; u32 fw_version; u32 nb_packet_buffer_size; - int (*read_status)(struct dvb_frontend *, fe_status_t *); + int (*read_status)(struct dvb_frontend *, enum fe_status *); int (*sleep)(struct dvb_frontend* fe); u8 buf[255]; }; diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c index 2b40393..0d248ce 100644 --- a/drivers/media/usb/dvb-usb/dib0700_core.c +++ b/drivers/media/usb/dvb-usb/dib0700_core.c @@ -655,10 +655,20 @@ out: struct dib0700_rc_response { u8 report_id; u8 data_state; - u8 system; - u8 not_system; - u8 data; - u8 not_data; + union { + struct { + u8 system; + u8 not_system; + u8 data; + u8 not_data; + } nec; + struct { + u8 not_used; + u8 system; + u8 data; + u8 not_data; + } rc5; + }; }; #define RC_MSG_SIZE_V1_20 6 @@ -694,8 +704,8 @@ static void dib0700_rc_urb_completion(struct urb *purb) deb_data("IR ID = %02X state = %02X System = %02X %02X Cmd = %02X %02X (len %d)\n", poll_reply->report_id, poll_reply->data_state, - poll_reply->system, poll_reply->not_system, - poll_reply->data, poll_reply->not_data, + poll_reply->nec.system, poll_reply->nec.not_system, + poll_reply->nec.data, poll_reply->nec.not_data, purb->actual_length); switch (d->props.rc.core.protocol) { @@ -704,30 +714,30 @@ static void dib0700_rc_urb_completion(struct urb *purb) toggle = 0; /* NEC protocol sends repeat code as 0 0 0 FF */ - if (poll_reply->system == 0x00 && - poll_reply->not_system == 0x00 && - poll_reply->data == 0x00 && - poll_reply->not_data == 0xff) { + if (poll_reply->nec.system == 0x00 && + poll_reply->nec.not_system == 0x00 && + poll_reply->nec.data == 0x00 && + poll_reply->nec.not_data == 0xff) { poll_reply->data_state = 2; break; } - if ((poll_reply->data ^ poll_reply->not_data) != 0xff) { + if ((poll_reply->nec.data ^ poll_reply->nec.not_data) != 0xff) { deb_data("NEC32 protocol\n"); - keycode = RC_SCANCODE_NEC32(poll_reply->system << 24 | - poll_reply->not_system << 16 | - poll_reply->data << 8 | - poll_reply->not_data); - } else if ((poll_reply->system ^ poll_reply->not_system) != 0xff) { + keycode = RC_SCANCODE_NEC32(poll_reply->nec.system << 24 | + poll_reply->nec.not_system << 16 | + poll_reply->nec.data << 8 | + poll_reply->nec.not_data); + } else if ((poll_reply->nec.system ^ poll_reply->nec.not_system) != 0xff) { deb_data("NEC extended protocol\n"); - keycode = RC_SCANCODE_NECX(poll_reply->system << 8 | - poll_reply->not_system, - poll_reply->data); + keycode = RC_SCANCODE_NECX(poll_reply->nec.system << 8 | + poll_reply->nec.not_system, + poll_reply->nec.data); } else { deb_data("NEC normal protocol\n"); - keycode = RC_SCANCODE_NEC(poll_reply->system, - poll_reply->data); + keycode = RC_SCANCODE_NEC(poll_reply->nec.system, + poll_reply->nec.data); } break; @@ -735,19 +745,19 @@ static void dib0700_rc_urb_completion(struct urb *purb) deb_data("RC5 protocol\n"); protocol = RC_TYPE_RC5; toggle = poll_reply->report_id; - keycode = RC_SCANCODE_RC5(poll_reply->system, poll_reply->data); + keycode = RC_SCANCODE_RC5(poll_reply->rc5.system, poll_reply->rc5.data); + + if ((poll_reply->rc5.data ^ poll_reply->rc5.not_data) != 0xff) { + /* Key failed integrity check */ + err("key failed integrity check: %02x %02x %02x %02x", + poll_reply->rc5.not_used, poll_reply->rc5.system, + poll_reply->rc5.data, poll_reply->rc5.not_data); + goto resubmit; + } break; } - if ((poll_reply->data + poll_reply->not_data) != 0xff) { - /* Key failed integrity check */ - err("key failed integrity check: %02x %02x %02x %02x", - poll_reply->system, poll_reply->not_system, - poll_reply->data, poll_reply->not_data); - goto resubmit; - } - rc_keydown(d->rc_dev, protocol, keycode, toggle); resubmit: diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index d7d55a2..7ed4964 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -861,22 +861,22 @@ static int dib7770_set_param_override(struct dvb_frontend *fe) struct dvb_usb_adapter *adap = fe->dvb->priv; struct dib0700_adapter_state *state = adap->priv; - u16 offset; - u8 band = BAND_OF_FREQUENCY(p->frequency/1000); - switch (band) { - case BAND_VHF: - state->dib7000p_ops.set_gpio(fe, 0, 0, 1); - offset = 850; - break; - case BAND_UHF: - default: - state->dib7000p_ops.set_gpio(fe, 0, 0, 0); - offset = 250; - break; - } - deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); - state->dib7000p_ops.set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); - return state->set_param_save(fe); + u16 offset; + u8 band = BAND_OF_FREQUENCY(p->frequency/1000); + switch (band) { + case BAND_VHF: + state->dib7000p_ops.set_gpio(fe, 0, 0, 1); + offset = 850; + break; + case BAND_UHF: + default: + state->dib7000p_ops.set_gpio(fe, 0, 0, 0); + offset = 250; + break; + } + deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); + state->dib7000p_ops.set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); + return state->set_param_save(fe); } static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap) @@ -3309,7 +3309,7 @@ static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) } static int novatd_read_status_override(struct dvb_frontend *fe, - fe_status_t *stat) + enum fe_status *stat) { struct dvb_usb_adapter *adap = fe->dvb->priv; struct dvb_usb_device *dev = adap->dev; @@ -3821,6 +3821,10 @@ MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); } \ } +#define DIB0700_NUM_FRONTENDS(n) \ + .num_frontends = n, \ + .size_of_priv = sizeof(struct dib0700_adapter_state) + struct dvb_usb_device_properties dib0700_devices[] = { { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -3828,7 +3832,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -3839,7 +3843,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = sizeof(struct dib0700_adapter_state), }, }, @@ -3893,7 +3896,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 2, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .frontend_attach = bristol_frontend_attach, .tuner_attach = bristol_tuner_attach, @@ -3901,7 +3904,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, }, { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .frontend_attach = bristol_frontend_attach, .tuner_attach = bristol_tuner_attach, @@ -3933,7 +3936,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 2, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -3945,7 +3948,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, }, { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -3998,7 +4001,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -4043,7 +4046,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -4054,7 +4057,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = sizeof(struct dib0700_adapter_state), }, }, @@ -4125,7 +4127,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -4136,7 +4138,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = sizeof(struct dib0700_adapter_state), }, }, @@ -4171,7 +4172,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 2, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -4182,9 +4183,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = sizeof(struct dib0700_adapter_state), }, { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -4195,7 +4195,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x03), }}, - .size_of_priv = sizeof(struct dib0700_adapter_state), } }, @@ -4230,7 +4229,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 2, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -4241,9 +4240,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = sizeof(struct dib0700_adapter_state), }, { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -4254,7 +4252,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x03), }}, - .size_of_priv = sizeof(struct dib0700_adapter_state), } }, @@ -4298,7 +4295,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 2, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -4309,9 +4306,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = sizeof(struct dib0700_adapter_state), }, { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -4322,7 +4318,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x03), }}, - .size_of_priv = sizeof(struct dib0700_adapter_state), } }, @@ -4349,7 +4344,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -4360,8 +4355,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = sizeof(struct - dib0700_adapter_state), }, }, @@ -4419,15 +4412,13 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .frontend_attach = s5h1411_frontend_attach, .tuner_attach = xc5000_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = sizeof(struct - dib0700_adapter_state), }, }, @@ -4457,15 +4448,13 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .frontend_attach = lgdt3305_frontend_attach, .tuner_attach = mxl5007t_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = sizeof(struct - dib0700_adapter_state), }, }, @@ -4485,7 +4474,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -4496,8 +4485,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), }, }, @@ -4537,7 +4524,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -4548,8 +4535,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), }, }, @@ -4583,7 +4568,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 2, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -4594,11 +4579,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), }, { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -4609,8 +4592,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x03), }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), }, }, @@ -4636,7 +4617,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -4648,8 +4629,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), }, }, @@ -4675,7 +4654,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -4687,8 +4666,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), }, }, @@ -4714,7 +4691,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -4726,8 +4703,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), }, }, @@ -4753,7 +4728,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -4765,8 +4740,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), }, }, @@ -4792,7 +4765,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -4804,8 +4777,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), }, }, @@ -4831,7 +4802,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 2, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -4843,11 +4814,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x03), }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), }, { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -4859,8 +4828,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), }, }, @@ -4886,15 +4853,13 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .frontend_attach = pctv340e_frontend_attach, .tuner_attach = xc4000_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }}, - .size_of_priv = sizeof(struct - dib0700_adapter_state), }, }, @@ -4923,7 +4888,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -4935,9 +4900,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x03), } }, - - .size_of_priv = - sizeof(struct dib0700_adapter_state), }, }, @@ -4963,7 +4925,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { - .num_frontends = 1, + DIB0700_NUM_FRONTENDS(1), .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -4976,9 +4938,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { DIB0700_DEFAULT_STREAMING_CONFIG(0x02), } }, - - .size_of_priv = - sizeof(struct dib0700_adapter_state), }, }, diff --git a/drivers/media/usb/dvb-usb/dtt200u-fe.c b/drivers/media/usb/dvb-usb/dtt200u-fe.c index 3d81daa..8637ad1 100644 --- a/drivers/media/usb/dvb-usb/dtt200u-fe.c +++ b/drivers/media/usb/dvb-usb/dtt200u-fe.c @@ -14,13 +14,14 @@ struct dtt200u_fe_state { struct dvb_usb_device *d; - fe_status_t stat; + enum fe_status stat; struct dtv_frontend_properties fep; struct dvb_frontend frontend; }; -static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat) +static int dtt200u_fe_read_status(struct dvb_frontend *fe, + enum fe_status *stat) { struct dtt200u_fe_state *state = fe->demodulator_priv; u8 st = GET_TUNE_STATUS, b[3]; @@ -105,7 +106,7 @@ static int dtt200u_fe_set_frontend(struct dvb_frontend *fe) struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct dtt200u_fe_state *state = fe->demodulator_priv; int i; - fe_status_t st; + enum fe_status st; u16 freq = fep->frequency / 250000; u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 }; diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index f1f357f..14ef25d 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -117,8 +117,13 @@ struct dw2102_state { u8 initialized; + u8 last_lock; struct i2c_client *i2c_client_tuner; - int (*old_set_voltage)(struct dvb_frontend *f, fe_sec_voltage_t v); + + /* fe hook functions*/ + int (*old_set_voltage)(struct dvb_frontend *f, enum fe_sec_voltage v); + int (*fe_read_status)(struct dvb_frontend *fe, + enum fe_status *status); }; /* debug */ @@ -437,7 +442,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i ibuf, msg[j].len + 2, DW210X_READ_MSG); memcpy(msg[j].buf, ibuf + 2, msg[j].len); - mdelay(10); + mdelay(10); } else if (((msg[j].buf[0] == 0xb0) && (msg[j].addr == 0x68)) || ((msg[j].buf[0] == 0xf7) && @@ -928,8 +933,6 @@ static int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) break; else mac[i] = ibuf[0]; - - debug_dump(mac, 6, printk); } return 0; @@ -946,7 +949,8 @@ static int su3000_identify_state(struct usb_device *udev, return 0; } -static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int dw210x_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { static u8 command_13v[] = {0x00, 0x01}; static u8 command_18v[] = {0x01, 0x01}; @@ -970,7 +974,8 @@ static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) return 0; } -static int s660_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int s660_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct dvb_usb_adapter *d = (struct dvb_usb_adapter *)(fe->dvb->priv); @@ -1001,6 +1006,24 @@ static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon) i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1); } +static int tt_s2_4600_read_status(struct dvb_frontend *fe, + enum fe_status *status) +{ + struct dvb_usb_adapter *d = + (struct dvb_usb_adapter *)(fe->dvb->priv); + struct dw2102_state *st = (struct dw2102_state *)d->dev->priv; + int ret; + + ret = st->fe_read_status(fe, status); + + /* resync slave fifo when signal change from unlock to lock */ + if ((*status & FE_HAS_LOCK) && (!st->last_lock)) + su3000_streaming_ctrl(d, 1); + + st->last_lock = (*status & FE_HAS_LOCK) ? 1 : 0; + return ret; +} + static struct stv0299_config sharp_z0194a_config = { .demod_address = 0x68, .inittab = sharp_z0194a_inittab, @@ -1553,6 +1576,12 @@ static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap) state->i2c_client_tuner = client; + /* hook fe: need to resync the slave fifo when signal locks */ + state->fe_read_status = adap->fe_adap[0].fe->ops.read_status; + adap->fe_adap[0].fe->ops.read_status = tt_s2_4600_read_status; + + state->last_lock = 0; + return 0; } @@ -1657,6 +1686,8 @@ enum dw2102_table_entry { GOTVIEW_SAT_HD, GENIATECH_T220, TECHNOTREND_S2_4600, + TEVII_S482_1, + TEVII_S482_2, }; static struct usb_device_id dw2102_table[] = { @@ -1682,6 +1713,8 @@ static struct usb_device_id dw2102_table[] = { [GENIATECH_T220] = {USB_DEVICE(0x1f4d, 0xD220)}, [TECHNOTREND_S2_4600] = {USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_4600)}, + [TEVII_S482_1] = {USB_DEVICE(0x9022, 0xd483)}, + [TEVII_S482_2] = {USB_DEVICE(0x9022, 0xd484)}, { } }; @@ -2199,12 +2232,20 @@ static struct dvb_usb_device_properties tt_s2_4600_properties = { } }, } }, - .num_device_descs = 1, + .num_device_descs = 3, .devices = { { "TechnoTrend TT-connect S2-4600", { &dw2102_table[TECHNOTREND_S2_4600], NULL }, { NULL }, }, + { "TeVii S482 (tuner 1)", + { &dw2102_table[TEVII_S482_1], NULL }, + { NULL }, + }, + { "TeVii S482 (tuner 2)", + { &dw2102_table[TEVII_S482_2], NULL }, + { NULL }, + }, } }; diff --git a/drivers/media/usb/dvb-usb/friio-fe.c b/drivers/media/usb/dvb-usb/friio-fe.c index d56f927..8ec92fb 100644 --- a/drivers/media/usb/dvb-usb/friio-fe.c +++ b/drivers/media/usb/dvb-usb/friio-fe.c @@ -210,7 +210,8 @@ error: return -EREMOTEIO; } -static int jdvbt90502_read_status(struct dvb_frontend *fe, fe_status_t *state) +static int jdvbt90502_read_status(struct dvb_frontend *fe, + enum fe_status *state) { u8 result; int ret; diff --git a/drivers/media/usb/dvb-usb/gp8psk-fe.c b/drivers/media/usb/dvb-usb/gp8psk-fe.c index 67957dd..db6eb79 100644 --- a/drivers/media/usb/dvb-usb/gp8psk-fe.c +++ b/drivers/media/usb/dvb-usb/gp8psk-fe.c @@ -51,7 +51,8 @@ static int gp8psk_fe_update_status(struct gp8psk_fe_state *st) return 0; } -static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) +static int gp8psk_fe_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct gp8psk_fe_state *st = fe->demodulator_priv; gp8psk_fe_update_status(st); @@ -236,8 +237,8 @@ static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe, return 0; } -static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe, - fe_sec_mini_cmd_t burst) +static int gp8psk_fe_send_diseqc_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd burst) { struct gp8psk_fe_state *st = fe->demodulator_priv; u8 cmd; @@ -254,7 +255,8 @@ static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe, return 0; } -static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int gp8psk_fe_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct gp8psk_fe_state* state = fe->demodulator_priv; @@ -265,7 +267,8 @@ static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) return 0; } -static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int gp8psk_fe_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct gp8psk_fe_state* state = fe->demodulator_priv; diff --git a/drivers/media/usb/dvb-usb/opera1.c b/drivers/media/usb/dvb-usb/opera1.c index 14a2119..2566d2f 100644 --- a/drivers/media/usb/dvb-usb/opera1.c +++ b/drivers/media/usb/dvb-usb/opera1.c @@ -167,7 +167,8 @@ static struct i2c_algorithm opera1_i2c_algo = { .functionality = opera1_i2c_func, }; -static int opera1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int opera1_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { static u8 command_13v[1]={0x00}; static u8 command_18v[1]={0x01}; diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c index 5801ae7..03f334d 100644 --- a/drivers/media/usb/dvb-usb/technisat-usb2.c +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c @@ -453,7 +453,7 @@ static struct stv090x_config technisat_usb2_stv090x_config; /* frontend attach */ static int technisat_usb2_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { int i; u8 gpio[3] = { 0 }; /* 0 = 2, 1 = 3, 2 = 4 */ diff --git a/drivers/media/usb/dvb-usb/vp702x-fe.c b/drivers/media/usb/dvb-usb/vp702x-fe.c index 5eab468..d361a72 100644 --- a/drivers/media/usb/dvb-usb/vp702x-fe.c +++ b/drivers/media/usb/dvb-usb/vp702x-fe.c @@ -26,8 +26,8 @@ struct vp702x_fe_state { struct dvb_frontend_ops ops; - fe_sec_voltage_t voltage; - fe_sec_tone_mode_t tone_mode; + enum fe_sec_voltage voltage; + enum fe_sec_tone_mode tone_mode; u8 lnb_buf[8]; @@ -72,7 +72,8 @@ static u8 vp702x_chksum(u8 *buf,int f, int count) return ~s+1; } -static int vp702x_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) +static int vp702x_fe_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct vp702x_fe_state *st = fe->demodulator_priv; vp702x_fe_refresh_state(st); @@ -243,13 +244,15 @@ static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe, return 0; } -static int vp702x_fe_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) +static int vp702x_fe_send_diseqc_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd burst) { deb_fe("%s\n",__func__); return 0; } -static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int vp702x_fe_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct vp702x_fe_state *st = fe->demodulator_priv; struct vp702x_device_state *dst = st->d->priv; @@ -282,8 +285,8 @@ static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) return 0; } -static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t - voltage) +static int vp702x_fe_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct vp702x_fe_state *st = fe->demodulator_priv; struct vp702x_device_state *dst = st->d->priv; diff --git a/drivers/media/usb/dvb-usb/vp702x.c b/drivers/media/usb/dvb-usb/vp702x.c index 22cf9f9..ee1e19e 100644 --- a/drivers/media/usb/dvb-usb/vp702x.c +++ b/drivers/media/usb/dvb-usb/vp702x.c @@ -259,12 +259,11 @@ static struct rc_map_table rc_map_vp702x_table[] = { /* remote control stuff (does not work with my box) */ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { +/* remove the following return to enabled remote querying */ +#if 0 u8 *key; int i; -/* remove the following return to enabled remote querying */ - return 0; - key = kmalloc(10, GFP_KERNEL); if (!key) return -ENOMEM; @@ -286,6 +285,8 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) break; } kfree(key); +#endif + return 0; } diff --git a/drivers/media/usb/dvb-usb/vp7045-fe.c b/drivers/media/usb/dvb-usb/vp7045-fe.c index b8825b1..e708afc 100644 --- a/drivers/media/usb/dvb-usb/vp7045-fe.c +++ b/drivers/media/usb/dvb-usb/vp7045-fe.c @@ -26,7 +26,8 @@ struct vp7045_fe_state { struct dvb_usb_device *d; }; -static int vp7045_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) +static int vp7045_fe_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct vp7045_fe_state *state = fe->demodulator_priv; u8 s0 = vp7045_read_reg(state->d,0x00), diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index a4b22c2..ed0b3a8 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -404,7 +404,9 @@ int em28xx_init_camera(struct em28xx *dev) .addr = client->addr, .platform_data = &camlink, }; - struct v4l2_mbus_framefmt fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; /* * FIXME: sensor supports resolutions up to 1600x1200, but @@ -425,10 +427,10 @@ int em28xx_init_camera(struct em28xx *dev) break; } - fmt.code = MEDIA_BUS_FMT_YUYV8_2X8; - fmt.width = 640; - fmt.height = 480; - v4l2_subdev_call(subdev, video, s_mbus_fmt, &fmt); + format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; + format.format.width = 640; + format.format.height = 480; + v4l2_subdev_call(subdev, pad, set_fmt, NULL, &format); /* NOTE: for UXGA=1600x1200 switch to 12MHz */ dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ; diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index a5b22c5..a382483 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -96,6 +96,7 @@ struct em28xx_dvb { int lna_gpio; struct i2c_client *i2c_client_demod; struct i2c_client *i2c_client_tuner; + struct i2c_client *i2c_client_sec; }; static inline void print_err_status(struct em28xx *dev, @@ -807,16 +808,6 @@ static struct tda18271_config em28xx_cxd2820r_tda18271_config = { .gate = TDA18271_GATE_DIGITAL, }; -static const struct tda10071_config em28xx_tda10071_config = { - .demod_i2c_addr = 0x55, /* (0xaa >> 1) */ - .tuner_i2c_addr = 0x14, - .i2c_wr_max = 64, - .ts_mode = TDA10071_TS_SERIAL, - .spec_inv = 0, - .xtal = 40444000, /* 40.444 MHz */ - .pll_multiplier = 20, -}; - static const struct a8293_config em28xx_a8293_config = { .i2c_addr = 0x08, /* (0x10 >> 1) */ }; @@ -1331,16 +1322,60 @@ static int em28xx_dvb_init(struct em28xx *dev) &dev->i2c_adap[dev->def_i2c_bus], &c3tech_duo_tda18271_config); break; - case EM28174_BOARD_PCTV_460E: - /* attach demod */ - dvb->fe[0] = dvb_attach(tda10071_attach, - &em28xx_tda10071_config, &dev->i2c_adap[dev->def_i2c_bus]); + case EM28174_BOARD_PCTV_460E: { + struct i2c_client *client; + struct i2c_board_info board_info; + struct tda10071_platform_data tda10071_pdata = {}; + struct a8293_platform_data a8293_pdata = {}; + + /* attach demod + tuner combo */ + tda10071_pdata.clk = 40444000, /* 40.444 MHz */ + tda10071_pdata.i2c_wr_max = 64, + tda10071_pdata.ts_mode = TDA10071_TS_SERIAL, + tda10071_pdata.pll_multiplier = 20, + tda10071_pdata.tuner_i2c_addr = 0x14, + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "tda10071_cx24118", I2C_NAME_SIZE); + board_info.addr = 0x55; + board_info.platform_data = &tda10071_pdata; + request_module("tda10071"); + client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); + if (client == NULL || client->dev.driver == NULL) { + result = -ENODEV; + goto out_free; + } + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + result = -ENODEV; + goto out_free; + } + dvb->fe[0] = tda10071_pdata.get_dvb_frontend(client); + dvb->i2c_client_demod = client; /* attach SEC */ - if (dvb->fe[0]) - dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus], - &em28xx_a8293_config); + a8293_pdata.dvb_frontend = dvb->fe[0]; + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "a8293", I2C_NAME_SIZE); + board_info.addr = 0x08; + board_info.platform_data = &a8293_pdata; + request_module("a8293"); + client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); + if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + dvb->i2c_client_sec = client; break; + } case EM2874_BOARD_DELOCK_61959: case EM2874_BOARD_MAXMEDIA_UB425_TC: /* attach demodulator */ @@ -1486,64 +1521,94 @@ static int em28xx_dvb_init(struct em28xx *dev) } } break; - case EM28178_BOARD_PCTV_461E: - { - /* demod I2C adapter */ - struct i2c_adapter *i2c_adapter; - struct i2c_client *client; - struct i2c_board_info info; - struct ts2020_config ts2020_config = { - }; - memset(&info, 0, sizeof(struct i2c_board_info)); - - /* attach demod */ - dvb->fe[0] = dvb_attach(m88ds3103_attach, - &pctv_461e_m88ds3103_config, - &dev->i2c_adap[dev->def_i2c_bus], - &i2c_adapter); - if (dvb->fe[0] == NULL) { - result = -ENODEV; - goto out_free; - } - - /* attach tuner */ - ts2020_config.fe = dvb->fe[0]; - strlcpy(info.type, "ts2022", I2C_NAME_SIZE); - info.addr = 0x60; - info.platform_data = &ts2020_config; - request_module("ts2020"); - client = i2c_new_device(i2c_adapter, &info); - if (client == NULL || client->dev.driver == NULL) { - dvb_frontend_detach(dvb->fe[0]); - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - dvb_frontend_detach(dvb->fe[0]); - result = -ENODEV; - goto out_free; - } + case EM28178_BOARD_PCTV_461E: { + struct i2c_client *client; + struct i2c_adapter *i2c_adapter; + struct i2c_board_info board_info; + struct m88ds3103_platform_data m88ds3103_pdata = {}; + struct ts2020_config ts2020_config = {}; + struct a8293_platform_data a8293_pdata = {}; - /* delegate signal strength measurement to tuner */ - dvb->fe[0]->ops.read_signal_strength = - dvb->fe[0]->ops.tuner_ops.get_rf_strength; + /* attach demod */ + m88ds3103_pdata.clk = 27000000; + m88ds3103_pdata.i2c_wr_max = 33; + m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL; + m88ds3103_pdata.ts_clk = 16000; + m88ds3103_pdata.ts_clk_pol = 1; + m88ds3103_pdata.agc = 0x99; + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "m88ds3103", I2C_NAME_SIZE); + board_info.addr = 0x68; + board_info.platform_data = &m88ds3103_pdata; + request_module("m88ds3103"); + client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); + if (client == NULL || client->dev.driver == NULL) { + result = -ENODEV; + goto out_free; + } + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + result = -ENODEV; + goto out_free; + } + dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(client); + i2c_adapter = m88ds3103_pdata.get_i2c_adapter(client); + dvb->i2c_client_demod = client; - /* attach SEC */ - if (!dvb_attach(a8293_attach, dvb->fe[0], - &dev->i2c_adap[dev->def_i2c_bus], - &em28xx_a8293_config)) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - dvb_frontend_detach(dvb->fe[0]); - result = -ENODEV; - goto out_free; - } + /* attach tuner */ + ts2020_config.fe = dvb->fe[0]; + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "ts2022", I2C_NAME_SIZE); + board_info.addr = 0x60; + board_info.platform_data = &ts2020_config; + request_module("ts2020"); + client = i2c_new_device(i2c_adapter, &board_info); + if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + dvb->i2c_client_tuner = client; + /* delegate signal strength measurement to tuner */ + dvb->fe[0]->ops.read_signal_strength = + dvb->fe[0]->ops.tuner_ops.get_rf_strength; - dvb->i2c_client_tuner = client; + /* attach SEC */ + a8293_pdata.dvb_frontend = dvb->fe[0]; + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "a8293", I2C_NAME_SIZE); + board_info.addr = 0x08; + board_info.platform_data = &a8293_pdata; + request_module("a8293"); + client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); + if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_tuner->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_tuner); + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; } + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + module_put(dvb->i2c_client_tuner->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_tuner); + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + dvb->i2c_client_sec = client; break; + } case EM28178_BOARD_PCTV_292E: { struct i2c_adapter *adapter; @@ -1579,6 +1644,7 @@ static int em28xx_dvb_init(struct em28xx *dev) /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = dvb->fe[0]; + si2157_config.if_port = 1; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2157", I2C_NAME_SIZE); info.addr = 0x60; @@ -1639,6 +1705,7 @@ static int em28xx_dvb_init(struct em28xx *dev) /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = dvb->fe[0]; + si2157_config.if_port = 0; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2146", I2C_NAME_SIZE); info.addr = 0x60; @@ -1727,7 +1794,6 @@ static int em28xx_dvb_fini(struct em28xx *dev) em28xx_info("Closing DVB extension\n"); dvb = dev->dvb; - client = dvb->i2c_client_tuner; em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE); @@ -1744,7 +1810,15 @@ static int em28xx_dvb_fini(struct em28xx *dev) } } + /* remove I2C SEC */ + client = dvb->i2c_client_sec; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + /* remove I2C tuner */ + client = dvb->i2c_client_tuner; if (client) { module_put(client->dev.driver->owner); i2c_unregister_device(client); diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 14eba9c..4397ce5 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -839,7 +839,6 @@ static int get_ressource(enum v4l2_buf_type f_type) return EM28XX_RESOURCE_VBI; default: BUG(); - return 0; } } diff --git a/drivers/media/usb/go7007/go7007-driver.c b/drivers/media/usb/go7007/go7007-driver.c index 95cffb7..0ab81ec 100644 --- a/drivers/media/usb/go7007/go7007-driver.c +++ b/drivers/media/usb/go7007/go7007-driver.c @@ -446,7 +446,7 @@ static void go7007_motion_regions(struct go7007 *go, struct go7007_buffer *vb) */ static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buffer *vb) { - u32 *bytesused = &vb->vb.v4l2_planes[0].bytesused; + u32 *bytesused; struct go7007_buffer *vb_tmp = NULL; if (vb == NULL) { @@ -458,6 +458,7 @@ static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buf go->next_seq++; return vb; } + bytesused = &vb->vb.v4l2_planes[0].bytesused; vb->vb.v4l2_buf.sequence = go->next_seq++; if (vb->modet_active && *bytesused + 216 < GO7007_BUF_SIZE) diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c index 3f986e1..4857c46 100644 --- a/drivers/media/usb/go7007/go7007-usb.c +++ b/drivers/media/usb/go7007/go7007-usb.c @@ -338,6 +338,7 @@ static const struct go7007_usb_board board_matrix_revolution = { }, }; +#if 0 static const struct go7007_usb_board board_lifeview_lr192 = { .flags = GO7007_USB_EZUSB, .main_info = { @@ -364,6 +365,7 @@ static const struct go7007_usb_board board_lifeview_lr192 = { }, }, }; +#endif static const struct go7007_usb_board board_endura = { .flags = 0, @@ -1096,8 +1098,10 @@ static int go7007_usb_probe(struct usb_interface *intf, case GO7007_BOARDID_LIFEVIEW_LR192: dev_err(&intf->dev, "The Lifeview TV Walker Ultra is not supported. Sorry!\n"); return -ENODEV; +#if 0 name = "Lifeview TV Walker Ultra"; board = &board_lifeview_lr192; +#endif break; case GO7007_BOARDID_SENSORAY_2250: dev_info(&intf->dev, "Sensoray 2250 found\n"); diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index d6bf982..c57207e 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c @@ -250,15 +250,17 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try) go->encoder_v_offset = go->board_info->sensor_v_offset; if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) { - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; - mbus_fmt.code = MEDIA_BUS_FMT_FIXED; - mbus_fmt.width = fmt ? fmt->fmt.pix.width : width; - mbus_fmt.height = height; + format.format.code = MEDIA_BUS_FMT_FIXED; + format.format.width = fmt ? fmt->fmt.pix.width : width; + format.format.height = height; go->encoder_h_halve = 0; go->encoder_v_halve = 0; go->encoder_subsample = 0; - call_all(&go->v4l2_dev, video, s_mbus_fmt, &mbus_fmt); + call_all(&go->v4l2_dev, pad, set_fmt, NULL, &format); } else { if (width <= sensor_width / 4) { go->encoder_h_halve = 1; diff --git a/drivers/media/usb/go7007/s2250-board.c b/drivers/media/usb/go7007/s2250-board.c index bb84668..5c2a495 100644 --- a/drivers/media/usb/go7007/s2250-board.c +++ b/drivers/media/usb/go7007/s2250-board.c @@ -405,12 +405,20 @@ static int s2250_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static int s2250_s_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int s2250_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *fmt = &format->format; struct s2250 *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); + if (format->pad) + return -EINVAL; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + return 0; + if (fmt->height < 640) { write_reg_fp(client, 0x12b, state->reg12b_val | 0x400); write_reg_fp(client, 0x140, 0x060); @@ -479,13 +487,17 @@ static const struct v4l2_subdev_audio_ops s2250_audio_ops = { static const struct v4l2_subdev_video_ops s2250_video_ops = { .s_std = s2250_s_std, .s_routing = s2250_s_video_routing, - .s_mbus_fmt = s2250_s_mbus_fmt, +}; + +static const struct v4l2_subdev_pad_ops s2250_pad_ops = { + .set_fmt = s2250_set_fmt, }; static const struct v4l2_subdev_ops s2250_ops = { .core = &s2250_core_ops, .audio = &s2250_audio_ops, .video = &s2250_video_ops, + .pad = &s2250_pad_ops, }; /* --------------------------------------------------------------------------*/ diff --git a/drivers/media/usb/gspca/benq.c b/drivers/media/usb/gspca/benq.c index 05f406dea..790baed 100644 --- a/drivers/media/usb/gspca/benq.c +++ b/drivers/media/usb/gspca/benq.c @@ -236,8 +236,8 @@ static void sd_isoc_irq(struct urb *urb) } data = (u8 *) urb->transfer_buffer + urb->iso_frame_desc[i].offset; - gspca_frame_add(gspca_dev, INTER_PACKET, - data, SD_PKT_SZ); + gspca_frame_add(gspca_dev, INTER_PACKET, + data, SD_PKT_SZ); } /* resubmit the URBs */ diff --git a/drivers/media/usb/gspca/sn9c2028.c b/drivers/media/usb/gspca/sn9c2028.c index 39b6b2e..c75b738 100644 --- a/drivers/media/usb/gspca/sn9c2028.c +++ b/drivers/media/usb/gspca/sn9c2028.c @@ -33,6 +33,16 @@ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ u8 sof_read; u16 model; + +#define MIN_AVG_LUM 8500 +#define MAX_AVG_LUM 10000 + int avg_lum; + u8 avg_lum_l; + + struct { /* autogain and gain control cluster */ + struct v4l2_ctrl *autogain; + struct v4l2_ctrl *gain; + }; }; struct init_command { @@ -128,7 +138,7 @@ static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command) status = -1; for (i = 0; i < 256 && status < 2; i++) status = sn9c2028_read1(gspca_dev); - if (status != 2) { + if (status < 0) { pr_err("long command status read error %d\n", status); return (status < 0) ? status : -EIO; } @@ -178,6 +188,9 @@ static int sd_config(struct gspca_dev *gspca_dev, case 0x7005: PDEBUG(D_PROBE, "Genius Smart 300 camera"); break; + case 0x7003: + PDEBUG(D_PROBE, "Genius Videocam Live v2"); + break; case 0x8000: PDEBUG(D_PROBE, "DC31VC"); break; @@ -248,6 +261,78 @@ static int run_start_commands(struct gspca_dev *gspca_dev, return 0; } +static void set_gain(struct gspca_dev *gspca_dev, s32 g) +{ + struct sd *sd = (struct sd *) gspca_dev; + + struct init_command genius_vcam_live_gain_cmds[] = { + {{0x1d, 0x25, 0x10 /* This byte is gain */, + 0x20, 0xab, 0x00}, 0}, + }; + if (!gspca_dev->streaming) + return; + + switch (sd->model) { + case 0x7003: + genius_vcam_live_gain_cmds[0].instruction[2] = g; + run_start_commands(gspca_dev, genius_vcam_live_gain_cmds, + ARRAY_SIZE(genius_vcam_live_gain_cmds)); + break; + default: + break; + } +} + +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev->usb_err = 0; + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + /* standalone gain control */ + case V4L2_CID_GAIN: + set_gain(gspca_dev, ctrl->val); + break; + /* autogain */ + case V4L2_CID_AUTOGAIN: + set_gain(gspca_dev, sd->gain->val); + break; + } + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + + +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 2); + + switch (sd->model) { + case 0x7003: + sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 20, 1, 0); + sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + break; + default: + break; + } + + return 0; +} static int start_spy_cam(struct gspca_dev *gspca_dev) { struct init_command spy_start_commands[] = { @@ -530,6 +615,119 @@ static int start_genius_cam(struct gspca_dev *gspca_dev) ARRAY_SIZE(genius_start_commands)); } +static int start_genius_videocam_live(struct gspca_dev *gspca_dev) +{ + int r; + struct sd *sd = (struct sd *) gspca_dev; + struct init_command genius_vcam_live_start_commands[] = { + {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 0}, + {{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, + {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, + + {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4}, + {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, + {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4}, + {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, + {{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4}, + {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4}, + {{0x1c, 0x20, 0x00, 0x2d, 0x00, 0x00}, 4}, + {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x22, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4}, + {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, + {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, + {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, + {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4}, + {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4}, + {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, + {{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4}, + {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4}, + {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x01, 0x04, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x02, 0x92, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x25, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x26, 0x02, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x27, 0x88, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x30, 0x38, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x31, 0x2a, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x32, 0x2a, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x33, 0x2a, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x34, 0x02, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x5b, 0x0a, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, + {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, + {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4}, + {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, + {{0x13, 0x29, 0x01, 0x62, 0x00, 0x00}, 4}, + {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4}, + {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4}, + {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4}, + {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x21, 0x2a, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x23, 0x28, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x11, 0x04, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x13, 0x03, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x15, 0xe0, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x16, 0x02, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x17, 0x80, 0x00, 0x00, 0x00}, 4}, + {{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1}, + {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 0}, + /* Camera should start to capture now. */ + {{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 0}, + {{0x1b, 0x32, 0x26, 0x00, 0x00, 0x00}, 0}, + {{0x1d, 0x25, 0x10, 0x20, 0xab, 0x00}, 0}, + }; + + r = run_start_commands(gspca_dev, genius_vcam_live_start_commands, + ARRAY_SIZE(genius_vcam_live_start_commands)); + if (r < 0) + return r; + + if (sd->gain) + set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain)); + + return r; +} + static int start_vivitar_cam(struct gspca_dev *gspca_dev) { struct init_command vivitar_start_commands[] = { @@ -623,6 +821,9 @@ static int sd_start(struct gspca_dev *gspca_dev) case 0x7005: err_code = start_genius_cam(gspca_dev); break; + case 0x7003: + err_code = start_genius_videocam_live(gspca_dev); + break; case 0x8001: err_code = start_spy_cam(gspca_dev); break; @@ -640,6 +841,8 @@ static int sd_start(struct gspca_dev *gspca_dev) return -ENXIO; } + sd->avg_lum = -1; + return err_code; } @@ -659,6 +862,39 @@ static void sd_stopN(struct gspca_dev *gspca_dev) PERR("Camera Stop command failed"); } +static void do_autogain(struct gspca_dev *gspca_dev, int avg_lum) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 cur_gain = v4l2_ctrl_g_ctrl(sd->gain); + + if (avg_lum == -1) + return; + + if (avg_lum < MIN_AVG_LUM) { + if (cur_gain == sd->gain->maximum) + return; + cur_gain++; + v4l2_ctrl_s_ctrl(sd->gain, cur_gain); + } + if (avg_lum > MAX_AVG_LUM) { + if (cur_gain == sd->gain->minimum) + return; + cur_gain--; + v4l2_ctrl_s_ctrl(sd->gain, cur_gain); + } + +} + +static void sd_dqcallback(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->autogain == NULL || !v4l2_ctrl_g_ctrl(sd->autogain)) + return; + + do_autogain(gspca_dev, sd->avg_lum); +} + /* Include sn9c2028 sof detection functions */ #include "sn9c2028.h" @@ -693,14 +929,17 @@ static const struct sd_desc sd_desc = { .name = MODULE_NAME, .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, + .dq_callback = sd_dqcallback, .pkt_scan = sd_pkt_scan, }; /* -- module initialisation -- */ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0458, 0x7005)}, /* Genius Smart 300, version 2 */ + {USB_DEVICE(0x0458, 0x7003)}, /* Genius Videocam Live v2 */ /* The Genius Smart is untested. I can't find an owner ! */ /* {USB_DEVICE(0x0c45, 0x8000)}, DC31VC, Don't know this camera */ {USB_DEVICE(0x0c45, 0x8001)}, /* Wild Planet digital spy cam */ diff --git a/drivers/media/usb/gspca/sn9c2028.h b/drivers/media/usb/gspca/sn9c2028.h index 8fd1d3e..f85bc10 100644 --- a/drivers/media/usb/gspca/sn9c2028.h +++ b/drivers/media/usb/gspca/sn9c2028.h @@ -21,8 +21,15 @@ * */ -static const unsigned char sn9c2028_sof_marker[5] = - { 0xff, 0xff, 0x00, 0xc4, 0xc4 }; +static const unsigned char sn9c2028_sof_marker[] = { + 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, + 0x00, + 0x00, /* seq */ + 0x00, + 0x00, + 0x00, /* avg luminance lower 8 bit */ + 0x00, /* avg luminance higher 8 bit */ +}; static unsigned char *sn9c2028_find_sof(struct gspca_dev *gspca_dev, unsigned char *m, int len) @@ -32,8 +39,13 @@ static unsigned char *sn9c2028_find_sof(struct gspca_dev *gspca_dev, /* Search for the SOF marker (fixed part) in the header */ for (i = 0; i < len; i++) { - if (m[i] == sn9c2028_sof_marker[sd->sof_read]) { + if ((m[i] == sn9c2028_sof_marker[sd->sof_read]) || + (sd->sof_read > 5)) { sd->sof_read++; + if (sd->sof_read == 11) + sd->avg_lum_l = m[i]; + if (sd->sof_read == 12) + sd->avg_lum = (m[i] << 8) + sd->avg_lum_l; if (sd->sof_read == sizeof(sn9c2028_sof_marker)) { PDEBUG(D_FRAM, "SOF found, bytes to analyze: %u." diff --git a/drivers/media/usb/gspca/sonixj.c b/drivers/media/usb/gspca/sonixj.c index c69b45d..fd1c870 100644 --- a/drivers/media/usb/gspca/sonixj.c +++ b/drivers/media/usb/gspca/sonixj.c @@ -1789,7 +1789,7 @@ static u32 expo_adjust(struct gspca_dev *gspca_dev, if (expo > 0x03ff) expo = 0x03ff; - if (expo < 0x0001) + if (expo < 0x0001) expo = 0x0001; gainOm[3] = expo >> 2; i2c_w8(gspca_dev, gainOm); diff --git a/drivers/media/usb/gspca/stk014.c b/drivers/media/usb/gspca/stk014.c index b0c70fe..d324d00 100644 --- a/drivers/media/usb/gspca/stk014.c +++ b/drivers/media/usb/gspca/stk014.c @@ -276,7 +276,7 @@ static int sd_start(struct gspca_dev *gspca_dev) gspca_dev->usb_err = ret; goto out; } - reg_r(gspca_dev, 0x0630); + reg_r(gspca_dev, 0x0630); rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */ reg_r(gspca_dev, 0x0650); snd_val(gspca_dev, 0x000020, 0xffffffff); diff --git a/drivers/media/usb/gspca/xirlink_cit.c b/drivers/media/usb/gspca/xirlink_cit.c index a41aa78..d5ed9d3 100644 --- a/drivers/media/usb/gspca/xirlink_cit.c +++ b/drivers/media/usb/gspca/xirlink_cit.c @@ -1772,7 +1772,8 @@ static int cit_start_model2(struct gspca_dev *gspca_dev) cit_write_reg(gspca_dev, 0x0070, 0x0119); /* All except 176x144 */ sd->sof_len = 2; break; - /* case VIDEOSIZE_352x240: */ +#if 0 + case VIDEOSIZE_352x240: cit_write_reg(gspca_dev, 0x002c, 0x0103); /* All except 320x240 */ cit_write_reg(gspca_dev, 0x0000, 0x0104); /* Same */ cit_write_reg(gspca_dev, 0x001e, 0x0105); /* 320x240, 352x240 */ @@ -1780,6 +1781,7 @@ static int cit_start_model2(struct gspca_dev *gspca_dev) cit_write_reg(gspca_dev, 0x0070, 0x0119); /* All except 176x144 */ sd->sof_len = 2; break; +#endif case 352: /* 352x288 */ cit_write_reg(gspca_dev, 0x002c, 0x0103); /* All except 320x240 */ cit_write_reg(gspca_dev, 0x0000, 0x0104); /* Same */ @@ -1853,13 +1855,15 @@ static int cit_start_model2(struct gspca_dev *gspca_dev) cit_model2_Packet1(gspca_dev, 0x0018, 0x0044); /* Another hardware setting */ clock_div = 8; break; - /* case VIDEOSIZE_352x240: */ +#if 0 + case VIDEOSIZE_352x240: /* This mode doesn't work as Windows programs it; changed to work */ cit_model2_Packet1(gspca_dev, 0x0014, 0x0009); /* Windows sets this to 8 */ cit_model2_Packet1(gspca_dev, 0x0016, 0x0003); /* Horizontal shift */ cit_model2_Packet1(gspca_dev, 0x0018, 0x0044); /* Windows sets this to 0x0045 */ clock_div = 10; break; +#endif case 352: /* 352x288 */ cit_model2_Packet1(gspca_dev, 0x0014, 0x0003); cit_model2_Packet1(gspca_dev, 0x0016, 0x0002); /* Horizontal shift */ @@ -1906,9 +1910,11 @@ static int cit_start_model2(struct gspca_dev *gspca_dev) case 320: /* 320x240 */ cit_model2_Packet1(gspca_dev, 0x0026, 0x0044); break; - /* case VIDEOSIZE_352x240: */ +#if 0 + case VIDEOSIZE_352x240: cit_model2_Packet1(gspca_dev, 0x0026, 0x0046); break; +#endif case 352: /* 352x288 */ cit_model2_Packet1(gspca_dev, 0x0026, 0x0048); break; diff --git a/drivers/media/usb/gspca/zc3xx.c b/drivers/media/usb/gspca/zc3xx.c index d3e1b6d..c5d8ee6 100644 --- a/drivers/media/usb/gspca/zc3xx.c +++ b/drivers/media/usb/gspca/zc3xx.c @@ -5942,23 +5942,23 @@ static void transfer_update(struct work_struct *work) reg07 = 0; good = 0; - for (;;) { + while (1) { msleep(100); /* To protect gspca_dev->usb_buf and gspca_dev->usb_err */ mutex_lock(&gspca_dev->usb_lock); #ifdef CONFIG_PM if (gspca_dev->frozen) - goto err; + break; #endif if (!gspca_dev->present || !gspca_dev->streaming) - goto err; + break; /* Bit 0 of register 11 indicates FIFO overflow */ gspca_dev->usb_err = 0; reg11 = reg_r(gspca_dev, 0x0011); if (gspca_dev->usb_err) - goto err; + break; change = reg11 & 0x01; if (change) { /* overflow */ @@ -5987,12 +5987,12 @@ static void transfer_update(struct work_struct *work) gspca_dev->usb_err = 0; reg_w(gspca_dev, reg07, 0x0007); if (gspca_dev->usb_err) - goto err; + break; } mutex_unlock(&gspca_dev->usb_lock); } - return; -err: + + /* Something went wrong. Unlock and return */ mutex_unlock(&gspca_dev->usb_lock); } @@ -6360,7 +6360,7 @@ static int zcxx_s_ctrl(struct v4l2_ctrl *ctrl) if (ctrl->val <= jpeg_qual[i]) break; } - if (i > 0 && i == qual && ctrl->val < jpeg_qual[i]) + if (i == ARRAY_SIZE(jpeg_qual) || (i > 0 && i == qual && ctrl->val < jpeg_qual[i])) i--; /* With high quality settings we need max bandwidth */ diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index efc761c..3f276d9 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -1,4 +1,5 @@ /* + * Mirics MSi2500 driver * Mirics MSi3101 SDR Dongle driver * * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> @@ -13,10 +14,6 @@ * 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. - * * That driver is somehow based of pwc driver: * (C) 1999-2004 Nemosoft Unv. * (C) 2004-2006 Luc Saillard (luc@saillard.org) @@ -119,7 +116,7 @@ struct msi2500_frame_buf { struct list_head list; }; -struct msi2500_state { +struct msi2500_dev { struct device *dev; struct video_device vdev; struct v4l2_device v4l2_dev; @@ -158,19 +155,19 @@ struct msi2500_state { /* Private functions */ static struct msi2500_frame_buf *msi2500_get_next_fill_buf( - struct msi2500_state *s) + struct msi2500_dev *dev) { unsigned long flags; struct msi2500_frame_buf *buf = NULL; - spin_lock_irqsave(&s->queued_bufs_lock, flags); - if (list_empty(&s->queued_bufs)) + spin_lock_irqsave(&dev->queued_bufs_lock, flags); + if (list_empty(&dev->queued_bufs)) goto leave; - buf = list_entry(s->queued_bufs.next, struct msi2500_frame_buf, list); + buf = list_entry(dev->queued_bufs.next, struct msi2500_frame_buf, list); list_del(&buf->list); leave: - spin_unlock_irqrestore(&s->queued_bufs_lock, flags); + spin_unlock_irqrestore(&dev->queued_bufs_lock, flags); return buf; } @@ -256,8 +253,8 @@ leave: * signed 14-bit sample */ -static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src, - unsigned int src_len) +static int msi2500_convert_stream(struct msi2500_dev *dev, u8 *dst, u8 *src, + unsigned int src_len) { unsigned int i, j, transactions, dst_len = 0; u32 sample[3]; @@ -268,26 +265,27 @@ static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src, for (i = 0; i < transactions; i++) { sample[i] = src[3] << 24 | src[2] << 16 | src[1] << 8 | src[0] << 0; - if (i == 0 && s->next_sample != sample[0]) { - dev_dbg_ratelimited(s->dev, - "%d samples lost, %d %08x:%08x\n", - sample[0] - s->next_sample, - src_len, s->next_sample, sample[0]); + if (i == 0 && dev->next_sample != sample[0]) { + dev_dbg_ratelimited(dev->dev, + "%d samples lost, %d %08x:%08x\n", + sample[0] - dev->next_sample, + src_len, dev->next_sample, + sample[0]); } /* * Dump all unknown 'garbage' data - maybe we will discover * someday if there is something rational... */ - dev_dbg_ratelimited(s->dev, "%*ph\n", 12, &src[4]); + dev_dbg_ratelimited(dev->dev, "%*ph\n", 12, &src[4]); src += 16; /* skip header */ - switch (s->pixelformat) { + switch (dev->pixelformat) { case V4L2_SDR_FMT_CU8: /* 504 x IQ samples */ { - s8 *s8src = (s8 *) src; - u8 *u8dst = (u8 *) dst; + s8 *s8src = (s8 *)src; + u8 *u8dst = (u8 *)dst; for (j = 0; j < 1008; j++) *u8dst++ = *s8src++ + 128; @@ -295,13 +293,13 @@ static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src, src += 1008; dst += 1008; dst_len += 1008; - s->next_sample = sample[i] + 504; + dev->next_sample = sample[i] + 504; break; } case V4L2_SDR_FMT_CU16LE: /* 252 x IQ samples */ { - s16 *s16src = (s16 *) src; - u16 *u16dst = (u16 *) dst; + s16 *s16src = (s16 *)src; + u16 *u16dst = (u16 *)dst; struct {signed int x:14; } se; /* sign extension */ unsigned int utmp; @@ -317,38 +315,38 @@ static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src, src += 1008; dst += 1008; dst_len += 1008; - s->next_sample = sample[i] + 252; + dev->next_sample = sample[i] + 252; break; } case MSI2500_PIX_FMT_SDR_MSI2500_384: /* 384 x IQ samples */ /* Dump unknown 'garbage' data */ - dev_dbg_ratelimited(s->dev, "%*ph\n", 24, &src[1000]); + dev_dbg_ratelimited(dev->dev, "%*ph\n", 24, &src[1000]); memcpy(dst, src, 984); src += 984 + 24; dst += 984; dst_len += 984; - s->next_sample = sample[i] + 384; + dev->next_sample = sample[i] + 384; break; case V4L2_SDR_FMT_CS8: /* 504 x IQ samples */ memcpy(dst, src, 1008); src += 1008; dst += 1008; dst_len += 1008; - s->next_sample = sample[i] + 504; + dev->next_sample = sample[i] + 504; break; case MSI2500_PIX_FMT_SDR_S12: /* 336 x IQ samples */ memcpy(dst, src, 1008); src += 1008; dst += 1008; dst_len += 1008; - s->next_sample = sample[i] + 336; + dev->next_sample = sample[i] + 336; break; case V4L2_SDR_FMT_CS14LE: /* 252 x IQ samples */ memcpy(dst, src, 1008); src += 1008; dst += 1008; dst_len += 1008; - s->next_sample = sample[i] + 252; + dev->next_sample = sample[i] + 252; break; default: break; @@ -356,17 +354,17 @@ static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src, } /* calculate sample rate and output it in 10 seconds intervals */ - if (unlikely(time_is_before_jiffies(s->jiffies_next))) { + if (unlikely(time_is_before_jiffies(dev->jiffies_next))) { #define MSECS 10000UL unsigned int msecs = jiffies_to_msecs(jiffies - - s->jiffies_next + msecs_to_jiffies(MSECS)); - unsigned int samples = s->next_sample - s->sample; - - s->jiffies_next = jiffies + msecs_to_jiffies(MSECS); - s->sample = s->next_sample; - dev_dbg(s->dev, "size=%u samples=%u msecs=%u sample rate=%lu\n", - src_len, samples, msecs, - samples * 1000UL / msecs); + dev->jiffies_next + msecs_to_jiffies(MSECS)); + unsigned int samples = dev->next_sample - dev->sample; + + dev->jiffies_next = jiffies + msecs_to_jiffies(MSECS); + dev->sample = dev->next_sample; + dev_dbg(dev->dev, "size=%u samples=%u msecs=%u sample rate=%lu\n", + src_len, samples, msecs, + samples * 1000UL / msecs); } return dst_len; @@ -378,27 +376,28 @@ static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src, */ static void msi2500_isoc_handler(struct urb *urb) { - struct msi2500_state *s = (struct msi2500_state *)urb->context; + struct msi2500_dev *dev = (struct msi2500_dev *)urb->context; int i, flen, fstatus; unsigned char *iso_buf = NULL; struct msi2500_frame_buf *fbuf; - if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET || - urb->status == -ESHUTDOWN)) { - dev_dbg(s->dev, "URB (%p) unlinked %ssynchronuously\n", - urb, urb->status == -ENOENT ? "" : "a"); + if (unlikely(urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN)) { + dev_dbg(dev->dev, "URB (%p) unlinked %ssynchronuously\n", + urb, urb->status == -ENOENT ? "" : "a"); return; } if (unlikely(urb->status != 0)) { - dev_dbg(s->dev, "called with status %d\n", urb->status); + dev_dbg(dev->dev, "called with status %d\n", urb->status); /* Give up after a number of contiguous errors */ - if (++s->isoc_errors > MAX_ISOC_ERRORS) - dev_dbg(s->dev, "Too many ISOC errors, bailing out\n"); + if (++dev->isoc_errors > MAX_ISOC_ERRORS) + dev_dbg(dev->dev, "Too many ISOC errors, bailing out\n"); goto handler_end; } else { /* Reset ISOC error counter. We did get here, after all. */ - s->isoc_errors = 0; + dev->isoc_errors = 0; } /* Compact data */ @@ -408,9 +407,9 @@ static void msi2500_isoc_handler(struct urb *urb) /* Check frame error */ fstatus = urb->iso_frame_desc[i].status; if (unlikely(fstatus)) { - dev_dbg_ratelimited(s->dev, - "frame=%d/%d has error %d skipping\n", - i, urb->number_of_packets, fstatus); + dev_dbg_ratelimited(dev->dev, + "frame=%d/%d has error %d skipping\n", + i, urb->number_of_packets, fstatus); continue; } @@ -422,18 +421,18 @@ static void msi2500_isoc_handler(struct urb *urb) iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; /* Get free framebuffer */ - fbuf = msi2500_get_next_fill_buf(s); + fbuf = msi2500_get_next_fill_buf(dev); if (unlikely(fbuf == NULL)) { - s->vb_full++; - dev_dbg_ratelimited(s->dev, - "videobuf is full, %d packets dropped\n", - s->vb_full); + dev->vb_full++; + dev_dbg_ratelimited(dev->dev, + "videobuf is full, %d packets dropped\n", + dev->vb_full); continue; } /* fill framebuffer */ ptr = vb2_plane_vaddr(&fbuf->vb, 0); - flen = msi2500_convert_stream(s, ptr, iso_buf, flen); + flen = msi2500_convert_stream(dev, ptr, iso_buf, flen); vb2_set_plane_payload(&fbuf->vb, 0, flen); vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE); } @@ -441,66 +440,66 @@ static void msi2500_isoc_handler(struct urb *urb) handler_end: i = usb_submit_urb(urb, GFP_ATOMIC); if (unlikely(i != 0)) - dev_dbg(s->dev, "Error (%d) re-submitting urb\n", i); + dev_dbg(dev->dev, "Error (%d) re-submitting urb\n", i); } -static void msi2500_iso_stop(struct msi2500_state *s) +static void msi2500_iso_stop(struct msi2500_dev *dev) { int i; - dev_dbg(s->dev, "\n"); + dev_dbg(dev->dev, "\n"); /* Unlinking ISOC buffers one by one */ for (i = 0; i < MAX_ISO_BUFS; i++) { - if (s->urbs[i]) { - dev_dbg(s->dev, "Unlinking URB %p\n", s->urbs[i]); - usb_kill_urb(s->urbs[i]); + if (dev->urbs[i]) { + dev_dbg(dev->dev, "Unlinking URB %p\n", dev->urbs[i]); + usb_kill_urb(dev->urbs[i]); } } } -static void msi2500_iso_free(struct msi2500_state *s) +static void msi2500_iso_free(struct msi2500_dev *dev) { int i; - dev_dbg(s->dev, "\n"); + dev_dbg(dev->dev, "\n"); /* Freeing ISOC buffers one by one */ for (i = 0; i < MAX_ISO_BUFS; i++) { - if (s->urbs[i]) { - dev_dbg(s->dev, "Freeing URB\n"); - if (s->urbs[i]->transfer_buffer) { - usb_free_coherent(s->udev, - s->urbs[i]->transfer_buffer_length, - s->urbs[i]->transfer_buffer, - s->urbs[i]->transfer_dma); + if (dev->urbs[i]) { + dev_dbg(dev->dev, "Freeing URB\n"); + if (dev->urbs[i]->transfer_buffer) { + usb_free_coherent(dev->udev, + dev->urbs[i]->transfer_buffer_length, + dev->urbs[i]->transfer_buffer, + dev->urbs[i]->transfer_dma); } - usb_free_urb(s->urbs[i]); - s->urbs[i] = NULL; + usb_free_urb(dev->urbs[i]); + dev->urbs[i] = NULL; } } } /* Both v4l2_lock and vb_queue_lock should be locked when calling this */ -static void msi2500_isoc_cleanup(struct msi2500_state *s) +static void msi2500_isoc_cleanup(struct msi2500_dev *dev) { - dev_dbg(s->dev, "\n"); + dev_dbg(dev->dev, "\n"); - msi2500_iso_stop(s); - msi2500_iso_free(s); + msi2500_iso_stop(dev); + msi2500_iso_free(dev); } /* Both v4l2_lock and vb_queue_lock should be locked when calling this */ -static int msi2500_isoc_init(struct msi2500_state *s) +static int msi2500_isoc_init(struct msi2500_dev *dev) { struct urb *urb; int i, j, ret; - dev_dbg(s->dev, "\n"); + dev_dbg(dev->dev, "\n"); - s->isoc_errors = 0; + dev->isoc_errors = 0; - ret = usb_set_interface(s->udev, 0, 1); + ret = usb_set_interface(dev->udev, 0, 1); if (ret) return ret; @@ -508,29 +507,29 @@ static int msi2500_isoc_init(struct msi2500_state *s) for (i = 0; i < MAX_ISO_BUFS; i++) { urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); if (urb == NULL) { - dev_err(s->dev, "Failed to allocate urb %d\n", i); - msi2500_isoc_cleanup(s); + dev_err(dev->dev, "Failed to allocate urb %d\n", i); + msi2500_isoc_cleanup(dev); return -ENOMEM; } - s->urbs[i] = urb; - dev_dbg(s->dev, "Allocated URB at 0x%p\n", urb); + dev->urbs[i] = urb; + dev_dbg(dev->dev, "Allocated URB at 0x%p\n", urb); urb->interval = 1; - urb->dev = s->udev; - urb->pipe = usb_rcvisocpipe(s->udev, 0x81); + urb->dev = dev->udev; + urb->pipe = usb_rcvisocpipe(dev->udev, 0x81); urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - urb->transfer_buffer = usb_alloc_coherent(s->udev, + urb->transfer_buffer = usb_alloc_coherent(dev->udev, ISO_BUFFER_SIZE, GFP_KERNEL, &urb->transfer_dma); if (urb->transfer_buffer == NULL) { - dev_err(s->dev, "Failed to allocate urb buffer %d\n", - i); - msi2500_isoc_cleanup(s); + dev_err(dev->dev, + "Failed to allocate urb buffer %d\n", i); + msi2500_isoc_cleanup(dev); return -ENOMEM; } urb->transfer_buffer_length = ISO_BUFFER_SIZE; urb->complete = msi2500_isoc_handler; - urb->context = s; + urb->context = dev; urb->start_frame = 0; urb->number_of_packets = ISO_FRAMES_PER_DESC; for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { @@ -541,14 +540,15 @@ static int msi2500_isoc_init(struct msi2500_state *s) /* link */ for (i = 0; i < MAX_ISO_BUFS; i++) { - ret = usb_submit_urb(s->urbs[i], GFP_KERNEL); + ret = usb_submit_urb(dev->urbs[i], GFP_KERNEL); if (ret) { - dev_err(s->dev, "usb_submit_urb %d failed with error %d\n", - i, ret); - msi2500_isoc_cleanup(s); + dev_err(dev->dev, + "usb_submit_urb %d failed with error %d\n", + i, ret); + msi2500_isoc_cleanup(dev); return ret; } - dev_dbg(s->dev, "URB 0x%p submitted.\n", s->urbs[i]); + dev_dbg(dev->dev, "URB 0x%p submitted.\n", dev->urbs[i]); } /* All is done... */ @@ -556,56 +556,56 @@ static int msi2500_isoc_init(struct msi2500_state *s) } /* Must be called with vb_queue_lock hold */ -static void msi2500_cleanup_queued_bufs(struct msi2500_state *s) +static void msi2500_cleanup_queued_bufs(struct msi2500_dev *dev) { unsigned long flags; - dev_dbg(s->dev, "\n"); + dev_dbg(dev->dev, "\n"); - spin_lock_irqsave(&s->queued_bufs_lock, flags); - while (!list_empty(&s->queued_bufs)) { + spin_lock_irqsave(&dev->queued_bufs_lock, flags); + while (!list_empty(&dev->queued_bufs)) { struct msi2500_frame_buf *buf; - buf = list_entry(s->queued_bufs.next, struct msi2500_frame_buf, - list); + buf = list_entry(dev->queued_bufs.next, + struct msi2500_frame_buf, list); list_del(&buf->list); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } - spin_unlock_irqrestore(&s->queued_bufs_lock, flags); + spin_unlock_irqrestore(&dev->queued_bufs_lock, flags); } /* The user yanked out the cable... */ static void msi2500_disconnect(struct usb_interface *intf) { struct v4l2_device *v = usb_get_intfdata(intf); - struct msi2500_state *s = - container_of(v, struct msi2500_state, v4l2_dev); + struct msi2500_dev *dev = + container_of(v, struct msi2500_dev, v4l2_dev); - dev_dbg(s->dev, "\n"); + dev_dbg(dev->dev, "\n"); - mutex_lock(&s->vb_queue_lock); - mutex_lock(&s->v4l2_lock); + mutex_lock(&dev->vb_queue_lock); + mutex_lock(&dev->v4l2_lock); /* No need to keep the urbs around after disconnection */ - s->udev = NULL; - v4l2_device_disconnect(&s->v4l2_dev); - video_unregister_device(&s->vdev); - spi_unregister_master(s->master); - mutex_unlock(&s->v4l2_lock); - mutex_unlock(&s->vb_queue_lock); - - v4l2_device_put(&s->v4l2_dev); + dev->udev = NULL; + v4l2_device_disconnect(&dev->v4l2_dev); + video_unregister_device(&dev->vdev); + spi_unregister_master(dev->master); + mutex_unlock(&dev->v4l2_lock); + mutex_unlock(&dev->vb_queue_lock); + + v4l2_device_put(&dev->v4l2_dev); } static int msi2500_querycap(struct file *file, void *fh, - struct v4l2_capability *cap) + struct v4l2_capability *cap) { - struct msi2500_state *s = video_drvdata(file); + struct msi2500_dev *dev = video_drvdata(file); - dev_dbg(s->dev, "\n"); + dev_dbg(dev->dev, "\n"); strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); - strlcpy(cap->card, s->vdev.name, sizeof(cap->card)); - usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info)); + strlcpy(cap->card, dev->vdev.name, sizeof(cap->card)); + usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | V4L2_CAP_TUNER; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; @@ -614,43 +614,46 @@ static int msi2500_querycap(struct file *file, void *fh, /* Videobuf2 operations */ static int msi2500_queue_setup(struct vb2_queue *vq, - const struct v4l2_format *fmt, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) + const struct v4l2_format *fmt, + unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + void *alloc_ctxs[]) { - struct msi2500_state *s = vb2_get_drv_priv(vq); + struct msi2500_dev *dev = vb2_get_drv_priv(vq); - dev_dbg(s->dev, "nbuffers=%d\n", *nbuffers); + dev_dbg(dev->dev, "nbuffers=%d\n", *nbuffers); /* Absolute min and max number of buffers available for mmap() */ *nbuffers = clamp_t(unsigned int, *nbuffers, 8, 32); *nplanes = 1; - sizes[0] = PAGE_ALIGN(s->buffersize); - dev_dbg(s->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]); + sizes[0] = PAGE_ALIGN(dev->buffersize); + dev_dbg(dev->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]); return 0; } static void msi2500_buf_queue(struct vb2_buffer *vb) { - struct msi2500_state *s = vb2_get_drv_priv(vb->vb2_queue); - struct msi2500_frame_buf *buf = - container_of(vb, struct msi2500_frame_buf, vb); + struct msi2500_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct msi2500_frame_buf *buf = container_of(vb, + struct msi2500_frame_buf, + vb); unsigned long flags; /* Check the device has not disconnected between prep and queuing */ - if (unlikely(!s->udev)) { + if (unlikely(!dev->udev)) { vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); return; } - spin_lock_irqsave(&s->queued_bufs_lock, flags); - list_add_tail(&buf->list, &s->queued_bufs); - spin_unlock_irqrestore(&s->queued_bufs_lock, flags); + spin_lock_irqsave(&dev->queued_bufs_lock, flags); + list_add_tail(&buf->list, &dev->queued_bufs); + spin_unlock_irqrestore(&dev->queued_bufs_lock, flags); } #define CMD_WREG 0x41 #define CMD_START_STREAMING 0x43 #define CMD_STOP_STREAMING 0x45 -#define CMD_READ_UNKNOW 0x48 +#define CMD_READ_UNKNOWN 0x48 #define msi2500_dbg_usb_control_msg(_dev, _r, _t, _v, _i, _b, _l) { \ char *_direction; \ @@ -663,7 +666,7 @@ static void msi2500_buf_queue(struct vb2_buffer *vb) _l & 0xff, _l >> 8, _direction, _l, _b); \ } -static int msi2500_ctrl_msg(struct msi2500_state *s, u8 cmd, u32 data) +static int msi2500_ctrl_msg(struct msi2500_dev *dev, u8 cmd, u32 data) { int ret; u8 request = cmd; @@ -671,39 +674,38 @@ static int msi2500_ctrl_msg(struct msi2500_state *s, u8 cmd, u32 data) u16 value = (data >> 0) & 0xffff; u16 index = (data >> 16) & 0xffff; - msi2500_dbg_usb_control_msg(s->dev, - request, requesttype, value, index, NULL, 0); - ret = usb_control_msg(s->udev, usb_sndctrlpipe(s->udev, 0), - request, requesttype, value, index, NULL, 0, 2000); + msi2500_dbg_usb_control_msg(dev->dev, request, requesttype, + value, index, NULL, 0); + ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), request, + requesttype, value, index, NULL, 0, 2000); if (ret) - dev_err(s->dev, "failed %d, cmd %02x, data %04x\n", - ret, cmd, data); + dev_err(dev->dev, "failed %d, cmd %02x, data %04x\n", + ret, cmd, data); return ret; } -#define F_REF 24000000 -#define DIV_R_IN 2 -static int msi2500_set_usb_adc(struct msi2500_state *s) +static int msi2500_set_usb_adc(struct msi2500_dev *dev) { - int ret, div_n, div_m, div_r_out, f_sr, f_vco, fract; + int ret; + unsigned int f_vco, f_sr, div_n, k, k_cw, div_out; u32 reg3, reg4, reg7; struct v4l2_ctrl *bandwidth_auto; struct v4l2_ctrl *bandwidth; - f_sr = s->f_adc; + f_sr = dev->f_adc; /* set tuner, subdev, filters according to sampling rate */ - bandwidth_auto = v4l2_ctrl_find(&s->hdl, + bandwidth_auto = v4l2_ctrl_find(&dev->hdl, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO); if (v4l2_ctrl_g_ctrl(bandwidth_auto)) { - bandwidth = v4l2_ctrl_find(&s->hdl, + bandwidth = v4l2_ctrl_find(&dev->hdl, V4L2_CID_RF_TUNER_BANDWIDTH); - v4l2_ctrl_s_ctrl(bandwidth, s->f_adc); + v4l2_ctrl_s_ctrl(bandwidth, dev->f_adc); } /* select stream format */ - switch (s->pixelformat) { + switch (dev->pixelformat) { case V4L2_SDR_FMT_CU8: reg7 = 0x000c9407; /* 504 */ break; @@ -728,6 +730,21 @@ static int msi2500_set_usb_adc(struct msi2500_state *s) } /* + * Fractional-N synthesizer + * + * +----------------------------------------+ + * v | + * Fref +----+ +-------+ +-----+ +------+ +---+ + * ------> | PD | --> | VCO | --> | /2 | ------> | /N.F | <-- | K | + * +----+ +-------+ +-----+ +------+ +---+ + * | + * | + * v + * +-------+ +-----+ Fout + * | /Rout | --> | /12 | ------> + * +-------+ +-----+ + */ + /* * Synthesizer config is just a educated guess... * * [7:0] 0x03, register address @@ -754,10 +771,14 @@ static int msi2500_set_usb_adc(struct msi2500_state *s) * * VCO 202000000 - 720000000++ */ + + #define F_REF 24000000 + #define DIV_PRE_N 2 + #define DIV_LO_OUT 12 reg3 = 0x01000303; reg4 = 0x00000004; - /* XXX: Filters? AGC? */ + /* XXX: Filters? AGC? VCO band? */ if (f_sr < 6000000) reg3 |= 0x1 << 20; else if (f_sr < 7000000) @@ -767,54 +788,55 @@ static int msi2500_set_usb_adc(struct msi2500_state *s) else reg3 |= 0xd << 20; - for (div_r_out = 4; div_r_out < 16; div_r_out += 2) { - f_vco = f_sr * div_r_out * 12; - dev_dbg(s->dev, "div_r_out=%d f_vco=%d\n", div_r_out, f_vco); + for (div_out = 4; div_out < 16; div_out += 2) { + f_vco = f_sr * div_out * DIV_LO_OUT; + dev_dbg(dev->dev, "div_out=%u f_vco=%u\n", div_out, f_vco); if (f_vco >= 202000000) break; } - div_n = f_vco / (F_REF * DIV_R_IN); - div_m = f_vco % (F_REF * DIV_R_IN); - fract = 0x200000ul * div_m / (F_REF * DIV_R_IN); + /* Calculate PLL integer and fractional control word. */ + div_n = div_u64_rem(f_vco, DIV_PRE_N * F_REF, &k); + k_cw = div_u64((u64) k * 0x200000, DIV_PRE_N * F_REF); reg3 |= div_n << 16; - reg3 |= (div_r_out / 2 - 1) << 10; - reg3 |= ((fract >> 20) & 0x000001) << 15; /* [20] */ - reg4 |= ((fract >> 0) & 0x0fffff) << 8; /* [19:0] */ + reg3 |= (div_out / 2 - 1) << 10; + reg3 |= ((k_cw >> 20) & 0x000001) << 15; /* [20] */ + reg4 |= ((k_cw >> 0) & 0x0fffff) << 8; /* [19:0] */ - dev_dbg(s->dev, "f_sr=%d f_vco=%d div_n=%d div_m=%d div_r_out=%d reg3=%08x reg4=%08x\n", - f_sr, f_vco, div_n, div_m, div_r_out, reg3, reg4); + dev_dbg(dev->dev, + "f_sr=%u f_vco=%u div_n=%u k=%u div_out=%u reg3=%08x reg4=%08x\n", + f_sr, f_vco, div_n, k, div_out, reg3, reg4); - ret = msi2500_ctrl_msg(s, CMD_WREG, 0x00608008); + ret = msi2500_ctrl_msg(dev, CMD_WREG, 0x00608008); if (ret) goto err; - ret = msi2500_ctrl_msg(s, CMD_WREG, 0x00000c05); + ret = msi2500_ctrl_msg(dev, CMD_WREG, 0x00000c05); if (ret) goto err; - ret = msi2500_ctrl_msg(s, CMD_WREG, 0x00020000); + ret = msi2500_ctrl_msg(dev, CMD_WREG, 0x00020000); if (ret) goto err; - ret = msi2500_ctrl_msg(s, CMD_WREG, 0x00480102); + ret = msi2500_ctrl_msg(dev, CMD_WREG, 0x00480102); if (ret) goto err; - ret = msi2500_ctrl_msg(s, CMD_WREG, 0x00f38008); + ret = msi2500_ctrl_msg(dev, CMD_WREG, 0x00f38008); if (ret) goto err; - ret = msi2500_ctrl_msg(s, CMD_WREG, reg7); + ret = msi2500_ctrl_msg(dev, CMD_WREG, reg7); if (ret) goto err; - ret = msi2500_ctrl_msg(s, CMD_WREG, reg4); + ret = msi2500_ctrl_msg(dev, CMD_WREG, reg4); if (ret) goto err; - ret = msi2500_ctrl_msg(s, CMD_WREG, reg3); + ret = msi2500_ctrl_msg(dev, CMD_WREG, reg3); if (ret) goto err; err: @@ -823,57 +845,57 @@ err: static int msi2500_start_streaming(struct vb2_queue *vq, unsigned int count) { - struct msi2500_state *s = vb2_get_drv_priv(vq); + struct msi2500_dev *dev = vb2_get_drv_priv(vq); int ret; - dev_dbg(s->dev, "\n"); + dev_dbg(dev->dev, "\n"); - if (!s->udev) + if (!dev->udev) return -ENODEV; - if (mutex_lock_interruptible(&s->v4l2_lock)) + if (mutex_lock_interruptible(&dev->v4l2_lock)) return -ERESTARTSYS; /* wake-up tuner */ - v4l2_subdev_call(s->v4l2_subdev, core, s_power, 1); + v4l2_subdev_call(dev->v4l2_subdev, core, s_power, 1); - ret = msi2500_set_usb_adc(s); + ret = msi2500_set_usb_adc(dev); - ret = msi2500_isoc_init(s); + ret = msi2500_isoc_init(dev); if (ret) - msi2500_cleanup_queued_bufs(s); + msi2500_cleanup_queued_bufs(dev); - ret = msi2500_ctrl_msg(s, CMD_START_STREAMING, 0); + ret = msi2500_ctrl_msg(dev, CMD_START_STREAMING, 0); - mutex_unlock(&s->v4l2_lock); + mutex_unlock(&dev->v4l2_lock); return ret; } static void msi2500_stop_streaming(struct vb2_queue *vq) { - struct msi2500_state *s = vb2_get_drv_priv(vq); + struct msi2500_dev *dev = vb2_get_drv_priv(vq); - dev_dbg(s->dev, "\n"); + dev_dbg(dev->dev, "\n"); - mutex_lock(&s->v4l2_lock); + mutex_lock(&dev->v4l2_lock); - if (s->udev) - msi2500_isoc_cleanup(s); + if (dev->udev) + msi2500_isoc_cleanup(dev); - msi2500_cleanup_queued_bufs(s); + msi2500_cleanup_queued_bufs(dev); /* according to tests, at least 700us delay is required */ msleep(20); - if (!msi2500_ctrl_msg(s, CMD_STOP_STREAMING, 0)) { + if (!msi2500_ctrl_msg(dev, CMD_STOP_STREAMING, 0)) { /* sleep USB IF / ADC */ - msi2500_ctrl_msg(s, CMD_WREG, 0x01000003); + msi2500_ctrl_msg(dev, CMD_WREG, 0x01000003); } /* sleep tuner */ - v4l2_subdev_call(s->v4l2_subdev, core, s_power, 0); + v4l2_subdev_call(dev->v4l2_subdev, core, s_power, 0); - mutex_unlock(&s->v4l2_lock); + mutex_unlock(&dev->v4l2_lock); } static struct vb2_ops msi2500_vb2_ops = { @@ -886,13 +908,13 @@ static struct vb2_ops msi2500_vb2_ops = { }; static int msi2500_enum_fmt_sdr_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) + struct v4l2_fmtdesc *f) { - struct msi2500_state *s = video_drvdata(file); + struct msi2500_dev *dev = video_drvdata(file); - dev_dbg(s->dev, "index=%d\n", f->index); + dev_dbg(dev->dev, "index=%d\n", f->index); - if (f->index >= s->num_formats) + if (f->index >= dev->num_formats) return -EINVAL; strlcpy(f->description, formats[f->index].name, sizeof(f->description)); @@ -902,45 +924,45 @@ static int msi2500_enum_fmt_sdr_cap(struct file *file, void *priv, } static int msi2500_g_fmt_sdr_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { - struct msi2500_state *s = video_drvdata(file); + struct msi2500_dev *dev = video_drvdata(file); - dev_dbg(s->dev, "pixelformat fourcc %4.4s\n", - (char *)&s->pixelformat); + dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n", + (char *)&dev->pixelformat); - f->fmt.sdr.pixelformat = s->pixelformat; - f->fmt.sdr.buffersize = s->buffersize; + f->fmt.sdr.pixelformat = dev->pixelformat; + f->fmt.sdr.buffersize = dev->buffersize; memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); return 0; } static int msi2500_s_fmt_sdr_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { - struct msi2500_state *s = video_drvdata(file); - struct vb2_queue *q = &s->vb_queue; + struct msi2500_dev *dev = video_drvdata(file); + struct vb2_queue *q = &dev->vb_queue; int i; - dev_dbg(s->dev, "pixelformat fourcc %4.4s\n", - (char *)&f->fmt.sdr.pixelformat); + dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n", + (char *)&f->fmt.sdr.pixelformat); if (vb2_is_busy(q)) return -EBUSY; memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); - for (i = 0; i < s->num_formats; i++) { + for (i = 0; i < dev->num_formats; i++) { if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { - s->pixelformat = formats[i].pixelformat; - s->buffersize = formats[i].buffersize; + dev->pixelformat = formats[i].pixelformat; + dev->buffersize = formats[i].buffersize; f->fmt.sdr.buffersize = formats[i].buffersize; return 0; } } - s->pixelformat = formats[0].pixelformat; - s->buffersize = formats[0].buffersize; + dev->pixelformat = formats[0].pixelformat; + dev->buffersize = formats[0].buffersize; f->fmt.sdr.pixelformat = formats[0].pixelformat; f->fmt.sdr.buffersize = formats[0].buffersize; @@ -948,16 +970,16 @@ static int msi2500_s_fmt_sdr_cap(struct file *file, void *priv, } static int msi2500_try_fmt_sdr_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { - struct msi2500_state *s = video_drvdata(file); + struct msi2500_dev *dev = video_drvdata(file); int i; - dev_dbg(s->dev, "pixelformat fourcc %4.4s\n", - (char *)&f->fmt.sdr.pixelformat); + dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n", + (char *)&f->fmt.sdr.pixelformat); memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); - for (i = 0; i < s->num_formats; i++) { + for (i = 0; i < dev->num_formats; i++) { if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { f->fmt.sdr.buffersize = formats[i].buffersize; return 0; @@ -971,17 +993,17 @@ static int msi2500_try_fmt_sdr_cap(struct file *file, void *priv, } static int msi2500_s_tuner(struct file *file, void *priv, - const struct v4l2_tuner *v) + const struct v4l2_tuner *v) { - struct msi2500_state *s = video_drvdata(file); + struct msi2500_dev *dev = video_drvdata(file); int ret; - dev_dbg(s->dev, "index=%d\n", v->index); + dev_dbg(dev->dev, "index=%d\n", v->index); if (v->index == 0) ret = 0; else if (v->index == 1) - ret = v4l2_subdev_call(s->v4l2_subdev, tuner, s_tuner, v); + ret = v4l2_subdev_call(dev->v4l2_subdev, tuner, s_tuner, v); else ret = -EINVAL; @@ -990,10 +1012,10 @@ static int msi2500_s_tuner(struct file *file, void *priv, static int msi2500_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct msi2500_state *s = video_drvdata(file); + struct msi2500_dev *dev = video_drvdata(file); int ret; - dev_dbg(s->dev, "index=%d\n", v->index); + dev_dbg(dev->dev, "index=%d\n", v->index); if (v->index == 0) { strlcpy(v->name, "Mirics MSi2500", sizeof(v->name)); @@ -1003,7 +1025,7 @@ static int msi2500_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) v->rangehigh = 15000000; ret = 0; } else if (v->index == 1) { - ret = v4l2_subdev_call(s->v4l2_subdev, tuner, g_tuner, v); + ret = v4l2_subdev_call(dev->v4l2_subdev, tuner, g_tuner, v); } else { ret = -EINVAL; } @@ -1012,19 +1034,19 @@ static int msi2500_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) } static int msi2500_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + struct v4l2_frequency *f) { - struct msi2500_state *s = video_drvdata(file); + struct msi2500_dev *dev = video_drvdata(file); int ret = 0; - dev_dbg(s->dev, "tuner=%d type=%d\n", f->tuner, f->type); + dev_dbg(dev->dev, "tuner=%d type=%d\n", f->tuner, f->type); if (f->tuner == 0) { - f->frequency = s->f_adc; + f->frequency = dev->f_adc; ret = 0; } else if (f->tuner == 1) { f->type = V4L2_TUNER_RF; - ret = v4l2_subdev_call(s->v4l2_subdev, tuner, g_frequency, f); + ret = v4l2_subdev_call(dev->v4l2_subdev, tuner, g_frequency, f); } else { ret = -EINVAL; } @@ -1033,22 +1055,22 @@ static int msi2500_g_frequency(struct file *file, void *priv, } static int msi2500_s_frequency(struct file *file, void *priv, - const struct v4l2_frequency *f) + const struct v4l2_frequency *f) { - struct msi2500_state *s = video_drvdata(file); + struct msi2500_dev *dev = video_drvdata(file); int ret; - dev_dbg(s->dev, "tuner=%d type=%d frequency=%u\n", - f->tuner, f->type, f->frequency); + dev_dbg(dev->dev, "tuner=%d type=%d frequency=%u\n", + f->tuner, f->type, f->frequency); if (f->tuner == 0) { - s->f_adc = clamp_t(unsigned int, f->frequency, - bands[0].rangelow, - bands[0].rangehigh); - dev_dbg(s->dev, "ADC frequency=%u Hz\n", s->f_adc); - ret = msi2500_set_usb_adc(s); + dev->f_adc = clamp_t(unsigned int, f->frequency, + bands[0].rangelow, + bands[0].rangehigh); + dev_dbg(dev->dev, "ADC frequency=%u Hz\n", dev->f_adc); + ret = msi2500_set_usb_adc(dev); } else if (f->tuner == 1) { - ret = v4l2_subdev_call(s->v4l2_subdev, tuner, s_frequency, f); + ret = v4l2_subdev_call(dev->v4l2_subdev, tuner, s_frequency, f); } else { ret = -EINVAL; } @@ -1057,13 +1079,13 @@ static int msi2500_s_frequency(struct file *file, void *priv, } static int msi2500_enum_freq_bands(struct file *file, void *priv, - struct v4l2_frequency_band *band) + struct v4l2_frequency_band *band) { - struct msi2500_state *s = video_drvdata(file); + struct msi2500_dev *dev = video_drvdata(file); int ret; - dev_dbg(s->dev, "tuner=%d type=%d index=%d\n", - band->tuner, band->type, band->index); + dev_dbg(dev->dev, "tuner=%d type=%d index=%d\n", + band->tuner, band->type, band->index); if (band->tuner == 0) { if (band->index >= ARRAY_SIZE(bands)) { @@ -1073,8 +1095,8 @@ static int msi2500_enum_freq_bands(struct file *file, void *priv, ret = 0; } } else if (band->tuner == 1) { - ret = v4l2_subdev_call(s->v4l2_subdev, tuner, - enum_freq_bands, band); + ret = v4l2_subdev_call(dev->v4l2_subdev, tuner, + enum_freq_bands, band); } else { ret = -EINVAL; } @@ -1131,29 +1153,28 @@ static struct video_device msi2500_template = { static void msi2500_video_release(struct v4l2_device *v) { - struct msi2500_state *s = - container_of(v, struct msi2500_state, v4l2_dev); + struct msi2500_dev *dev = container_of(v, struct msi2500_dev, v4l2_dev); - v4l2_ctrl_handler_free(&s->hdl); - v4l2_device_unregister(&s->v4l2_dev); - kfree(s); + v4l2_ctrl_handler_free(&dev->hdl); + v4l2_device_unregister(&dev->v4l2_dev); + kfree(dev); } static int msi2500_transfer_one_message(struct spi_master *master, - struct spi_message *m) + struct spi_message *m) { - struct msi2500_state *s = spi_master_get_devdata(master); + struct msi2500_dev *dev = spi_master_get_devdata(master); struct spi_transfer *t; int ret = 0; u32 data; list_for_each_entry(t, &m->transfers, transfer_list) { - dev_dbg(s->dev, "msg=%*ph\n", t->len, t->tx_buf); + dev_dbg(dev->dev, "msg=%*ph\n", t->len, t->tx_buf); data = 0x09; /* reg 9 is SPI adapter */ data |= ((u8 *)t->tx_buf)[0] << 8; data |= ((u8 *)t->tx_buf)[1] << 16; data |= ((u8 *)t->tx_buf)[2] << 24; - ret = msi2500_ctrl_msg(s, CMD_WREG, data); + ret = msi2500_ctrl_msg(dev, CMD_WREG, data); } m->status = ret; @@ -1162,9 +1183,9 @@ static int msi2500_transfer_one_message(struct spi_master *master, } static int msi2500_probe(struct usb_interface *intf, - const struct usb_device_id *id) + const struct usb_device_id *id) { - struct msi2500_state *s; + struct msi2500_dev *dev; struct v4l2_subdev *sd; struct spi_master *master; int ret; @@ -1175,65 +1196,65 @@ static int msi2500_probe(struct usb_interface *intf, .max_speed_hz = 12000000, }; - s = kzalloc(sizeof(struct msi2500_state), GFP_KERNEL); - if (s == NULL) { - dev_err(&intf->dev, "Could not allocate memory for state\n"); - return -ENOMEM; + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + ret = -ENOMEM; + goto err; } - mutex_init(&s->v4l2_lock); - mutex_init(&s->vb_queue_lock); - spin_lock_init(&s->queued_bufs_lock); - INIT_LIST_HEAD(&s->queued_bufs); - s->dev = &intf->dev; - s->udev = interface_to_usbdev(intf); - s->f_adc = bands[0].rangelow; - s->pixelformat = formats[0].pixelformat; - s->buffersize = formats[0].buffersize; - s->num_formats = NUM_FORMATS; + mutex_init(&dev->v4l2_lock); + mutex_init(&dev->vb_queue_lock); + spin_lock_init(&dev->queued_bufs_lock); + INIT_LIST_HEAD(&dev->queued_bufs); + dev->dev = &intf->dev; + dev->udev = interface_to_usbdev(intf); + dev->f_adc = bands[0].rangelow; + dev->pixelformat = formats[0].pixelformat; + dev->buffersize = formats[0].buffersize; + dev->num_formats = NUM_FORMATS; if (!msi2500_emulated_fmt) - s->num_formats -= 2; + dev->num_formats -= 2; /* Init videobuf2 queue structure */ - s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE; - s->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; - s->vb_queue.drv_priv = s; - s->vb_queue.buf_struct_size = sizeof(struct msi2500_frame_buf); - s->vb_queue.ops = &msi2500_vb2_ops; - s->vb_queue.mem_ops = &vb2_vmalloc_memops; - s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - ret = vb2_queue_init(&s->vb_queue); + dev->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE; + dev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; + dev->vb_queue.drv_priv = dev; + dev->vb_queue.buf_struct_size = sizeof(struct msi2500_frame_buf); + dev->vb_queue.ops = &msi2500_vb2_ops; + dev->vb_queue.mem_ops = &vb2_vmalloc_memops; + dev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + ret = vb2_queue_init(&dev->vb_queue); if (ret) { - dev_err(s->dev, "Could not initialize vb2 queue\n"); + dev_err(dev->dev, "Could not initialize vb2 queue\n"); goto err_free_mem; } /* Init video_device structure */ - s->vdev = msi2500_template; - s->vdev.queue = &s->vb_queue; - s->vdev.queue->lock = &s->vb_queue_lock; - video_set_drvdata(&s->vdev, s); + dev->vdev = msi2500_template; + dev->vdev.queue = &dev->vb_queue; + dev->vdev.queue->lock = &dev->vb_queue_lock; + video_set_drvdata(&dev->vdev, dev); /* Register the v4l2_device structure */ - s->v4l2_dev.release = msi2500_video_release; - ret = v4l2_device_register(&intf->dev, &s->v4l2_dev); + dev->v4l2_dev.release = msi2500_video_release; + ret = v4l2_device_register(&intf->dev, &dev->v4l2_dev); if (ret) { - dev_err(s->dev, "Failed to register v4l2-device (%d)\n", ret); + dev_err(dev->dev, "Failed to register v4l2-device (%d)\n", ret); goto err_free_mem; } /* SPI master adapter */ - master = spi_alloc_master(s->dev, 0); + master = spi_alloc_master(dev->dev, 0); if (master == NULL) { ret = -ENOMEM; goto err_unregister_v4l2_dev; } - s->master = master; + dev->master = master; master->bus_num = 0; master->num_chipselect = 1; master->transfer_one_message = msi2500_transfer_one_message; - spi_master_set_devdata(master, s); + spi_master_set_devdata(master, dev); ret = spi_register_master(master); if (ret) { spi_master_put(master); @@ -1241,57 +1262,57 @@ static int msi2500_probe(struct usb_interface *intf, } /* load v4l2 subdevice */ - sd = v4l2_spi_new_subdev(&s->v4l2_dev, master, &board_info); - s->v4l2_subdev = sd; + sd = v4l2_spi_new_subdev(&dev->v4l2_dev, master, &board_info); + dev->v4l2_subdev = sd; if (sd == NULL) { - dev_err(s->dev, "cannot get v4l2 subdevice\n"); + dev_err(dev->dev, "cannot get v4l2 subdevice\n"); ret = -ENODEV; goto err_unregister_master; } /* Register controls */ - v4l2_ctrl_handler_init(&s->hdl, 0); - if (s->hdl.error) { - ret = s->hdl.error; - dev_err(s->dev, "Could not initialize controls\n"); + v4l2_ctrl_handler_init(&dev->hdl, 0); + if (dev->hdl.error) { + ret = dev->hdl.error; + dev_err(dev->dev, "Could not initialize controls\n"); goto err_free_controls; } /* currently all controls are from subdev */ - v4l2_ctrl_add_handler(&s->hdl, sd->ctrl_handler, NULL); + v4l2_ctrl_add_handler(&dev->hdl, sd->ctrl_handler, NULL); - s->v4l2_dev.ctrl_handler = &s->hdl; - s->vdev.v4l2_dev = &s->v4l2_dev; - s->vdev.lock = &s->v4l2_lock; + dev->v4l2_dev.ctrl_handler = &dev->hdl; + dev->vdev.v4l2_dev = &dev->v4l2_dev; + dev->vdev.lock = &dev->v4l2_lock; - ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1); + ret = video_register_device(&dev->vdev, VFL_TYPE_SDR, -1); if (ret) { - dev_err(s->dev, "Failed to register as video device (%d)\n", - ret); + dev_err(dev->dev, + "Failed to register as video device (%d)\n", ret); goto err_unregister_v4l2_dev; } - dev_info(s->dev, "Registered as %s\n", - video_device_node_name(&s->vdev)); - dev_notice(s->dev, "SDR API is still slightly experimental and functionality changes may follow\n"); - + dev_info(dev->dev, "Registered as %s\n", + video_device_node_name(&dev->vdev)); + dev_notice(dev->dev, + "SDR API is still slightly experimental and functionality changes may follow\n"); return 0; - err_free_controls: - v4l2_ctrl_handler_free(&s->hdl); + v4l2_ctrl_handler_free(&dev->hdl); err_unregister_master: - spi_unregister_master(s->master); + spi_unregister_master(dev->master); err_unregister_v4l2_dev: - v4l2_device_unregister(&s->v4l2_dev); + v4l2_device_unregister(&dev->v4l2_dev); err_free_mem: - kfree(s); + kfree(dev); +err: return ret; } /* USB device ID list */ static struct usb_device_id msi2500_id_table[] = { - { USB_DEVICE(0x1df7, 0x2500) }, /* Mirics MSi3101 SDR Dongle */ - { USB_DEVICE(0x2040, 0xd300) }, /* Hauppauge WinTV 133559 LF */ - { } + {USB_DEVICE(0x1df7, 0x2500)}, /* Mirics MSi3101 SDR Dongle */ + {USB_DEVICE(0x2040, 0xd300)}, /* Hauppauge WinTV 133559 LF */ + {} }; MODULE_DEVICE_TABLE(usb, msi2500_id_table); diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.c b/drivers/media/usb/pvrusb2/pvrusb2-context.c index 924fc4c..fd888a6 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-context.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-context.c @@ -398,7 +398,8 @@ int pvr2_channel_claim_stream(struct pvr2_channel *cp, if (!sp) break; sp->user = cp; cp->stream = sp; - } while (0); pvr2_context_exit(cp->mc_head); + } while (0); + pvr2_context_exit(cp->mc_head); return code; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index 930593d..0533ef2 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -2602,14 +2602,16 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, "Error registering with v4l core, giving up"); goto fail; } - mutex_lock(&pvr2_unit_mtx); do { + mutex_lock(&pvr2_unit_mtx); + do { for (idx = 0; idx < PVR_NUM; idx++) { if (unit_pointers[idx]) continue; hdw->unit_number = idx; unit_pointers[idx] = hdw; break; } - } while (0); mutex_unlock(&pvr2_unit_mtx); + } while (0); + mutex_unlock(&pvr2_unit_mtx); cnt1 = 0; cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"pvrusb2"); @@ -2730,13 +2732,15 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw) pvr2_i2c_core_done(hdw); v4l2_device_unregister(&hdw->v4l2_dev); pvr2_hdw_remove_usb_stuff(hdw); - mutex_lock(&pvr2_unit_mtx); do { + mutex_lock(&pvr2_unit_mtx); + do { if ((hdw->unit_number >= 0) && (hdw->unit_number < PVR_NUM) && (unit_pointers[hdw->unit_number] == hdw)) { unit_pointers[hdw->unit_number] = NULL; } - } while (0); mutex_unlock(&pvr2_unit_mtx); + } while (0); + mutex_unlock(&pvr2_unit_mtx); kfree(hdw->controls); kfree(hdw->mpeg_ctrl_info); kfree(hdw); @@ -2958,14 +2962,17 @@ static void pvr2_subdev_update(struct pvr2_hdw *hdw) } if (hdw->res_hor_dirty || hdw->res_ver_dirty || hdw->force_dirty) { - struct v4l2_mbus_framefmt fmt; - memset(&fmt, 0, sizeof(fmt)); - fmt.width = hdw->res_hor_val; - fmt.height = hdw->res_ver_val; - fmt.code = MEDIA_BUS_FMT_FIXED; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + format.format.width = hdw->res_hor_val; + format.format.height = hdw->res_ver_val; + format.format.code = MEDIA_BUS_FMT_FIXED; pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_size(%dx%d)", - fmt.width, fmt.height); - v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_mbus_fmt, &fmt); + format.format.width, format.format.height); + v4l2_device_call_all(&hdw->v4l2_dev, 0, pad, set_fmt, + NULL, &format); } if (hdw->srate_dirty || hdw->force_dirty) { @@ -3343,14 +3350,16 @@ struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *hp) void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw) { int nr = pvr2_hdw_get_unit_number(hdw); - LOCK_TAKE(hdw->big_lock); do { + LOCK_TAKE(hdw->big_lock); + do { printk(KERN_INFO "pvrusb2: ================= START STATUS CARD #%d =================\n", nr); v4l2_device_call_all(&hdw->v4l2_dev, 0, core, log_status); pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:"); cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2"); pvr2_hdw_state_log_state(hdw); printk(KERN_INFO "pvrusb2: ================== END STATUS CARD #%d ==================\n", nr); - } while (0); LOCK_GIVE(hdw->big_lock); + } while (0); + LOCK_GIVE(hdw->big_lock); } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.c b/drivers/media/usb/pvrusb2/pvrusb2-io.c index 0c08f22..d860344 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-io.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-io.c @@ -514,12 +514,14 @@ void pvr2_stream_set_callback(struct pvr2_stream *sp, void *data) { unsigned long irq_flags; - mutex_lock(&sp->mutex); do { + mutex_lock(&sp->mutex); + do { spin_lock_irqsave(&sp->list_lock,irq_flags); sp->callback_data = data; sp->callback_func = func; spin_unlock_irqrestore(&sp->list_lock,irq_flags); - } while(0); mutex_unlock(&sp->mutex); + } while(0); + mutex_unlock(&sp->mutex); } void pvr2_stream_get_stats(struct pvr2_stream *sp, @@ -554,10 +556,12 @@ int pvr2_stream_set_buffer_count(struct pvr2_stream *sp,unsigned int cnt) { int ret; if (sp->buffer_target_count == cnt) return 0; - mutex_lock(&sp->mutex); do { + mutex_lock(&sp->mutex); + do { sp->buffer_target_count = cnt; ret = pvr2_stream_achieve_buffer_count(sp); - } while(0); mutex_unlock(&sp->mutex); + } while(0); + mutex_unlock(&sp->mutex); return ret; } @@ -590,7 +594,8 @@ int pvr2_stream_get_ready_count(struct pvr2_stream *sp) void pvr2_stream_kill(struct pvr2_stream *sp) { struct pvr2_buffer *bp; - mutex_lock(&sp->mutex); do { + mutex_lock(&sp->mutex); + do { pvr2_stream_internal_flush(sp); while ((bp = pvr2_stream_get_ready_buffer(sp)) != NULL) { pvr2_buffer_set_idle(bp); @@ -598,7 +603,8 @@ void pvr2_stream_kill(struct pvr2_stream *sp) if (sp->buffer_total_count != sp->buffer_target_count) { pvr2_stream_achieve_buffer_count(sp); } - } while(0); mutex_unlock(&sp->mutex); + } while(0); + mutex_unlock(&sp->mutex); } int pvr2_buffer_queue(struct pvr2_buffer *bp) @@ -612,7 +618,8 @@ int pvr2_buffer_queue(struct pvr2_buffer *bp) struct pvr2_stream *sp; if (!bp) return -EINVAL; sp = bp->stream; - mutex_lock(&sp->mutex); do { + mutex_lock(&sp->mutex); + do { pvr2_buffer_wipe(bp); if (!sp->dev) { ret = -EIO; @@ -636,7 +643,8 @@ int pvr2_buffer_queue(struct pvr2_buffer *bp) buffer_complete, bp); usb_submit_urb(bp->purb,GFP_KERNEL); - } while(0); mutex_unlock(&sp->mutex); + } while(0); + mutex_unlock(&sp->mutex); return ret; } @@ -647,7 +655,8 @@ int pvr2_buffer_set_buffer(struct pvr2_buffer *bp,void *ptr,unsigned int cnt) struct pvr2_stream *sp; if (!bp) return -EINVAL; sp = bp->stream; - mutex_lock(&sp->mutex); do { + mutex_lock(&sp->mutex); + do { spin_lock_irqsave(&sp->list_lock,irq_flags); if (bp->state != pvr2_buffer_state_idle) { ret = -EPERM; @@ -664,7 +673,8 @@ int pvr2_buffer_set_buffer(struct pvr2_buffer *bp,void *ptr,unsigned int cnt) bp->stream->i_bcount,bp->stream->i_count); } spin_unlock_irqrestore(&sp->list_lock,irq_flags); - } while(0); mutex_unlock(&sp->mutex); + } while(0); + mutex_unlock(&sp->mutex); return ret; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ioread.c b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c index cd995b5..614d557 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-ioread.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c @@ -205,7 +205,8 @@ int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp) unsigned int idx; struct pvr2_buffer *bp; - mutex_lock(&cp->mutex); do { + mutex_lock(&cp->mutex); + do { if (cp->stream) { pvr2_trace(PVR2_TRACE_START_STOP, "/*---TRACE_READ---*/" @@ -235,7 +236,8 @@ int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp) } cp->stream = sp; } - } while (0); mutex_unlock(&cp->mutex); + } while (0); + mutex_unlock(&cp->mutex); return 0; } @@ -245,13 +247,15 @@ int pvr2_ioread_set_enabled(struct pvr2_ioread *cp,int fl) int ret = 0; if ((!fl) == (!(cp->enabled))) return ret; - mutex_lock(&cp->mutex); do { + mutex_lock(&cp->mutex); + do { if (fl) { ret = pvr2_ioread_start(cp); } else { pvr2_ioread_stop(cp); } - } while (0); mutex_unlock(&cp->mutex); + } while (0); + mutex_unlock(&cp->mutex); return ret; } @@ -315,7 +319,8 @@ static void pvr2_ioread_filter(struct pvr2_ioread *cp) // Search the stream for our synchronization key. This is made // complicated by the fact that in order to be honest with // ourselves here we must search across buffer boundaries... - mutex_lock(&cp->mutex); while (1) { + mutex_lock(&cp->mutex); + while (1) { // Ensure we have a buffer if (!pvr2_ioread_get_buffer(cp)) break; if (!cp->c_data_len) break; @@ -362,7 +367,8 @@ static void pvr2_ioread_filter(struct pvr2_ioread *cp) } continue; // (for clarity) - } mutex_unlock(&cp->mutex); + } + mutex_unlock(&cp->mutex); } int pvr2_ioread_avail(struct pvr2_ioread *cp) @@ -422,7 +428,8 @@ int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt) cp->stream_running = !0; - mutex_lock(&cp->mutex); do { + mutex_lock(&cp->mutex); + do { // Suck data out of the buffers and copy to the user copied_cnt = 0; @@ -480,7 +487,8 @@ int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt) } } - } while (0); mutex_unlock(&cp->mutex); + } while (0); + mutex_unlock(&cp->mutex); if (!ret) { if (copied_cnt) { diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 749ad56..4d313ed 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -500,6 +500,7 @@ static const struct v4l2_ioctl_ops stk1160_ioctl_ops = { .vidioc_dqbuf = vb2_ioctl_dqbuf, .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_expbuf = vb2_ioctl_expbuf, .vidioc_log_status = v4l2_ctrl_log_status, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, @@ -645,7 +646,7 @@ int stk1160_vb2_setup(struct stk1160 *dev) q = &dev->vb_vidq; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR; + q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF; q->drv_priv = dev; q->buf_struct_size = sizeof(struct stk1160_buffer); q->ops = &stk1160_video_qops; diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 77ce9ef..fa5e8bd 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -621,7 +621,7 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev) dev->isoc_in.maxsize, size); - if (!dev->urb_buffer && tm6000_alloc_urb_buffers(dev) < 0) { + if (tm6000_alloc_urb_buffers(dev) < 0) { tm6000_err("cannot allocate memory for urb buffers\n"); /* call free, as some buffers might have been allocated */ @@ -714,8 +714,7 @@ static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf) struct tm6000_core *dev = fh->dev; unsigned long flags; - if (in_interrupt()) - BUG(); + BUG_ON(in_interrupt()); /* 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, diff --git a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c index cef7a00..d52d4a8 100644 --- a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c @@ -111,8 +111,8 @@ struct ttusb { int last_filter; u8 c; /* transaction counter, wraps around... */ - fe_sec_tone_mode_t tone; - fe_sec_voltage_t voltage; + enum fe_sec_tone_mode tone; + enum fe_sec_voltage voltage; int mux_state; // 0..2 - MuxSyncWord, 3 - nMuxPacks, 4 - muxpack u8 mux_npacks; @@ -511,7 +511,8 @@ static int ttusb_update_lnb(struct ttusb *ttusb) return err; } -static int ttusb_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int ttusb_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; @@ -520,7 +521,7 @@ static int ttusb_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) } #ifdef TTUSB_TONE -static int ttusb_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int ttusb_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) { struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index 15ab584..322b53a 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -1431,8 +1431,8 @@ static int ttusb_dec_init_stb(struct ttusb_dec *dec) __func__, model); return -ENOENT; } - if (version >= 0x01770000) - dec->can_playback = 1; + if (version >= 0x01770000) + dec->can_playback = 1; } return 0; } diff --git a/drivers/media/usb/ttusb-dec/ttusbdecfe.c b/drivers/media/usb/ttusb-dec/ttusbdecfe.c index 9c29552..8781335 100644 --- a/drivers/media/usb/ttusb-dec/ttusbdecfe.c +++ b/drivers/media/usb/ttusb-dec/ttusbdecfe.c @@ -39,7 +39,7 @@ struct ttusbdecfe_state { static int ttusbdecfe_dvbs_read_status(struct dvb_frontend *fe, - fe_status_t *status) + enum fe_status *status) { *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; @@ -48,7 +48,7 @@ static int ttusbdecfe_dvbs_read_status(struct dvb_frontend *fe, static int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe, - fe_status_t *status) + enum fe_status *status) { struct ttusbdecfe_state* state = fe->demodulator_priv; u8 b[] = { 0x00, 0x00, 0x00, 0x00, @@ -169,7 +169,8 @@ static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struc } -static int ttusbdecfe_dvbs_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int ttusbdecfe_dvbs_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; @@ -179,7 +180,8 @@ static int ttusbdecfe_dvbs_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t } -static int ttusbdecfe_dvbs_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int ttusbdecfe_dvbs_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 9d3525f..08fb0f2 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -599,15 +599,18 @@ static struct v4l2_file_operations usbtv_fops = { }; static int usbtv_queue_setup(struct vb2_queue *vq, - const struct v4l2_format *v4l_fmt, unsigned int *nbuffers, + const struct v4l2_format *fmt, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { struct usbtv *usbtv = vb2_get_drv_priv(vq); + unsigned size = USBTV_CHUNK * usbtv->n_chunks * 2 * sizeof(u32); - if (*nbuffers < 2) - *nbuffers = 2; + if (vq->num_buffers + *nbuffers < 2) + *nbuffers = 2 - vq->num_buffers; *nplanes = 1; - sizes[0] = USBTV_CHUNK * usbtv->n_chunks * 2 * sizeof(u32); + if (fmt && fmt->fmt.pix.sizeimage < size) + return -EINVAL; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size; return 0; } @@ -635,6 +638,7 @@ static int usbtv_start_streaming(struct vb2_queue *vq, unsigned int count) if (usbtv->udev == NULL) return -ENODEV; + usbtv->sequence = 0; return usbtv_start(usbtv); } diff --git a/drivers/media/usb/usbvision/usbvision-core.c b/drivers/media/usb/usbvision/usbvision-core.c index 44b0c28..7c04ef6 100644 --- a/drivers/media/usb/usbvision/usbvision-core.c +++ b/drivers/media/usb/usbvision/usbvision-core.c @@ -2390,8 +2390,8 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision) /* Submit all URBs */ for (buf_idx = 0; buf_idx < USBVISION_NUMSBUF; buf_idx++) { - err_code = usb_submit_urb(usbvision->sbuf[buf_idx].urb, - GFP_KERNEL); + err_code = usb_submit_urb(usbvision->sbuf[buf_idx].urb, + GFP_KERNEL); if (err_code) { dev_err(&usbvision->dev->dev, "%s: usb_submit_urb(%d) failed: error %d\n", diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index 12b403e..1c6d31f 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -1061,13 +1061,24 @@ static ssize_t usbvision_read(struct file *file, char __user *buf, __func__, (unsigned long)count, frame->bytes_read); - /* For now, forget the frame if it has not been read in one shot. */ -/* if (frame->bytes_read >= frame->scanlength) {*/ /* All data has been read */ +#if 1 + /* + * FIXME: + * For now, forget the frame if it has not been read in one shot. + */ + frame->bytes_read = 0; + + /* Mark it as available to be used again. */ + frame->grabstate = frame_state_unused; +#else + if (frame->bytes_read >= frame->scanlength) { + /* All data has been read */ frame->bytes_read = 0; /* Mark it as available to be used again. */ frame->grabstate = frame_state_unused; -/* } */ + } +#endif return count; } diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 5970dd6..4b5b3e8 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1967,8 +1967,6 @@ static void uvc_disconnect(struct usb_interface *intf) UVC_SC_VIDEOSTREAMING) return; - dev->state |= UVC_DEV_DISCONNECTED; - uvc_unregister_video(dev); } diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 87a19f3..f16b9b4 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -270,6 +270,18 @@ int uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) return ret; } +int uvc_export_buffer(struct uvc_video_queue *queue, + struct v4l2_exportbuffer *exp) +{ + int ret; + + mutex_lock(&queue->mutex); + ret = vb2_expbuf(&queue->queue, exp); + mutex_unlock(&queue->mutex); + + return ret; +} + int uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf, int nonblocking) { diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index c4b1ac6..2764f43 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -483,9 +483,6 @@ static int uvc_v4l2_open(struct file *file) uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n"); stream = video_drvdata(file); - if (stream->dev->state & UVC_DEV_DISCONNECTED) - return -ENODEV; - ret = usb_autopm_get_interface(stream->dev->intf); if (ret < 0) return ret; @@ -723,6 +720,18 @@ static int uvc_ioctl_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) return uvc_queue_buffer(&stream->queue, buf); } +static int uvc_ioctl_expbuf(struct file *file, void *fh, + struct v4l2_exportbuffer *exp) +{ + struct uvc_fh *handle = fh; + struct uvc_streaming *stream = handle->stream; + + if (!uvc_has_privileges(handle)) + return -EBUSY; + + return uvc_export_buffer(&stream->queue, exp); +} + static int uvc_ioctl_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) { struct uvc_fh *handle = fh; @@ -1478,6 +1487,7 @@ const struct v4l2_ioctl_ops uvc_ioctl_ops = { .vidioc_reqbufs = uvc_ioctl_reqbufs, .vidioc_querybuf = uvc_ioctl_querybuf, .vidioc_qbuf = uvc_ioctl_qbuf, + .vidioc_expbuf = uvc_ioctl_expbuf, .vidioc_dqbuf = uvc_ioctl_dqbuf, .vidioc_create_bufs = uvc_ioctl_create_bufs, .vidioc_streamon = uvc_ioctl_streamon, diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 20ccc9d..f839654 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -119,6 +119,14 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, ctrl->dwMaxVideoFrameSize = frame->dwMaxVideoFrameBufferSize; + /* The "TOSHIBA Web Camera - 5M" Chicony device (04f2:b50b) seems to + * compute the bandwidth on 16 bits and erroneously sign-extend it to + * 32 bits, resulting in a huge bandwidth value. Detect and fix that + * condition by setting the 16 MSBs to 0 when they're all equal to 1. + */ + if ((ctrl->dwMaxPayloadTransferSize & 0xffff0000) == 0xffff0000) + ctrl->dwMaxPayloadTransferSize &= ~0xffff0000; + if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) && stream->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH && stream->intf->num_altsetting > 1) { diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 1b594c2..816dd1a 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -517,10 +517,6 @@ struct uvc_streaming { } clock; }; -enum uvc_device_state { - UVC_DEV_DISCONNECTED = 1, -}; - struct uvc_device { struct usb_device *udev; struct usb_interface *intf; @@ -529,7 +525,6 @@ struct uvc_device { int intfnum; char name[32]; - enum uvc_device_state state; struct mutex lock; /* Protects users */ unsigned int users; atomic_t nmappings; @@ -635,6 +630,8 @@ extern int uvc_create_buffers(struct uvc_video_queue *queue, struct v4l2_create_buffers *v4l2_cb); extern int uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf); +extern int uvc_export_buffer(struct uvc_video_queue *queue, + struct v4l2_exportbuffer *exp); extern int uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf, int nonblocking); extern int uvc_queue_streamon(struct uvc_video_queue *queue, diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index ca85031..7433ba5 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -377,8 +377,7 @@ static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer *buf) { _DBG("%s\n", __func__); - if (in_interrupt()) - BUG(); + BUG_ON(in_interrupt()); videobuf_vmalloc_free(&buf->vb); buf->vb.state = VIDEOBUF_NEEDS_INIT; diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index ba7e21a..f7a01a7 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -89,7 +89,7 @@ config VIDEOBUF2_VMALLOC config VIDEOBUF2_DMA_SG tristate - #depends on HAS_DMA + depends on HAS_DMA select VIDEOBUF2_CORE select VIDEOBUF2_MEMOPS diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index c0e9638..04dc71e 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -25,6 +25,7 @@ #include <linux/videodev2.h> #include <linux/v4l2-dv-timings.h> #include <media/v4l2-dv-timings.h> +#include <linux/math64.h> MODULE_AUTHOR("Hans Verkuil"); MODULE_DESCRIPTION("V4L2 DV Timings Helper Functions"); @@ -261,6 +262,8 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, htot = V4L2_DV_BT_FRAME_WIDTH(bt); vtot = V4L2_DV_BT_FRAME_HEIGHT(bt); + if (bt->interlaced) + vtot /= 2; if (prefix == NULL) prefix = ""; @@ -281,6 +284,11 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, dev_prefix, bt->vfrontporch, (bt->polarities & V4L2_DV_VSYNC_POS_POL) ? "+" : "-", bt->vsync, bt->vbackporch); + if (bt->interlaced) + pr_info("%s: vertical bottom field: fp = %u, %ssync = %u, bp = %u\n", + dev_prefix, bt->il_vfrontporch, + (bt->polarities & V4L2_DV_VSYNC_POS_POL) ? "+" : "-", + bt->il_vsync, bt->il_vbackporch); pr_info("%s: pixelclock: %llu\n", dev_prefix, bt->pixelclock); pr_info("%s: flags (0x%x):%s%s%s%s%s\n", dev_prefix, bt->flags, (bt->flags & V4L2_DV_FL_REDUCED_BLANKING) ? @@ -313,6 +321,7 @@ EXPORT_SYMBOL_GPL(v4l2_print_dv_timings); #define CVT_MIN_V_BPORCH 7 /* lines */ #define CVT_MIN_V_PORCH_RND 3 /* lines */ #define CVT_MIN_VSYNC_BP 550 /* min time of vsync + back porch (us) */ +#define CVT_HSYNC_PERCENT 8 /* nominal hsync as percentage of line */ /* Normal blanking for CVT uses GTF to calculate horizontal blanking */ #define CVT_CELL_GRAN 8 /* character cell granularity */ @@ -337,6 +346,7 @@ EXPORT_SYMBOL_GPL(v4l2_print_dv_timings); * @vsync - the height of the vertical sync in lines. * @polarities - the horizontal and vertical polarities (same as struct * v4l2_bt_timings polarities). + * @interlaced - if this flag is true, it indicates interlaced format * @fmt - the resulting timings. * * This function will attempt to detect if the given values correspond to a @@ -348,7 +358,7 @@ EXPORT_SYMBOL_GPL(v4l2_print_dv_timings); * detection function. */ bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync, - u32 polarities, struct v4l2_dv_timings *fmt) + u32 polarities, bool interlaced, struct v4l2_dv_timings *fmt) { int v_fp, v_bp, h_fp, h_bp, hsync; int frame_width, image_height, image_width; @@ -365,22 +375,32 @@ bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync, else return false; + if (hfreq == 0) + return false; + /* Vertical */ if (reduced_blanking) { v_fp = CVT_RB_V_FPORCH; - v_bp = (CVT_RB_MIN_V_BLANK * hfreq + 1999999) / 1000000; + v_bp = (CVT_RB_MIN_V_BLANK * hfreq) / 1000000 + 1; v_bp -= vsync + v_fp; if (v_bp < CVT_RB_MIN_V_BPORCH) v_bp = CVT_RB_MIN_V_BPORCH; } else { v_fp = CVT_MIN_V_PORCH_RND; - v_bp = (CVT_MIN_VSYNC_BP * hfreq + 1999999) / 1000000 - vsync; + v_bp = (CVT_MIN_VSYNC_BP * hfreq) / 1000000 + 1 - vsync; if (v_bp < CVT_MIN_V_BPORCH) v_bp = CVT_MIN_V_BPORCH; } - image_height = (frame_height - v_fp - vsync - v_bp + 1) & ~0x1; + + if (interlaced) + image_height = (frame_height - 2 * v_fp - 2 * vsync - 2 * v_bp) & ~0x1; + else + image_height = (frame_height - v_fp - vsync - v_bp + 1) & ~0x1; + + if (image_height < 0) + return false; /* Aspect ratio based on vsync */ switch (vsync) { @@ -436,8 +456,8 @@ bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync, h_bp = h_blank / 2; frame_width = image_width + h_blank; - hsync = (frame_width * 8 + 50) / 100; - hsync = hsync - hsync % CVT_CELL_GRAN; + hsync = frame_width * CVT_HSYNC_PERCENT / 100; + hsync = (hsync / CVT_CELL_GRAN) * CVT_CELL_GRAN; h_fp = h_blank - hsync - h_bp; } @@ -450,11 +470,27 @@ bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync, fmt->bt.hsync = hsync; fmt->bt.vsync = vsync; fmt->bt.hbackporch = frame_width - image_width - h_fp - hsync; - fmt->bt.vbackporch = frame_height - image_height - v_fp - vsync; + + if (!interlaced) { + fmt->bt.vbackporch = frame_height - image_height - v_fp - vsync; + fmt->bt.interlaced = V4L2_DV_PROGRESSIVE; + } else { + fmt->bt.vbackporch = (frame_height - image_height - 2 * v_fp - + 2 * vsync) / 2; + fmt->bt.il_vbackporch = frame_height - image_height - 2 * v_fp - + 2 * vsync - fmt->bt.vbackporch; + fmt->bt.il_vfrontporch = v_fp; + fmt->bt.il_vsync = vsync; + fmt->bt.flags |= V4L2_DV_FL_HALF_LINE; + fmt->bt.interlaced = V4L2_DV_INTERLACED; + } + fmt->bt.pixelclock = pix_clk; fmt->bt.standards = V4L2_DV_BT_STD_CVT; + if (reduced_blanking) fmt->bt.flags |= V4L2_DV_FL_REDUCED_BLANKING; + return true; } EXPORT_SYMBOL_GPL(v4l2_detect_cvt); @@ -493,6 +529,7 @@ EXPORT_SYMBOL_GPL(v4l2_detect_cvt); * @vsync - the height of the vertical sync in lines. * @polarities - the horizontal and vertical polarities (same as struct * v4l2_bt_timings polarities). + * @interlaced - if this flag is true, it indicates interlaced format * @aspect - preferred aspect ratio. GTF has no method of determining the * aspect ratio in order to derive the image width from the * image height, so it has to be passed explicitly. Usually @@ -508,6 +545,7 @@ bool v4l2_detect_gtf(unsigned frame_height, unsigned hfreq, unsigned vsync, u32 polarities, + bool interlaced, struct v4l2_fract aspect, struct v4l2_dv_timings *fmt) { @@ -527,10 +565,19 @@ bool v4l2_detect_gtf(unsigned frame_height, else return false; + if (hfreq == 0) + return false; + /* Vertical */ v_fp = GTF_V_FP; - v_bp = (GTF_MIN_VSYNC_BP * hfreq + 999999) / 1000000 - vsync; - image_height = (frame_height - v_fp - vsync - v_bp + 1) & ~0x1; + v_bp = (GTF_MIN_VSYNC_BP * hfreq + 500000) / 1000000 - vsync; + if (interlaced) + image_height = (frame_height - 2 * v_fp - 2 * vsync - 2 * v_bp) & ~0x1; + else + image_height = (frame_height - v_fp - vsync - v_bp + 1) & ~0x1; + + if (image_height < 0) + return false; if (aspect.numerator == 0 || aspect.denominator == 0) { aspect.numerator = 16; @@ -540,25 +587,35 @@ bool v4l2_detect_gtf(unsigned frame_height, image_width = (image_width + GTF_CELL_GRAN/2) & ~(GTF_CELL_GRAN - 1); /* Horizontal */ - if (default_gtf) - h_blank = ((image_width * GTF_D_C_PRIME * hfreq) - - (image_width * GTF_D_M_PRIME * 1000) + - (hfreq * (100 - GTF_D_C_PRIME) + GTF_D_M_PRIME * 1000) / 2) / - (hfreq * (100 - GTF_D_C_PRIME) + GTF_D_M_PRIME * 1000); - else - h_blank = ((image_width * GTF_S_C_PRIME * hfreq) - - (image_width * GTF_S_M_PRIME * 1000) + - (hfreq * (100 - GTF_S_C_PRIME) + GTF_S_M_PRIME * 1000) / 2) / - (hfreq * (100 - GTF_S_C_PRIME) + GTF_S_M_PRIME * 1000); + if (default_gtf) { + u64 num; + u32 den; + + num = ((image_width * GTF_D_C_PRIME * (u64)hfreq) - + ((u64)image_width * GTF_D_M_PRIME * 1000)); + den = (hfreq * (100 - GTF_D_C_PRIME) + GTF_D_M_PRIME * 1000) * + (2 * GTF_CELL_GRAN); + h_blank = div_u64((num + (den >> 1)), den); + h_blank *= (2 * GTF_CELL_GRAN); + } else { + u64 num; + u32 den; + + num = ((image_width * GTF_S_C_PRIME * (u64)hfreq) - + ((u64)image_width * GTF_S_M_PRIME * 1000)); + den = (hfreq * (100 - GTF_S_C_PRIME) + GTF_S_M_PRIME * 1000) * + (2 * GTF_CELL_GRAN); + h_blank = div_u64((num + (den >> 1)), den); + h_blank *= (2 * GTF_CELL_GRAN); + } - h_blank = h_blank - h_blank % (2 * GTF_CELL_GRAN); frame_width = image_width + h_blank; pix_clk = (image_width + h_blank) * hfreq; pix_clk = pix_clk / GTF_PXL_CLK_GRAN * GTF_PXL_CLK_GRAN; hsync = (frame_width * 8 + 50) / 100; - hsync = hsync - hsync % GTF_CELL_GRAN; + hsync = ((hsync + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN) * GTF_CELL_GRAN; h_fp = h_blank / 2 - hsync; @@ -571,11 +628,27 @@ bool v4l2_detect_gtf(unsigned frame_height, fmt->bt.hsync = hsync; fmt->bt.vsync = vsync; fmt->bt.hbackporch = frame_width - image_width - h_fp - hsync; - fmt->bt.vbackporch = frame_height - image_height - v_fp - vsync; + + if (!interlaced) { + fmt->bt.vbackporch = frame_height - image_height - v_fp - vsync; + fmt->bt.interlaced = V4L2_DV_PROGRESSIVE; + } else { + fmt->bt.vbackporch = (frame_height - image_height - 2 * v_fp - + 2 * vsync) / 2; + fmt->bt.il_vbackporch = frame_height - image_height - 2 * v_fp - + 2 * vsync - fmt->bt.vbackporch; + fmt->bt.il_vfrontporch = v_fp; + fmt->bt.il_vsync = vsync; + fmt->bt.flags |= V4L2_DV_FL_HALF_LINE; + fmt->bt.interlaced = V4L2_DV_INTERLACED; + } + fmt->bt.pixelclock = pix_clk; fmt->bt.standards = V4L2_DV_BT_STD_GTF; + if (!default_gtf) fmt->bt.flags |= V4L2_DV_FL_REDUCED_BLANKING; + return true; } EXPORT_SYMBOL_GPL(v4l2_detect_gtf); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index aa407cb..85de455 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -142,6 +142,7 @@ const char *v4l2_field_names[] = { EXPORT_SYMBOL(v4l2_field_names); const char *v4l2_type_names[] = { + [0] = "0", [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "vid-cap", [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "vid-overlay", [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "vid-out", @@ -257,7 +258,8 @@ static void v4l_print_format(const void *arg, bool write_only) pr_cont(", width=%u, height=%u, " "pixelformat=%c%c%c%c, field=%s, " "bytesperline=%u, sizeimage=%u, colorspace=%d, " - "flags=0x%x, ycbcr_enc=%u, quantization=%u\n", + "flags=0x%x, ycbcr_enc=%u, quantization=%u, " + "xfer_func=%u\n", pix->width, pix->height, (pix->pixelformat & 0xff), (pix->pixelformat >> 8) & 0xff, @@ -266,7 +268,7 @@ static void v4l_print_format(const void *arg, bool write_only) prt_names(pix->field, v4l2_field_names), pix->bytesperline, pix->sizeimage, pix->colorspace, pix->flags, pix->ycbcr_enc, - pix->quantization); + pix->quantization, pix->xfer_func); break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: @@ -274,7 +276,7 @@ static void v4l_print_format(const void *arg, bool write_only) pr_cont(", width=%u, height=%u, " "format=%c%c%c%c, field=%s, " "colorspace=%d, num_planes=%u, flags=0x%x, " - "ycbcr_enc=%u, quantization=%u\n", + "ycbcr_enc=%u, quantization=%u, xfer_func=%u\n", mp->width, mp->height, (mp->pixelformat & 0xff), (mp->pixelformat >> 8) & 0xff, @@ -282,7 +284,7 @@ static void v4l_print_format(const void *arg, bool write_only) (mp->pixelformat >> 24) & 0xff, prt_names(mp->field, v4l2_field_names), mp->colorspace, mp->num_planes, mp->flags, - mp->ycbcr_enc, mp->quantization); + mp->ycbcr_enc, mp->quantization, mp->xfer_func); for (i = 0; i < mp->num_planes; i++) printk(KERN_DEBUG "plane %u: bytesperline=%u sizeimage=%u\n", i, mp->plane_fmt[i].bytesperline, @@ -1103,6 +1105,183 @@ static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops, return ops->vidioc_enum_output(file, fh, p); } +static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) +{ + const unsigned sz = sizeof(fmt->description); + const char *descr = NULL; + u32 flags = 0; + + /* + * We depart from the normal coding style here since the descriptions + * should be aligned so it is easy to see which descriptions will be + * longer than 31 characters (the max length for a description). + * And frankly, this is easier to read anyway. + * + * Note that gcc will use O(log N) comparisons to find the right case. + */ + switch (fmt->pixelformat) { + /* Max description length mask: descr = "0123456789012345678901234567890" */ + case V4L2_PIX_FMT_RGB332: descr = "8-bit RGB 3-3-2"; break; + case V4L2_PIX_FMT_RGB444: descr = "16-bit A/XRGB 4-4-4-4"; break; + case V4L2_PIX_FMT_ARGB444: descr = "16-bit ARGB 4-4-4-4"; break; + case V4L2_PIX_FMT_XRGB444: descr = "16-bit XRGB 4-4-4-4"; break; + case V4L2_PIX_FMT_RGB555: descr = "16-bit A/XRGB 1-5-5-5"; break; + case V4L2_PIX_FMT_ARGB555: descr = "16-bit ARGB 1-5-5-5"; break; + case V4L2_PIX_FMT_XRGB555: descr = "16-bit XRGB 1-5-5-5"; break; + case V4L2_PIX_FMT_RGB565: descr = "16-bit RGB 5-6-5"; break; + case V4L2_PIX_FMT_RGB555X: descr = "16-bit A/XRGB 1-5-5-5 BE"; break; + case V4L2_PIX_FMT_ARGB555X: descr = "16-bit ARGB 1-5-5-5 BE"; break; + case V4L2_PIX_FMT_XRGB555X: descr = "16-bit XRGB 1-5-5-5 BE"; break; + case V4L2_PIX_FMT_RGB565X: descr = "16-bit RGB 5-6-5 BE"; break; + case V4L2_PIX_FMT_BGR666: descr = "18-bit BGRX 6-6-6-14"; break; + case V4L2_PIX_FMT_BGR24: descr = "24-bit BGR 8-8-8"; break; + case V4L2_PIX_FMT_RGB24: descr = "24-bit RGB 8-8-8"; break; + case V4L2_PIX_FMT_BGR32: descr = "32-bit BGRA/X 8-8-8-8"; break; + case V4L2_PIX_FMT_ABGR32: descr = "32-bit BGRA 8-8-8-8"; break; + case V4L2_PIX_FMT_XBGR32: descr = "32-bit BGRX 8-8-8-8"; break; + case V4L2_PIX_FMT_RGB32: descr = "32-bit A/XRGB 8-8-8-8"; break; + case V4L2_PIX_FMT_ARGB32: descr = "32-bit ARGB 8-8-8-8"; break; + case V4L2_PIX_FMT_XRGB32: descr = "32-bit XRGB 8-8-8-8"; break; + case V4L2_PIX_FMT_GREY: descr = "8-bit Greyscale"; break; + case V4L2_PIX_FMT_Y4: descr = "4-bit Greyscale"; break; + case V4L2_PIX_FMT_Y6: descr = "6-bit Greyscale"; break; + case V4L2_PIX_FMT_Y10: descr = "10-bit Greyscale"; break; + case V4L2_PIX_FMT_Y12: descr = "12-bit Greyscale"; break; + case V4L2_PIX_FMT_Y16: descr = "16-bit Greyscale"; break; + case V4L2_PIX_FMT_Y16_BE: descr = "16-bit Greyscale BE"; break; + case V4L2_PIX_FMT_Y10BPACK: descr = "10-bit Greyscale (Packed)"; break; + case V4L2_PIX_FMT_PAL8: descr = "8-bit Palette"; break; + case V4L2_PIX_FMT_UV8: descr = "8-bit Chrominance UV 4-4"; break; + case V4L2_PIX_FMT_YVU410: descr = "Planar YVU 4:1:0"; break; + case V4L2_PIX_FMT_YVU420: descr = "Planar YVU 4:2:0"; break; + case V4L2_PIX_FMT_YUYV: descr = "YUYV 4:2:2"; break; + case V4L2_PIX_FMT_YYUV: descr = "YYUV 4:2:2"; break; + case V4L2_PIX_FMT_YVYU: descr = "YVYU 4:2:2"; break; + case V4L2_PIX_FMT_UYVY: descr = "UYVY 4:2:2"; break; + case V4L2_PIX_FMT_VYUY: descr = "VYUY 4:2:2"; break; + case V4L2_PIX_FMT_YUV422P: descr = "Planar YVU 4:2:2"; break; + case V4L2_PIX_FMT_YUV411P: descr = "Planar YUV 4:1:1"; break; + case V4L2_PIX_FMT_Y41P: descr = "YUV 4:1:1 (Packed)"; break; + case V4L2_PIX_FMT_YUV444: descr = "16-bit A/XYUV 4-4-4-4"; break; + case V4L2_PIX_FMT_YUV555: descr = "16-bit A/XYUV 1-5-5-5"; break; + case V4L2_PIX_FMT_YUV565: descr = "16-bit YUV 5-6-5"; break; + case V4L2_PIX_FMT_YUV32: descr = "32-bit A/XYUV 8-8-8-8"; break; + case V4L2_PIX_FMT_YUV410: descr = "Planar YUV 4:1:0"; break; + case V4L2_PIX_FMT_YUV420: descr = "Planar YUV 4:2:0"; break; + case V4L2_PIX_FMT_HI240: descr = "8-bit Dithered RGB (BTTV)"; break; + case V4L2_PIX_FMT_HM12: descr = "YUV 4:2:0 (16x16 Macroblocks)"; break; + case V4L2_PIX_FMT_M420: descr = "YUV 4:2:0 (M420)"; break; + case V4L2_PIX_FMT_NV12: descr = "Y/CbCr 4:2:0"; break; + case V4L2_PIX_FMT_NV21: descr = "Y/CrCb 4:2:0"; break; + case V4L2_PIX_FMT_NV16: descr = "Y/CbCr 4:2:2"; break; + case V4L2_PIX_FMT_NV61: descr = "Y/CrCb 4:2:2"; break; + case V4L2_PIX_FMT_NV24: descr = "Y/CbCr 4:4:4"; break; + case V4L2_PIX_FMT_NV42: descr = "Y/CrCb 4:4:4"; break; + case V4L2_PIX_FMT_NV12M: descr = "Y/CbCr 4:2:0 (N-C)"; break; + case V4L2_PIX_FMT_NV21M: descr = "Y/CrCb 4:2:0 (N-C)"; break; + case V4L2_PIX_FMT_NV16M: descr = "Y/CbCr 4:2:2 (N-C)"; break; + case V4L2_PIX_FMT_NV61M: descr = "Y/CrCb 4:2:2 (N-C)"; break; + case V4L2_PIX_FMT_NV12MT: descr = "Y/CbCr 4:2:0 (64x32 MB, N-C)"; break; + case V4L2_PIX_FMT_NV12MT_16X16: descr = "Y/CbCr 4:2:0 (16x16 MB, N-C)"; break; + case V4L2_PIX_FMT_YUV420M: descr = "Planar YUV 4:2:0 (N-C)"; break; + case V4L2_PIX_FMT_YVU420M: descr = "Planar YVU 4:2:0 (N-C)"; break; + case V4L2_PIX_FMT_SBGGR8: descr = "8-bit Bayer BGBG/GRGR"; break; + case V4L2_PIX_FMT_SGBRG8: descr = "8-bit Bayer GBGB/RGRG"; break; + case V4L2_PIX_FMT_SGRBG8: descr = "8-bit Bayer GRGR/BGBG"; break; + case V4L2_PIX_FMT_SRGGB8: descr = "8-bit Bayer RGRG/GBGB"; break; + case V4L2_PIX_FMT_SBGGR10: descr = "10-bit Bayer BGBG/GRGR"; break; + case V4L2_PIX_FMT_SGBRG10: descr = "10-bit Bayer GBGB/RGRG"; break; + case V4L2_PIX_FMT_SGRBG10: descr = "10-bit Bayer GRGR/BGBG"; break; + case V4L2_PIX_FMT_SRGGB10: descr = "10-bit Bayer RGRG/GBGB"; break; + case V4L2_PIX_FMT_SBGGR12: descr = "12-bit Bayer BGBG/GRGR"; break; + case V4L2_PIX_FMT_SGBRG12: descr = "12-bit Bayer GBGB/RGRG"; break; + case V4L2_PIX_FMT_SGRBG12: descr = "12-bit Bayer GRGR/BGBG"; break; + case V4L2_PIX_FMT_SRGGB12: descr = "12-bit Bayer RGRG/GBGB"; break; + case V4L2_PIX_FMT_SBGGR10P: descr = "10-bit Bayer BGBG/GRGR Packed"; break; + case V4L2_PIX_FMT_SGBRG10P: descr = "10-bit Bayer GBGB/RGRG Packed"; break; + case V4L2_PIX_FMT_SGRBG10P: descr = "10-bit Bayer GRGR/BGBG Packed"; break; + case V4L2_PIX_FMT_SRGGB10P: descr = "10-bit Bayer RGRG/GBGB Packed"; break; + case V4L2_PIX_FMT_SBGGR10ALAW8: descr = "8-bit Bayer BGBG/GRGR (A-law)"; break; + case V4L2_PIX_FMT_SGBRG10ALAW8: descr = "8-bit Bayer GBGB/RGRG (A-law)"; break; + case V4L2_PIX_FMT_SGRBG10ALAW8: descr = "8-bit Bayer GRGR/BGBG (A-law)"; break; + case V4L2_PIX_FMT_SRGGB10ALAW8: descr = "8-bit Bayer RGRG/GBGB (A-law)"; break; + case V4L2_PIX_FMT_SBGGR10DPCM8: descr = "8-bit Bayer BGBG/GRGR (DPCM)"; break; + case V4L2_PIX_FMT_SGBRG10DPCM8: descr = "8-bit Bayer GBGB/RGRG (DPCM)"; break; + case V4L2_PIX_FMT_SGRBG10DPCM8: descr = "8-bit Bayer GRGR/BGBG (DPCM)"; break; + case V4L2_PIX_FMT_SRGGB10DPCM8: descr = "8-bit Bayer RGRG/GBGB (DPCM)"; break; + case V4L2_PIX_FMT_SBGGR16: descr = "16-bit Bayer BGBG/GRGR (Exp.)"; break; + case V4L2_PIX_FMT_SN9C20X_I420: descr = "GSPCA SN9C20X I420"; break; + case V4L2_PIX_FMT_SPCA501: descr = "GSPCA SPCA501"; break; + case V4L2_PIX_FMT_SPCA505: descr = "GSPCA SPCA505"; break; + case V4L2_PIX_FMT_SPCA508: descr = "GSPCA SPCA508"; break; + case V4L2_PIX_FMT_STV0680: descr = "GSPCA STV0680"; break; + case V4L2_PIX_FMT_TM6000: descr = "A/V + VBI Mux Packet"; break; + case V4L2_PIX_FMT_CIT_YYVYUY: descr = "GSPCA CIT YYVYUY"; break; + case V4L2_PIX_FMT_KONICA420: descr = "GSPCA KONICA420"; break; + case V4L2_SDR_FMT_CU8: descr = "Complex U8"; break; + case V4L2_SDR_FMT_CU16LE: descr = "Complex U16LE"; break; + case V4L2_SDR_FMT_CS8: descr = "Complex S8"; break; + case V4L2_SDR_FMT_CS14LE: descr = "Complex S14LE"; break; + case V4L2_SDR_FMT_RU12LE: descr = "Real U12LE"; break; + + default: + /* Compressed formats */ + flags = V4L2_FMT_FLAG_COMPRESSED; + switch (fmt->pixelformat) { + /* Max description length mask: descr = "0123456789012345678901234567890" */ + case V4L2_PIX_FMT_MJPEG: descr = "Motion-JPEG"; break; + case V4L2_PIX_FMT_JPEG: descr = "JFIF JPEG"; break; + case V4L2_PIX_FMT_DV: descr = "1394"; break; + case V4L2_PIX_FMT_MPEG: descr = "MPEG-1/2/4"; break; + case V4L2_PIX_FMT_H264: descr = "H.264"; break; + case V4L2_PIX_FMT_H264_NO_SC: descr = "H.264 (No Start Codes)"; break; + case V4L2_PIX_FMT_H264_MVC: descr = "H.264 MVC"; break; + case V4L2_PIX_FMT_H263: descr = "H.263"; break; + case V4L2_PIX_FMT_MPEG1: descr = "MPEG-1 ES"; break; + case V4L2_PIX_FMT_MPEG2: descr = "MPEG-2 ES"; break; + case V4L2_PIX_FMT_MPEG4: descr = "MPEG-4 part 2 ES"; break; + case V4L2_PIX_FMT_XVID: descr = "Xvid"; break; + case V4L2_PIX_FMT_VC1_ANNEX_G: descr = "VC-1 (SMPTE 412M Annex G)"; break; + case V4L2_PIX_FMT_VC1_ANNEX_L: descr = "VC-1 (SMPTE 412M Annex L)"; break; + case V4L2_PIX_FMT_VP8: descr = "VP8"; break; + case V4L2_PIX_FMT_CPIA1: descr = "GSPCA CPiA YUV"; break; + case V4L2_PIX_FMT_WNVA: descr = "WNVA"; break; + case V4L2_PIX_FMT_SN9C10X: descr = "GSPCA SN9C10X"; break; + case V4L2_PIX_FMT_PWC1: descr = "Raw Philips Webcam Type (Old)"; break; + case V4L2_PIX_FMT_PWC2: descr = "Raw Philips Webcam Type (New)"; break; + case V4L2_PIX_FMT_ET61X251: descr = "GSPCA ET61X251"; break; + case V4L2_PIX_FMT_SPCA561: descr = "GSPCA SPCA561"; break; + case V4L2_PIX_FMT_PAC207: descr = "GSPCA PAC207"; break; + case V4L2_PIX_FMT_MR97310A: descr = "GSPCA MR97310A"; break; + case V4L2_PIX_FMT_JL2005BCD: descr = "GSPCA JL2005BCD"; break; + case V4L2_PIX_FMT_SN9C2028: descr = "GSPCA SN9C2028"; break; + case V4L2_PIX_FMT_SQ905C: descr = "GSPCA SQ905C"; break; + case V4L2_PIX_FMT_PJPG: descr = "GSPCA PJPG"; break; + case V4L2_PIX_FMT_OV511: descr = "GSPCA OV511"; break; + case V4L2_PIX_FMT_OV518: descr = "GSPCA OV518"; break; + case V4L2_PIX_FMT_JPGL: descr = "JPEG Lite"; break; + case V4L2_PIX_FMT_SE401: descr = "GSPCA SE401"; break; + case V4L2_PIX_FMT_S5C_UYVY_JPG: descr = "S5C73MX interleaved UYVY/JPEG"; break; + default: + WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat); + if (fmt->description[0]) + return; + flags = 0; + snprintf(fmt->description, sz, "%c%c%c%c%s", + (char)(fmt->pixelformat & 0x7f), + (char)((fmt->pixelformat >> 8) & 0x7f), + (char)((fmt->pixelformat >> 16) & 0x7f), + (char)((fmt->pixelformat >> 24) & 0x7f), + (fmt->pixelformat & (1 << 31)) ? "-BE" : ""); + break; + } + } + + if (descr) + WARN_ON(strlcpy(fmt->description, descr, sz) >= sz); + fmt->flags = flags; +} + static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -1112,34 +1291,43 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; bool is_rx = vfd->vfl_dir != VFL_DIR_TX; bool is_tx = vfd->vfl_dir != VFL_DIR_RX; + int ret = -EINVAL; switch (p->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: if (unlikely(!is_rx || !is_vid || !ops->vidioc_enum_fmt_vid_cap)) break; - return ops->vidioc_enum_fmt_vid_cap(file, fh, arg); + ret = ops->vidioc_enum_fmt_vid_cap(file, fh, arg); + break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: if (unlikely(!is_rx || !is_vid || !ops->vidioc_enum_fmt_vid_cap_mplane)) break; - return ops->vidioc_enum_fmt_vid_cap_mplane(file, fh, arg); + ret = ops->vidioc_enum_fmt_vid_cap_mplane(file, fh, arg); + break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!is_rx || !is_vid || !ops->vidioc_enum_fmt_vid_overlay)) break; - return ops->vidioc_enum_fmt_vid_overlay(file, fh, arg); + ret = ops->vidioc_enum_fmt_vid_overlay(file, fh, arg); + break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: if (unlikely(!is_tx || !is_vid || !ops->vidioc_enum_fmt_vid_out)) break; - return ops->vidioc_enum_fmt_vid_out(file, fh, arg); + ret = ops->vidioc_enum_fmt_vid_out(file, fh, arg); + break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: if (unlikely(!is_tx || !is_vid || !ops->vidioc_enum_fmt_vid_out_mplane)) break; - return ops->vidioc_enum_fmt_vid_out_mplane(file, fh, arg); + ret = ops->vidioc_enum_fmt_vid_out_mplane(file, fh, arg); + break; case V4L2_BUF_TYPE_SDR_CAPTURE: if (unlikely(!is_rx || !is_sdr || !ops->vidioc_enum_fmt_sdr_cap)) break; - return ops->vidioc_enum_fmt_sdr_cap(file, fh, arg); + ret = ops->vidioc_enum_fmt_sdr_cap(file, fh, arg); + break; } - return -EINVAL; + if (ret == 0) + v4l_fill_fmtdesc(p); + return ret; } static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, @@ -1618,6 +1806,8 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, if (ret) return ret; + CLEAR_AFTER_FIELD(create, format); + v4l_sanitize_format(&create->format); ret = ops->vidioc_create_bufs(file, fh, create); @@ -2354,7 +2544,7 @@ static long __video_do_ioctl(struct file *file, if (v4l2_is_known_ioctl(cmd)) { info = &v4l2_ioctls[_IOC_NR(cmd)]; - if (!test_bit(_IOC_NR(cmd), vfd->valid_ioctls) && + if (!test_bit(_IOC_NR(cmd), vfd->valid_ioctls) && !((info->flags & INFO_FL_CTRL) && vfh && vfh->ctrl_handler)) goto done; diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 73824a5..dc853e5 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -427,6 +427,25 @@ int v4l2_m2m_dqbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, EXPORT_SYMBOL_GPL(v4l2_m2m_dqbuf); /** + * v4l2_m2m_prepare_buf() - prepare a source or destination buffer, depending on + * the type + */ +int v4l2_m2m_prepare_buf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, + struct v4l2_buffer *buf) +{ + struct vb2_queue *vq; + int ret; + + vq = v4l2_m2m_get_vq(m2m_ctx, buf->type); + ret = vb2_prepare_buf(vq, buf); + if (!ret) + v4l2_m2m_try_schedule(m2m_ctx); + + return ret; +} +EXPORT_SYMBOL_GPL(v4l2_m2m_prepare_buf); + +/** * v4l2_m2m_create_bufs() - create a source or destination buffer, depending * on the type */ @@ -564,8 +583,16 @@ unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, if (list_empty(&src_q->done_list)) poll_wait(file, &src_q->done_wq, wait); - if (list_empty(&dst_q->done_list)) + if (list_empty(&dst_q->done_list)) { + /* + * If the last buffer was dequeued from the capture queue, + * return immediately. DQBUF will return -EPIPE. + */ + if (dst_q->last_buffer_dequeued) + return rc | POLLIN | POLLRDNORM; + poll_wait(file, &dst_q->done_wq, wait); + } if (m2m_ctx->m2m_dev->m2m_ops->lock) m2m_ctx->m2m_dev->m2m_ops->lock(m2m_ctx->priv); @@ -803,6 +830,15 @@ int v4l2_m2m_ioctl_dqbuf(struct file *file, void *priv, } EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_dqbuf); +int v4l2_m2m_ioctl_prepare_buf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct v4l2_fh *fh = file->private_data; + + return v4l2_m2m_prepare_buf(file, fh->m2m_ctx, buf); +} +EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_prepare_buf); + int v4l2_m2m_ioctl_expbuf(struct file *file, void *priv, struct v4l2_exportbuffer *eb) { diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c index 83143d3..b27cbb1 100644 --- a/drivers/media/v4l2-core/v4l2-of.c +++ b/drivers/media/v4l2-core/v4l2-of.c @@ -14,6 +14,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/slab.h> #include <linux/string.h> #include <linux/types.h> @@ -92,10 +93,6 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node, flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH : V4L2_MBUS_VSYNC_ACTIVE_LOW; - if (!of_property_read_u32(node, "pclk-sample", &v)) - flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING : - V4L2_MBUS_PCLK_SAMPLE_FALLING; - if (!of_property_read_u32(node, "field-even-active", &v)) flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH : V4L2_MBUS_FIELD_EVEN_LOW; @@ -104,6 +101,10 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node, else endpoint->bus_type = V4L2_MBUS_BT656; + if (!of_property_read_u32(node, "pclk-sample", &v)) + flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING : + V4L2_MBUS_PCLK_SAMPLE_FALLING; + if (!of_property_read_u32(node, "data-active", &v)) flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH : V4L2_MBUS_DATA_ACTIVE_LOW; @@ -141,6 +142,10 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node, * V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. * The caller should hold a reference to @node. * + * NOTE: This function does not parse properties the size of which is + * variable without a low fixed limit. Please use + * v4l2_of_alloc_parse_endpoint() in new drivers instead. + * * Return: 0. */ int v4l2_of_parse_endpoint(const struct device_node *node, @@ -149,8 +154,9 @@ int v4l2_of_parse_endpoint(const struct device_node *node, int rval; of_graph_parse_endpoint(node, &endpoint->base); - endpoint->bus_type = 0; - memset(&endpoint->bus, 0, sizeof(endpoint->bus)); + /* Zero fields from bus_type to until the end */ + memset(&endpoint->bus_type, 0, sizeof(*endpoint) - + offsetof(typeof(*endpoint), bus_type)); rval = v4l2_of_parse_csi_bus(node, endpoint); if (rval) @@ -166,6 +172,88 @@ int v4l2_of_parse_endpoint(const struct device_node *node, } EXPORT_SYMBOL(v4l2_of_parse_endpoint); +/* + * v4l2_of_free_endpoint() - free the endpoint acquired by + * v4l2_of_alloc_parse_endpoint() + * @endpoint - the endpoint the resources of which are to be released + * + * It is safe to call this function with NULL argument or on an + * endpoint the parsing of which failed. + */ +void v4l2_of_free_endpoint(struct v4l2_of_endpoint *endpoint) +{ + if (IS_ERR_OR_NULL(endpoint)) + return; + + kfree(endpoint->link_frequencies); + kfree(endpoint); +} +EXPORT_SYMBOL(v4l2_of_free_endpoint); + +/** + * v4l2_of_alloc_parse_endpoint() - parse all endpoint node properties + * @node: pointer to endpoint device_node + * + * All properties are optional. If none are found, we don't set any flags. + * This means the port has a static configuration and no properties have + * to be specified explicitly. + * If any properties that identify the bus as parallel are found and + * slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if we recognise + * the bus as serial CSI-2 and clock-noncontinuous isn't set, we set the + * V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. + * The caller should hold a reference to @node. + * + * v4l2_of_alloc_parse_endpoint() has two important differences to + * v4l2_of_parse_endpoint(): + * + * 1. It also parses variable size data and + * + * 2. The memory it has allocated to store the variable size data must + * be freed using v4l2_of_free_endpoint() when no longer needed. + * + * Return: Pointer to v4l2_of_endpoint if successful, on error a + * negative error code. + */ +struct v4l2_of_endpoint *v4l2_of_alloc_parse_endpoint( + const struct device_node *node) +{ + struct v4l2_of_endpoint *endpoint; + int len; + int rval; + + endpoint = kzalloc(sizeof(*endpoint), GFP_KERNEL); + if (!endpoint) + return ERR_PTR(-ENOMEM); + + rval = v4l2_of_parse_endpoint(node, endpoint); + if (rval < 0) + goto out_err; + + if (of_get_property(node, "link-frequencies", &len)) { + endpoint->link_frequencies = kmalloc(len, GFP_KERNEL); + if (!endpoint->link_frequencies) { + rval = -ENOMEM; + goto out_err; + } + + endpoint->nr_of_link_frequencies = + len / sizeof(*endpoint->link_frequencies); + + rval = of_property_read_u64_array( + node, "link-frequencies", endpoint->link_frequencies, + endpoint->nr_of_link_frequencies); + if (rval < 0) + goto out_err; + } + + return endpoint; + +out_err: + v4l2_of_free_endpoint(endpoint); + return ERR_PTR(rval); +} +EXPORT_SYMBOL(v4l2_of_alloc_parse_endpoint); + /** * v4l2_of_parse_link() - parse a link between two endpoints * @node: pointer to the endpoint at the local end of the link diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 66ada01..93b3154 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -182,6 +182,7 @@ module_param(debug, int, 0644); V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_TIMECODE) static void __vb2_queue_cancel(struct vb2_queue *q); +static void __enqueue_in_driver(struct vb2_buffer *vb); /** * __vb2_buf_mem_alloc() - allocate video memory for the given buffer @@ -1153,8 +1154,9 @@ EXPORT_SYMBOL_GPL(vb2_plane_cookie); /** * vb2_buffer_done() - inform videobuf that an operation on a buffer is finished * @vb: vb2_buffer returned from the driver - * @state: either VB2_BUF_STATE_DONE if the operation finished successfully - * or VB2_BUF_STATE_ERROR if the operation finished with an error. + * @state: either VB2_BUF_STATE_DONE if the operation finished successfully, + * VB2_BUF_STATE_ERROR if the operation finished with an error or + * VB2_BUF_STATE_QUEUED if the driver wants to requeue buffers. * If start_streaming fails then it should return buffers with state * VB2_BUF_STATE_QUEUED to put them back into the queue. * @@ -1205,8 +1207,11 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) atomic_dec(&q->owned_by_drv_count); spin_unlock_irqrestore(&q->done_lock, flags); - if (state == VB2_BUF_STATE_QUEUED) + if (state == VB2_BUF_STATE_QUEUED) { + if (q->start_streaming_called) + __enqueue_in_driver(vb); return; + } /* Inform any processes that may be waiting for buffers */ wake_up(&q->done_wq); @@ -1237,6 +1242,23 @@ void vb2_discard_done(struct vb2_queue *q) } EXPORT_SYMBOL_GPL(vb2_discard_done); +static void vb2_warn_zero_bytesused(struct vb2_buffer *vb) +{ + static bool __check_once __read_mostly; + + if (__check_once) + return; + + __check_once = true; + __WARN(); + + pr_warn_once("use of bytesused == 0 is deprecated and will be removed in the future,\n"); + if (vb->vb2_queue->allow_zero_bytesused) + pr_warn_once("use VIDIOC_DECODER_CMD(V4L2_DEC_CMD_STOP) instead.\n"); + else + pr_warn_once("use the actual size instead.\n"); +} + /** * __fill_vb2_buffer() - fill a vb2_buffer with information provided in a * v4l2_buffer by the userspace. The caller has already verified that struct @@ -1247,16 +1269,6 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b { unsigned int plane; - if (V4L2_TYPE_IS_OUTPUT(b->type)) { - if (WARN_ON_ONCE(b->bytesused == 0)) { - pr_warn_once("use of bytesused == 0 is deprecated and will be removed in the future,\n"); - if (vb->vb2_queue->allow_zero_bytesused) - pr_warn_once("use VIDIOC_DECODER_CMD(V4L2_DEC_CMD_STOP) instead.\n"); - else - pr_warn_once("use the actual size instead.\n"); - } - } - if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { if (b->memory == V4L2_MEMORY_USERPTR) { for (plane = 0; plane < vb->num_planes; ++plane) { @@ -1297,6 +1309,9 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b struct v4l2_plane *pdst = &v4l2_planes[plane]; struct v4l2_plane *psrc = &b->m.planes[plane]; + if (psrc->bytesused == 0) + vb2_warn_zero_bytesused(vb); + if (vb->vb2_queue->allow_zero_bytesused) pdst->bytesused = psrc->bytesused; else @@ -1331,6 +1346,9 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b } if (V4L2_TYPE_IS_OUTPUT(b->type)) { + if (b->bytesused == 0) + vb2_warn_zero_bytesused(vb); + if (vb->vb2_queue->allow_zero_bytesused) v4l2_planes[0].bytesused = b->bytesused; else @@ -1945,6 +1963,11 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) return -EIO; } + if (q->last_buffer_dequeued) { + dprintk(3, "last buffer dequeued already, will not wait for buffers\n"); + return -EPIPE; + } + if (!list_empty(&q->done_list)) { /* * Found a buffer that we were waiting for. @@ -2100,6 +2123,9 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n /* Remove from videobuf queue */ list_del(&vb->queued_entry); q->queued_count--; + if (!V4L2_TYPE_IS_OUTPUT(q->type) && + vb->v4l2_buf.flags & V4L2_BUF_FLAG_LAST) + q->last_buffer_dequeued = true; /* go back to dequeued state */ __vb2_dqbuf(vb); @@ -2313,6 +2339,7 @@ static int vb2_internal_streamoff(struct vb2_queue *q, enum v4l2_buf_type type) */ __vb2_queue_cancel(q); q->waiting_for_buffers = !V4L2_TYPE_IS_OUTPUT(q->type); + q->last_buffer_dequeued = false; dprintk(3, "successful\n"); return 0; @@ -2655,8 +2682,16 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) if (V4L2_TYPE_IS_OUTPUT(q->type) && q->queued_count < q->num_buffers) return res | POLLOUT | POLLWRNORM; - if (list_empty(&q->done_list)) + if (list_empty(&q->done_list)) { + /* + * If the last buffer was dequeued from a capture queue, + * return immediately. DQBUF will return -EPIPE. + */ + if (q->last_buffer_dequeued) + return res | POLLIN | POLLRDNORM; + poll_wait(file, &q->done_wq, wait); + } /* * Take first buffer available for dequeuing. diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 644dec73..94c1e64 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -299,7 +299,6 @@ static struct sg_table *vb2_dc_dmabuf_ops_map( /* stealing dmabuf mutex to serialize map/unmap operations */ struct mutex *lock = &db_attach->dmabuf->lock; struct sg_table *sgt; - int ret; mutex_lock(lock); @@ -318,8 +317,9 @@ static struct sg_table *vb2_dc_dmabuf_ops_map( } /* mapping to the client with new direction */ - ret = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, dma_dir); - if (ret <= 0) { + sgt->nents = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, + dma_dir); + if (!sgt->nents) { pr_err("failed to map scatterlist\n"); mutex_unlock(lock); return ERR_PTR(-EIO); diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c index 45c708e..7289b81 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c @@ -147,8 +147,9 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size, * No need to sync to the device, this will happen later when the * prepare() memop is called. */ - if (dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->nents, - buf->dma_dir, &attrs) == 0) + sgt->nents = dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents, + buf->dma_dir, &attrs); + if (!sgt->nents) goto fail_map; buf->handler.refcount = &buf->refcount; @@ -187,7 +188,7 @@ static void vb2_dma_sg_put(void *buf_priv) dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs); dprintk(1, "%s: Freeing buffer of %d pages\n", __func__, buf->num_pages); - dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->nents, + dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir, &attrs); if (buf->vaddr) vm_unmap_ram(buf->vaddr, buf->num_pages); @@ -314,9 +315,11 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr, * No need to sync to the device, this will happen later when the * prepare() memop is called. */ - if (dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->nents, - buf->dma_dir, &attrs) == 0) + sgt->nents = dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents, + buf->dma_dir, &attrs); + if (!sgt->nents) goto userptr_fail_map; + return buf; userptr_fail_map: @@ -351,7 +354,8 @@ static void vb2_dma_sg_put_userptr(void *buf_priv) dprintk(1, "%s: Releasing userspace buffer of %d pages\n", __func__, buf->num_pages); - dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir, &attrs); + dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir, + &attrs); if (buf->vaddr) vm_unmap_ram(buf->vaddr, buf->num_pages); sg_free_table(buf->dma_sgt); @@ -502,7 +506,6 @@ static struct sg_table *vb2_dma_sg_dmabuf_ops_map( /* stealing dmabuf mutex to serialize map/unmap operations */ struct mutex *lock = &db_attach->dmabuf->lock; struct sg_table *sgt; - int ret; mutex_lock(lock); @@ -521,8 +524,9 @@ static struct sg_table *vb2_dma_sg_dmabuf_ops_map( } /* mapping to the client with new direction */ - ret = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, dma_dir); - if (ret <= 0) { + sgt->nents = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, + dma_dir); + if (!sgt->nents) { pr_err("failed to map scatterlist\n"); mutex_unlock(lock); return ERR_PTR(-EIO); diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index 657ab30..2fe4c27 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c @@ -287,7 +287,6 @@ static struct sg_table *vb2_vmalloc_dmabuf_ops_map( /* stealing dmabuf mutex to serialize map/unmap operations */ struct mutex *lock = &db_attach->dmabuf->lock; struct sg_table *sgt; - int ret; mutex_lock(lock); @@ -306,8 +305,9 @@ static struct sg_table *vb2_vmalloc_dmabuf_ops_map( } /* mapping to the client with new direction */ - ret = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, dma_dir); - if (ret <= 0) { + sgt->nents = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, + dma_dir); + if (!sgt->nents) { pr_err("failed to map scatterlist\n"); mutex_unlock(lock); return ERR_PTR(-EIO); |