diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-26 03:55:48 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-26 03:55:48 +0300 |
commit | 5b4ca4447757019f11a601b0009534ef84bed801 (patch) | |
tree | 09bc8445e61aea621580d7587c21ac3f2b0cafb4 /drivers/media | |
parent | 0db9723cacf4d62bc3685fb15179b39ee4e17679 (diff) | |
parent | faebbd8f134f0c054f372982c8ddd1bbcc41b440 (diff) | |
download | linux-5b4ca4447757019f11a601b0009534ef84bed801.tar.xz |
Merge tag 'media/v4.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- Lots of improvements at the DVB API DocBook documentation. Now, the
frontend and the network APIs are fully in sync with the Kernel and
looks more like the rest of the media documentation;
- New frontend driver: cx24120
- New driver for a PCI device: cobalt. This driver is actually not
sold in the market, but it is a good example of a multi-HDMI input
device;
- The dt3155 driver were promoted from staging;
- The mantis driver got remote controller support;
- New V4L2 driver for ST bdisp SoC chipsets;
- Make sparse and smatch happier: several bugs were solved by fixing
the issues reported by those static code analyzers.
- Lots of new device additions, new features, improvements and cleanups
at the existing drivers.
* tag 'media/v4.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (553 commits)
[media] lmedm04: fix the range for relative measurements
[media] lmedm04: use u32 instead of u64 for relative stats
[media] omap3isp: remove unused var
[media] saa7134: fix page size on some archs
[media] use CONFIG_PM_SLEEP for suspend/resume
[media] tuner-i2c: be consistent with I2C declaration
[media] si470x: cleanup define namespace
[media] bdisp: prevent compiling on random arch
[media] vb2: Don't WARN when v4l2_buffer.bytesused is 0 for multiplanar buffers
[media] MAINTAINERS: Add entry for the Renesas VSP1 driver
[media] videodev2.h: fix copy-and-paste error in V4L2_MAP_XFER_FUNC_DEFAULT
[media] Revert "[media] vb2: Push mmap_sem down to memops"
[media] mantis: cleanup a warning
[media] bdisp-debug: don't try to divide by s64
[media] cx88: don't declare restart_video_queue if not used
[media] au0828: move dev->boards atribuition to happen earlier
[media] lmedm04: implement dvb v5 statistics
[media] bdisp: remove unused var
[media] bdisp: remove needless check
ts2020: fix compilation on i386
...
Diffstat (limited to 'drivers/media')
473 files changed, 23455 insertions, 6623 deletions
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 157099243d61..3ef3d6c6bbf8 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 a8c6cdfaa2f5..e5936380b1e5 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 437912e49824..2b2460e9e6b4 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 7e14e90d2922..9c59f4306883 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 77e45475f4c7..8220257903ef 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 f06f3a9070f5..b8eff235367d 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 dc4528dcbb98..835c54d60e74 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 eb8bd689b936..4cc39e4a8318 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 367b8e77feb8..f4305ae800f4 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 ae36d0ae0fb1..b15754d95ec0 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 1d60d200d9ab..41f2a3939979 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 882ca417f328..842b9c8f80c6 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 816269e5f706..4816947294fe 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 97c151d5b2e1..0d35f5850ff1 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 23d399bec804..ebab1b83e1fc 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 780da58132f1..97ecbe01034c 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 5f0411939ffc..aff36538f582 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 8001690d7576..e23197da84af 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 82ce47bdf5dc..59018afaa95f 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 493665899565..544c5f65d19a 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 4e11dc4b1335..8fe552e293ed 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 5d06c99b0e97..b744a3f8d467 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 b8aca1c84786..951b3847e6f6 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 638c7aa0fb7e..d30275f27644 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 86563260d0f2..fd033cca6e11 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 edc8eafc5c09..d2d06dcd7683 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 7b510f2ae20f..cb36475e322b 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 2916d7c74a1d..8814f36d53fb 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 acb965ce0358..5f77bc80a896 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 000000000000..3b0ef52bb834 --- /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 000000000000..f0970423e16f --- /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 7975c6608e20..e18cf9e1185e 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 758aee5a072f..975f3c926fe8 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 72b0e2db3aab..42fad6aa3958 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 490e090048ef..def6d21d1445 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 4b428959b16e..a0d53f01a8bf 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 008cb2ac8480..21abf1b4ed4d 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 35fe364c7182..4e028b41c0d5 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 3b024bfe980a..0b8fb5dd1889 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 68e2af2650d3..47cb72243b9d 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 af91e0c92339..7a61172d0d45 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 ffad181a9692..583d6b7fabed 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 dcb9a15ef0c2..35eb71fe3c2b 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 c505d696f92d..33be5d6b9e10 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 8c6663b6399d..94c26270fff0 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 780c37bdcb72..2b8b4b1656a2 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 f75dec443783..8f92aca0b073 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 2bfa7a435974..b28b5787b39a 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 687e893d29fe..34b9441840da 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 d46cf5f7cd2e..b975da099929 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 bae9c71dc3e9..9ed88e014942 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 9d0d0347758f..e8fc0329ea64 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 d5acc304786b..14e996d45fac 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 9d424809d06b..c9012e677cd1 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 67c8e6df42e8..40e359f2d17d 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 4d571a2282d4..6dc225c4bc91 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 0c642a5bf823..b46450a10b80 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 c77002fcc8e2..3a4d4606a426 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 ddf866c46f8b..0977871232a2 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 99efeba3c31a..7880f71ccd8a 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 d08570af1c10..47121866163d 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 d9a2b0e768e0..721fbc07e9ee 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 2e1a61893fc1..cf3cc20510da 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 416cce3fefc7..7bbb2c18c2dd 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 3c92f36ea5c7..e2c191c8b196 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 f3ba7b5faa2e..4aca0fb9a8a7 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 c463da7f6dcc..d7ca0fdd0084 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 d3d928e1c0ce..e9b2d2b69b1d 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 9b3b4962da7c..04b355a005fb 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 a2c0958111f8..eee8c22c51ec 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 d63bc9c13dce..9b6f464c48bd 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 3ddea4471d2b..79bc671e8769 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 e486dc0d8e60..dbd5f43fa128 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 8f54c39ca63f..cfc005ee11d8 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 f749c8ac5f39..a113282d6956 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 2163490c1e6b..c36e6764eead 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 2c3b50e828d7..123bb2f8e4b6 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 8a8e1ecb762d..79c3040912ab 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 90ae6c72c0e3..73f9505367ac 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 cbbd259eacfe..35b1053b3640 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 873ea1da844b..e82413b975e6 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 e1b8df62bd59..3d01f4f22aca 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 d50d5376c9c5..cf793f39a09b 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 b400f7b3c2e7..822ea4b7a7ff 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 a8e912e679a5..c29a4c2bf71a 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 c3a922c37903..5dcd3a41d23f 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 3ff8806ca584..7edb885ae9c8 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 d2594768bff2..342ea84860df 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 5ff474a7ff29..10964848a2f1 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 64f35fed7ae1..9afc3f42290e 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 93eeaf7118fd..9c22a4c70d87 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 6ec16a243741..4215652f8eb7 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 69862e1fd9e9..b2d9fe13e1a0 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 7d3999a4e974..f5b722d8081b 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 4cc5d10ed0d4..7c2eeee69757 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 5db588ebfc24..25e238c370e5 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 70d702ae6f49..3225d0cc93c7 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 d7efce8043ed..c07e6fe2cb10 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 16850e2bf02f..62ad7a7be9f8 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 57dc2abaa87b..e87ac30d7fb8 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 1bb81b5ae6e0..4378fe1b978e 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 c73899d3a53d..756650f154ab 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 632b25156e4c..c93d9a45f7f7 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 d40f226160ef..75b4d8b25657 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 b57ecf42e75a..a8177807fb65 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 b31ff265ff24..ec3e18e5ff50 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 995db0689ddd..89bf6f64b078 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 2c88abfab531..fe31dd541955 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 a0a7b1664c53..fa63a9e929ce 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 0b2a934f53e5..25bdf6e0f963 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 b1425830a24e..91c6dcf65d2a 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 dce22ce35d20..456cdc7fb1e7 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 1bff7f457e19..a684424e665a 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 ca1e0d54b69a..44a55656093f 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 71fb63299de7..8451086c563f 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 a2631be7ffac..0e209b56c76c 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 4a19b85995f1..f6dc6307d35a 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 da89f4249846..0ffbfa5b2dfb 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 03f839c431e9..54d7c713eec8 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 fcfe2e080cb0..95a33e187f8e 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 69e62f42e2e1..796543fa2c8d 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 90164a38cd36..f61b143a0052 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 1714af94eca2..9220e5cf0d21 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 bb42b563c42d..aacfdda3e005 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 9c17eacaec24..526952396422 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 82946cd517f5..ef9764a02d4c 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 6fe9793b98b3..17acda6bcb6e 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 346a85be6de2..345d1eda8c05 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 6f30ea76151a..71ee8f586430 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 873fe1949e98..c70ababce954 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 40a1a95c7ce9..f0d3f5a2da46 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 d220af579a64..321834ba8f57 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 28940cc3a766..e2dd1617662f 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 12d93203d405..95bcd4026451 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 60ffcf098bef..808360fd6539 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 b5a37fe10a6a..4cf79b2422d4 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 69aeaf397624..29846245aa3b 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 bd496447749a..e15a789ad596 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 d7307862c2c5..af5eaf2db2a0 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 a10f7f8f0558..57132cdba5ea 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 edebd114279d..6edffc7b74e3 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 b9847527eb5a..2d1e25f10973 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 08b234bd2962..53c5ea89f0b9 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 297ef04e146a..774e0d0c94cb 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 de803a11efb4..d0ad6a25bdab 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 f14c0e6435a3..ba3c4156644d 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 7147c8b68fac..0eae5f4471e2 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 0d0f9a917cd3..7d517361e419 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 557f25def3a0..636ebd6fe5dc 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 ec89cfa927a2..f68c2352c63c 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 2e9a53502551..4fbdd1e9f7ee 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 441e0fda24fe..6dfaead6aaa8 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 35d9c8d25589..3b6eeed2e2b9 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 64f08365e6b2..de10a76ba6df 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 a246d4d64b8b..f31377408550 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 e3c907a97765..9b4f5deec748 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 93ae031bdafb..bab9ac0c1764 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 f4eef2fa6f6f..1f8af1ee8352 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 8daac88b33fe..f150a8bd94dc 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 aa93d2e88572..8caae1c07541 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 841dc55457cf..03a7fc7316ae 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 1752428c43c5..c769cf663f84 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 9b853215d146..42bec9bf1892 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 10c735c3a082..b62b6ddc4356 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 070c152da95a..0c50e5285cf6 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 1c6bc306ecdc..24e47279e30c 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 68cdab9c0903..e4fa0746f75e 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 787cdfb08749..05077cffd235 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 00e7f043977e..4c72a18c0b8c 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 218144a99016..f318ae9bb57a 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 0baf0d2967ee..23ce53bd47c3 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 2364d16586b3..9f1f9169fb5b 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 bc12060e0882..3632958f2158 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 f2261dfe5d1a..4a90eee5e3bb 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 c22c4ae06844..c5cc14ef8347 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 d70d98f1a571..6a2cfdd44e3e 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 000000000000..3be1b2c3c386 --- /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 000000000000..b328955abbd2 --- /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 000000000000..720e3ad93a9e --- /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 000000000000..f0bdf10cfd57 --- /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 000000000000..513fb1f71794 --- /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 000000000000..08db699ced37 --- /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 000000000000..e83f5c9f7e7d --- /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 000000000000..0fc88fd5fa7b --- /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 000000000000..b994b8efdc99 --- /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 000000000000..c206df930669 --- /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 000000000000..04dcaf9198d2 --- /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 000000000000..8077daea51cd --- /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 000000000000..ad16b89b8d0c --- /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 000000000000..a4c1cfaacf95 --- /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 000000000000..dd4bff9cf339 --- /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 000000000000..5119484a24d9 --- /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 000000000000..a28a8482c1d4 --- /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 000000000000..e5c6d032c6f2 --- /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 000000000000..b40c2d141b58 --- /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 000000000000..62be553cd8e2 --- /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 000000000000..9bc9ef1fd3a8 --- /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 000000000000..a480529f561e --- /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 000000000000..602419e589d3 --- /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 000000000000..95471c995067 --- /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 000000000000..384a3e156301 --- /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 000000000000..2a029026bf82 --- /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 000000000000..bdef2df5d689 --- /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 5a55630d09db..30bbe8d1ea55 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 4aeb7c6b8ce1..71227a155cba 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 83f5074706f9..260e462d91b4 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 79aee30d5fd8..55525af1f482 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 c82d25d53341..c9860845264f 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 0a91df2c9f08..aaf4e46ff3e9 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 745caabe3397..6e8c24cdb2cd 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 6f817d8732da..a6c45eb0a105 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 e73344c94963..be14d7de7cd8 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 2232b389c441..ec76470d12a4 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 aeda8d3990ae..027ead438194 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 3501be9f19d8..aab7cf4c9825 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 1b2ed238cdb6..9dfa5ee32a8f 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 98344540c51f..34f505744477 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 32eb7fdb875e..7510e80eb2ff 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 c9decd80bf61..400e5caefd58 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 b9fe1ac24803..785fe2e0d702 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 9e3492e20766..0ac2dd35fe50 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 ed11716731e9..88915fb87e80 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 000000000000..5145e0dfa2aa --- /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 000000000000..89fa637ec54c --- /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 000000000000..89d0dc705e4a --- /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 000000000000..4e1f4d598d57 --- /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 ccf548c255f1..8a55ccb8f0c9 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 c2e60b4f292d..8616fa8193bc 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 e8b6c7ad2ba9..ee0ef6e48c7d 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 6fe6c4a0e858..9a21c17fc376 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 104914a5bf06..68b5800030b7 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 801fc55b6167..cdefffc16d9e 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 8ff448bb792d..d48778a366a9 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 566c407175a4..1d59c7e039f7 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 895ddba3c0fb..d72ee47dc6e4 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 0e5252e5c0ef..7f7f1d4d7bb1 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 000000000000..0fbd92987c02 --- /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 2f188c089666..b2dbc7b2e0f6 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 a70719218631..f1c96aec8c7b 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 7c1bd167225c..3b1928594b12 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 323f38ef8e3d..764b1c66ea1b 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 e29bc3af4baf..1b92d836a564 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 51e2fbd18b1b..fa30930d7047 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 acc35b42e53c..e7e4428109c3 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 1b637b74ef58..d0e70dc0e16f 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 2db15159d514..0268f20b8097 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 7a37e8fe2ee2..0d2e2b217121 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 ac3cd74e824e..1d2c310ce838 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 3ca078057755..c7405766609c 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 a349e964e0bc..72d7f992375e 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 73ffbabf831c..101ba8729416 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 594dc3ad4750..56b932c97196 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 54e650b4dff1..8a2abb34186b 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 f4da674e7f26..8ef6399d794f 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 dc3d6516edf7..11a172000291 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 2709b83d57b1..4b202fa5fbc4 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 3afbcb70b518..21a579309575 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 5306e549e526..4d36586ad752 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 99d09a7566d3..035039cfae6d 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 8bf0553b8d2f..6b5f6f45d285 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 4f3b1dd18ba4..e7e586c1ba53 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 9bd1f73f82da..f30758e24f5d 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 6c73f5b155f6..a18fe5d47238 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 5b72da5ce418..c2b738227f58 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 cfabcbacc33d..3285c37b4583 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 9cf3c6cba498..3206a826b80d 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 16ae71592e8c..e9a783b71b45 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 9266965412c3..4434e0f28c26 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 add06ab5124d..269e0782c7b6 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 4f7e3b42263f..0342d84913b8 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 2bbf81583d33..37521a2ee504 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 f48ba978f835..1efba6c64ebf 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 6e025fea2542..859fd03d82f9 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 cd1a07ce27cb..18906e0c80e1 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 411592524c63..143fd7899ecd 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 d384a6b0b09f..59b3a36a3639 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 45199a12b9d9..3f24fce74fc1 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 835635b0c712..3a55927edb95 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 23e05499b509..e9674b40007c 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 a4d8867e1d7b..b5b65962ce8f 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 6ccc48833fd8..99972beca262 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 3d8a806c20bb..1ccbe1a49a4b 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 b6801e035ea4..40119b3c52c1 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 421f53188c6c..a4e7d21c9e4c 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 8f855616c237..114f9aba1c00 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 a30cc2f7e4f1..1fba339cddc1 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 6a437f86dcdc..b7e70fb05eb8 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 d0430071d2ee..109797bb8fbb 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 8e6fe0200117..6d6e0ca91fb4 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 6a5c8f6c688e..8e0af221b2e9 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 d1d06cbd1f6a..781bf7286d53 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 c4ab46f5bd92..f69cdd7da10c 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 ccfcf3f528d3..7767e072d623 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 fd2891c886a3..9b9e423e4fc4 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 b7b2e472240a..40423c6c5324 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 f315ef946cd4..4f5586a4cbff 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 bbf428104871..5b76e3db6a92 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 92d954973ccf..c07f367aa436 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 562845361246..77890bd0deab 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 110fd70c7326..5e2b4df48b3c 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 7ffdf4dbaf8c..97167f6ffd1e 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 0ed9b3adfcdf..b5f165a68566 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 17b189a81ec5..f09c5f17a42f 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 15cb254ccc39..13803270d104 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 f6a61b9ceff4..76e6289a5612 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 2d5bd3ac7f81..f47b332f0418 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 ec3e1248923d..421a7c3b595b 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 8333fbc2fe96..8de61dc1e142 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 b09bcd140491..9a923b1a9bac 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 cefad184fe96..12497f5ed8e9 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 0e74aabf5f9a..79940757b34f 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 2a9501d7e7c8..5ef67774971d 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 3621af91d460..c75d4354d182 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 dde1ccc730be..8b799bae01b8 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 c835beb2a1a8..287902681164 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 192377f55840..ea4c423f0cf8 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 3435fd2ca8ec..ace41f53caca 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 16f65ecb70a3..ba8dcd11ae0e 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 8d6e343fec0f..fcb942de0c7f 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 6460f8e1b07f..db7700b0af7c 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 9ce202f53934..c5c6c4e91f7b 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 cd93241eb497..12d3626ecf22 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 7bfe7665687f..d708df410f74 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 f535910b4187..cc8eb0758219 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 8e74fb7f2a07..bda29bc1b933 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 000000000000..bc53496fa74c --- /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 000000000000..18282a0f80c9 --- /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 000000000000..fc8c54f725ad --- /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 000000000000..465828e859e2 --- /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 000000000000..e7e1a425f65a --- /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 000000000000..9e782ebe18da --- /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 000000000000..0cf98577222c --- /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 678ed9f353cb..32e4ff46daf3 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 4d6b4cc57c57..295fde5fdb75 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 d33f16495dbc..a047b4716741 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 9e15aee9a52e..c72349c83fab 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 2b9070098b08..339c8b7e53c8 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 c7651a506668..f99092ca8f5c 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 caf131666e37..d2f2188a0efe 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 79c1890de972..43014b2733db 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 424aa7abc723..8f231a6e68c9 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 2c333356451c..86b8bf3fe745 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 cb766eb154e7..1458c7955547 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 a50cd2e2535b..9baed6a10334 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 dab5990f45a0..c4268d1b2f82 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 aa446271ad34..fc73927a4abc 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 0af43dc7715c..0862c1f24f57 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 d7324c726fc2..84bae795b70d 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 efde88adf624..98e50e446d57 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 dccf58691650..9cbb8cdf0ac0 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 e6b55edc8f8d..04baafe5e901 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 2a497c80c77f..471d6a8ae8a4 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 57f0bc3b60e7..091d793f6583 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 4b7660470e2f..6c0ca900702e 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 e9d03ac69a27..0b04b56571da 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 9d6574bebf78..c9e349b169c4 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 a587c9bac930..dd203de5de95 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 5c63c2ec6183..bd7b3bdb1a88 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 229853d68451..7dbc9ca6d885 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 58ec5986274e..1c087cb76815 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 84fa6e9b59a1..8939ebd74391 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 d16bc67af732..f9c70baf6e0c 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 d12dc3da5931..58ef06f35175 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 abf60794223d..fbbd3bbcd252 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 000000000000..3328cbefabad --- /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 000000000000..7958f458527a --- /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 000000000000..1e096bbda4a0 --- /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 000000000000..202500cb3061 --- /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 85af7a869167..baeb5971fd52 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 e1cf23c3875b..9d0e161c2a88 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 b68d4f762734..4b994aa2f2a7 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 b732ac6a26d8..b9e4645c731c 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 63dace8198b0..d8bdf63ce985 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 f8c5e47a30aa..9d015db65280 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 c4def66f9aa2..ec74244a3853 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 0e758ae2e529..37d040158dff 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 bf4a44272f0e..5a17cb88ff27 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 983510d282f6..8294af909174 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 510239f80c0d..03538f88f488 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 e74b8b2f2fc3..aa9340c05b43 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 cb0070483e65..d6d5d11bbfe0 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 b4162315773d..522690d97b42 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 f0c9c42867de..12f916e53150 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 b1ce6770f88e..862ea46995d7 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 646c99452136..031a43d7e7af 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 74cfc3c98edb..b533240f8ec0 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 bc419f8a9671..ae8cbece6d2b 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 71159a58860f..a7a8452e99d2 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 d74ae26621ca..a6245ef379c4 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 a564c4a9fba7..4db97ab744d6 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 cd8fa5b25304..ecc463db8f69 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 83a6240f64d3..d4f6ca0c4d92 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 2c3375c7aeb9..7b0548181cdc 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 73cc1ce0575c..bc406c5ec69d 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 18f005634c67..bda67a5a76f2 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 d12f5e4ad8bf..4e941f00b600 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 8be1474b2c36..9dd7c7cb06b1 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 edc27355f271..6b469e8c4c6e 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 082ae6ba492f..0934024fb89d 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 983ea8339154..47a98a2014a5 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 39e887925e3d..491913778bcc 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 fe00da105e77..4a117a58c39a 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 e42bde081cd7..a2fd49b6be83 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 610d5675bde6..66ee161fc7ba 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 80261ac40208..a08014d20a5c 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 c261e160c158..c6ff8968286a 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 00d3bce9a690..54790fbe8fdc 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 16c0b7d4f8e7..95a7388e89d4 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 3a6f3ad1eadb..1db1bb0d57bc 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 80a29f5377ea..6e02a15d39ce 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 cdf59bcd760c..0376c092bab8 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 5de6f7c04d09..4cc55b3a0558 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 ecefa5c477fa..ea3753653368 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 895441fe90f7..c3cac4c12fb3 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 1b5d7ffb685e..9f6115a2ee01 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 740f3f496f12..ac97075d75f7 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 0df52ab32a7b..92e47d6c3ee3 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 c890fe46acd3..b3ec743a7a2e 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 ffc3704abded..ab7151181728 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 927617d95616..8fd8f5b489d2 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 2b40393836ff..0d248ce02a9b 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 d7d55a20e959..7ed49646a699 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 3d81daa49172..8637ad1be6be 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 f1f357f43ff0..14ef25dc6cd3 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 d56f927fc31a..8ec92fbeabad 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 67957dd99ede..db6eb79cde07 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 14a2119912ba..2566d2f1c2ad 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 5801ae7f672a..03f334d3a8f4 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 5eab468dd904..d361a72ca0fa 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 22cf9f96cb9e..ee1e19e36445 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 b8825b18c003..e708afc6a57f 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 a4b22c2c3ba7..ed0b3a87983e 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 a5b22c5a240c..a38248360833 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 14eba9c65de3..4397ce5e78df 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 95cffb771a62..0ab81ec8897a 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 3f986e1178ce..4857c467e76c 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 d6bf982efa42..c57207e268c3 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 bb846680bcd4..5c2a49534d2b 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 05f406deae13..790baed33963 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 39b6b2e02963..c75b7388a85c 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 8fd1d3e05665..f85bc106bc52 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 c69b45d7cfbf..fd1c8706d86a 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 b0c70fea760b..d324d001e114 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 a41aa7817c54..d5ed9d36ce25 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 d3e1b6d8bf49..c5d8ee6fa3c7 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 efc761c78f72..3f276d921cca 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 924fc4c6019a..fd888a604462 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 930593d7028d..0533ef20decf 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 0c08f22bdfce..d860344de84e 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 cd995b54732e..614d55767a4e 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 749ad5603c9e..4d313ed4c32e 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 77ce9efe1f24..fa5e8bda2ae4 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 cef7a00099ea..d52d4a8d39ad 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 15ab584cf265..322b53a4f1dd 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 9c29552aedec..8781335ab92f 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 9d3525f659f0..08fb0f2da64d 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 44b0c28d69b6..7c04ef697fb6 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 12b403e78d52..1c6d31f7c1b9 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 5970dd6a1c1c..4b5b3e8fb7d3 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 87a19f33e460..f16b9b42689d 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 c4b1ac6750d8..2764f43607c1 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 20ccc9d315dc..f839654ea436 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 1b594c203992..816dd1a0fd81 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 ca850316d379..7433ba5c4bad 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 ba7e21a73023..f7a01a72eb9e 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 c0e96382feba..04dc71e3ebf0 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 aa407cb5f830..85de4557f696 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 73824a5ada83..dc853e57f91f 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 83143d39dea7..b27cbb1f5afe 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 66ada01c796c..93b315459098 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 644dec73d220..94c1e6455d36 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 45c708e463b9..7289b81bd7b7 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 657ab302a5cf..2fe4c27f524a 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); |